Skip to content

The handoff's READY line counts polled trees as recorded, and a stale registration is suppressed whenever a sidecar names the same path #117

Description

@brettheap

Two places where the recovery-facing output claims more than it knows.

1. The READY line counts the trees that were POLLED, not the sidecars that were WRITTEN

lane-handoff's poll_writer increments before either the observation or the inventory write is known to have worked:

	writer_count=$((writer_count + 1))
	...
	if [ -n "$lc_on" ] && [ "$pw_orc" = 0 ]; then
		LANES_NO_FETCH=1 "$LANES_EDIT" set-lane-tree "$lane" "$pw_d" \
			... >/dev/null 2>&1 ||
			note "the worktree inventory entry for $pw_d could not be written — ..."
	fi

and the READY line spends that count on a different sentence:

	say "  inventory: $writer_count worktree(s) recorded — lanes-edit.sh lane-trees $lane"

A tree whose observation refused (lane-tree-now exit 1, a checkout git cannot be read through) files no sidecar at all, and a tree whose set-lane-tree was refused (the fence, an unknown schema) files none either — both are still counted as recorded. The note is on stderr among the handoff's other notes; the READY block is the summary a person reads when they are recovering, and it says the inventory holds N entries that lane-trees does not have.

2. A stale registration is suppressed whenever a sidecar names the same path

lane_reconcile seeds the seen-set from every sidecar before the registration sweep:

    [ -n "${lrc_p:-}" ] && lrc_seen="$lrc_seen $lrc_p $(lane_real_path "$lrc_p") "

and the sweep skips anything already in it:

      case "$lrc_seen" in *" $lrc_wp "*|*" $lrc_wpr "*) continue ;; esac
      if [ -d "$lrc_wp" ]; then
        ... unmanaged ...
      else
        ... stale-registration ... `git -C %s worktree prune` is a person's act

So a tree that WAS inventoried and whose directory has since been removed is reported only as missing or possible-loss — the classification the sidecar branch gives it — and never as stale-registration, because the sidecar named the path first. git still holds the registration, the report omits the git worktree prune remedy, and the estate's resume refuses that leg for a stale registration the recovery report said nothing about.

These two pull in opposite directions and the tension is the reason this is filed rather than patched: the seen-set exists so that ONE tree is named ONCE (612ba5c, the symlinked-path defect where every tree was reported twice), and the registered-but-gone condition wants to be said about a path a sidecar has already spoken for.

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 took only the two safety holes it could not land with. Neither of these misreports work as clean: the first over-counts a summary line whose detail is a command away, and the second names a real tree under the wrong heading.

What's open

For the count: track the inventory writes that succeeded and say N of M polled, so the number and lane-trees agree. For the registration: decide the registered-but-gone case BEFORE the path is deduplicated, and let one tree carry both facts on one row (possible-loss AND a live registration, with the prune named) rather than choosing between two rows and one heading.

Filed from Copilot round 6 on #97 — #97 (comment) and #97 (comment) — and named in openspec/changes/add-crash-consistent-lane-worktree-recovery/tasks.md section 7.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions