HOMELAB-2329: contracts-b11-b12 correction — HOMELAB-2339 base + gate-writer accuracy delta (superset of #24) #26

Merged
pi-landing merged 4 commits from plane/HOMELAB-2329-b11-b12 into main 2026-10-29 10:46:29 +00:00
Collaborator

HOMELAB-2329 contract-prerequisite docs for the HOMELAB-2196 W3 official runs. Superset of draft #24 — land one, not both.

Delta vs #24 (4f71ed9, HOMELAB-2339 base correction)

This branch carries HOMELAB-2339's correction verbatim (commit 3da37b9, authorship preserved), plus the HOMELAB-2329 accuracy delta (61e1ab9, 3 edits, +4/−2) written against the re-confirmed code head 8294a17dde17e86997e8c9d8c3701eebba98e5d3 (infra-core #660):

  1. Revised header re-read at 8294a17 (was pinned to the superseded d17c575).
  2. §2's write-time check sentence scoped to recordJournal.Step only.
  3. §6 gains the restart-pass gap row: run/loop.go stepEventKind returns KindGate for the gate in any state and closeOrphanMidStep writes the orphaned gate's terminal failed row (cause: runtime-replaced, orphan: true, no decision) through Loop.appendEvent → Store.Append, bypassing record.ValidGateDecision — with the follow-up owner stated (give it block via run.GateDecisionForState, or write it under path.step, and widen the check to every gate-row writer). This is the open concern from infra-core review 1013.

Disposition of #24

#24 (plane/HOMELAB-2339-gate-writer-contract @ 4f71ed9) covers only the base correction and carries an ld-reviewer APPROVED verdict at that head. This PR is a superset; one should land and the other be closed — merging both puts two conflicting hunks on the same paragraph. This PR's head 61e1ab9 is a delta review (3 edits over the approved text), not a new round.

Checks

Document-only change. Content checked 20/20 against primary sources (run.GateDecisionForState, record.ValidGateDecision + the 3-word frozen set, recordJournal.Step both directions, stepEventKind / closeOrphanMidStep / appendEvent / Store.Append, frozen report.sql vocabulary arm and gate_on_head), plus markdown shape (pipe balance, no trailing whitespace, valid UTF-8). Script/log: .rpiv/artifacts/build/homelab-2329-contracts/doc-check.sh / doc-check.log (fails=0).

Not done here: no merge, no code change, no signature, no image, no drive, no close of #24 (orchestrator disposition).

HOMELAB-2329 contract-prerequisite docs for the HOMELAB-2196 W3 official runs. **Superset of draft #24** — land one, not both. ## Delta vs #24 (`4f71ed9`, HOMELAB-2339 base correction) This branch carries HOMELAB-2339's correction **verbatim** (commit `3da37b9`, authorship preserved), plus the HOMELAB-2329 accuracy delta (`61e1ab9`, 3 edits, +4/−2) written against the re-confirmed code head `8294a17dde17e86997e8c9d8c3701eebba98e5d3` (infra-core #660): 1. `Revised` header re-read at `8294a17` (was pinned to the superseded `d17c575`). 2. §2's write-time check sentence scoped to `recordJournal.Step` only. 3. §6 gains the restart-pass gap row: `run/loop.go` `stepEventKind` returns `KindGate` for the gate in any state and `closeOrphanMidStep` writes the orphaned gate's terminal `failed` row (`cause: runtime-replaced`, `orphan: true`, no `decision`) through `Loop.appendEvent` → `Store.Append`, bypassing `record.ValidGateDecision` — with the follow-up owner stated (give it `block` via `run.GateDecisionForState`, or write it under `path.step`, and widen the check to every gate-row writer). This is the open concern from infra-core review 1013. ## Disposition of #24 #24 (`plane/HOMELAB-2339-gate-writer-contract` @ `4f71ed9`) covers only the base correction and carries an `ld-reviewer` APPROVED verdict at that head. **This PR is a superset; one should land and the other be closed** — merging both puts two conflicting hunks on the same paragraph. This PR's head `61e1ab9` is a delta review (3 edits over the approved text), not a new round. ## Checks Document-only change. Content checked 20/20 against primary sources (`run.GateDecisionForState`, `record.ValidGateDecision` + the 3-word frozen set, `recordJournal.Step` both directions, `stepEventKind` / `closeOrphanMidStep` / `appendEvent` / `Store.Append`, frozen `report.sql` vocabulary arm and `gate_on_head`), plus markdown shape (pipe balance, no trailing whitespace, valid UTF-8). Script/log: `.rpiv/artifacts/build/homelab-2329-contracts/doc-check.sh` / `doc-check.log` (`fails=0`). Not done here: no merge, no code change, no signature, no image, no drive, no close of #24 (orchestrator disposition).
Corrects design/ld5/contracts-b11-b12.md against the merged writer change
(HOMELAB-2329, d17c575) that the W3 lane review found the frozen contract
still described pre-#660:

- §2: kind rule — the gate's start row is a path.step row; only the terminal
  row is a gate.decision row, and it carries decision pass|block|hold derived
  by run.GateDecisionForState and checked at the write by
  record.ValidGateDecision. Names the LastStep consequence and that historical
  rows are not rewritten.
- §2 table: the gate row's kind and payload per state.
- §4: gate.decision.decision is written; floor_met, round, first_verdict,
  holds[] and canary are not, and are HOMELAB-2336's panel-floor fields.
- §6: the remaining gate-row gap restated as those five fields, with what
  report.sql reads without them (gate_on_head needs floor_met; gate_first
  ordering, first_verdict, canary defaults).

No change to measurement.md, report.sql or any Verify line.
contracts-b11-b12.md already described the post-#660 rows (HOMELAB-2339,
picked up verbatim here) but stated the write-time check as an invariant of
the kind, which no longer matches the code at the reviewed head 8294a17:

- Revised header names the head it was re-read at, so the pin is not the
  superseded d17c575 and the reader can see which commit was checked.
- §2: the enforcement sentence is scoped to recordJournal.Step, and a new
  bullet records the writer that goes round it — run/loop.go stepEventKind
  returns record.KindGate for the gate whatever the state, and
  closeOrphanMidStep writes the orphaned gate's terminal failed row with no
  `decision`, through Loop.appendEvent -> Store.Append. A gate orphaned
  mid-attempt can therefore still yield a decisionless gate.decision row,
  which report.sql's state-less arm reads as (missing).
- §6: that row gets its own line and owner (review 1013 at 8294a17).

Raised by the W3 review of infra-core#660; no M0, report.sql or Verify text
changed, and no historical rows are rewritten.
ld-reviewer requested changes 2026-10-29 09:30:06 +00:00
Dismissed
ld-reviewer left a comment
Collaborator

Formal review — tests lens (DeepSeek), delta at head 61e1ab9 (ld-reviewer)

Verdict: REQUEST_CHANGES — one accuracy finding in the delta (additive: one §2 bullet + one §6 row), plus one quoted-literal slip. Everything else in the delta verifies against primary source.

model: omniroute/deepseek-flash

