claude/.claude/tasks/2026-06-27-doc-sync-coupled.md
Bastien Chanot 345e43731c chore(memory): BDR-036 + LRN-058..060 + EVAL-008 — doc-sync coupled close
Capitalize the doc-sync coupled chantier: BDR-036 (the invariant, 3 honesties engraved — built-not-reordered, MINOR non-gated surface-replaces-gate, init-project partial + sweep scope-expansion); LRN-058 (same bug-class != same fix — verify the twin's precondition); LRN-059 (swap flips meanings, sweep caught prior-chantier debt README:153 != letter-suffix insertion); LRN-060 (fail-closed guard proven by what it refuses, loudly; argv not separator-string); EVAL-008 (28/28 real-exec, anomalies surfaced). Journal 2026-06-27. BLK-010/011 flags + the frozen plan + TODO checkmarks. BLK-011 record left at STEP 13 (append-only); only the TODO locator moved to STEP 12 (live locator vs immutable record).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ho5EQCFTSvYamuRtVZpp2d
2026-06-27 03:22:12 +02:00

9.3 KiB
Raw Blame History

Doc-sync Coupled — Implementation Plan (v1)

Frozen 2026-06-27. Twin of coupled-capitalize (BDR-034), same PR-stranding class — but NOT the same fix. The deferred note ("reorder before FINISH") was REFUTED in analysis: doc-syncer commits NOTHING (proven, zero git commit/add), so reordering uncommitted docs still misses the merge/PR. Real fix = REORDER + CREATE a doc-commit mechanism (it does not exist; memory already had one). NO git add -A ever — safety lives in the (dynamic) pathspec.

Goal: every orchestrator flow that syncs public docs also COMMITS those docs automatically, on the branch, BEFORE FINISH integrates it — so doc patches reach the merge/PR instead of stranding uncommitted in the working tree.

Architecture: lib/doc-commit.sh (surgical commit of ONLY the files doc-sync patched this run, passed as args, filtered to changed paths, never -A, hard-guard excluding .claude/+CLAUDE.md) + include lib/doc-commit.md referenced by the 2 orchestrators at their doc-sync step. Both orchestrators reordered (doc-sync before FINISH). Mirror of memory-commit.sh + capitalize-commit.md with 4 deltas:

# memory-commit (twin) doc-commit (this) Why
Δ1 fixed scope .claude/memory+.claude/tasks dynamic — patched-file list as args docs scatter across an enumerable set; commit only what was touched
Δ2 TARGETS .claude/ hard-guard EXCLUDES .claude/+CLAUDE.md BDR-022 — inverse scope; defense-in-depth
Δ3 2-hash dance (code hash anchored in entries) no hash — docs carry no SHA LRN-052 — anchoring N-A to docs
Δ4 chore(memory): <IDs> — <flow> docs: <summary> — <flow> separate concern, mirror

Consumption = MECHANICAL (LRN-057 case a, = BDR-034): commit on the branch before FINISH, the merge carries it. No external-cognitive injection needed.

Conscious acknowledgments (state them, don't paper over)

  • Partial init-project fix. After this chantier: ship-feature FULLY fixed; init-project PARTIAL — doc-sync ok, but scaffold + 5b-bootstrap-README commit gap stays open (BLK-010). doc-commit must NOT ramasse the bootstrap README — not its job (would re-create the over-reach we ban). Do NOT believe init-project repaired while the scaffold hole remains.
  • MINOR doc content is non-gated yet auto-committed. This is a CONSCIOUS choice, NOT "same as memory": memory CONTENT was always gated, so auto-commit only ever embarked approved entries. doc-sync auto-mode patches MINOR silently (no gate). Resolution: surface-don't-block. MINOR is factual (command/param/path/version/dead link — same bar as AUTO patches); a blocking gate = friction disproportionate, and the PR diff re-shows it. The doc-commit's visible surface REPLACES the gate as the review surface — ✅ committed README, USAGE — <summary of what changed>, NOT a bare count. Strengthening the MINOR gate itself = separate doc-syncer chantier.

Global Constraints (verbatim, apply to every task)

  • Stage/commit ONLY the files doc-sync patched this run, passed as args. NEVER git add -A / git add . / git commit -a. NEVER stage anything under .claude/** or CLAUDE.md (hard guard — BDR-022, inverse of memory-commit).
  • Dynamic pathspec: filter the passed list to paths with real pending changes (LRN-051 — git commit -- <no-match> ABORTS the whole commit; git add tolerates). A clean/absent passed path is dropped, not fatal.
  • Partial-commit safety: git commit -- <changed-paths> ignores the rest of the index → dangling code (untracked OR pre-staged) is never embarked.
  • Idempotent: empty list / clean tree → no-op, exit 0, no commit.
  • Fail-closed: detached HEAD / merge / rebase / cherry-pick in progress → no commit, skip (exit 3).
  • NO hash anchoring — docs carry no SHA (LRN-052). Commit msg docs: <summary> — <flow>.
  • Surface is VISIBLE: report committed files + a one-line change summary, not just a count.
  • shellcheck clean on lib/doc-commit.sh + test harness.

File Structure

Action File Responsibility
Create lib/doc-commit.sh dynamic-scope surgical doc commit (CLI + sourceable), inverse-exclusion guard
Create lib/doc-commit.md include protocol (mirror capitalize-commit, 4 deltas, visible surface)
Create lib/tests/run-doc-commit.sh TDD: inverse-exclusion + dynamic-pathspec + dangling + stale-index + idempotent + unsafe, real git fixture
Modify agents/doc-syncer.md add PATCHED_FILES: block to OUTPUT (STEP 9) + AUTO MODE (STEP A4); no logic change, callers unaffected
Modify agents/feater.md · bugfixer.md · hotfixer.md Task 6b (sweep-found scope expansion) — wire doc-commit into each DOC SYNC step
Modify skills/ship-feature/SKILL.md reorder DOC SYNC before FINISH + doc-commit include; DELETE HTML comment (lines 196198); renumber FAILURE PATHS / FINAL OUTPUT
Modify skills/init-project/SKILL.md move SYNC README before FINISH (new STEP 10c) + doc-commit include; renumber /13 PROGRESS PROTOCOL headers; conscious partial-fix note (BLK-010)
Modify README.md · USAGE.md · CHANGELOG.md ref-sweep (README:153, USAGE:196/256) + changelog entry
Append .claude/memory/ (BDR + LRN) document the invariant at close
Append .claude/memory/blockers.md BLK-010 scaffold gap, BLK-011 GSD ROADMAP — done this turn

Tasks

  • Task 1lib/doc-commit.sh (TDD, same hard requirement as memory-commit: every test REALLY EXECUTED with real outputs reported before Task 2 — no presumed git behavior; Δ2 + Δ1 especially must be proven on real git).
    • T1 inverse exclusion (Δ2): a passed path under .claude/ (e.g. .claude/memory/x.md) or CLAUDE.md is REJECTED — not committed, guard fires. The load-bearing delta vs memory-commit; prove it on real git.
    • T2 dynamic pathspec (Δ1): pass [README.md, USAGE.md, DEPLOY.md] where only README+USAGE changed → commit contains exactly README+USAGE; the clean DEPLOY.md path is filtered, commit does NOT abort (LRN-051).
    • T3 dangling not embarked: untracked AND pre-staged non-doc code (src/x) NOT in the doc commit, stays untracked/staged.
    • T4 stale-index: doc staged as version A, working-tree version B → commit contains B (git add -- re-stage neutralizes stale index). Mirror of memory T2-bis.
    • T5 idempotent: empty list / clean → no-op exit 0, no commit. T6 unsafe: detached HEAD / merge in progress → exit 3, no commit.
  • Task 2lib/doc-commit.md include (WHEN / DO / HARD RULE surgical / ORDERING before FINISH / IDEMPOTENT / VISIBLE-SURFACE report / no-hash note / inverse-scope vs capitalize-commit). State the 2 conscious acknowledgments inline.
  • Task 3agents/doc-syncer.md: add PATCHED_FILES: (newline-separated real paths, or empty) to STEP 9 OUTPUT + AUTO MODE STEP A4. Additive, no logic change, auto-mode scope: contract unchanged → callers unaffected (BDR-022 preserved). Future-proofs the isolated-subagent invocation; in-thread, the list is already in hand.
  • Task 4 — ship-feature reorder: STEP 8 = DOC SYNC (was 9, + doc-commit include), STEP 9 = FINISH (was 8). DELETE the twin-chantier HTML comment. Renumber FAILURE PATHS + FINAL OUTPUT refs. Pipeline stays "9-step".
  • Task 5 — init-project reorder: new STEP 10c = DOC SYNC (moved from 12, + doc-commit include) after STEP 10b CAPITALIZE, before STEP 11 FINISH; old STEP 13 GSD → STEP 12. Update PROGRESS PROTOCOL /13 headers. Add the conscious partial-fix note pointing at BLK-010 (scaffold/bootstrap still open) + BLK-011 (GSD ROADMAP).
  • Task 6 — ref-sweep: README:153, USAGE:196, USAGE:256, CHANGELOG. Grep READS not just WRITES (LRN-002/LRN-045). Result: live refs all fixed in Task 4/5, no old headers survive, historicals left. Sweep also caught the inline-flow gap → Task 6b.
  • Task 6b — SCOPE EXPANSION (sweep-found, NOT in the original frozen plan — honesty). feat/bugfix/hotfix each have a DOC SYNC step that patched docs but committed nothing → docs left dirty (milder than PR-strand, same class; the asymmetry vs memory is the decider — BDR-034 wired ALL flows). Wire doc-commit into each (1-line include + paragraph, mirror of capitalize-commit). Set = the 3 flows that doc-sync, NOT all 4 capitalize flows: commit-change has no DOC SYNC. hotfix IS wired (its DOC SYNC is unconditional; only its CAPITALIZE is skip-by-default; the include no-ops on empty). We extend the mechanical REPLICATION of a built+tested mechanism; we defer NEW work (BLK-010/011).
  • Task 7 — behavioral verify doc (lib/tests/ end-to-end check, ship-feature + init-project paths) + shellcheck + CHANGELOG entry + close with BDR + LRN. The closing BDR states the surface-replaces-gate choice HONESTLY (MINOR non-gated auto-committed) — not glossed as memory-equivalent.

Deferred / flagged separate (by design, not omission)

  • BLK-010 scaffold + bootstrap-README commit gap (init-project; unborn HEAD + worktree) → own chantier. Flagged this turn.
  • BLK-011 GSD STEP 13 ROADMAP.md post-FINISH (3rd post-FINISH artifact) → own thread. Flagged this turn.
  • Strengthening doc-sync's MINOR gate → separate doc-syncer chantier.
  • doc-sync as isolated subagent (vs in-thread) → PATCHED_FILES: already future-proofs it; no work now.