The rulings themselves (the first post missed them):
plan-1-d1
| T5 self | unix socket under t.TempDir() can exceed sunpath in this sandbox | Ruling 1 | Ruling 1: T5's socket test makes its socket dir with os.MkdirTemp("", "rr") + t.Cleanup(RemoveAll), not t.TempDir() — the repo's own idiom (internal/edge/doortest.go shortSockDir) for the ~104-byte sun_path limit — costs noth Ruling 2: subagents run file-writing shell commands and git commits with the sandbox disabled, because the worktree sits outside this session's sandbox write roots; Edit/Write tools work directly — costs only prompt noise if wro Ruling 3: Exe error → keep polling and remember the error for the deadline reason, EXCEPT a permission error (os.IsPermission / EACCES), which marks the binary check unavailable for this settle (logged once) so an unprivileged c Ruling 4: the readiness probe client must not follow redirects (CheckRedirect → http.ErrUseLastResponse), matching internal/edge/prober.go — spec §2.4 compares the configured status against the upstream's own answer, and a fo Ruling 5: Task 9's README operator note is NOT written tonight — README prose must pass copy-review, which needs Paul at the review server; the draft text stays in the plan (Task 9 Step 1) and is applied after his review — cos Ruling 6: Task 9's gate is the forge CI run on the pushed branch (.amadan/ci.d is the repo's declared gate) plus a local cross-compile; no local go test ./... on this shared machine — cost if wrong: a failure surfaces in CI ra Ruling F1: exe outside WantDir is not-ready (keep polling), fails only at the deadline naming the exe — systemd's fork/exec window is documented — cost if wrong: a wrong-binary start takes up to the 30 s window to reject inste Ruling F2: inactive/dead during settle = deliberate stop → not judged, not restarted, no refusal — spec §2.3 "a unit an operator stopped stays a no-op" — cost if wrong: a build that exits 0 with Restart=no reads as "stopped Ruling F3: Retry travels in the pending-promote payload and applies at execution — spec §2.5 says the API door takes retry; approvals must not change its meaning — cost if wrong: none beyond the payload field Ruling F4: process groups also require the same channel — a different channel is a different promotion, and a shared process across channels is not a real console shape — cost if wrong: a same-process sibling on another channe Ruling F5: Show errors inside the settle loop retry until the deadline — a transient observation failure is not a §2.3 failure condition — cost if wrong: a dead D-Bus delays rejection to the deadline Ruling F6: refusals are written after the rollback restart with Recovered/RecoveryError/RestoredVersion; restored="" unless rolledBack; siblings stamped with bound.PrevVersion; alerts distinguish failed recovery — spec §2.6 req Ruling F7: retry freshness enforced against the CAS-read pointer inside sg.promote — the refusal identity must change on every successful retry — cost if wrong: up to 2 s extra wait on a racing retry Ruling F8: a non-blocking refusal is reconciled (removed) before the cur==ver return — a stale record otherwise shows in status --live forever — cost if wrong: one extra file read per pass per host (stat of a usually-absent fi Ruling F3a (fixer's adaptation, accepted): a retry skips the pipeline order check at proposal and execution, refused at proposal unless the channel serves that version, and relies on PromoteOnLadder's version guard at execution �� Ruling F2a (fixer's adaptation, accepted): the stop rule also applies to rollbackUnitRestart — cost if wrong: a rollback the operator stops is reported as stopped, not failed Ruling F7a (fixer's adaptation, accepted): if the 2 s wait cannot produce a strictly later stamp (clock skew), the retry is refused — cost if wrong: a retry fails under skew and is re-run
plan-2-d2
| T4 | README note | Ruling 1 below | Ruling 1: Plan 2 Task 4's README note is not written tonight — README prose needs copy-review with Paul (same as Plan 1 Ruling 5); Task 4 is the gate only (forge CI + cross builds) — cost if wrong: the operator note lands late Ruling 2: PreviousProgram fails closed — skips only a missing (os.ErrNotExist) or unparseable manifest, returns any other error — spec §3 exists to stop a wrong-program ship and a silent off-switch on a store blip defeats it fix round 1/5 (1 addressed, 1 open — new: unparseable manifests now fail the ship instead of being skipped, contradicting Ruling 2; commits fee7f2cc..f1c33a09) Ruling 3: the program check runs only for a NEW version: API door after the "already shipped" idempotent short-circuit (just before release.Ship); CLI direct mode skips it when the version already has a manifest (release.Ship then Ruling 4: refusal records gain Kind ("wrong-program" for D2; "" = D1 not-up), omitempty, schema stays 1; the gate line, the alert subject/body and the status row branch on it: D2 says "<ver> is program <P>, not pointed live (still Ruling 5: the live binary's program is always folded into the route's history (whenever cur != "" and not already present), not only when the history is empty — the live binary is by definition one the route has run — cost if Ruling 6: the webhook envelope keeps kind=releaserefused and carries the record's Kind as refusalkind (the fixer's adaptation: the embedded field was shadowed) — cost if wrong: a webhook consumer reads a differently named fiel gate only (Ruling 1) — pushed for forge CI; cross builds below Ruling G1: ProgramChange = allowChange for any Go binary release, independent of the comparison — explicit consent must reach boxes that missed the previous change — cost if wrong: none (the flag means what it says) Ruling G2: direct re-ship still stamps Program/ProgramChange via a shared StampProgram, skipping only the comparison; the pre-existing BuiltAt byte-conflict on direct re-ships stays out of scope — cost if wrong: direct re-ships Ruling G3: m == nil → no D2 refusal, print and retry next pass — an unknown override is not a refusal reason — cost if wrong: a wrong-program build is re-examined each pass until its manifest is readable (never pointed live Ruling G4: wrong-program guidance says ship a NEW version with carlos ship --program-change and promote it; mismatch errors name carlos ship — immutability makes re-shipping the same version useless — cost if wrong: wording, t Plan 2: parked — 20-release window boundary test missing — Ruling: real but not load-bearing (VersionCandidates' window is pre-existing, tested code; PreviousProgram only reads its result) — surfaced to Paul Plan 2: parked — direct-mode comparison-skip test does not exercise the skip (re-ship unflagged A while B is newest) — Ruling: real test gap, code path reviewed correct twice; surfaced to Paul
plan-3-d3
Ruling 1: README note (Task 10) is not written tonight — copy review needs Paul; Task 10 is the gate only. Ruling 2: every preflight.md adjustment is accepted and binding for its task; each dispatch points the implementer at its task's section — the plan predates Plans 1-2's review changes, and the reader checked each against current Ruling 3: a D3 staged-bytes refusal (proof does not match the staged bytes) gets its own Refusal Kind ("not-proven"), Recovered: true, RestoredVersion: cur, with its own gate line, alert and status wording (no --retry, no rollback Ruling 4: the new private ProofWaits status field gets the same leak guards as ReleaseRefusals (dry-run needle + scope check, contract allowlist + fixture, CollectBox/BuildFleet leak test) — the fleet feed is public — cost if Ruling 5: a proof wait is cleared on every early return that stops the gate being consulted for that head (bake hold, poisoned, refusal gate), not only on admit, so fastMembers does not sweep a held host every 2 s — cost if wron Ruling 6: Task 10's gate is forge CI + darwin/windows cross builds (Plan 1 Ruling 6); root-package tests use an isolated HOME Ruling 7 (implementer's adaptations, accepted): clear() also forgets cached misses; a policy-error wait carries the real load error as its reason (Task 8 prints it verbatim) — cost if wrong: one extra GET per channel move Ruling 8: before Task 6 wires recordSettled into the root pass, recordSettled also requires ExecPath == the route's live link and the hashed exe == FileSHA256(live link) (the same equality observe enforces), else records nothing � Ruling 9 (implementer's addition, accepted with the fix): a wait the sweep neither renews nor clears backs off like an unstaged route (closes a 2 s hammer via ptr==nil) — cost if wrong: a stale wait is re-swept at most every 5 m gate only (Ruling 6) — pushed for forge CI; cross builds below Ruling H1: second Decode must be io.EOF — fail closed on any trailing input — cost if wrong: none Ruling H2: absent = Lstat not-exist; anything Lstat finds that cannot be read is closed — a broken symlink is a broken config — cost if wrong: an operator's dangling symlink holds deploys until fixed (logged every pass) Ruling H3: a RefusalNotProven blocks only while the current clean policy requires that app; no-require/no-file ignores+clears it; policy error keeps it — break glass must work — cost if wrong: none for D1/D2 (untouched) Ruling H4: record live healthy builds BEFORE release.Pass, mint after — the healthy build present at switch-on must be in the history before adoption can replace it — cost if wrong: one extra observation per route on passes wh Ruling H5: hash cache keyed on file identity (size, mtime, inode where available); proven cache keyed on (acct, app, sha, prover) — cost if wrong: an extra hash after a touch Ruling H6: write the docs/site/cli.md carlos proof section, plain and factual, flagged for Paul's copy review before merge — the gate requires it and the branch is not merged without review — cost if wrong: Paul rewrites it Ruling H4a (fixer's adaptation, accepted): the mint half reuses the first observation only if the live link and the unit's InvocationID/MainPID are unchanged; otherwise it re-observes — a rollback during the pass must not let a
plan-4-d4
Ruling 1: Tasks 1 and 4 (README prose in platform and carloku-infrastructure) are held for copy review with Paul; their text stays in the plan. Ruling 2: Task 5 (the rollout) is held for Paul: it changes production boxes and needs a published release. Ruling 3: Task 2 works in a git worktree of carloku-infrastructure at /home/paulca/github.com/carlosframework/carloku-infrastructure-console-defences, branch console-release-defences from origin/main; the PR is opened for Paul and