You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Keep supervised manual ctx as legacy compatibility and refuse managed lanes - #121
Merged 2026-10-06 at 09:38:31 UTC as 00971b929f586179828481e7cb34db181f386937, squash of tested head f13d32975d7457d662249385d23ee28a7f713c4c onto main fea9a29. Final landing checks passed: 1096 Linux tests, 1096 full macOS tests plus 20 focused macOS tests, 888 no-submodule tests / 208 expected skips, Windows, launch guards, Bash 3.2 parse and Sonar. The three runner-cancelled jobs passed on attempt 2; the original successful macOS gate was retained. No admin override was needed. Local focused integration validation passed 47 tests. Final ownership check found no open landing; all 62 review threads were resolved. T017 landing and T022 reconciliation validation are complete in this final review record. Feature branch and worktree are preserved. Exact-head Codex request received quota exhaustion, not a completed bot review; focused expert review provides separate evidence. Open follow-ups #158 and #159 remain open.
Manual /ctx could resume the transcript it had just paused, lose its pane when launch failed, or allow an older restart attempt to publish into a retry. This change preserves a supervised legacy restart: the backend records the operation before respawn, launches a fresh Claude session with the preserved handoff, and confirms the intended live transcript.
Brett's 2026-10-04 decision is legacy compatibility; refuse managed lanes. Managed or unreadable ownership refuses. Restart generation and attempt belong to the legacy intent; PR #97 lifecycle snapshots and feature 001's managed JSON ledger retain their separate authorities.
Reserve preparing before supervised preservation. Fence claims, child writes and finalizers by operation, generation and attempt. Each attempt reserves its transcript once.
Bind agent, profile, accessible absolute directory, pane, window and the row's handoff. Read back the complete pending launch facts and checksum before respawn. Verify operation-bound handoff filesystem identity under the shared writer mutex and atomically replace the resolved target. Preserve parent and leaf symlinks.
Validate all mandatory record fields and refuse unknown keys, duplicate keys, malformed or blank lines and control delimiters. Preserve exact field bytes. Create private, exclusive same-directory intent temporaries.
Leave live or unknown children/holders starting and indeterminate. Retry becomes available only after confirmed launch termination and holder absence. Reconcile TERM/HUP across claim publication; cooperatively stop and reap observers without signaling recycled numeric PIDs.
Forward configured roots and launcher binding values into the pane. Current pending launch facts replace prior profile values explicitly. Repeat all-holder checks before every claimed attempt.
Legacy rename shares the mutex and refuses unfinished/failed restart ownership. Its existing four-file EXIT rollback is an explicit exception to crash-atomic publication; restart preservation and resume stamping use the atomic publication helper.
Current head f13d329 includes four landing corrections:
macOS portability: C-locale POSIX control checks in writer and early handoff preflight; spelling-only rename refusal before case-equivalent path reads; controlling tty and owned-process cleanup for the interactive retry fixture. Full macOS confirmation remains required.
terminal fixture: consume nonblocking PTY master output while waiting for prompts and process exit, and close the master before exceptional cleanup. This addresses the sole remaining macOS fixture failure: queued terminal echo can prevent Darwin controlling-terminal teardown even after a kill signal. Existing exit-4, exactly-one-launch and persisted attempt/state assertions remain. macOS CI checks this fixture before the long full suite; the full suite remains the required landing gate. Production code is unchanged by b20882a.
preparation recovery: failed preservation-only / attempt 0 / no new transcript permits ordinary resume only with no operation/attempt tokens or fresh selectors and every holder confirmed absent. Exact state/mode/attempt/transcript/operation/generation are rechecked before binding changes, after ordinary selection and before exec. The failed intent remains unchanged; failed fresh launches remain supervisor-only and preparing stays blocked. Status and product contracts distinguish these failure classes.
Shell parsing, error-level ShellCheck, Python compilation, diff checks and strict OpenSpec validation pass. The nine-role focused review has no remaining blocker. Added regressions cover actual aborted preparation resuming its recorded UUID, unchanged intent, live/unknown/old-helper holders, late/final holder and operation changes, invalid/malformed records, operation/attempt tokens and fresh selectors. 40 focused local tests passed at predecessor 6b92e35: 19 preparation recovery cases, 15 control/rename/PTY cases, and 6 checkout preflight cases. Each group ran through the serialized workstation wrapper. 21 focused local root/integration cases pass at fb28987 in 135.89 seconds through the serialized wrapper. The standalone local PTY wrapper stayed queued behind unrelated workstation tests and was stopped after the same regression passed in macOS CI; no standalone local pass is claimed. The preparation recovery finding is implemented, runtime-validated and resolved; later Copilot findings remain in #159 under the explicit two-round cap.
Current landing run 37365599854 is retrying runner-cancelled jobs on f13d329 after reconciliation with landed PR #164 (main fea9a29). The sole merge conflict was the two appended shell-suite sections; both original sections are retained byte-for-byte, with index act tests before supervised restart tests. Production code merged automatically. The shared resolver/restart sandbox now explicitly retains LANES_INDEX=off after its environment scrub, so test pushes cannot nudge an installed indexer. The index remains derived and non-gating: restart acts neither enable indexed reads nor consult their outputs. Five private restart helpers are unchanged from fd09e2d, and five generic diagnostic helpers match incoming main verbatim. Corrected test order and fixture isolation passed focused expert re-review. Bash parsing, error-level ShellCheck, Python compilation, staged diff checks and strict OpenSpec validation pass. The serialized local root/managed/ordinary-launch run passed 47 tests / 1049 deselected in 167.78 seconds after waiting behind unrelated workstation pytest.
The current head passed 1096 full macOS tests in 5522.19 seconds, plus 20 focused macOS tests in 189.35 seconds, completing at 21:27:50Z. Guard, parse and Sonar pass. The initial Linux, no-submodule and Windows jobs were canceled before any test step because GitHub could not allocate hosted runners. After the workflow finished, failed-job rerun was accepted at 21:39:22Z as attempt 2; only those three jobs are rerunning, and the successful macOS gate is retained. These canceled jobs are not claimed passes. Main remains fea9a29; final merge still requires the retry results.
The immediately preceding fd09e2d head passed all CI: 1047 Linux tests in 1712.55 seconds, 1047 macOS tests in 6015.46 seconds (plus 20 focused macOS tests in 220.24 seconds), and 839 no-submodule tests / 208 expected skips in 2372.68 seconds. Windows, guard, Bash 3.2 parse and Sonar also passed. #164 landed before #121 merged, so the new combined head requires its own landing gate; predecessor passes are historical evidence.
Fresh exact-head Codex review was requested for f13d329; the bot reported quota exhaustion. No completed exact-head bot review is claimed. The focused local expert panel has no remaining blocker. P1 4186306909 is implemented, runtime-validated and resolved.
Historical predecessor validation at 6b92e35: full Linux 1028 passed in 2147.82 seconds; no-submodule 820 passed / 208 expected skips in 2264.19 seconds; Windows, guard, Bash 3.2 parse and Sonar pass. Its full macOS run failed 1 fixture / 1027 passed in 6676.28 seconds. The required Codex request at that predecessor received a quota-exhaustion response; it is not a completed review. The older 774d189 macOS gate failed 14 cases / 993 passed, prompting the original portability correction. Prior-head results do not substitute for this head's pending landing gate.
Follow up post-cap legacy restart validation and preservation races #159 records deferred cases from later comments: Git checkout membership, the ordinary handoff ownership-check/write interleaving, restart-intent exit-2 ambiguity, matching completed operation tokens in direct lane-start, and missing holder-pane evidence during readiness. It also records the later checkout-root hint and optional flag-shaped parser-value cases, with evidence dismissing the broader partial-preservation and silent-operation-regeneration claims. These are not claimed fixed. Later same-operation identity mutation, empty/unset tmux environment forwarding and reserved operation-none token cases are also recorded there with bounded read-only triage; broader unsafe-launch claims were not established. Static collisions already refuse; collision-induced launch through a changing-register interleaving remains unproven. The latest review at fb28987 adds direct active-launch missing pane evidence and sole intent leaf-symlink publication to Follow up post-cap legacy restart validation and preservation races #159. Its holder-witness overview is recorded as contract hardening: current readiness already deduplicates by PID and prefers the current UUID, so its claimed ambiguity is unsupported. These later threads are resolved as recorded follow-ups under the cap, not as implemented fixes.
Brett released the merge hold on 2026-10-05. PR #97 and PR #164 have landed and this head is reconciled with both. The ready label remains applied so this updated head reruns the full macOS landing gate; squash merge follows only after that gate, other checks pass. The exact-head Codex review is requested explicitly; quota-limited bot responses will be recorded without claiming a pass. The completed expert panel provides separate review evidence. Preserve the feature branch and worktree. No installation or real-session canary is part of this landing. The protocol's supervisor mechanism remains documented as an explicit deviation.
…ould commit
The previous writer proved #94's cause and wrote most of the implementation in
the working tree, then lost its process with nothing committed. This commit is
that working tree verbatim, so the work survives the next crash; it is not a
reviewed state and the acts are finished in the commits that follow.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EaHzfTLW4u9ukpWuw8Dt6r
…start's resume sources, not beside one
#87 gave `lane-start` an exact-uuid resume (`resume_sid`, the row's last id or
the last PAUSED record's) and a bg-holder fence. Both of its resume sources are
gated on `(( ! fresh ))`, and this branch moves what decides `fresh` above them:
the lane's own restart intent on disk, then `--fresh`, then the environment
variable that #94 measured not arriving. The merge is a union — no hunk of
either side is dropped — and the semantic check is that #94's own suite case
still holds with BOTH of #87's sources available on disk and no variable set.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EaHzfTLW4u9ukpWuw8Dt6r
…with the check written to catch it
The review pass over the rescued work found three defects, and the first is the
one that matters: `set-restart-intent` keeps every field a transition does not
name — which is what lets the supervisor write `starting` without blanking the
digest every later launch is fenced on — but five of those fields belong to ONE
OPERATION, and the readiness predicate is built on two of them. A second `/ctx`
inherited the last one's `new_transcript`, a uuid the new launch will never
mint, so readiness could only ever run to its deadline; and it inherited the
last one's `old_transcript`, which is the uuid the replacement must be DISTINCT
FROM. Being distinct from it is the check that catches openRepoTools#94 — a
pane that came back resuming the transcript the context clear had just paused —
so an inherited one let the measured defect through the predicate written for
it. `old_transcript`, `new_transcript`, `attempt`, `reason` and `created` now
fall back to nothing when the operation changes; a caller that names one still
wins, and the fields that belong to the LANE are kept exactly as before.
The other two are diagnostics that lie. `lane-start` treated a `2` from
`restart-intent` as a read that FAILED and printed a note, so every launch of
every lane on a workstation whose `lanes-edit.sh` predates this change would
nag about a state that is simply the old one — the estate's fence is `0` an
answer, `8` no answer and `2` a helper predating the read, and the last two fall
to the next rung. And `--restart-status` told a reader that `lanes-edit.sh` has
no `lane-state` when the lane merely has no snapshot, which would send somebody
hunting an installation problem the day #97 lands.
Brett Heap's brainstorm packet for this change is committed beside the
implementation, as #97 committed its own, and the proposal now carries a verdict
for each of its documents and for each OpenSpec file: what matched, what
deviated, and which numbered decision answers it.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EaHzfTLW4u9ukpWuw8Dt6r
…ate limit
The predecessor's working tree, committed as it stood so no third writer has to
find it again. Two files, both of them the suite catching up with what the
implementation already does:
`tests/test_lane_helpers.sh` — the three Amendment 18 Addendum 2 (i-8) `/ctx`
respawn cases now assert the SUPERVISOR line rather than the launch line, on all
three PATHs (no `lane`, this estate's `lane`, a stranger's `lane`), which is the
stronger property: what tmux is asked to start no longer depends on anything a
person's shell profile can change. The handoff-skill cases assert the old tmux
recipe's ABSENCE in executable form while the file still quotes it in the
paragraph that says why it went. And every supervisor case pins `TMUX_PANE`,
because the suite is very often run inside tmux and an inherited pane makes the
pane check refuse for a reason the case was not written to test.
`docs/README-lanes.md` — the `/ctx` paragraph says that what tmux starts is a
supervisor, not the session itself.
One suite failure is outstanding and under investigation; it passed in the
previous run, which is the shape of a race rather than a defect, and this commit
records the state rather than a verdict.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EaHzfTLW4u9ukpWuw8Dt6r
… beside the supervised restart
`main` moved twice under this branch: every `chmod` `--install` performs now
fails through `die` and a second writer of either hook refuses whether or not
our own entry is beside it (#102), and `wip init` stops reading a failed
`git status` as clean, refuses a template path whose ancestor is a symlink or
not a directory, refuses one staged at a mode it never wrote, and names a
skip-worktree path HEAD carries and the disk does not (#101).
Both touch `openRepoTools`, `README.md` and three pytest files; this branch
touches none of them. The merge is a union with no overlapping hunk, which is
what `git merge` reports and what the file list proves: the shell suite's
`ort_text` assertions read `openRepoTools` from the tree and are unchanged on
either side.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EaHzfTLW4u9ukpWuw8Dt6r
…y-second deadline that counted sleeps was never sixty seconds
Two writers died at rate limits over this change and each left the same note:
one suite failure, and it passed in the previous run. It is solved, and it is
neither a race nor anything this branch wrote.
**THE FLAKE: a write whose result is the line already there was REFUSED.** The
case is Amendment 15's `--confirm in a window named for this lane in ANOTHER
case exits 0`, and 5 is what `lanes-edit.sh` dies with when a write cannot prove
what it did. `replace_line` proves it touched exactly one line by demanding
`1 1` from `git diff --no-index --numstat` — and an edit that changes NOTHING
produces no output at all, so the comparison was against an empty string and the
act died 5 with `numstat: none`. The guard read *nothing changed* as *more than
one line changed*, which are opposite facts.
It is reached by ordinary use and not by a contrivance. `set-row-state` writes
`<STATE> · $(utc_now) · <line>` and `utc_now` is SECONDS, so two stamps of one
state phrase inside one second are byte-identical — and two `lane-start
--no-launch` runs of one lane in one window are exactly that pair, which is what
the `--confirm` case does. Eight identical writes in a loop against the shipped
file: `rc=0 0 5 5 5 5 0 5`, decided by nothing but where the second boundary
fell. Ten against the fixed one: 0 every time, the unchanged ones saying so.
So a result byte-identical to the file it would replace is a write that is DONE.
`replace_line` returns 0, writes nothing and says which line already read that
way; `commit_push` already had *nothing staged — no commit made* on its own
line, and none of the four callers ever wanted the file to DIFFER — they wanted
it to SAY something. `set-row-state` reads a `REPLACE_LINE_NOOP` flag so its own
note says UNCHANGED rather than announcing a replacement that did not happen.
The new case pins it BY CONSTRUCTION rather than by racing the clock:
`replace-in-row` with the same text on both sides is identical whatever the
second is. On a workstation the old behaviour was a lane stamped twice in a
second being told its write was refused, while the register already said
precisely what the caller asked for.
**THE DEADLINE: `supervise_watch` added 2 per turn and called it the elapsed
time.** That counts the `sleep` and never the `live-holder` read between two of
them — and that read resolves the lane, reads the published row and scans every
session record this workstation has. The design's *"waits up to 60 seconds"* was
sixty seconds PLUS thirty register reads, and the INDETERMINATE line then
reported a number that had never elapsed to the one person reading it. It is
wall clock now and reports the true elapsed beside the deadline it was measured
against; the counted sleeps are kept as the FLOOR, so a workstation whose `date`
cannot answer, or whose clock steps backwards, still terminates the loop.
**And three things in the suite that rested on something nobody wrote down.**
`trap cleanup EXIT INT TERM` cleaned up on TERM and RETURNED. `tests/run.sh`
states the rule for its own lock — *"a handler that only cleans up and RETURNS
releases the lock while this suite carries on running"* — and one handler on all
three broke it here in the other direction: a TERM removed `$SANDBOX` and the
run carried on against a sandbox that was gone, every case after it `env:
'.../bin/lane-start': No such file or directory`, printing `1567 passed, 233
failed`. A killed run that reports two hundred failures is a transcript that lies
about this repository, and somebody reads those. INT and TERM exit 130 and 143
now; EXIT still returns, because the status it carries is the suite's own.
The two supervisor cases asserted an ORDER with a stopwatch: a fixed `sleep 8`
in the fake child, inside which the observer had to fit two 2-second sleeps, two
`live-holder` polls and its write, with nothing ordering the two events. Both
children now wait for the file the observer writes — `state: ready`, and a
`reason` naming INDETERMINATE — under a bounded cap.
And two cases named `TMUX_PANE` twice in one `env`, relying on the later
assignment winning. That is true of every `env` this runs under and is written
down nowhere; they name their own pane instead.
**One digest, three commands, pinned to one body.** `lanes-edit.sh` RECORDS the
handoff digest, `lane-start` VERIFIES it before a launch and `lane-handoff`
verifies it before a supervisor claims an operation — three installed files with
no library between them, which is this estate's shape. Two of them are already
proved to agree by behaviour; a case now pins the third, and pins that "the
same" means the BODY and not the name. A copy that drifted would not fail
loudly: it would record one digest and verify another.
**And the deviation cites the decisions that record it.** `lane-handoff`'s
comment at the respawn said "decision 5" where the proposal promises decisions
10 and 11 — 10 for the supervisor being a MODE rather than the installed word
decision 5 proposed, 11 for neither of (i-8)'s doors being taken at that level —
and design decision 10 spelled the mode `--supervise <lane>` where the command
takes `--supervise --lane <lane>`.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EaHzfTLW4u9ukpWuw8Dt6r
…redential assertion stops being vacuous on BSD (CI hygiene on #121)
Both come from this repository's own hygiene gate, and both are defects the
rescued work carried in.
**`--flag ""` refused an empty value and `--flag=` took one**, for
`set-restart-intent`'s `--expect`, `--expect-generation`, `--expect-operation`,
`--operation`, `--generation` and `--attempt`. The `=` spelling of an empty
value then read as ABSENT, and every rung below the flag ran on a value the
operator DID give: an `--expect=` would have fenced on nothing at all, and an
`--expect-operation=` would have claimed an operation it was not entitled to —
which is the fence this whole change is built on, opened by a spelling. This is
`#26`'s paragraph (`the review of c3ebcfe`, `lane-start:707`) arriving at a new
subcommand, and the six now refuse in both spellings. The flags beside them that
take `[ "$#" -ge 2 ]` deliberately ACCEPT an empty value in both spellings,
because `none` is an answer for those fields; the comment says which is which.
**And the "no field could carry a credential" assertion was vacuous on BSD.** It
read `grep -ci 'token\|secret\|password\|key'`, and `\|` is a GNU extension to
BRE: BSD `grep` matches it LITERALLY and reports no error, so on the macOS job
that assertion counted occurrences of the single string `token\|secret\|…` —
none, always, whatever the record held. An assertion that cannot fail is not an
assertion, and this one is the case that proves the restart intent has nowhere
to put a secret. `-E` and a real alternation.
`python3 -m pytest tests/test_repo_hygiene.py -q` — 144 passed.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EaHzfTLW4u9ukpWuw8Dt6r
Adds restart-intent storage and CAS updates; schema safety and local-read handling need changes.
lane-start
Prioritizes persisted fresh-launch intent; schema, identity, and generation validation need changes.
lane-handoff
Implements restart transactions and supervision; signal handling, operation propagation, outcome handling, generation fencing, and fail-closed reads need changes.
On the launcher path the operation is only placed in LANE_RESTART_OPERATION; no --operation argument is passed, and lane-start does not consume that variable, so its operation fence is skipped for the launch that pclaude starts. This means the supervisor's $sr_op is not actually propagated through the launcher as the interface/documentation claims. Pass the operation through the launcher contract or add an equivalent validation before executing the child.
This timeout transition omits --expect-generation "$sw_gen", even though the claim and ready transitions fence on both generation and operation. If the lifecycle generation advances while the observer waits, it can still rewrite a starting intent for the same operation, defeating stale-observer protection. Include the generation in this CAS.
LANES_NO_FETCH=1 "$LANES_EDIT" set-restart-intent "$sw_lane" starting \
--expect starting --expect-operation "$sw_op" \
--reason "INDETERMINATE: ${sw_waited}s elapsed (deadline ${SUPERVISE_READY_SECONDS}s) with the child alive and readiness unconfirmed; ${READY_WHY:-no evidence}" >/dev/null 2>&1 || :
lane-handoff:668
Failure finalization is not fenced on generation, unlike the supervisor's claim and readiness finalizer. If an older launch reaches this path after the lifecycle generation advances while the operation identifier is still present, supervise_failed can mark the newer intent failed. Pass the claimed generation through supervise_failed and require it in this compare-and-swap.
This pipeline discards the lane-state read's exit status. Once the #91 helper is installed, a real lifecycle read failure is indistinguishable from the compatibility case where the helper is absent, so ri_gen falls back to 0 and the code can still write the intent and respawn the pane without proving the current generation. Capture the status and refuse on every code other than the documented no-helper/no-snapshot answers; this pre-kill gate must fail closed.
The restart intent's agent and profile fields are never parsed or compared with this launch. A caller can therefore run lane-start --agent codex (or arrive through a different profile) while a pending fresh-from-handoff intent records another agent/account; the readiness predicate checks transcript, holder, and pane but not these identities, so the wrong process can still be accepted as ready. Refuse conflicting agent/profile values before setting fresh=1, as required by the runtime-conflict contract.
case "$ri_state" in
pending|starting)
if [ "$ri_mode" = fresh-from-handoff ]; then
# THE DIRECTORY IS COMPARED BEFORE ANYTHING IS TAKEN. `real_of` is this
# file's own resolver, so a symlinked projects root does not read as a
# disagreement it is not.
if [ -n "$ri_dir" ] && [ "$ri_dir" != none ] && [ "$(real_of "$ri_dir")" != "$(real_of "$DIR")" ]; then
die "lane $LANE's restart intent (operation ${ri_op:-none}, state $ri_state) names checkout $ri_dir and this launch stands in $DIR. That is a conflict and not a preference: a launch that lands in the right transcript and the wrong directory loses the repository's CLAUDE.md and the lane's memory, silently (Evidence 3). Nothing was renamed, written or started. Launch it where the intent says, or read the intent: lanes-edit.sh restart-intent $LANE" 2
fi
# THE HANDOFF'S DIGEST IS VERIFIED ON EVERY LAUNCH (spec: *a changed or
# missing handoff blocks launch and retry*), because the top block of
# that file is literally this launch's first prompt and a file that has
# moved under the intent is a different instruction. A `none` digest is
# *not checked here* — a workstation with neither `sha256sum` nor
# `shasum` — and says so rather than passing silently.
if [ -n "$ri_hf" ] && [ "$ri_hf" != none ] && [ -n "$ri_dig" ] && [ "$ri_dig" != none ]; then
ri_now="$(handoff_digest_of "$ri_hf")"
if [ "$ri_now" != "$ri_dig" ]; then
die "lane $LANE's handoff has changed since its restart intent was written: the intent records digest $ri_dig for $ri_hf and that file now digests $ri_now. The top block of that file is this launch's FIRST PROMPT, so launching now would hand the new session the block of a handoff the /ctx did not write. Nothing was renamed, written or started (operation ${ri_op:-none}). Take the handoff again: lane-handoff --restart" 2
fi
fi
fresh=1
fresh_why=" (restart intent ${ri_op:-none}, state $ri_state: the /ctx respawn)"
lane-start:3539
The prepared-transcript update is another fenced transition, but it checks only the operation. If the lifecycle generation changes while this launch is preparing, a stale lane-start can write its transcript into the current intent and let readiness confirm evidence from the old generation. Add the intent generation to this CAS, matching the supervisor claim/finalizer.
This new sidecar read is documented as local and network-free, but log_sync fetches origin unless LANES_NO_FETCH=1 is already supplied by the caller. A direct lanes-edit.sh restart-intent <lane> can therefore block on or mutate remote-tracking state while merely inspecting restart status. Force the local-read mode here so the subcommand itself preserves the sidecar's read-only contract.
…g unticked with nothing beside it
`tasks.md` §0 names a reason for every deferral and named five; 7.5 — *amend
`add-automatic-context-rollover` so its success condition is readiness-confirmed
`RUNNING`* — was left unticked with nothing said, which reads as forgotten rather
than as decided.
There is nothing on this branch to amend. `openspec/changes/` here holds
`add-supervised-context-restart` and `interactive-lane-name-repair` and nothing
else; that change exists only as an untracked working copy in the main checkout.
Writing a second copy of somebody else's proposal into this branch to tick a box
would be worse than the open box.
And what this change OWES it does exist, which is the half worth saying: the
outcome to consume is the restart intent reaching `ready`, readable from any
window with `lane-handoff --restart-status --lane <lane>`, and the requirement
*Automatic rollover waits for supervised completion* is already in this change's
spec for that proposal to point at.
`openspec validate add-supervised-context-restart --strict` — valid.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EaHzfTLW4u9ukpWuw8Dt6r
The reason will be displayed to describe this comment to others. Learn more.
🟡 Changes recommended
Unresolved critical and moderate findings affect restart correctness and safety.
Get a fresh assessment by requesting another Copilot review.
Review details
Suppressed comments (10)
lane-handoff:647
RI_AGENT is loaded from the fenced intent but is never used to build SUPERVISE_CMD. For a fresh-from-handoff intent naming the supported codex agent, the direct fallback invokes lane-start without --agent, so it can fall back to the lane record/default agent; when a profile is present, the other branch always invokes pclaude regardless of the intent's agent. The replacement can therefore start a different agent than the one recorded by /ctx. Select or validate an agent-specific launcher and pass the intent's agent on the direct path.
This fallback tells the operator to start pclaude, but at this point a pending restart intent is the authority for the launch. Following that line bypasses the supervisor and can resume the transcript /ctx just paused—the exact failure this change is intended to prevent. The manual recovery here must invoke the absolute supervisor command ($launch_line) rather than the pre-intent ordinary restart command.
die "the record and the restart intent are written and \`tmux respawn-pane -k -t $target\` was refused, so this pane is exactly as it was and the lane's restart intent is \`pending\` for operation $operation. Nothing was killed. Start it yourself: $restart_cmd
or hand this pane to the supervisor once tmux will take it:
$launch_line" 2
lane-handoff:776
The watcher can already be in the middle of recording ready (or the indeterminate result) when the child exits, but this unconditional kill terminates it before that fenced write completes. The parent then reloads starting and can report a successful child as a failed restart, or lose the indeterminate record; wait for the watcher to finish instead of killing it after the child exits.
The supervisor is started across the tmux server boundary, but this command only carries LANES_WORKSTATION into its command string. If the intent was written using the supported LANES_LANE_STATE_ROOT (or a non-default PROJECTS_ROOT), the respawned supervisor resolves a different control root and reports that the intent is missing, so the pane is left with a pending restart that cannot be launched. Thread the control-root overrides (or persist the resolved root) alongside the workstation value.
PCLAUDE is an explicit launcher override for this command, but it is also read only from the supervisor's post-tmux environment (supervise_argv uses it at lines 632–635). A user who relies on a custom launcher therefore loses that override at respawn and may silently fall back to a different PATH launcher or direct lane-start, changing the selected profile/agent. Carry the override in the command string or resolve and persist the launcher path before respawning.
This path only checks whether handoff_file is absolute; it ignores handoff_written, which is 0 when the refresh failed or when the row has no usable handoff. The intent can therefore be written without a handoff/digest (or with the old file), and the supervisor can launch a fresh session with no verified first prompt, despite the documented fourth pre-kill gate. Refuse the restart before writing the PAUSED/row records when the refresh did not succeed.
case "$handoff_file" in /*) ri_args+=(--handoff "$handoff_file") ;; esac
lane-handoff:607
The timeout transition is fenced only by operation. If a newer lifecycle generation reuses or supersedes this intent between the observer read and this write, this stale observer can still overwrite the newer generation's starting record with the old timeout reason. Include the generation passed to supervise_watch in this CAS.
LANES_NO_FETCH=1 "$LANES_EDIT" set-restart-intent "$sw_lane" starting \
--expect starting --expect-operation "$sw_op" \
--reason "INDETERMINATE: ${sw_waited}s elapsed (deadline ${SUPERVISE_READY_SECONDS}s) with the child alive and readiness unconfirmed; ${READY_WHY:-no evidence}" >/dev/null 2>&1 || :
lane-start:2462
lane_restart_read returns success with state=UNKNOWN-SCHEMA, but this code then applies the explicit --fresh (or LANE_START_FRESH) fallback. A direct launch can consequently bypass a restart intent that this reader explicitly cannot interpret, instead of failing closed as the reader's UNKNOWN-SCHEMA result promises. Refuse an unknown-schema intent before applying either fallback.
if (( ! fresh )) && [ "$fresh_flag" = 1 ]; then
fresh=1
fresh_why=" (--fresh)"
lanes-edit.sh:9523
The CAS reads only state, generation, operation, and attempt; it never checks the existing file's schema before rewriting it. A newer or malformed intent that lane_restart_read exposes as UNKNOWN-SCHEMA can therefore be overwritten by set-restart-intent, which writes the current schema and may discard fields this version does not understand. Reject a non-current existing schema before performing the transition, rather than treating it as a normal intent.
if [ -r "$sri_f" ]; then
sri_now="$(lane_sidecar_field "$sri_f" state)"
sri_nowg="$(lane_sidecar_field "$sri_f" generation)"
sri_nowo="$(lane_sidecar_field "$sri_f" operation)"
sri_nowa="$(lane_sidecar_field "$sri_f" attempt)"
fi
This migration step still says to install a separate supervisor, but the implementation's decision 10 and the task checklist explicitly make the supervisor a mode of the existing lane-handoff command and keep the installed command count at twelve. Following this stale step would create the thirteenth installed word that the design rejects; update it to verify the existing lane-handoff --supervise mode instead.
6. Install the supervisor alongside the other openRepoTools commands and verify absolute-path resolution on Linux, macOS, and WSL2.
…d never have fired (Copilot round 1 on #121)
Five findings, all five taken, and the first needed the process structure
changed and not only a handler.
**A `TERM` TO THE PANE ROOT LEFT THE INTENT `starting` FOR EVER.** That is the
one state nothing recovers from by itself: `--supervise` refuses to launch from
it, because a second session of one lane is Amendment 18(h)'s collision, and the
next `/ctx` refuses too, because `--expect 'none|ready|failed'` is exactly what
stops an ordinary context clear superseding an operation in flight. Meanwhile
`--restart-status` said `IN FLIGHT: a supervisor holds this operation` about a
supervisor that was gone.
**AND A TRAP WOULD NOT HAVE FIRED, because bash defers one until the foreground
command returns** — and this supervisor's foreground command is an interactive
Claude that runs for hours. Measured in isolation: a shell running `sleep 20` in
the foreground did not reach its `TERM` trap for the whole twenty seconds; the
same shell with the sleep backgrounded and `wait`ed ran the trap in the same
second. So the child is backgrounded and `wait`ed, and the two things a
background job loses are put back, because this child is an interactive terminal
program and neither loss is survivable for one:
* ITS STDIN. With job control off — every non-interactive bash — an
asynchronous command's stdin is redirected from `/dev/null`. Measured. Fd 9
holds this pane's own stdin, saved before the loop, and the child is started
`<&9 9<&-`, the close so that no descriptor of this script's bookkeeping is
handed on to Claude.
* ITS `INT` AND `QUIT`. Bash sets both to SIG_IGN for an async command and
SIG_IGN SURVIVES `exec`, so Claude would have come up with Ctrl-C dead, in
the pane a person had just cleared the context of. Measured: `SigIgn
0000000000000006` on the child without the reset, `0000000000000000` with
it. `trap - INT QUIT` in the child's subshell restores the disposition this
shell was entered with, and does so even though the supervisor has since set
`trap '' INT` for itself — which it now does deliberately, because Ctrl-C
reaches the whole foreground process group and a supervisor that exited on
it would tear the pane down under a Claude that was merely interrupted.
`TERM` and `HUP` now mark the intent `failed`, fenced, with a reason naming the
signal and whether the child was still running, and they KILL NOTHING
(Amendment 8(f)). `failed` is safe even with a live child, because a retry is a
NEW `--supervise` and that mode's own gate reads `live-holder` before it launches
and refuses on a live one. The exact shipped structure was verified end to end:
the parent's trap fires in the same second, the child survives the parent, the
child's stdin is the pane's, its `SigIgn` is empty and its fd table is `0 1 2`.
**THE INTENT WRITER WALKED PAST AN UNKNOWN SCHEMA.** The read side fails closed
with `UNKNOWN-SCHEMA`; the write side copied the fields this version knows
forward, dropped the ones it does not, and stamped the file `schema: 1` — the
read-side protection undone by the other half of one command. It is checked
inside the lock now and refuses with 2 rather than 7: 7 is *another act got there
first, re-read and decide*, and this is *this copy of the tooling must not touch
this file at all*.
**AND `lane-start` RESUMED ON ONE.** `UNKNOWN-SCHEMA` fell through to the
ordinary resume-source resolution, which is the SAFE half of the decision
sitting on top of the unsafe one: it authorises no FRESH session, and the resume
source waiting for a lane whose `/ctx` has just killed its pane is the transcript
that `/ctx` PAUSED. That is `openRepoTools#94` reached down a second road. It
refuses now, in Amendment 7(d)'s shape, naming both ways out — because it costs
a person the lane until one of them is taken.
**THE USAGE BLOCK PROMISED AN EXIT CODE NO PATH RETURNED.** `4 indeterminate`
was unreachable: the observer's own `return 4` is read by nothing, because it
runs in the background and the RECORD is what decides. So the record decides
this too — an operation whose reason begins `INDETERMINATE:` ends 4 and says
*ran past the readiness deadline still alive*. The `failed` transition STAYS,
and that half of the review is declined with its reason: INDETERMINATE is the
answer for a child that is ALIVE at the deadline, and this branch is reached only
once that child has EXITED, which is a launch that ended having never been
confirmed and is retryable — leaving it `starting` would wedge the lane in the
state the first finding above exists to close.
**AND THE FAILURE WRITE WAS NOT FENCED ON THE GENERATION.** The readiness
finalizer always was; the failure write, the signal write and the INDETERMINATE
note were not, so a superseded supervisor could publish an old verdict over a
newer generation's record. All five state transitions carry it now — and on the
generation CLAIMED rather than the one on disk, because the post-child branch has
just re-`ri_load`ed and would have read the NEWER generation and matched it,
which is precisely the write the fence exists to refuse. It is empty until a
claim is made, so a signal arriving before one does not fence on a `0` nobody
holds, and a signal arriving before the lane is even known says so and writes
nothing.
`openspec validate add-supervised-context-restart --strict` — valid.
`python3 -m pytest tests/test_repo_hygiene.py -q` — 144 passed.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EaHzfTLW4u9ukpWuw8Dt6r
…ke Ctrl-C is
Round 1's two behaviour changes reach a person through the pane, and the manual
described neither.
**A supervisor somebody kills leaves the same retryable record.** `SIGTERM` or
`SIGHUP` — a `tmux kill-pane`, a logout, a person's `kill` — mark the intent
`failed` with a reason naming the signal and whether the child was still
running, and exit 143 or 129, killing nothing. The paragraph says why that
matters: without it a signalled supervisor left the intent `starting`, which is
the one state nothing recovers from by itself, while `--restart-status` reported
`IN FLIGHT: a supervisor holds this operation` about a supervisor that was gone.
**And Ctrl-C in that pane belongs to the SESSION.** The supervisor ignores
`SIGINT` so that interrupting Claude cannot tear the pane down under it, and the
launch is started with `INT` and `QUIT` put back to their defaults so the
keystroke reaches the session itself — which is the half a person would only
discover by pressing it.
The retry paragraph also says exit 4 beside exit 3 now, because the two mean
different things and the command distinguishes them.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EaHzfTLW4u9ukpWuw8Dt6r
The reason will be displayed to describe this comment to others. Learn more.
🟡 Changes recommended
One or more issues must be addressed before approval.
Get a fresh assessment by requesting another Copilot review.
Review details
Suppressed comments (7)
lane-handoff:1118
The signal handler ignores the fenced write's result and then unconditionally tells the user that the intent is failed and retryable. If a newer operation/generation wins, the CAS exits 7 and leaves that newer record untouched; if the write itself fails, the old intent can remain starting. The output and recovery instructions are then false, so this path needs to branch on the write result before claiming failure.
LANES_NO_FETCH=1 "$LANES_EDIT" set-restart-intent "$lane" failed \
--expect 'pending|starting' --expect-operation "$operation" \
${sv_sg_fence[@]+"${sv_sg_fence[@]}"} \
--reason "the supervisor was sent SIG$1 before readiness was confirmed; $sv_sg_alive" \
>/dev/null 2>&1 || :
lane-handoff:2049
The respawn command only forwards LANES_WORKSTATION, but lane_control_root gives LANES_LANE_STATE_ROOT first priority and PROJECTS_ROOT is another resolver input. When either is configured in the shell that wrote the intent, tmux starts this supervisor with the server's environment, so it cannot resolve the just-written restart-intent.yaml and refuses before launching the replacement. Propagate the configured root selectors in the command string (and cover an actually executed respawn command, not only the logged tmux invocation).
Exit 2 is not the same as “no live holder” here: lanes-edit.sh canon_lane returns 2 when case-insensitive duplicate lane rows make the lookup ambiguous. Allowing this result proceeds to launch a second session without an unambiguous lane binding; only the documented no-holder result (8) should pass this gate.
8 | 2) : ;;
lane-handoff:739
The launcher path exports LANE_RESTART_OPERATION, but lane-start does not consume that variable, and the launcher invocation above does not receive --operation. Thus only the direct lane-start fallback enforces the operation at the child boundary; a launcher that delays or detaches can run without the supervisor's operation fence. Thread the operation through the launcher contract (or add an equivalent file-backed child claim) rather than relying on this unused environment variable.
This fresh-intent branch never binds the selected agent to the intent's agent field. AGENT was already allowed to come from --agent or the current row, so lane-start --operation <op> --agent codex ... can consume an intent recorded for Claude and launch the wrong agent, instead of refusing the conflict required by the restart contract. Compare the selected agent with the intent before proceeding.
fi
fi
fresh=1
fresh_why=" (restart intent ${ri_op:-none}, state $ri_state: the /ctx respawn)"
lane-start:3561
A lost operation fence must abort the launch. If the intent moves from this operation to a newer one while the pre-exec record work is in progress, this 7 branch only logs a note and continues to exec; the old child can therefore create a second session even though its supervisor can no longer mark it ready. Exit/refuse here before launching the stale command.
case "$ri_wrc" in
0) step "restart intent $ri_op: starting${ri_new:+, expected transcript $ri_new}" ;;
7) note "the restart intent moved under this launch (another operation owns lane $LANE now). The launch goes on — it is the one this pane was respawned for — but its supervisor will read the newer operation and will not mark this one ready." ;;
*) note "the restart intent could not be updated (set-restart-intent exited $ri_wrc), so the supervisor has no expected transcript to confirm against and will fall to its timeout. The launch is unaffected." ;;
lanes-edit.sh:9533
The reader treats a missing schema: exactly as UNKNOWN-SCHEMA, but this write guard only rejects non-empty mismatches. A schema-less or otherwise malformed intent can therefore be copied forward and stamped as schema 1, destroying the record that the read side correctly refuses. Reject every value other than the current schema, including empty.
sri_nows="$(lane_sidecar_field "$sri_f" schema 2>/dev/null || :)"
if [ -n "$sri_nows" ] && [ "$sri_nows" != "$LANE_RESTART_SCHEMA" ]; then
release_lock
die "lane $lane's restart intent is schema '$sri_nows' and this \`lanes-edit.sh\` writes schema $LANE_RESTART_SCHEMA. Nothing was written: taking a transition over it would copy forward the fields this version knows, drop the ones it does not, and stamp the file as an older schema — which is a newer tooling's record quietly replaced by an older one. Read it with a helper that knows that schema, or remove $sri_f once you know no restart is in flight." 2
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.
This migration step still says to install the supervisor as a command, but decision 10 and task 4.6 explicitly change the design to a mode of the already-installed lane-handoff with nothing new to install. Keeping this step makes the migration plan contradict the implementation and can lead an operator to look for a nonexistent installed command.
This scenario promises explicit finalize-or-stop actions, but the implementation only records INDETERMINATE and later exposes status/retry; tasks 6.4 and 6.5 are explicitly unchecked and no finalize, stop, cancellation, or generation-advancing command exists. Either implement those actions before making this requirement normative or change the scenario to describe the currently delivered status/retry behavior.
Refuse managed ownership, reserve preservation before writes, fence each child attempt and transcript, publish owned handoff stamps atomically, and retain indeterminate ownership while a child may live.
This design section says the prerequisite has not landed and defines the implementation as a sibling sidecar that must work without #97, but this branch is explicitly reconciled with landed PR #97 and contains its managed projection/lifecycle integration. Please rewrite this section as historical context or update it to the current authority and dependency model; otherwise it contradicts the implementation contract maintained in analysis.md.
Dependency description incorrectly treats PR #97 as unlanded
This dependency description still says PR #97 is in flight and not on main, while the reconciliation section in analysis.md and the current implementation explicitly integrate landed PR #97 (b1015f4). Leaving this as the active dependency model tells maintainers that the lifecycle is optional and that this sidecar must stand alone; update the proposal to describe the landed integration and keep only historical wording where appropriate.
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.
The new lane-holders output is documented as one line per live process, but this key includes the transcript UUID ($1 FS $4). A single live Claude process can have both its current and historical session records (the readiness code already handles that case), so two UUIDs for one PID are emitted as two holders. Consumers of this all-holder interface can then treat one process as an ambiguity; deduplicate on the live PID after record_is_live has validated its identity.
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.
Three files conflicted. Each one was resolved by keeping #121's text and
adding this branch's on top:
- lane-start: both sides added a section just before "6. launch". #121's
5c (the restart intent is written before exec) comes first, then 5e
(the daily report). The report therefore starts only after the intent
write, which can refuse the launch.
- lanes-edit.sh: both sides extended the unknown-subcommand list. The
list keeps #121's five new entries (lane-holders,
legacy-restart-check, publish-handoff, restart-intent,
set-restart-intent) and adds pathspec-check.
- tests/test_lane_helpers.sh: both sides added a section before
"nothing real touched". #121's supervised-restart section comes first,
then the #162 bytecode section.
Lane: openRepoTools-3
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#121 (supervised context restart) landed as 00971b9 while #171 was
open. It changed lanes-edit.sh, lane-handoff, lane-start,
docs/README-lanes.md and tests/test_lane_helpers.sh. This is a merge
and not a rebase because the branch is already pushed, and rewriting
it would need a force push.
One textual conflict: the unknown-subcommand refusal in lanes-edit.sh.
The resolution takes #121's list (lane-holders, legacy-restart-check,
publish-handoff, restart-intent, set-restart-intent) and appends this
branch's `worktrees`. The list still matches the dispatcher's 63 arms.
One semantic fix on top of #121's text: #121's new lane_state_rename
branch, taken when a lane has restart history, moves lane-state.yaml
and trees/ into the new name's control root. That move changes the
inventory the worktrees table mirrors, so it now sets
LANES_INDEX_NUDGE_INV like the other two move branches. #121's
restart-intent.yaml is not part of that inventory, so its writer
nudges nothing.
docs/README-lanes.md and tests/test_lane_helpers.sh merged without
conflict. This branch's changes to those two files and to lanes-edit.sh
are unchanged from fea9a29..f1e96c1, apart from the refusal list and
the nudge line above.
Lane: openRepoTools-3
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Main moved one commit since f85e618: #121, supervised manual ctx kept as
legacy compatibility, which changes lane-handoff, lane-start, lanes-edit.sh,
tests.yml and the lane-helper tests. No file is shared with this branch; the
merge gates the combination, because --install places those very tools.
Lane: openxfactory-5 (openXfactory-5)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
readylanding gate: runs tests-macos once before the squash
2 participants
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Merged 2026-10-06 at 09:38:31 UTC as
00971b929f586179828481e7cb34db181f386937, squash of tested headf13d32975d7457d662249385d23ee28a7f713c4conto mainfea9a29. Final landing checks passed: 1096 Linux tests, 1096 full macOS tests plus 20 focused macOS tests, 888 no-submodule tests / 208 expected skips, Windows, launch guards, Bash 3.2 parse and Sonar. The three runner-cancelled jobs passed on attempt 2; the original successful macOS gate was retained. No admin override was needed. Local focused integration validation passed 47 tests. Final ownership check found no open landing; all 62 review threads were resolved. T017 landing and T022 reconciliation validation are complete in this final review record. Feature branch and worktree are preserved. Exact-head Codex request received quota exhaustion, not a completed bot review; focused expert review provides separate evidence. Open follow-ups #158 and #159 remain open.Manual
/ctxcould resume the transcript it had just paused, lose its pane when launch failed, or allow an older restart attempt to publish into a retry. This change preserves a supervised legacy restart: the backend records the operation before respawn, launches a fresh Claude session with the preserved handoff, and confirms the intended live transcript.Brett's 2026-10-04 decision is legacy compatibility; refuse managed lanes. Managed or unreadable ownership refuses. Restart generation and attempt belong to the legacy intent; PR #97 lifecycle snapshots and feature 001's managed JSON ledger retain their separate authorities.
preparingbefore supervised preservation. Fence claims, child writes and finalizers by operation, generation and attempt. Each attempt reserves its transcript once.startingand indeterminate. Retry becomes available only after confirmed launch termination and holder absence. Reconcile TERM/HUP across claim publication; cooperatively stop and reap observers without signaling recycled numeric PIDs.specs/005-supervised-legacy-ctx/owns implementation tasks. This is manual legacy compatibility, not automatic rollover or managed lane implementation.Current head f13d329 includes four landing corrections:
preservation-only/ attempt 0 / no new transcript permits ordinary resume only with no operation/attempt tokens or fresh selectors and every holder confirmed absent. Exact state/mode/attempt/transcript/operation/generation are rechecked before binding changes, after ordinary selection and before exec. The failed intent remains unchanged; failed fresh launches remain supervisor-only and preparing stays blocked. Status and product contracts distinguish these failure classes.Shell parsing, error-level ShellCheck, Python compilation, diff checks and strict OpenSpec validation pass. The nine-role focused review has no remaining blocker. Added regressions cover actual aborted preparation resuming its recorded UUID, unchanged intent, live/unknown/old-helper holders, late/final holder and operation changes, invalid/malformed records, operation/attempt tokens and fresh selectors. 40 focused local tests passed at predecessor 6b92e35: 19 preparation recovery cases, 15 control/rename/PTY cases, and 6 checkout preflight cases. Each group ran through the serialized workstation wrapper. 21 focused local root/integration cases pass at fb28987 in 135.89 seconds through the serialized wrapper. The standalone local PTY wrapper stayed queued behind unrelated workstation tests and was stopped after the same regression passed in macOS CI; no standalone local pass is claimed. The preparation recovery finding is implemented, runtime-validated and resolved; later Copilot findings remain in #159 under the explicit two-round cap.
Current landing run 37365599854 is retrying runner-cancelled jobs on f13d329 after reconciliation with landed PR #164 (main fea9a29). The sole merge conflict was the two appended shell-suite sections; both original sections are retained byte-for-byte, with index act tests before supervised restart tests. Production code merged automatically. The shared resolver/restart sandbox now explicitly retains
LANES_INDEX=offafter its environment scrub, so test pushes cannot nudge an installed indexer. The index remains derived and non-gating: restart acts neither enable indexed reads nor consult their outputs. Five private restart helpers are unchanged from fd09e2d, and five generic diagnostic helpers match incoming main verbatim. Corrected test order and fixture isolation passed focused expert re-review. Bash parsing, error-level ShellCheck, Python compilation, staged diff checks and strict OpenSpec validation pass. The serialized local root/managed/ordinary-launch run passed 47 tests / 1049 deselected in 167.78 seconds after waiting behind unrelated workstation pytest.The current head passed 1096 full macOS tests in 5522.19 seconds, plus 20 focused macOS tests in 189.35 seconds, completing at 21:27:50Z. Guard, parse and Sonar pass. The initial Linux, no-submodule and Windows jobs were canceled before any test step because GitHub could not allocate hosted runners. After the workflow finished, failed-job rerun was accepted at 21:39:22Z as attempt 2; only those three jobs are rerunning, and the successful macOS gate is retained. These canceled jobs are not claimed passes. Main remains fea9a29; final merge still requires the retry results.
The immediately preceding fd09e2d head passed all CI: 1047 Linux tests in 1712.55 seconds, 1047 macOS tests in 6015.46 seconds (plus 20 focused macOS tests in 220.24 seconds), and 839 no-submodule tests / 208 expected skips in 2372.68 seconds. Windows, guard, Bash 3.2 parse and Sonar also passed. #164 landed before #121 merged, so the new combined head requires its own landing gate; predecessor passes are historical evidence.
Fresh exact-head Codex review was requested for f13d329; the bot reported quota exhaustion. No completed exact-head bot review is claimed. The focused local expert panel has no remaining blocker. P1 4186306909 is implemented, runtime-validated and resolved.
Historical predecessor validation at 6b92e35: full Linux 1028 passed in 2147.82 seconds; no-submodule 820 passed / 208 expected skips in 2264.19 seconds; Windows, guard, Bash 3.2 parse and Sonar pass. Its full macOS run failed 1 fixture / 1027 passed in 6676.28 seconds. The required Codex request at that predecessor received a quota-exhaustion response; it is not a completed review. The older 774d189 macOS gate failed 14 cases / 993 passed, prompting the original portability correction. Prior-head results do not substitute for this head's pending landing gate.
Review follow-ups follow AGENTS.md's explicit two-round Copilot cap:
Brett released the merge hold on 2026-10-05. PR #97 and PR #164 have landed and this head is reconciled with both. The
readylabel remains applied so this updated head reruns the full macOS landing gate; squash merge follows only after that gate, other checks pass. The exact-head Codex review is requested explicitly; quota-limited bot responses will be recorded without claiming a pass. The completed expert panel provides separate review evidence. Preserve the feature branch and worktree. No installation or real-session canary is part of this landing. The protocol's supervisor mechanism remains documented as an explicit deviation.Closes #94