From ef0926ed33d96747e4f92311e74737421facda57 Mon Sep 17 00:00:00 2001
From: "J. Kirby Ross" <james@flyingrobots.dev>
Date: Sat, 1 Nov 2025 17:15:36 -0700
Subject: [PATCH 1/3] hotfix(ci/docs): deterministic docs rollup check

- CI: normalize 'Generated:' header lines before diff to avoid false failures on older branches
- Docs: record hotfix in execution plan + decision log
- Rollup: regenerated (no functional changes)
---
 .github/workflows/echo-total-check.yml | 12 ++++++++++--
 docs/decision-log.md                   |  6 ++++++
 docs/echo-total.md                     |  9 +++++++++
 docs/execution-plan.md                 |  3 +++
 4 files changed, 28 insertions(+), 2 deletions(-)

diff --git a/.github/workflows/echo-total-check.yml b/.github/workflows/echo-total-check.yml
index f3ffeeee..dabd3418 100644
--- a/.github/workflows/echo-total-check.yml
+++ b/.github/workflows/echo-total-check.yml
@@ -18,8 +18,16 @@ jobs:
       - name: Fail if echo-total.md changed
         run: |
           set -euo pipefail
-          if ! git diff --quiet -- docs/echo-total.md; then
+          tmp=$(mktemp -d)
+          # Save the committed rollup from HEAD and the just-regenerated one
+          git show HEAD:docs/echo-total.md > "$tmp/before.md" || true
+          cp docs/echo-total.md "$tmp/after.md"
+          # Normalize known non-deterministic headers if they appear in older branches
+          # (e.g., lines beginning with 'Generated:').
+          sed -E '/^Generated:/d' "$tmp/before.md" > "$tmp/before.norm" || true
+          sed -E '/^Generated:/d' "$tmp/after.md"  > "$tmp/after.norm"  || true
+          if ! diff -u "$tmp/before.norm" "$tmp/after.norm" >/dev/null; then
             echo "docs/echo-total.md is out of date. Run 'make echo-total' (or scripts/gen-echo-total.sh) and commit the result." >&2
-            git --no-pager diff -- docs/echo-total.md || true
+            diff -u "$tmp/before.norm" "$tmp/after.norm" || true
             exit 1
           fi
diff --git a/docs/decision-log.md b/docs/decision-log.md
index 8866f1e1..bd2ff2d3 100644
--- a/docs/decision-log.md
+++ b/docs/decision-log.md
@@ -158,3 +158,9 @@ The following entries use a heading + bullets format for richer context.
 - Context: PR‑10 (README/CI/docs) accidentally included commit header tests in `snapshot.rs`, overlapping with PR‑09 (tests‑only).
 - Decision: Remove the test module from PR‑10 to keep it strictly docs/CI/tooling; keep all BLAKE3 commit header tests in PR‑09 (`echo/pr-09-blake3-header-tests`).
 - Consequence: Clear PR boundaries; no runtime behavior change in PR‑10.
+
+## 2025-11-02 — Hotfix: CI docs rollup determinism
+
+- Context: CI rollup job failed on branches where `scripts/gen-echo-total.sh` previously wrote a timestamp header, causing `git diff` to always differ.
+- Decision: Update `.github/workflows/echo-total-check.yml` to normalize out `Generated:` lines before diffing, making the check deterministic across old/new rollup formats.
+- Consequence: No more false failures; contributors still run `make echo-total` locally when docs change.
diff --git a/docs/echo-total.md b/docs/echo-total.md
index 47b271de..dbbde621 100644
--- a/docs/echo-total.md
+++ b/docs/echo-total.md
@@ -529,6 +529,9 @@ Populate with concrete tasks in priority order. When you start one, move it to 
 - When finishing a milestone, snapshot the diagrams and link them in the memorial for posterity.
 
 Remember: every entry here shrinks temporal drift between Codices. Leave breadcrumbs; keep Echo’s spine alive. 🌀
+> 2025-11-02 — Hotfix: deterministic rollup check (CI)
+
+- Made CI rollup check robust against legacy non-deterministic headers by normalizing out lines starting with `Generated:` before comparing. Current generator emits a stable header, but this guards older branches and avoids false negatives.
 
 
 ---
@@ -697,6 +700,12 @@ The following entries use a heading + bullets format for richer context.
 - Decision: Remove the test module from PR‑10 to keep it strictly docs/CI/tooling; keep all BLAKE3 commit header tests in PR‑09 (`echo/pr-09-blake3-header-tests`).
 - Consequence: Clear PR boundaries; no runtime behavior change in PR‑10.
 
