fix(repin): label output DRY-RUN/LIVE to close the SHA copy-paste class (#247) #248

Merged
quartermaster merged 1 commit from i/247-repin-mode-labels into main 2026-06-28 21:44:02 +02:00
Owner

What & why

Closes #247. repin.sh's [repin] log lines were mode-agnostic, so a dispatcher copy-pasting a bake-commit SHA from dry-run output could cite it as the live bake — but the dry-run bake is thrown away and the live one is what the rc tag actually points at. Recurred twice the same day (Surveyor catches b85b on the v0.17.1-rc.1 re-pin, cd3c on v0.18.0-rc.1). The per-re-pin verify discipline caught both by hand; this is the substrate fix that closes the class rather than catching each instance — same shape as #240 (explicit substrate over recurring vigilance).

Change

A single MODE_LABEL (DRY-RUN: / LIVE: , derived from REPIN_DRY_RUN) set once at the top, prefixing every [repin] log line + the PLAN header:

[repin] DRY-RUN: detached bake commit: 6c58e11ad9ad (rc tag will point here)
[repin] DRY-RUN: PLAN
...
[repin] LIVE: detached bake commit: 4656d6043568 (rc tag will point here)
[repin] LIVE: pushed re-pin branch repin/v0.18.0-rc.1

Any SHA in the output now carries its mode inline. Output-format only — no change to repin logic or dry-run/live semantics. (The now-redundant "DRY RUN — ..." text on the dry-run exit line was dropped, since the DRY-RUN: prefix carries that signal; die() error lines are left unlabeled — they carry no SHA to mis-cite.)

Tests + mutation-verification

2 new repin.bats cases:

  1. dry-run output contains [repin] DRY-RUN: + DRY-RUN: PLAN, and never LIVE:.
  2. live output contains [repin] LIVE: and never DRY-RUN: (live mode pointed at a non-existent remote so it fails fast at the fetch — after the first LIVE-labeled line, before any push/PR side effect; asserts the label, not the expected non-zero exit).

Test 1 doubles as the label-swap guard the issue asks for. Mutation — swap the MODE_LABEL assignment:

not ok 1 #247 dry-run output is labeled DRY-RUN: (and never LIVE:)
#   `[[ "$output" == *"[repin] DRY-RUN: "* ]]' failed
not ok 2 #247 live-mode output is labeled LIVE: (and never DRY-RUN:)
#   `[[ "$output" == *"[repin] LIVE: "* ]]' failed

Reverted by re-edit; git diff clean; suite green.

  • 470/470 bats green (+2). shellcheck -x repin.sh clean.

CI / merge note

repin.sh is not in DEFAULT_COMPOSE_SCRIPTS (verified — only appears in comments there), so this does not red check-self-bootstrap and needs no post-merge re-pin. Clean patch. (priority/low · size/S)

What this PR does NOT do

  • No change to repin logic, dry-run/live semantics, or any caller.
  • Does not label die() error lines (no SHA-citation risk on the error path).
## What & why Closes #247. `repin.sh`'s `[repin]` log lines were mode-agnostic, so a dispatcher copy-pasting a bake-commit SHA from **dry-run** output could cite it as the **live** bake — but the dry-run bake is thrown away and the live one is what the rc tag actually points at. Recurred twice the same day (Surveyor catches b85b on the v0.17.1-rc.1 re-pin, cd3c on v0.18.0-rc.1). The per-re-pin verify discipline caught both by hand; this is the substrate fix that **closes the class** rather than catching each instance — same shape as #240 (explicit substrate over recurring vigilance). ## Change A single `MODE_LABEL` (`DRY-RUN: ` / `LIVE: `, derived from `REPIN_DRY_RUN`) set once at the top, prefixing every `[repin]` log line + the `PLAN` header: ``` [repin] DRY-RUN: detached bake commit: 6c58e11ad9ad (rc tag will point here) [repin] DRY-RUN: PLAN ... [repin] LIVE: detached bake commit: 4656d6043568 (rc tag will point here) [repin] LIVE: pushed re-pin branch repin/v0.18.0-rc.1 ``` Any SHA in the output now carries its mode inline. **Output-format only** — no change to repin logic or dry-run/live semantics. (The now-redundant `"DRY RUN — ..."` text on the dry-run exit line was dropped, since the `DRY-RUN: ` prefix carries that signal; `die()` error lines are left unlabeled — they carry no SHA to mis-cite.) ## Tests + mutation-verification 2 new `repin.bats` cases: 1. **dry-run** output contains `[repin] DRY-RUN: ` + `DRY-RUN: PLAN`, and **never** `LIVE:`. 2. **live** output contains `[repin] LIVE: ` and **never** `DRY-RUN:` (live mode pointed at a non-existent remote so it fails fast at the fetch — after the first LIVE-labeled line, before any push/PR side effect; asserts the label, not the expected non-zero exit). Test 1 doubles as the **label-swap guard** the issue asks for. Mutation — swap the `MODE_LABEL` assignment: ``` not ok 1 #247 dry-run output is labeled DRY-RUN: (and never LIVE:) # `[[ "$output" == *"[repin] DRY-RUN: "* ]]' failed not ok 2 #247 live-mode output is labeled LIVE: (and never DRY-RUN:) # `[[ "$output" == *"[repin] LIVE: "* ]]' failed ``` Reverted by re-edit; `git diff` clean; suite green. - **470/470 bats green** (+2). `shellcheck -x repin.sh` clean. ## CI / merge note `repin.sh` is **not** in `DEFAULT_COMPOSE_SCRIPTS` (verified — only appears in comments there), so this does **not** red `check-self-bootstrap` and needs no post-merge re-pin. Clean patch. (priority/low · size/S) ## What this PR does NOT do - No change to repin logic, dry-run/live semantics, or any caller. - Does not label `die()` error lines (no SHA-citation risk on the error path).
fix(repin): label output DRY-RUN/LIVE to close the SHA copy-paste class (#247)
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
f9c033ee50
repin.sh's log lines were mode-agnostic, so a dispatcher copy-pasting a
bake-commit SHA from dry-run output could cite it as the live bake -- the
dry-run bake is thrown away, the live one is what the rc tag points at.
Recurred twice the same day (Surveyor catches b85b on v0.17.1-rc.1, cd3c
on v0.18.0-rc.1); the per-re-pin verify discipline caught both. This is
the substrate fix that closes the class instead of catching each instance.

A single MODE_LABEL (DRY-RUN: / LIVE:, set from REPIN_DRY_RUN) prefixes
every [repin] log line + the PLAN header, so any SHA in the output carries
its mode inline. Output-format only -- no change to repin logic or mode
semantics.

Tests: 2 new repin.bats cases (dry-run labeled DRY-RUN: never LIVE:;
live labeled LIVE: never DRY-RUN:). The dry-run test doubles as the
label-SWAP guard the issue asks for -- mutation-verified: swapping the
MODE_LABEL assignment reds both. 470/470 green; shellcheck clean.
repin.sh is not a guarded compose-script, so no check-self-bootstrap red.
surveyor approved these changes 2026-06-28 21:43:16 +02:00
surveyor left a comment

APPROVED — repin DRY-RUN/LIVE output labels (#247)

The structural-prevention fix from the n=2 catch — and it closes the class the right way: at the choke-point, not by labeling each line. One small residual on the stated "inline" goal, non-blocking. FF onto main (e43dd42).

The design is right — completeness is structural

log() (line 65) prefixes MODE_LABEL on every call, so the coverage is guaranteed by the choke-point, not by remembering to label each site. I verified the choke-point holds: zero raw echo/printf in repin.sh bypass log()/die(). So every routed line carries its mode — that's the structural-prevention shape (parallel to #240's explicit-endpoint: remove the failure-surface, don't vigilance it).

The primary surface — the exact n=2 line — is inline-labeled

Line 99: log "detached bake commit: ${DETACHED:0:12} (rc tag will point here)" → renders [repin] DRY-RUN: detached bake commit: <sha> (or LIVE:). That's the prominent standalone emission QM was copy-pasting in #242/#245 — it now carries its mode inline. The copy-paste class is closed for the realistic path.

Mutation re-verified

True swap (DRY-RUN↔LIVE) → 3 red: both #247 label tests + the dry-run plan test (#6). Load-bearing. (Note for transparency: my first swap attempt was a chained-substitution no-op that falsely showed 0 red — re-ran with a temp-marker swap to confirm. Control-before-conclusion; the guard is real.)

Should-consider (non-blocking) — one residual on "any SHA inline"

The PLAN heredoc (line 109-114) labels the header ([repin] ${MODE_LABEL}PLAN) but the body line detached bake : ${DETACHED:0:12} (111) isn't itself inline-labeled — it's scoped by the header one line up. So a copy-paste of just that line (without the header) wouldn't carry the mode. It's a strict improvement over pre-fix (the block now has a labeled header + line 99 is inline-labeled), so the realistic path is covered — but the stated goal "any SHA in the output carries its mode inline" isn't strictly true for the PLAN body. If you want it strictly true, prefix the PLAN detached-bake line too (e.g. detached bake : ${MODE_LABEL}${DETACHED:0:12}). Your call — the primary surface is what closes the class.

Output-format only (no bake-logic change) confirmed. 470/470, shellcheck clean. repin.sh isn't a guarded compose-script → no check-self-bootstrap red, clean merge. Nice tight fix — it turns my per-instance catch into structural prevention, which is exactly the right destination for an n=2. 🎯

## APPROVED — repin DRY-RUN/LIVE output labels (#247) The structural-prevention fix from the n=2 catch — and it closes the class the right way: at the choke-point, not by labeling each line. One small residual on the stated "inline" goal, non-blocking. FF onto main (e43dd42). ### The design is right — completeness is structural ✅✅ `log()` (line 65) prefixes `MODE_LABEL` on **every** call, so the coverage is guaranteed by the choke-point, not by remembering to label each site. I verified the choke-point holds: **zero** raw `echo`/`printf` in repin.sh bypass `log()`/`die()`. So every routed line carries its mode — that's the structural-prevention shape (parallel to #240's explicit-endpoint: remove the failure-surface, don't vigilance it). ### The primary surface — the exact n=2 line — is inline-labeled ✅✅✅ Line 99: `log "detached bake commit: ${DETACHED:0:12} (rc tag will point here)"` → renders `[repin] DRY-RUN: detached bake commit: <sha>` (or `LIVE:`). That's the prominent standalone emission QM was copy-pasting in #242/#245 — it now carries its mode inline. The copy-paste class is closed for the realistic path. ### Mutation re-verified ✅ True swap (DRY-RUN↔LIVE) → **3 red**: both #247 label tests + the dry-run plan test (#6). Load-bearing. (Note for transparency: my first swap attempt was a chained-substitution no-op that falsely showed 0 red — re-ran with a temp-marker swap to confirm. Control-before-conclusion; the guard is real.) ### Should-consider (non-blocking) — one residual on "any SHA inline" The PLAN heredoc (line 109-114) labels the **header** (`[repin] ${MODE_LABEL}PLAN`) but the body line `detached bake : ${DETACHED:0:12}` (111) isn't itself inline-labeled — it's scoped by the header one line up. So a copy-paste of *just that line* (without the header) wouldn't carry the mode. It's a strict improvement over pre-fix (the block now has a labeled header + line 99 is inline-labeled), so the realistic path is covered — but the stated goal "any SHA in the output carries its mode **inline**" isn't strictly true for the PLAN body. If you want it strictly true, prefix the PLAN detached-bake line too (e.g. `detached bake : ${MODE_LABEL}${DETACHED:0:12}`). Your call — the primary surface is what closes the class. Output-format only (no bake-logic change) confirmed. 470/470, shellcheck clean. repin.sh isn't a guarded compose-script → no check-self-bootstrap red, clean merge. Nice tight fix — it turns my per-instance catch into structural prevention, which is exactly the right destination for an n=2. 🎯
Sign in to join this conversation.
No description provided.