Skip to content
Download PDF

Drift and reconcile ​

Specs and code want to diverge. You edit code under deadline and forget the spec; you draft a spec and never build it; a refactor changes a shape the spec still describes the old way. Left alone, that divergence — drift — makes .forge/specs/ untrustworthy, and an untrustworthy spec is worse than none. Forge gives you two commands to keep the two sides honest: /forge.driftdetects divergence, and /forge.reconcile resolves it. Both are non-destructive to run, so you can call them freely at any point.

Drift is spec-versus-code divergence ​

Drift is any place where your specs and your code no longer describe the same system. forge drift — the CLI command — cross-references .forge/specs/ against the codebase and sorts every divergence into one of three classes.

ClassMeaningThe gap
GhostCode with no specThe system does something no spec describes
PhantomSpec with no codeA spec describes something the system does not do
MutatedCode and spec disagreeBoth exist, but their shapes have diverged

Detection is deterministic — for the CLI

forge drift is a pure Go function — same inputs, same classification, every run. It classifies; it does not fix. It never blocks, so you can run it as often as you like without disturbing an in-flight change. Fixing is reconcile's job. This determinism claim covers the CLI only — the /forge.drift skill below adds a fourth category that a pure function cannot compute.

/forge.drift adds a fourth class the CLI cannot see: Inverted ​

forge drift (CLI) and /forge.drift (agent skill) share a command name but not an engine — the same split documented for forge roadmap vs. /forge.roadmap. The CLI above is static-analysis-only: it can verify Ghost, Phantom, and Mutated because those are all structural comparisons between a declared shape and an implemented one — a route, a field name, an entity. /forge.drift, the LLM-driven skill, detects those same three classes plus a fourth: Inverted.

An Inverted finding is not about code at all. It fires when the implementation/architecture layer — plan.md's Technical Context, or infra.md — contradicts an intent-level Non-Functional Requirement or Failure Condition declared in spec.md. Two examples: an NFR requires recovery within 30 seconds of an AZ failure, but infra.md describes a single-AZ deployment; or a platform pivot from Vercel to GCP lands in infra.md while plan.md still assumes the old platform. In both cases the code can be structurally perfect — every route and field matching its spec — while the system still targets the wrong scale, platform, or recovery posture. That is why Inverted is non-structural: it survives a Ghost/Phantom/Mutated check untouched and would silently invalidate downstream tasks if nothing looked for it.

Inverted detection cannot be deterministic because judging it requires reading comprehension a parser doesn't have: deciding whether an architecture "can satisfy" a recovery-time or scale target, or whether two free-text documents disagree about a platform, is a judgment call, not a structural diff. drift.Classify — the CLI's engine — never attempts it and is not meant to; it stays a pure function over parseable code/spec shapes. /forge.drift also renders its own emoji legend for its report (👻 Ghost, 👁 Phantom, 🔀 Mutated, 🔄 Inverted), distinct from the CLI's plain-text output.

Catch drift early ​

Make drift part of your rhythm, not just a final gate. The longer a Ghost or a Phantom sits, the more work accretes around a wrong assumption. Run it alongside forge analyze — the 100-point quality score — so you see both how good the current state is and where it has quietly slipped out of sync.

sh
forge drift        # classify Ghost / Phantom / Mutated
forge analyze      # 100-point quality score for the current state

Catching drift while it is one Mutated requirement is cheap. Catching it after ten changes have built on the divergence is not.

Reconcile brings the two sides back together ​

Where drift reports, /forge.reconcile resolves. It reads the artifact you just created or changed, scans everything it could conflict with — other specs, plans, tasks, and the foundation baselines (constitution, security, infra, brand, design) — and walks you through each conflict it finds. Reconciliation runs automatically after any spec-modifying command, so contradictions get caught as they are introduced rather than accumulating; you can also run it by hand at any time.

Severity-ordered detection passes ​

Reconcile runs a fixed sequence of focused detection passes, ordered by severity so the most dangerous conflicts surface first:

#PassSeverityCatches
1ContradictionCriticalDirect logical conflicts — "use PostgreSQL" vs "use MongoDB exclusively"
2Constitution violationCriticalNew content that breaks a declared MUST/SHALL principle
3Terminology driftHighDifferent words for one concept — "customer" vs "user"
4Scope overlapHighTwo specs independently specifying the same feature
5Dependency conflictMediumAssumptions that contradict an existing plan
6Brand & design inconsistencyMediumHardcoded values instead of design-token references
7Infrastructure misalignmentMediumAssuming a service the infra baseline does not define
8Security baseline misalignmentMediumA public endpoint where the baseline requires auth

Interactive, one conflict at a time ​

Conflicts are presented individually. For each, you choose how it resolves — keep the new artifact, keep the existing one, merge them under a rule you describe, or defer it. Every decision is appended to a reconciliation log, so the resolution history is auditable and deferred items get re-evaluated the next time the same artifacts are reconciled.

Constitution violations cannot be deferred ​

The one rule that has no "later": a constitution violation must be resolved before you proceed. Defer a terminology quibble or a scope overlap if you must — they will resurface in the log. A constitution violation cannot be deferred at all. It is a critical pass for a reason: the constitution is the standing truth every change is measured against, and a spec that violates it is a spec building on a contradiction.

No deferring constitution conflicts

reconcile will not let a constitution violation be logged-and-forgotten. It stands in the way until you resolve it — because it also caps your analyze score, a deferred violation would silently penalize every quality assessment that follows.

Where they sit in the workflow ​

drift and reconcile are cross-cutting — not phases on the spine, but non-destructive commands you can call at any point. reconcile fires automatically on the way out of every spec-modifying command; drift is yours to run whenever you want a read on how far code and spec have parted. Together they keep .forge/specs/ an honest description of the system, so the specs you promote on archive are worth trusting.

Next steps ​

  • Foundation phases — the baselines reconcile measures specs against.
  • The workflow — where cross-cutting commands fit the spine.
  • Commands — forge drift, the /forge.reconcile agent skill, and the full surface.
  • Best practices — run analyze and drift on a rhythm.