Cycle step 7 · /sdd drift-check
Drift Lock — code and SPEC in the same PR
Spec drift — code evolving without the artifacts following — is the number-one risk of developing with AI agents. The Drift Lock neutralizes it with a simple, non-negotiable policy: code and SPEC synchronized in the same PR, verified by the human and measured by the machine.
A process failure, not an agent error
This is SDD Mode's second founding principle: Drift = Process Failure. When a SPEC falls out of sync with the code, the culprit is not the agent that generated the code — it is the process that allowed merging without synchronizing. Updating the artifacts is part of the Definition of Done: a task whose code is merged but whose SPEC is out of sync is not finished.
This framing changes everything in practice: a detected drift is a process success, not a shame to hide. The most dangerous drift is the one you never check for.
Silent degradation — 1, 5, 20 iterations
Spec drift makes no noise; it accumulates. After one unsynchronized iteration, the SPEC is slightly misaligned — a renamed field, an edge case added to the code only. After five iterations, it is obsolete: the agent that receives it works from a wrong baseline and confidently generates incorrect code. After twenty iterations, it is unusable — and the team is back to developing without a specification, having paid the cost of writing one without keeping the benefit.
Any change to a feature's behaviour requires an immediate SPEC update, in the same session. No exceptions. That is what separates the spec-anchored stance from disposable spec-first.
The Anti-Drift Check — three questions at the end of the iteration
Before closing a ticket, the Product Engineer answers three questions for each SPEC used in the session — ten minutes, under their responsibility:
- Does the delivered behaviour match exactly what the SPEC describes?
- Is the list of impacted files in the SPEC still exhaustive?
- Does the DRIFT CRITERION of the parent Intent Statement signal a gap between the initial intent and what was delivered?
If the answer to any of the three is no, the SPEC — and possibly the Intent Statement — is updated before closing. The third question is the deepest: it checks not that the code matches the SPEC, but that the delivery honours the original human intent.
The PR policy
The lock is mechanical: the updated SPEC is committed in the same PR as the code. Not in a follow-up PR "we'll get to later", not in a documentation ticket: the same one. A PR that modifies application code without touching the corresponding SPEC triggers the DRIFT verdict — and does not merge. /sdd drift-check runs this control before every PR: if everything is synchronized, the SPEC moves to done status, the indexes are updated, and an entry is added to CHANGELOG-ARTEFACTS.md.
Algorithmic measurement (v1.10) — /sdd trace and the CI
Since v1.10, the Drift Lock no longer rests on human discipline alone: it is measured algorithmically. Two controls combine: the git heuristic (drift-detection skill — code modified without a SPEC update in the same PR) and the traceability matrix (traceability skill — @intent / @spec / @verified-by / @governance annotations cross-referenced with .aiad/intents/ and .aiad/specs/).
npx aiad-sdd trace --fail-on-gap # a blocking gap fails the pipeline
# Blocking gaps detected by the matrix:
# - Orphan SPEC : referenced by the code, missing from the artifacts
# - Orphan Intent : no code references it
# - Validated, unimplemented SPEC : no @spec annotation cites it
In CI, the .github/workflows/sdd-trace.yml GitHub Action invokes this command on every PR: a blocking gap fails the pipeline. The matrix is the final arbiter — a traceability gap counts as DRIFT even when the git heuristic says OK. On every successful run, the .aiad/metrics/traceability/trace.{md,json} snapshot is regenerated.
UNKNOWN verdict — absence of evidence is not evidence
When the @spec annotations are missing from the modified application code, detection cannot conclude "no drift". The mandatory verdict is UNKNOWN — never OK by default. This is the direct application of the JNSP policy (Je Ne Sais Pas — "I don't know"): absence of evidence of drift ≠ evidence of absence of drift.
Verdict: UNKNOWN (JNSP)
What is measured: <files checked and their annotations>
What is missing: <file(s) without @spec or orphan annotation>
Human action: add the annotation, create the missing SPEC,
or whitelist explicitly in .aiad/hook-bypass.yml
The UNKNOWN verdict is treated as a DRIFT by the pre-commit hook and by the CI. It never degrades into a silent OK — that very silence is what would turn a blind spot into intentional debt.
The last link in the chain of evidence
The Drift Lock does not only keep the documentation accurate. In doctrine v1.9, it is the last link in the chain of evidence that conditions automated deployment: a deployment without human intervention is only admissible if the code is trusted in the sense of a verifiable chain — Intent Statement, SPEC validated at the Gate, traced checks, Drift Lock — and not through declarative trust in the tool or the model. This is the criterion Roblox set for accepting agentic code in production (QCon AI, 2026); AIAD makes it the entry criterion for Continuous Deployment of agent-produced code. The practical consequence for an organisation with more modest means: reserve automated deployment for features whose chain of evidence is complete.
The same chain makes the organisation's accountability demonstrable: the Intent Statement documents the intent and its author, the SPEC the delegated scope, the Gate trace the human validation, the Drift Lock the synchronisation between what was intended and what was delivered. It documents diligence — and, where applicable, fault: a trace that could only exonerate would not be evidence. See Human Authorship and Agent autonomy.
The artifact Sync micro-phase — 15 minutes, 4 questions
In addition to the end-of-iteration Anti-Drift Check, every implementation loop closes with the artifact Sync micro-phase: fifteen minutes, under the PE's responsibility, non-negotiable. Four questions:
| Question | If the answer requires it |
|---|---|
| Does the SPEC reflect the implemented behaviour? | Update the SPEC |
| Is the SPEC's Drift Criterion still valid? | Revise it if the impacted files have changed |
| Was a notable agent error fixed manually? | Document it in the Lessons Learned |
| Has a new convention emerged? | Add it to the AGENT-GUIDE patterns |
Drift Lock passed, PR merged: the SPEC is done, the Intent archived, the context cleaned up. Consolidation continues in the rituals — /aiad retro, /aiad intention — and a new iteration can start from a fresh Intent Statement.