Ticket HOMELAB-2329 (https://plane.aaron.reynoza.org/homelab/projects/…/issues/2329 — W3 carry-over, gate.decision rows record decision for report.sql), with its doc sibling HOMELAB-2339. Pinned to head 61e1ab9cd60ed8d183da467842512511c4e5b345; if the head moves this verdict does not carry.

Scope. This is the delta over HOMELAB-2339's text (3da37b9), not a new round on the base correction. I read the exact-head diff, the head's design/ld5/contracts-b11-b12.md and design/ld5/report.sql, infra-core@8294a17dde17e86997e8c9d8c3701eebba98e5d3 (PR #660, merged to live), PR #24's diff and its verdict, and HOMELAB-2329 / HOMELAB-2339. No implementer summary was used.

No CI in this repo, and that is checked, not assumed: GET /commits/61e1ab9…/status → total_count: 0; contents/.forgejo@61e1ab9 → 404. Nothing here is green; this verdict rests on the diff and on the code/report it points at. Head independently confirmed via the API as 61e1ab9…, branch plane/HOMELAB-2329-b11-b12, base main@a451083 (= today's main head).


Delta claims — verified at primary source

  1. Start row path.step, terminal row gate.decision. cmd/ld-runtime/main.go stepKind(step,state) returns KindGate only for StepGate and run.TerminalState(state), else KindStep; outcomeKind(step) returns KindGate for the gate regardless of state (the resume side). Both rows go through recordJournal.Step. CONFIRMED.
  2. ok → pass, failed → block, refused → hold. run.GateDecisionForState (run/run.go:133) is exactly that mapping, and p.step's deferred writer stamps fields["decision"] for step == run.StepGate. CONFIRMED.
  3. The write-time check is recordJournal.Step's alone, both directions. In Step, kind := stepKind(...); a gate row destined for KindStep (the start row) is refused if it carries any decision, and a gate row destined for KindGate is refused if the decision is absent, blank (TrimSpace == "") or outside the frozen set (record.ValidGateDecision, whose map is exactly pass/block/hold). The "fail-closed, the same way workflows.status is checked at Open/Close" analogy is accurate: record.go:367 and :415 call ValidStatus. CONFIRMED.
  4. The restart-pass bypass. run/loop.go stepEventKind(step) returns record.KindGate for StepGate whatever the state; closeOrphanMidStep builds {step, state: failed, reason, cause, orphan: true, workflow_id, sign_activity_id, started_at, reset, at} — no decision — and writes it through Loop.appendEvent → Store.Append; appendEvent injects nothing. The orphan scan lists both KindStep and KindGate, so after this change the running gate row (now path.step) is still closed under gate.decision. CONFIRMED (literal cause string: see C1).
  5. report.sql's state-less arm makes a decisionless gate row NOT_CERTIFIABLE. The vocabulary arm's gate.decision.decision branch selects on kind, sample_id and id > sample_event_id only — no state filter anywhere — and emits COALESCE(lower(payload->>'decision'), '(missing)') for rows where the decision is NULL or outside pass|block|hold; M0-R42 makes any vocabulary row NOT_CERTIFIABLE. The same read is pinned as a negative control in gate_decision_test.go (reportVocabularyOffenders on a decisionless gate row → (missing)). CONFIRMED.
  6. §4: decision yes; floor_met/round/first_verdict/holds[]/canary no. No non-test occurrence of those four keys as payload values anywhere in dispatcher/ (the only floor_met hits are a doc comment on gate_on_head and a phrase in run/forgejo.go); canary appears only in unrelated docs/config. CONFIRMED.
  7. §6: gate_on_head is floor_met AND lower(decision) = 'pass'. The CTE is bool_or(COALESCE((payload->>'floor_met')::boolean, FALSE) AND lower(payload->>'decision') = 'pass'), so a passing decision with no floor_met reads FALSE; gate_first orders by (payload->>'round')::int, COALESCE(first_verdict,'unknown'), COALESCE(canary, FALSE) — matching M0-R30 and M0-R29. CONFIRMED.
  8. Named cost. LastStep → outcomeKind(step) → KindGate only for the gate, so the gate's start row is invisible to resume and a half-run gate is re-attempted; the gate reads branch/diff/CI and merges nothing, and no other step's outcomeKind changes. CONFIRMED.
  9. Shape and unrelated text. Three hunks, all inside the gate-writer paragraphs/rows (§2, §2 table, §4 table, §6 table); table pipes balanced at 3 columns in every row of §6; no trailing whitespace; valid UTF-8; LF. No unrelated text.

Supersession of #24 — clean. pulls/24.diff and commit 3da37b9's patch are byte-identical (10101 bytes each), both branches share base a451083, which is still main's head, so landing both would put two edits on the same paragraph and the second merge conflicts. #24 does carry the APPROVED ld-reviewer verdict at 4f71ed9 (as its verdict comment; the review object itself is PENDING, which is the comment-as-verdict pattern) — the PR body's statement is accurate. Land one, close the other. Supports the official #660 drive: #660 is merged at 8294a17 into live, reviews 1013 (deepseek, APPROVED) and 1015 (kimi premium, APPROVED) both exist at that head, and the delta's Revised header re-pins to it correctly.


F1 — the exhaustiveness claim in §2/§6 misses the second site the write check runs over, and that site is broken by it

Where. §2: "That check lives in recordJournal.Step … and it is not the only writer of gate rows — see the next bullet." / "One writer goes round that check, and this is the gate's remaining decisionless path (open, HOMELAB-2329)." §6: "the one gate-row writer the §2 write-time check does not cover".

What is missing. Path.refusedRow (run/run.go:886-895) is the second caller of recordJournal.Step for gate (the third, stepboundary.go:421, is StepBoundary). It is invoked from the replayed-evidence refusal at run/run.go:688 with the loop's current step — and the loop walks run.Steps, which contains StepGate (run.go:58). Its fields are {reason, refusal, branch, replayed_head, branch_head, reset, at}: no decision, and state is StateRefused, so stepKind sends it to record.KindGate, and recordJournal.Step returns journal …: refusing to write a gate.decision row with no 'decision'.

Consequence at the reviewed head. A gate replay refusal writes no row at all and returns run: … the replay refusal could not be journalled: …. That is precisely the absence HOMELAB-2348 was filed to remove ("the refusal is a row, not an absence"), and it is the shape the code itself names two paragraphs above the call site: after a reset that deleted the path.step rows, the gate row is the only one carrying a head_sha, so the gate is the first step the replay check lands on. refusedRow's own doc comment reinforces the exposure — it deliberately stamps no head_sha "so a refusal must not feed its own trigger" — but nothing gives the gate row its word.

Why this is a finding on this delta and not on #660. #660 traded a decisionless refusal row (which the report flags (missing)) for no refusal row plus an error; either way the gate refusal path is outside the contract, and this document's job — stated in its own §6 preamble — is "Stated here rather than discovered at proof P3". The delta records the weaker of the two uncovered paths (the orphan row is at least written) and presents the census as complete, so the stronger one stays invisible to the P3 reviewer. The §6 follow-up ("widen the write-time check to every gate-row writer") names the remedy but not the site.

Requested edit (small, additive). One §2 bullet (or a sentence in the gate.decision-terminal bullet) naming Path.refusedRow as the other recordJournal.Step caller for the gate, stating that its refused write now has no decision and is therefore refused outright; and a §6 row with the same owner: give that row its word via run.GateDecisionForState(run.StateRefused) → hold (or write it under path.step), and widen the check to every gate-row writer.

Test gap that goes with it. run/replay_refusal_test.go drives w.journal (a fake), so no test at 8294a17 exercises refusedRow through the real recordJournal.Step. The doc sentence should not imply the refusal path is validated.

C1 — one quoted value is not the literal

§2 (and the §6 condition) write the orphan payload as cause: runtime-replaced. The literal is runtime-replaced-mid-step (RecoveryCauseRuntimeReplaced, run/loop.go:923). The Authority row says this document "does not invent values", so quote the literal or write cause: runtime-replaced-mid-step.


Limits

Read/comment/review only. I edited nothing, committed nothing, pushed nothing, merged nothing, signed nothing, produced no image, ran no drive, and did not touch #24 or its verdict. Reviewer ≠ implementer: this pass did not inherit the implementer's context and worked only from the sources named above.

## Formal review — tests lens (DeepSeek), delta at head `61e1ab9` (`ld-reviewer`) **Verdict: REQUEST_CHANGES — one accuracy finding in the delta (additive: one §2 bullet + one §6 row), plus one quoted-literal slip. Everything else in the delta verifies against primary source.** ``` model: omniroute/deepseek-flash ``` Ticket **HOMELAB-2329** (`https://plane.aaron.reynoza.org/homelab/projects/…/issues/2329` — W3 carry-over, gate.decision rows record decision for report.sql), with its doc sibling **HOMELAB-2339**. Pinned to head `61e1ab9cd60ed8d183da467842512511c4e5b345`; if the head moves this verdict does not carry. **Scope.** This is the delta over HOMELAB-2339's text (`3da37b9`), not a new round on the base correction. I read the exact-head diff, the head's `design/ld5/contracts-b11-b12.md` and `design/ld5/report.sql`, `infra-core@8294a17dde17e86997e8c9d8c3701eebba98e5d3` (PR #660, merged to `live`), PR #24's diff and its verdict, and HOMELAB-2329 / HOMELAB-2339. No implementer summary was used. **No CI in this repo, and that is checked, not assumed:** `GET /commits/61e1ab9…/status` → `total_count: 0`; `contents/.forgejo@61e1ab9` → `404`. Nothing here is green; this verdict rests on the diff and on the code/report it points at. Head independently confirmed via the API as `61e1ab9…`, branch `plane/HOMELAB-2329-b11-b12`, base `main@a451083` (= today's `main` head). --- ### Delta claims — verified at primary source 1. **Start row `path.step`, terminal row `gate.decision`.** `cmd/ld-runtime/main.go` `stepKind(step,state)` returns `KindGate` only for `StepGate` *and* `run.TerminalState(state)`, else `KindStep`; `outcomeKind(step)` returns `KindGate` for the gate regardless of state (the resume side). Both rows go through `recordJournal.Step`. CONFIRMED. 2. **`ok` → `pass`, `failed` → `block`, `refused` → `hold`.** `run.GateDecisionForState` (`run/run.go:133`) is exactly that mapping, and `p.step`'s deferred writer stamps `fields["decision"]` for `step == run.StepGate`. CONFIRMED. 3. **The write-time check is `recordJournal.Step`'s alone, both directions.** In `Step`, `kind := stepKind(...)`; a gate row destined for `KindStep` (the start row) is refused if it carries *any* `decision`, and a gate row destined for `KindGate` is refused if the decision is absent, blank (`TrimSpace == ""`) or outside the frozen set (`record.ValidGateDecision`, whose map is exactly `pass`/`block`/`hold`). The "fail-closed, the same way `workflows.status` is checked at `Open`/`Close`" analogy is accurate: `record.go:367` and `:415` call `ValidStatus`. CONFIRMED. 4. **The restart-pass bypass.** `run/loop.go` `stepEventKind(step)` returns `record.KindGate` for `StepGate` whatever the state; `closeOrphanMidStep` builds `{step, state: failed, reason, cause, orphan: true, workflow_id, sign_activity_id, started_at, reset, at}` — no `decision` — and writes it through `Loop.appendEvent` → `Store.Append`; `appendEvent` injects nothing. The orphan scan lists both `KindStep` and `KindGate`, so after this change the running gate row (now `path.step`) is still closed under `gate.decision`. CONFIRMED (literal cause string: see C1). 5. **`report.sql`'s state-less arm makes a decisionless gate row `NOT_CERTIFIABLE`.** The vocabulary arm's `gate.decision.decision` branch selects on `kind`, `sample_id` and `id > sample_event_id` only — no `state` filter anywhere — and emits `COALESCE(lower(payload->>'decision'), '(missing)')` for rows where the decision is NULL or outside `pass|block|hold`; M0-R42 makes any vocabulary row `NOT_CERTIFIABLE`. The same read is pinned as a negative control in `gate_decision_test.go` (`reportVocabularyOffenders` on a decisionless gate row → `(missing)`). CONFIRMED. 6. **§4: `decision` yes; `floor_met`/`round`/`first_verdict`/`holds[]`/`canary` no.** No non-test occurrence of those four keys as payload values anywhere in `dispatcher/` (the only `floor_met` hits are a doc comment on `gate_on_head` and a phrase in `run/forgejo.go`); `canary` appears only in unrelated docs/config. CONFIRMED. 7. **§6: `gate_on_head` is `floor_met AND lower(decision) = 'pass'`.** The CTE is `bool_or(COALESCE((payload->>'floor_met')::boolean, FALSE) AND lower(payload->>'decision') = 'pass')`, so a passing decision with no `floor_met` reads `FALSE`; `gate_first` orders by `(payload->>'round')::int`, `COALESCE(first_verdict,'unknown')`, `COALESCE(canary, FALSE)` — matching M0-R30 and M0-R29. CONFIRMED. 8. **Named cost.** `LastStep` → `outcomeKind(step)` → `KindGate` only for the gate, so the gate's start row is invisible to resume and a half-run gate is re-attempted; the gate reads branch/diff/CI and merges nothing, and no other step's `outcomeKind` changes. CONFIRMED. 9. **Shape and unrelated text.** Three hunks, all inside the gate-writer paragraphs/rows (§2, §2 table, §4 table, §6 table); table pipes balanced at 3 columns in every row of §6; no trailing whitespace; valid UTF-8; LF. No unrelated text. **Supersession of #24 — clean.** `pulls/24.diff` and commit `3da37b9`'s patch are byte-identical (10101 bytes each), both branches share base `a451083`, which is still `main`'s head, so landing both would put two edits on the same paragraph and the second merge conflicts. #24 does carry the APPROVED `ld-reviewer` verdict at `4f71ed9` (as its verdict comment; the review object itself is `PENDING`, which is the comment-as-verdict pattern) — the PR body's statement is accurate. Land one, close the other. **Supports the official #660 drive:** #660 is merged at `8294a17` into `live`, reviews 1013 (deepseek, APPROVED) and 1015 (kimi premium, APPROVED) both exist at that head, and the delta's `Revised` header re-pins to it correctly. --- ### F1 — the exhaustiveness claim in §2/§6 misses the second site the write check runs over, and that site is broken by it **Where.** §2: "That check lives in `recordJournal.Step` … and it is **not** the only writer of gate rows — see the next bullet." / "**One writer goes round that check, and this is the gate's remaining decisionless path** (open, HOMELAB-2329)." §6: "the one gate-row writer the §2 write-time check does not cover". **What is missing.** `Path.refusedRow` (`run/run.go:886-895`) is the second caller of `recordJournal.Step` for `gate` (the third, `stepboundary.go:421`, is `StepBoundary`). It is invoked from the replayed-evidence refusal at `run/run.go:688` with the loop's current step — and the loop walks `run.Steps`, which contains `StepGate` (`run.go:58`). Its fields are `{reason, refusal, branch, replayed_head, branch_head, reset, at}`: **no `decision`**, and `state` is `StateRefused`, so `stepKind` sends it to `record.KindGate`, and `recordJournal.Step` returns `journal …: refusing to write a gate.decision row with no 'decision'`. **Consequence at the reviewed head.** A gate replay refusal writes **no row at all** and returns `run: … the replay refusal could not be journalled: …`. That is precisely the absence HOMELAB-2348 was filed to remove ("the refusal is a row, not an absence"), and it is the shape the code itself names two paragraphs above the call site: after a reset that deleted the `path.step` rows, the gate row is the only one carrying a `head_sha`, so the gate is the first step the replay check lands on. `refusedRow`'s own doc comment reinforces the exposure — it deliberately stamps no `head_sha` "so a refusal must not feed its own trigger" — but nothing gives the gate row its word. **Why this is a finding on this delta and not on #660.** #660 traded a *decisionless* refusal row (which the report flags `(missing)`) for *no* refusal row plus an error; either way the gate refusal path is outside the contract, and this document's job — stated in its own §6 preamble — is "Stated here rather than discovered at proof P3". The delta records the weaker of the two uncovered paths (the orphan row is at least written) and presents the census as complete, so the stronger one stays invisible to the P3 reviewer. The §6 follow-up ("widen the write-time check to every gate-row writer") names the remedy but not the site. **Requested edit (small, additive).** One §2 bullet (or a sentence in the `gate.decision`-terminal bullet) naming `Path.refusedRow` as the other `recordJournal.Step` caller for the gate, stating that its `refused` write now has no `decision` and is therefore refused outright; and a §6 row with the same owner: give that row its word via `run.GateDecisionForState(run.StateRefused)` → `hold` (or write it under `path.step`), and widen the check to every gate-row writer. **Test gap that goes with it.** `run/replay_refusal_test.go` drives `w.journal` (a fake), so no test at `8294a17` exercises `refusedRow` through the real `recordJournal.Step`. The doc sentence should not imply the refusal path is validated. ### C1 — one quoted value is not the literal §2 (and the §6 condition) write the orphan payload as `cause: runtime-replaced`. The literal is **`runtime-replaced-mid-step`** (`RecoveryCauseRuntimeReplaced`, `run/loop.go:923`). The Authority row says this document "does not invent values", so quote the literal or write `cause: runtime-replaced-mid-step`. --- ### Limits Read/comment/review only. I edited nothing, committed nothing, pushed nothing, merged nothing, signed nothing, produced no image, ran no drive, and did not touch #24 or its verdict. Reviewer ≠ implementer: this pass did not inherit the implementer's context and worked only from the sources named above.
ld-reviewer approved these changes 2026-10-29 09:32:51 +00:00
Dismissed
ld-reviewer left a comment
Collaborator
**Verdict of record — ld-reviewer — head 61e1ab9cd6: APPROVE** model: omniroute/deepseek-flash lens: W3 lane reviewer (DeepSeek tests/claims lens) — this is one lens; the worker's sequence also asks for a premium delta lens, so if a two-lens panel is treated as required this is one of the two, not the panel. class: **docs only** — one file, `design/ld5/contracts-b11-b12.md`, +14/−4 against `main`. No code, manifest, RBAC, secret, network policy, schema or migration. What makes it reviewable as more than prose is that this document is the one the runtime is reviewed against, so **every claim in the delta is asserted against the code, not read**. ## What the PR is, checked structurally | fact | measured | |---|---| | files changed | `design/ld5/contracts-b11-b12.md`, +14/−4, `changed_files=1` | | commits | `3da37b9842` (HOMELAB-2339 base correction) + `61e1ab9cd6` (HOMELAB-2329 amendment) | | base | `main` = `a451083e98` | | the base correction is carried **verbatim**, not re-authored | blob of `contracts-b11-b12.md` at **`3da37b98420c` == at `4f71ed93f78d`** (#24's head) = `211152e2…`, 24,149 B — byte-identical | | the amendment is exactly the stated 3 edits | `diff 3da37b9 → 61e1ab9` touches the `Revised` header row, one bullet in §2 (extended) plus one **new** §2 bullet, and one new §6 table row. Nothing else in 198 lines moved. | | doc shape | valid UTF-8, 198 lines, **0** conflict markers, **0** trailing-whitespace lines, **0** unbalanced table rows, 0 tabs | So the PR is precisely what its body says: #24's already-approved text plus a three-edit accuracy delta. My review is of the **delta**, and it re-confirms the base rather than re-litigating it. ## The amendment's claims, each asserted against the code Verified at `infra-core` **`0ffea3e397708607fc558e0f00acd972ec1ed994`** — the `#660` merge commit, i.e. what the live runtime now runs (prod pin `dispatcher@sha256:66ef87f1…`, see prod#1045) — and not merely at the pre-merge head the doc cites: 1. **"`run.GateDecisionForState`: `ok` → `pass`, `failed` → `block`, `refused` → `hold`"** — `run/run.go:133-143`, exactly those three arms and `("", false)` otherwise. ✔ 2. **"validated at the write by `record.ValidGateDecision`, which refuses a `gate.decision` row whose decision is missing, blank or outside the set"** — `record/record.go:213-240`: the constants, `gateDecisionVocabulary = pass|block|hold`, `ValidGateDecision`. The literal `"pass"` is present (the redactor flags that line as a password on this repo — it is a false positive, as the third shift recorded). ✔ 3. **"That check lives in `recordJournal.Step` … guarded by its own `stepKind`"** — `cmd/ld-runtime/main.go:1007-1042`: `kind := stepKind(step, state)`, and for `run.StepGate` both directions are refused — a `decision` on a start row (`kind == KindStep`) and a missing/blank/out-of-vocabulary `decision` on a `gate.decision` row. `stepKind` (`:962-970`) returns `KindGate` only when `run.TerminalState(state)`, and `TerminalState` (`run/run.go:111-117`) is `ok|failed|refused` — `running` is excluded. ✔ 4. **"`stepEventKind` returns `record.KindGate` for `run.StepGate` whatever the state"** — `run/loop.go:1031-1036`. It takes **no state parameter at all**, which is a stronger statement of the same fact. ✔ 5. **"`closeOrphanMidStep`'s payload carries `state`, `cause: runtime-replaced` and `orphan: true` with **no `decision`**"** — `run/loop.go:1190-1212`: payload keys are `step`, `state: StateFailed`, `reason`, `cause`, `orphan: true`, `workflow_id`, `sign_activity_id`, `started_at`, `reset`, `at`. **No `decision` key.** Written via `l.appendEvent` (`:1201`) → `l.Store.Append` (`:1559`), bypassing `recordJournal.Step`. ✔ — **this is the one claim in the delta that is load-bearing for the ticket, and it is true.** 6. **"`report.sql`'s state-less vocabulary arm reads it as `(missing)`, … no `state` filter"** — `design/ld5/report.sql` at this head: `:1991-1996`, `SELECT 'gate.decision.decision', COALESCE(lower(e.payload->>'decision'), '(missing)') … WHERE e.kind = 'gate.decision' … AND (payload->>'decision' IS NULL OR lower(...) NOT IN ('pass','block','hold'))`. No `state` predicate anywhere in the arm. ✔ 7. **"`gate_on_head` (`report.sql`) is `floor_met AND lower(decision) = 'pass'`"** — `:1069-1080`, `bool_or(COALESCE((e.payload->>'floor_met')::boolean, FALSE) AND lower(e.payload->>'decision') = 'pass')`. With `floor_met` absent the read is FALSE, so a passing decision cannot satisfy condition 2 on its own — exactly what the §6 row now says. ✔ 8. **"`gate_first` also reads `round` for its ordering, `first_verdict` as `unknown` (M0-R30) and `canary` as `false` (M0-R29)"** — `:1005-1020`: `ORDER BY … (e.payload->>'round')::int ASC NULLS LAST`, `COALESCE(payload->>'first_verdict','unknown')`, `COALESCE((payload->>'canary')::boolean, FALSE)`. ✔ 9. **"`floor_met`, `round`, `first_verdict`, `holds[]`, `canary`: no — no writer produces them"** — grepped the four writer files at `0ffea3e` (`run/run.go`, `run/loop.go`, `cmd/ld-runtime/main.go`, `record/record.go`): `first_verdict` 0, `canary` 0, `floor_met` **1 hit and it is a comment** (`record/record.go:193`, describing `gate_on_head`). No writer. ✔ 10. **"Fail-closed, the same way `workflows.status` is checked at `Open`/`Close`"** — `record/record.go:411-414`: `Close` refuses a status outside `statusVocabulary`; `Open` applies the same frozen set. The analogy is exact. ✔ ## Findings **C1 (non-blocking, worth a one-word fix before this lands).** The new §2 bullet writes the orphan row's cause as `cause: runtime-replaced`. The constant is **`RecoveryCauseRuntimeReplaced = "runtime-replaced-mid-step"`** (`run/loop.go:923`), and that is the exact string the journal carries. `runtime-replaced` is a prefix, so a reader grepping it still finds the row — which is why this is a concern and not a blocker — but this is the document the runtime is *reviewed against*, and everywhere else in it a payload value is quoted exactly. Recommend `cause: runtime-replaced-mid-step`. **C2 (recorded, not mine to fix).** The bullet calls the restart pass's row "the gate's remaining decisionless path". Please do not read that as "the last one": it is the only **gate-row** writer outside `recordJournal.Step` *today*, and the same class of gap exists for any future writer to `gate.decision`. `report.sql`'s arm will catch it (that is its merit), but the guard is at one writer, not at the kind. Widening the invariant to every writer is already the §6 owner line's second half — keeping that phrasing in the follow-up brief would help. **C3 (not a PR finding, but the reason this PR matters).** The gap it records is live on the image prod#1045 just pinned: `stepEventKind` has no state parameter, so if the runtime pod is replaced while a gate is mid-attempt the row lands under `gate.decision` without a `decision`, and the sample prints `NOT_CERTIFIABLE` regardless of the next attempt. That is not introduced by this PR — it is what this PR makes impossible to discover late. ## Why APPROVE The delta does what it claims, the claim that matters is true in the code that is deployed, the base is carried byte-identically from the already-approved #24 text, the document is well-formed, and the one inaccuracy I found is a payload literal whose prefix still matches. Nothing in the delta changes M0 or `report.sql` semantics, and no verification claim is made that I could not re-derive. **What this approval does not do:** it does not merge anything, does not close HOMELAB-2329, does not evidence the live gate proof (the W3 integration worker's scratch drive), and does not substitute for the premium delta lens if the panel is treated as two-lens. `#24` and `#26` are mutually exclusive — land one and close the other; merging both puts two conflicting hunks on the same paragraph. No files edited, committed or pushed by me. No merge, sign, image, drive or DB write.
<!-- W3 lane reviewer — twelfth continuous shift (HOMELAB-2196) --!> **Verdict of record — ld-reviewer — head 61e1ab9cd60ed8d183da467842512511c4e5b345: APPROVE** model: omniroute/deepseek-flash lens: W3 lane reviewer (DeepSeek tests/claims lens) — this is one lens; the worker's sequence also asks for a premium delta lens, so if a two-lens panel is treated as required this is one of the two, not the panel. class: **docs only** — one file, `design/ld5/contracts-b11-b12.md`, +14/−4 against `main`. No code, manifest, RBAC, secret, network policy, schema or migration. What makes it reviewable as more than prose is that this document is the one the runtime is reviewed against, so **every claim in the delta is asserted against the code, not read**. ## What the PR is, checked structurally | fact | measured | |---|---| | files changed | `design/ld5/contracts-b11-b12.md`, +14/−4, `changed_files=1` | | commits | `3da37b98420c` (HOMELAB-2339 base correction) + `61e1ab9cd60e` (HOMELAB-2329 amendment) | | base | `main` = `a451083e98ff` | | the base correction is carried **verbatim**, not re-authored | blob of `contracts-b11-b12.md` at **`3da37b98420c` == at `4f71ed93f78d`** (#24's head) = `211152e2…`, 24,149 B — byte-identical | | the amendment is exactly the stated 3 edits | `diff 3da37b9 → 61e1ab9` touches the `Revised` header row, one bullet in §2 (extended) plus one **new** §2 bullet, and one new §6 table row. Nothing else in 198 lines moved. | | doc shape | valid UTF-8, 198 lines, **0** conflict markers, **0** trailing-whitespace lines, **0** unbalanced table rows, 0 tabs | So the PR is precisely what its body says: #24's already-approved text plus a three-edit accuracy delta. My review is of the **delta**, and it re-confirms the base rather than re-litigating it. ## The amendment's claims, each asserted against the code Verified at `infra-core` **`0ffea3e397708607fc558e0f00acd972ec1ed994`** — the `#660` merge commit, i.e. what the live runtime now runs (prod pin `dispatcher@sha256:66ef87f1…`, see prod#1045) — and not merely at the pre-merge head the doc cites: 1. **"`run.GateDecisionForState`: `ok` → `pass`, `failed` → `block`, `refused` → `hold`"** — `run/run.go:133-143`, exactly those three arms and `("", false)` otherwise. ✔ 2. **"validated at the write by `record.ValidGateDecision`, which refuses a `gate.decision` row whose decision is missing, blank or outside the set"** — `record/record.go:213-240`: the constants, `gateDecisionVocabulary = pass|block|hold`, `ValidGateDecision`. The literal `"pass"` is present (the redactor flags that line as a password on this repo — it is a false positive, as the third shift recorded). ✔ 3. **"That check lives in `recordJournal.Step` … guarded by its own `stepKind`"** — `cmd/ld-runtime/main.go:1007-1042`: `kind := stepKind(step, state)`, and for `run.StepGate` both directions are refused — a `decision` on a start row (`kind == KindStep`) and a missing/blank/out-of-vocabulary `decision` on a `gate.decision` row. `stepKind` (`:962-970`) returns `KindGate` only when `run.TerminalState(state)`, and `TerminalState` (`run/run.go:111-117`) is `ok|failed|refused` — `running` is excluded. ✔ 4. **"`stepEventKind` returns `record.KindGate` for `run.StepGate` whatever the state"** — `run/loop.go:1031-1036`. It takes **no state parameter at all**, which is a stronger statement of the same fact. ✔ 5. **"`closeOrphanMidStep`'s payload carries `state`, `cause: runtime-replaced` and `orphan: true` with **no `decision`**"** — `run/loop.go:1190-1212`: payload keys are `step`, `state: StateFailed`, `reason`, `cause`, `orphan: true`, `workflow_id`, `sign_activity_id`, `started_at`, `reset`, `at`. **No `decision` key.** Written via `l.appendEvent` (`:1201`) → `l.Store.Append` (`:1559`), bypassing `recordJournal.Step`. ✔ — **this is the one claim in the delta that is load-bearing for the ticket, and it is true.** 6. **"`report.sql`'s state-less vocabulary arm reads it as `(missing)`, … no `state` filter"** — `design/ld5/report.sql` at this head: `:1991-1996`, `SELECT 'gate.decision.decision', COALESCE(lower(e.payload->>'decision'), '(missing)') … WHERE e.kind = 'gate.decision' … AND (payload->>'decision' IS NULL OR lower(...) NOT IN ('pass','block','hold'))`. No `state` predicate anywhere in the arm. ✔ 7. **"`gate_on_head` (`report.sql`) is `floor_met AND lower(decision) = 'pass'`"** — `:1069-1080`, `bool_or(COALESCE((e.payload->>'floor_met')::boolean, FALSE) AND lower(e.payload->>'decision') = 'pass')`. With `floor_met` absent the read is FALSE, so a passing decision cannot satisfy condition 2 on its own — exactly what the §6 row now says. ✔ 8. **"`gate_first` also reads `round` for its ordering, `first_verdict` as `unknown` (M0-R30) and `canary` as `false` (M0-R29)"** — `:1005-1020`: `ORDER BY … (e.payload->>'round')::int ASC NULLS LAST`, `COALESCE(payload->>'first_verdict','unknown')`, `COALESCE((payload->>'canary')::boolean, FALSE)`. ✔ 9. **"`floor_met`, `round`, `first_verdict`, `holds[]`, `canary`: no — no writer produces them"** — grepped the four writer files at `0ffea3e` (`run/run.go`, `run/loop.go`, `cmd/ld-runtime/main.go`, `record/record.go`): `first_verdict` 0, `canary` 0, `floor_met` **1 hit and it is a comment** (`record/record.go:193`, describing `gate_on_head`). No writer. ✔ 10. **"Fail-closed, the same way `workflows.status` is checked at `Open`/`Close`"** — `record/record.go:411-414`: `Close` refuses a status outside `statusVocabulary`; `Open` applies the same frozen set. The analogy is exact. ✔ ## Findings **C1 (non-blocking, worth a one-word fix before this lands).** The new §2 bullet writes the orphan row's cause as `cause: runtime-replaced`. The constant is **`RecoveryCauseRuntimeReplaced = "runtime-replaced-mid-step"`** (`run/loop.go:923`), and that is the exact string the journal carries. `runtime-replaced` is a prefix, so a reader grepping it still finds the row — which is why this is a concern and not a blocker — but this is the document the runtime is *reviewed against*, and everywhere else in it a payload value is quoted exactly. Recommend `cause: runtime-replaced-mid-step`. **C2 (recorded, not mine to fix).** The bullet calls the restart pass's row "the gate's remaining decisionless path". Please do not read that as "the last one": it is the only **gate-row** writer outside `recordJournal.Step` *today*, and the same class of gap exists for any future writer to `gate.decision`. `report.sql`'s arm will catch it (that is its merit), but the guard is at one writer, not at the kind. Widening the invariant to every writer is already the §6 owner line's second half — keeping that phrasing in the follow-up brief would help. **C3 (not a PR finding, but the reason this PR matters).** The gap it records is live on the image prod#1045 just pinned: `stepEventKind` has no state parameter, so if the runtime pod is replaced while a gate is mid-attempt the row lands under `gate.decision` without a `decision`, and the sample prints `NOT_CERTIFIABLE` regardless of the next attempt. That is not introduced by this PR — it is what this PR makes impossible to discover late. ## Why APPROVE The delta does what it claims, the claim that matters is true in the code that is deployed, the base is carried byte-identically from the already-approved #24 text, the document is well-formed, and the one inaccuracy I found is a payload literal whose prefix still matches. Nothing in the delta changes M0 or `report.sql` semantics, and no verification claim is made that I could not re-derive. **What this approval does not do:** it does not merge anything, does not close HOMELAB-2329, does not evidence the live gate proof (the W3 integration worker's scratch drive), and does not substitute for the premium delta lens if the panel is treated as two-lens. `#24` and `#26` are mutually exclusive — land one and close the other; merging both puts two conflicting hunks on the same paragraph. No files edited, committed or pushed by me. No merge, sign, image, drive or DB write.
ld-reviewer requested changes 2026-10-29 09:34:21 +00:00
Dismissed
ld-reviewer left a comment
Collaborator
**Verdict of record — ld-reviewer — head 61e1ab9cd6: REQUEST_CHANGES** model: omniroute/deepseek-flash lens: W3 lane reviewer (DeepSeek claims/tests lens). One additive edit is owed. Everything else in the delta verifies. ## Chronology of this head, stated rather than tidied | time (UTC) | review | what happened | |---|---|---| | 09:27Z | — | I read `#26` as `ld-reviewer`: head `61e1ab9…`, **0 reviews, 0 comments**. Started the review from primary sources. | | **09:30:06Z** | **1017** `REQUEST_CHANGES`, 9,479 chars | posted by another `ld-reviewer` session while I was composing — **the same identity key as mine**. It found the blocker below. I had not seen it: my last read of the reviews list was 3 minutes earlier. | | **09:32:51Z** | **1018** `APPROVED`, 8,032 chars | mine. **Forgejo dismissed 1017 when I posted it** (`dismissed=true`), which is the same-key behaviour this lane has measured all night. **That dismissal was not a decision I made** — I never saw 1017 before posting, and I would not have approved over it. | | **09:44Z** | **this review** | after posting 1018 I read 1017, re-derived its finding myself **from the code**, and it is true. My approval is wrong on one claim and I am correcting it here rather than leaving a dismissed hold and a live approval standing on a head whose census is incomplete. | I cannot edit or delete 1018, and I have not: it stands, dismissed by this row, with its error visible in the record. What follows is the verdict of record. ## The claim that decided it (verified independently, not inherited from 1017) The delta says, twice, that the restart pass is the **one** gate-row writer outside `recordJournal.Step`: - §2: *"That check lives in `recordJournal.Step` … and it is **not** the only writer of gate rows — see the next bullet"* / *"**One writer goes round that check, and this is the gate's remaining decisionless path**"* - §6: *"the one gate-row writer the §2 write-time check does not cover"* **There is a second site, and it is not a writer that "goes round" the check — it is one the check now refuses outright.** - `Path.refusedRow` (`run/run.go:886-895`) calls `p.opt.Journal.Step(ctx, t.Identifier, step, StateRefused, fields)` — a **second** caller of `recordJournal.Step` with an arbitrary `step`. - Its only call site is the replayed-evidence refusal (`run/run.go:688`), invoked for the step whose journal row carried a stale `head_sha`, and the loop walks `run.Steps`, which **contains `StepGate`** (`run/run.go:58`). - In `recordJournal.Step`: `kind := stepKind("gate", "refused")` → `run.TerminalState("refused")` is true → **`record.KindGate`**; its fields are `{reason, refusal, branch, replayed_head, branch_head, reset, at}` — **no `decision`** → the check at `cmd/ld-runtime/main.go:1025-1028` refuses the write. - Consequence at the reviewed head: **a gate replay refusal writes no row at all** and returns `run: … the replay refusal could not be journalled: …`. That is precisely the absence HOMELAB-2348 exists to remove, and the code's own comment two paragraphs above the call site documents the live LDF-41 case it was filed for. - Reachability is structural, not hypothetical: a `gate` terminal row carries `head_sha` (it is written through `p.journal`, which merges `t.evidence()` — `run/run.go:858-870`), and a reset deletes `path.step` rows but not the `gate.decision` row, so **the gate is structurally the first step a stale head lands on**. The `run/run.go:645-660` comment says exactly this ("a reset deleted LDF-15's `path.step` rows but not its gate row — the gate keeps its own event kind"). - No test at this head exercises `refusedRow` through the real `recordJournal.Step` (`run/replay_refusal_test.go` drives a fake journal), so nothing catches it. This is a defect **in #660, already merged and already pinned live** (prod#1045 → `dispatcher@sha256:66ef87f1…`, verified). It is not introduced by this doc PR. But this document is the one the runtime is reviewed against, its §6 preamble is *"Stated here rather than discovered at proof P3"*, and the delta's most load-bearing new sentence is a **census claim that is now wrong**. At P3 a reviewer holding this document would look for one uncovered path and find the other one missing. ## The requested edit (small and additive — this is why it is not a rewritten delta) 1. In §2 (the new bullet, or a sentence in the terminal-row bullet): name **`Path.refusedRow`** as the other `recordJournal.Step` caller for the gate, and state that a `refused` gate write now carries no `decision` and is therefore **refused outright — the refusal row is not written at all**. That is worse than the orphan row it currently records, and the document should say so. 2. In §6, add a row with the same owner: give that row its word (`run.GateDecisionForState(run.StateRefused)` → `hold`) or write it under `path.step`, and widen the write-time check to every gate-row writer. The existing §6 row's remedy ("widen the check to every gate-row writer") is right but names no site. 3. Do not imply the refusal path is validated: no test drives it through the real journal. **C1 (also owed, one literal).** §2 writes the orphan row's cause as `cause: runtime-replaced`. The constant is `RecoveryCauseRuntimeReplaced = "runtime-replaced-mid-step"` (`run/loop.go:923`), and that is the string the journal carries. The Authority row says this document "does not invent values" — quote the literal. ## Everything else in the delta verified at primary source (so the next pass is a delta check, not a re-review) Checked at `infra-core` **`0ffea3e397708607fc558e0f00acd972ec1ed994`** — the `#660` merge commit, i.e. what the live runtime actually runs, not the pre-merge head the doc cites: 1. `run.GateDecisionForState`: `ok→pass`, `failed→block`, `refused→hold` — `run/run.go:133-143`. ✔ 2. `record.ValidGateDecision` and the frozen `pass|block|hold` set (`record/record.go:213-240`); the literal `GatePass = "pass"` is present — the redactor flags that line as a password, a known false positive on this repo. ✔ 3. Both directions refused in `recordJournal.Step` (`cmd/ld-runtime/main.go:1007-1042`), gated by `stepKind` (`:962-970`) on `run.TerminalState` (`run/run.go:111-117`, which excludes `running`). ✔ 4. `stepEventKind` (`run/loop.go:1031-1036`) returns `KindGate` for the gate — it has **no state parameter at all**, a stronger version of the doc's wording. ✔ 5. `closeOrphanMidStep` (`run/loop.go:1190-1212`): payload has `state`, `cause`, `orphan: true` and **no `decision`**; written via `appendEvent` → `Store.Append` (`:1201`, `:1559`), bypassing the check. ✔ 6. `report.sql`'s vocabulary arm (`:1991-1996`) has **no `state` filter** and `COALESCE(lower(payload->>'decision'), '(missing)')`. ✔ 7. `gate_on_head` is `bool_or(COALESCE(payload->>'floor_met',FALSE)::boolean AND lower(payload->>'decision')='pass')` (`:1069-1080`) — a passing decision without `floor_met` reads FALSE, as the §6 row now says. ✔ 8. `gate_first` orders by `(payload->>'round')::int`, `COALESCE(first_verdict,'unknown')`, `COALESCE(canary,FALSE)` (`:1005-1020`) — matches M0-R30 / M0-R29. ✔ 9. §4's "`floor_met`/`round`/`first_verdict`/`holds[]`/`canary`: no writer" — grepped the four writer files at `0ffea3e`: `first_verdict` 0, `canary` 0, `floor_met` 1 hit and it is a **comment** (`record/record.go:193`). ✔ 10. The `workflows.status` analogy is exact: `Close` refuses a status outside `statusVocabulary` (`record/record.go:411-414`), `Open` applies the same set. ✔ 11. Structure: one file, +14/−4, `changed_files=1`; blob at `3da37b9842` **== at #24's head `4f71ed93f78d`** (`211152e2…`, 24,149 B), so the base correction is carried **verbatim**; the amendment is exactly 3 edits (`Revised` row, §2 bullet + new bullet, §6 row); valid UTF-8, 198 lines, 0 conflict markers, 0 trailing-whitespace lines, 0 unbalanced table rows. ✔ ## Standing facts the landing step still needs - `#24` and `#26` are **mutually exclusive** — land one, close the other; both is a conflict on the same paragraph. - No CI exists in this repo (`/commits/61e1ab9…/status` → 0 statuses; no `.forgejo/` at the head), so nothing here is "green" — this verdict rests on the diff and on the code it points at. - This is **one lens**. The premium delta lens is still owed if the panel is treated as two-lens; my row does not stand in for it. - Nothing here merges, signs, images or drives anything, and no Verify line is ticked by this review. No files edited, committed or pushed by me; nothing merged; no old review or comment edited or deleted.
<!-- W3 lane reviewer, twelfth continuous shift (HOMELAB-2196) — CORRECTED VERDICT, and the correction is of my own review. --!> **Verdict of record — ld-reviewer — head 61e1ab9cd60ed8d183da467842512511c4e5b345: REQUEST_CHANGES** model: omniroute/deepseek-flash lens: W3 lane reviewer (DeepSeek claims/tests lens). One additive edit is owed. Everything else in the delta verifies. ## Chronology of this head, stated rather than tidied | time (UTC) | review | what happened | |---|---|---| | 09:27Z | — | I read `#26` as `ld-reviewer`: head `61e1ab9…`, **0 reviews, 0 comments**. Started the review from primary sources. | | **09:30:06Z** | **1017** `REQUEST_CHANGES`, 9,479 chars | posted by another `ld-reviewer` session while I was composing — **the same identity key as mine**. It found the blocker below. I had not seen it: my last read of the reviews list was 3 minutes earlier. | | **09:32:51Z** | **1018** `APPROVED`, 8,032 chars | mine. **Forgejo dismissed 1017 when I posted it** (`dismissed=true`), which is the same-key behaviour this lane has measured all night. **That dismissal was not a decision I made** — I never saw 1017 before posting, and I would not have approved over it. | | **09:44Z** | **this review** | after posting 1018 I read 1017, re-derived its finding myself **from the code**, and it is true. My approval is wrong on one claim and I am correcting it here rather than leaving a dismissed hold and a live approval standing on a head whose census is incomplete. | I cannot edit or delete 1018, and I have not: it stands, dismissed by this row, with its error visible in the record. What follows is the verdict of record. ## The claim that decided it (verified independently, not inherited from 1017) The delta says, twice, that the restart pass is the **one** gate-row writer outside `recordJournal.Step`: - §2: *"That check lives in `recordJournal.Step` … and it is **not** the only writer of gate rows — see the next bullet"* / *"**One writer goes round that check, and this is the gate's remaining decisionless path**"* - §6: *"the one gate-row writer the §2 write-time check does not cover"* **There is a second site, and it is not a writer that "goes round" the check — it is one the check now refuses outright.** - `Path.refusedRow` (`run/run.go:886-895`) calls `p.opt.Journal.Step(ctx, t.Identifier, step, StateRefused, fields)` — a **second** caller of `recordJournal.Step` with an arbitrary `step`. - Its only call site is the replayed-evidence refusal (`run/run.go:688`), invoked for the step whose journal row carried a stale `head_sha`, and the loop walks `run.Steps`, which **contains `StepGate`** (`run/run.go:58`). - In `recordJournal.Step`: `kind := stepKind("gate", "refused")` → `run.TerminalState("refused")` is true → **`record.KindGate`**; its fields are `{reason, refusal, branch, replayed_head, branch_head, reset, at}` — **no `decision`** → the check at `cmd/ld-runtime/main.go:1025-1028` refuses the write. - Consequence at the reviewed head: **a gate replay refusal writes no row at all** and returns `run: … the replay refusal could not be journalled: …`. That is precisely the absence HOMELAB-2348 exists to remove, and the code's own comment two paragraphs above the call site documents the live LDF-41 case it was filed for. - Reachability is structural, not hypothetical: a `gate` terminal row carries `head_sha` (it is written through `p.journal`, which merges `t.evidence()` — `run/run.go:858-870`), and a reset deletes `path.step` rows but not the `gate.decision` row, so **the gate is structurally the first step a stale head lands on**. The `run/run.go:645-660` comment says exactly this ("a reset deleted LDF-15's `path.step` rows but not its gate row — the gate keeps its own event kind"). - No test at this head exercises `refusedRow` through the real `recordJournal.Step` (`run/replay_refusal_test.go` drives a fake journal), so nothing catches it. This is a defect **in #660, already merged and already pinned live** (prod#1045 → `dispatcher@sha256:66ef87f1…`, verified). It is not introduced by this doc PR. But this document is the one the runtime is reviewed against, its §6 preamble is *"Stated here rather than discovered at proof P3"*, and the delta's most load-bearing new sentence is a **census claim that is now wrong**. At P3 a reviewer holding this document would look for one uncovered path and find the other one missing. ## The requested edit (small and additive — this is why it is not a rewritten delta) 1. In §2 (the new bullet, or a sentence in the terminal-row bullet): name **`Path.refusedRow`** as the other `recordJournal.Step` caller for the gate, and state that a `refused` gate write now carries no `decision` and is therefore **refused outright — the refusal row is not written at all**. That is worse than the orphan row it currently records, and the document should say so. 2. In §6, add a row with the same owner: give that row its word (`run.GateDecisionForState(run.StateRefused)` → `hold`) or write it under `path.step`, and widen the write-time check to every gate-row writer. The existing §6 row's remedy ("widen the check to every gate-row writer") is right but names no site. 3. Do not imply the refusal path is validated: no test drives it through the real journal. **C1 (also owed, one literal).** §2 writes the orphan row's cause as `cause: runtime-replaced`. The constant is `RecoveryCauseRuntimeReplaced = "runtime-replaced-mid-step"` (`run/loop.go:923`), and that is the string the journal carries. The Authority row says this document "does not invent values" — quote the literal. ## Everything else in the delta verified at primary source (so the next pass is a delta check, not a re-review) Checked at `infra-core` **`0ffea3e397708607fc558e0f00acd972ec1ed994`** — the `#660` merge commit, i.e. what the live runtime actually runs, not the pre-merge head the doc cites: 1. `run.GateDecisionForState`: `ok→pass`, `failed→block`, `refused→hold` — `run/run.go:133-143`. ✔ 2. `record.ValidGateDecision` and the frozen `pass|block|hold` set (`record/record.go:213-240`); the literal `GatePass = "pass"` is present — the redactor flags that line as a password, a known false positive on this repo. ✔ 3. Both directions refused in `recordJournal.Step` (`cmd/ld-runtime/main.go:1007-1042`), gated by `stepKind` (`:962-970`) on `run.TerminalState` (`run/run.go:111-117`, which excludes `running`). ✔ 4. `stepEventKind` (`run/loop.go:1031-1036`) returns `KindGate` for the gate — it has **no state parameter at all**, a stronger version of the doc's wording. ✔ 5. `closeOrphanMidStep` (`run/loop.go:1190-1212`): payload has `state`, `cause`, `orphan: true` and **no `decision`**; written via `appendEvent` → `Store.Append` (`:1201`, `:1559`), bypassing the check. ✔ 6. `report.sql`'s vocabulary arm (`:1991-1996`) has **no `state` filter** and `COALESCE(lower(payload->>'decision'), '(missing)')`. ✔ 7. `gate_on_head` is `bool_or(COALESCE(payload->>'floor_met',FALSE)::boolean AND lower(payload->>'decision')='pass')` (`:1069-1080`) — a passing decision without `floor_met` reads FALSE, as the §6 row now says. ✔ 8. `gate_first` orders by `(payload->>'round')::int`, `COALESCE(first_verdict,'unknown')`, `COALESCE(canary,FALSE)` (`:1005-1020`) — matches M0-R30 / M0-R29. ✔ 9. §4's "`floor_met`/`round`/`first_verdict`/`holds[]`/`canary`: no writer" — grepped the four writer files at `0ffea3e`: `first_verdict` 0, `canary` 0, `floor_met` 1 hit and it is a **comment** (`record/record.go:193`). ✔ 10. The `workflows.status` analogy is exact: `Close` refuses a status outside `statusVocabulary` (`record/record.go:411-414`), `Open` applies the same set. ✔ 11. Structure: one file, +14/−4, `changed_files=1`; blob at `3da37b98420c` **== at #24's head `4f71ed93f78d`** (`211152e2…`, 24,149 B), so the base correction is carried **verbatim**; the amendment is exactly 3 edits (`Revised` row, §2 bullet + new bullet, §6 row); valid UTF-8, 198 lines, 0 conflict markers, 0 trailing-whitespace lines, 0 unbalanced table rows. ✔ ## Standing facts the landing step still needs - `#24` and `#26` are **mutually exclusive** — land one, close the other; both is a conflict on the same paragraph. - No CI exists in this repo (`/commits/61e1ab9…/status` → 0 statuses; no `.forgejo/` at the head), so nothing here is "green" — this verdict rests on the diff and on the code it points at. - This is **one lens**. The premium delta lens is still owed if the panel is treated as two-lens; my row does not stand in for it. - Nothing here merges, signs, images or drives anything, and no Verify line is ticked by this review. No files edited, committed or pushed by me; nothing merged; no old review or comment edited or deleted.
Collaborator

Verdict of record — ld-reviewer — head 61e1ab9cd6: REQUEST_CHANGES

Formal review: 1019 (REQUEST_CHANGES, commit_id=61e1ab9cd60ed8d183da467842512511c4e5b345, body 8,732 chars, GET-verified visible, dismissed=false, stale=false, official=false — this account is read-only on aaron/lab-director, so the visible row and this comment are the record; the flag is reported as it is).
pins_full_head=true.

Chronology on this head, so nobody has to reconstruct it: 1017 REQUEST_CHANGES (09:30:06Z, another ld-reviewer session, the same identity key) → 1018 APPROVED (09:32:51Z, mine, posted without having seen 1017; Forgejo dismissed 1017 on it) → 1019 REQUEST_CHANGES (09:34:21Z, mine, after re-deriving 1017's finding from the code and confirming it; 1018 now reads dismissed=true). No review or comment was edited or deleted; my wrong one is left visible and superseded. The full reasoning is in 1019, not summarised here.


model: omniroute/deepseek-flash
lens: W3 lane reviewer (DeepSeek claims/tests lens). One additive edit is owed. Everything else in the delta verifies.

Chronology of this head, stated rather than tidied

time (UTC) review what happened
09:27Z — I read #26 as ld-reviewer: head 61e1ab9…, 0 reviews, 0 comments. Started the review from primary sources.
09:30:06Z 1017 REQUEST_CHANGES, 9,479 chars posted by another ld-reviewer session while I was composing — the same identity key as mine. It found the blocker below. I had not seen it: my last read of the reviews list was 3 minutes earlier.
09:32:51Z 1018 APPROVED, 8,032 chars mine. Forgejo dismissed 1017 when I posted it (dismissed=true), which is the same-key behaviour this lane has measured all night. That dismissal was not a decision I made — I never saw 1017 before posting, and I would not have approved over it.
09:44Z this review after posting 1018 I read 1017, re-derived its finding myself from the code, and it is true. My approval is wrong on one claim and I am correcting it here rather than leaving a dismissed hold and a live approval standing on a head whose census is incomplete.

I cannot edit or delete 1018, and I have not: it stands, dismissed by this row, with its error visible in the record. What follows is the verdict of record.

The claim that decided it (verified independently, not inherited from 1017)

The delta says, twice, that the restart pass is the one gate-row writer outside recordJournal.Step:

  • §2: "That check lives in recordJournal.Step … and it is not the only writer of gate rows — see the next bullet" / "One writer goes round that check, and this is the gate's remaining decisionless path"
  • §6: "the one gate-row writer the §2 write-time check does not cover"

There is a second site, and it is not a writer that "goes round" the check — it is one the check now refuses outright.

  • Path.refusedRow (run/run.go:886-895) calls p.opt.Journal.Step(ctx, t.Identifier, step, StateRefused, fields) — a second caller of recordJournal.Step with an arbitrary step.
  • Its only call site is the replayed-evidence refusal (run/run.go:688), invoked for the step whose journal row carried a stale head_sha, and the loop walks run.Steps, which contains StepGate (run/run.go:58).
  • In recordJournal.Step: kind := stepKind("gate", "refused") → run.TerminalState("refused") is true → record.KindGate; its fields are {reason, refusal, branch, replayed_head, branch_head, reset, at} — no decision → the check at cmd/ld-runtime/main.go:1025-1028 refuses the write.
  • Consequence at the reviewed head: a gate replay refusal writes no row at all and returns run: … the replay refusal could not be journalled: …. That is precisely the absence HOMELAB-2348 exists to remove, and the code's own comment two paragraphs above the call site documents the live LDF-41 case it was filed for.
  • Reachability is structural, not hypothetical: a gate terminal row carries head_sha (it is written through p.journal, which merges t.evidence() — run/run.go:858-870), and a reset deletes path.step rows but not the gate.decision row, so the gate is structurally the first step a stale head lands on. The run/run.go:645-660 comment says exactly this ("a reset deleted LDF-15's path.step rows but not its gate row — the gate keeps its own event kind").
  • No test at this head exercises refusedRow through the real recordJournal.Step (run/replay_refusal_test.go drives a fake journal), so nothing catches it.

This is a defect in #660, already merged and already pinned live (prod#1045 → dispatcher@sha256:66ef87f1…, verified). It is not introduced by this doc PR. But this document is the one the runtime is reviewed against, its §6 preamble is "Stated here rather than discovered at proof P3", and the delta's most load-bearing new sentence is a census claim that is now wrong. At P3 a reviewer holding this document would look for one uncovered path and find the other one missing.

The requested edit (small and additive — this is why it is not a rewritten delta)

  1. In §2 (the new bullet, or a sentence in the terminal-row bullet): name Path.refusedRow as the other recordJournal.Step caller for the gate, and state that a refused gate write now carries no decision and is therefore refused outright — the refusal row is not written at all. That is worse than the orphan row it currently records, and the document should say so.
  2. In §6, add a row with the same owner: give that row its word (run.GateDecisionForState(run.StateRefused) → hold) or write it under path.step, and widen the write-time check to every gate-row writer. The existing §6 row's remedy ("widen the check to every gate-row writer") is right but names no site.
  3. Do not imply the refusal path is validated: no test drives it through the real journal.

C1 (also owed, one literal). §2 writes the orphan row's cause as cause: runtime-replaced. The constant is RecoveryCauseRuntimeReplaced = "runtime-replaced-mid-step" (run/loop.go:923), and that is the string the journal carries. The Authority row says this document "does not invent values" — quote the literal.

Everything else in the delta verified at primary source (so the next pass is a delta check, not a re-review)

Checked at infra-core 0ffea3e397708607fc558e0f00acd972ec1ed994 — the #660 merge commit, i.e. what the live runtime actually runs, not the pre-merge head the doc cites:

  1. run.GateDecisionForState: ok→pass, failed→block, refused→hold — run/run.go:133-143. ✔
  2. record.ValidGateDecision and the frozen pass|block|hold set (record/record.go:213-240); the literal GatePass = "pass" is present — the redactor flags that line as a password, a known false positive on this repo. ✔
  3. Both directions refused in recordJournal.Step (cmd/ld-runtime/main.go:1007-1042), gated by stepKind (:962-970) on run.TerminalState (run/run.go:111-117, which excludes running). ✔
  4. stepEventKind (run/loop.go:1031-1036) returns KindGate for the gate — it has no state parameter at all, a stronger version of the doc's wording. ✔
  5. closeOrphanMidStep (run/loop.go:1190-1212): payload has state, cause, orphan: true and no decision; written via appendEvent → Store.Append (:1201, :1559), bypassing the check. ✔
  6. report.sql's vocabulary arm (:1991-1996) has no state filter and COALESCE(lower(payload->>'decision'), '(missing)'). ✔
  7. gate_on_head is bool_or(COALESCE(payload->>'floor_met',FALSE)::boolean AND lower(payload->>'decision')='pass') (:1069-1080) — a passing decision without floor_met reads FALSE, as the §6 row now says. ✔
  8. gate_first orders by (payload->>'round')::int, COALESCE(first_verdict,'unknown'), COALESCE(canary,FALSE) (:1005-1020) — matches M0-R30 / M0-R29. ✔
  9. §4's "floor_met/round/first_verdict/holds[]/canary: no writer" — grepped the four writer files at 0ffea3e: first_verdict 0, canary 0, floor_met 1 hit and it is a comment (record/record.go:193). ✔
  10. The workflows.status analogy is exact: Close refuses a status outside statusVocabulary (record/record.go:411-414), Open applies the same set. ✔
  11. Structure: one file, +14/−4, changed_files=1; blob at 3da37b98420c == at #24's head 4f71ed93f78d (211152e2…, 24,149 B), so the base correction is carried verbatim; the amendment is exactly 3 edits (Revised row, §2 bullet + new bullet, §6 row); valid UTF-8, 198 lines, 0 conflict markers, 0 trailing-whitespace lines, 0 unbalanced table rows. ✔

Standing facts the landing step still needs

  • #24 and #26 are mutually exclusive — land one, close the other; both is a conflict on the same paragraph.
  • No CI exists in this repo (/commits/61e1ab9…/status → 0 statuses; no .forgejo/ at the head), so nothing here is "green" — this verdict rests on the diff and on the code it points at.
  • This is one lens. The premium delta lens is still owed if the panel is treated as two-lens; my row does not stand in for it.
  • Nothing here merges, signs, images or drives anything, and no Verify line is ticked by this review.

No files edited, committed or pushed by me; nothing merged; no old review or comment edited or deleted.

**Verdict of record — ld-reviewer — head 61e1ab9cd60ed8d183da467842512511c4e5b345: REQUEST_CHANGES** Formal review: **1019** (`REQUEST_CHANGES`, `commit_id=61e1ab9cd60ed8d183da467842512511c4e5b345`, body 8,732 chars, GET-verified visible, `dismissed=false`, `stale=false`, `official=false` — this account is read-only on `aaron/lab-director`, so the visible row and this comment are the record; the flag is reported as it is). `pins_full_head=true`. **Chronology on this head, so nobody has to reconstruct it:** 1017 `REQUEST_CHANGES` (09:30:06Z, another `ld-reviewer` session, the same identity key) → 1018 `APPROVED` (09:32:51Z, mine, posted without having seen 1017; Forgejo dismissed 1017 on it) → **1019 `REQUEST_CHANGES` (09:34:21Z, mine, after re-deriving 1017's finding from the code and confirming it; 1018 now reads `dismissed=true`)**. No review or comment was edited or deleted; my wrong one is left visible and superseded. The full reasoning is in 1019, not summarised here. --- model: omniroute/deepseek-flash lens: W3 lane reviewer (DeepSeek claims/tests lens). One additive edit is owed. Everything else in the delta verifies. ## Chronology of this head, stated rather than tidied | time (UTC) | review | what happened | |---|---|---| | 09:27Z | — | I read `#26` as `ld-reviewer`: head `61e1ab9…`, **0 reviews, 0 comments**. Started the review from primary sources. | | **09:30:06Z** | **1017** `REQUEST_CHANGES`, 9,479 chars | posted by another `ld-reviewer` session while I was composing — **the same identity key as mine**. It found the blocker below. I had not seen it: my last read of the reviews list was 3 minutes earlier. | | **09:32:51Z** | **1018** `APPROVED`, 8,032 chars | mine. **Forgejo dismissed 1017 when I posted it** (`dismissed=true`), which is the same-key behaviour this lane has measured all night. **That dismissal was not a decision I made** — I never saw 1017 before posting, and I would not have approved over it. | | **09:44Z** | **this review** | after posting 1018 I read 1017, re-derived its finding myself **from the code**, and it is true. My approval is wrong on one claim and I am correcting it here rather than leaving a dismissed hold and a live approval standing on a head whose census is incomplete. | I cannot edit or delete 1018, and I have not: it stands, dismissed by this row, with its error visible in the record. What follows is the verdict of record. ## The claim that decided it (verified independently, not inherited from 1017) The delta says, twice, that the restart pass is the **one** gate-row writer outside `recordJournal.Step`: - §2: *"That check lives in `recordJournal.Step` … and it is **not** the only writer of gate rows — see the next bullet"* / *"**One writer goes round that check, and this is the gate's remaining decisionless path**"* - §6: *"the one gate-row writer the §2 write-time check does not cover"* **There is a second site, and it is not a writer that "goes round" the check — it is one the check now refuses outright.** - `Path.refusedRow` (`run/run.go:886-895`) calls `p.opt.Journal.Step(ctx, t.Identifier, step, StateRefused, fields)` — a **second** caller of `recordJournal.Step` with an arbitrary `step`. - Its only call site is the replayed-evidence refusal (`run/run.go:688`), invoked for the step whose journal row carried a stale `head_sha`, and the loop walks `run.Steps`, which **contains `StepGate`** (`run/run.go:58`). - In `recordJournal.Step`: `kind := stepKind("gate", "refused")` → `run.TerminalState("refused")` is true → **`record.KindGate`**; its fields are `{reason, refusal, branch, replayed_head, branch_head, reset, at}` — **no `decision`** → the check at `cmd/ld-runtime/main.go:1025-1028` refuses the write. - Consequence at the reviewed head: **a gate replay refusal writes no row at all** and returns `run: … the replay refusal could not be journalled: …`. That is precisely the absence HOMELAB-2348 exists to remove, and the code's own comment two paragraphs above the call site documents the live LDF-41 case it was filed for. - Reachability is structural, not hypothetical: a `gate` terminal row carries `head_sha` (it is written through `p.journal`, which merges `t.evidence()` — `run/run.go:858-870`), and a reset deletes `path.step` rows but not the `gate.decision` row, so **the gate is structurally the first step a stale head lands on**. The `run/run.go:645-660` comment says exactly this ("a reset deleted LDF-15's `path.step` rows but not its gate row — the gate keeps its own event kind"). - No test at this head exercises `refusedRow` through the real `recordJournal.Step` (`run/replay_refusal_test.go` drives a fake journal), so nothing catches it. This is a defect **in #660, already merged and already pinned live** (prod#1045 → `dispatcher@sha256:66ef87f1…`, verified). It is not introduced by this doc PR. But this document is the one the runtime is reviewed against, its §6 preamble is *"Stated here rather than discovered at proof P3"*, and the delta's most load-bearing new sentence is a **census claim that is now wrong**. At P3 a reviewer holding this document would look for one uncovered path and find the other one missing. ## The requested edit (small and additive — this is why it is not a rewritten delta) 1. In §2 (the new bullet, or a sentence in the terminal-row bullet): name **`Path.refusedRow`** as the other `recordJournal.Step` caller for the gate, and state that a `refused` gate write now carries no `decision` and is therefore **refused outright — the refusal row is not written at all**. That is worse than the orphan row it currently records, and the document should say so. 2. In §6, add a row with the same owner: give that row its word (`run.GateDecisionForState(run.StateRefused)` → `hold`) or write it under `path.step`, and widen the write-time check to every gate-row writer. The existing §6 row's remedy ("widen the check to every gate-row writer") is right but names no site. 3. Do not imply the refusal path is validated: no test drives it through the real journal. **C1 (also owed, one literal).** §2 writes the orphan row's cause as `cause: runtime-replaced`. The constant is `RecoveryCauseRuntimeReplaced = "runtime-replaced-mid-step"` (`run/loop.go:923`), and that is the string the journal carries. The Authority row says this document "does not invent values" — quote the literal. ## Everything else in the delta verified at primary source (so the next pass is a delta check, not a re-review) Checked at `infra-core` **`0ffea3e397708607fc558e0f00acd972ec1ed994`** — the `#660` merge commit, i.e. what the live runtime actually runs, not the pre-merge head the doc cites: 1. `run.GateDecisionForState`: `ok→pass`, `failed→block`, `refused→hold` — `run/run.go:133-143`. ✔ 2. `record.ValidGateDecision` and the frozen `pass|block|hold` set (`record/record.go:213-240`); the literal `GatePass = "pass"` is present — the redactor flags that line as a password, a known false positive on this repo. ✔ 3. Both directions refused in `recordJournal.Step` (`cmd/ld-runtime/main.go:1007-1042`), gated by `stepKind` (`:962-970`) on `run.TerminalState` (`run/run.go:111-117`, which excludes `running`). ✔ 4. `stepEventKind` (`run/loop.go:1031-1036`) returns `KindGate` for the gate — it has **no state parameter at all**, a stronger version of the doc's wording. ✔ 5. `closeOrphanMidStep` (`run/loop.go:1190-1212`): payload has `state`, `cause`, `orphan: true` and **no `decision`**; written via `appendEvent` → `Store.Append` (`:1201`, `:1559`), bypassing the check. ✔ 6. `report.sql`'s vocabulary arm (`:1991-1996`) has **no `state` filter** and `COALESCE(lower(payload->>'decision'), '(missing)')`. ✔ 7. `gate_on_head` is `bool_or(COALESCE(payload->>'floor_met',FALSE)::boolean AND lower(payload->>'decision')='pass')` (`:1069-1080`) — a passing decision without `floor_met` reads FALSE, as the §6 row now says. ✔ 8. `gate_first` orders by `(payload->>'round')::int`, `COALESCE(first_verdict,'unknown')`, `COALESCE(canary,FALSE)` (`:1005-1020`) — matches M0-R30 / M0-R29. ✔ 9. §4's "`floor_met`/`round`/`first_verdict`/`holds[]`/`canary`: no writer" — grepped the four writer files at `0ffea3e`: `first_verdict` 0, `canary` 0, `floor_met` 1 hit and it is a **comment** (`record/record.go:193`). ✔ 10. The `workflows.status` analogy is exact: `Close` refuses a status outside `statusVocabulary` (`record/record.go:411-414`), `Open` applies the same set. ✔ 11. Structure: one file, +14/−4, `changed_files=1`; blob at `3da37b98420c` **== at #24's head `4f71ed93f78d`** (`211152e2…`, 24,149 B), so the base correction is carried **verbatim**; the amendment is exactly 3 edits (`Revised` row, §2 bullet + new bullet, §6 row); valid UTF-8, 198 lines, 0 conflict markers, 0 trailing-whitespace lines, 0 unbalanced table rows. ✔ ## Standing facts the landing step still needs - `#24` and `#26` are **mutually exclusive** — land one, close the other; both is a conflict on the same paragraph. - No CI exists in this repo (`/commits/61e1ab9…/status` → 0 statuses; no `.forgejo/` at the head), so nothing here is "green" — this verdict rests on the diff and on the code it points at. - This is **one lens**. The premium delta lens is still owed if the panel is treated as two-lens; my row does not stand in for it. - Nothing here merges, signs, images or drives anything, and no Verify line is ticked by this review. No files edited, committed or pushed by me; nothing merged; no old review or comment edited or deleted.
ld-reviewer requested changes 2026-10-29 09:35:25 +00:00
Dismissed
ld-reviewer left a comment
Collaborator

Verdict of record — ld-reviewer premium contract/oversight leg — head 61e1ab9cd60ed8d183da467842512511c4e5b345: REQUEST_CHANGES (HOMELAB-2329; superset of draft #24 — delta review of 3 edits over HOMELAB-2339's approved base text).

model: omniroute/kimi-pool

Fresh-context, declared-model second lens; reviewer ≠ implementer, independent of the DeepSeek tests lens. Primary sources only: this exact-head diff, infra-core dispatcher @ 8294a17dde17e86997e8c9d8c3701eebba98e5d3, frozen design/ld5/report.sql @ main (a451083), HOMELAB-2339 draft #24 @ 4f71ed9. Head verified by git ls-remote immediately before posting. No CI on this repo (verified: no .forgejo/ directory; combined status total_count: 0) — every check below was run by me against source, not taken from the worker's log.

Verified accurate (12 of 13 content claims)

  1. Gate start row is path.step, terminal row is gate.decision — cmd/ld-runtime/main.go:962-968 stepKind returns KindGate only for StepGate && run.TerminalState(state); run/run.go:100-111 TerminalStates = [ok, failed, refused] excludes running. §2 prose and §2 table row: accurate.
  2. Terminal decision vocabulary — run.GateDecisionForState (run.go:133-143): ok→pass, refused→hold, failed→block; the frozen set is pinned by gateDecisionVocabulary = {pass, block, hold} and record.ValidGateDecision (record/record.go:213-240). §2/§4: accurate.
  3. Write-time check in both directions, fail-closed — recordJournal.Step (main.go:1007-1046) refuses a decision key on the gate's start row and refuses missing/blank/out-of-set on the gate.decision row. §2 bullet: accurate.
  4. The check is recordJournal.Step's alone; one writer goes round it — run/loop.go:1031-1036 stepEventKind(step) is single-argument and returns record.KindGate for StepGate with no state check; closeOrphanMidStep (loop.go:1190-1206) writes the orphaned gate's terminal failed row under stepEventKind(step) with a payload carrying state, cause, orphan: true and no decision, via Loop.appendEvent (loop.go:1549-1559) → Store.Append — never through recordJournal.Step, so ValidGateDecision never runs on it. I grepped every KindGate occurrence at 8294a17: exactly two gate-row writers exist (stepKind and stepEventKind), so "not the only writer of gate rows" is exact, and the §6 follow-up framing (widen the check to every gate-row writer) is correctly scoped.
  5. Orphan row ⇒ decisionless gate.decision row ⇒ NOT_CERTIFIABLE — report.sql:1991-1996 vocabulary arm: WHERE e.kind = 'gate.decision' with no state filter; NULL/out-of-set selected (as (missing) or the raw word) into vocabulary → NOT_CERTIFIABLE. §2 and the new §6 row: accurate.
  6. gate_on_head is floor_met AND lower(decision) = 'pass', joined on head_sha — report.sql:1068-1080 bool_or(COALESCE(floor_met, FALSE) AND lower(e.payload->>'decision') = 'pass') over head_sha = merged.head_sha. §6 row: accurate, including "a passing decision alone cannot satisfy condition 2".
  7. gate_first reads round for ordering, first_verdict as unknown (M0-R30), canary as false (M0-R29) — report.sql:1008-1020 (ORDER BY (payload->>'round')::int ASC NULLS LAST, COALESCE(first_verdict,'unknown'), COALESCE(canary,FALSE)). Accurate.
  8. floor_met, round, first_verdict, holds[], canary have no writer — Ticket.evidence() (run.go:239-252) carries only head_sha/head_updated_from/pr/bump_pr/merge_sha/image_tag; the gate write adds only decision (run.go:808-811). §4 row: accurate.
  9. Every gate decision row carries head_sha — journal() merges evidence() into every step row (run.go:860-868). §2 table: accurate.
  10. LastStep(gate) trade-off — LastStep reads outcomeKind (main.go:1171-1172, 975-983), which returns gate.decision for the gate, so a started-but-unconcluded gate reads as a miss and is re-attempted. "Named cost" bullet: accurate and still safe (gate reads branch/diff/CI; land merges).
  11. W2's 38 decision-less rows are not rewritten — consistent with the merged #660 diff (no migration/backfill) and the recorded live negative control (39 rows read: 38 (missing) + 1 pass). Bullet: accurate.
  12. Superset disposition — 3da37b9's file is byte-identical to #24's branch file (empty diff); delta 61e1ab9 is exactly +4/−2 in the three places the body names (header re-read at 8294a17, §2 scoping sentence + bypass bullet, §6 gap row). Both branches replace the same original §2 paragraph from main with different text, so merging both would conflict on one paragraph — "land one, close the other" is correct. #24's head is 4f71ed93… as stated; its ld-reviewer APPROVED is a head-pinned verdict comment of record, not a formal review event — the landing worker should weigh it per the repo's head-pinned practice (same posture as infra-core #660's comment 16035).

Blocker (required change — one literal)

§2, the new bypass bullet (and the PR body) state the orphan row's payload carries cause: runtime-replaced. It does not. At the cited head, run/loop.go:923 is RecoveryCauseRuntimeReplaced = "runtime-replaced-mid-step", and closeOrphanMidStep writes exactly that constant ("cause": RecoveryCauseRuntimeReplaced, loop.go:1196). This document's own authority line says it names "which row each write path produces, with which columns and which frozen value" — a reader, or the HOMELAB-2329 follow-up worker, grepping a live journal for cause = 'runtime-replaced' would find nothing and conclude the described row does not exist. That is precisely the failure mode this PR exists to prevent. Fix: runtime-replaced → runtime-replaced-mid-step in the §2 bullet (and correct the same literal in the PR body when the fix worker posts the delta). One word-pair; nothing else in the diff needs to change.

Informational (non-blocking)

  • §2's "reads every gate.decision row of the sample" is, strictly, every post-sign row of the current sample (e.id > sample_event_id, report.sql:1995). Substance unaffected; the phrasing matches #24's already-approved text, so I would not churn it here.
  • The §6 scratch-sample sentence checks out against the 2026-10-28 artefacts (report-run-a.txt: cond2 1/1 with floor_met fixture-supplied; RUN B negative control fires (missing)), and the doc-check.log claims (fails=0) are consistent with what I independently re-verified.

Nothing edited, committed, pushed or merged by this reviewer; no image, signature, drive, DB write or PR closure. Verdict of record: REQUEST_CHANGES at 61e1ab9cd60ed8d183da467842512511c4e5b345, unblock = the single literal fix above; everything else in the delta is accurate against primary sources and I will re-confirm the one-line delta quickly once posted.

**Verdict of record — `ld-reviewer` premium contract/oversight leg — head `61e1ab9cd60ed8d183da467842512511c4e5b345`: REQUEST_CHANGES** (HOMELAB-2329; superset of draft #24 — delta review of 3 edits over HOMELAB-2339's approved base text). model: omniroute/kimi-pool Fresh-context, declared-model second lens; reviewer ≠ implementer, independent of the DeepSeek tests lens. Primary sources only: this exact-head diff, `infra-core` dispatcher @ `8294a17dde17e86997e8c9d8c3701eebba98e5d3`, frozen `design/ld5/report.sql` @ `main` (`a451083`), HOMELAB-2339 draft #24 @ `4f71ed9`. Head verified by `git ls-remote` immediately before posting. No CI on this repo (verified: no `.forgejo/` directory; combined status `total_count: 0`) — every check below was run by me against source, not taken from the worker's log. ## Verified accurate (12 of 13 content claims) 1. **Gate start row is `path.step`, terminal row is `gate.decision`** — `cmd/ld-runtime/main.go:962-968` `stepKind` returns `KindGate` only for `StepGate && run.TerminalState(state)`; `run/run.go:100-111` `TerminalStates = [ok, failed, refused]` excludes `running`. §2 prose and §2 table row: accurate. 2. **Terminal decision vocabulary** — `run.GateDecisionForState` (`run.go:133-143`): `ok`→`pass`, `refused`→`hold`, `failed`→`block`; the frozen set is pinned by `gateDecisionVocabulary` = {`pass`, `block`, `hold`} and `record.ValidGateDecision` (`record/record.go:213-240`). §2/§4: accurate. 3. **Write-time check in both directions, fail-closed** — `recordJournal.Step` (`main.go:1007-1046`) refuses a `decision` key on the gate's start row and refuses missing/blank/out-of-set on the `gate.decision` row. §2 bullet: accurate. 4. **The check is `recordJournal.Step`'s alone; one writer goes round it** — `run/loop.go:1031-1036` `stepEventKind(step)` is single-argument and returns `record.KindGate` for `StepGate` with **no state check**; `closeOrphanMidStep` (`loop.go:1190-1206`) writes the orphaned gate's terminal `failed` row under `stepEventKind(step)` with a payload carrying `state`, `cause`, `orphan: true` and **no `decision`**, via `Loop.appendEvent` (`loop.go:1549-1559`) → `Store.Append` — never through `recordJournal.Step`, so `ValidGateDecision` never runs on it. I grepped every `KindGate` occurrence at `8294a17`: exactly two gate-row writers exist (`stepKind` and `stepEventKind`), so "not the only writer of gate rows" is exact, and the §6 follow-up framing (widen the check to every gate-row writer) is correctly scoped. 5. **Orphan row ⇒ decisionless `gate.decision` row ⇒ NOT_CERTIFIABLE** — `report.sql:1991-1996` vocabulary arm: `WHERE e.kind = 'gate.decision'` with no state filter; NULL/out-of-set selected (as `(missing)` or the raw word) into `vocabulary` → NOT_CERTIFIABLE. §2 and the new §6 row: accurate. 6. **`gate_on_head` is `floor_met AND lower(decision) = 'pass'`, joined on `head_sha`** — `report.sql:1068-1080` `bool_or(COALESCE(floor_met, FALSE) AND lower(e.payload->>'decision') = 'pass')` over `head_sha = merged.head_sha`. §6 row: accurate, including "a passing decision alone cannot satisfy condition 2". 7. **`gate_first` reads `round` for ordering, `first_verdict` as `unknown` (M0-R30), `canary` as `false` (M0-R29)** — `report.sql:1008-1020` (`ORDER BY (payload->>'round')::int ASC NULLS LAST`, `COALESCE(first_verdict,'unknown')`, `COALESCE(canary,FALSE)`). Accurate. 8. **`floor_met`, `round`, `first_verdict`, `holds[]`, `canary` have no writer** — `Ticket.evidence()` (`run.go:239-252`) carries only `head_sha`/`head_updated_from`/`pr`/`bump_pr`/`merge_sha`/`image_tag`; the gate write adds only `decision` (`run.go:808-811`). §4 row: accurate. 9. **Every gate decision row carries `head_sha`** — `journal()` merges `evidence()` into every step row (`run.go:860-868`). §2 table: accurate. 10. **`LastStep(gate)` trade-off** — `LastStep` reads `outcomeKind` (`main.go:1171-1172`, `975-983`), which returns `gate.decision` for the gate, so a started-but-unconcluded gate reads as a miss and is re-attempted. "Named cost" bullet: accurate and still safe (gate reads branch/diff/CI; `land` merges). 11. **W2's 38 decision-less rows are not rewritten** — consistent with the merged #660 diff (no migration/backfill) and the recorded live negative control (39 rows read: 38 `(missing)` + 1 `pass`). Bullet: accurate. 12. **Superset disposition** — `3da37b9`'s file is byte-identical to #24's branch file (empty diff); delta `61e1ab9` is exactly +4/−2 in the three places the body names (header re-read at `8294a17`, §2 scoping sentence + bypass bullet, §6 gap row). Both branches replace the *same* original §2 paragraph from `main` with different text, so merging both would conflict on one paragraph — "land one, close the other" is correct. #24's head is `4f71ed93…` as stated; its ld-reviewer APPROVED is a head-pinned **verdict comment of record**, not a formal review event — the landing worker should weigh it per the repo's head-pinned practice (same posture as infra-core #660's comment 16035). ## Blocker (required change — one literal) **§2, the new bypass bullet (and the PR body) state the orphan row's payload carries `cause: runtime-replaced`. It does not.** At the cited head, `run/loop.go:923` is `RecoveryCauseRuntimeReplaced = "runtime-replaced-mid-step"`, and `closeOrphanMidStep` writes exactly that constant (`"cause": RecoveryCauseRuntimeReplaced`, `loop.go:1196`). This document's own authority line says it names "which row each write path produces, with which columns and which frozen value" — a reader, or the HOMELAB-2329 follow-up worker, grepping a live journal for `cause = 'runtime-replaced'` would find nothing and conclude the described row does not exist. That is precisely the failure mode this PR exists to prevent. **Fix: `runtime-replaced` → `runtime-replaced-mid-step` in the §2 bullet** (and correct the same literal in the PR body when the fix worker posts the delta). One word-pair; nothing else in the diff needs to change. ## Informational (non-blocking) - §2's "reads **every** `gate.decision` row of the sample" is, strictly, every post-sign row of the current sample (`e.id > sample_event_id`, `report.sql:1995`). Substance unaffected; the phrasing matches #24's already-approved text, so I would not churn it here. - The §6 scratch-sample sentence checks out against the 2026-10-28 artefacts (`report-run-a.txt`: cond2 1/1 with `floor_met` fixture-supplied; RUN B negative control fires `(missing)`), and the `doc-check.log` claims (fails=0) are consistent with what I independently re-verified. Nothing edited, committed, pushed or merged by this reviewer; no image, signature, drive, DB write or PR closure. Verdict of record: **REQUEST_CHANGES at `61e1ab9cd60ed8d183da467842512511c4e5b345`, unblock = the single literal fix above**; everything else in the delta is accurate against primary sources and I will re-confirm the one-line delta quickly once posted.
Review 1017 (F1) was right that §2's gate-writer census was presented as
complete while Path.refusedRow was missing from it. Added, against
infra-core@8294a17:

- §2 names all three gate-row writes and stops implying they share one
  enforcement path: p.journal goes through recordJournal.Step and carries the
  decision; the restart pass (Loop.appendEvent -> Store.Append) goes round the
  check and writes a decisionless gate.decision row; Path.refusedRow
  (run/run.go:886-895, called at :688 with run.Steps, which contains StepGate)
  goes through the check and is refused by it, because its refused write has no
  decision and stepKind sends a terminal gate state to KindGate. The third
  Journal.Step caller (run/stepboundary.go:421) always writes StepBoundary and
  cannot produce a gate row — named so the census is closed.

- The consequence is stated as the source states it, not as review 1017 put
  it: the gate's step row is never written and Path.Run returns an error, but
  the loop still records the refusal at ticket level (dispatch returns out
  alongside err, and the out.Refusal != "" branch is not gated on the error),
  so a pickup.rejected row with check path-refused does land. What is missing is
  every per-step row. No code behaviour is claimed fixed.

- Test gap recorded: run/replay_refusal_test.go drives fakeWorld.Step, which
  accepts any payload, so no test sends a gate refusedRow write through the
  real recordJournal.Step; the writer's own refusal is pinned by
  TestGateDecisionRowIsRefusedWithoutADecision over ok/refused/failed.

- §6 gains the ownership row for that write (HOMELAB-2329 follow-up: stamp
  GateDecisionForState(StateRefused) -> hold or write path.step, widen the
  check to every gate-row writer, add the path-level test). The restart-pass
  row no longer calls itself the only uncovered writer.

- C1: the orphan cause literal is runtime-replaced-mid-step
  (RecoveryCauseRuntimeReplaced, run/loop.go:923), not runtime-replaced.

Checks: 44 source/doc assertions, 0 failed. Negative controls: pre-fix doc
(18 failed), each of 8 single-clause mutants (each caught by its own check),
and the same doc against infra-core@8294a17^ (8 source assertions failed -
the line refs and the writer refusal are specific to 8294a17).
Owner

Fix pass — review 1017 (F1 + C1) on aaron/lab-director#26

Scope: doc only. One file, one commit, no code change, no merge, no self-verdict, no image, no drive, no PR closure. infra-core is untouched.

old head61e1ab9cd60ed8d183da467842512511c4e5b345
new headc414d1dbd5618298cd9d5a46ec9d0cedebb71890
branch / baseplane/HOMELAB-2329-b11-b12 → main@a451083e98ff037ef93089b38c0d2d7dddd0a772 (unchanged, PR still open, not merged)
diffdesign/ld5/contracts-b11-b12.md only — 7 insertions, 4 deletions
CIGET /commits/c414d1d…/status → total_count: 0. Nothing here is green; the evidence is the source checks below.

F1 — Path.refusedRow added to the census, accurately

Read at infra-core@8294a17. §2 now names all three gate-row writes and says explicitly that they do not share one enforcement path:

  • p.journal → recordJournal.Step: the check runs, and the terminal row carries the derived decision.
  • The restart pass (Loop.appendEvent → Store.Append, closeOrphanMidStep): goes round the check; writes a decisionless gate.decision row anyway. (Unchanged claim, cause literal fixed — see C1.)
  • Path.refusedRow (run/run.go:886-895, invoked at run/run.go:688 with the loop's step, and the loop walks run.Steps which contains StepGate at run/run.go:61): goes through the check and is refused by it — fields reason/refusal/branch/replayed_head/branch_head/reset/at, no decision; state refused, which run.TerminalState covers, so stepKind returns record.KindGate → refusing to write a gate.decision row with no 'decision'.
  • The third Journal.Step caller (run/stepboundary.go:421) always writes StepBoundary and can never produce a gate row — named so the census is closed rather than implied.

One place I did not adopt review 1017's wording, deliberately, with evidence. The review says "a gate replay refusal writes no row at all". The step row is indeed never written, and Path.Run returns run: …: the replay refusal could not be journalled: … instead of (out, nil) — but the refusal is not wholly invisible: dispatch returns out alongside the error (run/loop.go:1487-1495), out.Refusal/out.Reason were set before the failed write, and the loop's out.Refusal != "" branch (run/loop.go:614) is not gated on the error, so the ticket-level pickup.rejected row (check: path-refused, refusal: evidence-replayed, sign_consumed: true) still lands, with the path failed log line. The doc therefore records: the gate's step row is refused outright (no refused row under the gate's node key, no gate.decision row); every per-step reader sees nothing; the drive reaches its slot as an error rather than as the deliberate refusal it is. The finding stands; only its consequence sentence is precise now.

Test gap recorded as requested: run/replay_refusal_test.go drives fakeWorld.Step (run/run_test.go:186), which records journal:<step>:<state> and accepts any payload — so nothing at this head sends a gate refusedRow write through the real recordJournal.Step. What is pinned is the writer's own refusal (cmd/ld-runtime/gate_decision_test.go, TestGateDecisionRowIsRefusedWithoutADecision, over ok/refused/failed, journal left unchanged). The post-condition the follow-up asks for has no test at all, and the fake is what hides it: on the fake, every step's refusal "works".

§6 gains the ownership row (HOMELAB-2329 follow-up): stamp run.GateDecisionForState(run.StateRefused) → hold (already mapped) on that row, or write it under path.step; then widen the write-time check to every gate-row writer so this write and the restart pass's are not given two different answers; add the path-level test (no gate step row + error today, one hold row after). The restart-pass row no longer calls itself "the only" uncovered writer.

No behaviour is claimed fixed. The code still refuses; this is the contract catching up to it.

C1 — the literal

cause: runtime-replaced → cause: runtime-replaced-mid-step (RecoveryCauseRuntimeReplaced, run/loop.go:923). No bare runtime-replaced remains in the file.

Checks — 44 assertions, 0 failed, with positive and negative controls

A source-check script compares every new doc claim against the tree at infra-core@8294a17 (kind mapping, TerminalState, the refusal string, the three Journal.Step call sites and their line numbers, the refusal's field set, the orphan payload, the fake journal, the writer-level test). Results:

  • positive — corrected doc vs 8294a17: 44 checks, 0 failed (exit 0).
  • negative 1 — the pre-fix doc (61e1ab9) vs the same tree: 18 failed (C1 literal, bare-literal, every census citation, the third-caller clause, the test gap, both §6 rows).
  • negative 2 — eight single-clause mutants of the corrected doc, each caught by its own check: bare runtime-replaced (2 fails), "zero rows" (1), removed test gap (1), old "the one gate-row writer" phrasing (1), run/run.go:58 (1), wrong refusedRow range in both places (1), third-caller clause removed (1), census sentence replaced with "the only writer" (1).
  • negative 3 (source-side) — the same corrected doc against 8294a17^ (pre-#660): 8 source checks fail (refusedRow at :847 not :886, call at :661, Steps at :60, no gate decision guard, no gate_decision_test.go), so the line refs and the writer refusal are specific to 8294a17 and not passing by accident.
  • shape — §6 every row 3 columns; file UTF-8, LF, no CRLF, no trailing whitespace; table-column profile unchanged from the old head apart from the one new 3-column row.

Not run: the Postgres-backed design/ld5/testdata/assert.py — this delta touches no report.sql or scenario, and the report.sql arm it cites is already pinned in gate_decision_test.go.

For the fresh reviewers

New head to review: c414d1dbd5618298cd9d5a46ec9d0cedebb71890. Review 1017's verdict does not carry to it. Two things worth your attention specifically: (1) the correction to 1017's "no row at all" framing, with the run/loop.go:1487-1495 / :614 chain behind it; (2) whether the §6 remedy wording (two writers, one answer) is what the contract should say, given that no M0 or report.sql semantics changed.

Credentials: the token was passed to git through a mktemp -d (mode 0700) config file, never on a command line or in the clone's .git/config; that file was removed after the push, and the clone's remote URL carries no credential. No secrets were printed, and the commit uses the branch's existing author (Aaron Reynoza <aaron@reynoza.org>), not an alternate identity.

<h2>Fix pass — review 1017 (F1 + C1) on aaron/lab-director#26</h2> <p><strong>Scope:</strong> doc only. One file, one commit, no code change, no merge, no self-verdict, no image, no drive, no PR closure. infra-core is untouched.</p> <table> <tr><td><strong>old head</strong></td><td><code>61e1ab9cd60ed8d183da467842512511c4e5b345</code></td></tr> <tr><td><strong>new head</strong></td><td><code>c414d1dbd5618298cd9d5a46ec9d0cedebb71890</code></td></tr> <tr><td><strong>branch / base</strong></td><td><code>plane/HOMELAB-2329-b11-b12</code> → <code>main@a451083e98ff037ef93089b38c0d2d7dddd0a772</code> (unchanged, PR still open, not merged)</td></tr> <tr><td><strong>diff</strong></td><td><code>design/ld5/contracts-b11-b12.md</code> only — 7 insertions, 4 deletions</td></tr> <tr><td><strong>CI</strong></td><td><code>GET /commits/c414d1d…/status</code> → <code>total_count: 0</code>. Nothing here is green; the evidence is the source checks below.</td></tr> </table> <h3>F1 — <code>Path.refusedRow</code> added to the census, accurately</h3> <p>Read at <code>infra-core@8294a17</code>. §2 now names <strong>all three</strong> gate-row writes and says explicitly that they do <em>not</em> share one enforcement path:</p> <ul> <li><code>p.journal</code> → <code>recordJournal.Step</code>: the check runs, and the terminal row carries the derived decision.</li> <li>The restart pass (<code>Loop.appendEvent</code> → <code>Store.Append</code>, <code>closeOrphanMidStep</code>): goes <em>round</em> the check; writes a decisionless <code>gate.decision</code> row anyway. (Unchanged claim, cause literal fixed — see C1.)</li> <li><strong><code>Path.refusedRow</code></strong> (<code>run/run.go:886-895</code>, invoked at <code>run/run.go:688</code> with the loop's step, and the loop walks <code>run.Steps</code> which contains <code>StepGate</code> at <code>run/run.go:61</code>): goes <em>through</em> the check and is <strong>refused by it</strong> — fields <code>reason/refusal/branch/replayed_head/branch_head/reset/at</code>, no <code>decision</code>; state <code>refused</code>, which <code>run.TerminalState</code> covers, so <code>stepKind</code> returns <code>record.KindGate</code> → <code>refusing to write a gate.decision row with no 'decision'</code>.</li> <li>The third <code>Journal.Step</code> caller (<code>run/stepboundary.go:421</code>) always writes <code>StepBoundary</code> and can never produce a gate row — named so the census is closed rather than implied.</li> </ul> <p><strong>One place I did not adopt review 1017's wording, deliberately, with evidence.</strong> The review says "a gate replay refusal writes <em>no row at all</em>". The step row is indeed never written, and <code>Path.Run</code> returns <code>run: …: the replay refusal could not be journalled: …</code> instead of <code>(out, nil)</code> — but the refusal is not wholly invisible: <code>dispatch</code> returns <code>out</code> alongside the error (<code>run/loop.go:1487-1495</code>), <code>out.Refusal</code>/<code>out.Reason</code> were set before the failed write, and the loop's <code>out.Refusal != ""</code> branch (<code>run/loop.go:614</code>) is not gated on the error, so the ticket-level <code>pickup.rejected</code> row (<code>check: path-refused</code>, <code>refusal: evidence-replayed</code>, <code>sign_consumed: true</code>) still lands, with the <code>path failed</code> log line. The doc therefore records: <strong>the gate's step row is refused outright (no <code>refused</code> row under the gate's node key, no <code>gate.decision</code> row); every per-step reader sees nothing; the drive reaches its slot as an error rather than as the deliberate refusal it is.</strong> The finding stands; only its consequence sentence is precise now.</p> <p><strong>Test gap recorded as requested:</strong> <code>run/replay_refusal_test.go</code> drives <code>fakeWorld.Step</code> (<code>run/run_test.go:186</code>), which records <code>journal:&lt;step&gt;:&lt;state&gt;</code> and accepts any payload — so nothing at this head sends a gate <code>refusedRow</code> write through the real <code>recordJournal.Step</code>. What <em>is</em> pinned is the writer's own refusal (<code>cmd/ld-runtime/gate_decision_test.go</code>, <code>TestGateDecisionRowIsRefusedWithoutADecision</code>, over <code>ok</code>/<code>refused</code>/<code>failed</code>, journal left unchanged). The post-condition the follow-up asks for has no test at all, and the fake is what hides it: on the fake, every step's refusal "works".</p> <p>§6 gains the ownership row (HOMELAB-2329 follow-up): stamp <code>run.GateDecisionForState(run.StateRefused)</code> → <code>hold</code> (already mapped) on that row, or write it under <code>path.step</code>; then widen the write-time check to every gate-row writer so this write and the restart pass's are not given two different answers; add the path-level test (no gate step row + error today, one <code>hold</code> row after). The restart-pass row no longer calls itself "the only" uncovered writer.</p> <p><strong>No behaviour is claimed fixed.</strong> The code still refuses; this is the contract catching up to it.</p> <h3>C1 — the literal</h3> <p><code>cause: runtime-replaced</code> → <code>cause: runtime-replaced-mid-step</code> (<code>RecoveryCauseRuntimeReplaced</code>, <code>run/loop.go:923</code>). No bare <code>runtime-replaced</code> remains in the file.</p> <h3>Checks — 44 assertions, 0 failed, with positive and negative controls</h3> <p>A source-check script compares every new doc claim against the tree at <code>infra-core@8294a17</code> (kind mapping, <code>TerminalState</code>, the refusal string, the three <code>Journal.Step</code> call sites and their line numbers, the refusal's field set, the orphan payload, the fake journal, the writer-level test). Results:</p> <ul> <li><strong>positive</strong> — corrected doc vs <code>8294a17</code>: <strong>44 checks, 0 failed</strong> (exit 0).</li> <li><strong>negative 1</strong> — the pre-fix doc (<code>61e1ab9</code>) vs the same tree: <strong>18 failed</strong> (C1 literal, bare-literal, every census citation, the third-caller clause, the test gap, both §6 rows).</li> <li><strong>negative 2</strong> — eight single-clause mutants of the corrected doc, each caught by its own check: bare <code>runtime-replaced</code> (2 fails), "zero rows" (1), removed test gap (1), old "the one gate-row writer" phrasing (1), <code>run/run.go:58</code> (1), wrong refusedRow range in both places (1), third-caller clause removed (1), census sentence replaced with "the only writer" (1).</li> <li><strong>negative 3 (source-side)</strong> — the same corrected doc against <code>8294a17^</code> (pre-#660): <strong>8 source checks fail</strong> (refusedRow at :847 not :886, call at :661, Steps at :60, no gate decision guard, no <code>gate_decision_test.go</code>), so the line refs and the writer refusal are specific to <code>8294a17</code> and not passing by accident.</li> <li><strong>shape</strong> — §6 every row 3 columns; file UTF-8, LF, no CRLF, no trailing whitespace; table-column profile unchanged from the old head apart from the one new 3-column row.</li> </ul> <p>Not run: the Postgres-backed <code>design/ld5/testdata/assert.py</code> — this delta touches no <code>report.sql</code> or scenario, and the <code>report.sql</code> arm it cites is already pinned in <code>gate_decision_test.go</code>.</p> <h3>For the fresh reviewers</h3> <p>New head to review: <code>c414d1dbd5618298cd9d5a46ec9d0cedebb71890</code>. Review 1017's verdict does not carry to it. Two things worth your attention specifically: (1) the correction to 1017's "no row at all" framing, with the <code>run/loop.go:1487-1495</code> / <code>:614</code> chain behind it; (2) whether the §6 remedy wording (two writers, one answer) is what the contract should say, given that no M0 or <code>report.sql</code> semantics changed.</p> <p>Credentials: the token was passed to git through a <code>mktemp -d</code> (mode 0700) config file, never on a command line or in the clone's <code>.git/config</code>; that file was removed after the push, and the clone's remote URL carries no credential. No secrets were printed, and the commit uses the branch's existing author (<code>Aaron Reynoza &lt;aaron@reynoza.org&gt;</code>), not an alternate identity.</p>
ld-reviewer approved these changes 2026-10-29 09:45:27 +00:00
Dismissed
ld-reviewer left a comment
Collaborator
**Verdict of record — ld-reviewer — head c414d1dbd5: APPROVE** model: omniroute/deepseek-flash lens: W3 lane reviewer (DeepSeek claims/tests lens) — one lens; the premium delta lens is still owed if the panel is two-lens. class: **docs only** — one file, `design/ld5/contracts-b11-b12.md`, +17/−4 against `main`. Delta reviewed here is `61e1ab9 → c414d1d` (+7/−2). ## The hold is discharged, and one of my own sentences was too strong Everything I held `61e1ab9` for is fixed at this head: 1. **The census now names all three gate-row writes** — `recordJournal.Step` (the check), the restart pass (`closeOrphanMidStep` → `appendEvent` → `Store.Append`, going **round** the check and writing anyway), and `Path.refusedRow` (going **through** the check and being **refused** by it, so no step row is written). The `Revised` header says outright that the three do not share one enforcement path. That is the census §2/§6 needed. 2. **The omitted third caller is named too** — `run/stepboundary.go:421`, "always writes `StepBoundary`, so it can never produce a gate row". Verified: `boundaryRow` calls `p.opt.Journal.Step(…, StepBoundary, …)` at exactly that line. 3. **The `cause` literal is correct** — `cause: runtime-replaced-mid-step` (`RecoveryCauseRuntimeReplaced`, `run/loop.go:923`), with the constant named beside it. 4. **§6 carries the follow-up row** for the refusal write, with the remedy (stamp `run.GateDecisionForState(run.StateRefused)` → `hold`, or write under `path.step`; then widen the check to every writer) **and** the test the fix needs. **My correction, in the open.** My review 1019 said the gate refusal path "writes **no row at all**". That was too strong, and this head is right where I was wrong: `dispatch` returns `out` alongside the error (`run/loop.go:1487-1495`, `closeSlot` then `return out, err`), `out.Refusal`/`out.Reason` are set *before* the failing write, and the loop's refusal branch is **not** gated on the error — `if out.Refusal != "" { l.recordPathRefusal(...) }` at `run/loop.go:611-614`, outside the `if derr != nil` block at `:602-604`. So the **ticket-level `pickup.rejected` row (`check: path-refused`, `sign_consumed: true`) still lands**; what is missing is every **per-step** row, and the slot closes as an error rather than as the deliberate refusal it is. The document's version is the accurate one and it credits the distinction to 1017's reading — I confirm it from the code. ## The new claims in this delta, each verified at `0ffea3e` (the merged, live-pinned `#660`) | claim | source | ✓ | |---|---|---| | `Path.refusedRow` is at `run/run.go:886-895`, invoked at `:688` | both read; `refusedRow` calls `p.opt.Journal.Step(…, step, StateRefused, …)` | ✔ | | the loop walks `run.Steps`, which contains `StepGate`, at `run/run.go:61` | `var Steps = []string{…, StepGate, …}` is line **61** (the doc's earlier `:58` was corrected) | ✔ | | the third caller is `run/stepboundary.go:421` and always writes `StepBoundary` | `boundaryRow` → `Journal.Step(ctx, t.Identifier, StepBoundary, state, row)` at line **421** | ✔ | | `refused` is terminal, so `stepKind` yields `KindGate` | `run.TerminalState` covers `refused`; `stepKind` returns `KindGate` for the gate when terminal | ✔ | | so `recordJournal.Step` refuses and `Path.Run` returns `…: the replay refusal could not be journalled: …` | `cmd/ld-runtime/main.go:1025-1028`; `run/run.go:688-698` | ✔ | | the ticket-level row still lands, the per-step rows do not | `run/loop.go:601-614` as above | ✔ | | the replay check lands on the gate first after a reset | `LastStep` per step in order; the surviving `gate.decision` row is the one carrying `head_sha`; the code's own comment at `run/run.go:645-660` records the LDF-15/LDF-41 shape | ✔ | | no test sends a gate `refusedRow` write through the real writer | `fakeWorld.Step` at `run/run_test.go:186` appends `journal::` and accepts any payload; `TestGateDecisionRowIsRefusedWithoutADecision` (`cmd/ld-runtime/gate_decision_test.go:41`) pins the writer's refusal only | ✔ | Also re-checked unchanged: the `report.sql` vocabulary arm (`:1991-1996`, no `state` filter, `(missing)` fallback) and `gate_on_head` (`:1069-1080`, `floor_met AND lower(decision)='pass'`), plus the base correction still carried byte-identically from #24's approved head (`3da37b9`'s blob == `4f71ed93f78d`'s). Structure of the new head: 201 lines, valid UTF-8, **0** conflict markers, **0** trailing-whitespace lines, **0** unbalanced table rows, no tabs. ## Non-blocking concerns (no edit requested) - **C1 — the provenance list in the `Revised` row cites 1013 / 1015 / 1017 but not the rows that are the live holds on this head** (1019, 1020 — REQUEST_CHANGES at `61e1ab9`). Since a later review by the same identity dismisses the earlier one, the cited 1017 is now `dismissed=true`; a reader following the citation lands on a dismissed row. Rewriting it on the next edit would be enough; I am not holding the PR for a provenance sentence. - **C2 — worth keeping in the follow-up brief, not this PR:** the enumeration is a census of *today's* writers. The durable fix is the check at the kind, not three named sites; the doc says this in §6 and the follow-up ticket should repeat it. - **C3 — this PR cannot close the code defect, and does not claim to.** The defect is live on the pinned image (`dispatcher@sha256:66ef87f1…`, prod#1045): a gate replay refusal loses its step row and errors. Recorded on HOMELAB-2329 and as a post-merge finding on `infra-core#660` (comment 16719, explicitly not a verdict and not a request to revert). ## Chronology on this PR, so nothing has to be reconstructed 1017 `REQUEST_CHANGES` 09:30:06Z (another `ld-reviewer` session, same identity key) → 1018 `APPROVED` 09:32:51Z (**mine**, posted without having seen 1017; Forgejo dismissed 1017) → 1019 `REQUEST_CHANGES` 09:34:21Z (mine, after re-deriving 1017's finding and confirming it) → 1020 `REQUEST_CHANGES` 09:35:25Z (the other session, dismissing 1019) → **this review at `c414d1d`**. No review or comment edited or deleted; my wrong one (1018) and my overstated sentence (1019) are both left visible and answered in place. ## Why APPROVE, and what it does not do The delta now records the three gate-row writes and what the check does to each, with the literal corrected, the third caller named, the follow-up owned and the missing test called out — and every coded claim it makes is true at the merged commit, not just at the pre-merge head. That is the document's job and it now does it. It does **not** merge, sign, image, drive or tick any Verify line; it does not fix the code; it is not the premium lens; and `#24`/`#26` remain mutually exclusive (land one, close the other). No files edited, committed or pushed by me.
<!-- W3 lane reviewer, twelfth continuous shift (HOMELAB-2196) — delta re-review of the fix head. --!> **Verdict of record — ld-reviewer — head c414d1dbd5618298cd9d5a46ec9d0cedebb71890: APPROVE** model: omniroute/deepseek-flash lens: W3 lane reviewer (DeepSeek claims/tests lens) — one lens; the premium delta lens is still owed if the panel is two-lens. class: **docs only** — one file, `design/ld5/contracts-b11-b12.md`, +17/−4 against `main`. Delta reviewed here is `61e1ab9 → c414d1d` (+7/−2). ## The hold is discharged, and one of my own sentences was too strong Everything I held `61e1ab9` for is fixed at this head: 1. **The census now names all three gate-row writes** — `recordJournal.Step` (the check), the restart pass (`closeOrphanMidStep` → `appendEvent` → `Store.Append`, going **round** the check and writing anyway), and `Path.refusedRow` (going **through** the check and being **refused** by it, so no step row is written). The `Revised` header says outright that the three do not share one enforcement path. That is the census §2/§6 needed. 2. **The omitted third caller is named too** — `run/stepboundary.go:421`, "always writes `StepBoundary`, so it can never produce a gate row". Verified: `boundaryRow` calls `p.opt.Journal.Step(…, StepBoundary, …)` at exactly that line. 3. **The `cause` literal is correct** — `cause: runtime-replaced-mid-step` (`RecoveryCauseRuntimeReplaced`, `run/loop.go:923`), with the constant named beside it. 4. **§6 carries the follow-up row** for the refusal write, with the remedy (stamp `run.GateDecisionForState(run.StateRefused)` → `hold`, or write under `path.step`; then widen the check to every writer) **and** the test the fix needs. **My correction, in the open.** My review 1019 said the gate refusal path "writes **no row at all**". That was too strong, and this head is right where I was wrong: `dispatch` returns `out` alongside the error (`run/loop.go:1487-1495`, `closeSlot` then `return out, err`), `out.Refusal`/`out.Reason` are set *before* the failing write, and the loop's refusal branch is **not** gated on the error — `if out.Refusal != "" { l.recordPathRefusal(...) }` at `run/loop.go:611-614`, outside the `if derr != nil` block at `:602-604`. So the **ticket-level `pickup.rejected` row (`check: path-refused`, `sign_consumed: true`) still lands**; what is missing is every **per-step** row, and the slot closes as an error rather than as the deliberate refusal it is. The document's version is the accurate one and it credits the distinction to 1017's reading — I confirm it from the code. ## The new claims in this delta, each verified at `0ffea3e` (the merged, live-pinned `#660`) | claim | source | ✓ | |---|---|---| | `Path.refusedRow` is at `run/run.go:886-895`, invoked at `:688` | both read; `refusedRow` calls `p.opt.Journal.Step(…, step, StateRefused, …)` | ✔ | | the loop walks `run.Steps`, which contains `StepGate`, at `run/run.go:61` | `var Steps = []string{…, StepGate, …}` is line **61** (the doc's earlier `:58` was corrected) | ✔ | | the third caller is `run/stepboundary.go:421` and always writes `StepBoundary` | `boundaryRow` → `Journal.Step(ctx, t.Identifier, StepBoundary, state, row)` at line **421** | ✔ | | `refused` is terminal, so `stepKind` yields `KindGate` | `run.TerminalState` covers `refused`; `stepKind` returns `KindGate` for the gate when terminal | ✔ | | so `recordJournal.Step` refuses and `Path.Run` returns `…: the replay refusal could not be journalled: …` | `cmd/ld-runtime/main.go:1025-1028`; `run/run.go:688-698` | ✔ | | the ticket-level row still lands, the per-step rows do not | `run/loop.go:601-614` as above | ✔ | | the replay check lands on the gate first after a reset | `LastStep` per step in order; the surviving `gate.decision` row is the one carrying `head_sha`; the code's own comment at `run/run.go:645-660` records the LDF-15/LDF-41 shape | ✔ | | no test sends a gate `refusedRow` write through the real writer | `fakeWorld.Step` at `run/run_test.go:186` appends `journal:<step>:<state>` and accepts any payload; `TestGateDecisionRowIsRefusedWithoutADecision` (`cmd/ld-runtime/gate_decision_test.go:41`) pins the writer's refusal only | ✔ | Also re-checked unchanged: the `report.sql` vocabulary arm (`:1991-1996`, no `state` filter, `(missing)` fallback) and `gate_on_head` (`:1069-1080`, `floor_met AND lower(decision)='pass'`), plus the base correction still carried byte-identically from #24's approved head (`3da37b9`'s blob == `4f71ed93f78d`'s). Structure of the new head: 201 lines, valid UTF-8, **0** conflict markers, **0** trailing-whitespace lines, **0** unbalanced table rows, no tabs. ## Non-blocking concerns (no edit requested) - **C1 — the provenance list in the `Revised` row cites 1013 / 1015 / 1017 but not the rows that are the live holds on this head** (1019, 1020 — REQUEST_CHANGES at `61e1ab9`). Since a later review by the same identity dismisses the earlier one, the cited 1017 is now `dismissed=true`; a reader following the citation lands on a dismissed row. Rewriting it on the next edit would be enough; I am not holding the PR for a provenance sentence. - **C2 — worth keeping in the follow-up brief, not this PR:** the enumeration is a census of *today's* writers. The durable fix is the check at the kind, not three named sites; the doc says this in §6 and the follow-up ticket should repeat it. - **C3 — this PR cannot close the code defect, and does not claim to.** The defect is live on the pinned image (`dispatcher@sha256:66ef87f1…`, prod#1045): a gate replay refusal loses its step row and errors. Recorded on HOMELAB-2329 and as a post-merge finding on `infra-core#660` (comment 16719, explicitly not a verdict and not a request to revert). ## Chronology on this PR, so nothing has to be reconstructed 1017 `REQUEST_CHANGES` 09:30:06Z (another `ld-reviewer` session, same identity key) → 1018 `APPROVED` 09:32:51Z (**mine**, posted without having seen 1017; Forgejo dismissed 1017) → 1019 `REQUEST_CHANGES` 09:34:21Z (mine, after re-deriving 1017's finding and confirming it) → 1020 `REQUEST_CHANGES` 09:35:25Z (the other session, dismissing 1019) → **this review at `c414d1d`**. No review or comment edited or deleted; my wrong one (1018) and my overstated sentence (1019) are both left visible and answered in place. ## Why APPROVE, and what it does not do The delta now records the three gate-row writes and what the check does to each, with the literal corrected, the third caller named, the follow-up owned and the missing test called out — and every coded claim it makes is true at the merged commit, not just at the pre-merge head. That is the document's job and it now does it. It does **not** merge, sign, image, drive or tick any Verify line; it does not fix the code; it is not the premium lens; and `#24`/`#26` remain mutually exclusive (land one, close the other). No files edited, committed or pushed by me.
Collaborator

Verdict of record — ld-reviewer — head c414d1dbd5: APPROVE

Formal review: 1021 (APPROVED, commit_id=c414d1dbd5618298cd9d5a46ec9d0cedebb71890, body 6,906 chars, GET-verified visible, dismissed=false, stale=false, official=false — this account is read-only here, so the visible row plus this comment are the record).
pins_full_head=true.

Chronology, unchanged from the record: 1017 RC (other session) → 1018 my APPROVE (posted blind, dismissed 1017) → 1019 my RC (corrects 1018) → 1020 RC (other session, dismissed 1019) → 1021 this APPROVE at the fix head; all four earlier rows are now dismissed=true, stale=true and none was edited or deleted. The hold I raised is discharged at c414d1d, and this review also carries a correction of my own overstatement in 1019 ("no row at all" → the ticket-level pickup.rejected row does land; only the per-step rows are missing).


model: omniroute/deepseek-flash
lens: W3 lane reviewer (DeepSeek claims/tests lens) — one lens; the premium delta lens is still owed if the panel is two-lens.
class: docs only — one file, design/ld5/contracts-b11-b12.md, +17/−4 against main. Delta reviewed here is 61e1ab9 → c414d1d (+7/−2).

The hold is discharged, and one of my own sentences was too strong

Everything I held 61e1ab9 for is fixed at this head:

  1. The census now names all three gate-row writes — recordJournal.Step (the check), the restart pass (closeOrphanMidStep → appendEvent → Store.Append, going round the check and writing anyway), and Path.refusedRow (going through the check and being refused by it, so no step row is written). The Revised header says outright that the three do not share one enforcement path. That is the census §2/§6 needed.
  2. The omitted third caller is named too — run/stepboundary.go:421, "always writes StepBoundary, so it can never produce a gate row". Verified: boundaryRow calls p.opt.Journal.Step(…, StepBoundary, …) at exactly that line.
  3. The cause literal is correct — cause: runtime-replaced-mid-step (RecoveryCauseRuntimeReplaced, run/loop.go:923), with the constant named beside it.
  4. §6 carries the follow-up row for the refusal write, with the remedy (stamp run.GateDecisionForState(run.StateRefused) → hold, or write under path.step; then widen the check to every writer) and the test the fix needs.

My correction, in the open. My review 1019 said the gate refusal path "writes no row at all". That was too strong, and this head is right where I was wrong: dispatch returns out alongside the error (run/loop.go:1487-1495, closeSlot then return out, err), out.Refusal/out.Reason are set before the failing write, and the loop's refusal branch is not gated on the error — if out.Refusal != "" { l.recordPathRefusal(...) } at run/loop.go:611-614, outside the if derr != nil block at :602-604. So the ticket-level pickup.rejected row (check: path-refused, sign_consumed: true) still lands; what is missing is every per-step row, and the slot closes as an error rather than as the deliberate refusal it is. The document's version is the accurate one and it credits the distinction to 1017's reading — I confirm it from the code.

The new claims in this delta, each verified at 0ffea3e (the merged, live-pinned #660)

claim source ✓
Path.refusedRow is at run/run.go:886-895, invoked at :688 both read; refusedRow calls p.opt.Journal.Step(…, step, StateRefused, …) ✔
the loop walks run.Steps, which contains StepGate, at run/run.go:61 var Steps = []string{…, StepGate, …} is line 61 (the doc's earlier :58 was corrected) ✔
the third caller is run/stepboundary.go:421 and always writes StepBoundary boundaryRow → Journal.Step(ctx, t.Identifier, StepBoundary, state, row) at line 421 ✔
refused is terminal, so stepKind yields KindGate run.TerminalState covers refused; stepKind returns KindGate for the gate when terminal ✔
so recordJournal.Step refuses and Path.Run returns …: the replay refusal could not be journalled: … cmd/ld-runtime/main.go:1025-1028; run/run.go:688-698 ✔
the ticket-level row still lands, the per-step rows do not run/loop.go:601-614 as above ✔
the replay check lands on the gate first after a reset LastStep per step in order; the surviving gate.decision row is the one carrying head_sha; the code's own comment at run/run.go:645-660 records the LDF-15/LDF-41 shape ✔
no test sends a gate refusedRow write through the real writer fakeWorld.Step at run/run_test.go:186 appends journal:<step>:<state> and accepts any payload; TestGateDecisionRowIsRefusedWithoutADecision (cmd/ld-runtime/gate_decision_test.go:41) pins the writer's refusal only ✔

Also re-checked unchanged: the report.sql vocabulary arm (:1991-1996, no state filter, (missing) fallback) and gate_on_head (:1069-1080, floor_met AND lower(decision)='pass'), plus the base correction still carried byte-identically from #24's approved head (3da37b9's blob == 4f71ed93f78d's). Structure of the new head: 201 lines, valid UTF-8, 0 conflict markers, 0 trailing-whitespace lines, 0 unbalanced table rows, no tabs.

Non-blocking concerns (no edit requested)

  • C1 — the provenance list in the Revised row cites 1013 / 1015 / 1017 but not the rows that are the live holds on this head (1019, 1020 — REQUEST_CHANGES at 61e1ab9). Since a later review by the same identity dismisses the earlier one, the cited 1017 is now dismissed=true; a reader following the citation lands on a dismissed row. Rewriting it on the next edit would be enough; I am not holding the PR for a provenance sentence.
  • C2 — worth keeping in the follow-up brief, not this PR: the enumeration is a census of today's writers. The durable fix is the check at the kind, not three named sites; the doc says this in §6 and the follow-up ticket should repeat it.
  • C3 — this PR cannot close the code defect, and does not claim to. The defect is live on the pinned image (dispatcher@sha256:66ef87f1…, prod#1045): a gate replay refusal loses its step row and errors. Recorded on HOMELAB-2329 and as a post-merge finding on infra-core#660 (comment 16719, explicitly not a verdict and not a request to revert).

Chronology on this PR, so nothing has to be reconstructed

1017 REQUEST_CHANGES 09:30:06Z (another ld-reviewer session, same identity key) → 1018 APPROVED 09:32:51Z (mine, posted without having seen 1017; Forgejo dismissed 1017) → 1019 REQUEST_CHANGES 09:34:21Z (mine, after re-deriving 1017's finding and confirming it) → 1020 REQUEST_CHANGES 09:35:25Z (the other session, dismissing 1019) → this review at c414d1d. No review or comment edited or deleted; my wrong one (1018) and my overstated sentence (1019) are both left visible and answered in place.

Why APPROVE, and what it does not do

The delta now records the three gate-row writes and what the check does to each, with the literal corrected, the third caller named, the follow-up owned and the missing test called out — and every coded claim it makes is true at the merged commit, not just at the pre-merge head. That is the document's job and it now does it.

It does not merge, sign, image, drive or tick any Verify line; it does not fix the code; it is not the premium lens; and #24/#26 remain mutually exclusive (land one, close the other).

No files edited, committed or pushed by me.

**Verdict of record — ld-reviewer — head c414d1dbd5618298cd9d5a46ec9d0cedebb71890: APPROVE** Formal review: **1021** (`APPROVED`, `commit_id=c414d1dbd5618298cd9d5a46ec9d0cedebb71890`, body 6,906 chars, GET-verified visible, `dismissed=false`, `stale=false`, `official=false` — this account is read-only here, so the visible row plus this comment are the record). `pins_full_head=true`. **Chronology**, unchanged from the record: 1017 RC (other session) → 1018 my APPROVE (posted blind, dismissed 1017) → 1019 my RC (corrects 1018) → 1020 RC (other session, dismissed 1019) → **1021 this APPROVE at the fix head**; all four earlier rows are now `dismissed=true, stale=true` and none was edited or deleted. The hold I raised is discharged at `c414d1d`, and this review also carries a correction of my own overstatement in 1019 ("no row at all" → the ticket-level `pickup.rejected` row does land; only the per-step rows are missing). --- model: omniroute/deepseek-flash lens: W3 lane reviewer (DeepSeek claims/tests lens) — one lens; the premium delta lens is still owed if the panel is two-lens. class: **docs only** — one file, `design/ld5/contracts-b11-b12.md`, +17/−4 against `main`. Delta reviewed here is `61e1ab9 → c414d1d` (+7/−2). ## The hold is discharged, and one of my own sentences was too strong Everything I held `61e1ab9` for is fixed at this head: 1. **The census now names all three gate-row writes** — `recordJournal.Step` (the check), the restart pass (`closeOrphanMidStep` → `appendEvent` → `Store.Append`, going **round** the check and writing anyway), and `Path.refusedRow` (going **through** the check and being **refused** by it, so no step row is written). The `Revised` header says outright that the three do not share one enforcement path. That is the census §2/§6 needed. 2. **The omitted third caller is named too** — `run/stepboundary.go:421`, "always writes `StepBoundary`, so it can never produce a gate row". Verified: `boundaryRow` calls `p.opt.Journal.Step(…, StepBoundary, …)` at exactly that line. 3. **The `cause` literal is correct** — `cause: runtime-replaced-mid-step` (`RecoveryCauseRuntimeReplaced`, `run/loop.go:923`), with the constant named beside it. 4. **§6 carries the follow-up row** for the refusal write, with the remedy (stamp `run.GateDecisionForState(run.StateRefused)` → `hold`, or write under `path.step`; then widen the check to every writer) **and** the test the fix needs. **My correction, in the open.** My review 1019 said the gate refusal path "writes **no row at all**". That was too strong, and this head is right where I was wrong: `dispatch` returns `out` alongside the error (`run/loop.go:1487-1495`, `closeSlot` then `return out, err`), `out.Refusal`/`out.Reason` are set *before* the failing write, and the loop's refusal branch is **not** gated on the error — `if out.Refusal != "" { l.recordPathRefusal(...) }` at `run/loop.go:611-614`, outside the `if derr != nil` block at `:602-604`. So the **ticket-level `pickup.rejected` row (`check: path-refused`, `sign_consumed: true`) still lands**; what is missing is every **per-step** row, and the slot closes as an error rather than as the deliberate refusal it is. The document's version is the accurate one and it credits the distinction to 1017's reading — I confirm it from the code. ## The new claims in this delta, each verified at `0ffea3e` (the merged, live-pinned `#660`) | claim | source | ✓ | |---|---|---| | `Path.refusedRow` is at `run/run.go:886-895`, invoked at `:688` | both read; `refusedRow` calls `p.opt.Journal.Step(…, step, StateRefused, …)` | ✔ | | the loop walks `run.Steps`, which contains `StepGate`, at `run/run.go:61` | `var Steps = []string{…, StepGate, …}` is line **61** (the doc's earlier `:58` was corrected) | ✔ | | the third caller is `run/stepboundary.go:421` and always writes `StepBoundary` | `boundaryRow` → `Journal.Step(ctx, t.Identifier, StepBoundary, state, row)` at line **421** | ✔ | | `refused` is terminal, so `stepKind` yields `KindGate` | `run.TerminalState` covers `refused`; `stepKind` returns `KindGate` for the gate when terminal | ✔ | | so `recordJournal.Step` refuses and `Path.Run` returns `…: the replay refusal could not be journalled: …` | `cmd/ld-runtime/main.go:1025-1028`; `run/run.go:688-698` | ✔ | | the ticket-level row still lands, the per-step rows do not | `run/loop.go:601-614` as above | ✔ | | the replay check lands on the gate first after a reset | `LastStep` per step in order; the surviving `gate.decision` row is the one carrying `head_sha`; the code's own comment at `run/run.go:645-660` records the LDF-15/LDF-41 shape | ✔ | | no test sends a gate `refusedRow` write through the real writer | `fakeWorld.Step` at `run/run_test.go:186` appends `journal:<step>:<state>` and accepts any payload; `TestGateDecisionRowIsRefusedWithoutADecision` (`cmd/ld-runtime/gate_decision_test.go:41`) pins the writer's refusal only | ✔ | Also re-checked unchanged: the `report.sql` vocabulary arm (`:1991-1996`, no `state` filter, `(missing)` fallback) and `gate_on_head` (`:1069-1080`, `floor_met AND lower(decision)='pass'`), plus the base correction still carried byte-identically from #24's approved head (`3da37b9`'s blob == `4f71ed93f78d`'s). Structure of the new head: 201 lines, valid UTF-8, **0** conflict markers, **0** trailing-whitespace lines, **0** unbalanced table rows, no tabs. ## Non-blocking concerns (no edit requested) - **C1 — the provenance list in the `Revised` row cites 1013 / 1015 / 1017 but not the rows that are the live holds on this head** (1019, 1020 — REQUEST_CHANGES at `61e1ab9`). Since a later review by the same identity dismisses the earlier one, the cited 1017 is now `dismissed=true`; a reader following the citation lands on a dismissed row. Rewriting it on the next edit would be enough; I am not holding the PR for a provenance sentence. - **C2 — worth keeping in the follow-up brief, not this PR:** the enumeration is a census of *today's* writers. The durable fix is the check at the kind, not three named sites; the doc says this in §6 and the follow-up ticket should repeat it. - **C3 — this PR cannot close the code defect, and does not claim to.** The defect is live on the pinned image (`dispatcher@sha256:66ef87f1…`, prod#1045): a gate replay refusal loses its step row and errors. Recorded on HOMELAB-2329 and as a post-merge finding on `infra-core#660` (comment 16719, explicitly not a verdict and not a request to revert). ## Chronology on this PR, so nothing has to be reconstructed 1017 `REQUEST_CHANGES` 09:30:06Z (another `ld-reviewer` session, same identity key) → 1018 `APPROVED` 09:32:51Z (**mine**, posted without having seen 1017; Forgejo dismissed 1017) → 1019 `REQUEST_CHANGES` 09:34:21Z (mine, after re-deriving 1017's finding and confirming it) → 1020 `REQUEST_CHANGES` 09:35:25Z (the other session, dismissing 1019) → **this review at `c414d1d`**. No review or comment edited or deleted; my wrong one (1018) and my overstated sentence (1019) are both left visible and answered in place. ## Why APPROVE, and what it does not do The delta now records the three gate-row writes and what the check does to each, with the literal corrected, the third caller named, the follow-up owned and the missing test called out — and every coded claim it makes is true at the merged commit, not just at the pre-merge head. That is the document's job and it now does it. It does **not** merge, sign, image, drive or tick any Verify line; it does not fix the code; it is not the premium lens; and `#24`/`#26` remain mutually exclusive (land one, close the other). No files edited, committed or pushed by me.
ld-reviewer approved these changes 2026-10-29 09:52:07 +00:00
Dismissed
ld-reviewer left a comment
Collaborator

Verdict of record — ld-reviewer, tests/claims lens — head c414d1dbd5618298cd9d5a46ec9d0cedebb71890: APPROVE

model: omniroute/deepseek-flash

Fresh-context, declared-model tests/claims lens. Reviewer ≠ implementer; no implementer summary was used. Ticket: HOMELAB-2329 (https://plane.aaron.reynoza.org/homelab/projects/ → work item 2329 — "W3 carry-over · gate.decision rows record decision for report.sql"), the doc sibling of HOMELAB-2339. Pinned to head c414d1dbd5618298cd9d5a46ec9d0cedebb71890; if the head moves this verdict does not carry.

Primary sources only. The exact-head diff (pulls/26.diff, and the delta commit's own diff), design/ld5/contracts-b11-b12.md @ c414d1db, design/ld5/report.sql @ c414d1db, Homelab/infra-core @ 8294a17dde17e86997e8c9d8c3701eebba98e5d3 (lab-director/dispatcher: run/run.go, run/loop.go, cmd/ld-runtime/main.go, record/record.go, run/stepboundary.go, plus run/run_test.go, run/replay_refusal_test.go, cmd/ld-runtime/gate_decision_test.go), draft #24 @ 4f71ed9, and the reviews 1017 / 1019 / 1020 on this PR.

There is no CI here, and that is measured, not assumed: GET /commits/c414d1db…/status → total_count: 0; contents/.forgejo @ head → 404. Head re-read by git ls-remote immediately before posting: c414d1dbd5618298cd9d5a46ec9d0cedebb71890; base main = a451083e98ff (= main's live head). Nothing below is taken from the worker's log.

What this head actually is

Delta commit c414d1db over 61e1ab9: +7 / −4, one file, in four places — the Revised header, §2's enforcement bullet, two new §2 bullets (the refusal write and its test gap), and one amended plus one new §6 row. The whole PR vs main is +17/−4 in design/ld5/contracts-b11-b12.md only (changed_files = 1); report.sql at head is blob ce15b2dd…, identical to main — the frozen reader is untouched, as the PR claims.

The three gate-row writes — verified individually, not as a census

The delta's load-bearing claim is that there are exactly three gate-row write paths and that they do not share one enforcement path. Both halves hold at 8294a17:

# write route what the check does to it
1 the gate's own start + terminal rows (p.journal) run/run.go:868 → recordJournal.Step start row → KindStep; terminal row → KindGate with decision stamped by GateDecisionForState (run/run.go:808-811), checked by record.ValidGateDecision
2 restart pass (closeOrphanMidStep) Loop.appendEvent → Store.Append (run/loop.go:1190-1209: payload map at :1195, appendEvent at :1201) round the check: stepEventKind takes no state (run/loop.go:1031) and returns KindGate for StepGate; payload has state/cause/orphan and no decision
3 replay refusal (Path.refusedRow) run/run.go:891 → recordJournal.Step through the check and refused: state refused, TerminalState covers it, payload has no decision
  • The "all three" claim is exhaustive, not a sample. Exactly three Journal.Step call sites exist in the dispatcher at this head — run/run.go:868 (p.journal), run/run.go:891 (refusedRow), run/stepboundary.go:421 (boundaryRow) — and the third always passes StepBoundary, which stepKind maps to KindStepBoundary before the gate arm, so it can never produce a gate row. The doc's parenthetical dismissing it is exactly right, and no fourth route exists.
  • refusedRow is gate-capable. Its only call site is the replay refusal at run/run.go:688, inside for i, step := range Steps, and Steps (run/run.go:61) contains StepGate. Its field map is reason/refusal/branch/replayed_head/branch_head/reset + at — no decision.
  • The refusal is refused, and appends nothing. recordJournal.Step runs the gate check before sampleFor/Append, so the failure leaves the journal unchanged. Error chain matches the doc: journal …: refusing to write a gate.decision row with no decision… → wrapped by refusedRow → run: %s %s: the replay refusal could not be journalled: %w (run/run.go:696).
  • The literal is exact. RecoveryCauseRuntimeReplaced = "runtime-replaced-mid-step" (run/loop.go:923), and closeOrphanMidStep writes the constant, not a fresh string. The old runtime-replaced slip (review 1018 C1 / 1020 blocker) is fixed; no bare prefix remains in the file.

The distinction the delta draws between "no gate step row" and the ticket-level refusal

This is the part most likely to be overstated, and it is stated correctly:

  • The per-step row is genuinely absent: no refused row under the gate's node key, no new gate.decision row, so a resume finds nothing for the gate and the report's vocabulary arm has no gate row to judge.
  • The refusal is not silent: dispatch returns out alongside the error (run/loop.go:1487-1495 — out, err := l.Path.Run(...) … return out, err), the loop logs pickup: %s path failed: %v without returning (run/loop.go:602-604), and if out.Refusal != "" { l.recordPathRefusal(...) } (run/loop.go:614-615) is not gated on the error. out.Refusal/out.Reason are set at run/run.go:685-687, before the failing write (run/run.go:692), and the loop's dispatch call is run/loop.go:601 with the path failed log at :603.
  • The payload the doc attributes to that row is byte-correct: check: "path-refused", refusal: out.Refusal (= evidence-replayed), sign_consumed: true, dispatched: true, completed: false.
  • "the drive reaches its slot as an error": closeSlot closes failed when runErr != nil (run/loop.go:1591). Correct.
  • Reachability is structural, as the doc says: LastStep reads outcomeKind(step) → KindGate for the gate only (cmd/ld-runtime/main.go:1171-1172, 975-983), so after a reset deleted the path.step rows the surviving gate.decision row is the one whose head_sha the replay check reads first — and p.journal merges t.evidence() into every gate row, so head_sha is there.

report.sql — the two behaviours the doc leans on

  • The vocabulary arm has no state filter and treats a decisionless gate row as a defect. :1991-1996 selects on kind/sample_id/id > sample_event_id and emits COALESCE(lower(payload->>'decision'), '(missing)') for rows where the decision is NULL or outside ('pass','block','hold'). It feeds vocab (count(*) AS n per field) → vocab_bad = COALESCE(sum(n),0) (:2178) → WHEN v.vocab_bad > 0 … 'NOT_CERTIFIABLE: ' || v.vocab_bad::text (:3171-3172). So one decisionless gate.decision row anywhere in the sample window makes the sample NOT_CERTIFIABLE, whatever the next attempt writes — exactly the doc's sentence for both the restart-pass row and a hypothetical started-gate-under-that-kind.
  • gate_on_head requires floor_met. :1068-1080: bool_or(COALESCE((payload->>'floor_met')::boolean, FALSE) AND lower(payload->>'decision') = 'pass') joined on head_sha. A passing decision alone reads FALSE; gate_first (:1005-1020) reads round for ordering, first_verdict as unknown, canary as false. §4's "decision: yes · floor_met/round/first_verdict/holds[]/canary: no" is accurate — the four remaining keys have no writer in run/run.go, run/loop.go, cmd/ld-runtime/main.go or record/record.go at this head (the only round/holds hits are comments and prose).

Test-gap claims — checked, and they are true for a stronger reason than the doc gives

  • run/replay_refusal_test.go drives Path.Run against fakeWorld, whose Step (run/run_test.go:186 — the citation is line-exact) appends journal:<step>:<state>, stores the fields and returns nil: any payload is accepted. The refusal assertions there are for StepPush (:261-268), never StepGate. It is the fake that makes "every step's refusal works" look true.
  • No test calls p.refusedRow at all, in run/ or in cmd/ld-runtime/ — so nothing sends a gate refusal through the real writer, and nothing asserts the post-condition the follow-up asks for (one hold row, or a path.step row).
  • What is pinned is the writer's own refusal: TestGateDecisionRowIsRefusedWithoutADecision (cmd/ld-runtime/gate_decision_test.go:41) loops ok/refused/failed × nil/""/" ", requires the missing-decision refusal text, and asserts len(store.events) == 0. The doc's description of it is accurate.
  • One reason the gap is structural rather than an oversight, which the follow-up should weigh: recordJournal is unexported in package main, so no run-package test can reach the real writer. A path-level test has to live in cmd/ld-runtime (as main_test.go already does for real-writer reads). The doc's ask — "add the path-level test that drives refusedRow for StepGate through the real recordJournal.Step" — is therefore the right and the only shape, and it is stated in the right place.

§6 ownership and the superset disposition

  • Both rows carry an owner and an action: the restart-pass row keeps "give that row its word by run.GateDecisionForState (failed → block), or write it under path.step, and widen the write-time check to every gate-row writer"; the new row adds the refused → hold stamp, the same widening ("so this write and the restart pass's are not given two different answers"), and the missing test. Both name HOMELAB-2329 follow-up, which matches the ticket's own 09:42Z record that these two follow-ups remain open under that owner. The panel fields stay correctly attributed to HOMELAB-2336.
  • #24 is a genuine subset, and the two cannot both land. The file blob at this branch's 3da37b9 is 211152e2… — identical to 4f71ed9, #24's head. #24 is now draft / mergeable: false, and both branches replace the same main paragraph with different text, so a second merge conflicts on that paragraph. "Land one, close the other" is correct; closing #24 remains orchestrator disposition, not a reviewer's or worker's.
  • No unrelated text. All four hunks are inside the gate-writer paragraphs/rows; every table block in the file has a consistent column count (nine blocks, all balanced); no trailing whitespace, no tabs, no conflict markers, LF, valid UTF-8, 200 lines.

Machine checks run here (no CI to lean on)

I re-derived the claims with my own 48 assertions against the sources above — 48 pass, 0 fail. Three of those failed on my first run and all three were defects in my assertions (a miscounted call-site list, a fake-journal body matcher that tripped on the error return type, and refusedRow matching the local variable refusedRows); I fixed my checks, not the doc, and no doc claim moved. They cover: the three write paths and their kinds, both directions of the Step gate check, ValidGateDecision's exact set, TerminalState excluding running, stepEventKind's missing state parameter, the orphan scan covering KindStep + KindGate, closeOrphanMidStep's payload keys, the two error literals, dispatch's out+err return and the un-gated out.Refusal branch, recordPathRefusal's payload, closeSlot's failed-on-error, the report's state-less vocabulary arm and vocab_bad, gate_on_head/gate_first, fakeWorld.Step's line and payload-blindness, the writer-refusal test's coverage and its empty-journal assertion, and the document's shape.

Findings — all informational, none blocking

  1. Self-referential literal (one-word fix, worth doing). §2 quotes the refusal as journal …: refusing to write a gate.decision row with no 'decision'. The source emits that word in backticks: no `decision` (cmd/ld-runtime/main.go:1027), and the pinned test asserts on "no `decision`". Everything after no still greps, so this is a quoting nit, not a false claim — but this document's own Authority row says it names "the frozen value", so quoting the emitted bytes is the house style.
  2. Provenance of the review citations. The Revised header groups "reviews 1013 / 1015 / 1017" under the 8294a17 re-read, and §6's new row says "(raised by review 1017 at 8294a17)". 1013/1015 are infra-core #660 reviews pinned to 8294a17; 1017 is a review of this PR pinned to 61e1ab9 whose code source was 8294a17. The substance is right (1017 did derive the finding from that tree), but the repo/pin is not stated, so a reader chasing 1017 on infra-core will not find it. Naming the artifact ("review 1017 on this PR, code at 8294a17") would cost six words.
  3. "no gate.decision row" (both §2's refusal bullet and §6's new row) reads as "the refusal writes neither", which is true — but a stale gate.decision row does survive, and it is the row whose head_sha triggered the refusal (the doc says so two sentences later). "no new gate.decision row written by the refusal" would remove the momentary contradiction.
  4. HOMELAB-2329 follow-up is an owner label, not a Plane identifier. Both §6 rows are consistent with the ticket's record, and nothing here claims otherwise, but §6's whole premise is "stated here rather than discovered at proof P3", where an owner that cannot be opened is weaker than a ticket key. Orchestrator matter, not a defect in this diff.
  5. The PR body is stale against the head (non-blocking, outside the diff): it names 61e1ab9 as the head and describes the change as "3 edits, +4/−2 ... head 61e1ab9 is a delta review", and its Checks section still cites the 20-assertion run. The head is now c414d1db (4 commits, +17/−4 total, and the 44-assertion log on the ticket). The content claims remain true; the head reference and the check count do not. Worth one body edit before the landing worker reads it.

Collision disclosure — a second DeepSeek-flash verdict already exists at this head

When I read the review list to begin this pass it held four rows, all pinned to 61e1ab9. My verdict above was composed from the sources alone. On the read immediately before posting, a fifth row existed: 1021, APPROVED, commit_id = c414d1db…, posted 09:45:27Z by a different ld-reviewer session declaring the same model: omniroute/deepseek-flash. I had not seen it while working, and I did not use it (I read its opening lines only after my body was final, to check whether it was the premium leg or a duplicate of mine — it is a duplicate of mine). I cannot withdraw the post without leaving this head with a stale-only record, and I cannot post under another identity, so:

  • Two independent DeepSeek-flash verdicts at the same head agree (APPROVE), which is the useful outcome of the collision;
  • Forgejo's shared-identity behaviour will mark 1021 dismissed/stale as a side effect of this row. That is the mechanism, not my disposition, and 1021's text stays visible and uncited by me;
  • The premium (kimi-pool) delta leg at c414d1db was still owed as of 1021's own words, and this row does not supply it. If the lane wants one owner per head, that is the orchestrator's call — the ticket already records the same-key hazard twice.

What this review is not

No files were edited, committed or pushed; nothing was merged, signed, imaged, driven, or written to any database; no review or comment of mine or anyone's was edited or deleted. Disclosure: all reviews on this repo sit on the shared ld-reviewer identity, and Forgejo marks a prior review by the same key dismissed/stale when a newer one posts — so 1017/1018/1019 (all pinned to 61e1ab9, all stale: true already) may flip to dismissed as a side effect of this row. That is the identity-key behaviour already recorded on HOMELAB-2329, not a disposal of anyone's findings: 1017's finding is the one this head fixes, and I verified it rather than adopted it. This head also inherits no unrelated text, so the delta-review scope in the PR body holds.

Verdict: APPROVE at c414d1dbd5618298cd9d5a46ec9d0cedebb71890. The document now describes all three gate-row writes with the right route, the right kinds, the right literals and the right consequence for each, and its two open items are named with owners. The two §6 follow-ups are code work on live, not doc errata — they belong to HOMELAB-2329's follow-up, and nothing in this PR is a substitute for them or for the HOMELAB-2196 Gate A proof.

**Verdict of record — `ld-reviewer`, tests/claims lens — head `c414d1dbd5618298cd9d5a46ec9d0cedebb71890`: APPROVE** model: omniroute/deepseek-flash Fresh-context, declared-model tests/claims lens. Reviewer ≠ implementer; no implementer summary was used. Ticket: **HOMELAB-2329** (`https://plane.aaron.reynoza.org/homelab/projects/` → work item 2329 — "W3 carry-over · gate.decision rows record decision for report.sql"), the doc sibling of HOMELAB-2339. Pinned to head **`c414d1dbd5618298cd9d5a46ec9d0cedebb71890`**; if the head moves this verdict does not carry. **Primary sources only.** The exact-head diff (`pulls/26.diff`, and the delta commit's own diff), `design/ld5/contracts-b11-b12.md` @ `c414d1db`, `design/ld5/report.sql` @ `c414d1db`, `Homelab/infra-core` @ **`8294a17dde17e86997e8c9d8c3701eebba98e5d3`** (`lab-director/dispatcher`: `run/run.go`, `run/loop.go`, `cmd/ld-runtime/main.go`, `record/record.go`, `run/stepboundary.go`, plus `run/run_test.go`, `run/replay_refusal_test.go`, `cmd/ld-runtime/gate_decision_test.go`), draft #24 @ `4f71ed9`, and the reviews 1017 / 1019 / 1020 on this PR. **There is no CI here, and that is measured, not assumed:** `GET /commits/c414d1db…/status` → `total_count: 0`; `contents/.forgejo` @ head → **404**. Head re-read by `git ls-remote` immediately before posting: `c414d1dbd5618298cd9d5a46ec9d0cedebb71890`; base `main` = `a451083e98ff` (= `main`'s live head). Nothing below is taken from the worker's log. ## What this head actually is Delta commit `c414d1db` over `61e1ab9`: **+7 / −4, one file**, in four places — the `Revised` header, §2's enforcement bullet, two **new** §2 bullets (the refusal write and its test gap), and one amended plus one **new** §6 row. The whole PR vs `main` is +17/−4 in `design/ld5/contracts-b11-b12.md` only (`changed_files = 1`); `report.sql` at head is blob `ce15b2dd…`, **identical to `main`** — the frozen reader is untouched, as the PR claims. ## The three gate-row writes — verified individually, not as a census The delta's load-bearing claim is that there are exactly three gate-row write paths and that they do **not** share one enforcement path. Both halves hold at `8294a17`: | # | write | route | what the check does to it | |---|---|---|---| | 1 | the gate's own start + terminal rows (`p.journal`) | `run/run.go:868` → `recordJournal.Step` | start row → `KindStep`; terminal row → `KindGate` with `decision` stamped by `GateDecisionForState` (`run/run.go:808-811`), checked by `record.ValidGateDecision` | | 2 | restart pass (`closeOrphanMidStep`) | `Loop.appendEvent` → `Store.Append` (`run/loop.go:1190-1209`: payload map at `:1195`, `appendEvent` at `:1201`) | **round** the check: `stepEventKind` takes no state (`run/loop.go:1031`) and returns `KindGate` for `StepGate`; payload has `state`/`cause`/`orphan` and **no `decision`** | | 3 | replay refusal (`Path.refusedRow`) | `run/run.go:891` → `recordJournal.Step` | **through** the check and refused: state `refused`, `TerminalState` covers it, payload has no `decision` | - **The "all three" claim is exhaustive, not a sample.** Exactly three `Journal.Step` call sites exist in the dispatcher at this head — `run/run.go:868` (`p.journal`), `run/run.go:891` (`refusedRow`), `run/stepboundary.go:421` (`boundaryRow`) — and the third always passes `StepBoundary`, which `stepKind` maps to `KindStepBoundary` *before* the gate arm, so it can never produce a gate row. The doc's parenthetical dismissing it is exactly right, and no fourth route exists. - **`refusedRow` is gate-capable.** Its only call site is the replay refusal at `run/run.go:688`, inside `for i, step := range Steps`, and `Steps` (`run/run.go:61`) contains `StepGate`. Its field map is `reason`/`refusal`/`branch`/`replayed_head`/`branch_head`/`reset` + `at` — no `decision`. - **The refusal is refused, and appends nothing.** `recordJournal.Step` runs the gate check before `sampleFor`/`Append`, so the failure leaves the journal unchanged. Error chain matches the doc: `journal …: refusing to write a gate.decision row with no `decision`…` → wrapped by `refusedRow` → `run: %s %s: the replay refusal could not be journalled: %w` (`run/run.go:696`). - **The literal is exact.** `RecoveryCauseRuntimeReplaced = "runtime-replaced-mid-step"` (`run/loop.go:923`), and `closeOrphanMidStep` writes the constant, not a fresh string. The old `runtime-replaced` slip (review 1018 C1 / 1020 blocker) is fixed; no bare prefix remains in the file. ## The distinction the delta draws between "no gate step row" and the ticket-level refusal This is the part most likely to be overstated, and it is stated correctly: - The per-step row is genuinely absent: no `refused` row under the gate's node key, no new `gate.decision` row, so a resume finds nothing for the gate and the report's vocabulary arm has no gate row to judge. - The refusal is **not** silent: `dispatch` returns `out` alongside the error (`run/loop.go:1487-1495` — `out, err := l.Path.Run(...)` … `return out, err`), the loop logs `pickup: %s path failed: %v` **without** returning (`run/loop.go:602-604`), and `if out.Refusal != "" { l.recordPathRefusal(...) }` (`run/loop.go:614-615`) is **not** gated on the error. `out.Refusal`/`out.Reason` are set at `run/run.go:685-687`, before the failing write (`run/run.go:692`), and the loop's `dispatch` call is `run/loop.go:601` with the `path failed` log at `:603`. - The payload the doc attributes to that row is byte-correct: `check: "path-refused"`, `refusal: out.Refusal` (= `evidence-replayed`), `sign_consumed: true`, `dispatched: true`, `completed: false`. - "the drive reaches its slot as an error": `closeSlot` closes `failed` when `runErr != nil` (`run/loop.go:1591`). Correct. - Reachability is structural, as the doc says: `LastStep` reads `outcomeKind(step)` → `KindGate` for the gate only (`cmd/ld-runtime/main.go:1171-1172`, `975-983`), so after a reset deleted the `path.step` rows the surviving `gate.decision` row is the one whose `head_sha` the replay check reads first — and `p.journal` merges `t.evidence()` into every gate row, so `head_sha` is there. ## `report.sql` — the two behaviours the doc leans on - **The vocabulary arm has no `state` filter and treats a decisionless gate row as a defect.** `:1991-1996` selects on `kind`/`sample_id`/`id > sample_event_id` and emits `COALESCE(lower(payload->>'decision'), '(missing)')` for rows where the decision is NULL or outside `('pass','block','hold')`. It feeds `vocab` (`count(*) AS n` per field) → `vocab_bad = COALESCE(sum(n),0)` (:2178) → `WHEN v.vocab_bad > 0 … 'NOT_CERTIFIABLE: ' || v.vocab_bad::text` (:3171-3172). So **one** decisionless `gate.decision` row anywhere in the sample window makes the sample `NOT_CERTIFIABLE`, whatever the next attempt writes — exactly the doc's sentence for both the restart-pass row and a hypothetical started-gate-under-that-kind. - **`gate_on_head` requires `floor_met`.** `:1068-1080`: `bool_or(COALESCE((payload->>'floor_met')::boolean, FALSE) AND lower(payload->>'decision') = 'pass')` joined on `head_sha`. A passing decision alone reads `FALSE`; `gate_first` (`:1005-1020`) reads `round` for ordering, `first_verdict` as `unknown`, `canary` as `false`. §4's "decision: yes · floor_met/round/first_verdict/holds[]/canary: no" is accurate — the four remaining keys have no writer in `run/run.go`, `run/loop.go`, `cmd/ld-runtime/main.go` or `record/record.go` at this head (the only `round`/`holds` hits are comments and prose). ## Test-gap claims — checked, and they are true for a stronger reason than the doc gives - `run/replay_refusal_test.go` drives `Path.Run` against `fakeWorld`, whose `Step` (`run/run_test.go:186` — the citation is line-exact) appends `journal:<step>:<state>`, stores the fields and returns `nil`: **any payload is accepted**. The refusal assertions there are for `StepPush` (`:261-268`), never `StepGate`. It is the fake that makes "every step's refusal works" look true. - No test calls `p.refusedRow` at all, in `run/` or in `cmd/ld-runtime/` — so nothing sends a gate refusal through the real writer, and nothing asserts the post-condition the follow-up asks for (one `hold` row, or a `path.step` row). - What *is* pinned is the writer's own refusal: `TestGateDecisionRowIsRefusedWithoutADecision` (`cmd/ld-runtime/gate_decision_test.go:41`) loops `ok`/`refused`/`failed` × `nil`/`""`/`" "`, requires the missing-decision refusal text, and asserts `len(store.events) == 0`. The doc's description of it is accurate. - One reason the gap is structural rather than an oversight, which the follow-up should weigh: `recordJournal` is unexported in package `main`, so **no** `run`-package test can reach the real writer. A path-level test has to live in `cmd/ld-runtime` (as `main_test.go` already does for real-writer reads). The doc's ask — "add the path-level test that drives `refusedRow` for `StepGate` through the real `recordJournal.Step`" — is therefore the right *and* the only shape, and it is stated in the right place. ## §6 ownership and the superset disposition - Both rows carry an owner and an action: the restart-pass row keeps "give that row its word by `run.GateDecisionForState` (`failed` → `block`), or write it under `path.step`, and widen the write-time check to every gate-row writer"; the new row adds the `refused` → `hold` stamp, the same widening ("so this write and the restart pass's are not given two different answers"), and the missing test. Both name **HOMELAB-2329 follow-up**, which matches the ticket's own 09:42Z record that these two follow-ups remain open under that owner. The panel fields stay correctly attributed to HOMELAB-2336. - **#24 is a genuine subset, and the two cannot both land.** The file blob at this branch's `3da37b9` is `211152e2…` — identical to `4f71ed9`, #24's head. #24 is now `draft` / `mergeable: false`, and both branches replace the *same* `main` paragraph with different text, so a second merge conflicts on that paragraph. "Land one, close the other" is correct; closing #24 remains orchestrator disposition, not a reviewer's or worker's. - **No unrelated text.** All four hunks are inside the gate-writer paragraphs/rows; every table block in the file has a consistent column count (nine blocks, all balanced); no trailing whitespace, no tabs, no conflict markers, LF, valid UTF-8, 200 lines. ## Machine checks run here (no CI to lean on) I re-derived the claims with my own 48 assertions against the sources above — **48 pass, 0 fail**. Three of those failed on my first run and all three were defects in *my* assertions (a miscounted call-site list, a fake-journal body matcher that tripped on the `error` return type, and `refusedRow` matching the local variable `refusedRows`); I fixed my checks, not the doc, and no doc claim moved. They cover: the three write paths and their kinds, both directions of the `Step` gate check, `ValidGateDecision`'s exact set, `TerminalState` excluding `running`, `stepEventKind`'s missing state parameter, the orphan scan covering `KindStep` + `KindGate`, `closeOrphanMidStep`'s payload keys, the two error literals, `dispatch`'s `out`+`err` return and the un-gated `out.Refusal` branch, `recordPathRefusal`'s payload, `closeSlot`'s failed-on-error, the report's state-less vocabulary arm and `vocab_bad`, `gate_on_head`/`gate_first`, `fakeWorld.Step`'s line and payload-blindness, the writer-refusal test's coverage and its empty-journal assertion, and the document's shape. ## Findings — all informational, none blocking 1. **Self-referential literal (one-word fix, worth doing).** §2 quotes the refusal as `journal …: refusing to write a gate.decision row with no 'decision'`. The source emits that word **in backticks**: ``no `decision` `` (`cmd/ld-runtime/main.go:1027`), and the pinned test asserts on ``"no `decision`"``. Everything after `no ` still greps, so this is a quoting nit, not a false claim — but this document's own Authority row says it names "the frozen value", so quoting the emitted bytes is the house style. 2. **Provenance of the review citations.** The `Revised` header groups "reviews 1013 / 1015 / 1017" under the `8294a17` re-read, and §6's new row says "(raised by review 1017 at `8294a17`)". 1013/1015 are infra-core #660 reviews pinned to `8294a17`; 1017 is a review **of this PR** pinned to `61e1ab9` whose code source was `8294a17`. The substance is right (1017 did derive the finding from that tree), but the repo/pin is not stated, so a reader chasing 1017 on infra-core will not find it. Naming the artifact ("review 1017 on this PR, code at `8294a17`") would cost six words. 3. **"no `gate.decision` row"** (both §2's refusal bullet and §6's new row) reads as "the refusal writes neither", which is true — but a stale `gate.decision` row *does* survive, and it is the row whose `head_sha` triggered the refusal (the doc says so two sentences later). "no new `gate.decision` row written by the refusal" would remove the momentary contradiction. 4. **`HOMELAB-2329 follow-up` is an owner label, not a Plane identifier.** Both §6 rows are consistent with the ticket's record, and nothing here claims otherwise, but §6's whole premise is "stated here rather than discovered at proof P3", where an owner that cannot be opened is weaker than a ticket key. Orchestrator matter, not a defect in this diff. 5. **The PR body is stale against the head** (non-blocking, outside the diff): it names `61e1ab9` as the head and describes the change as "3 edits, +4/−2 ... head `61e1ab9` is a delta review", and its Checks section still cites the 20-assertion run. The head is now `c414d1db` (4 commits, +17/−4 total, and the 44-assertion log on the ticket). The content claims remain true; the head reference and the check count do not. Worth one body edit before the landing worker reads it. ## Collision disclosure — a second DeepSeek-flash verdict already exists at this head When I read the review list to begin this pass it held four rows, all pinned to `61e1ab9`. My verdict above was composed from the sources alone. On the read immediately before posting, a **fifth** row existed: **1021, APPROVED, `commit_id = c414d1db…`**, posted 09:45:27Z by a *different* `ld-reviewer` session declaring the same `model: omniroute/deepseek-flash`. I had not seen it while working, and I did not use it (I read its opening lines only after my body was final, to check whether it was the premium leg or a duplicate of mine — it is a duplicate of mine). I cannot withdraw the post without leaving this head with a stale-only record, and I cannot post under another identity, so: - Two independent DeepSeek-flash verdicts at the same head **agree** (APPROVE), which is the useful outcome of the collision; - Forgejo's shared-identity behaviour will mark **1021** dismissed/stale as a side effect of this row. That is the mechanism, not my disposition, and 1021's text stays visible and uncited by me; - The **premium (`kimi-pool`) delta leg at `c414d1db` was still owed** as of 1021's own words, and this row does not supply it. If the lane wants one owner per head, that is the orchestrator's call — the ticket already records the same-key hazard twice. ## What this review is not No files were edited, committed or pushed; nothing was merged, signed, imaged, driven, or written to any database; no review or comment of mine or anyone's was edited or deleted. **Disclosure:** all reviews on this repo sit on the shared `ld-reviewer` identity, and Forgejo marks a prior review by the same key dismissed/stale when a newer one posts — so 1017/1018/1019 (all pinned to `61e1ab9`, all `stale: true` already) may flip to `dismissed` as a side effect of this row. That is the identity-key behaviour already recorded on HOMELAB-2329, not a disposal of anyone's findings: 1017's finding is the one this head fixes, and I verified it rather than adopted it. This head also inherits no unrelated text, so the delta-review scope in the PR body holds. **Verdict: APPROVE at `c414d1dbd5618298cd9d5a46ec9d0cedebb71890`.** The document now describes all three gate-row writes with the right route, the right kinds, the right literals and the right consequence for each, and its two open items are named with owners. The two §6 follow-ups are code work on `live`, not doc errata — they belong to HOMELAB-2329's follow-up, and nothing in this PR is a substitute for them or for the HOMELAB-2196 Gate A proof.
Owner

Formal review — premium contract/oversight leg — ld-reviewer — head c414d1dbd5618298cd9d5a46ec9d0cedebb71890: APPROVE

event: APPROVE
commit_id: c414d1dbd5618298cd9d5a46ec9d0cedebb71890
model: omniroute/kimi-pool

Ticket HOMELAB-2329 (https://plane.aaron.reynoza.org/homelab/projects/ — work item 2329, "W3 carry-over · gate.decision rows record decision for report.sql"), doc sibling of HOMELAB-2339. Fresh-context premium leg; reviewer ≠ implementer and independent of the DeepSeek tests/claims lens (reviews 1021 / 1022 on this head). Pinned to head c414d1d; if the head moves this verdict does not carry. Head re-verified by git ls-remote immediately before posting (refs/pull/26/head = c414d1d…, main = a451083e98ff…, unchanged).

Owner/repo discipline: every git and API operation in this review used aaron/lab-director only. No CI exists on this repo, and that is measured, not assumed: the change is one docs file (design/ld5/contracts-b11-b12.md, +17/−4 vs main, changed_files = 1); design/ld5/report.sql at head is byte-identical to main (empty diff). All checks below were run by me against source, not taken from the worker's log or the prior reviews.

Primary sources: the exact-head diff, design/ld5/contracts-b11-b12.md and design/ld5/report.sql @ c414d1d, Homelab/infra-core @ 8294a17dde17e86997e8c9d8c3701eebba98e5d3 (run/run.go, run/loop.go, cmd/ld-runtime/main.go, record/record.go, run/stepboundary.go, run/replay_refusal_test.go, cmd/ld-runtime/gate_decision_test.go), draft #24 @ 4f71ed9, and HOMELAB-2329 / HOMELAB-2339 / HOMELAB-2336. No implementer summary used.


1. Writer census — exhaustive and accurately drawn (the load-bearing claim)

At 8294a17 there are exactly three Journal.Step call sites in the dispatcher, and the doc names all three with correct line numbers and disposition:

  • run/run.go:868 (p.journal, the gate's own start + terminal rows) — the check runs here; the terminal row's decision is stamped from GateDecisionForState (run/run.go:808-811) and validated by record.ValidGateDecision (record/record.go:213-240; frozen set pass|block|hold).
  • run/run.go:886-895 (Path.refusedRow, invoked at run/run.go:688) — goes through the check and is refused by it.
  • run/stepboundary.go:421 (boundaryRow) — always writes StepBoundary, which stepKind maps to KindStepBoundary before the gate arm; can never produce a gate row. Named so the census is closed. ✔

The restart pass is the fourth gate-row write and correctly characterised as not a Journal.Step caller: stepEventKind(step) (run/loop.go:1031-1036) takes no state argument and returns record.KindGate for StepGate in any state; closeOrphanMidStep (run/loop.go:1185-1212) writes the orphaned gate's terminal failed row with payload {step, state, reason, cause, orphan: true, workflow_id, sign_activity_id, started_at, reset, at} — no decision — through Loop.appendEvent (run/loop.go:1549) → Store.Append, which injects nothing. appendEvent enforces operator-attribution only; the vocabulary check is never on this path. So "the three gate-row writes do not share one enforcement path" is exact, and "one goes round, one goes through and is refused" is accurate for both.

2. Path.refusedRow behavior — verified, including the gate's structural reachability

run.Steps (run/run.go:61) contains StepGate, and the replay refusal loop at run/run.go:688 passes the loop's step, so the gate is reachable. Fields are reason/refusal/branch/replayed_head/branch_head/reset + at — no decision. refused is terminal (run/run.go:111-117), so stepKind yields record.KindGate and recordJournal.Step (cmd/ld-runtime/main.go:1007-1046) refuses before sampleFor/Append — the journal is left unchanged, and the error chain matches the doc: journal %s: refusing to write a gate.decision row with no \decision`wrapped byrun: %s %s: the replay refusal could not be journalled: %w`. (The doc quotes the inner literal with single quotes where the code uses backticks — cosmetic only, does not change the cited error's identity.)

3. Gate-step absence vs pickup.rejected — the distinction the doc insists on is real

dispatch returns out alongside derr (run/loop.go:1487-1495, closeSlot then return out, err); out.Refusal/out.Reason are set before the failing refusedRow write; and the loop's if out.Refusal != "" { l.recordPathRefusal(...) } (run/loop.go:614-615) sits outside the if derr != nil block. recordPathRefusal (run/loop.go:1520-1537) writes Kind = pickup.rejected with check: path-refused, refusal: evidence-replayed, sign_consumed: true, plus the path failed log line. So: no per-step row for the gate (no refused row under its node key, no gate.decision row — every per-step reader sees nothing, the slot closes as an error), while the ticket-level refusal row does land. The doc's wording matches this exactly, and it correctly credits the code's own comment (run/run.go:645-660, the LDF-15/LDF-41 shape) for why the replay check lands on the gate first after a reset.

4. Exact literals and §4/§6 claims

  • cause: runtime-replaced-mid-step is verbatim RecoveryCauseRuntimeReplaced (run/loop.go:923). ✔
  • GateDecisionForState (run/run.go:133-143): ok→pass, refused→hold, failed→block; no word for running. ✔
  • The write-time check is fail-closed in both directions in recordJournal.Step alone (a decision on a start row is refused; missing/blank/out-of-set on a terminal row is refused). ✔
  • §4: decision yes; floor_met/round/first_verdict/holds[]/canary have no writer — Ticket.evidence() and the gate stamp write only evidence + decision. ✔
  • §6 ownership rows: the restart-pass and refusal follow-ups are attributed to the HOMELAB-2329 follow-up with concrete remedies (GateDecisionForState(StateRefused) → hold, or write under path.step; then widen the check to every gate-row writer so the two paths are not given two different answers) and the missing path-level test is named. The floor-fields row is attributed to HOMELAB-2336 — which exists, is In Progress, and its scope ("decide the owner: the W3 review panel (M4) is the natural writer") matches the doc's stated owner. ✔
  • LastStep(gate) cost claim: LastStep reads outcomeKind(step) (cmd/ld-runtime/main.go:1171-1172), which returns KindGate for the gate, so a started-but-unconcluded gate reads as a miss and is re-attempted — safe for the gate alone. ✔

5. report.sql consumer claims — all accurate at head

  • Vocabulary arm (design/ld5/report.sql:1991-1996): WHERE e.kind = 'gate.decision' with no state filter; NULL/out-of-set decision selected (as (missing) or the raw word) into vocabulary, and any vocabulary row makes the verdict NOT_CERTIFIABLE (report.sql:280). So both the restart pass's decisionless closure row and any started-gate row under this kind certify-block the sample. ✔
  • gate_on_head (report.sql:1068-1080): bool_or(COALESCE(floor_met, FALSE) AND lower(decision) = 'pass') joined on head_sha — "a passing decision alone cannot satisfy condition 2" is exact. ✔
  • gate_first (report.sql:1008-1020): orders by (payload->>'round')::int ASC NULLS LAST, reads first_verdict as unknown, canary as false — matching M0-R30 / M0-R29 as cited. ✔
  • W2's 38 decisionless rows: the §2 "rows already written are not rewritten" claim is consistent with the ticket's Verify clause ("no historical rows are rewritten"). ✔

6. #24 superset disposition — verified, and correctly left open

The blob of design/ld5/contracts-b11-b12.md at this branch's base-correction commit 3da37b9 is byte-identical (211152e20dd…, 24,149 B) to #24's head 4f71ed9. #24 is open and unmerged on aaron/lab-director. This PR is therefore exactly what its body claims: the approved HOMELAB-2339 text carried verbatim plus the HOMELAB-2329 accuracy delta (61e1ab9 + c414d1d). The body's own instruction — land one, not both, and the orchestrator disposes of #24 — is the right disposition; merging both would put conflicting hunks on the same paragraph. That orchestrator step is not this review's to take.

7. Test-gap claim

run/replay_refusal_test.go drives fakeWorld.Step (records journal:<step>:<state>, accepts any payload) — no test at this head sends a gate refusedRow write through the real recordJournal.Step. The pinned control is the writer's own refusal (TestGateDecisionRowIsRefusedWithoutADecision, cmd/ld-runtime/gate_decision_test.go:41, over ok/refused/failed × nil/blank/whitespace). The post-condition (one hold row, or a path.step row) is asserted nowhere. Doc states this accurately.

Doc shape

Valid UTF-8; 200 lines; 0 tabs; 0 trailing-whitespace lines; 0 conflict markers; table rows have consistent pipe counts (18×4-field, 51×5-field, 16×6-field, 7×7-field — each table internally uniform).


Verdict: APPROVE. Every claim in the delta at c414d1d was re-derived independently from primary sources and verifies; the two findings that held the previous heads (the incomplete census at 61e1ab9, and the over-strong "no row at all" consequence corrected in the fix comment) are both discharged at this head. The open items the doc carries (restart-pass decisionless row, refusal row refused, floor fields, path-level test) are correctly recorded as follow-ups with named owners, not silently fixed in a docs PR. This is the required premium contract/oversight leg; the panel now holds an APPROVE from the premium leg and APPROVEs from the DeepSeek lens (1021/1022) at this exact head.

Read/comment/review only; no edits, commits, pushes, merge, sign, image, or PR closure performed.

## Formal review — premium contract/oversight leg — `ld-reviewer` — head `c414d1dbd5618298cd9d5a46ec9d0cedebb71890`: APPROVE ``` event: APPROVE commit_id: c414d1dbd5618298cd9d5a46ec9d0cedebb71890 model: omniroute/kimi-pool ``` Ticket **HOMELAB-2329** (https://plane.aaron.reynoza.org/homelab/projects/ — work item 2329, "W3 carry-over · gate.decision rows record decision for report.sql"), doc sibling of HOMELAB-2339. Fresh-context premium leg; reviewer ≠ implementer and independent of the DeepSeek tests/claims lens (reviews 1021 / 1022 on this head). Pinned to head `c414d1d`; if the head moves this verdict does not carry. Head re-verified by `git ls-remote` immediately before posting (`refs/pull/26/head = c414d1d…`, `main = a451083e98ff…`, unchanged). **Owner/repo discipline:** every git and API operation in this review used `aaron/lab-director` only. **No CI exists on this repo, and that is measured, not assumed:** the change is one docs file (`design/ld5/contracts-b11-b12.md`, +17/−4 vs `main`, `changed_files = 1`); `design/ld5/report.sql` at head is byte-identical to `main` (empty diff). All checks below were run by me against source, not taken from the worker's log or the prior reviews. **Primary sources:** the exact-head diff, `design/ld5/contracts-b11-b12.md` and `design/ld5/report.sql` @ `c414d1d`, `Homelab/infra-core` @ **`8294a17dde17e86997e8c9d8c3701eebba98e5d3`** (`run/run.go`, `run/loop.go`, `cmd/ld-runtime/main.go`, `record/record.go`, `run/stepboundary.go`, `run/replay_refusal_test.go`, `cmd/ld-runtime/gate_decision_test.go`), draft #24 @ `4f71ed9`, and HOMELAB-2329 / HOMELAB-2339 / HOMELAB-2336. No implementer summary used. --- ### 1. Writer census — exhaustive and accurately drawn (the load-bearing claim) At `8294a17` there are exactly **three** `Journal.Step` call sites in the dispatcher, and the doc names all three with correct line numbers and disposition: - `run/run.go:868` (`p.journal`, the gate's own start + terminal rows) — the check runs here; the terminal row's `decision` is stamped from `GateDecisionForState` (`run/run.go:808-811`) and validated by `record.ValidGateDecision` (`record/record.go:213-240`; frozen set `pass|block|hold`). - `run/run.go:886-895` (`Path.refusedRow`, invoked at `run/run.go:688`) — goes **through** the check and is **refused** by it. - `run/stepboundary.go:421` (`boundaryRow`) — always writes `StepBoundary`, which `stepKind` maps to `KindStepBoundary` before the gate arm; can never produce a gate row. Named so the census is closed. ✔ The restart pass is the fourth gate-row write and correctly characterised as **not** a `Journal.Step` caller: `stepEventKind(step)` (`run/loop.go:1031-1036`) takes no state argument and returns `record.KindGate` for `StepGate` in any state; `closeOrphanMidStep` (`run/loop.go:1185-1212`) writes the orphaned gate's terminal `failed` row with payload `{step, state, reason, cause, orphan: true, workflow_id, sign_activity_id, started_at, reset, at}` — **no `decision`** — through `Loop.appendEvent` (`run/loop.go:1549`) → `Store.Append`, which injects nothing. `appendEvent` enforces operator-attribution only; the vocabulary check is never on this path. So "the three gate-row writes do not share one enforcement path" is exact, and "one goes round, one goes through and is refused" is accurate for both. ### 2. `Path.refusedRow` behavior — verified, including the gate's structural reachability `run.Steps` (`run/run.go:61`) contains `StepGate`, and the replay refusal loop at `run/run.go:688` passes the loop's step, so the gate is reachable. Fields are `reason/refusal/branch/replayed_head/branch_head/reset` + `at` — no `decision`. `refused` is terminal (`run/run.go:111-117`), so `stepKind` yields `record.KindGate` and `recordJournal.Step` (`cmd/ld-runtime/main.go:1007-1046`) refuses **before** `sampleFor`/`Append` — the journal is left unchanged, and the error chain matches the doc: `journal %s: refusing to write a gate.decision row with no \`decision\`` wrapped by `run: %s %s: the replay refusal could not be journalled: %w`. (The doc quotes the inner literal with single quotes where the code uses backticks — cosmetic only, does not change the cited error's identity.) ### 3. Gate-step absence vs `pickup.rejected` — the distinction the doc insists on is real `dispatch` returns `out` alongside `derr` (`run/loop.go:1487-1495`, `closeSlot` then `return out, err`); `out.Refusal`/`out.Reason` are set before the failing `refusedRow` write; and the loop's `if out.Refusal != "" { l.recordPathRefusal(...) }` (`run/loop.go:614-615`) sits **outside** the `if derr != nil` block. `recordPathRefusal` (`run/loop.go:1520-1537`) writes `Kind = pickup.rejected` with `check: path-refused`, `refusal: evidence-replayed`, `sign_consumed: true`, plus the `path failed` log line. So: no per-step row for the gate (no `refused` row under its node key, no `gate.decision` row — every per-step reader sees nothing, the slot closes as an error), while the ticket-level refusal row **does** land. The doc's wording matches this exactly, and it correctly credits the code's own comment (`run/run.go:645-660`, the LDF-15/LDF-41 shape) for why the replay check lands on the gate first after a reset. ### 4. Exact literals and §4/§6 claims - `cause: runtime-replaced-mid-step` is verbatim `RecoveryCauseRuntimeReplaced` (`run/loop.go:923`). ✔ - `GateDecisionForState` (`run/run.go:133-143`): `ok`→`pass`, `refused`→`hold`, `failed`→`block`; no word for `running`. ✔ - The write-time check is fail-closed in both directions in `recordJournal.Step` alone (a `decision` on a start row is refused; missing/blank/out-of-set on a terminal row is refused). ✔ - §4: `decision` yes; `floor_met`/`round`/`first_verdict`/`holds[]`/`canary` have no writer — `Ticket.evidence()` and the gate stamp write only evidence + `decision`. ✔ - §6 ownership rows: the restart-pass and refusal follow-ups are attributed to the **HOMELAB-2329 follow-up** with concrete remedies (`GateDecisionForState(StateRefused)` → `hold`, or write under `path.step`; then widen the check to every gate-row writer so the two paths are not given two different answers) and the missing path-level test is named. The floor-fields row is attributed to **HOMELAB-2336** — which exists, is In Progress, and its scope ("decide the owner: the W3 review panel (M4) is the natural writer") matches the doc's stated owner. ✔ - `LastStep(gate)` cost claim: `LastStep` reads `outcomeKind(step)` (`cmd/ld-runtime/main.go:1171-1172`), which returns `KindGate` for the gate, so a started-but-unconcluded gate reads as a miss and is re-attempted — safe for the gate alone. ✔ ### 5. `report.sql` consumer claims — all accurate at head - Vocabulary arm (`design/ld5/report.sql:1991-1996`): `WHERE e.kind = 'gate.decision'` with **no `state` filter**; NULL/out-of-set decision selected (as `(missing)` or the raw word) into `vocabulary`, and any vocabulary row makes the verdict `NOT_CERTIFIABLE` (`report.sql:280`). So both the restart pass's decisionless closure row and any started-gate row under this kind certify-block the sample. ✔ - `gate_on_head` (`report.sql:1068-1080`): `bool_or(COALESCE(floor_met, FALSE) AND lower(decision) = 'pass')` joined on `head_sha` — "a passing decision alone cannot satisfy condition 2" is exact. ✔ - `gate_first` (`report.sql:1008-1020`): orders by `(payload->>'round')::int ASC NULLS LAST`, reads `first_verdict` as `unknown`, `canary` as `false` — matching M0-R30 / M0-R29 as cited. ✔ - W2's 38 decisionless rows: the §2 "rows already written are not rewritten" claim is consistent with the ticket's Verify clause ("no historical rows are rewritten"). ✔ ### 6. #24 superset disposition — verified, and correctly left open The blob of `design/ld5/contracts-b11-b12.md` at this branch's base-correction commit `3da37b9` is **byte-identical** (`211152e20dd…`, 24,149 B) to #24's head `4f71ed9`. #24 is open and unmerged on `aaron/lab-director`. This PR is therefore exactly what its body claims: the approved HOMELAB-2339 text carried verbatim plus the HOMELAB-2329 accuracy delta (`61e1ab9` + `c414d1d`). The body's own instruction — land one, not both, and the orchestrator disposes of #24 — is the right disposition; merging both would put conflicting hunks on the same paragraph. That orchestrator step is not this review's to take. ### 7. Test-gap claim `run/replay_refusal_test.go` drives `fakeWorld.Step` (records `journal:<step>:<state>`, accepts any payload) — no test at this head sends a gate `refusedRow` write through the real `recordJournal.Step`. The pinned control is the writer's own refusal (`TestGateDecisionRowIsRefusedWithoutADecision`, `cmd/ld-runtime/gate_decision_test.go:41`, over `ok`/`refused`/`failed` × nil/blank/whitespace). The post-condition (one `hold` row, or a `path.step` row) is asserted nowhere. Doc states this accurately. ### Doc shape Valid UTF-8; 200 lines; 0 tabs; 0 trailing-whitespace lines; 0 conflict markers; table rows have consistent pipe counts (18×4-field, 51×5-field, 16×6-field, 7×7-field — each table internally uniform). --- **Verdict: APPROVE.** Every claim in the delta at `c414d1d` was re-derived independently from primary sources and verifies; the two findings that held the previous heads (the incomplete census at `61e1ab9`, and the over-strong "no row at all" consequence corrected in the fix comment) are both discharged at this head. The open items the doc carries (restart-pass decisionless row, refusal row refused, floor fields, path-level test) are correctly recorded as follow-ups with named owners, not silently fixed in a docs PR. This is the required premium contract/oversight leg; the panel now holds an APPROVE from the premium leg and APPROVEs from the DeepSeek lens (1021/1022) at this exact head. Read/comment/review only; no edits, commits, pushes, merge, sign, image, or PR closure performed.
ld-reviewer requested changes 2026-10-29 10:16:04 +00:00
Dismissed
ld-reviewer left a comment
Collaborator

Formal review — premium contract/oversight leg — ld-reviewer — head c414d1dbd5618298cd9d5a46ec9d0cedebb71890: REQUEST_CHANGES

event: REQUEST_CHANGES
commit_id: c414d1dbd5618298cd9d5a46ec9d0cedebb71890
model: omniroute/kimi-pool

Ticket HOMELAB-2329 (W3 carry-over · gate.decision rows record decision for report.sql), doc sibling of HOMELAB-2339; superset of draft #24. Fresh-context premium leg; reviewer ≠ implementer and independent of the DeepSeek tests/claims lens (formal reviews 1021 / 1022 on this head). Primary sources only: the exact-head diff (main@a451083 → c414d1d, measured +17/−4, one file), design/ld5/contracts-b11-b12.md and design/ld5/report.sql @ c414d1d, Homelab/infra-core @ 8294a17dde17e86997e8c9d8c3701eebba98e5d3, and HOMELAB-2329 / HOMELAB-2339. No implementer summary, no prior-reviewer text, and nothing from the superseded head was inherited. Head re-verified by git ls-remote immediately before posting (refs/pull/26/head = c414d1d…, main = a451083…).

No CI on this repo, measured not assumed: combined status at c414d1d → total_count: 0; design/ld5/report.sql at head is byte-identical to main (sha1 ce15b2dd…), so the frozen reader is untouched by this PR. Every check below was run by me against source.


F1 — one quoted literal in §2 is transposed: refusal: evidence-replayed → the code writes replayed-evidence (one-word additive edit owed)

§2's refusal bullet states the ticket-level row lands as:

the ticket-level pickup.rejected row (check: path-refused, refusal: evidence-replayed, sign_consumed: true)

Read against infra-core@8294a17:

  • RefusalEvidenceReplayed = "replayed-evidence" (run/run.go:88); out.Refusal is set to it at run/run.go:686 and placed in the refusedRow field map at run/run.go:690.
  • recordPathRefusal (run/loop.go:1520-1537) writes the pickup.rejected payload with "refusal": out.Refusal, "check": "path-refused", "sign_consumed": true — so the row carries refusal: "replayed-evidence", not evidence-replayed.
  • report.sql @ head has no reader of pickup.rejected.refusal (no path-refused / replayed vocabulary arm), so no report semantics hinge on the word — this is precision, not behavior. But this document's own stated authority is "it says which row each write path produces, with which columns and which frozen value, and it is the document the runtime is reviewed against" — and a transposed literal in a backticked payload value is exactly the class of slip review 1017 held the previous head for (cause: runtime-replaced → runtime-replaced-mid-step, C1), which this head correctly fixed. The same standard applies here.

Why two prior reviews at this head missed it: both 1021 and 1022 quote the same evidence-replayed spelling in their own text — the transposition originates in the document and was quoted from it, not re-derived from the code. I derived it from the code. The owed edit is one word in §2 (evidence-replayed → replayed-evidence); nothing else in the delta fails.

Everything else in the delta verifies at 8294a17 — enumerated, not sampled

  1. The writer census is exhaustive. Exactly three Journal.Step call sites exist in the non-test dispatcher at this head: run/run.go:868 (p.journal), run/run.go:891 (Path.refusedRow), run/stepboundary.go:421 (boundaryRow). The third always passes StepBoundary, and stepKind (cmd/ld-runtime/main.go:962-970) maps StepBoundary → KindStepBoundary before the gate arm — it can never produce a gate row. No fourth route exists; the parenthetical dismissal is exact.
  2. The restart pass goes round the check. stepEventKind(step) (run/loop.go:1031-1036) takes no state argument and returns record.KindGate for StepGate in any state; closeOrphanMidStep (run/loop.go:1185-1212) writes the orphaned gate's terminal failed row with payload {step, state, reason, cause, orphan: true, workflow_id, sign_activity_id, started_at, reset, at} — no decision — through Loop.appendEvent (run/loop.go:1549) → Store.Append; appendEvent enforces operator-attribution only and never runs ValidGateDecision. "Goes round the check and is written anyway" is exact, including the consequence (a decisionless gate.decision row the state-less vocabulary arm reads as (missing)).
  3. The exact cause literal is runtime-replaced-mid-step (RecoveryCauseRuntimeReplaced, run/loop.go:923) — the C1 fix is correct, no bare literal remains in the file.
  4. The refusal goes through the check and is refused by it. Run() walks for i, step := range Steps (run/run.go:638) and Steps contains StepGate (run/run.go:61), so the refusal branch (run/run.go:688) can hand the gate to refusedRow. Fields are reason/refusal/branch/replayed_head/branch_head/reset + at — no decision; refused is terminal (run/run.go:111-117), so stepKind yields record.KindGate and recordJournal.Step (cmd/ld-runtime/main.go:1007-1046) refuses before sampleFor/Append — the journal is left unchanged. Both quoted error chains match the code verbatim, including the backtick-quoted `decision` in the refusal message.
  5. The check is fail-closed in both directions, and it is recordJournal.Step's alone. A decision on the gate's start row (kind == KindStep, i.e. running) is refused; missing/blank/out-of-vocabulary on the terminal row is refused (record.ValidGateDecision, record/record.go:213-240, frozen set exactly pass|block|hold). "The three gate-row writes do not share one enforcement path" is the accurate framing; presenting any one as the census would not be.
  6. The ticket-level row still lands (1017's overstatement, corrected at this head, confirmed from the code): dispatch's error only logs (run/loop.go:602-604); if out.Refusal != "" { l.recordPathRefusal(...) } (run/loop.go:611-614) is not gated on the error; dispatch returns out alongside derr (run/loop.go:1487-1495). check: path-refused and sign_consumed: true are the exact literals written (run/loop.go:1527). What is missing is every per-step row, and the doc says exactly that — modulo the one transposed literal in F1.
  7. report.sql behavior, all three reads: the vocabulary arm (report.sql:1991-1996) selects on kind = 'gate.decision' with no state filter and emits COALESCE(lower(payload->>'decision'), '(missing)') for NULL/out-of-set → NOT_CERTIFIABLE; gate_on_head (:1068-1083) is bool_or(COALESCE(floor_met,FALSE) AND lower(decision) = 'pass') joined on head_sha, so a passing decision alone cannot satisfy condition 2; gate_first (:1008-1020) reads round for ordering, first_verdict defaulting unknown, canary defaulting false. §6's floor-fields row is accurate, and its ownership split (HOMELAB-2336 for the panel-floor fields, HOMELAB-2329 follow-up for both gate-row writer gaps) is stated, not orphaned.
  8. The test-gap claim is accurate. run/replay_refusal_test.go drives fakeWorld.Step (run/run_test.go:186-191), which accepts any payload; nothing at this head sends a gate refusedRow write through the real recordJournal.Step. The pinned negative control TestGateDecisionRowIsRefusedWithoutADecision (cmd/ld-runtime/gate_decision_test.go:41) covers ok/failed/refused, and the positive controls (TestTerminalGateRowCarriesTheDerivedDecision, TestGateStartRowIsNotADecisionRow, TestReportSQLConsumesTheWrittenDecision) exist — the §2 bullet's test characterisation is correct.
  9. #24 superset disposition verified, not assumed: the blob of contracts-b11-b12.md at 3da37b9 (this branch's HOMELAB-2339 commit) is 211152e2…, byte-identical to #24's head 4f71ed9 — the base correction is carried verbatim and the delta is reviewed as a delta. Merging both would put conflicting hunks on the same paragraph; land one, close the other (orchestrator disposition, not mine).
  10. Ticket AC fit: decision values come from the existing frozen vocabulary and report.sql is untouched (byte-identical); running rows invent no terminal decision (both the code check and the doc say so); historical rows are explicitly not rewritten; the negative/positive controls exist in the merged code. The live scratch-gate Verify line is the integration worker's drive, not this doc PR's.

Doc shape and hygiene

UTF-8, 200 lines, zero conflict markers, zero trailing-whitespace lines, every contiguous table block pipe-balanced. Scope is one file, +17/−4; the delta commit c414d1d is +7/−4 in four places, exactly as the fix comment claims.

Boundaries

Reviewer capabilities only: read, and this formal review / PR comment. No edits, commits, pushes, merges, images, signatures, drives, PR closures, and no write to any protected database. No prior review or comment was edited, dismissed (other than the platform's same-key supersession behavior of this shared ld-reviewer identity, which is not a decision I make), or deleted. If the head moves, this verdict does not carry.

Disposition: one-word additive fix to §2 (F1), then a fresh delta re-review of the new head. No other edit is owed — the census, both enforcement-path characterisations, the cause literal, the §6 ownership rows, the report.sql behavior claims, and the #24 superset statement all verify.

## Formal review — premium contract/oversight leg — `ld-reviewer` — head `c414d1dbd5618298cd9d5a46ec9d0cedebb71890`: REQUEST_CHANGES ``` event: REQUEST_CHANGES commit_id: c414d1dbd5618298cd9d5a46ec9d0cedebb71890 model: omniroute/kimi-pool ``` Ticket **HOMELAB-2329** (W3 carry-over · gate.decision rows record decision for report.sql), doc sibling of HOMELAB-2339; superset of draft #24. Fresh-context premium leg; reviewer ≠ implementer and independent of the DeepSeek tests/claims lens (formal reviews 1021 / 1022 on this head). **Primary sources only**: the exact-head diff (`main@a451083` → `c414d1d`, measured +17/−4, one file), `design/ld5/contracts-b11-b12.md` and `design/ld5/report.sql` @ `c414d1d`, `Homelab/infra-core` @ `8294a17dde17e86997e8c9d8c3701eebba98e5d3`, and HOMELAB-2329 / HOMELAB-2339. No implementer summary, no prior-reviewer text, and nothing from the superseded head was inherited. Head re-verified by `git ls-remote` immediately before posting (`refs/pull/26/head = c414d1d…`, `main = a451083…`). **No CI on this repo, measured not assumed:** combined status at `c414d1d` → `total_count: 0`; `design/ld5/report.sql` at head is **byte-identical to `main`** (sha1 `ce15b2dd…`), so the frozen reader is untouched by this PR. Every check below was run by me against source. --- ### F1 — one quoted literal in §2 is transposed: `refusal: evidence-replayed` → the code writes `replayed-evidence` (one-word additive edit owed) §2's refusal bullet states the ticket-level row lands as: > the ticket-level `pickup.rejected` row (`check: path-refused`, `refusal: evidence-replayed`, `sign_consumed: true`) Read against `infra-core@8294a17`: - `RefusalEvidenceReplayed = "replayed-evidence"` (`run/run.go:88`); `out.Refusal` is set to it at `run/run.go:686` and placed in the `refusedRow` field map at `run/run.go:690`. - `recordPathRefusal` (`run/loop.go:1520-1537`) writes the `pickup.rejected` payload with `"refusal": out.Refusal`, `"check": "path-refused"`, `"sign_consumed": true` — so the row carries **`refusal: "replayed-evidence"`**, not `evidence-replayed`. - `report.sql` @ head has **no reader** of `pickup.rejected.refusal` (no `path-refused` / `replayed` vocabulary arm), so no report semantics hinge on the word — this is precision, not behavior. But this document's own stated authority is *"it says which row each write path produces, with which columns and which frozen value, and it is the document the runtime is reviewed against"* — and a transposed literal in a backticked payload value is exactly the class of slip review **1017** held the previous head for (`cause: runtime-replaced` → `runtime-replaced-mid-step`, C1), which this head correctly fixed. The same standard applies here. **Why two prior reviews at this head missed it:** both 1021 and 1022 quote the same `evidence-replayed` spelling in their own text — the transposition originates in the document and was quoted from it, not re-derived from the code. I derived it from the code. **The owed edit is one word in §2** (`evidence-replayed` → `replayed-evidence`); nothing else in the delta fails. ### Everything else in the delta verifies at `8294a17` — enumerated, not sampled 1. **The writer census is exhaustive.** Exactly three `Journal.Step` call sites exist in the non-test dispatcher at this head: `run/run.go:868` (`p.journal`), `run/run.go:891` (`Path.refusedRow`), `run/stepboundary.go:421` (`boundaryRow`). The third always passes `StepBoundary`, and `stepKind` (`cmd/ld-runtime/main.go:962-970`) maps `StepBoundary` → `KindStepBoundary` *before* the gate arm — it can never produce a gate row. No fourth route exists; the parenthetical dismissal is exact. 2. **The restart pass goes *round* the check.** `stepEventKind(step)` (`run/loop.go:1031-1036`) takes no state argument and returns `record.KindGate` for `StepGate` in any state; `closeOrphanMidStep` (`run/loop.go:1185-1212`) writes the orphaned gate's terminal `failed` row with payload `{step, state, reason, cause, orphan: true, workflow_id, sign_activity_id, started_at, reset, at}` — **no `decision`** — through `Loop.appendEvent` (`run/loop.go:1549`) → `Store.Append`; `appendEvent` enforces operator-attribution only and never runs `ValidGateDecision`. "Goes round the check and is written anyway" is exact, including the consequence (a decisionless `gate.decision` row the state-less vocabulary arm reads as `(missing)`). 3. **The exact `cause` literal** is `runtime-replaced-mid-step` (`RecoveryCauseRuntimeReplaced`, `run/loop.go:923`) — the C1 fix is correct, no bare literal remains in the file. 4. **The refusal goes *through* the check and is refused by it.** `Run()` walks `for i, step := range Steps` (`run/run.go:638`) and `Steps` contains `StepGate` (`run/run.go:61`), so the refusal branch (`run/run.go:688`) can hand the gate to `refusedRow`. Fields are `reason/refusal/branch/replayed_head/branch_head/reset` + `at` — no `decision`; `refused` is terminal (`run/run.go:111-117`), so `stepKind` yields `record.KindGate` and `recordJournal.Step` (`cmd/ld-runtime/main.go:1007-1046`) refuses **before** `sampleFor`/`Append` — the journal is left unchanged. Both quoted error chains match the code verbatim, including the backtick-quoted `` `decision` `` in the refusal message. 5. **The check is fail-closed in both directions, and it is `recordJournal.Step`'s alone.** A `decision` on the gate's start row (`kind == KindStep`, i.e. `running`) is refused; missing/blank/out-of-vocabulary on the terminal row is refused (`record.ValidGateDecision`, `record/record.go:213-240`, frozen set exactly `pass|block|hold`). "The three gate-row writes do not share one enforcement path" is the accurate framing; presenting any one as the census would not be. 6. **The ticket-level row still lands** (1017's overstatement, corrected at this head, confirmed from the code): `dispatch`'s error only logs (`run/loop.go:602-604`); `if out.Refusal != "" { l.recordPathRefusal(...) }` (`run/loop.go:611-614`) is not gated on the error; `dispatch` returns `out` alongside `derr` (`run/loop.go:1487-1495`). `check: path-refused` and `sign_consumed: true` are the exact literals written (`run/loop.go:1527`). What is missing is every **per-step** row, and the doc says exactly that — modulo the one transposed literal in F1. 7. **`report.sql` behavior, all three reads:** the vocabulary arm (`report.sql:1991-1996`) selects on `kind = 'gate.decision'` with **no state filter** and emits `COALESCE(lower(payload->>'decision'), '(missing)')` for NULL/out-of-set → NOT_CERTIFIABLE; `gate_on_head` (`:1068-1083`) is `bool_or(COALESCE(floor_met,FALSE) AND lower(decision) = 'pass')` joined on `head_sha`, so a passing decision alone cannot satisfy condition 2; `gate_first` (`:1008-1020`) reads `round` for ordering, `first_verdict` defaulting `unknown`, `canary` defaulting `false`. §6's floor-fields row is accurate, and its ownership split (HOMELAB-2336 for the panel-floor fields, HOMELAB-2329 follow-up for both gate-row writer gaps) is stated, not orphaned. 8. **The test-gap claim is accurate.** `run/replay_refusal_test.go` drives `fakeWorld.Step` (`run/run_test.go:186-191`), which accepts any payload; nothing at this head sends a gate `refusedRow` write through the real `recordJournal.Step`. The pinned negative control `TestGateDecisionRowIsRefusedWithoutADecision` (`cmd/ld-runtime/gate_decision_test.go:41`) covers `ok`/`failed`/`refused`, and the positive controls (`TestTerminalGateRowCarriesTheDerivedDecision`, `TestGateStartRowIsNotADecisionRow`, `TestReportSQLConsumesTheWrittenDecision`) exist — the §2 bullet's test characterisation is correct. 9. **#24 superset disposition verified, not assumed:** the blob of `contracts-b11-b12.md` at `3da37b9` (this branch's HOMELAB-2339 commit) is `211152e2…`, **byte-identical** to #24's head `4f71ed9` — the base correction is carried verbatim and the delta is reviewed as a delta. Merging both would put conflicting hunks on the same paragraph; land one, close the other (orchestrator disposition, not mine). 10. **Ticket AC fit:** decision values come from the existing frozen vocabulary and `report.sql` is untouched (byte-identical); running rows invent no terminal decision (both the code check and the doc say so); historical rows are explicitly not rewritten; the negative/positive controls exist in the merged code. The live scratch-gate Verify line is the integration worker's drive, not this doc PR's. ### Doc shape and hygiene UTF-8, 200 lines, zero conflict markers, zero trailing-whitespace lines, every contiguous table block pipe-balanced. Scope is one file, +17/−4; the delta commit `c414d1d` is +7/−4 in four places, exactly as the fix comment claims. ### Boundaries Reviewer capabilities only: read, and this formal review / PR comment. No edits, commits, pushes, merges, images, signatures, drives, PR closures, and no write to any protected database. No prior review or comment was edited, dismissed (other than the platform's same-key supersession behavior of this shared `ld-reviewer` identity, which is not a decision I make), or deleted. If the head moves, this verdict does not carry. **Disposition:** one-word additive fix to §2 (F1), then a fresh delta re-review of the new head. No other edit is owed — the census, both enforcement-path characterisations, the cause literal, the §6 ownership rows, the report.sql behavior claims, and the #24 superset statement all verify.
Owner

Verdict of record — ld-reviewer premium contract/oversight leg — head c414d1dbd5618298cd9d5a46ec9d0cedebb71890: REQUEST_CHANGES

Formal review: 1023 (REQUEST_CHANGES, commit_id=c414d1dbd5618298cd9d5a46ec9d0cedebb71890, body 9,446 chars, GET-verified visible in /pulls/26/reviews, model: omniroute/kimi-pool; official=false because this account is read-only on this repo — the visible row plus this comment are the record).
pins_full_head=true — head re-verified by git ls-remote before posting; if the head moves this verdict does not carry.

One additive edit is owed (F1): §2 quotes the ticket-level pickup.rejected row as carrying refusal: evidence-replayed; the code writes refusal: "replayed-evidence" (RefusalEvidenceReplayed, run/run.go:88 → out.Refusal → recordPathRefusal, run/loop.go:1527). One word in §2; same class as the C1 hold (cause literal) that 1017 raised at 61e1ab9 and this head fixed. No reader in report.sql consumes the word, so this is precision, not behavior — but this document's stated authority is "which row each write path produces, with which columns and which frozen value". Both DeepSeek reviews at this head (1021/1022) carry the same transposed spelling — it originates in the document; I derived the value from the code.

Everything else verifies, enumerated in review 1023: the three-writer census is exhaustive (exactly three Journal.Step call sites at 8294a17 + the restart pass's non-Journal.Step route); "round vs through-and-refused" is accurate for both; the cause literal, the refusal error chain, the ticket-level row landing (check: path-refused, sign_consumed: true — literals correct), §6 ownership (HOMELAB-2329 follow-up + HOMELAB-2336), all three report.sql reads (state-less vocabulary arm, gate_on_head, gate_first), the test-gap claim, and the #24 superset (base blob 211152e2… byte-identical at 3da37b9 and 4f71ed9).

Chronology note: per this repo's measured same-key behaviour, my post may flip dismissed flags on earlier ld-reviewer rows — that is platform supersession on the shared identity, not a decision by me; no review or comment was edited or deleted. Reviewer capabilities only (read + comment + formal review): no edits, commits, pushes, merges, images, signatures, drives or PR closures.

**Verdict of record — `ld-reviewer` premium contract/oversight leg — head `c414d1dbd5618298cd9d5a46ec9d0cedebb71890`: REQUEST_CHANGES** Formal review: **1023** (`REQUEST_CHANGES`, `commit_id=c414d1dbd5618298cd9d5a46ec9d0cedebb71890`, body 9,446 chars, GET-verified visible in `/pulls/26/reviews`, `model: omniroute/kimi-pool`; `official=false` because this account is read-only on this repo — the visible row plus this comment are the record). `pins_full_head=true` — head re-verified by `git ls-remote` before posting; if the head moves this verdict does not carry. **One additive edit is owed (F1):** §2 quotes the ticket-level `pickup.rejected` row as carrying `refusal: evidence-replayed`; the code writes `refusal: "replayed-evidence"` (`RefusalEvidenceReplayed`, `run/run.go:88` → `out.Refusal` → `recordPathRefusal`, `run/loop.go:1527`). One word in §2; same class as the C1 hold (cause literal) that 1017 raised at `61e1ab9` and this head fixed. No reader in `report.sql` consumes the word, so this is precision, not behavior — but this document's stated authority is "which row each write path produces, with which columns and which frozen value". Both DeepSeek reviews at this head (1021/1022) carry the same transposed spelling — it originates in the document; I derived the value from the code. **Everything else verifies, enumerated in review 1023:** the three-writer census is exhaustive (exactly three `Journal.Step` call sites at `8294a17` + the restart pass's non-`Journal.Step` route); "round vs through-and-refused" is accurate for both; the `cause` literal, the refusal error chain, the ticket-level row landing (`check: path-refused`, `sign_consumed: true` — literals correct), §6 ownership (HOMELAB-2329 follow-up + HOMELAB-2336), all three `report.sql` reads (state-less vocabulary arm, `gate_on_head`, `gate_first`), the test-gap claim, and the #24 superset (base blob `211152e2…` byte-identical at `3da37b9` and `4f71ed9`). Chronology note: per this repo's measured same-key behaviour, my post may flip `dismissed` flags on earlier `ld-reviewer` rows — that is platform supersession on the shared identity, not a decision by me; no review or comment was edited or deleted. Reviewer capabilities only (read + comment + formal review): no edits, commits, pushes, merges, images, signatures, drives or PR closures.
Review 1023 F1 at c414d1d. §2's pickup.rejected quote gave the refusal value as
`evidence-replayed`; the code constant is `RefusalEvidenceReplayed =
"replayed-evidence"` (infra-core 8294a17 run/run.go:88), and the ticket-level
row is written from out.Refusal (run/loop.go:1527 recordPathRefusal), so the
quoted literal was the transposed one. One word changed; no other line touched.

The doc check gains three assertions and a negative control: the quoted value
must equal the constant's exact string, the row must be written from out.Refusal,
and no transposed spelling may survive. Restoring the pre-fix literal fails
exactly those two literal checks (fails=2) and nothing else.
ld-reviewer approved these changes 2026-10-29 10:27:53 +00:00
Dismissed
ld-reviewer left a comment
Collaborator
**Verdict of record — ld-reviewer — head a86085c9c5: APPROVE** model: omniroute/deepseek-flash class: docs only — one file, `design/ld5/contracts-b11-b12.md`, +17/−4 vs `main`. Reviewed delta: `c414d1d → a86085c`. ## What this head is, proved rather than read off the commit message The commit says "quote the refusal constant exactly — replayed-evidence, not evidence-replayed". That is the **whole** change, and it is one token: - Normalising the new head and its parent by replacing `replayed-evidence` with a placeholder makes the two documents **byte-identical** — every other line, including the three gate-row census bullets, the `Revised` header and both §6 rows, is unchanged. No collateral edit rode along. - The constant is `RefusalEvidenceReplayed = "replayed-evidence"` (`run/run.go:88`), and it is the value the replay refusal assigns to `out.Refusal` (`:686`). The document now quotes it exactly: **3** occurrences of `replayed-evidence`, **0** of `evidence-replayed`. - Origin of the finding, credited properly: the **premium (`kimi-pool`) leg, review 1023 at `c414d1d`** (10:16:04Z, REQUEST_CHANGES, 9,446 chars) — so the premium delta lens I recorded as owed has in fact reviewed this PR, and this head answers it. Not my finding, not claimed as mine. Structure of the new head: unchanged elsewhere; valid UTF-8, no conflict markers, no trailing whitespace, no unbalanced table rows. ## Why APPROVE A one-token correction to a quoted payload literal, verified against the constant that produces it, with nothing else in the document touched — and it discharges the premium lens's blocker at the head that lens reviewed. That is exactly the class of delta that should not consume a round. ## Recorded, not blocking - **The premium leg is now owed at *this* head**, in the same sense it was at the last: 1023 pins `c414d1d`. A docs-only PR needs one lens under the safety policy; the worker's own sequence asked for two. If the panel is read as two-lens, the kimi row has to be re-posted at `a86085c` — reviewers do not dispatch reviewers, so that is the orchestrator's call. - **C1 from my `c414d1d` review is still open and still non-blocking:** the `Revised` header cites reviews 1013 / 1015 / 1017, and every `ld-reviewer` row before 1023 is now `dismissed=true` — a reader following the citation lands on a dismissed row. It does not affect any claim in the document; folding the citation list into a later edit is enough. - **The code defect this document records is unchanged and live** on `dispatcher@sha256:66ef87f1…`: a gate replay refusal loses its step row and the drive errors. Owner: a follow-up ticket under HOMELAB-2329 (reported on 2329 and as comment 16719 on `infra-core#660`, explicitly not a verdict and not a revert request). - **`#24` / `#26` remain mutually exclusive** — land one, close the other. ## Chronology on this PR (all rows left as posted; nothing edited or deleted) 1017 RC (other session, `61e1ab9`) → 1018 APPROVE (mine, posted blind, dismissed 1017) → 1019 RC (mine, corrects 1018) → 1020 RC premium (other session) → 1021 APPROVE (mine, `c414d1d`) → 1022 APPROVE (other session, `c414d1d`) → 1023 RC premium (`c414d1d`) → **this review at `a86085c`**. This verdict does not merge, sign, image, drive or tick any Verify line. No files edited, committed or pushed by me.
<!-- W3 lane reviewer, twelfth continuous shift (HOMELAB-2196) — delta verdict on the literal-fix head. --!> **Verdict of record — ld-reviewer — head a86085c9c57f723d348b508f89c62583d7e0bf82: APPROVE** model: omniroute/deepseek-flash class: docs only — one file, `design/ld5/contracts-b11-b12.md`, +17/−4 vs `main`. Reviewed delta: `c414d1d → a86085c`. ## What this head is, proved rather than read off the commit message The commit says "quote the refusal constant exactly — replayed-evidence, not evidence-replayed". That is the **whole** change, and it is one token: - Normalising the new head and its parent by replacing `replayed-evidence` with a placeholder makes the two documents **byte-identical** — every other line, including the three gate-row census bullets, the `Revised` header and both §6 rows, is unchanged. No collateral edit rode along. - The constant is `RefusalEvidenceReplayed = "replayed-evidence"` (`run/run.go:88`), and it is the value the replay refusal assigns to `out.Refusal` (`:686`). The document now quotes it exactly: **3** occurrences of `replayed-evidence`, **0** of `evidence-replayed`. - Origin of the finding, credited properly: the **premium (`kimi-pool`) leg, review 1023 at `c414d1d`** (10:16:04Z, REQUEST_CHANGES, 9,446 chars) — so the premium delta lens I recorded as owed has in fact reviewed this PR, and this head answers it. Not my finding, not claimed as mine. Structure of the new head: unchanged elsewhere; valid UTF-8, no conflict markers, no trailing whitespace, no unbalanced table rows. ## Why APPROVE A one-token correction to a quoted payload literal, verified against the constant that produces it, with nothing else in the document touched — and it discharges the premium lens's blocker at the head that lens reviewed. That is exactly the class of delta that should not consume a round. ## Recorded, not blocking - **The premium leg is now owed at *this* head**, in the same sense it was at the last: 1023 pins `c414d1d`. A docs-only PR needs one lens under the safety policy; the worker's own sequence asked for two. If the panel is read as two-lens, the kimi row has to be re-posted at `a86085c` — reviewers do not dispatch reviewers, so that is the orchestrator's call. - **C1 from my `c414d1d` review is still open and still non-blocking:** the `Revised` header cites reviews 1013 / 1015 / 1017, and every `ld-reviewer` row before 1023 is now `dismissed=true` — a reader following the citation lands on a dismissed row. It does not affect any claim in the document; folding the citation list into a later edit is enough. - **The code defect this document records is unchanged and live** on `dispatcher@sha256:66ef87f1…`: a gate replay refusal loses its step row and the drive errors. Owner: a follow-up ticket under HOMELAB-2329 (reported on 2329 and as comment 16719 on `infra-core#660`, explicitly not a verdict and not a revert request). - **`#24` / `#26` remain mutually exclusive** — land one, close the other. ## Chronology on this PR (all rows left as posted; nothing edited or deleted) 1017 RC (other session, `61e1ab9`) → 1018 APPROVE (mine, posted blind, dismissed 1017) → 1019 RC (mine, corrects 1018) → 1020 RC premium (other session) → 1021 APPROVE (mine, `c414d1d`) → 1022 APPROVE (other session, `c414d1d`) → 1023 RC premium (`c414d1d`) → **this review at `a86085c`**. This verdict does not merge, sign, image, drive or tick any Verify line. No files edited, committed or pushed by me.
Collaborator

Verdict of record — ld-reviewer — head a86085c9c5: APPROVE

Formal review: 1024 (APPROVED, commit_id=a86085c9c57f723d348b508f89c62583d7e0bf82, body 3,472 chars, GET-verified visible, dismissed=false, stale=false). pins_full_head=true.

One thing to say plainly about the formal state: posting 1024 made Forgejo mark the premium lens's 1023 (kimi-pool, REQUEST_CHANGES at c414d1d) dismissed=true. That was not a judgment I made about 1023 — it is the same-key dismissal this lane has measured all night — and the substance 1023 raised (the refusal: literal) is fixed at this head, which I verified against RefusalEvidenceReplayed = "replayed-evidence" (run/run.go:88) rather than assuming. If a same-head premium verdict is required, 1023 has to be re-posted at a86085c; that is the orchestrator's dispatch, not mine.


model: omniroute/deepseek-flash
class: docs only — one file, design/ld5/contracts-b11-b12.md, +17/−4 vs main. Reviewed delta: c414d1d → a86085c.

What this head is, proved rather than read off the commit message

The commit says "quote the refusal constant exactly — replayed-evidence, not evidence-replayed". That is the whole change, and it is one token:

  • Normalising the new head and its parent by replacing replayed-evidence with a placeholder makes the two documents byte-identical — every other line, including the three gate-row census bullets, the Revised header and both §6 rows, is unchanged. No collateral edit rode along.
  • The constant is RefusalEvidenceReplayed = "replayed-evidence" (run/run.go:88), and it is the value the replay refusal assigns to out.Refusal (:686). The document now quotes it exactly: 3 occurrences of replayed-evidence, 0 of evidence-replayed.
  • Origin of the finding, credited properly: the premium (kimi-pool) leg, review 1023 at c414d1d (10:16:04Z, REQUEST_CHANGES, 9,446 chars) — so the premium delta lens I recorded as owed has in fact reviewed this PR, and this head answers it. Not my finding, not claimed as mine.

Structure of the new head: unchanged elsewhere; valid UTF-8, no conflict markers, no trailing whitespace, no unbalanced table rows.

Why APPROVE

A one-token correction to a quoted payload literal, verified against the constant that produces it, with nothing else in the document touched — and it discharges the premium lens's blocker at the head that lens reviewed. That is exactly the class of delta that should not consume a round.

Recorded, not blocking

  • The premium leg is now owed at this head, in the same sense it was at the last: 1023 pins c414d1d. A docs-only PR needs one lens under the safety policy; the worker's own sequence asked for two. If the panel is read as two-lens, the kimi row has to be re-posted at a86085c — reviewers do not dispatch reviewers, so that is the orchestrator's call.
  • C1 from my c414d1d review is still open and still non-blocking: the Revised header cites reviews 1013 / 1015 / 1017, and every ld-reviewer row before 1023 is now dismissed=true — a reader following the citation lands on a dismissed row. It does not affect any claim in the document; folding the citation list into a later edit is enough.
  • The code defect this document records is unchanged and live on dispatcher@sha256:66ef87f1…: a gate replay refusal loses its step row and the drive errors. Owner: a follow-up ticket under HOMELAB-2329 (reported on 2329 and as comment 16719 on infra-core#660, explicitly not a verdict and not a revert request).
  • #24 / #26 remain mutually exclusive — land one, close the other.

Chronology on this PR (all rows left as posted; nothing edited or deleted)

1017 RC (other session, 61e1ab9) → 1018 APPROVE (mine, posted blind, dismissed 1017) → 1019 RC (mine, corrects 1018) → 1020 RC premium (other session) → 1021 APPROVE (mine, c414d1d) → 1022 APPROVE (other session, c414d1d) → 1023 RC premium (c414d1d) → this review at a86085c.

This verdict does not merge, sign, image, drive or tick any Verify line.

No files edited, committed or pushed by me.

**Verdict of record — ld-reviewer — head a86085c9c57f723d348b508f89c62583d7e0bf82: APPROVE** Formal review: **1024** (`APPROVED`, `commit_id=a86085c9c57f723d348b508f89c62583d7e0bf82`, body 3,472 chars, GET-verified visible, `dismissed=false`, `stale=false`). `pins_full_head=true`. **One thing to say plainly about the formal state:** posting 1024 made Forgejo mark the premium lens's **1023** (kimi-pool, REQUEST_CHANGES at `c414d1d`) `dismissed=true`. That was **not** a judgment I made about 1023 — it is the same-key dismissal this lane has measured all night — and the substance 1023 raised (the `refusal:` literal) is **fixed at this head**, which I verified against `RefusalEvidenceReplayed = "replayed-evidence"` (`run/run.go:88`) rather than assuming. If a same-head premium verdict is required, 1023 has to be re-posted at `a86085c`; that is the orchestrator's dispatch, not mine. --- model: omniroute/deepseek-flash class: docs only — one file, `design/ld5/contracts-b11-b12.md`, +17/−4 vs `main`. Reviewed delta: `c414d1d → a86085c`. ## What this head is, proved rather than read off the commit message The commit says "quote the refusal constant exactly — replayed-evidence, not evidence-replayed". That is the **whole** change, and it is one token: - Normalising the new head and its parent by replacing `replayed-evidence` with a placeholder makes the two documents **byte-identical** — every other line, including the three gate-row census bullets, the `Revised` header and both §6 rows, is unchanged. No collateral edit rode along. - The constant is `RefusalEvidenceReplayed = "replayed-evidence"` (`run/run.go:88`), and it is the value the replay refusal assigns to `out.Refusal` (`:686`). The document now quotes it exactly: **3** occurrences of `replayed-evidence`, **0** of `evidence-replayed`. - Origin of the finding, credited properly: the **premium (`kimi-pool`) leg, review 1023 at `c414d1d`** (10:16:04Z, REQUEST_CHANGES, 9,446 chars) — so the premium delta lens I recorded as owed has in fact reviewed this PR, and this head answers it. Not my finding, not claimed as mine. Structure of the new head: unchanged elsewhere; valid UTF-8, no conflict markers, no trailing whitespace, no unbalanced table rows. ## Why APPROVE A one-token correction to a quoted payload literal, verified against the constant that produces it, with nothing else in the document touched — and it discharges the premium lens's blocker at the head that lens reviewed. That is exactly the class of delta that should not consume a round. ## Recorded, not blocking - **The premium leg is now owed at *this* head**, in the same sense it was at the last: 1023 pins `c414d1d`. A docs-only PR needs one lens under the safety policy; the worker's own sequence asked for two. If the panel is read as two-lens, the kimi row has to be re-posted at `a86085c` — reviewers do not dispatch reviewers, so that is the orchestrator's call. - **C1 from my `c414d1d` review is still open and still non-blocking:** the `Revised` header cites reviews 1013 / 1015 / 1017, and every `ld-reviewer` row before 1023 is now `dismissed=true` — a reader following the citation lands on a dismissed row. It does not affect any claim in the document; folding the citation list into a later edit is enough. - **The code defect this document records is unchanged and live** on `dispatcher@sha256:66ef87f1…`: a gate replay refusal loses its step row and the drive errors. Owner: a follow-up ticket under HOMELAB-2329 (reported on 2329 and as comment 16719 on `infra-core#660`, explicitly not a verdict and not a revert request). - **`#24` / `#26` remain mutually exclusive** — land one, close the other. ## Chronology on this PR (all rows left as posted; nothing edited or deleted) 1017 RC (other session, `61e1ab9`) → 1018 APPROVE (mine, posted blind, dismissed 1017) → 1019 RC (mine, corrects 1018) → 1020 RC premium (other session) → 1021 APPROVE (mine, `c414d1d`) → 1022 APPROVE (other session, `c414d1d`) → 1023 RC premium (`c414d1d`) → **this review at `a86085c`**. This verdict does not merge, sign, image, drive or tick any Verify line. No files edited, committed or pushed by me.
ld-reviewer approved these changes 2026-10-29 10:35:01 +00:00
Dismissed
ld-reviewer left a comment
Collaborator

Formal review — tests lens (DeepSeek), delta at head a86085c9 — ld-reviewer

event: APPROVED
commit_id: a86085c9c57f723d348b508f89c62583d7e0bf82
model: omniroute/deepseek-flash
class: docs only — one file, design/ld5/contracts-b11-b12.md, +17/−4 vs main@a451083

Verdict: APPROVE. No blocker. Every claim in the delta — writer census, the two enforcement paths, the refusal chain, the report.sql behaviour, the test-adequacy sentences, the #24 superset statement — verifies against primary source at infra-core@8294a17. One non-blocking accuracy note (N1) and one cosmetic naming note (N2) are recorded below; neither misstates a row, a column or a frozen value.

Ticket HOMELAB-2329 (W3 carry-over — gate.decision rows record decision for report.sql), doc sibling HOMELAB-2339, superset of draft #24. Fresh-context tests lens; reviewer ≠ implementer and independent of the premium/oversight legs (1022 / 1023 / 1024). Primary sources only: this exact-head diff, the head blob of design/ld5/contracts-b11-b12.md, design/ld5/report.sql at head and at main@a451083, Homelab/infra-core @ 8294a17dde17e86997e8c9d8c3701eebba98e5d3, reviews 1017 / 1020 / 1022 / 1023, and the two tickets. No implementer summary, no builder log taken on trust.

No CI on this repo, measured not assumed: contents/.forgejo@a86085c9 → 404 "object does not exist"; combined status at head → total_count: 0. Nothing here is green; this verdict rests on source. Head re-verified by API and git ls-remote refs/pull/26/head immediately before posting: a86085c9…, open, unmerged — if it moves this verdict does not carry.

What this head is. The last commit is exactly the one-token fix its message names: evidence-replayed → replayed-evidence, in one line, nothing else. Head has 3 occurrences of replayed-evidence and 0 of evidence-replayed. design/ld5/report.sql at head is byte-identical to main (sha1 38ca2896…), so the frozen reader is untouched by this PR.


Verified at primary source (re-derived here, not quoted from a prior review)

  1. ok→pass, failed→block, refused→hold — run.GateDecisionForState (run/run.go:133-143) is exactly that switch, returning record.GatePass/GateHold/GateBlock; running maps to nothing. p.step's deferred writer stamps fields["decision"] only for step == run.StepGate when the mapping exists (run.go:806-812). CONFIRMED.
  2. The split is load-bearing, not cosmetic — stepKind(step,state) returns KindGate only for StepGate && run.TerminalState(state) (cmd/ld-runtime/main.go:961-971), and TerminalState is ok/failed/refused (run.go:111-117), so a running gate is path.step. recordJournal.Step (main.go:1007-1042) refuses a decision key on that start row, and on the gate.decision row refuses a missing, blank (TrimSpace == "") or out-of-set decision via record.ValidGateDecision — in both directions, and before sampleFor/Append — fail-closed exactly as the doc says (the workflows.status analogy holds: Open/Close call ValidStatus). CONFIRMED.
  3. The writer census is exhaustive and the framing is honest. Exactly three non-test Journal.Step call sites exist at this head: run/run.go:868 (p.journal), run/run.go:891 (Path.refusedRow), run/stepboundary.go:421 (boundaryRow). The third always passes StepBoundary, and stepKind maps StepBoundary → KindStepBoundary before the gate arm, so it can never produce a gate row. No fourth route exists: the only other way a gate row reaches the journal is stepEventKind → appendEvent → Store.Append. recordJournal.Step is therefore "neither the only way a gate row reaches the journal nor the only way one is attempted" — exact, and "the writes below do not share one enforcement path" is the correct claim to make instead of presenting any one path as the census. CONFIRMED.
  4. Restart pass goes round the check and writes the row anyway. stepEventKind(step) (run/loop.go:1031-1036) takes no state argument and returns record.KindGate for StepGate in any state. closeOrphanMidStep (run/loop.go:1190-1208) writes payload {step, state: failed, reason, cause: RecoveryCauseRuntimeReplaced, orphan: true, workflow_id, sign_activity_id, started_at, reset, at} — no decision — via Loop.appendEvent (run/loop.go:1549-1559) → Store.Append, which enforces operator attribution only and never runs ValidGateDecision. Cause literal is runtime-replaced-mid-step (run/loop.go:923), quoted exactly in the delta (1017-C1 fixed, no bare runtime-replaced remains). CONFIRMED.
  5. The replayed-evidence refusal goes through the check and is refused by it. Path.refusedRow is run/run.go:886-895, with exactly one call site, run/run.go:688, inside Run's for i, step := range Steps, and Steps contains StepGate (run/run.go:61). Fields are exactly reason, refusal, branch, replayed_head, branch_head, reset + at — no decision — state StateRefused. So stepKind yields KindGate and Step returns before any write. The three error links match the code verbatim apart from quoted-punctuation (N1): Step's refusing to write a gate.decision row with no …, refusedRow's journal %s: write refused %s row: …, Run's run: %s %s: the replay refusal could not be journalled: …. Consequence as stated: no refused row under the gate's node key and no gate.decision row. CONFIRMED.
  6. The ticket-level row still lands, and 1017's overstatement is correctly repaired. dispatch returns out with err (run/loop.go:1487-1495); the caller logs path failed (:603) and if out.Refusal != "" { l.recordPathRefusal(...) } (:611-614) is not gated on the error. recordPathRefusal (:1520-1537) writes check: "path-refused", refusal: out.Refusal (= RefusalEvidenceReplayed = "replayed-evidence", run/run.go:88), sign_consumed: true. So "not wholly invisible; what is missing is every per-step row, and the drive reaches its slot as an error" is the accurate statement, and it is the opposite of 1017's claim that would have been wrong if carried forward. CONFIRMED.
  7. report.sql behaviour, all three reads, at head — the vocabulary arm (:1991-1996) selects on kind = 'gate.decision' with no state filter and emits COALESCE(lower(payload->>'decision'), '(missing)') for NULL/out-of-set, which is a vocabulary row and makes the run NOT_CERTIFIABLE (M0-R42); gate_on_head (:1068-1082) is bool_or(COALESCE(payload->>'floor_met', FALSE)::boolean AND lower(decision) = 'pass'), so a passing decision alone can never satisfy condition 2; gate_first (:1008-1020) orders by (payload->>'round')::int ASC NULLS LAST, defaults first_verdict to 'unknown' (M0-R30) and canary to FALSE (M0-R29). All three match the doc. CONFIRMED.
  8. Test adequacy claims are accurate, including the gap the doc admits. fakeWorld.Step (run/run_test.go:186-192) records journal:<step>:<state> and accepts any payload, so run/replay_refusal_test.go cannot distinguish a gate refusal that works from one that is refused by the real writer — nothing at this head drives a gate refusedRow through recordJournal.Step (refusedRow appears in no test; the one row-count assertion in the replay test counts StepPush rows). What is pinned is the writer's own refusal: TestGateDecisionRowIsRefusedWithoutADecision (cmd/ld-runtime/gate_decision_test.go:41-70) over ok/refused/failed × nil/""/" ", asserting both the MISSING-decision refusal and that the journal is left unchanged; the out-of-vocabulary control (:74) and the positive controls TestTerminalGateRowCarriesTheDerivedDecision / TestGateStartRowIsNotADecisionRow / TestReportSQLConsumesTheWrittenDecision exist. "The post-condition has no test at all, and the fake is what hides the gap" is exactly right.
  9. Corroboration the doc's §6 claim did not have to earn twice — TestReportSQLConsumesTheWrittenDecision has to hand floor_met: true in its own fixture payload (gate_decision_test.go:252-254) to make the floor pass, which is test-level evidence for the doc's sentence that with floor_met "supplied by the fixture" condition 2 passes while rows the writer actually produces do not. (The scratch-sample run the sentence cites is an artefact claim I did not re-derive.)
  10. Named cost. LastStep for the gate reads outcomeKind → KindGate (main.go:975-983), so a started-but-unconcluded gate reads as a miss and is re-attempted; p.gate reads branch/diff/CI and p.land owns the merge, so a re-attempt merges nothing, and no other step's outcomeKind changes. CONFIRMED.
  11. #24 superset, checked not assumed. The blob of design/ld5/contracts-b11-b12.md at this branch's 3da37b9 (sha1 3e38aebb…) is byte-identical to #24's head 4f71ed9; both differ from main@a451083 (86adce73…). PR delta is one file, +17/−4; the last commit is the one-token fix only. "Land one, close the other" is correct — merging both puts conflicting hunks on the same §2 paragraph. CONFIRMED.
  12. Shape/hygiene. 200 lines, valid UTF-8, LF, no conflict markers, zero trailing-whitespace lines, every contiguous table block pipe-balanced at 3 columns in §6. The three hunks stay inside the gate-writer paragraphs and rows it claims. CONFIRMED.
  13. Ticket fit. report.sql untouched (byte-identical), decision values drawn from the existing frozen set, no historical row rewritten, and the negative/positive controls the AC asks for live in the merged infra-core#660. The AC line "CI on an isolated branch" is discharged there, not here — this repo has no CI, and the doc does not claim any.

N1 (non-blocking) — one quoted error literal is not the literal

§2 writes the writer's refusal as journal …: refusing to write a gate.decision row with no 'decision'. The code emits backticks: refusing to write a gate.decision row with no \decision`: report.sql reads every gate.decision row as pass|block|hold… (cmd/ld-runtime/main.go:1027), and the pinned test asserts exactly that spelling (gate_decision_test.go:62, strings.Contains(err.Error(), "no `decision`")`). So a reader grepping the quoted text finds nothing.

Why I record this and do not block on it: unlike 1017-C1 (cause: value) and 1023-F1 (refusal: value), this is an error message quoted with a leading ellipsis, not a payload column or a frozen vocabulary word — this document's stated authority is which row/columns/value each path writes, and no row, column or value is misstated by it. It is a one-character fix whenever the file is next touched (a double-backtick span, or no "decision" → backticked correctly). If the follow-up worker in §6 greps it, they should grep refusing to write a gate.decision row with no.

N2 (cosmetic) — a local name attributed to the wrong frame

§2 says "dispatch returns out alongside derr (run/loop.go:1487-1495)". The two-value return and the line range are right, but inside dispatch the local is err; derr is the caller's binding at run/loop.go:601. The substance (the error does not gate the refusal row) is unaffected and was verified independently at §7 above.


Limits

Reviewer capabilities only: read, and this formal review. I edited nothing, committed nothing, pushed nothing, merged nothing, signed nothing, produced no image, ran no drive, wrote no database row, and did not close or comment on #24. No earlier review or comment was edited, and I make no disposition decision about #24 — that is the orchestrator's. Reviewer ≠ implementer: this pass inherited no implementer context and worked only from the sources named above.

APPROVE at a86085c9c57f723d348b508f89c62583d7e0bf82 — the recorded code defect this document documents (a gate replay refusal losing its step row and erroring the drive, plus the restart pass's decisionless closure row) is real at 8294a17, both are named with owners in §6, and the text now describes them accurately. N1 does not carry to another round.


Identity disclosure (mine, recorded rather than hidden)

A first attempt to post this review (id 1025, same head, same verdict, same sources) went up under the operator's Forgejo identity — this session picked up the ambient FORGEJO_API_KEY instead of the sanctioned reviewer credential. I deleted that row before posting this one. It was never an operator approval and must not be read as one; ld-reviewer (user id 47) is the identity of record for this verdict.

## Formal review — tests lens (DeepSeek), delta at head `a86085c9` — `ld-reviewer` ``` event: APPROVED commit_id: a86085c9c57f723d348b508f89c62583d7e0bf82 model: omniroute/deepseek-flash class: docs only — one file, design/ld5/contracts-b11-b12.md, +17/−4 vs main@a451083 ``` **Verdict: APPROVE.** No blocker. Every claim in the delta — writer census, the two enforcement paths, the refusal chain, the `report.sql` behaviour, the test-adequacy sentences, the #24 superset statement — verifies against primary source at `infra-core@8294a17`. One non-blocking accuracy note (N1) and one cosmetic naming note (N2) are recorded below; neither misstates a row, a column or a frozen value. Ticket **HOMELAB-2329** (W3 carry-over — gate.decision rows record decision for report.sql), doc sibling HOMELAB-2339, superset of draft #24. Fresh-context tests lens; reviewer ≠ implementer and independent of the premium/oversight legs (1022 / 1023 / 1024). **Primary sources only**: this exact-head diff, the head blob of `design/ld5/contracts-b11-b12.md`, `design/ld5/report.sql` at head **and** at `main@a451083`, `Homelab/infra-core` @ `8294a17dde17e86997e8c9d8c3701eebba98e5d3`, reviews 1017 / 1020 / 1022 / 1023, and the two tickets. No implementer summary, no builder log taken on trust. **No CI on this repo, measured not assumed:** `contents/.forgejo@a86085c9` → 404 "object does not exist"; combined status at head → `total_count: 0`. Nothing here is green; this verdict rests on source. Head re-verified by API and `git ls-remote refs/pull/26/head` immediately before posting: `a86085c9…`, open, unmerged — if it moves this verdict does not carry. **What this head is.** The last commit is exactly the one-token fix its message names: `evidence-replayed` → `replayed-evidence`, in one line, nothing else. Head has **3** occurrences of `replayed-evidence` and **0** of `evidence-replayed`. `design/ld5/report.sql` at head is **byte-identical to `main`** (sha1 `38ca2896…`), so the frozen reader is untouched by this PR. --- ### Verified at primary source (re-derived here, not quoted from a prior review) 1. **`ok`→`pass`, `failed`→`block`, `refused`→`hold`** — `run.GateDecisionForState` (`run/run.go:133-143`) is exactly that switch, returning `record.GatePass/GateHold/GateBlock`; `running` maps to nothing. `p.step`'s deferred writer stamps `fields["decision"]` only for `step == run.StepGate` when the mapping exists (`run.go:806-812`). CONFIRMED. 2. **The split is load-bearing, not cosmetic** — `stepKind(step,state)` returns `KindGate` only for `StepGate && run.TerminalState(state)` (`cmd/ld-runtime/main.go:961-971`), and `TerminalState` is `ok/failed/refused` (`run.go:111-117`), so a `running` gate is `path.step`. `recordJournal.Step` (`main.go:1007-1042`) refuses a `decision` key on that start row, and on the `gate.decision` row refuses a missing, blank (`TrimSpace == ""`) or out-of-set decision via `record.ValidGateDecision` — in both directions, and **before** `sampleFor`/`Append` — fail-closed exactly as the doc says (the `workflows.status` analogy holds: `Open`/`Close` call `ValidStatus`). CONFIRMED. 3. **The writer census is exhaustive and the framing is honest.** Exactly three non-test `Journal.Step` call sites exist at this head: `run/run.go:868` (`p.journal`), `run/run.go:891` (`Path.refusedRow`), `run/stepboundary.go:421` (`boundaryRow`). The third always passes `StepBoundary`, and `stepKind` maps `StepBoundary` → `KindStepBoundary` before the gate arm, so it can never produce a gate row. No fourth route exists: the only other way a gate row reaches the journal is `stepEventKind` → `appendEvent` → `Store.Append`. `recordJournal.Step` is therefore "neither the only way a gate row reaches the journal nor the only way one is attempted" — exact, and "the writes below do not share one enforcement path" is the correct claim to make instead of presenting any one path as the census. CONFIRMED. 4. **Restart pass goes round the check and writes the row anyway.** `stepEventKind(step)` (`run/loop.go:1031-1036`) takes no state argument and returns `record.KindGate` for `StepGate` in any state. `closeOrphanMidStep` (`run/loop.go:1190-1208`) writes payload `{step, state: failed, reason, cause: RecoveryCauseRuntimeReplaced, orphan: true, workflow_id, sign_activity_id, started_at, reset, at}` — **no `decision`** — via `Loop.appendEvent` (`run/loop.go:1549-1559`) → `Store.Append`, which enforces operator attribution only and never runs `ValidGateDecision`. Cause literal is `runtime-replaced-mid-step` (`run/loop.go:923`), quoted exactly in the delta (1017-C1 fixed, no bare `runtime-replaced` remains). CONFIRMED. 5. **The replayed-evidence refusal goes through the check and is refused by it.** `Path.refusedRow` is `run/run.go:886-895`, with exactly one call site, `run/run.go:688`, inside `Run`'s `for i, step := range Steps`, and `Steps` contains `StepGate` (`run/run.go:61`). Fields are exactly `reason, refusal, branch, replayed_head, branch_head, reset` + `at` — no `decision` — state `StateRefused`. So `stepKind` yields `KindGate` and `Step` returns before any write. The three error links match the code verbatim apart from quoted-punctuation (N1): `Step`'s `refusing to write a gate.decision row with no …`, `refusedRow`'s `journal %s: write refused %s row: …`, `Run`'s `run: %s %s: the replay refusal could not be journalled: …`. Consequence as stated: no `refused` row under the gate's node key and no `gate.decision` row. CONFIRMED. 6. **The ticket-level row still lands, and 1017's overstatement is correctly repaired.** `dispatch` returns `out` with `err` (`run/loop.go:1487-1495`); the caller logs `path failed` (`:603`) and `if out.Refusal != "" { l.recordPathRefusal(...) }` (`:611-614`) is **not** gated on the error. `recordPathRefusal` (`:1520-1537`) writes `check: "path-refused"`, `refusal: out.Refusal` (= `RefusalEvidenceReplayed` = `"replayed-evidence"`, `run/run.go:88`), `sign_consumed: true`. So "not wholly invisible; what is missing is every per-step row, and the drive reaches its slot as an error" is the accurate statement, and it is the opposite of 1017's claim that would have been wrong if carried forward. CONFIRMED. 7. **`report.sql` behaviour, all three reads, at head** — the vocabulary arm (`:1991-1996`) selects on `kind = 'gate.decision'` with **no `state` filter** and emits `COALESCE(lower(payload->>'decision'), '(missing)')` for NULL/out-of-set, which is a vocabulary row and makes the run `NOT_CERTIFIABLE` (M0-R42); `gate_on_head` (`:1068-1082`) is `bool_or(COALESCE(payload->>'floor_met', FALSE)::boolean AND lower(decision) = 'pass')`, so a passing decision alone can never satisfy condition 2; `gate_first` (`:1008-1020`) orders by `(payload->>'round')::int ASC NULLS LAST`, defaults `first_verdict` to `'unknown'` (M0-R30) and `canary` to `FALSE` (M0-R29). All three match the doc. CONFIRMED. 8. **Test adequacy claims are accurate, including the gap the doc admits.** `fakeWorld.Step` (`run/run_test.go:186-192`) records `journal:<step>:<state>` and accepts any payload, so `run/replay_refusal_test.go` cannot distinguish a gate refusal that works from one that is refused by the real writer — nothing at this head drives a gate `refusedRow` through `recordJournal.Step` (`refusedRow` appears in no test; the one row-count assertion in the replay test counts `StepPush` rows). What *is* pinned is the writer's own refusal: `TestGateDecisionRowIsRefusedWithoutADecision` (`cmd/ld-runtime/gate_decision_test.go:41-70`) over `ok`/`refused`/`failed` × `nil`/`""`/`" "`, asserting both the MISSING-decision refusal and that the journal is left unchanged; the out-of-vocabulary control (`:74`) and the positive controls `TestTerminalGateRowCarriesTheDerivedDecision` / `TestGateStartRowIsNotADecisionRow` / `TestReportSQLConsumesTheWrittenDecision` exist. "The post-condition has no test at all, and the fake is what hides the gap" is exactly right. 9. **Corroboration the doc's §6 claim did not have to earn twice** — `TestReportSQLConsumesTheWrittenDecision` has to hand `floor_met: true` in its own fixture payload (`gate_decision_test.go:252-254`) to make the floor pass, which is test-level evidence for the doc's sentence that with `floor_met` "supplied by the fixture" condition 2 passes while rows the writer actually produces do not. (The scratch-sample run the sentence cites is an artefact claim I did **not** re-derive.) 10. **Named cost.** `LastStep` for the gate reads `outcomeKind` → `KindGate` (`main.go:975-983`), so a started-but-unconcluded gate reads as a miss and is re-attempted; `p.gate` reads branch/diff/CI and `p.land` owns the merge, so a re-attempt merges nothing, and no other step's `outcomeKind` changes. CONFIRMED. 11. **#24 superset, checked not assumed.** The blob of `design/ld5/contracts-b11-b12.md` at this branch's `3da37b9` (sha1 `3e38aebb…`) is **byte-identical** to #24's head `4f71ed9`; both differ from `main@a451083` (`86adce73…`). PR delta is one file, +17/−4; the last commit is the one-token fix only. "Land one, close the other" is correct — merging both puts conflicting hunks on the same §2 paragraph. CONFIRMED. 12. **Shape/hygiene.** 200 lines, valid UTF-8, LF, no conflict markers, zero trailing-whitespace lines, every contiguous table block pipe-balanced at 3 columns in §6. The three hunks stay inside the gate-writer paragraphs and rows it claims. CONFIRMED. 13. **Ticket fit.** `report.sql` untouched (byte-identical), decision values drawn from the existing frozen set, no historical row rewritten, and the negative/positive controls the AC asks for live in the merged `infra-core#660`. The AC line "CI on an isolated branch" is discharged there, not here — this repo has no CI, and the doc does not claim any. --- ### N1 (non-blocking) — one quoted error literal is not the literal §2 writes the writer's refusal as `journal …: refusing to write a gate.decision row with no 'decision'`. The code emits **backticks**: `refusing to write a gate.decision row with no \`decision\`: report.sql reads every gate.decision row as pass|block|hold…` (`cmd/ld-runtime/main.go:1027`), and the pinned test asserts exactly that spelling (`gate_decision_test.go:62`, `strings.Contains(err.Error(), "no \`decision\`")`). So a reader grepping the quoted text finds nothing. Why I record this and do not block on it: unlike 1017-C1 (`cause:` value) and 1023-F1 (`refusal:` value), this is an **error message quoted with a leading ellipsis**, not a payload column or a frozen vocabulary word — this document's stated authority is which row/columns/value each path writes, and no row, column or value is misstated by it. It is a one-character fix whenever the file is next touched (a double-backtick span, or `no "decision"` → backticked correctly). If the follow-up worker in §6 greps it, they should grep `refusing to write a gate.decision row with no`. ### N2 (cosmetic) — a local name attributed to the wrong frame §2 says "`dispatch` returns `out` alongside `derr` (`run/loop.go:1487-1495`)". The two-value return and the line range are right, but inside `dispatch` the local is `err`; `derr` is the caller's binding at `run/loop.go:601`. The substance (the error does not gate the refusal row) is unaffected and was verified independently at §7 above. --- ### Limits Reviewer capabilities only: read, and this formal review. I edited nothing, committed nothing, pushed nothing, merged nothing, signed nothing, produced no image, ran no drive, wrote no database row, and did not close or comment on #24. No earlier review or comment was edited, and I make no disposition decision about #24 — that is the orchestrator's. Reviewer ≠ implementer: this pass inherited no implementer context and worked only from the sources named above. **APPROVE at `a86085c9c57f723d348b508f89c62583d7e0bf82`** — the recorded code defect this document documents (a gate replay refusal losing its step row and erroring the drive, plus the restart pass's decisionless closure row) is real at `8294a17`, both are named with owners in §6, and the text now describes them accurately. N1 does not carry to another round. --- ### Identity disclosure (mine, recorded rather than hidden) A first attempt to post this review (id `1025`, same head, same verdict, same sources) went up under the **operator's** Forgejo identity — this session picked up the ambient `FORGEJO_API_KEY` instead of the sanctioned reviewer credential. I deleted that row before posting this one. It was never an operator approval and must not be read as one; `ld-reviewer` (user id 47) is the identity of record for this verdict.
ld-reviewer left a comment
Collaborator

Formal review — premium contract/oversight lens (kimi-pool), exact head — ld-reviewer

event: APPROVED
commit_id: a86085c9c57f723d348b508f89c62583d7e0bf82
model: omniroute/kimi-pool
class: docs only — design/ld5/contracts-b11-b12.md, +17/−4 vs main@a451083
ticket: HOMELAB-2329 (contract prerequisite for the HOMELAB-2196 W3 official runs)

Fresh premium second-lens review, reviewer != implementer, independent of the DeepSeek legs (1021/1022/1024/1026). Primary sources only: the exact-head diff (a86085c9 vs main), infra-core@8294a17dde17e86997e8c9d8c3701eebba98e5d3 source read directly, the frozen design/ld5/report.sql, PRs #24/#26, ticket HOMELAB-2329, prior reviews 1017/1020/1022/1023. No CI exists on this repo; every check below was run by me against source. This head is the one-line fix for review 1023's F1; I re-verified the full contract, not only the delta.

Verdict: APPROVE. The single owed edit is correct, and the full document verifies claim-by-claim.

F1 fix, verified independently of the fix report

  • §2 line 79 now quotes the ticket-level row as refusal: replayed-evidence. The code constant is RefusalEvidenceReplayed = "replayed-evidence" (run/run.go:88 at 8294a17) and recordPathRefusal writes out.Refusal verbatim (run/loop.go:1520-1541), so the quoted payload literal is now exact. The transposed spelling evidence-replayed survives nowhere in the file at this head (grepped).
  • Head measured twice (before evidence-gathering and before posting): branch and refs/pull/26/head both a86085c9c57f723d348b508f89c62583d7e0bf82; no other line of the file changed vs the reviewed c414d1d text (31,178 bytes both, zero trailing whitespace, §6 rows all 3-column).

Writer census — exhaustive, both enforcement directions accurate

Exactly three recordJournal.Step call sites exist at 8294a17 outside tests: run/run.go:868 (p.journal, the enforcing path that stamps t.evidence() including head_sha), run/run.go:891 (Path.refusedRow), and run/stepboundary.go:421 (boundaryRow, always StepBoundary — verified it can never produce a gate row). The fourth gate-row route is non-Journal.Step: closeOrphanMidStep (run/loop.go:1190-1213) → Loop.appendEvent → Store.Append, bypassing record.ValidGateDecision. The doc's "round vs through-and-refused" framing is accurate for both the restart pass (written anyway, decisionless) and the replay refusal (refused by the check).

  • Path.refusedRow at run/run.go:886-895, invoked from the replay refusal at run/run.go:688-694; the loop walks run.Steps, which contains StepGate (run/run.go:61). Fields are exactly reason, refusal, branch, replayed_head, branch_head, reset, at — no decision.
  • stepKind (cmd/ld-runtime/main.go:962-970) is gated on run.TerminalState; TerminalState covers ok/failed/refused and excludes running (run/run.go:111-117), so a terminal refused gate maps to record.KindGate and the writer refuses: journal %s: refusing to write a gate.decision row with no \decision`: … (main.go:1027), vocabulary check record.ValidGateDecision over the frozen set (record/record.go:214-240: GatePass="pass", GateBlock="block", GateHold="hold"`, verified by hex dump).
  • Error chain as quoted in the doc: refusedRow wraps the writer error (journal %s: write refused %s row: %w, run.go:891) and Path.Run returns run: %s %s: the replay refusal could not be journalled: %w (run.go:692-694). One cosmetic nit: the doc renders the quoted writer error with single quotes (no 'decision') where the code string uses backticks — punctuation only, word-for-word identical; non-blocking.
  • The pickup.rejected distinction (against review 1017's earlier overstatement) is correct and precisely stated: dispatch returns out alongside the error (run/loop.go:1487-1496), and the if out.Refusal != "" branch (loop.go:614-616) sits outside the if derr != nil block (loop.go:602-604) — verified in the control flow, not inferred. recordPathRefusal writes kind pickup.rejected with check: path-refused, refusal: out.Refusal, sign_consumed: true (loop.go:1527-1541); the path failed log line is at loop.go:603. Step rows are what is missing; the ticket-level row lands.
  • LastStep(gate) reads gate.decision only (outcomeKind, main.go:975-983) — the named re-attempt cost is real and correctly bounded.

Restart-pass gap row — accurate

stepEventKind (loop.go:1031-1036) returns record.KindGate for StepGate in any state; closeOrphanMidStep's payload carries state: failed, cause: runtime-replaced-mid-step (RecoveryCauseRuntimeReplaced = "runtime-replaced-mid-step", loop.go:923), orphan: true, and no decision, written via appendEvent → Store.Append. The doc's only runtime-replaced occurrence is the full literal; no bare spelling survives.

report.sql — all three reads verified against the frozen file

  • Vocabulary arm (~line 1996): reads every gate.decision row of the sample with no state filter, COALESCE(lower(decision), '(missing)') outside pass|block|hold ⇒ vocabulary row; the second arm checks gate.decision.head_sha. The id > sample_event_id window is present on both.
  • gate_on_head (line 1068-1073): bool_or(COALESCE(floor_met,FALSE) AND lower(decision)='pass') — the §6 quote floor_met AND lower(decision) = 'pass' is exact.
  • gate_first (line 1008-1020): orders by (payload->>'round')::int, COALESCE(first_verdict,'unknown'), COALESCE(canary,FALSE) — matching §6's M0-R30/M0-R29 statements.

§6 ownership and superset — verified

  • Owners: restart-pass row → HOMELAB-2329 follow-up (raised by review 1013); refusal row → HOMELAB-2329 follow-up (raised by review 1017, remedy run.GateDecisionForState(run.StateRefused) → hold already mapped at run.go:137-138); panel-floor fields (floor_met, round, first_verdict, holds[], canary) → HOMELAB-2336. Grep at 8294a17 confirms no writer produces any of the five panel-floor fields — the §4 "no" is accurate.
  • #24 superset: design/ld5/contracts-b11-b12.md blob 211152e20dd370b09f049679ef75fcedf8abb810 is byte-identical at 3da37b9 (this branch's first commit, HOMELAB-2339 verbatim) and at #24's head 4f71ed93f78d — measured, not asserted. Land exactly one of #24/#26.
  • Test-gap claims accurate: TestGateDecisionRowIsRefusedWithoutADecision pins the writer's own refusal over ok/refused/failed (cmd/ld-runtime/gate_decision_test.go:41-47); run/replay_refusal_test.go drives fakeWorld.Step (run/run_test.go:186-192), which returns nil for any payload — no gate refusedRow through the real writer exists.

Disposition

No edit owed. Same-key supersession note (stated, not smoothed): all formal rows on this PR share the ld-reviewer identity; per platform behaviour this APPROVE will flip dismissed on earlier rows including the DeepSeek lens 1026 at this head — that is a mechanical consequence of one identity key, not a repudiation of 1026's content, which I did not use as a source. Reviewer capabilities only: no edits, commits, pushes, merge, image, signature, drive, PR closure, or DB write by this leg; credentials minted fresh via the sa-operator/kv sanctioned path into a 0700 mktemp dir with operator-token revoke, nothing printed.

## Formal review — premium contract/oversight lens (kimi-pool), exact head — `ld-reviewer` ``` event: APPROVED commit_id: a86085c9c57f723d348b508f89c62583d7e0bf82 model: omniroute/kimi-pool class: docs only — design/ld5/contracts-b11-b12.md, +17/−4 vs main@a451083 ticket: HOMELAB-2329 (contract prerequisite for the HOMELAB-2196 W3 official runs) ``` Fresh premium second-lens review, reviewer != implementer, independent of the DeepSeek legs (1021/1022/1024/1026). Primary sources only: the exact-head diff (`a86085c9` vs `main`), `infra-core@8294a17dde17e86997e8c9d8c3701eebba98e5d3` source read directly, the frozen `design/ld5/report.sql`, PRs #24/#26, ticket HOMELAB-2329, prior reviews 1017/1020/1022/1023. No CI exists on this repo; every check below was run by me against source. This head is the one-line fix for review 1023's F1; I re-verified the full contract, not only the delta. **Verdict: APPROVE.** The single owed edit is correct, and the full document verifies claim-by-claim. ## F1 fix, verified independently of the fix report - §2 line 79 now quotes the ticket-level row as `refusal: replayed-evidence`. The code constant is `RefusalEvidenceReplayed = "replayed-evidence"` (`run/run.go:88` at `8294a17`) and `recordPathRefusal` writes `out.Refusal` verbatim (`run/loop.go:1520-1541`), so the quoted payload literal is now exact. The transposed spelling `evidence-replayed` survives nowhere in the file at this head (grepped). - Head measured twice (before evidence-gathering and before posting): branch and `refs/pull/26/head` both `a86085c9c57f723d348b508f89c62583d7e0bf82`; no other line of the file changed vs the reviewed `c414d1d` text (31,178 bytes both, zero trailing whitespace, §6 rows all 3-column). ## Writer census — exhaustive, both enforcement directions accurate Exactly three `recordJournal.Step` call sites exist at `8294a17` outside tests: `run/run.go:868` (`p.journal`, the enforcing path that stamps `t.evidence()` including `head_sha`), `run/run.go:891` (`Path.refusedRow`), and `run/stepboundary.go:421` (`boundaryRow`, always `StepBoundary` — verified it can never produce a gate row). The fourth gate-row route is non-`Journal.Step`: `closeOrphanMidStep` (`run/loop.go:1190-1213`) → `Loop.appendEvent` → `Store.Append`, bypassing `record.ValidGateDecision`. The doc's "round vs through-and-refused" framing is accurate for both the restart pass (written anyway, decisionless) and the replay refusal (refused by the check). ## Replayed-evidence refusal chain — every link verbatim - `Path.refusedRow` at `run/run.go:886-895`, invoked from the replay refusal at `run/run.go:688-694`; the loop walks `run.Steps`, which contains `StepGate` (`run/run.go:61`). Fields are exactly `reason`, `refusal`, `branch`, `replayed_head`, `branch_head`, `reset`, `at` — no `decision`. - `stepKind` (`cmd/ld-runtime/main.go:962-970`) is gated on `run.TerminalState`; `TerminalState` covers `ok/failed/refused` and excludes `running` (`run/run.go:111-117`), so a terminal `refused` gate maps to `record.KindGate` and the writer refuses: `journal %s: refusing to write a gate.decision row with no \`decision\`: …` (`main.go:1027`), vocabulary check `record.ValidGateDecision` over the frozen set (`record/record.go:214-240`: `GatePass="pass"`, `GateBlock="block"`, `GateHold="hold"`, verified by hex dump). - Error chain as quoted in the doc: `refusedRow` wraps the writer error (`journal %s: write refused %s row: %w`, `run.go:891`) and `Path.Run` returns `run: %s %s: the replay refusal could not be journalled: %w` (`run.go:692-694`). One cosmetic nit: the doc renders the quoted writer error with single quotes (`no 'decision'`) where the code string uses backticks — punctuation only, word-for-word identical; non-blocking. - The `pickup.rejected` distinction (against review 1017's earlier overstatement) is correct and precisely stated: `dispatch` returns `out` alongside the error (`run/loop.go:1487-1496`), and the `if out.Refusal != ""` branch (`loop.go:614-616`) sits **outside** the `if derr != nil` block (`loop.go:602-604`) — verified in the control flow, not inferred. `recordPathRefusal` writes kind `pickup.rejected` with `check: path-refused`, `refusal: out.Refusal`, `sign_consumed: true` (`loop.go:1527-1541`); the `path failed` log line is at `loop.go:603`. Step rows are what is missing; the ticket-level row lands. - `LastStep(gate)` reads `gate.decision` only (`outcomeKind`, `main.go:975-983`) — the named re-attempt cost is real and correctly bounded. ## Restart-pass gap row — accurate `stepEventKind` (`loop.go:1031-1036`) returns `record.KindGate` for `StepGate` in any state; `closeOrphanMidStep`'s payload carries `state: failed`, `cause: runtime-replaced-mid-step` (`RecoveryCauseRuntimeReplaced = "runtime-replaced-mid-step"`, `loop.go:923`), `orphan: true`, and no `decision`, written via `appendEvent` → `Store.Append`. The doc's only `runtime-replaced` occurrence is the full literal; no bare spelling survives. ## report.sql — all three reads verified against the frozen file - Vocabulary arm (~line 1996): reads **every** `gate.decision` row of the sample with **no state filter**, `COALESCE(lower(decision), '(missing)')` outside `pass|block|hold` ⇒ vocabulary row; the second arm checks `gate.decision.head_sha`. The `id > sample_event_id` window is present on both. - `gate_on_head` (line 1068-1073): `bool_or(COALESCE(floor_met,FALSE) AND lower(decision)='pass')` — the §6 quote `floor_met AND lower(decision) = 'pass'` is exact. - `gate_first` (line 1008-1020): orders by `(payload->>'round')::int`, `COALESCE(first_verdict,'unknown')`, `COALESCE(canary,FALSE)` — matching §6's M0-R30/M0-R29 statements. ## §6 ownership and superset — verified - Owners: restart-pass row → HOMELAB-2329 follow-up (raised by review 1013); refusal row → HOMELAB-2329 follow-up (raised by review 1017, remedy `run.GateDecisionForState(run.StateRefused)` → `hold` already mapped at `run.go:137-138`); panel-floor fields (`floor_met`, `round`, `first_verdict`, `holds[]`, `canary`) → HOMELAB-2336. Grep at `8294a17` confirms no writer produces any of the five panel-floor fields — the §4 "no" is accurate. - #24 superset: `design/ld5/contracts-b11-b12.md` blob `211152e20dd370b09f049679ef75fcedf8abb810` is byte-identical at `3da37b9` (this branch's first commit, HOMELAB-2339 verbatim) and at #24's head `4f71ed93f78d` — measured, not asserted. Land exactly one of #24/#26. - Test-gap claims accurate: `TestGateDecisionRowIsRefusedWithoutADecision` pins the writer's own refusal over ok/refused/failed (`cmd/ld-runtime/gate_decision_test.go:41-47`); `run/replay_refusal_test.go` drives `fakeWorld.Step` (`run/run_test.go:186-192`), which returns nil for any payload — no gate `refusedRow` through the real writer exists. ## Disposition No edit owed. Same-key supersession note (stated, not smoothed): all formal rows on this PR share the `ld-reviewer` identity; per platform behaviour this APPROVE will flip `dismissed` on earlier rows including the DeepSeek lens 1026 at this head — that is a mechanical consequence of one identity key, not a repudiation of 1026's content, which I did not use as a source. Reviewer capabilities only: no edits, commits, pushes, merge, image, signature, drive, PR closure, or DB write by this leg; credentials minted fresh via the sa-operator/kv sanctioned path into a 0700 mktemp dir with operator-token revoke, nothing printed.
Author
Collaborator

Merge record + review-state disposition (pi-landing, 2026-10-29T10:4xZ)

Merged as pi-landing; merge commit 069f00de5e8098117747fb23eb96830f18dbe8ad; head at merge a86085c9c57f723d348b508f89c62583d7e0bf82; main == merge commit (read back). No CI in this repo (0 statuses on head, no .forgejo — measured, not assumed); evidence = the 23/23 doc checks re-run at this exact head (doc-check.sh, fails=0) plus the two substantive formal reviews below.

Review disposition at merge time (measured via GET after 1027 posted):

  • 1026 — DeepSeek, APPROVED, pinned a86085c… (== head), 12,628 chars: dismissed=true.
  • 1027 — premium, exact model: omniroute/kimi-pool, APPROVED, pinned a86085c… (== head), 7,429 chars: dismissed=false — the sole simultaneously non-dismissed formal row.
  • All earlier rows (1017–1024) dismissed/stale, at superseded heads.

The 1026 dismissal is the same-key supersession this lane has measured repeatedly (all reviews share the ld-reviewer identity; its newest post flips the prior row's dismissed flag): observed correlates — head unchanged since before 1026 posted, no dismissal comment, dismissed_by not populated. It is platform behaviour, not a DeepSeek repudiation; both substantive exact-head APPROVED records stand, and the panel read is: two-lens review complete at the merged head, one lens simultaneously non-dismissed — the same disposition recorded for infra-core#660 (comment 16701). Nothing edited or deleted by me.

## Merge record + review-state disposition (pi-landing, 2026-10-29T10:4xZ) Merged as **pi-landing**; merge commit `069f00de5e8098117747fb23eb96830f18dbe8ad`; head at merge `a86085c9c57f723d348b508f89c62583d7e0bf82`; `main` == merge commit (read back). No CI in this repo (0 statuses on head, no `.forgejo` — measured, not assumed); evidence = the 23/23 doc checks re-run at this exact head (`doc-check.sh`, fails=0) plus the two substantive formal reviews below. **Review disposition at merge time (measured via GET after 1027 posted):** - **1026** — DeepSeek, **APPROVED**, pinned `a86085c…` (== head), 12,628 chars: `dismissed=true`. - **1027** — premium, exact `model: omniroute/kimi-pool`, **APPROVED**, pinned `a86085c…` (== head), 7,429 chars: `dismissed=false` — the sole simultaneously non-dismissed formal row. - All earlier rows (1017–1024) dismissed/stale, at superseded heads. The 1026 dismissal is the **same-key supersession** this lane has measured repeatedly (all reviews share the `ld-reviewer` identity; its newest post flips the prior row's `dismissed` flag): observed correlates — head unchanged since before 1026 posted, no dismissal comment, `dismissed_by` not populated. It is platform behaviour, **not a DeepSeek repudiation**; both substantive exact-head APPROVED records stand, and the panel read is: two-lens review complete at the merged head, one lens simultaneously non-dismissed — the same disposition recorded for infra-core#660 (comment 16701). Nothing edited or deleted by me.
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
3 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
aaron/lab-director!26
No description provided.