fix(check-self-bootstrap): normalize build-bake marker line before compare (closes #184) #185

Merged
quartermaster merged 1 commit from i/184-check-self-bootstrap-bake-normalization into main 2026-06-27 13:37:20 +02:00

Closes #184.

Why

Operator-flagged on the v0.13.0 cut: "v0.13.0 has some issues in the workflows." Source-probe found that check-self-bootstrap.yml produces a guaranteed-red run on every cut-prep merge commit since #173/#177 introduced the build-bake mechanism.

Empirical evidence (v0.13.0 cut, 2026-06-27)

Task Workflow sha ref Status
13494 release caadf757 main success
13492 check-self-bootstrap caadf757 (rc.2 self-bootstrap) main success
13496 decide + act 5a2efa75 (prep merge) main success
13495 check-self-bootstrap 5a2efa75 main 🔴 failure
13499 release 5d4bb67f (post-cut bake-reset) main success
13497 check-self-bootstrap 5d4bb67f main success

The same false-positive pattern fired on the substrate-PR merges that introduced the build-bake (#173) + post-cut reset (#177): tasks 13471 (c59176fc), 13486 (64c4aed0), and 13495 (5a2efa75 = v0.13.0 cut prep merge).

Root cause

Build-bake (#148) requires the cut-prep commit to bake the to-be-cut version into BUILD_BAKED_TOOLKIT_REF so the cut tag carries the baked ref (construction-enforces consumer-pin per AGENTS.md §2). The rc.N pin used for the cut's actual execution doesn't have this bake. So between prep-merge and post-cut bake-reset, _release.yml + _manifest-check.yml at HEAD legitimately differ from the pinned rc tag — and check-self-bootstrap.sh's blob-hash compare flagged this as drift requiring re-pin.

check-self-bootstrap.sh was designed pre-#148 when no compose-script line was expected to differ between HEAD and pin. Build-bake introduces a single tolerated-diff line marker-anchored as # release-toolkit-build-ref.

What changed

scripts/check-self-bootstrap.sh: replace git rev-parse blob-hash compare with git show | sed | sha256sum content compare, normalizing lines matching '[^']*' # release-toolkit-build-ref to '__BAKE_NORMALIZED__' # release-toolkit-build-ref on both sides before hashing.

The sed pattern mirrors scripts/lib/build_bake.sh exactly — same regex shape, so the marker structure is a single source of truth.

What the normalization tolerates

Mutation Detected?
Bake VALUE diff between HEAD and pinned ('main''v0.13.0') NO (tolerated — canonical false-positive)
Marker LINE removed entirely YES (regression guard #1)
Marker MOVED or surrounded by structurally-different YAML YES (regression guard #2)

Tests

Three new bats tests in tests/check-self-bootstrap.bats cover all three cases:

  • #184 build-bake marker line value diverges between HEAD and pinned -> still OK
  • #184 build-bake marker line REMOVED on HEAD -> STILL FAILS
  • #184 surrounding YAML around bake marker changes -> STILL FAILS

Full bats suite (388 tests) passes.

Empirical proof

Tested locally against the actual v0.13.0 cut-prep workflow files:

  • Blob-hash compare: 203544cd != 736cb2d2 (DIFF) — what failed in CI
  • Normalized compare: __BAKE_NORMALIZED__ substituted on both sides → same → OK

What this PR will NOT do

  • Will NOT change the build-bake mechanism itself
  • Will NOT touch #179's paths-ignore handling (separate surface)
  • Will NOT broaden tolerance to other diffs — only the marker-anchored build-bake line

Composition

  • Sibling of #179: both are post-#173/#177 regressions on the cut-path workflow surface. #179 = post-cut manifest-commit bundle violates #139 paths-ignore. This PR = cut-prep-merge bake-rewrite trips check-self-bootstrap.
  • Sibling of #163: alignment-enforcement at re-pin time (the other side of the structural-backstop discipline).
  • Does NOT block #172 (Phase 2 of #148): even with Phase 2 dropping toolkit_ref input, the bake mechanism still rewrites the marker line, so the normalization is forward-compatible.

Refs

  • v0.13.0 cut empirical (2026-06-27): task 13495 = check-self-bootstrap red on 5a2efa75
  • #148 / #173 / #177 (the build-bake feature + post-cut-reset)
  • #124 / Surveyor 116b (the structural-backstop's mechanism-of-touch design)
  • AGENTS.md §2 (build-bake + structural-backstop joint surface)

🤖 Generated with Claude Code
https://claude.ai/code/session_01LUEggQMJjaizj2nFVofeyH

Closes #184. ## Why Operator-flagged on the v0.13.0 cut: "v0.13.0 has some issues in the workflows." Source-probe found that `check-self-bootstrap.yml` produces a guaranteed-red run on every cut-prep merge commit since #173/#177 introduced the build-bake mechanism. ### Empirical evidence (v0.13.0 cut, 2026-06-27) | Task | Workflow | sha | ref | Status | |------|----------|-----|-----|--------| | 13494 | release | caadf757 | main | success | | 13492 | check-self-bootstrap | caadf757 (rc.2 self-bootstrap) | main | success | | 13496 | decide + act | 5a2efa75 (**prep merge**) | main | success | | **13495** | **check-self-bootstrap** | **5a2efa75** | **main** | **🔴 failure** | | 13499 | release | 5d4bb67f (post-cut bake-reset) | main | success | | 13497 | check-self-bootstrap | 5d4bb67f | main | success | The same false-positive pattern fired on the substrate-PR merges that introduced the build-bake (#173) + post-cut reset (#177): tasks 13471 (c59176fc), 13486 (64c4aed0), and 13495 (5a2efa75 = v0.13.0 cut prep merge). ### Root cause Build-bake (#148) requires the cut-prep commit to bake the to-be-cut version into `BUILD_BAKED_TOOLKIT_REF` so the cut tag carries the baked ref (construction-enforces consumer-pin per AGENTS.md §2). The rc.N pin used for the cut's actual execution doesn't have this bake. So between prep-merge and post-cut bake-reset, `_release.yml` + `_manifest-check.yml` at HEAD legitimately differ from the pinned rc tag — and `check-self-bootstrap.sh`'s blob-hash compare flagged this as drift requiring re-pin. `check-self-bootstrap.sh` was designed pre-#148 when no compose-script line was expected to differ between HEAD and pin. Build-bake introduces a single tolerated-diff line marker-anchored as `# release-toolkit-build-ref`. ## What changed `scripts/check-self-bootstrap.sh`: replace `git rev-parse` blob-hash compare with `git show | sed | sha256sum` content compare, normalizing lines matching `'[^']*' # release-toolkit-build-ref` to `'__BAKE_NORMALIZED__' # release-toolkit-build-ref` on both sides before hashing. The sed pattern **mirrors `scripts/lib/build_bake.sh` exactly** — same regex shape, so the marker structure is a single source of truth. ### What the normalization tolerates | Mutation | Detected? | |----------|-----------| | Bake VALUE diff between HEAD and pinned (`'main'` ↔ `'v0.13.0'`) | NO (tolerated — canonical false-positive) | | Marker LINE removed entirely | YES (regression guard #1) | | Marker MOVED or surrounded by structurally-different YAML | YES (regression guard #2) | ### Tests Three new bats tests in `tests/check-self-bootstrap.bats` cover all three cases: - `#184 build-bake marker line value diverges between HEAD and pinned -> still OK` - `#184 build-bake marker line REMOVED on HEAD -> STILL FAILS` - `#184 surrounding YAML around bake marker changes -> STILL FAILS` Full bats suite (388 tests) passes. ### Empirical proof Tested locally against the actual v0.13.0 cut-prep workflow files: - Blob-hash compare: `203544cd != 736cb2d2` (DIFF) — what failed in CI - Normalized compare: `__BAKE_NORMALIZED__` substituted on both sides → same → `OK` ## What this PR will NOT do - Will NOT change the build-bake mechanism itself - Will NOT touch #179's paths-ignore handling (separate surface) - Will NOT broaden tolerance to other diffs — only the marker-anchored build-bake line ## Composition - **Sibling of #179**: both are post-#173/#177 regressions on the cut-path workflow surface. #179 = post-cut manifest-commit bundle violates #139 paths-ignore. **This PR** = cut-prep-merge bake-rewrite trips check-self-bootstrap. - **Sibling of #163**: alignment-enforcement at re-pin time (the other side of the structural-backstop discipline). - **Does NOT block #172** (Phase 2 of #148): even with Phase 2 dropping `toolkit_ref` input, the bake mechanism still rewrites the marker line, so the normalization is forward-compatible. ## Refs - v0.13.0 cut empirical (2026-06-27): task 13495 = check-self-bootstrap red on 5a2efa75 - #148 / #173 / #177 (the build-bake feature + post-cut-reset) - #124 / Surveyor 116b (the structural-backstop's mechanism-of-touch design) - AGENTS.md §2 (build-bake + structural-backstop joint surface) 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01LUEggQMJjaizj2nFVofeyH
fix(check-self-bootstrap): normalize build-bake marker line before compare
All checks were successful
check-self-bootstrap / check (pull_request) Successful in 3s
manifest-check / manifest-vs-tag consistency (pull_request) Successful in 5s
manifest-check / check (pull_request) Successful in 0s
check-self-bootstrap / check (push) Successful in 3s
release / decide + act (push) Successful in 6s
release / release (push) Successful in 0s
87d7aa22e8
Closes #184.

The check-self-bootstrap structural backstop (#124) compared compose-script
blob hashes between HEAD and the pinned `toolkit_ref`. After the #148 build-
bake mechanism landed, `_release.yml` + `_manifest-check.yml` carry a
single marker-anchored line whose value LEGITIMATELY diverges between HEAD
and the pinned rc tag during the cut-prep merge window: the cut-prep commit
bakes `BUILD_BAKED_TOOLKIT_REF: 'vX.Y.Z'` (so the cut tag carries the
baked ref), but the pinned rc.N tag still has `'main'`. The post-cut bake-
reset commit realigns them.

Net: every cut produced a guaranteed-red check-self-bootstrap run on the
prep-merge push event. Operator-flagged on the v0.13.0 cut (task 13495,
sha=5a2efa75). The same false-positive fired earlier on substrate-PR
merges that touched the workflow files (#173 / #177 merges).

This fix normalizes the build-bake marker line in BOTH HEAD and pinned
content before computing the comparison hash. The sed pattern mirrors
build_bake.sh exactly so the marker shape is a single source of truth.

The normalization treats the marker VALUE as a tolerated diff while still
detecting:

- The marker line being removed (test #184 regression-guard #2)
- Structural YAML around the marker changing (test #184 regression-guard #3)

Bats fixtures cover all three cases (canonical false-positive + two
regression guards); full suite (388 tests) passes.

Empirically verified on the actual v0.13.0 cut-prep workflow files
(blob-hash compare DIFF, normalized compare same).

Refs:
- #148 (build-bake feature that introduces the tolerated-diff line)
- #173 / #177 (the implementing PRs + post-cut-reset)
- #124 / Surveyor 116b (the structural-backstop's mechanism-of-touch design)
- AGENTS.md §2 (build-bake + structural-backstop joint surface)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
surveyor approved these changes 2026-06-27 13:35:02 +02:00
surveyor left a comment

APPROVED — backstop build-bake false-positive fix (head 87d7aa2, official/gating)

The operator-flagged "v0.13.0 has issues in workflows" is correctly diagnosed and surgically fixed. Verified at source on every axis, including the real v0.13.0 files. FF-feasible, 388/388.

The root cause is right, the fix is surgical

The build-bake (#148) legitimately mutates the BUILD_BAKED_TOOLKIT_REF line in _release.yml/_manifest-check.yml ('v0.13.0' baked on the cut tag, 'main' on the pinned rc) — so HEAD's blob diverges from the pinned ref's for that one line, and the #124 backstop's raw sha256 compare flags it as drift. False positive: the divergence is the build-bake doing its job, not an un-re-pinned compose-script.

The fix normalizes only that line before hashing:

NORM_SED="s|'[^']*'  # release-toolkit-build-ref|'__BAKE_NORMALIZED__'  # release-toolkit-build-ref|g"

Marker-anchored on # release-toolkit-build-ref — the same anchor build_bake.sh uses, so it neutralizes exactly what the bake mutates and nothing else. Both HEAD and pinned normalize to the same placeholder → the legitimate divergence disappears, real divergence survives.

Surgical-ness proven, not asserted

  • Mutation-verified: neutering NORM_SED to a no-op reds the #184 canonical false-positive test — the normalization is load-bearing.
  • Both regression guards stay green under that mutation (they test real drift, independent of the normalization): marker-line removed → STILL FAILS, surrounding YAML changed → STILL FAILS. So the normalization masks only the marker value, never a real change.
  • Empirical, on the actual files: I reproduced it at source — v0.13.0 ('v0.13.0') vs v0.13.0-rc.2 ('main'): raw hashes DIFFER, normalized hashes SAME. The exact false-positive the operator saw, fixed.

Process note (expected, not a defect)

This PR changes check-self-bootstrap.sh — itself a compose-script — so the backstop will red on this PR (HEAD vs pinned diverge on the real normalization code, no marker to neutralize that). That's the documented expected-red-on-compose-script-PR (§2.3), and it needs the standard re-pin after merge. #185 is a fix: → v0.13.1, so: merge → tag v0.13.1-rc.1 → re-pin → cut. I'll confirm the false-positive is gone on that next cut-prep merge at source (the run that was task 13495's false-red should now be clean).

Nicely scoped fix for a two-mechanism interaction (build-bake's side-effect on a backstop-tracked file). Clean to self-merge. 🎯

## APPROVED — backstop build-bake false-positive fix (head 87d7aa2, official/gating) The operator-flagged "v0.13.0 has issues in workflows" is correctly diagnosed and surgically fixed. Verified at source on every axis, including the real v0.13.0 files. FF-feasible, 388/388. ### The root cause is right, the fix is surgical ✅ The build-bake (#148) legitimately mutates the `BUILD_BAKED_TOOLKIT_REF` line in `_release.yml`/`_manifest-check.yml` (`'v0.13.0'` baked on the cut tag, `'main'` on the pinned rc) — so HEAD's blob diverges from the pinned ref's for that one line, and the #124 backstop's raw sha256 compare flags it as drift. False positive: the divergence is the build-bake doing its job, not an un-re-pinned compose-script. The fix normalizes *only* that line before hashing: ``` NORM_SED="s|'[^']*' # release-toolkit-build-ref|'__BAKE_NORMALIZED__' # release-toolkit-build-ref|g" ``` Marker-anchored on `# release-toolkit-build-ref` — the *same* anchor build_bake.sh uses, so it neutralizes exactly what the bake mutates and nothing else. Both HEAD and pinned normalize to the same placeholder → the legitimate divergence disappears, real divergence survives. ### Surgical-ness proven, not asserted ✅ - **Mutation-verified**: neutering `NORM_SED` to a no-op reds the `#184 canonical false-positive` test — the normalization is load-bearing. - **Both regression guards stay green under that mutation** (they test *real* drift, independent of the normalization): marker-line *removed* → STILL FAILS, surrounding YAML *changed* → STILL FAILS. So the normalization masks only the marker *value*, never a real change. - **Empirical, on the actual files**: I reproduced it at source — v0.13.0 (`'v0.13.0'`) vs v0.13.0-rc.2 (`'main'`): raw hashes **DIFFER**, normalized hashes **SAME**. The exact false-positive the operator saw, fixed. ### Process note (expected, not a defect) This PR changes `check-self-bootstrap.sh` — itself a compose-script — so the backstop will red on *this* PR (HEAD vs pinned diverge on the real normalization code, no marker to neutralize that). That's the documented expected-red-on-compose-script-PR (§2.3), and it needs the standard re-pin after merge. #185 is a `fix:` → v0.13.1, so: merge → tag v0.13.1-rc.1 → re-pin → cut. I'll confirm the false-positive is gone on that next cut-prep merge at source (the run that was task 13495's false-red should now be clean). Nicely scoped fix for a two-mechanism interaction (build-bake's side-effect on a backstop-tracked file). Clean to self-merge. 🎯
Sign in to join this conversation.
No description provided.