From 9314d9fb4a5c18a8cc1f3d50b230cdb323f06ba8 Mon Sep 17 00:00:00 2001 From: Aaron Stainback Date: Wed, 29 Apr 2026 06:53:55 -0400 Subject: [PATCH 1/5] fix(active-trajectory): binary direction split + NUL-safe parsing + lease-rejected-after-dry-run message + deferred-follow-up list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Multi-AI review 2026-04-29T10:50Z packet (Amara + Claude.ai + Deepseek + Gemini + Ani convergent) added five corrections: 1. **Binary ledger split by direction** (Amara): the prior version counted `binary_modified_files` direction-agnostic, which conflated "would be erased on hard-reset" with "would be added on hard- reset." Replaced with three buckets: binary_acehack_only_files (status A → ERASED on hard-reset) binary_lfg_only_files (status D → ADDED on hard-reset; not loss) binary_modified_or_renamed_files (M/R/T → needs semantic classification) 2. **NUL-safe parsing** (Amara): replaced the Bash-only process- substitution helper with a two-pass numstat -z + name-status -z pipeline that handles paths with spaces / odd characters and doesn't depend on Bash >= 4 process substitution. 3. **Lease-rejected-after-dry-run message** (Claude.ai + Amara): when dry-run succeeds and the real push rejects the lease, the operator's first hypothesis should be "remote moved between dry- run and push" (expected; lease did its job), not "lease syntax wrong" (would lead to debugging the wrong layer). Added explicit message to the failure branch. 4. **Gate updated**: replaced `binary_acehack_only_files = 0 (binary files exist only on LFG, OR each binary file has been classified)` with the cleaner two-condition form: binary_acehack_only_files = 0 (would be ERASED) binary_modified_or_renamed_classified = all (each SAFE or FORWARD-SYNC) 5. **Deferred-follow-up list added** (Claude.ai + Amara). Four items captured for visibility, NOT blocking 0/0/0: - Gate-runner script (`tools/zero-zero-zero/check-gate.sh`) - Self-reference rule for personas in operational specs (Otto-too) - LOST recovery deferred-with-stated-condition predicate format - Dry-run + real-push as one operator-approved unit + timestamp capture Best blade (Amara): "Text lines can be counted. Binary files must be classified. The gate clears only what the ledger can prove." Co-Authored-By: Claude Opus 4.7 --- docs/active-trajectory.md | 108 ++++++++++++++++++++++++++------------ 1 file changed, 74 insertions(+), 34 deletions(-) diff --git a/docs/active-trajectory.md b/docs/active-trajectory.md index 332fd3dd0..a405e88c1 100644 --- a/docs/active-trajectory.md +++ b/docs/active-trajectory.md @@ -105,36 +105,61 @@ Best blade (Amara): *"Line-count dominance is a smoke detector. Content equivale The drift trajectory is a metric; the GATE is the ledger. Hand-counts drift; ledgers from `git diff --numstat` don't. +The ledger is computed in two passes (text via `numstat`, binary direction via `name-status`) and joined NUL-safely. Per multi-AI review 2026-04-29T10:50Z: binary files emit `-/-` in `numstat` because lines aren't countable, but they CAN be erased on hard-reset, so they need direction classification — `acehack-only` vs `lfg-only` vs `modified-on-both`. + ```bash -git diff --numstat origin/main..acehack/main | awk ' - # Binary files: numstat emits "-\t-\t". They have no countable lines, - # but content can still be lost on hard-reset. Count them separately so - # they require explicit classification rather than being silently dropped. - $1 == "-" && $2 == "-" { - binary_files += 1 - next - } - { - add += $1; del += $2; files += 1 - if ($1 == 0) zero_files += 1 - } - END { - print "text_modified_files=" files - print "zero_acehack_only_files=" zero_files - print "potential_loss_lines=" add - print "lfg_newer_lines=" del - print "binary_modified_files=" (binary_files+0) - if ((binary_files+0) > 0) { - print "WARNING: binary files in diff need separate classification (lines uncountable)." - print "Run: git diff --name-status origin/main..acehack/main | awk '\''$1!~/^[D]$/'\'' | grep -F -f <(git diff --numstat origin/main..acehack/main | awk '\''$1==\"-\"{print $3}'\'')" - } - } -' +# Pass 1: text files (numstat reports lines) +git diff --numstat -z origin/main..acehack/main \ + | awk -v RS='\0' ' + $1 != "-" && $2 != "-" { + add += $1; del += $2; files += 1 + if ($1 == 0) zero_files += 1 + } + END { + print "text_modified_files=" files + print "zero_acehack_only_text_files=" zero_files + print "potential_loss_lines=" add + print "lfg_newer_lines=" del + } + ' + +# Pass 2: binary files split by direction (name-status reports A/M/D/R/T) +# - "A" from AceHack-side perspective = AceHack-only (hard-reset ERASES) → loss-relevant +# - "D" from AceHack-side perspective = LFG-only (hard-reset ADDS) → not a loss +# - "M"/"R"/"T" = modified on both sides → needs semantic classification +git diff --numstat -z origin/main..acehack/main \ + | awk -v RS='\0' 'BEGIN{ORS="\0"} $1 == "-" && $2 == "-" { print $3 }' \ + > /tmp/binary-paths.nul +if [ -s /tmp/binary-paths.nul ]; then + git diff --name-status -z origin/main..acehack/main \ + | awk -v RS='\0' ' + # name-status with -z: statuspath or for renames statusoldnew + BEGIN{i=0} + {if (i==0) {st=$0; i=1} else {p=$0; print st "\t" p; i=0}} + ' \ + | grep -Ff /tmp/binary-paths.nul \ + | awk -F'\t' ' + $1=="A" { ace_only += 1 } + $1=="D" { lfg_only += 1 } + $1 ~ /^[MRTC]/ { modified_both += 1 } + END { + print "binary_acehack_only_files=" (ace_only+0) + print "binary_lfg_only_files=" (lfg_only+0) + print "binary_modified_or_renamed_files=" (modified_both+0) + } + ' +fi ``` -Per Codex 2026-04-29T10:42Z catch (PR #835): the prior version of this script silently excluded binary files via `$1 != "-" && $2 != "-"`. `git diff --numstat` emits `-/-` for binary content because it can't count lines, but binary files CAN still be erased on hard-reset. New version counts them separately and surfaces a warning when present. +Per Codex 2026-04-29T10:42Z catch + Amara 2026-04-29T10:50Z direction-split: the prior one-pass version silently excluded binary files via `$1 != "-" && $2 != "-"`. v2 counts binary direction separately and uses `-z` NUL-safe parsing throughout (handles paths with spaces / odd chars). + +**Reset-loss surface for binary files:** + +- `binary_acehack_only_files` → would be ERASED on hard-reset; this is the gate-relevant count. +- `binary_lfg_only_files` → would be ADDED on hard-reset; not a loss. +- `binary_modified_or_renamed_files` → exists on both with content/mode/path differences; needs semantic classification (e.g., is the AceHack version more correct, or is LFG's the canonical?). -Verified 2026-04-29T10:43Z: the 5 binary-classified files in the current diff are all LFG-only (status `D` from AceHack perspective; hard-reset ADDS them, doesn't erase AceHack content), so this specific instance has zero binary-loss surface. The script fix is for general correctness. +Verified 2026-04-29T10:43Z: the 5 binary-classified files in the current diff have status `D` (LFG-only), so `binary_acehack_only_files = 0` and `binary_modified_or_renamed_files = 0` in this specific round. Current ledger (computed 2026-04-29T10:25Z): @@ -150,14 +175,15 @@ unclassified_lines = 176 HEURISTIC_LFG_DOMINATES — pending per-file sema Hard-reset is signoff-eligible ONLY when: ```text -unclassified_lines = 0 -unsafe_lines = 0 -binary_acehack_only_files = 0 (binary files exist only on LFG, OR each binary file has been classified) -fresh-clone fsck = clean -hard-reset preflight = clean -ls-remote-vs-fetch SHA match = verified -dry-run push shape = clean -maintainer signoff = yes +unclassified_lines = 0 +unsafe_lines = 0 +binary_acehack_only_files = 0 (would be ERASED on hard-reset) +binary_modified_or_renamed_classified = all (each must be SAFE_TO_RESET_LFG_SUPERSEDES or NEEDS_FORWARD_SYNC) +fresh-clone fsck = clean +hard-reset preflight = clean +ls-remote-vs-fetch SHA match = verified +dry-run push shape = clean +maintainer signoff = yes ``` Per multi-AI review 2026-04-29T10:35Z: dry-run push shape verification is added to the gate. Validates refspec + credentials + push shape before the real destructive operation. The real lease still matters at the real push (server-side check); dry-run is an additive safety check, not a replacement. @@ -358,6 +384,15 @@ A peer-call to Grok this session reported the inverse claim ("AceHack has the se **Hard-reset is NOT YET signoff-eligible.** The strict gate above requires `unclassified_lines = 0`, and the current ledger says `unclassified_lines = 176` (18 files in HEURISTIC_LFG_DOMINATES). The next agent-owned work is per-file semantic inspection of those 18 files to either promote each to SAFE_TO_RESET_LFG_SUPERSEDES (with named evidence) or downgrade to NEEDS_FORWARD_SYNC. +### Deferred follow-ups (NOT blocking 0/0/0 progress, captured for visibility) + +Per multi-AI review 2026-04-29T10:50Z packet: + +- **Gate-runner script**: build `tools/zero-zero-zero/check-gate.sh` that emits a machine-readable summary of all 9 gate conditions and fails closed. Replaces the prose ledger with a verifiable-by-execution gate. Otherwise the conditions can drift via hand-edit. +- **Self-reference rule for personas in operational specs**: "Otto" is a named identity in the substrate. Should references to "Otto" in reusable operational specs follow the same role-vs-name rule as references to "Aaron" / "Amara"? Probably yes. Capture in `docs/AGENT-BEST-PRACTICES.md` extension. +- **LOST recovery soft-trigger predicate format**: "deferred with stated condition" needs a verifiable predicate that auto-resurfaces the work for resume/retire decision when the condition becomes true. Example shape: `"deferred until: (B-0105 lands) AND (no consolidation work is active)"`. +- **Time-gap between dry-run and real push**: structure the destructive sequence so dry-run + real push run as one operator-approved unit, not two separate decisions. Capture timestamps for both for any post-incident analysis. + State summary: - 9 infra files: SAFE_TO_RESET_LFG_SUPERSEDES (6 files, 97 lines, named evidence) or ALREADY_RESOLVED (3 files, 0 lines, identical content). @@ -424,6 +459,11 @@ Remaining steps to clear the gate: refs/remotes/origin/main:refs/heads/main then echo "LEASE REJECTED: acehack/main moved or expectation stale." + echo "" + echo "If dry-run succeeded above and real push rejected: the remote moved" + echo "between dry-run and push. This is EXPECTED behavior — the lease did" + echo "its job. The fix is NOT to debug syntax." + echo "" echo "DO NOT RETRY BLINDLY. Re-fetch, recompute content-drift ledger," echo "and re-enter the signoff gate from the top." exit 1 From e17c5ca0fae1a4edfc6309cc5c7cf12aeb564745 Mon Sep 17 00:00:00 2001 From: Aaron Stainback Date: Wed, 29 Apr 2026 07:08:10 -0400 Subject: [PATCH 2/5] fix(active-trajectory): soften 'NUL-safe' overclaim + flag inline snippet as illustrative + bump gate-runner priority Multi-AI review 2026-04-29T11:05Z (Codex P1 cluster + Copilot 5-thread cluster + Amara): my prior commit overclaimed "NUL-safe parsing throughout" while the inline awk/grep snippet has real bugs: - awk $3 with default whitespace FS breaks on paths with spaces - grep -Ff reads newline-delimited, not NUL-delimited - numstat -z rename/copy records are addsdels/dev/null oldnew (extra NUL fields), not one-row-per-NUL - name-status -z rename/copy rows are statusoldnew (3 fields), not the 2-field shape my parser assumed; the toggle parser desynchronizes on first rename - RS='\0' / ORS='\0' is a gawk extension; BSD awk (macOS default) lacks it - /tmp/binary-paths.nul fixed path; no mktemp + trap cleanup The CONCEPTUAL fix (split binary direction into 3 buckets) is correct and stays. The IMPLEMENTATION is now explicitly marked illustrative- only with a warning block enumerating each bug. The durable home is `tools/zero-zero-zero/check-gate.sh` (deferred follow-up, bumped to highest priority among deferred items). Stopgap rule added for this round: if binary_modified_files is non-zero, classify direction manually via `git diff --name-status -z` per file + direct `git show` evidence. Do NOT rely on the inline snippet. Best blade (Amara): "The binary hole is found. The gate condition is right. The parser still needs teeth." This addresses 7 of the 8 unresolved review threads on this PR. Thread 8 (persona names in current-state doc) is already addressed by the maintainer 2026-04-29T10:30Z classification call recorded in the file's header (history surface, not current-state). Co-Authored-By: Claude Opus 4.7 --- docs/active-trajectory.md | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/docs/active-trajectory.md b/docs/active-trajectory.md index a405e88c1..cd5d3144a 100644 --- a/docs/active-trajectory.md +++ b/docs/active-trajectory.md @@ -105,7 +105,20 @@ Best blade (Amara): *"Line-count dominance is a smoke detector. Content equivale The drift trajectory is a metric; the GATE is the ledger. Hand-counts drift; ledgers from `git diff --numstat` don't. -The ledger is computed in two passes (text via `numstat`, binary direction via `name-status`) and joined NUL-safely. Per multi-AI review 2026-04-29T10:50Z: binary files emit `-/-` in `numstat` because lines aren't countable, but they CAN be erased on hard-reset, so they need direction classification — `acehack-only` vs `lfg-only` vs `modified-on-both`. +The ledger is computed in two passes (text via `numstat`, binary direction via `name-status`). Per multi-AI review 2026-04-29T10:50Z: binary files emit `-/-` in `numstat` because lines aren't countable, but they CAN be erased on hard-reset, so they need direction classification — `acehack-only` vs `lfg-only` vs `modified-on-both`. + +**The shell snippet below is ILLUSTRATIVE, NOT DURABLE.** Per multi-AI review 2026-04-29T11:05Z (Codex + Copilot 7-thread cluster + Amara): the inline awk/grep approach below has real NUL-safety bugs and is not portable across awk implementations: + +- `awk $3` with default whitespace FS breaks on paths with spaces (need `FS='\t'`). +- `grep -Ff` reads newline-delimited patterns, not NUL-delimited (the `ORS="\0"` write doesn't compose with `grep -f`). +- `numstat -z` rename/copy records are `addsdelsNUL oldnew`, not just one NUL-delimited row. +- `name-status -z` rename/copy rows are `statusoldnew` (3 fields), not `statuspath` (2 fields). The toggle parser desynchronizes. +- `RS='\0'` / `ORS='\0'` is a gawk extension; macOS BSD awk doesn't support it. +- `/tmp/binary-paths.nul` is a fixed path with no `mktemp` + `trap` cleanup; clobber-prone under concurrency. + +The durable home for the gate-runner is `tools/zero-zero-zero/check-gate.sh` (deferred follow-up, see "Deferred follow-ups" below). That script must be tested against fixtures including: paths with spaces, binary add, binary delete, binary modify, binary rename, binary copy, gawk-vs-BSD-awk. + +**Stopgap rule for this round**: if `binary_modified_files` is non-zero in this ledger, do NOT rely on the inline snippet to classify direction. Use `git diff --name-status -z origin/main..acehack/main -- ` per binary file + direct `git show` evidence, manually, until the gate-runner script exists. ```bash # Pass 1: text files (numstat reports lines) @@ -151,7 +164,7 @@ if [ -s /tmp/binary-paths.nul ]; then fi ``` -Per Codex 2026-04-29T10:42Z catch + Amara 2026-04-29T10:50Z direction-split: the prior one-pass version silently excluded binary files via `$1 != "-" && $2 != "-"`. v2 counts binary direction separately and uses `-z` NUL-safe parsing throughout (handles paths with spaces / odd chars). +Per Codex 2026-04-29T10:42Z catch + Amara 2026-04-29T10:50Z direction-split: the prior one-pass version silently excluded binary files via `$1 != "-" && $2 != "-"`. The conceptual fix (split direction into three buckets) is correct. The inline implementation above is illustrative only — see the warning block above this code; the durable NUL-safe + portable implementation lives in the deferred gate-runner script. **Reset-loss surface for binary files:** @@ -388,7 +401,7 @@ A peer-call to Grok this session reported the inverse claim ("AceHack has the se Per multi-AI review 2026-04-29T10:50Z packet: -- **Gate-runner script**: build `tools/zero-zero-zero/check-gate.sh` that emits a machine-readable summary of all 9 gate conditions and fails closed. Replaces the prose ledger with a verifiable-by-execution gate. Otherwise the conditions can drift via hand-edit. +- **Gate-runner script** (now bumped to highest priority among deferred follow-ups): build `tools/zero-zero-zero/check-gate.sh` that emits a machine-readable summary of all 9 gate conditions and fails closed. Replaces the prose ledger AND the illustrative inline snippet above with a verifiable-by-execution gate. Per multi-AI review 2026-04-29T11:05Z (Codex P1 + Copilot 5 threads + Amara): the durable script must be tested against fixtures: paths with spaces, binary add, binary delete, binary modify, binary rename, binary copy, gawk-vs-BSD-awk portability, `mktemp` + `trap` cleanup. Until the script lands, binary direction MUST be classified manually via `git diff --name-status -z` per file + direct `git show` evidence. Best blade (Amara): *"The binary hole is found. The gate condition is right. The parser still needs teeth."* - **Self-reference rule for personas in operational specs**: "Otto" is a named identity in the substrate. Should references to "Otto" in reusable operational specs follow the same role-vs-name rule as references to "Aaron" / "Amara"? Probably yes. Capture in `docs/AGENT-BEST-PRACTICES.md` extension. - **LOST recovery soft-trigger predicate format**: "deferred with stated condition" needs a verifiable predicate that auto-resurfaces the work for resume/retire decision when the condition becomes true. Example shape: `"deferred until: (B-0105 lands) AND (no consolidation work is active)"`. - **Time-gap between dry-run and real push**: structure the destructive sequence so dry-run + real push run as one operator-approved unit, not two separate decisions. Capture timestamps for both for any post-incident analysis. From d2bf214a631514b887ed2823bb707c8a23a54b04 Mon Sep 17 00:00:00 2001 From: Aaron Stainback Date: Wed, 29 Apr 2026 07:12:06 -0400 Subject: [PATCH 3/5] fix(active-trajectory): stopgap rule references new binary metric names MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Codex P1 catch — internal inconsistency: stopgap rule cited the OLD metric name 'binary_modified_files' that the rewritten script no longer emits. Fixed to reference the new gate-relevant metrics (binary_acehack_only_files OR binary_modified_or_renamed_files). Also clarified that binary_lfg_only_files is NOT a stopgap trigger (LFG-only files get ADDED on hard-reset; no AceHack content lost). Co-Authored-By: Claude Opus 4.7 --- docs/active-trajectory.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/active-trajectory.md b/docs/active-trajectory.md index cd5d3144a..37b63e314 100644 --- a/docs/active-trajectory.md +++ b/docs/active-trajectory.md @@ -118,7 +118,7 @@ The ledger is computed in two passes (text via `numstat`, binary direction via ` The durable home for the gate-runner is `tools/zero-zero-zero/check-gate.sh` (deferred follow-up, see "Deferred follow-ups" below). That script must be tested against fixtures including: paths with spaces, binary add, binary delete, binary modify, binary rename, binary copy, gawk-vs-BSD-awk. -**Stopgap rule for this round**: if `binary_modified_files` is non-zero in this ledger, do NOT rely on the inline snippet to classify direction. Use `git diff --name-status -z origin/main..acehack/main -- ` per binary file + direct `git show` evidence, manually, until the gate-runner script exists. +**Stopgap rule for this round**: if either `binary_acehack_only_files > 0` OR `binary_modified_or_renamed_files > 0` in this ledger (the two gate-relevant binary metrics emitted by the new script), do NOT rely on the inline snippet to classify direction. Use `git diff --name-status -z origin/main..acehack/main -- ` per binary file + direct `git show` evidence, manually, until the gate-runner script exists. (`binary_lfg_only_files > 0` is NOT a stopgap trigger — LFG-only files get added on hard-reset; no AceHack content lost.) ```bash # Pass 1: text files (numstat reports lines) From 52d8e03971e75858f1aa7e465b93ba672f0c1ed6 Mon Sep 17 00:00:00 2001 From: Aaron Stainback Date: Wed, 29 Apr 2026 07:22:04 -0400 Subject: [PATCH 4/5] fix(active-trajectory): remove broken inline shell snippet entirely Multi-AI review (Codex P0 + Copilot 5-thread cluster) on PR #836 stayed unresolved on the inline binary-direction shell parser even after I marked it 'ILLUSTRATIVE, NOT DURABLE'. The reviewer's position is correct: an illustrative-but-broken parser left in a load-bearing doc encourages copy-paste use of code with 6 known bugs (awk default-FS path-with-spaces breakage, grep -Ff not NUL-aware, name-status -z rename-record desync, gawk-only RS, fixed /tmp path not race-safe, lfg-only-vs-modified misclassification). The disclaimer was less effective than the bugs. Removed the snippet entirely; replaced with prose pointing at: 1. The "Stopgap rule" above for binary classification this round 2. The deferred gate-runner script (tools/zero-zero-zero/check-gate.sh) as the durable home The conceptual structure (3 binary buckets) remains. The text-file ledger is straightforward enough that the prose description suffices. Re-armed auto-merge (was disarmed during this iteration). Submit- nuget CI failure is a transient GitHub API 5xx (same shape as prior github 502 incidents); will rerun the failed job. Co-Authored-By: Claude Opus 4.7 --- docs/active-trajectory.md | 50 +++++---------------------------------- 1 file changed, 6 insertions(+), 44 deletions(-) diff --git a/docs/active-trajectory.md b/docs/active-trajectory.md index 37b63e314..45222ea6c 100644 --- a/docs/active-trajectory.md +++ b/docs/active-trajectory.md @@ -120,51 +120,13 @@ The durable home for the gate-runner is `tools/zero-zero-zero/check-gate.sh` (de **Stopgap rule for this round**: if either `binary_acehack_only_files > 0` OR `binary_modified_or_renamed_files > 0` in this ledger (the two gate-relevant binary metrics emitted by the new script), do NOT rely on the inline snippet to classify direction. Use `git diff --name-status -z origin/main..acehack/main -- ` per binary file + direct `git show` evidence, manually, until the gate-runner script exists. (`binary_lfg_only_files > 0` is NOT a stopgap trigger — LFG-only files get added on hard-reset; no AceHack content lost.) -```bash -# Pass 1: text files (numstat reports lines) -git diff --numstat -z origin/main..acehack/main \ - | awk -v RS='\0' ' - $1 != "-" && $2 != "-" { - add += $1; del += $2; files += 1 - if ($1 == 0) zero_files += 1 - } - END { - print "text_modified_files=" files - print "zero_acehack_only_text_files=" zero_files - print "potential_loss_lines=" add - print "lfg_newer_lines=" del - } - ' - -# Pass 2: binary files split by direction (name-status reports A/M/D/R/T) -# - "A" from AceHack-side perspective = AceHack-only (hard-reset ERASES) → loss-relevant -# - "D" from AceHack-side perspective = LFG-only (hard-reset ADDS) → not a loss -# - "M"/"R"/"T" = modified on both sides → needs semantic classification -git diff --numstat -z origin/main..acehack/main \ - | awk -v RS='\0' 'BEGIN{ORS="\0"} $1 == "-" && $2 == "-" { print $3 }' \ - > /tmp/binary-paths.nul -if [ -s /tmp/binary-paths.nul ]; then - git diff --name-status -z origin/main..acehack/main \ - | awk -v RS='\0' ' - # name-status with -z: statuspath or for renames statusoldnew - BEGIN{i=0} - {if (i==0) {st=$0; i=1} else {p=$0; print st "\t" p; i=0}} - ' \ - | grep -Ff /tmp/binary-paths.nul \ - | awk -F'\t' ' - $1=="A" { ace_only += 1 } - $1=="D" { lfg_only += 1 } - $1 ~ /^[MRTC]/ { modified_both += 1 } - END { - print "binary_acehack_only_files=" (ace_only+0) - print "binary_lfg_only_files=" (lfg_only+0) - print "binary_modified_or_renamed_files=" (modified_both+0) - } - ' -fi -``` +**The inline shell snippet was REMOVED 2026-04-29T11:20Z** per multi-AI review packet (Codex P0 + Copilot 5-thread cluster + Amara). Even with an "illustrative" disclaimer, a broken parser left in the doc encourages copy-paste use of code that has 6 known bugs (awk default-FS path-with-spaces breakage, `grep -Ff` not NUL-aware, name-status `-z` rename-record desync, gawk-only `RS='\0'`, fixed `/tmp/binary-paths.nul` not race-safe, missing semantic LFG-only-vs-modified distinction). + +The conceptual structure remains correct (three binary buckets — `acehack_only`, `lfg_only`, `modified_or_renamed`). The execution belongs in `tools/zero-zero-zero/check-gate.sh` as a real script with fixtures (paths with spaces, binary add/delete/modify/rename/copy, gawk-vs-BSD-awk portability, `mktemp` + `trap` cleanup). That script is the highest-priority deferred follow-up. + +**Until that script exists, classify binary files manually** (see "Stopgap rule" above): `git diff --name-status -z origin/main..acehack/main -- ` per binary file + direct `git show` evidence + manual bucket assignment. -Per Codex 2026-04-29T10:42Z catch + Amara 2026-04-29T10:50Z direction-split: the prior one-pass version silently excluded binary files via `$1 != "-" && $2 != "-"`. The conceptual fix (split direction into three buckets) is correct. The inline implementation above is illustrative only — see the warning block above this code; the durable NUL-safe + portable implementation lives in the deferred gate-runner script. +For the text-file ledger, the conceptual computation is straightforward: `git diff --numstat origin/main..acehack/main` reports added/removed line counts per file (with `-/-` for binary). Sum the non-binary rows for `potential_loss_lines` and `lfg_newer_lines`. The current round's verified text-ledger numbers (273 / 18046) were computed manually 2026-04-29T10:25Z and are recorded in the trajectory table above. **Reset-loss surface for binary files:** From 6d3d2b432c8ba51fddbe092a8198ccb09400a767 Mon Sep 17 00:00:00 2001 From: Aaron Stainback Date: Wed, 29 Apr 2026 07:28:17 -0400 Subject: [PATCH 5/5] fix(active-trajectory): gate splits binary-classified into 3 conditions (don't conflate 'classified' with 'safe') MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Codex P1 catch — real and important. The prior gate said 'binary_modified_or_renamed_classified = all' which only checked that classification HAPPENED. A binary file classified NEEDS_FORWARD_SYNC would satisfy that gate even though NEEDS_FORWARD_SYNC means content must be forward-synced FIRST. Fix: split the binary-modified-or-renamed condition into three: binary_modified_or_renamed_unclassified = 0 (verdict required) binary_files_needing_forward_sync = 0 (NEEDS_FORWARD_SYNC must complete sync first) binary_files_needing_human_decision = 0 (NEEDS_HUMAN_DECISION requires maintainer call) This mirrors the text-line gate structure (unclassified=0 AND unsafe=0) applied to binary files via direct file counts. Co-Authored-By: Claude Opus 4.7 --- docs/active-trajectory.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/active-trajectory.md b/docs/active-trajectory.md index 45222ea6c..6903dcb65 100644 --- a/docs/active-trajectory.md +++ b/docs/active-trajectory.md @@ -153,7 +153,9 @@ Hard-reset is signoff-eligible ONLY when: unclassified_lines = 0 unsafe_lines = 0 binary_acehack_only_files = 0 (would be ERASED on hard-reset) -binary_modified_or_renamed_classified = all (each must be SAFE_TO_RESET_LFG_SUPERSEDES or NEEDS_FORWARD_SYNC) +binary_modified_or_renamed_unclassified = 0 (each must have a classification verdict) +binary_files_needing_forward_sync = 0 (NEEDS_FORWARD_SYNC requires forward-sync FIRST) +binary_files_needing_human_decision = 0 (NEEDS_HUMAN_DECISION requires maintainer call) fresh-clone fsck = clean hard-reset preflight = clean ls-remote-vs-fetch SHA match = verified