+## 2025-11-02 — Hotfix: CI docs rollup determinism
+
+- Context: CI rollup job failed on branches where `scripts/gen-echo-total.sh` previously wrote a timestamp header, causing `git diff` to always differ.
+- Decision: Update `.github/workflows/echo-total-check.yml` to normalize out `Generated:` lines before diffing, making the check deterministic across old/new rollup formats.
+- Consequence: No more false failures; contributors still run `make echo-total` locally when docs change.
+
 
 ---
 
diff --git a/docs/execution-plan.md b/docs/execution-plan.md
index 1947e48e..c6be071a 100644
--- a/docs/execution-plan.md
+++ b/docs/execution-plan.md
@@ -302,3 +302,6 @@ Populate with concrete tasks in priority order. When you start one, move it to 
 - When finishing a milestone, snapshot the diagrams and link them in the memorial for posterity.
 
 Remember: every entry here shrinks temporal drift between Codices. Leave breadcrumbs; keep Echo’s spine alive. 🌀
+> 2025-11-02 — Hotfix: deterministic rollup check (CI)
+
+- Made CI rollup check robust against legacy non-deterministic headers by normalizing out lines starting with `Generated:` before comparing. Current generator emits a stable header, but this guards older branches and avoids false negatives.

From e509efde127a6b8a6880a7635fde8a11cf22801d Mon Sep 17 00:00:00 2001
From: "J. Kirby Ross" <james@flyingrobots.dev>
Date: Sat, 1 Nov 2025 17:28:40 -0700
Subject: [PATCH 2/3] hotfix(ci/docs): tighten rollup normalization to
 header-only + GH annotation

- Normalize only header-region lines matching ^\s*[Gg]enerated(\s*(:|at:|by:))? to avoid deleting arbitrary content
- Add GitHub Actions ::error annotation for clearer diagnostics
- Log follow-up in execution plan and decision log
- Regenerate rollup
---
 .github/workflows/echo-total-check.yml | 22 ++++++++++++++++++----
 docs/decision-log.md                   |  5 +++++
 docs/echo-total.md                     |  9 +++++++++
 docs/execution-plan.md                 |  4 ++++
 4 files changed, 36 insertions(+), 4 deletions(-)

diff --git a/.github/workflows/echo-total-check.yml b/.github/workflows/echo-total-check.yml
index dabd3418..a77a77cf 100644
--- a/.github/workflows/echo-total-check.yml
+++ b/.github/workflows/echo-total-check.yml
@@ -22,11 +22,25 @@ jobs:
           # Save the committed rollup from HEAD and the just-regenerated one
           git show HEAD:docs/echo-total.md > "$tmp/before.md" || true
           cp docs/echo-total.md "$tmp/after.md"
-          # Normalize known non-deterministic headers if they appear in older branches
-          # (e.g., lines beginning with 'Generated:').
-          sed -E '/^Generated:/d' "$tmp/before.md" > "$tmp/before.norm" || true
-          sed -E '/^Generated:/d' "$tmp/after.md"  > "$tmp/after.norm"  || true
+          # Normalize header-only legacy lines: remove only in the header region
+          # (from file start up to the first blank line) lines that match
+          #   ^\s*[Gg]enerated(\s*(:|at:|by:))?
+          # This avoids deleting arbitrary occurrences deeper in the document.
+          normalize_header() {
+            awk '
+              BEGIN { in_header=1 }
+              {
+                if (in_header) {
+                  if ($0 ~ /^[[:space:]]*$/) { in_header=0; print; next }
+                  if ($0 ~ /^[[:space:]]*[Gg]enerated([[:space:]]*(:|at:|by:))?/) next; else print
+                } else { print }
+              }
+            ' "$1"
+          }
+          normalize_header "$tmp/before.md" > "$tmp/before.norm" || true
+          normalize_header "$tmp/after.md"  > "$tmp/after.norm"  || true
           if ! diff -u "$tmp/before.norm" "$tmp/after.norm" >/dev/null; then
+            echo "::error file=docs/echo-total.md,line=1,col=1::docs/echo-total.md is out of date. Run 'make echo-total' (or scripts/gen-echo-total.sh) and commit the result." >&2
             echo "docs/echo-total.md is out of date. Run 'make echo-total' (or scripts/gen-echo-total.sh) and commit the result." >&2
             diff -u "$tmp/before.norm" "$tmp/after.norm" || true
             exit 1
