docs: make the phases-plan sync rule explicit and deferral strict

Sub-phase 2.2 hit both failure modes this rule exists to prevent. Its own
implementation switched the UIA client construction and left phases.md
asserting the old one, so the product's source of truth contradicted the code
for four commits. Separately, what 2.2 could not resolve was recorded in the
ledger and the PR description but not in 2.4, which is the sub-phase that has
to act on it - the reviewer of this PR would have seen it, the planner of the
next one would not.

CLAUDE.md now states the rule in full: phases.md is the source of truth for
the product, the sub-phase plan is the source of truth for implementation and
review, and neither may contradict the other or the code at any commit. A
contradiction found while planning is corrected in phases.md in the same PR,
in place, citing what disproved it.

Deferral is stated as the exception it should be. The default is that the
implementer makes it work; harder-than-expected, plan-underestimated, and
PR-already-large are explicitly not grounds. An unknown is settled with a
probe before it is allowed to justify a deferral. Whenever something is
deferred, the receiving sub-phase in phases.md is updated in the same PR - a
ledger row or a PR description is not sufficient, because those are read by
this reviewer rather than by the next planner.
This commit is contained in:
Lahfir 2026-07-28 18:58:37 -06:00
parent f4a505e5f6
commit eefd589e8f

View file

@ -41,6 +41,43 @@ Bypass for an emergency commit with `git commit --no-verify` or `SKIP_PRECOMMIT=
Cross-platform Rust CLI + MCP server enabling AI agents to observe and control desktop applications via native OS accessibility trees.
## Source of Truth & Sync (Non-Negotiable)
Two documents govern every phase, and they are never allowed to disagree.
- **`docs/phases.md` is the source of truth for the product.** Scope, exit criteria, invariants, API mappings, dependency pins and phase order live there. What the product *is* and *will be* is settled by that document.
- **The sub-phase plan under `docs/plans/` is the source of truth for implementation and review.** How a sub-phase is built, what its units are, and what its Verification Contract and Definition of Done require are settled by the plan.
- **They must be in sync at every commit, and both must match the code.** A statement in one that contradicts the other, or contradicts what shipped, is a defect in its own right — not documentation debt to be tidied later. The next sub-phase's planner reads these documents as fact; a stale line becomes a wrong decision.
### Planning: contradictions are corrected on discovery
Research routinely disproves statements in `docs/phases.md`. When it does:
- **Correct `docs/phases.md` in the same PR that discovered it.** Never plan around a statement known to be false, and never leave the correction to a later sub-phase.
- **Correct in place; never annotate.** Rewrite the statement so the document reads true. No "previously said X", no "NOTE:", no changelog line — the document is the product's source of truth, not its history.
- **Cite what disproved it** — a `probes/**/FINDINGS.md` row id, or the verified source.
- The plan carries the correction as its own implementation unit, so it is reviewed alongside the work.
### Implementation: build it, do not defer it
**Deferral is the exception and the bar is high. The default is that the implementer makes it work.**
- **Attempt the work fully before concluding it cannot be done.** "Harder than expected", "the plan underestimated it", "a later sub-phase touches this anyway", and "the PR is already large" are **not** grounds for deferral.
- A deferral is justified only when the work is genuinely blocked: technically impossible on the platform, dependent on infrastructure that does not exist yet, or completable only by violating a stated invariant or safety property. Name which one applies.
- **Measure before deferring.** If the obstacle is an unknown, settle it with a probe or an experiment first. A deferral resting on an assumption is not a deferral, it is a guess — and an assumption that turns out to be wrong has usually hidden work that was a few hours away.
- Reducing scope is the owner's call, not the implementer's. If the work genuinely cannot land, say so explicitly and stop; do not narrow the deliverable quietly.
### Every deferral updates `docs/phases.md` immediately
When something is deferred — at planning time or at implementation time — the sub-phase that now owns it is updated in the **same PR**, before that PR is opened for review:
- Write the deferred work into the **receiving** sub-phase's scope in `docs/phases.md`, in enough detail that its implementer can act on it without reading this PR or its plan.
- State what was learned that forces it there, and cite the evidence.
- If the deferral changes what the **originating** sub-phase delivers, correct that sub-phase's scope and exit criteria too, so it never claims work it did not ship.
- A ledger row, a PR description, or a plan's residual list is **not** sufficient. Those are read by this PR's reviewer; `docs/phases.md` is read by the next sub-phase's planner, and that is who needs to know.
**A PR that defers work without updating `docs/phases.md` is incomplete and must not be merged.**
## Git & Commits
### Branching during a platform phase (Phase 2 = Windows, in progress)