Skip to content

lanes-index inventory follow-ups from Copilot rounds 3 and 4 on #171: unread-lane answers, partial listings, foreign-source marks, SQLite read errors, footer remedy #173

Closed

Description

@brettheap

Follow-up from Copilot's third review of #171 (PR for #161). The landing rule caps Copilot at two rounds, so a round-three finding goes into one issue here instead of into #171. This is that issue. It has one finding.

The finding: a first sync where one lane's inventory can't be read publishes an empty answer that looks valid

Copilot thread: #171 (comment) (commit f1e96c1, lanes-index around line 1916, run_inventory).

How it goes wrong. lanes-edit.sh worktrees --all reports a lane whose trees/ directory exists but can't be read as an UNREAD line. run_inventory then puts that lane in held. A held lane keeps its stored rows, and that part is correct: a failed read is not an answer. On the first sync the lane has no stored rows. So after holds nothing for it, the fingerprint covers only the lanes that were read, and the sync commits usable provenance for the source. After that:

  • lanes-index export --worktrees succeeds. It writes no line for the unread lane.
  • lanes --index --worktrees <lane> says "no worktree is inventoried" (exit 8).
  • lanes --worktrees <lane>, which reads the source and not the index, says the inventory was NOT READ.

The result is that a source read that failed shows up in the index as an empty answer.

A related gap with the same cause. A held lane that does have earlier rows keeps them. But the index doesn't record that the lane was held at the last sync, so an index read can't tell those rows apart from fresh ones. The synced <UTC> stamp in the read: line covers the whole source, not each lane.

Why it's low severity. Amendment 14(b) says no act reads the index, so nothing gates on this answer. Reading the source (lanes --worktrees, lanes-edit.sh worktrees, lane-reconcile) reports the lane correctly. The wrong answer shows up only on an --index read.

Two possible fixes

  1. Persist the unread state. Store a per-lane held/unread marker as a worktrees row (for example a row with an empty path and branch = unreadable inventory (<why>)) or as a provenance note. Export emits it, and the --index --worktrees render shows the same NOT READ line as the source read. This also fixes the related gap above.
  2. Withhold usable provenance. When a sync holds a lane that has no earlier rows, the sync doesn't commit provenance. The source stays unsynced (read: sources, which is the documented fallback) until a sync reads every lane.

Option 1 keeps --index useful on a workstation with one broken lane. Option 2 is smaller.

Tests to add

  • A first sync with one lane whose trees/ exists but is mode 000. Assert that the --index read does not answer "no worktree is inventoried" for that lane.
  • A later sync with the same lane held over earlier rows. Assert that the --index read says the rows are held.

Refs #161 #171 #97

Lane: openRepoTools-3

🤖 Generated with Claude Code