diff --git a/docs/decision-log.md b/docs/decision-log.md
index bd2ff2d3..78c396f9 100644
--- a/docs/decision-log.md
+++ b/docs/decision-log.md
@@ -164,3 +164,8 @@ The following entries use a heading + bullets format for richer context.
 - Context: CI rollup job failed on branches where `scripts/gen-echo-total.sh` previously wrote a timestamp header, causing `git diff` to always differ.
 - Decision: Update `.github/workflows/echo-total-check.yml` to normalize out `Generated:` lines before diffing, making the check deterministic across old/new rollup formats.
 - Consequence: No more false failures; contributors still run `make echo-total` locally when docs change.
+
+## 2025-11-02 — Hotfix follow-up: tighter normalization + annotations
+
+- Decision: Limit normalization to the header region only and accept case/whitespace/legacy variants (`Generated:`, `generated at:`, `Generated by:`). Emit a GitHub Actions `::error` annotation targeting `docs/echo-total.md` when differences remain to improve diagnostics.
+- Consequence: Clearer CI failures; minimal, targeted normalization avoids masking content issues.
diff --git a/docs/echo-total.md b/docs/echo-total.md
index dbbde621..fb564b44 100644
--- a/docs/echo-total.md
+++ b/docs/echo-total.md
@@ -533,6 +533,10 @@ Remember: every entry here shrinks temporal drift between Codices. Leave breadcr
 
 - Made CI rollup check robust against legacy non-deterministic headers by normalizing out lines starting with `Generated:` before comparing. Current generator emits a stable header, but this guards older branches and avoids false negatives.
 
+> 2025-11-02 — Hotfix follow-up: tighter normalization + annotation
+
+- CI normalization now only removes `Generated` header lines in the top-of-file header block (from start to first blank line) and tolerates whitespace/case variants and legacy forms like `Generated:`, `generated at:`, `Generated by:`. Added a GitHub Actions annotation on failure to point directly at `docs/echo-total.md`.
+
 
 ---
 
@@ -706,6 +710,11 @@ The following entries use a heading + bullets format for richer context.
 - Decision: Update `.github/workflows/echo-total-check.yml` to normalize out `Generated:` lines before diffing, making the check deterministic across old/new rollup formats.
 - Consequence: No more false failures; contributors still run `make echo-total` locally when docs change.
 
+## 2025-11-02 — Hotfix follow-up: tighter normalization + annotations
+
+- Decision: Limit normalization to the header region only and accept case/whitespace/legacy variants (`Generated:`, `generated at:`, `Generated by:`). Emit a GitHub Actions `::error` annotation targeting `docs/echo-total.md` when differences remain to improve diagnostics.
+- Consequence: Clearer CI failures; minimal, targeted normalization avoids masking content issues.
+
 
 ---
 
diff --git a/docs/execution-plan.md b/docs/execution-plan.md
index c6be071a..22b7eaab 100644
--- a/docs/execution-plan.md
+++ b/docs/execution-plan.md
@@ -305,3 +305,7 @@ Remember: every entry here shrinks temporal drift between Codices. Leave breadcr
 > 2025-11-02 — Hotfix: deterministic rollup check (CI)
 
 - Made CI rollup check robust against legacy non-deterministic headers by normalizing out lines starting with `Generated:` before comparing. Current generator emits a stable header, but this guards older branches and avoids false negatives.
+
+> 2025-11-02 — Hotfix follow-up: tighter normalization + annotation
+
+- CI normalization now only removes `Generated` header lines in the top-of-file header block (from start to first blank line) and tolerates whitespace/case variants and legacy forms like `Generated:`, `generated at:`, `Generated by:`. Added a GitHub Actions annotation on failure to point directly at `docs/echo-total.md`.

From fc60fb924c49e3e2783f4684f6e3a7b32dc42e6e Mon Sep 17 00:00:00 2001
From: "J. Kirby Ross" <james@flyingrobots.dev>
Date: Sat, 1 Nov 2025 17:40:55 -0700
Subject: [PATCH 3/3] ci(docs): include 'on:' variant in rollup header
 normalization; regenerate rollup

---
 .github/workflows/echo-total-check.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.github/workflows/echo-total-check.yml b/.github/workflows/echo-total-check.yml
index a77a77cf..042d06b9 100644
--- a/.github/workflows/echo-total-check.yml
+++ b/.github/workflows/echo-total-check.yml
@@ -32,7 +32,7 @@ jobs:
               {
                 if (in_header) {
                   if ($0 ~ /^[[:space:]]*$/) { in_header=0; print; next }
-                  if ($0 ~ /^[[:space:]]*[Gg]enerated([[:space:]]*(:|at:|by:))?/) next; else print
+                  if ($0 ~ /^[[:space:]]*[Gg]enerated([[:space:]]*(:|at:|by:|on:))?/) next; else print
                 } else { print }
               }
             ' "$1"
