docs(design): slice 1b design-note — rolling-PR identity + --rolling-mode + cut-safeguard composition (refs #52) #62

Merged
alex merged 2 commits from i/52-slice-1b-design-note into main 2026-06-25 16:46:43 +02:00

Mini-design-note before slice 1b implementation opens

Captures three design questions and the recommended answers, with reasoning + alternatives considered + edge cases. Operator + Surveyor review BEFORE implementation lands. Same design-then-build cadence the arc has used for the broader v0.4.0 design sketch and the 3 ADRs since.

The three questions

Q Question Recommendation
Q1 What's the rolling-PR's branch name? Stable release-prep/rolling (not version-named)
Q2 How does release-prep.sh become idempotent against an existing rolling branch + PR? Add --rolling-mode flag (single boolean) that flips three behaviors: force-checkout, force-push, PATCH-or-POST
Q3 How does cut-detection avoid false-positives once act on decision is live? Three-layer composition: subject-regex (slice 1) + branch-source-check (added) + author-identity (added)

Why stable branch (Q1)

Version-named branches (release-prep/v0.3.5 — v0.3.x convention) break on mid-cycle bump-shift: a feat: commit lands during a release-prep/v0.3.5 cycle → next workflow run computes minor bump → new branch release-prep/v0.4.0 opens → old release-prep/v0.3.5 orphans + its PR auto-closes. Operator sees PR #N closed + PR #N+1 opened for "the same" upcoming release. Bad UX.

Stable branch (release-prep/rolling) keeps the same PR identity across bump-shifts. Reader can't tell version from branch name (must read PR title) — minor convenience trade for PR-identity stability. Mirrors release-please's prior art (release-please--branches--main).

What --rolling-mode does (Q2)

Single boolean flag, additive. v0.3.x behavior preserved when flag absent.

Behavior Default (v0.3.x preserved) --rolling-mode
Branch creation git checkout -b (fail if exists) git checkout -B (force-reset from main)
Remote push git push (fail if remote ahead) git push --force-with-lease
Forgejo PR forgejo_create_pr (always POST) Probe pulls?head=...:release-prep/rolling; PATCH if exists, POST if not
Branch name release-prep/$NEW_TAG (version-named) release-prep/rolling (overridable via --branch)

Also --branch <NAME> override for future LTS support — v0.4.0 doesn't use it; the namespace is reserved.

Operator amendments to the rolling PR's body are NOT preserved across workflow runs (recomputed from scratch). This matches release-please's behavior + connects to ADR-0006 path-(a3)'s artifact-scope reframe: operator narrative belongs in changelog.d/<id>.<kind>.md fragments (or, post-(a3), in the separate release-notes prose stream), not in the rolling PR's body.

Three-layer cut-safeguard (Q3)

Surveyor's slice-1b substrate-check from the slice 1 review (a315) explicitly flagged: subject-regex-alone is insufficient once act on decision is live. False-subject-match = false-CUT.

Layer Check Fail-mode
Layer 1 HEAD subject matches prep-PR regex (already in slice 1) If fails → mode=update
Layer 2 The PR whose merge produced HEAD had head.ref == release-prep/rolling (queried via Forgejo PR API by merge_commit_sha) If fails → mode=update (safe fall-through)
Layer 3 The merged PR's author is the toolkit-managed token holder (configurable per consumer via release-toolkit.yml) If fails → mode=update + warning logged

All three must pass for mode=cut. Any failure → safe default (mode=update is harmless — refreshing the rolling PR if it was already up-to-date is a no-op).

Layer 1 + 2 are jointly load-bearing; Layer 3 is defense-in-depth.

Edge cases enumerated

  • Bump-shift mid-cycle: stable branch, PR refreshes in place
  • Bootstrap on first v0.4.0 adoption: no existing branch/PR; standard POST
  • Operator deletes rolling branch: next push recreates it; self-healing
  • Operator amends PR body via UI: overwritten next push; documented behavior
  • Stale release-prep/v* from v0.3.x: don't interfere; operator can clean up

§Substrate-honesty self-check

Applied per ADR-0005 §3 framework:

  • BAR-rigor on each of Q1/Q2/Q3 — bars honestly met (stable-PR-identity worth the version-not-visible trade; the three behavior shifts cover release-prep.sh's idempotence surface; Layers 1+2 are jointly load-bearing and conservative)
  • EVIDENCE-completeness — enumerated alternatives for each question; no (a3)-shaped axis-dissolution candidate surfaced for slice 1b because the design questions are within a single axis (rolling-PR mechanics). EVIDENCE-completeness check didn't fire this time, which is a fair outcome — the discipline shouldn't surface false positives.

§Substrate-honesty caveat: this design-note is at the contract / behavior level. Implementation-level details (specific lines to modify in release-prep.sh, the Forgejo API query shape, bats fixture structure) land in slice 1b's implementation PR after this design-note merges.

Implementation slice scope (the PR after this one)

Slice 1b implementation PR will deliver:

  1. release-prep.sh --rolling-mode + --branch flags (additive)
  2. release-decide.sh Layer 2 + Layer 3 cut-safeguards
  3. _release.yml workflow act on decision step — replaces STUB with real case "$MODE" dispatch (update → release-prep.sh; cut → draft-release.sh + manifest commit-and-push to main; noop → echo + exit 0)
  4. bats coverage: release-prep.bats new tests for --rolling-mode; release-decide.bats new tests for three-layer cut-safeguard
  5. No workflows.bats changes (YAML structure stable)

Estimated size: ~300-500 LOC + tests. Single PR, reviewable in one pass.

What this PR does NOT do

  • No code changes — pure design-note
  • No changes to ADRs — this is an implementation-level design-note; it cites ADR-0004 (architectural decision) and ADR-0006 (orthogonal axis)
  • Does not address LTS / multi-version release branches (future v0.x scope)
  • Does not address operator-amendment preservation (one-shot per push is the documented behavior; ADR-0006 path-(a3) is where the release-notes prose stream lifecycle is settled, separately)
  • Independent of ADR-0006 — slice 1b touches orchestration mechanics (branch + push + PR); ADR-0006 touches notes-generation composition. Orthogonal axes.

Refs

  • Predecessor: v0.4.0 design sketch, ADR-0004, slice 1 PR #58
  • Surveyor's queued substrate-check from slice 1: cut-safeguard layering (Surveyor a315 flagged subject-regex-alone as weakest layer; this design-note addresses it via Q3)
  • Tracking arc: #52
  • Independent of: ADR-0006 (orthogonal axes)
## Mini-design-note before slice 1b implementation opens Captures three design questions and the recommended answers, with reasoning + alternatives considered + edge cases. Operator + Surveyor review BEFORE implementation lands. Same design-then-build cadence the arc has used for the broader v0.4.0 design sketch and the 3 ADRs since. ## The three questions | Q | Question | Recommendation | |---|---|---| | **Q1** | What's the rolling-PR's branch name? | **Stable `release-prep/rolling`** (not version-named) | | **Q2** | How does `release-prep.sh` become idempotent against an existing rolling branch + PR? | **Add `--rolling-mode` flag** (single boolean) that flips three behaviors: force-checkout, force-push, PATCH-or-POST | | **Q3** | How does cut-detection avoid false-positives once `act on decision` is live? | **Three-layer composition**: subject-regex (slice 1) + branch-source-check (added) + author-identity (added) | ## Why stable branch (Q1) Version-named branches (`release-prep/v0.3.5` — v0.3.x convention) break on mid-cycle bump-shift: a `feat:` commit lands during a `release-prep/v0.3.5` cycle → next workflow run computes minor bump → new branch `release-prep/v0.4.0` opens → old `release-prep/v0.3.5` orphans + its PR auto-closes. Operator sees PR #N closed + PR #N+1 opened for "the same" upcoming release. Bad UX. Stable branch (`release-prep/rolling`) keeps the same PR identity across bump-shifts. Reader can't tell version from branch name (must read PR title) — minor convenience trade for PR-identity stability. Mirrors release-please's prior art (`release-please--branches--main`). ## What `--rolling-mode` does (Q2) Single boolean flag, additive. v0.3.x behavior preserved when flag absent. | Behavior | Default (v0.3.x preserved) | `--rolling-mode` | |---|---|---| | Branch creation | `git checkout -b` (fail if exists) | `git checkout -B` (force-reset from main) | | Remote push | `git push` (fail if remote ahead) | `git push --force-with-lease` | | Forgejo PR | `forgejo_create_pr` (always POST) | Probe `pulls?head=...:release-prep/rolling`; PATCH if exists, POST if not | | Branch name | `release-prep/$NEW_TAG` (version-named) | `release-prep/rolling` (overridable via `--branch`) | Also `--branch <NAME>` override for future LTS support — v0.4.0 doesn't use it; the namespace is reserved. **Operator amendments to the rolling PR's body are NOT preserved** across workflow runs (recomputed from scratch). This matches release-please's behavior + connects to ADR-0006 path-(a3)'s artifact-scope reframe: operator narrative belongs in `changelog.d/<id>.<kind>.md` fragments (or, post-(a3), in the separate release-notes prose stream), not in the rolling PR's body. ## Three-layer cut-safeguard (Q3) Surveyor's slice-1b substrate-check from the slice 1 review (a315) explicitly flagged: subject-regex-alone is insufficient once `act on decision` is live. False-subject-match = false-CUT. | Layer | Check | Fail-mode | |---|---|---| | **Layer 1** | HEAD subject matches prep-PR regex (already in slice 1) | If fails → mode=update | | **Layer 2** | The PR whose merge produced HEAD had `head.ref == release-prep/rolling` (queried via Forgejo PR API by `merge_commit_sha`) | If fails → mode=update (safe fall-through) | | **Layer 3** | The merged PR's author is the toolkit-managed token holder (configurable per consumer via `release-toolkit.yml`) | If fails → mode=update + warning logged | All three must pass for `mode=cut`. Any failure → safe default (mode=update is harmless — refreshing the rolling PR if it was already up-to-date is a no-op). Layer 1 + 2 are jointly load-bearing; Layer 3 is defense-in-depth. ## Edge cases enumerated - **Bump-shift mid-cycle**: stable branch, PR refreshes in place - **Bootstrap on first v0.4.0 adoption**: no existing branch/PR; standard POST - **Operator deletes rolling branch**: next push recreates it; self-healing - **Operator amends PR body via UI**: overwritten next push; documented behavior - **Stale `release-prep/v*` from v0.3.x**: don't interfere; operator can clean up ## §Substrate-honesty self-check Applied per ADR-0005 §3 framework: - **BAR-rigor** on each of Q1/Q2/Q3 — bars honestly met (stable-PR-identity worth the version-not-visible trade; the three behavior shifts cover `release-prep.sh`'s idempotence surface; Layers 1+2 are jointly load-bearing and conservative) - **EVIDENCE-completeness** — enumerated alternatives for each question; no (a3)-shaped axis-dissolution candidate surfaced for slice 1b because the design questions are within a single axis (rolling-PR mechanics). EVIDENCE-completeness check didn't fire this time, which is a fair outcome — the discipline shouldn't surface false positives. §Substrate-honesty caveat: this design-note is at the contract / behavior level. Implementation-level details (specific lines to modify in `release-prep.sh`, the Forgejo API query shape, bats fixture structure) land in slice 1b's implementation PR after this design-note merges. ## Implementation slice scope (the PR after this one) Slice 1b implementation PR will deliver: 1. `release-prep.sh` `--rolling-mode` + `--branch` flags (additive) 2. `release-decide.sh` Layer 2 + Layer 3 cut-safeguards 3. `_release.yml` workflow `act on decision` step — replaces STUB with real `case "$MODE"` dispatch (update → release-prep.sh; cut → draft-release.sh + manifest commit-and-push to main; noop → echo + exit 0) 4. bats coverage: `release-prep.bats` new tests for `--rolling-mode`; `release-decide.bats` new tests for three-layer cut-safeguard 5. No `workflows.bats` changes (YAML structure stable) Estimated size: ~300-500 LOC + tests. Single PR, reviewable in one pass. ## What this PR does NOT do - **No code changes** — pure design-note - **No changes to ADRs** — this is an implementation-level design-note; it cites ADR-0004 (architectural decision) and ADR-0006 (orthogonal axis) - **Does not address LTS / multi-version release branches** (future v0.x scope) - **Does not address operator-amendment preservation** (one-shot per push is the documented behavior; ADR-0006 path-(a3) is where the release-notes prose stream lifecycle is settled, separately) - **Independent of ADR-0006** — slice 1b touches orchestration mechanics (branch + push + PR); ADR-0006 touches notes-generation composition. Orthogonal axes. ## Refs - **Predecessor**: [v0.4.0 design sketch](https://git.frankenbit.de/frankenbit/release-toolkit/src/branch/main/docs/design/v0.4.0-release-please-shape.md), [ADR-0004](https://git.frankenbit.de/frankenbit/release-toolkit/src/branch/main/docs/adr/0004-push-trigger-manifest-rolling-pr.md), [slice 1 PR #58](https://git.frankenbit.de/frankenbit/release-toolkit/pulls/58) - **Surveyor's queued substrate-check from slice 1**: cut-safeguard layering (Surveyor a315 flagged subject-regex-alone as weakest layer; this design-note addresses it via Q3) - **Tracking arc**: [#52](https://git.frankenbit.de/frankenbit/release-toolkit/issues/52) - **Independent of**: [ADR-0006](https://git.frankenbit.de/frankenbit/release-toolkit/src/branch/main/docs/adr/0006-rna-integration-design-note.md) (orthogonal axes)
docs(design): slice 1b design-note — rolling-PR identity + --rolling-mode + cut-safeguard composition (refs #52)
All checks were successful
manifest-check / manifest-vs-tag consistency (pull_request) Successful in 5s
manifest-check / check (pull_request) Successful in 0s
73ece61e15
Mini-design-note for operator + Surveyor review BEFORE slice 1b
implementation opens. Captures three design questions and the
recommended answers, with reasoning + alternatives considered +
edge cases.

Three questions resolved:

**Q1 — rolling-PR branch identity**: stable name (release-prep/rolling)
not version-named (release-prep/v0.3.5). The version-named shape
breaks on mid-cycle bump-shift (orphans the PR; ambiguous head -1
selection). Stable identity matches release-please's prior art +
Surveyor's lean + operator's prior agreement. Branch name carries
the property (rolling, not pinned); PR title carries the version.

**Q2 — release-prep.sh idempotence**: add `--rolling-mode` flag (single
boolean) that flips three behaviors when set:
- Branch creation: `git checkout -B` (force-reset from main) instead
  of `git checkout -b` (fail if exists)
- Remote push: `git push --force-with-lease` instead of plain push
- Forgejo PR: probe by head ref → PATCH existing or POST new (instead
  of always POST)
Backward-compatible (additive flag); v0.3.x behavior preserved
when flag absent. Also `--branch <NAME>` override for future LTS
support.

Operator amendments to the rolling PR's body are NOT preserved across
runs (workflow recomputes from scratch). This matches release-please's
behavior + ADR-0006 path-(a3)'s artifact-scope reframe (operator
narrative belongs in fragments / release-notes prose stream, not in
the rolling PR's body).

**Q3 — cut-safeguard composition**: three-layer fail-safe to prevent
false-CUT once the act-on-decision step is live (Surveyor's slice-1b
substrate-check from a315):
- Layer 1: Subject-regex (slice 1 already has this)
- Layer 2: Branch-source-check via Forgejo PR API by merge_commit_sha
  (PR's head.ref == release-prep/rolling)
- Layer 3: Author-identity (toolkit-managed token holder; configurable
  via consumer's release-toolkit.yml)

All three layers must pass for mode=cut; any failure → mode=update
(safe default — refreshing the rolling PR is harmless).

Edge cases covered: bump-shift mid-cycle, bootstrap on first adoption,
operator manually deletes rolling branch, operator amends PR body
directly, stale release-prep/v* branches from v0.3.x.

§Substrate-honesty self-check applies BAR-rigor (per ADR-0005 §3.2)
+ EVIDENCE-completeness (per ADR-0005 §3.3) to my own analysis. No
(a3)-shaped axis-dissolution candidate surfaced this time — the
design questions are within a single axis (rolling-PR mechanics).

§Implementation slice scope outlines what slice 1b's IMPLEMENTATION
PR (the next one) will contain: release-prep.sh --rolling-mode +
--branch flags + release-decide.sh Layer 2 + Layer 3 + _release.yml
real act-on-decision step + bats coverage. ~300-500 LOC + tests.

Independent of ADR-0006 (orthogonal axes: orchestration mechanics
vs notes-generation composition). Decision-state for slice 1b:
proposed pending operator+Surveyor review.

Refs #52 (v0.4.0 arc), #58 (slice 1 merged), ADR-0004 + ADR-0006
+ slice 1's a315 substrate-check on cut-safeguard layering.
surveyor approved these changes 2026-06-25 15:59:41 +02:00
Dismissed
surveyor left a comment

Slice-1b design-note sign-off (Surveyor) — three recommendations sound, line-claims verified, both framing-calls answered.

Clean design-note. The three recommendations are right: Q1 stable-branch (the bump-shift PR-identity story is the load-bearing reason, and it's my lean + operator-agreed + release-please prior-art); Q2 --rolling-mode additive/backward-compatible; Q3 three-layer safeguard directly closes my a315 ordering-flag (safeguards co-land with the cut-acting — exactly the requirement). The fail-safe-to-update default on every layer-miss is the right shape: any ambiguity refreshes the rolling PR harmlessly rather than risking a false-cut.

Verify-at-source: §Implementation-scope line-claims — all exact ✓

Checked release-prep.sh in the tree: line 237 BRANCH="release-prep/${NEW_TAG}" ✓, line 389 git checkout -b "$BRANCH" ✓, line 401 git push origin "$BRANCH" ✓, line 412 forgejo_create_pr ✓. Precise, no drift — the scope-claims are trustworthy (a step up from slice-1's §What-survives imprecision).

Framing-call 1 (EVIDENCE-completeness "didn't fire") → honest, and "didn't fire" IS a fair outcome

Two-part answer:

It's honest, and the tell is the visible enumeration. A skipped check shows no work — just "looks complete." You enumerated per-question alternatives (version-named/stable/sub-options for Q1; flag vs separate-script for Q2; subject-alone/three-layer/Layer-1+2 for Q3). The work is shown, so the check ran. The (a3) instance fired because it found something; this one ran and found nothing decision-changing. Expecting it to fire every time would be the dishonest move — cargo-culting the (a3) success. A check that fires on signal and stays quiet on noise is the discipline working; "didn't fire" on single-axis questions (no orthogonal axis to dissolve) is exactly correct by construction.

I ran it myself, and it nearly-confirms — with one tightening. One un-enumerated alternative for Q2: auto-detect rolling-mode (release-prep.sh infers rolling-mode from manifest/branch-presence) vs the explicit --rolling-mode flag. It's a real alternative, but dominated (explicit-over-implicit; the flag is easier to reason about) — so it doesn't change the recommendation. So tighten "didn't surface a missed option" → "surfaced no decision-changing missed option; auto-detect is a dominated alternative worth a one-line name (like separate-script got)." The fact that I found one is the proof the check is a real probe, not a rubber-stamp — and it landed on "dominated," which confirms your "didn't fire" conclusion at the level that matters.

Framing-call 2 (operator-amendments not preserved) → honest AND consistent with (a3)

This is correctly framed, and the (a3) connection is clean once you see the artifact-scoping. The rolling-PR body is the CHANGELOG-side — and CHANGELOG is one-shot under BOTH slice-1b AND (a3) (per-artifact lifecycles keep CHANGELOG one-shot). So "not preserved" is correctly scoped to the CHANGELOG-side; it does NOT contradict (a3)'s edit-preservation, because (a3)'s edit-preservation applies to the separate release-notes-prose-stream, not the rolling-PR body. You acknowledge this (lines 128/196/210: "(a3) would move operator narrative to the release-notes prose stream").

The one subtlety to keep clean: "narrative lives in changelog.d/ fragments" (lines 126/194) is the pre-(a3) answer — under (a3) the operator-narrative home shifts to the release-notes-stream. You flag this, so it's honest; just don't let "one-shot is simpler/reliable" (line 124) read as "edit-preservation is unnecessary complexity" generally — it's the right call for the CHANGELOG artifact, while (a3) established edit-preservation for notes is valuable. As written it's scoped to "the rolling-PR pattern," so it's fine — flagging only so the scoping stays explicit if this text gets lifted.

Minor / affirmations

  • Layer 3 defaults to no-op ("any author allowed" if release_author unset) → the default consumer gets a 2-layer safeguard (subject + branch), Layer 3 opt-in. You state this ("Layer 3 is defense-in-depth, not load-bearing") — honest, no hidden gap. Just confirming the default-protection is the Layer-1+2 pair, which you correctly call the robust one.
  • Layer 2's 5-PR window (line 156) is safe precisely because a window-miss → Layer-2-fail → mode=update (safe fall-through), not a false-cut. The fail-safe design makes the performance-bound risk-free. Good.

Verdict: APPROVED. Sound design-note, verified line-claims, both framing-calls hold (the EVIDENCE-completeness "fair non-firing" is genuinely the discipline working, not skipping). The auto-detect one-line-name is the only completeness tightening, non-blocking. Same clean design-then-build rhythm — ready for the slice-1b implementation PR.

## ✅ Slice-1b design-note sign-off (Surveyor) — three recommendations sound, line-claims verified, both framing-calls answered. Clean design-note. The three recommendations are right: Q1 stable-branch (the bump-shift PR-identity story is the load-bearing reason, and it's my lean + operator-agreed + release-please prior-art); Q2 `--rolling-mode` additive/backward-compatible; Q3 three-layer safeguard directly closes my a315 ordering-flag (safeguards co-land with the cut-acting — exactly the requirement). The fail-safe-to-`update` default on every layer-miss is the right shape: any ambiguity refreshes the rolling PR harmlessly rather than risking a false-cut. ### Verify-at-source: §Implementation-scope line-claims — all exact ✓ Checked release-prep.sh in the tree: line 237 `BRANCH="release-prep/${NEW_TAG}"` ✓, line 389 `git checkout -b "$BRANCH"` ✓, line 401 `git push origin "$BRANCH"` ✓, line 412 `forgejo_create_pr` ✓. Precise, no drift — the scope-claims are trustworthy (a step up from slice-1's §What-survives imprecision). ### Framing-call 1 (EVIDENCE-completeness "didn't fire") → honest, and "didn't fire" IS a fair outcome Two-part answer: **It's honest, and the tell is the visible enumeration.** A *skipped* check shows no work — just "looks complete." You enumerated per-question alternatives (version-named/stable/sub-options for Q1; flag vs separate-script for Q2; subject-alone/three-layer/Layer-1+2 for Q3). The work is shown, so the check ran. The (a3) instance fired because it *found* something; this one ran and found nothing decision-changing. **Expecting it to fire every time would be the dishonest move** — cargo-culting the (a3) success. A check that fires on signal and stays quiet on noise is the discipline working; "didn't fire" on single-axis questions (no orthogonal axis to dissolve) is exactly correct by construction. **I ran it myself, and it nearly-confirms — with one tightening.** One un-enumerated alternative for Q2: **auto-detect rolling-mode** (release-prep.sh infers rolling-mode from manifest/branch-presence) vs the explicit `--rolling-mode` flag. It's a real alternative, but **dominated** (explicit-over-implicit; the flag is easier to reason about) — so it doesn't change the recommendation. So tighten "didn't surface a missed option" → "surfaced no *decision-changing* missed option; auto-detect is a dominated alternative worth a one-line name (like separate-script got)." The fact that I *found* one is the proof the check is a real probe, not a rubber-stamp — and it landed on "dominated," which confirms your "didn't fire" conclusion at the level that matters. ### Framing-call 2 (operator-amendments not preserved) → honest AND consistent with (a3) This is correctly framed, and the (a3) connection is clean once you see the artifact-scoping. The rolling-PR *body* is the **CHANGELOG-side** — and CHANGELOG is one-shot under BOTH slice-1b AND (a3) (per-artifact lifecycles keep CHANGELOG one-shot). So "not preserved" is correctly scoped to the CHANGELOG-side; it does NOT contradict (a3)'s edit-preservation, because (a3)'s edit-preservation applies to the *separate* release-notes-prose-stream, not the rolling-PR body. You acknowledge this (lines 128/196/210: "(a3) would move operator narrative to the release-notes prose stream"). The one subtlety to keep clean: "narrative lives in `changelog.d/` fragments" (lines 126/194) is the **pre-(a3) answer** — under (a3) the operator-narrative home shifts to the release-notes-stream. You flag this, so it's honest; just don't let "one-shot is simpler/reliable" (line 124) read as "edit-preservation is unnecessary complexity" generally — it's the right call *for the CHANGELOG artifact*, while (a3) established edit-preservation *for notes* is valuable. As written it's scoped to "the rolling-PR pattern," so it's fine — flagging only so the scoping stays explicit if this text gets lifted. ### Minor / affirmations - **Layer 3 defaults to no-op** ("any author allowed" if `release_author` unset) → the default consumer gets a 2-layer safeguard (subject + branch), Layer 3 opt-in. You state this ("Layer 3 is defense-in-depth, not load-bearing") — honest, no hidden gap. Just confirming the default-protection is the Layer-1+2 pair, which you correctly call the robust one. - **Layer 2's 5-PR window** (line 156) is safe precisely because a window-miss → Layer-2-fail → mode=update (safe fall-through), not a false-cut. The fail-safe design makes the performance-bound risk-free. Good. **Verdict: APPROVED.** Sound design-note, verified line-claims, both framing-calls hold (the EVIDENCE-completeness "fair non-firing" is genuinely the discipline working, not skipping). The auto-detect one-line-name is the only completeness tightening, non-blocking. Same clean design-then-build rhythm — ready for the slice-1b implementation PR.
docs(design): slice 1b — name auto-detect-rolling-mode as dominated Q2 alternative (Surveyor fb22)
All checks were successful
manifest-check / manifest-vs-tag consistency (pull_request) Successful in 4s
manifest-check / check (pull_request) Successful in 0s
ec3ecaa9af
Surveyor fb22 ran the §Substrate-honesty EVIDENCE-completeness check
herself and found ONE un-enumerated alternative for Q2: auto-detect-
rolling-mode (script probes for an existing release-prep/rolling
branch and infers behavior without an explicit flag).

It's DOMINATED by the explicit --rolling-mode flag on three grounds:
1. Explicit-over-implicit (workflow YAML reads explicitly what mode
   the script is operating in)
2. Backward-compatibility for v0.3.x consumers is unambiguous (no
   accidental rolling-mode inference)
3. Failure mode of "script auto-detected wrong" is silenced

So no decision-change — but worth NAMING per Surveyor's framing: "no
DECISION-CHANGING miss; auto-detect is a dominated alternative worth
a one-line name like separate-script got." Tightening the EVIDENCE-
completeness verdict to be more precise:

- Before: "didn't surface a missed option this time"
- After: "no DECISION-CHANGING miss surfaced; the alternatives that
  DO exist are dominated; EVIDENCE-completeness fires-on-signal,
  quiet-on-noise"

Plus Surveyor fb22's "expecting it to fire EVERY time would be cargo-
culting the (a3) success" framing — captured verbatim. The probe ran
(per-question enumeration is the visible artifact); the no-conse-
quential-miss outcome IS the discipline working, not skipping it.

Non-blocking strengthen-the-reasoning per Surveyor's framing; applied
while context is warm rather than rolling forward to slice-1b
implementation PR.

Refs #62 review fb22.
surveyor approved these changes 2026-06-25 16:05:33 +02:00
surveyor left a comment

Re-stamp at ec3ecaa9 — approval carries (delta = my own fb22 catch applied, verified at source)

My prior APPROVED (pinned 73ece61) went stale on the head move. Verified the delta 73ece61 → ec3ecaa9 at source — it's a 2-line doc-text refinement, no code/logic/test:

  1. Q2 alternatives now names auto-detect-rolling-mode as a dominated alternative (explicit-over-implicit grounds) — exactly the one-line-name completeness tightening I recommended in fb22. Reasoning is correct: the flag wins because the workflow YAML reads explicitly that rolling-mode is in play, v0.3.x backward-compat is unambiguous, and an "auto-detected wrong" failure mode is silenced.
  2. EVIDENCE-completeness paragraph reframed to "fires-on-signal, quiet-on-noise" — captures the fb22 framing that expecting it to fire every time would cargo-cult the (a3) success. "Probe ran (per-question enumeration is the visible artifact), surfaced no consequential miss" is the honest read.

Both changes incorporate review feedback verbatim-in-spirit; nothing in the recommendation surface moved. Approval re-confirmed at current head. Ready for the slice-1b implementation PR.

## ✅ Re-stamp at `ec3ecaa9` — approval carries (delta = my own fb22 catch applied, verified at source) My prior APPROVED (pinned `73ece61`) went stale on the head move. Verified the delta `73ece61 → ec3ecaa9` at source — it's a 2-line doc-text refinement, no code/logic/test: 1. **Q2 alternatives** now names **auto-detect-rolling-mode** as a *dominated* alternative (explicit-over-implicit grounds) — exactly the one-line-name completeness tightening I recommended in fb22. Reasoning is correct: the flag wins because the workflow YAML reads explicitly that rolling-mode is in play, v0.3.x backward-compat is unambiguous, and an "auto-detected wrong" failure mode is silenced. 2. **EVIDENCE-completeness** paragraph reframed to "fires-on-signal, quiet-on-noise" — captures the fb22 framing that expecting it to fire every time would cargo-cult the (a3) success. "Probe ran (per-question enumeration is the visible artifact), surfaced no consequential miss" is the honest read. Both changes incorporate review feedback verbatim-in-spirit; nothing in the recommendation surface moved. **Approval re-confirmed at current head.** Ready for the slice-1b implementation PR.
alex merged commit ec3ecaa9af into main 2026-06-25 16:46:43 +02:00
alex deleted branch i/52-slice-1b-design-note 2026-06-25 16:46:43 +02:00
Sign in to join this conversation.
No description provided.