Repository navigation
The lifecycle's remaining fail-open reads: an unreadable register becomes 'no holder', an unreadable sidecar becomes no tree, and two git reads become fabricated values #113
Description
Four reads in the crash-consistent lifecycle still convert a failure into an answer, which is the rule (R22, Amendment 7(d): a read that failed is never an answer) the capability on #97 exists to enforce. Each is one || : or one continue.
1. The holder ids — an unreadable register becomes "no holder" (lane_reconcile):
lrc_ids="$( { session_ids_of_lane "$lrc_lane" 2>/dev/null || :
session_ids_local_of_lane "$lrc_lane" 2>/dev/null || :; } | awk 'NF && !seen[$0]++')"Both reads are swallowed, so a register or local-row read that FAILED comes out as an empty id set. live_holder answers 8 for an empty set — this lane records no session, nothing can be live — and the verdict table then reads RUNNING + 8 as ungraceful-stop and SWAPPING + 8 as interrupted-swap. A crash is pronounced on a liveness question nobody answered. live_holder's own contract already has three answers (0 a holder, 8 none, anything else the records could not be read) and lane_reconcile already maps its * to indeterminate; what is missing is the same distinction one read earlier.
2. An unreadable tree sidecar is dropped (lane_trees_list):
for ltl_f in "$ltl_root"/trees/*.yaml; do
[ -r "$ltl_f" ] || continueAn existing record nobody can read and a record that is not there go into the same silence. The tree it names can then no longer be classified missing or possible-loss — every stored observation of it is gone — and it can be rediscovered only as unmanaged; where it is the lane's ONLY sidecar the function returns 8, this lane owns no worktree, about an inventory nobody could read.
3. git config --get branch.<b>.remote is unguarded (lane_tree_now):
ltn_cfg="$(git -C "$ltn_p" config --get "branch.$ltn_raw.merge" 2>/dev/null)" || ltn_crc=$?
case "$ltn_crc" in 0|1) : ;; *) return 3 ;; esac
if [ -n "$ltn_cfg" ]; then
ltn_rem="$(git -C "$ltn_p" config --get "branch.$ltn_raw.remote" 2>/dev/null || :)"
ltn_u="${ltn_rem:-.}/${ltn_cfg#refs/heads/}"The merge read one line above asks git for its status and returns 3 for anything but found or not found; the remote read beside it does not. A read that failed becomes an empty remote, and ${ltn_rem:-.} then FABRICATES a local upstream — ./<merge> — which is filed in the sidecar as an observation, with unknown unpushed beside it.
4. git worktree list --porcelain is swallowed (lane_reconcile, the unmanaged/stale sweep):
done <<EOF
$(git -C "$lrc_dir" worktree list --porcelain 2>/dev/null || :)
EOFAn owning checkout whose registrations cannot be read is treated exactly as one with no registrations: every stale registration and every unmanaged tree in it is omitted, while the report can still print a resumable verdict. The estate's own resume then fails on the stale registration the report said nothing about.
Why this is filed rather than fixed on #97
Copilot review rounds are capped at two per pull request (Brett Heap's ruling of 2026-09-16); #97 is at round six, and it took only the two findings of that round that are safety holes it could not land with — an unreadable lifecycle snapshot read as this lane has no snapshot, and set-lane-tree writing outside the lane mutex. These four are the same class and none is new to that branch: 1, 2 and 4 are unchanged since the capability's first commit, and 3 is the one read round 5's sweep of lane_tree_now did not reach.
What's open
Each wants its own distinction kept rather than a new mechanism: an id set that could not be read must not reach live_holder as an empty one; an unreadable sidecar wants a row of its own that lane-reconcile reports as indeterminate (its file name is tree_id_for of the path, so the id is knowable without reading it); the remote read wants the case its sibling already has; and the registration sweep wants the command's status captured, with a verdict that refuses to read as a clearance when the sweep could not be made.
Filed from Copilot round 6 on #97 — #97 (comment), #97 (comment), #97 (comment), #97 (comment) — and named in openspec/changes/add-crash-consistent-lane-worktree-recovery/tasks.md section 7.
Activity
brettheap commentedon Sep 16, 2026
CLAIMED — lane openRepoTools-3, session 4135b2c9-34a6-47e3-a156-5adebb632fae@Eagle, 2026-09-16T13:05:21Z, for #113
Logged in
lanes/log/openRepoTools-3.mdat7e42cff54cab9bf9b946e7544e3bcc9b224a101b.The three reads (lane-collision-protocol Rule 1):
openRepoTools#91: the two safety holes of the sixth round — a snapsho…
Take Codex's four inventory findings on ec9847e
Crash-consistent lane worktree recovery: a lane now says WHERE its se…