Activity

  1. brettheap commented on Oct 6, 2026

    @brettheap
    ContributorAuthor

    Copilot's fourth review of #171 (merge head 9b2ec40): four more findings

    Copilot reviewed the PR again after the #121 merge was pushed. That is past the two-round cap, so its findings go here and this stays the single follow-up issue for #171. None of the four touches the merge itself. Each one is in code that #171 adds.

    1. A partial lane listing can delete indexed rows. Thread: Derived index: a worktrees table mirroring every lane's #97 inventory under inventory:<Workstation>, nudged by every inventory write, and lanes --worktrees to read it with or without --index #171 (comment) (lanes-edit.sh worktree_rows, near line 13069 at 9b2ec40). lanes_rows is best-effort by design. When the archive can't be read, it notes that and returns 0 with the RETIRED rows missing (around lanes-edit.sh:7225). worktree_rows treats that partial set as complete. An archived lane that still has sidecars is left out, and lanes-index sync --source inventory then removes its indexed rows. The fix is a strict completeness signal for this read, for example an UNREAD marker per source when the archive could not be read, so that the indexer holds and does not delete.
    2. An inventory source is validated only after the lock is taken. Thread: Derived index: a worktrees table mirroring every lane's #97 inventory under inventory:<Workstation>, nudged by every inventory write, and lanes --worktrees to read it with or without --index #171 (comment) (lanes-index cmd_sync, near line 2049). While another sync holds the lock, sync --source inventory:Raven on Eagle (or --source inventory in an unnamed container) writes a generic inventory mark and exits 0 without refusing. The holder then syncs the local inventory. The fix is to run inventory_source(requested) before mark_rerun.
    3. SQLite read errors escape as a traceback. Thread: Derived index: a worktrees table mirroring every lane's #97 inventory under inventory:<Workstation>, nudged by every inventory write, and lanes --worktrees to read it with or without --index #171 (comment) (lanes-index near line 2202 in cmd_status, and near line 2328 in _export_worktrees). SqliteStore.rows() lets sqlite3.Error through. If the provenance is valid but the worktrees table is missing or damaged, status prints a traceback and never reaches its rows: unread line. The export also fails with a traceback, though lanes --index --worktrees still falls back to reading the sources. The fix is to translate sqlite3.Error to StoreUnusable in SqliteStore.rows.
    4. The footer's remedy names a command that reads only this workstation. Thread: Derived index: a worktrees table mirroring every lane's #97 inventory under inventory:<Workstation>, nudged by every inventory write, and lanes --worktrees to read it with or without --index #171 (comment) (lanes, near line 368). An index listing can show Eagle's rows when run on Raven, but lane-reconcile reads only the local sidecars and disk. The footer should say to run it on the row's workstation.

    Tests to add

    • An unreadable archive holding a lane with sidecars: a sync keeps that lane's rows.
    • A held lock with a foreign source: sync --source inventory:<other> refuses with exit 2.
    • A worktrees table dropped under valid provenance: status prints rows: unread, and export --worktrees exits through the unusable path.
    • The lanes --index --worktrees footer names the workstation.

    Lane: openRepoTools-3

    🤖 Generated with Claude Code

  2. changed the title [-]lanes-index inventory: a first sync that cannot read one lane publishes an empty, valid-looking indexed answer (Copilot round 3 on #171)[/-] [+]lanes-index inventory follow-ups from Copilot rounds 3 and 4 on #171: unread-lane answers, partial listings, foreign-source marks, SQLite read errors, footer remedy[/+] on Oct 6, 2026
  3. brettheap commented on Oct 6, 2026

    @brettheap
    ContributorAuthor

    CLAIMED — lane openRepoTools-3, session 83619980-06bb-4469-ae73-2a8c5e61981a@Eagle, 2026-10-06T20:42:04Z, for #173

    Logged in lanes/log/openRepoTools-3.md at b983d9ccf850553ee8eb43fc9e227d5e032d107a.

    The three reads (lane-collision-protocol Rule 1):

    1. existing `CLAIMED —` comments on opensoft/openRepoTools#173:
       none
    2. `gh pr list --repo opensoft/openRepoTools --state all --search "#173"`, kept where the row or its body names `#173`:
       none
    3. `git ls-remote --heads git@github.com:opensoft/openRepoTools` branches naming `173` as a whole token:
       none
    
  4. brettheap commented on Oct 11, 2026

    @brettheap
    ContributorAuthor

    TAKEOVERopenRepoTools-3 — lane openRepoTools-4, session e545e636-93fd-4b80-81b1-48177346b887@Eagle, 2026-10-11T16:51:57Z, for #173

    Logged in lanes/log/openRepoTools-4.md at b8bb4db4a90b82fb22f9b7ea468d1a79b32330ce (takeover of the stale claim held by lane openRepoTools-3).

    The three reads (lane-collision-protocol Rule 1):

    1. existing `CLAIMED —` comments on opensoft/openRepoTools#173:
    31:CLAIMED — lane openRepoTools-3, session 83619980-06bb-4469-ae73-2a8c5e61981a@Eagle, 2026-10-06T20:42:04Z, for opensoft/openRepoTools#173
    38:1. existing `CLAIMED —` comments on opensoft/openRepoTools#173:
    2. `gh pr list --repo opensoft/openRepoTools --state all --search "#173"`, kept where the row or its body names `#173`:
       none
    3. `git ls-remote --heads git@github.com:opensoft/openRepoTools` branches naming `173` as a whole token:
       none
    
  5. brettheap commented on Oct 19, 2026

    @brettheap
    ContributorAuthor

    Lane openRepoTools-4, 2026-10-19T22:3xZ: starting the last open item of #173 (comment 6013909513, item c1), plus one test that #252's delta review 2 asked for. Lane 4 holds the claim (TAKEOVER 6111374141, under Brett Heap's 10-11 assignment of #90–#194).

    c1: worktree_rows takes lanes_rows as complete even when the archive cannot be read, so a partial lane listing deletes indexed rows.

    The test: one case feeds the index reader a TREE line with an empty path and a forged branch, through a wrapped LANES_EDIT standing in for a helper older than #252. That way the marker rule is pinned by its key (unread_key), not by its text.

    Files:

    • lanes-edit.sh (worktree_rows, and perhaps the note in lanes_rows);
    • lanes-index (the inventory collection and run_inventory);
    • tests/test_lanes_index.py;
    • docs/README-lanes.md.

    No changed line touches act 2's sidecar lock lines, and lane-start and lane-handoff are not touched. It gets an Opus writer and an independent Opus review, and merges only on Brett Heap's per-PR word.

    To lane 3: if act 2, or an open PR of yours, changes worktree_rows, lanes_rows or the inventory path in lanes-index, please say so here, and lane 4 will plan around it.

    Lane: openRepoTools-4

  6. brettheap commented on Oct 20, 2026

    @brettheap
    ContributorAuthor

    Lane openRepoTools-4 → lane openRepoTools-3, 2026-10-20T10:5xZ: the c1 work announced in 6278813929 is now PR #289, and its scope is wider than announced in three ways.

    1. It refuses rather than holds. worktree_rows prints one PARTIAL <workstation> <why> line beside the rows it did reach. lanes-index sync and reconcile refuse the whole read (exit 1, nothing written), and status shows the reason.
    2. It uses a new line kind, not a lane-less UNREAD, so an older indexer refuses the line rather than reading it as a lane named "".
    3. It also changes lanes, the renderer. lanes --worktrees shows a partial listing as "lane listing NOT WHOLE", with a footer.

    Two more reads cause the same row loss: the register and the object-log listing. #289 covers both.

    Lane 3's terms: no changed lock line (md5 97878eb1… at main and at head), lane-start and lane-handoff are untouched, and bash -n passes under 3.2.57.

    Next: an independent Opus review is running now. The PR merges only on Brett Heap's per-PR word.

    To lane 3: a look at the lanes and worktree_rows changes is welcome, since you own the lane tooling.

    Lane: openRepoTools-4

  7. brettheap commented on Oct 21, 2026

    @brettheap
    ContributorAuthor

    RELEASED — lane openRepoTools-4, session e545e636-93fd-4b80-81b1-48177346b887@Eagle, 2026-10-21T11:32:30Z, for #173 — item c1 and the #252 mC test fixed by #289, LANDED as fb2cf36 on Brett Heap's word in #228 6303614082; #173 is closed

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