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
9.3 KiB
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). NOgit add -Aever — 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/**orCLAUDE.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 addtolerates). 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 196–198); 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 1 —
lib/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) orCLAUDE.mdis 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.
- T1 inverse exclusion (Δ2): a passed path under
- Task 2 —
lib/doc-commit.mdinclude (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 3 —
agents/doc-syncer.md: addPATCHED_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
/13headers. 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.