- name
- drift-update
- description
- Execute the handoff briefs a /drift-handoff run wrote to docs/audits/<audit-date>/<source-id>/ — apply each brief's edits, run its own verification steps, and stamp it done. Use when the user says to execute, apply, action, or work through the drift handoffs or briefs, or points at a docs/audits directory. Reads briefs from disk and never from the conversation, so it runs cold in a fresh session (preferred) or warm straight after /drift-audit and /drift-handoff. Walks briefs in numbered order with a checkpoint each — confirm the brief's quoted evidence still exists, apply, verify, stamp, continue — and stops on the first failure rather than pressing on. Briefs whose Kind is a decision or an investigation rather than an edit are put back to the user, never executed. Skips briefs already carrying an execution log, so an interrupted run resumes where it stopped. Hands off to /commit at the end.
- argument-hint
- [audit-date | source-id | path] [brief-number[,brief-number...]]
- allowed-tools
- Read Edit Write Glob Grep Bash
- model
- inherit
- effort
- max
- disable-model-invocation
- false
- context
- inline
# Drift update
Execute the briefs on disk. `/drift-audit` finds the drift, `/drift-handoff`
writes it down, and this skill is the third turn: it applies what the briefs
specify, verifies with the steps the briefs supply, and records that it ran.
The briefs are the instruction set. This skill contributes the loop around
them — resolution, a staleness gate, triage, checkpointing, and a stamp — not
the content of any edit.
**Read every brief from disk, every time.** Never reconstruct one from the
conversation, from memory of an audit, or from a summary, even when this
session produced it. The file is the contract; the transcript is not.
Paths below are relative to the repo root. This skill is project scope — it
lives in `.claude/skills/`, deployed nowhere since 2026-09-09 — so it only
fires in sessions inside this repo.
## 1. Preconditions and session posture
**Fresh session is the intended way to run this.** A brief is written to be
read cold; running cold is what proves it was written well.
Check whether `/drift-audit` or `/drift-handoff` **ran in this session**. If
either did, this is a **warm** run. A report that is merely present does not
count: an @-mention or a path argument loads `00-audit-report.md` with its
`## Audit window` and `## Recommended actions` intact, but none of the audit
turn's context the limits below exist for. Runs on 2026-09-08 and 2026-09-11
both met this and stamped themselves fresh. Warm is allowed, with two limits:
- **Refuse a brief whose targets include `.claude/skills/drift-audit/`,
`.claude/skills/drift-handoff/`, or `.claude/skills/drift-update/`.** Editing
the skill that produced the briefs, in the session that produced them, is the
one case where warm is actually unsound. Name the brief, say why it was
skipped, and tell the user to run it from a fresh session.
- **Cap the run at three briefs.** The audit turn is the expensive one; its
fetched sources and artifact sweep are still resident. Apply the first three
eligible briefs, stop, and report the remainder as pending a fresh session.
The cap counts briefs this run **applies**; one that 4.2 stamps as
`already-applied` costs a grep and an append, so it does not consume the
budget. Compaction part-way through an edit is worse than a restart, because a
compacted session is a lossy warm one — strictly worse than a cold one.
Say which posture the run used in the closing report. A warm run that does not
announce itself looks like a cold one that skipped work.
## 2. Resolve the brief set
The target is a directory: `docs/audits/<audit-date>/<source-id>/`.
Argument forms, all optional:
- **A path** — `docs/audits/2026-08-29/fabric`, in either slash style.
Use it directly. This is the shape of the hand-written invocation this skill
replaces, so it must keep working.
- **ISO date** (`YYYY-MM-DD`) — that run's directory. If it holds more than one
source directory, apply the multi-source rule below.
- **Source id** (`fabric`, `powerbi`, `vscode-agent`, `claude-code`, …) — that
source under the most recent audit date that has one.
- **Trailing brief numbers** — one integer, or a comma-separated list
(`1,2,3,5`), restricts the run to those briefs, still walked in numbered
order. Without them a cold run has no cap and walks every unstamped brief
in one pass; name numbers to keep a session to a batch one `/commit` can
review.
- **No argument** — the most recent date directory under `docs/audits/`.
**Multiple source directories under one date are separate runs of work, not one
run.** List them and ask which to execute. Do not silently pick the first or
concatenate them: sources produce unrelated edits with unrelated verification,
which is the same reason `/drift-handoff` gives them sibling directories.
Then, in the resolved directory:
- `Glob` the numbered briefs. `00-audit-report.md` is not a brief; it is
evidence, and step 4 governs when to open it. `README.md` is not one
either: it is the generated index of the directory, worth a glance for
where things stand, but the `## Execution log` in each brief is the
resume mechanism, not the index's status column.
- **Skip any brief already carrying an `## Execution log` section.** That is
the resume mechanism. Report skipped-as-done briefs by name so a short run is
never mistaken for an empty one.
- If every brief is already stamped, say so and stop. Nothing to do is a
result, not a failure.
If the directory does not exist, **stop**:
> No briefs at `<path>`. This skill executes briefs that `/drift-handoff`
> already wrote; it does not derive work from an audit report. Run
> `/drift-audit` then `/drift-handoff` first, or name an existing directory
> under `docs/audits/`.
## 3. Triage — which briefs this skill may execute
Read each brief's **Kind** line before doing anything with it. It is the
metadata block's most load-bearing field and it classifies the brief:
- **Edit** — "factual correction to committed prose", "rewrite the lineage
section", "propagate a GA status". Execute it.
- **Decision** — the Kind says the output is a decision, a scoping call, or
that no file is corrected by this brief. The worked case is a brief reading
`Kind: scoping decision, not an edit`, whose body then says it exists to make
the decision makeable, not to make it. **Never execute one.** Present the
brief's problem and evidence to the user, ask the question it poses, and
record the answer per step 4.6. A skill that cheerfully writes a new skill
because a brief mentioned one has misread its only instruction.
- **Investigation** — the Kind says measurement, probe, research or an
empirical step, and no edit is authorized until it reports. Split it by
what it needs. A **doc lookup** settles like an edit's own fetch: run it,
and apply the edit only if the page establishes it. **Anything more** —
a person at a GUI, a tenant, a cold probe session, a repo the user
chooses — is not run here: escalate it per step 4.6 with the brief's
method named, so it runs later as its own task. This kind went unnamed
until 2026-09-11, and runs improvised it: one probed for a running
Desktop before escalating, another relabelled a measurement as a decision.
- **Self-referential** — the target is the drift skills' own machinery, most
often `.claude/skills/drift-audit/references/sources.md`. Apply it, but
understand what verification is available: such a brief typically specifies
"verified by re-running an audit, not by grepping prose", and this skill
cannot re-run an audit against its own just-edited registry. Run the gates
that do apply, then record the behavioural check as **deferred to the next
`/drift-audit` run** in the execution log and in the closing report.
A sub-sectioned brief (`## D-1`, `## D-2`, …) is triaged per defect. A defect
carrying an **Open question** blocks that defect only — ask the user about it,
apply the rest of the brief, and note the deferral in the execution log.
## 4. The per-brief loop
One brief at a time, in numbered order — that order encodes dependency where
one exists. Each brief runs the full loop before the next one starts. **Stop
the whole run on the first failure**; do not skip ahead to an easier brief.
### 4.1 Read the brief
In full, from disk. Honour every section, not just **What to change**:
- **Constraint on the fix** bounds the edit. It usually names what the evidence
does *not* establish, precisely so the fix does not overreach. Obey it even
when a broader change looks obviously right.
- **Not fixable** / **Out of scope** describes what survives the fix on
purpose. Do not attempt those parts, and do not report them as incomplete.
### 4.2 Staleness gate
Briefs are executed days or weeks after they are written, and the tree moves.
Before editing, confirm each target in **What to change** still looks like the
brief says it does: `Grep` for the quoted offending line at the named path.
- **Quote found** — proceed to 4.3.
- **Quote absent** — **do not guess and do not search for something similar.**
Grep once more at the same path, this time for the brief's intended
*post-fix* text. A missing quote means one of two opposite things, and that
second grep is the only cheap way to tell them apart:
- **Corrected text present** — the fix is already in the tree, applied by
hand or by an earlier unstamped run, and the brief's intent is satisfied.
Skip 4.3 and 4.4, go straight to **4.5 and stamp it `already-applied`**.
Nothing is edited, but the brief is now done and a later run passes over
it. Without this stamp the run never converges: a set applied by hand
before this skill first ran would be re-derived in full, every time.
- **Corrected text also absent** — the target was rewritten, renamed, or
deleted for reasons the brief knows nothing about. The correction is *not*
in the tree and this brief can no longer put it there. **Stop the run** and
report it, as for a partially valid brief below. Do **not** stamp: a stamp
here would silently retire an unaddressed correction.
- **Some targets found, some not** — treat it as a stop. A partially valid
brief means the tree diverged in a way nobody predicted, and that deserves a
human look before anything is written.
### 4.3 Apply
Make the edits the brief enumerates, at the paths it names, and nothing else.
**Do not fix adjacent problems.** Something else wrong in a file you are
editing is a finding for the closing report, not licence to widen the diff.
The audit / handoff / update split exists so that analysis, transcription, and
execution stay separable; an unbriefed edit made here has no evidence behind it
and no verification step written for it.
Equally, **do not re-open the brief's reasoning.** If the brief looks wrong,
stop the run and say so in chat rather than improving it in passing — the same
rule `/drift-handoff` follows when transcribing.
### 4.4 Verify
Run the brief's own **Verification** section, in order, as commands. It is
numbered and runnable for exactly this reason, and the shared-verification test
is what decided the brief's boundaries in the first place.
Two adjustments to the repo's standard gates:
- `uv run --with pyyaml scripts/lint-frontmatter.py <file>` — run per brief, on
any skill or rule file it touched.
- `pre-commit run --all-files` — run **once at the end of the whole run**, not
per brief. It is repo-wide and slow, and per-brief runs tell you nothing
extra. Skip it altogether when the run wrote nothing: a brief set that came
back wholly already-stamped or already-applied leaves no diff for it to
check, and running it anyway is a slow repo-wide no-op.
A failed verification stops the run. Report the command, its output, and the
state of the tree; leave the edits in place rather than reverting, so the user
can see what happened.
**One check this skill cannot perform:** an edited `SKILL.md` does not reliably
reload mid-session on Windows, so no brief that edits a skill can have its
behaviour validated in the session that applied it. Lint and prose checks pass;
behavioural confirmation is a fresh-session task. Say so rather than implying
the skill was exercised, and name the task: `/test-skill <skill> @<brief>`,
which takes the brief's *What to change* as the claim to separate from the
baseline and appends its confirmation to this execution log rather than
deleting the brief.
### 4.5 Stamp
Append to the brief file:
```markdown
## Execution log
- **Executed**: <ISO date> — <applied | applied with deferrals |
already-applied | escalated>
- **Session**: <fresh | warm>
- **Files changed**: `<path>`, `<path>`
- **Verification**: <which steps ran and passed>
- **Deferred**: <what could not be checked here, and what would check it>
- **Deviations**: <anything done differently from the brief, and why — or none>
```
An `already-applied` stamp uses the same shape with different content:
**Files changed** is `none`, and **Verification** is the confirming grep from
4.2 — the post-fix text, found at the named path — rather than the brief's own
steps, which were never run.
Append; never rewrite the brief above it. The brief as written is the record of
what was decided, and the log is the record of what happened — keeping them
distinct is what makes the pair auditable.
Then regenerate the directory's index:
```bash
uv run scripts/audit-status.py --dir <the resolved directory>
```
That rewrites its `README.md` from the briefs, so this brief's row moves from
`pending` to the outcome and date just stamped. The index is derived, never
edited, and the `lint-audit-index` pre-commit hook fails a commit whose index
disagrees with its briefs — so a stamp and its regenerated README are one
commit.
**`- **Closed**: <ISO date> — <how>` is the one key added after the stamp**,
by whichever later session discharges what the log left open — an
`/author-skill` run that authored the accepted candidates, a `/drift-audit`
run that performed the deferred behavioural check, a decision the user made.
Append it to the existing log; the `Executed` and `Deferred` lines were
accurate when written and stay as they are. The index reads it and shows the
row as `closed`. Without it an escalated brief reads as open forever, which is
how the four skills authored from 2026-09-10 brief 07 left no trace in the
ledger until a later audit wrote a brief to record them.
`docs/audits/` is tracked, so these stamps are history and not just working
state: they make a re-run resumable, and they are also the record of what a
brief actually did. That does not make them the changelog — the commit message
still documents the change. Stamps are committed alongside the edits they
describe, so a brief and its outcome land together.
### 4.6 Checkpoint
Emit one line — brief number, outcome, files touched — then continue. Do not
batch the reporting to the end; a run that fails at brief five should already
have shown what briefs one through four did.
For an escalated brief, the checkpoint is the question itself. For a decision,
put the brief's problem and evidence in front of the user and ask; for an
investigation, say what it needs and ask where it should run. Stamp the answer
into the execution log as `escalated`. Whatever work the answer implies is a
separate task, started deliberately — not something to fold into this run.
**That task needs a home before the run ends.** The stamp makes every later
run skip the brief, and `docs/handoffs/execute/README.md` reads a stamped brief
as done, so work recorded only in the brief's own log is invisible to both.
Add it to that file's audit follow-up table, under what it needs — re-reading
the file immediately first, since it is the most contended one here. The same
goes for a deferral that leaves work rather than a re-check, and for an
adjacent finding. Found 2026-09-11, when two runs' follow-ups turned out to be
in no queue.
## 5. Report and hand off
Close with:
1. **Per-brief outcomes**, one line each: applied, escalated,
already-applied, already-stamped, or not-reached. Keep the last three
distinct: *applied* is a change this run wrote, *already-applied* is one
4.2 found already in the tree and stamped now, *already-stamped* is one a
previous run had already logged before this one started.
2. **Session posture**, and anything the posture cost — briefs held back by
the warm cap or the self-referential refusal.
3. **Deferred verification** — every check that needs a fresh session or a
later `/drift-audit` run, named with what would perform it.
4. **Adjacent findings** — problems seen but deliberately not fixed.
5. **Brief-format defects.** If a brief could not be executed without opening
`00-audit-report.md`, say which one and what was missing from it. A brief is
supposed to be sufficient cold; every fallback to the report is evidence
that `/drift-handoff` under-specified one, and this is the only place that
failure is observable.
6. `pre-commit run --all-files` result — or that it was skipped because the
run made no edits.
Then hand off to `/commit`. Unlike `/drift-handoff`, this skill changes tracked
files, so there is a real diff — and `/commit` splits it logically, which is
why this skill does not commit per brief. If the run stopped early, say plainly
which edits are applied and uncommitted before handing over. A run that wrote
nothing has nothing to hand over: report the clean tree and stop, rather than
invoking `/commit` against an empty diff.
Do **not** start the work an escalated decision implies, and do not begin the
next source's briefs. Both are separate, deliberate invocations.
## 6. Constraints
- **Briefs come from disk.** Never from the transcript, a summary, or memory.
- **The brief set is the scope.** No unbriefed edits, no adjacent fixes, no
re-opened reasoning.
- **Kind decides.** Decision and investigation briefs are escalated, never
executed — and anything a run leaves for later gets a queue row.
- **Stale splits two ways, and neither is improvising.** A missing quoted
line means the fix already landed (stamp `already-applied`) or the target
moved (stop the run). Never substitute a line that looks close enough.
- **Constraints and Out-of-scope sections are binding**, not advisory.
- **First failure stops the run.** Leave the tree as it is and report.
- **Stamp what ran**, including deferrals and deviations.
- **Warm runs announce themselves**, cap at three briefs, and refuse briefs
targeting the drift skills themselves.
عرض على GitHub