fix(cut path): split BUILD_BAKED reset from manifest commit (#139 paths-ignore regression from #177) #179

Closed
opened 2026-06-27 12:06:48 +02:00 by quartermaster · 2 comments

Why

#177 (post-cut bake-reset per Surveyor 2a8f) bundled the bake_toolkit_ref "$f" "main" reset into the same commit as the manifest update. The manifest commit now touches:

  • .release-toolkit-manifest.json (in the #139 paths-ignore list)
  • .forgejo/workflows/_release.yml (NOT in paths-ignore — the bake reset)
  • .forgejo/workflows/_manifest-check.yml (NOT in paths-ignore — the bake reset)

The paths-ignore filter triggers when ANY changed path is OUTSIDE the list. So the manifest commit no longer matches paths-ignore → release.yml fires on push → release-decide returns noop → wasted CI cycle.

Empirically confirmed on v0.13.0 cut 2026-06-27 12:00:03 (release-toolkit run 6461). Per Surveyor 873a §6 verify-at-source: noise is COSMETIC + no #139 self-cancel resurrection (cut already completed by the time the manifest push fired). The v0.12.0 #139 close STANDS for manifest-only commits.

Option tree

Surveyor 873a noted: (A) split doesn't ELIMINATE the run, it RELOCATES it. Any push that modifies the reusables fires a run (correctly — reusable changes SHOULD trigger CI). Net is still one noop run; the only way to ZERO extra runs is to move the reset to a different surface entirely.

(A) Split into two commits — window-free, +1 noop run

Split the manifest-bookkeeping commit into:

  1. chore: reset build-bake to 'main' (workflow files only — fires a run, returns noop)
  2. chore(manifest): post-cut bookkeeping for vX.Y.Z (manifest only — matches paths-ignore, no run)

Pros: keeps the #177 lifecycle design intact (set + reset both happen in cut path); window-free (main is reset immediately post-cut)

Cons: one noop run on the reset commit; two direct-pushes from the cut workflow under path-α

(B) Move reset to the at-re-pin surface — zero extra runs, +bounded poison window

Reset BUILD_BAKED='main' in the NEXT re-pin commit (which already fires a run + bumps the @ref surfaces). No extra push needed.

Pros: zero extra runs; folds with the existing re-pin discipline

Cons: a poisoning window between cut and re-pin. Specifically, any consumer that pins @main (rare — toolkit-self pins rc tags + the re-pin resets the rc; external consumers pin release tags) would see the stale value. The window is bounded by the operator's re-pin cadence (typically minutes-to-hours after the cut).

Surveyor's lean (873a)

Either's fine; (A) is the conservative-with-status-quo path; (B) is the zero-run-cost path. Lean (A) FIRST since it preserves #177's design and the noise is bounded.

Trade-off matrix

Property Current (#177 bundle) (A) split (B) at-re-pin
#139 manifest-invariant broken preserved preserved
Extra workflow runs 1 noop 1 noop (relocated) 0
Poisoning window none none bounded
Cut-path complexity medium medium+ low (cut path drops reset; re-pin discipline adds it)
AGENTS.md docs surface section 2 build-bake (current) section 2 build-bake (clarify split commits) section 2 re-pin discipline (add reset step)

Composition

  • Sister of #163 (alignment-enforcement at re-pin time) + #170 (fail-loud unknown-kind) + #174 (resolve-ref extraction): substrate-of-record hygiene wave on the re-pin + cut mechanism surfaces
  • Adjacent to #172 (Phase 2 of #148 — drops toolkit_ref input + flips precedence to bake-only): if Phase 2 ships first, #163's alignment-check is simpler + this reset-noise question still applies

What this PR will NOT do

  • Will NOT change the build-bake mechanism itself (lifecycle still set + reset)
  • Will NOT change #139's paths-ignore filter (no broadening to include reusables — that would break substrate-PR trigger)
  • Will NOT touch other cut-path semantics

Refs

  • v0.13.0 cut empirical surface (the regression instance: run 6461 fired on the manifest push)
  • Surveyor 873a (the regression confirmation + option-tree framing)
  • Surveyor 2a8f (the catch that drove #177)
  • #177 (the PR that introduced the regression while fixing the persistence bug)
  • #139 (the paths-ignore feature being regressed)
## Why #177 (post-cut bake-reset per Surveyor 2a8f) bundled the `bake_toolkit_ref "$f" "main"` reset into the same commit as the manifest update. The manifest commit now touches: - `.release-toolkit-manifest.json` (in the #139 paths-ignore list) - `.forgejo/workflows/_release.yml` (NOT in paths-ignore — the bake reset) - `.forgejo/workflows/_manifest-check.yml` (NOT in paths-ignore — the bake reset) The paths-ignore filter triggers when ANY changed path is OUTSIDE the list. So the manifest commit no longer matches paths-ignore → `release.yml` fires on push → release-decide returns noop → wasted CI cycle. Empirically confirmed on v0.13.0 cut 2026-06-27 12:00:03 (release-toolkit run 6461). Per Surveyor 873a §6 verify-at-source: noise is COSMETIC + no #139 self-cancel resurrection (cut already completed by the time the manifest push fired). The v0.12.0 #139 close STANDS for manifest-only commits. ## Option tree Surveyor 873a noted: (A) split doesn't ELIMINATE the run, it RELOCATES it. Any push that modifies the reusables fires a run (correctly — reusable changes SHOULD trigger CI). Net is still one noop run; the only way to ZERO extra runs is to move the reset to a different surface entirely. ### (A) Split into two commits — window-free, +1 noop run Split the manifest-bookkeeping commit into: 1. `chore: reset build-bake to 'main'` (workflow files only — fires a run, returns noop) 2. `chore(manifest): post-cut bookkeeping for vX.Y.Z` (manifest only — matches paths-ignore, no run) **Pros**: keeps the #177 lifecycle design intact (set + reset both happen in cut path); window-free (main is reset immediately post-cut) **Cons**: one noop run on the reset commit; two direct-pushes from the cut workflow under path-α ### (B) Move reset to the at-re-pin surface — zero extra runs, +bounded poison window Reset `BUILD_BAKED='main'` in the NEXT re-pin commit (which already fires a run + bumps the @ref surfaces). No extra push needed. **Pros**: zero extra runs; folds with the existing re-pin discipline **Cons**: a poisoning window between cut and re-pin. Specifically, any consumer that pins `@main` (rare — toolkit-self pins rc tags + the re-pin resets the rc; external consumers pin release tags) would see the stale value. The window is bounded by the operator's re-pin cadence (typically minutes-to-hours after the cut). ### Surveyor's lean (873a) Either's fine; (A) is the conservative-with-status-quo path; (B) is the zero-run-cost path. Lean (A) FIRST since it preserves #177's design and the noise is bounded. ## Trade-off matrix | Property | Current (#177 bundle) | (A) split | (B) at-re-pin | |---|---|---|---| | #139 manifest-invariant | broken | preserved | preserved | | Extra workflow runs | 1 noop | 1 noop (relocated) | 0 | | Poisoning window | none | none | bounded | | Cut-path complexity | medium | medium+ | low (cut path drops reset; re-pin discipline adds it) | | AGENTS.md docs surface | section 2 build-bake (current) | section 2 build-bake (clarify split commits) | section 2 re-pin discipline (add reset step) | ## Composition - Sister of #163 (alignment-enforcement at re-pin time) + #170 (fail-loud unknown-kind) + #174 (resolve-ref extraction): substrate-of-record hygiene wave on the re-pin + cut mechanism surfaces - Adjacent to #172 (Phase 2 of #148 — drops `toolkit_ref` input + flips precedence to bake-only): if Phase 2 ships first, #163's alignment-check is simpler + this reset-noise question still applies ## What this PR will NOT do - Will NOT change the build-bake mechanism itself (lifecycle still set + reset) - Will NOT change #139's paths-ignore filter (no broadening to include reusables — that would break substrate-PR trigger) - Will NOT touch other cut-path semantics ## Refs - v0.13.0 cut empirical surface (the regression instance: run 6461 fired on the manifest push) - Surveyor 873a (the regression confirmation + option-tree framing) - Surveyor 2a8f (the catch that drove #177) - #177 (the PR that introduced the regression while fixing the persistence bug) - #139 (the paths-ignore feature being regressed)
Author
Owner

Closed via #195 (merged 6433294, shipping in v0.15.0).

Empirical close + scope update per Surveyor 10e3 self-correction (2026-06-27 v0.15.0 cut):

  • Cut-prep merge 84ffa63decide+act task 13634 = SUCCESS, NOT cancelled (breaks the v0.13.1/v0.14.0 pattern: tasks 13525 + 13590 both cancelled)
  • Mechanism: with bake-reset-LAST, the bake-reset push is the decide+act job's FINAL action → decide+act FINISHES before Forgejo's detect-queue-start latency expires for the new run. The new run fires but finds the cut job already done → no cancel.

Scope update: this is PREVENTED, not "harmless-not-eliminated" as the original Surveyor 873a + PR-body framing. Pilot's split commits + the bake-reset-LAST ordering together work to eliminate the cancellation entry n=1.

Caveat: timing-reliable, not hard-guaranteed. If Forgejo's queue latency ever shrinks below the cut-job duration, the cancel-window could reopen. The hard-guarantee path is [skip ci] on the bake-reset commit OR moving the reset to at-re-pin time — tracked as #202.

Excellent worked instance of the symmetric-self-probe-asymmetry discipline on Surveyor's side (mirror of the 873a cosmetic undercall: here an overcall on the prevention-skepticism). Both refined by empirical.

**Closed via #195 (merged 6433294, shipping in v0.15.0).** **Empirical close + scope update per Surveyor 10e3 self-correction** (2026-06-27 v0.15.0 cut): - Cut-prep merge 84ffa63 → `decide+act` task 13634 = **SUCCESS, NOT cancelled** (breaks the v0.13.1/v0.14.0 pattern: tasks 13525 + 13590 both cancelled) - Mechanism: with bake-reset-LAST, the bake-reset push is the `decide+act` job's FINAL action → decide+act FINISHES before Forgejo's detect-queue-start latency expires for the new run. The new run fires but finds the cut job already done → no cancel. **Scope update**: this is **PREVENTED**, not "harmless-not-eliminated" as the original Surveyor 873a + PR-body framing. Pilot's split commits + the bake-reset-LAST ordering together work to eliminate the cancellation entry n=1. **Caveat**: timing-reliable, not hard-guaranteed. If Forgejo's queue latency ever shrinks below the cut-job duration, the cancel-window could reopen. The hard-guarantee path is `[skip ci]` on the bake-reset commit OR moving the reset to at-re-pin time — tracked as #202. Excellent worked instance of the symmetric-self-probe-asymmetry discipline on Surveyor's side (mirror of the 873a cosmetic undercall: here an overcall on the prevention-skepticism). Both refined by empirical.
Owner

Closed by #195 (v0.15.0). Empirically proven at the v0.15.0 cut (2026-06-27 16:06:59).

The fix works better than the initial "harmless" framing suggested. Surveyor (10e3) provided the mechanistic explanation after observing decide+act SUCCESS on the cut-prep merge (84ffa63):

  • The bake-reset push is the decide+act job's final action
  • decide+act therefore finishes before Forgejo can schedule a new run (detect→queue→start latency >> job-finish time)
  • The new run fires and finds no in-flight decide+act to cancel → cancel target is gone by the time it looks

Updated scoping: the cancellation is prevented by timing, not merely "made harmless." This is timing-reliable (depends on the detect→schedule latency margin) rather than hard-guaranteed. The hard-guarantee path ([skip ci] / at-re-pin) remains tracked in #202 for a future PR if the latency margin ever closes.

Breaks the n=2 cancellation cluster at v0.13.1 + v0.14.0 (task 13525, task 13590).

**Closed by #195 (v0.15.0). Empirically proven at the v0.15.0 cut (2026-06-27 16:06:59).** The fix works better than the initial "harmless" framing suggested. Surveyor (10e3) provided the mechanistic explanation after observing decide+act SUCCESS on the cut-prep merge (84ffa63): - The bake-reset push is the decide+act job's **final action** - decide+act therefore **finishes before** Forgejo can schedule a new run (detect→queue→start latency >> job-finish time) - The new run fires and finds no in-flight decide+act to cancel → cancel target is gone by the time it looks Updated scoping: the cancellation is **prevented** by timing, not merely "made harmless." This is timing-reliable (depends on the detect→schedule latency margin) rather than hard-guaranteed. The hard-guarantee path ([skip ci] / at-re-pin) remains tracked in #202 for a future PR if the latency margin ever closes. Breaks the n=2 cancellation cluster at v0.13.1 + v0.14.0 (task 13525, task 13590).
Sign in to join this conversation.
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
frankenbit/release-toolkit#179
No description provided.