feat(doc-syncer): PATCHED_FILES newline output for doc-commit handoff
doc-syncer now emits PATCHED_FILES — every public-doc file created/modified this run, ONE PATH PER LINE — in both STEP 9 OUTPUT (full audit) and AUTO MODE STEP A4 (the path orchestrators call). NONE stays silent (no line → doc-commit sees empty → no-ops). Additive: detection/patching logic and the `auto-mode scope:` input contract are unchanged → callers unaffected. Separator contract, producer↔consumer aligned + proven: newline is doc-syncer's OUTPUT format (paths carry no newlines); the agent splits on newline and passes EACH path as a SEPARATE argv element to lib/doc-commit.sh. The helper takes argv (no in-band separator) → a path with spaces survives as one argument. lib/doc-commit.md spells this out (never flatten to a space-joined string + re-split, which would mis-split a spaced path the helper then silently drops). New test T7 PROVES it on real git: 'docs/My Guide.md' → committed as one file (28/28, shellcheck clean). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ho5EQCFTSvYamuRtVZpp2d
This commit is contained in:
parent
4a54a65dd4
commit
fb1f359da5
@ -719,8 +719,16 @@ CREATED : <count> files
|
|||||||
REMOVED : <count> files / sections
|
REMOVED : <count> files / sections
|
||||||
HUMAN PENDING: <count> items (see report above)
|
HUMAN PENDING: <count> items (see report above)
|
||||||
SKIPPED : <count> (user declined)
|
SKIPPED : <count> (user declined)
|
||||||
|
PATCHED_FILES: (one real path per LINE below; "(none)" if no write)
|
||||||
|
<path created or modified this run>
|
||||||
|
<path created or modified this run>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
`PATCHED_FILES` is the machine-readable handle the doc-commit step (`lib/doc-commit.md`)
|
||||||
|
consumes — every public-doc file created or modified this run, ONE PATH PER LINE. Each line
|
||||||
|
is passed as a SEPARATE argument to `lib/doc-commit.sh` (newline split, space-safe). It NEVER
|
||||||
|
lists `.claude/**` or `CLAUDE.md` (never targets, BDR-022). Empty / `(none)` → doc-commit no-ops.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## AUTO MODE
|
## AUTO MODE
|
||||||
@ -782,8 +790,9 @@ Categorize:
|
|||||||
|
|
||||||
### STEP A4 — ACT
|
### STEP A4 — ACT
|
||||||
|
|
||||||
- **NONE** → exit completely silent. No output.
|
- **NONE** → exit completely silent. No output (no `PATCHED_FILES` → the doc-commit step
|
||||||
- **MINOR** → patch silently. One-line confirmation:
|
sees an empty list and no-ops).
|
||||||
|
- **MINOR** → patch silently. One-line confirmation per file:
|
||||||
`doc-sync: patched <file> (<what changed>)`
|
`doc-sync: patched <file> (<what changed>)`
|
||||||
- **SIGNIFICANT** → surface to user before patching:
|
- **SIGNIFICANT** → surface to user before patching:
|
||||||
```
|
```
|
||||||
@ -793,6 +802,16 @@ Categorize:
|
|||||||
```
|
```
|
||||||
Wait for approval.
|
Wait for approval.
|
||||||
|
|
||||||
|
After writing in MINOR or approved-SIGNIFICANT, emit the machine-readable handle the
|
||||||
|
doc-commit step (`lib/doc-commit.md`) consumes — ONE real path PER LINE:
|
||||||
|
```
|
||||||
|
PATCHED_FILES:
|
||||||
|
<path created or modified this run>
|
||||||
|
<path created or modified this run>
|
||||||
|
```
|
||||||
|
Emit ONLY when something was written; NONE stays silent. Never lists `.claude/**` or
|
||||||
|
`CLAUDE.md` (never targets, BDR-022).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## RULES
|
## RULES
|
||||||
|
|||||||
@ -18,12 +18,13 @@ and any SIGNIFICANT-gated patch), with the code already committed.
|
|||||||
the doc commit strands outside the merge/PR (the exact bug this fixes). See ORDERING.
|
the doc commit strands outside the merge/PR (the exact bug this fixes). See ORDERING.
|
||||||
|
|
||||||
doc-syncer runs IN-THREAD (the orchestrator loads it), so the list of files it patched is
|
doc-syncer runs IN-THREAD (the orchestrator loads it), so the list of files it patched is
|
||||||
already in hand — surfaced as `PATCHED_FILES:` in doc-syncer's OUTPUT. Pass that list.
|
already in hand — surfaced as `PATCHED_FILES:` in doc-syncer's OUTPUT, ONE PATH PER LINE.
|
||||||
|
Pass each line as a SEPARATE argument (see DO step 3).
|
||||||
|
|
||||||
## DO
|
## DO
|
||||||
|
|
||||||
1. Collect `PATCHED_FILES` — the public-doc paths doc-syncer wrote this run (its OUTPUT
|
1. Collect `PATCHED_FILES` — the public-doc paths doc-syncer wrote this run (its OUTPUT
|
||||||
block). Empty → nothing to commit; the helper no-ops.
|
block, ONE PATH PER LINE). Empty → nothing to commit; the helper no-ops.
|
||||||
|
|
||||||
2. Compose — from the patch context the AGENT holds (doc-syncer ran in-thread, so the
|
2. Compose — from the patch context the AGENT holds (doc-syncer ran in-thread, so the
|
||||||
agent knows exactly what changed) — BOTH artifacts:
|
agent knows exactly what changed) — BOTH artifacts:
|
||||||
@ -34,11 +35,19 @@ already in hand — surfaced as `PATCHED_FILES:` in doc-syncer's OUTPUT. Pass th
|
|||||||
Both are the AGENT's to write — the helper produces NEITHER (its only stdout is the
|
Both are the AGENT's to write — the helper produces NEITHER (its only stdout is the
|
||||||
hash). This is the load-bearing point of the visible surface: see the rc 0 row.
|
hash). This is the load-bearing point of the visible surface: see the rc 0 row.
|
||||||
|
|
||||||
3. Commit surgically via the helper, passing EXACTLY the patched files, capturing the hash:
|
3. Commit surgically via the helper, passing EXACTLY the patched files — each path as a
|
||||||
|
SEPARATE argument (split `PATCHED_FILES` on NEWLINES only), capturing the hash:
|
||||||
|
|
||||||
doc_hash=$(bash "$HOME/.claude/lib/doc-commit.sh" commit "<message>" <PATCHED_FILES…>)
|
doc_hash=$(bash "$HOME/.claude/lib/doc-commit.sh" commit "<message>" "<path-1>" "<path-2>" …)
|
||||||
rc=$?
|
rc=$?
|
||||||
|
|
||||||
|
SEPARATOR — the helper takes argv (no in-band separator), so a path with spaces
|
||||||
|
(`docs/My Guide.md`) survives as ONE argument and commits correctly (proven, T7). NEVER
|
||||||
|
flatten the list into a single space-joined string and re-split it: that mis-splits a
|
||||||
|
spaced path into garbage args, which the helper's `[ -e ]` filter then silently drops —
|
||||||
|
the spaced doc would strand. Newline is doc-syncer's OUTPUT format (paths carry no
|
||||||
|
newlines); argv is the handoff to the helper.
|
||||||
|
|
||||||
4. REPORT BY (rc, doc_hash) — handle EVERY exit, not just success:
|
4. REPORT BY (rc, doc_hash) — handle EVERY exit, not just success:
|
||||||
|
|
||||||
| rc | doc_hash | meaning | what to do |
|
| rc | doc_hash | meaning | what to do |
|
||||||
|
|||||||
@ -12,6 +12,7 @@
|
|||||||
# T4 stale-staged doc (version A) → commit carries working-tree version B
|
# T4 stale-staged doc (version A) → commit carries working-tree version B
|
||||||
# T5 idempotent — empty list / clean tree → no-op exit 0
|
# T5 idempotent — empty list / clean tree → no-op exit 0
|
||||||
# T6 unsafe git state (detached HEAD) → exit 3, no commit
|
# T6 unsafe git state (detached HEAD) → exit 3, no commit
|
||||||
|
# T7 path WITH A SPACE passed as one arg → committed (argv is space-safe, no separator)
|
||||||
#
|
#
|
||||||
# No -e: run every test and report, even after a failure.
|
# No -e: run every test and report, even after a failure.
|
||||||
set -uo pipefail
|
set -uo pipefail
|
||||||
@ -158,6 +159,20 @@ if [ "$RC" -eq 3 ]; then ok "detached HEAD → exit 3"; else ko "expected 3, got
|
|||||||
if [ "$(git -C "$R" rev-parse HEAD)" = "$BEFORE" ]; then ok "no commit created"; else ko "a commit was created"; fi
|
if [ "$(git -C "$R" rev-parse HEAD)" = "$BEFORE" ]; then ok "no commit created"; else ko "a commit was created"; fi
|
||||||
rm -rf "$R"
|
rm -rf "$R"
|
||||||
|
|
||||||
|
echo "T7 — path WITH A SPACE passed as one arg → committed (argv is space-safe)"
|
||||||
|
R="$(new_repo)"
|
||||||
|
mkdir -p "$R/docs"
|
||||||
|
printf 'guide baseline\n' >"$R/docs/My Guide.md"
|
||||||
|
git -C "$R" add -A; git -C "$R" commit -qm "add spaced doc"
|
||||||
|
printf 'feature added\n' >>"$R/docs/My Guide.md"
|
||||||
|
run "$R" commit "docs: T7 spaced" "docs/My Guide.md"
|
||||||
|
printf ' rc=%s out(hash)=[%s]\n' "$RC" "$OUT"
|
||||||
|
if [ "$RC" -eq 0 ]; then ok "exit 0"; else ko "expected 0, got $RC"; fi
|
||||||
|
if [ -n "$OUT" ]; then ok "hash printed (commit made)"; else ko "no hash"; fi
|
||||||
|
if git -C "$R" cat-file -e "HEAD:docs/My Guide.md" 2>/dev/null; then ok "spaced path present in HEAD"; else ko "spaced path not committed"; fi
|
||||||
|
if [ -z "$(git -C "$R" status --porcelain -- "docs/My Guide.md")" ]; then ok "spaced doc clean (embarked as ONE file, not split)"; else ko "spaced doc still dirty"; fi
|
||||||
|
rm -rf "$R"
|
||||||
|
|
||||||
rm -f "$ERRFILE"
|
rm -f "$ERRFILE"
|
||||||
echo ""
|
echo ""
|
||||||
printf 'RESULT: %d passed, %d failed\n' "$PASS" "$FAIL"
|
printf 'RESULT: %d passed, %d failed\n' "$PASS" "$FAIL"
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user