Repository navigation
A lane listing that is not whole no longer removes indexed worktree rows: the inventory read says PARTIAL, lanes --worktrees prints it NOT WHOLE, and lanes-index writes nothing over it; an older helper's tree with no path stays a tree (#173 item c1, #252 delta review 2) - #289
Merged
Merged
Conversation
… and an older helper's tree with no path and a marker's branch stays a tree (#173 item c1, #252 delta review 2) Item c1 of #173 (Copilot's fourth review of #171): `worktree_rows` takes `lanes_rows --all --closed` as whole, and that listing only notes on stderr a register or an archive it could not read - and says nothing at all of an object-log listing it could not read. A lane named by the failed read alone is then a lane with no trees, and `lanes-index sync --source inventory` removes its rows. These tests are written before the fix and fail at 21e0829 on the assertion under test: - `test_a_lane_listing_that_is_not_whole_removes_no_row`, four cases: the archive, the register (the inventory's suspected sibling, real: repoC-1's only row is the register's), the object-log listing, and all three - which left the listing empty, so the helper said "none" and the sync removed every row. A published object is made unreadable by moving its loose object aside in the clone. - `test_a_lane_whose_log_could_not_be_read_keeps_its_rows`: a published log git cannot read gives the listing no `dir`, the control root falls from rung 2 to rung 3, and the lane's rows are removed. - `test_a_listing_whose_log_warnings_could_not_be_kept_is_not_whole` and `test_an_unlistable_log_directory_with_no_origin_is_a_partial_listing`: whether a log failed is not known without the warnings file, and under `LANES_NO_GIT=1` the logs are named by listing the local directory. And the SHOULD of #252's delta review 2: `test_an_older_helpers_tree_with_no_path_and_a_markers_branch_is_a_tree` feeds the reader, through a wrapped `LANES_EDIT` standing in for a helper older than #252, a TREE line with an empty path and a branch that reads like the unread marker's. It passes at 21e0829, where a marker is its key, and fails under mutant mC, 5bf29d9's rule (no path and the marker's branch). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ows: the inventory read says PARTIAL, lanes --worktrees prints it NOT WHOLE, and lanes-index writes nothing over it (#173 item c1) `worktree_rows` read the lanes through `lanes_rows --all --closed`, whose names come from the register's rows, the archive's rows and the object logs' file names, and whose control roots come from each log's `dir`. A listing a person reads may not refuse, so where one of those reads failed it noted it on stderr - the log listing not even that - and listed the rest; the inventory took that as whole and `lanes-index sync --source inventory` removed the rows of every lane it could not name. With all three unread the listing was empty and the read said 8, "none": every row was removed. For the whole listing (never one named lane), `worktree_rows` now asks the register (before the listing, so a read that succeeds is the cached text the listing reads), the archive, the published log listing or, with no origin, the log directory, and every published log (out of the warnings the listing's own read of them left; where those could not be kept, whether one failed is not known). Any failure is ONE `PARTIAL <workstation> <why>` line beside the rows it did reach, and an empty listing over a failed read is that line alone, never 8. `lanes --worktrees` prints it as the lane listing NOT WHOLE, with a footer. `collect_inventory` refuses a read that carries it, so `sync` and `reconcile --source inventory` write nothing, exit 1 and record why; the table stays the last whole read, dated by its `synced` stamp. Refused, not held: holding only the lanes it could not name needs a marker for each, one for the listing (a first sync has no rows to hold) and a one-lane `--index` read that knows of it, or the index again answers "no worktree is inventoried" for a lane it never read. A new line kind, not a lane-less `UNREAD`: an indexer older than this reads any four-field `UNREAD` as a lane - it would hold a lane named "" and still remove the rest - and refuses a line kind it does not know. Lock lines (`acquire_lock`, `release_lock`, `lock_try`, `LOCK_HELD`) unchanged; `lane-start` and `lane-handoff` untouched. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Sorry @brettheap, you've used your own review budget of 250,000 diff characters for the last 7 days. You can request another review in 1 day and 9 hours by commenting |
Reviewer's GuideThe PR makes lane-listing completeness explicit, prevents partial inventory reads from deleting or modifying indexed rows, renders the condition to users, and adds broad regression coverage including legacy-helper compatibility. Sequence diagram for refusing a partial lane inventory syncsequenceDiagram
participant Caller
participant WorktreeRows as worktree_rows
participant Register
participant Archive
participant Logs as ObjectLogs
participant Inventory as lanes-index
Caller->>WorktreeRows: worktree_rows()
WorktreeRows->>Register: register_text_checked()
WorktreeRows->>Archive: archive_text()
WorktreeRows->>Logs: git ls-tree or ls log directory
WorktreeRows->>WorktreeRows: lanes_rows --all --closed
WorktreeRows-->>Inventory: rows plus PARTIAL workstation reason
Inventory->>Inventory: collect_inventory()
Inventory-->>Caller: exit 1, nothing written
Flow diagram for whole and partial lane listingsflowchart TD
A[Read lane listing] --> B{All required reads succeeded?}
B -->|Yes| C[Emit lane rows]
C --> D[Sync inventory changes]
B -->|No| E[Emit rows reached plus PARTIAL]
E --> F[Keep last whole index unchanged]
F --> G[Report NOT WHOLE to users]
File-Level Changes
Assessment against linked issues
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
This was referenced Oct 20, 2026
…hecked, a log list that fails after the check removes no row, the register is asked before the listing, an r-- log directory with no origin is not whole, a dry run refuses a partial listing, and the index read says its last sync failed (#173 item c1, the review of #289) The independent review of #289 at 03b6299 found the checks and the listing's reads to be separate reads (SHOULD-1, probes P2 and P11), no test pinning the register's check before the listing (SHOULD-2, mutant mR), an `ls` that lists an r-- log directory (N1), no word of a refused sync in the `--index` read (N2) and no test of a dry run's refusal (N4). Each is a test here, and the code is still 03b6299's: - the archive readable for the check and not after it: repoZ-1's row is removed at 03b6299; - the list of the logs failing on the read after the check, and on every read after it: repoB-1, found through its log's `dir` alone, loses its row; - the register's first read failing and every later one reading: refused, as it already is at 03b6299 - the test that kills mR; - the no-origin log directory at mode 400 beside mode 000; - `reconcile --dry-run` over each partial listing exits 1; - `lanes --index --worktrees` after a refused sync names its last error. A `git` shim on PATH for one call fails only the counted calls a case names, which `_unreadable` cannot do. And the hung-indexer test waits for `.argv` as its sibling does: the stub writes `.stdin` first, so `.argv` could be read before it was there (the race the review traced at d2c26ae). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…vents say a list of the logs they could not make, an r-- log directory with no origin is not whole, and the index read names its last sync's error (#173 item c1, the review of #289) The review of #289 at 03b6299 (SHOULD-1): `worktree_rows` asked the archive and the list of the logs, and the listing then read both again - the archive four more times, the list twice (`known_lanes` for the names, `remote_log_events` for the events every `dir` comes from). A read that failed only after the check thinned a listing taken as whole: repoZ-1's row, or every row found through a log's `dir`, was removed (probes P2 and P11). - (b) The check's reads are the listing's. Where the archive and the list of the logs read, `worktree_rows` pins their text (`PIN_ARCHIVE`, `PIN_LOGS`) for the listing alone and drops it after: `archive_text` and `known_lanes` hand it back instead of reading again. Not a cache kept for the process: `add-row` rescans the archive after its rebase, and must read it as it then stands. - (a) `remote_log_events` says a list of the logs it could not make (`unlisted logs: ...`) instead of reading as no logs, and `worktree_rows` reads that line back out of the events' warnings, as it reads "unreadable log": the events are built once per process, so it speaks for the read every `dir` came from. The reason is the check's own, said once. - (c) docs/README-lanes.md says each read is made once for the listing, and what is still read twice: with no origin, the log directory and its files; and the events' own question whether origin/<branch> is there. - N1: with no origin, the log directory is asked with `-d`, `-r` and `-x`, as the trees' directory is: `ls` listed an r-- one whose files no glob could then open. - N2: `lanes-index export --worktrees` writes this workstation's last sync error as a fifth field of a source's meta line, and `lanes --index --worktrees` prints it after `synced <UTC>` as `(its last sync failed: <UTC> <why>)`. An older reader ignores the field. The tests are ca6b1b0's. No changed line names a lock function or `LOCK_HELD`, and `lane-start` and `lane-handoff` are untouched. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Main moved from this branch's base 21e0829 by nine commits: lane-handoff's lifecycle read (677acc0), #228's release series (c82578f to 234b670), #271 (f18b818), #284 (90eed74) and #265 (a42946e). Of this PR's files, only lanes-edit.sh (lane_reconcile's leg sweep) and docs/README-lanes.md (the triad section) changed there, away from its hunks, and the merge is clean. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…which SonarCloud's quality gate counted as 28 duplicated lines of new code (#289) `test_a_log_list_that_fails_after_the_check_removes_no_row` took the 14-line setup of `test_a_lane_whose_log_could_not_be_read_keeps_its_rows` whole: repoB-1 resumed in a checkout of its own, its tree under that checkout's parent, and a sync with no override naming a control root. SonarCloud's gate on #289 at cef454e failed on it (4.9% duplication on new code, 3% allowed). The setup is now `_a_lane_found_through_its_log`, which both tests call; neither test's assertions change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ame the last sync's error that the line now carries (the review of #289, N2) The file's header and the `worktrees` dispatch both quote the stderr line `read: index (<store>) at inventory:<ws> synced <UTC>`. Since d26658d it is followed by `(its last sync failed: <UTC> <why>)` while this workstation's last sync of that source wrote nothing, as docs/README-lanes.md says. Comments only. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Oct 20, 2026
…s no row, the lane whose log sorts last is named, and the index read labels what it shows the last error (review r2 of #289, SHOULD-A, NIT-2 and NIT-1) The delta review r2 of #289 at ddf7f6e found a lane's `dir` read again for each lane with trees (SHOULD-A, probe C1). `lane_trees_list` and `lane_state_read` work the control root out through `lane_control_root` with no `dir`, which reads the lane's log a second and a third time, and a `git show` that fails there is thrown away. The review also found no test with a log-only lane that sorts last (NIT-2, mutant mNoSentinel), and an `--index` read line saying "its last sync failed" where a refused `reconcile --dry-run` records the error too (NIT-1). Each is a test here, and the code is still ddf7f6e's: - repoB-1 is found through its log's `dir` alone, with a lifecycle snapshot there, and synced. A `git` shim then fails only the second `show` of its log. At ddf7f6e that is `lane_trees_list`'s read: the root falls to `$PROJECTS_ROOT/.lane-state` and the sync removes the row. - repoY-1, a lane with a log alone that sorts after repoM-2.md, is named by the listing and indexed. This passes at ddf7f6e, and it is the test that kills mNoSentinel. - The N2 test looks for `(last error: <UTC> <why>)`, the name `status` gives what is recorded. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…t, so a later read of the lane's log that fails removes no row, and the `--index` read calls what it shows the last error (review r2 of #289, SHOULD-A, NIT-1 and NIT-3) Review r2 of #289 found the control root worked out three times for each lane with trees (SHOULD-A, probe C1). `worktree_rows` hands `lane_control_root` the listing's own `dir`, but `lane_trees_list` and `lane_state_read` called it with the lane alone, and it read the lane's log again for each. `lane_log_events` throws a failed `git show` away, so the root fell to `$PROJECTS_ROOT/.lane-state` and `lane_trees_list` answered 8. The lane read as one with no trees: `worktrees --all` said nothing, and `lanes-index sync` removed its rows. Both now take an optional second argument, `lane_control_root`'s own payload. `worktree_rows` passes all three the one payload it builds from the listing's `dir`. Every other caller passes the lane alone, and `"${2-}"` hands `lane_control_root` the empty payload it had before. Those callers are `lane_state_of`, `lane_reconcile` and the `lane-state` and `lane-trees` verbs, and through them `lane-start`, `lane-handoff`, `lane-end` and the lifecycle verbs. With no `LANES_LANE_STATE_ROOT`, a whole `worktrees --all` now shows a lane's log once instead of three times, and lists the logs twice instead of four times (review r2's probe B0). NIT-1: the `--index` read's fifth field is `status`'s `last error`, which a refused `reconcile --dry-run` records too, so it is now labelled `(last error: <UTC> <why>)`. What a dry run records is unchanged. NIT-3: docs/README-lanes.md said each read is made once. It now says the list of the logs is made twice, and that a lane's `dir` is read once. The header and dispatch comments, `lanes-index`'s export comment and the README's `--index` paragraph say the same. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
This was referenced Oct 20, 2026
brettheap
pushed a commit
that referenced
this pull request
Oct 21, 2026
…rea, and add the lines for #263, #289, #294 and #296, the changes after a42946e (#228) `docs/release-notes/v1.1.0.md` takes the fixes of lane 3's review of d8a349d (#293 comments 6314185715 and 6314529807, the second of which replaces three of the corrected texts of the first) and the lines for the changes after a42946e. The review's fixes: - Line 45 (#255, #271) no longer says that `lane-reconcile` and `lane-handoff` read a dependency nested in a leg: only the sweep and `lane-end` do. It says that a leg directory this account cannot search is unreadable and never `absent`, that a nested dependency is unreadable to the sweep and `lane-end` too, and that the sweep still reads a declared leg beneath such a directory as `absent` (#272, open). It also says NOT POLLED where the tool does. - Line 46 (#280, #283): an `awk` exits, it does not return, and the sentence on a status of 0 or 8 is gone. - Line 61 (#214): the fence never checks whose a local commit is, only that it adds or changes a register or handoff file. - The `<other-changes>` item counts 44 of the 53, because the openRepoShape pin's line (#233) is in the list, and the other 9, not 43 and 10. The milestone item names #247 and lists the six entries of 2026-10-20. - #209 is not tests-only: its `-e` fixes `lanes`' stderr filter under macOS's BSD grep, so it moves from the test suite to the lane area, and its one line there carries its test changes too. It is cited once. The lines for the changes after a42946e, each in its area and worded from its squash commit and description: #263 (d9065df) and #289 (fb2cf36) under the register and `lanes-edit.sh`, #294 (acc89ea, which closes #292) under `lane`, `lane-start`, `lane-end` and the name guard, and #296, which pins every Ubuntu runner to ubuntu-24.04, under the test suite and its checks. #296 has not landed yet: lane 3 lands it right before #293. The `<other-changes>` item says the lines were added on 2026-10-21 and are not in its counts, and the placeholder stays for #293 itself. Not touched: lane 3's optional sentence on #271 and its NIT on the tag. Lane: openRepoTools-2 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
brettheap
added a commit
that referenced
this pull request
Oct 21, 2026
… 1.1.0 and list, by area and from the squash titles of aaa7bc8..a42946e, what else changed on main since v1.0.0 (#228) (#293) Part of #228. It brings `docs/release-notes/v1.1.0.md` up to date on main: first on `a42946e`, as lane 3 asked on Brett Heap's word (#228 comment 6303608345, the section for lane openRepoTools-2, task 1), then with lane 3's review of `d8a349d` (comments 6314185715 and 6314529807 on this pull request), with the lines for the three changes that landed after `a42946e`, and with the line for #296, which landed right before this pull request. It is one file, changed in two commits (`d8a349d` and `bebb77d`), 59 insertions and 4 deletions against main. Lands last before rehearsal D's freeze; lane 3 reviews and merges it (#228 6303608345) **What changed** - **Lane 3's review is applied,** in the second commit: - **The line on #255 and #271** no longer says that `lane-reconcile` and `lane-handoff` read a dependency nested in a leg, since only the sweep and `lane-end` do. It says that a leg directory this account cannot search is unreadable and never `absent`; that a dependency nested in a leg whose directory, or one above it, it cannot search is unreadable to the sweep and `lane-end` too; and that one known gap remains, #272, where the sweep reads a declared leg beneath such a directory as `absent`, so `lane-end` does not hold on it. It also says NOT POLLED where the tool prints it, and it says that the item closes two gaps in #246, where it said "both gaps" with nothing before it to refer to. - **The line on #280 and #283:** an `awk` exits and does not "return", and the sentence on a status of 0 or 8 is gone, because a reader of the notes cannot act on it. - **The line on #214:** the fence passes a local commit only when it adds or changes a register or handoff file, and never checks whose it is, so the line no longer says "the lane tooling's own". - **The counts in the `<other-changes>` item:** the pin's line (#233) is in the list, so the list carries 44 of the 53, and the other 9 have their lines under "What 1.1.0 adds", not 43 and 10. The item says "the openRepoShape pin" where the runner pin of #296 could be taken for it. - **The milestone item** names #247, so it lists the six entries the milestone held on 2026-10-20. - **#209 is not tests-only.** Its `-e` fixes `lanes`' stderr filter under macOS's BSD `grep`, so it moves from the test suite to the lane area, after #208's, and its one line there also carries its test changes: the `repoG#8` assertion and the count of bash files in prose. It is cited once. - **Lines for the changes after `a42946e`:** #263 (`d9065df`), #289 (`fb2cf36`) and #294 (`acc89ea`, which closes #292) landed on 2026-10-21, from 11:28Z to 11:30Z. Each has a line in its area, worded from its squash commit and its description: #263 and #289 under "The register and `lanes-edit.sh`", and #294 under "`lane`, `lane-start`, `lane-end`, the name guard and their helpers". - **#296 has its line too,** last under "The test suite and its checks": CI and the release workflow run on `ubuntu-24.04`, because `ubuntu-latest` is now Ubuntu 26.04, and `macos-latest` is unchanged. It landed right before this pull request, as `5afba4a`. - **"What 1.1.0 adds" gains two lines,** after the annotated-tags item. They are for the three entries that closed in the v1.1.0 milestone after the draft was written: - **#255,** fixed by #271: the lane tools name what they could not read in a triad's legs. `lane-handoff` names every tree-inventory record that is not a whole schema-1 one, and a leg directory this account cannot search is unreadable and never `absent`. Only the sweep and `lane-end` also see a dependency nested in such a leg, since `lane-reconcile` and `lane-handoff` read declared legs only, and #272 stays open as the known gap. - **#280,** fixed by #283: `lane-handoff` reads the lane's lifecycle whole and parses it afterwards, so an `awk` that exits early can no longer turn `lane-state`'s SIGPIPE into a lifecycle that could not be read. - #283 is #280's pull request, so the three numbers make two lines. Each line cites the issue and its pull request, as the hook-pair line does for #237 and #247. - **"What else changed since v1.0.0" is drafted** from `git log aaa7bc8..a42946e`, which is 53 squash commits, one pull request each and no merge commit. It is grouped by area, one line each, and each line ends with its pull request. It lists 44 of the 53: the pin's line (#233) at its head and 43 by area, as 4 on the estate commands, 10 on the register and `lanes-edit.sh`, 11 on `lane`, `lane-start`, `lane-end` and the name guard, 6 on the handoff and its skill, 1 on the lane tools in a triad's legs (#246), 9 on the test suite and its checks, and 2 on the triad migration's records. - **The other 9 are accounted for elsewhere:** the package series of #228 (#262, #267, #268, #269, #270 and #284) is covered by #228's lines, and #247, #271 and #283 have the lines above. - **The lines added on 2026-10-21** are for the four changes after `a42946e`: #263 and #289 on the register and `lanes-edit.sh`, #294 on `lane`, `lane-start`, `lane-end` and the name guard, and #296 on the test suite and its checks. The areas now hold 47 lines, one for each of 47 pull requests, and #233's line at the head of the list makes 48. - **The list is redone at the tag.** It is drafted from the squash titles only. - **"Before the tag" is updated in three items:** - `<pr-count>` gives the count at `a42946e`, which is 53; - `<other-changes>` says what was drafted, which 9 pull requests have their lines under "What 1.1.0 adds", that the lines for #263, #289, #294 and #296 were added on 2026-10-21, and what is left to do at the tag; the placeholder's own line now stands for the changes after `a42946e` that have no line above; - the milestone item names the six entries the milestone held on 2026-10-20: #228 still open, #237 closed by its pull request #247, #255 closed, and #280 closed by its pull request #283. **Not added:** nothing that has landed. #296 landed right before this pull request and has its line. This pull request itself, and whatever lands after it, is what the `<other-changes>` placeholder stands for. None of #263, #289, #294, #296 and #292 is in the v1.1.0 milestone, which still holds the six entries of 2026-10-20. **How this keeps the draft's rules** - **One-line paragraphs:** every added line is its own list item, and none is wrapped. - **References:** every reference above "Before the tag" is spelled `opensoft/openRepoTools#N`, with no bare `#N`, since the notes are published from another repository after the migration. - **Placeholders:** `<other-changes>` stays as a named placeholder in code font, as the closing line of the list and as its checklist item. `<pr-count>` is unchanged apart from the drafting-time count. - **The file's closing lines are untouched:** the self-naming last line stays last. **Tests** - **T023's verify command** passes: the last line names `openRepoTools-spec` and `docs/release-notes/v1.1.0.md`, `## Before the tag` is there, and so is `pipx install --force openrepotools`. - **Coverage:** a script over `git log aaa7bc8..acc89ea`, 56 commits and no merge, finds each pull request cited above "Before the tag" except the six of #228's package series, which #228's lines cover. That is 46 by area, #233 at the head of the list, and #247, #271 and #283 under "What 1.1.0 adds". #296 is not in that range, and its line cites it. - **Hygiene:** by grep over `tests/`, no test names this file. The two that read its content scan every tracked file, and both are in `tests/test_repo_hygiene.py`. The only other test that names `release-notes` is in `tests/test_release_workflow.py`, and it reads `release.yml`, not the notes. All of `tests/test_repo_hygiene.py` was run on the file, through `tests/run.sh` with every `LANES_*` and `TMUX*` variable unset: ```text -k 'repo_hygiene' -v collected 2933 items / 2696 deselected / 237 selected 237 passed, 2696 deselected in 2.59s ``` - **Not run:** the whole suite. CI's `tests` job is the suite of record. This pull request's own runs on `bebb77d` went red on `ubuntu-latest`, which is Ubuntu 26.04, for the reasons #296 gives, because #296 was not yet on main. The record is lane 3's queue run over main, #296 and `bebb77d`, on `ubuntu-24.04` (below). **Where the draft's rules left room, and lane 3's answers (comment 6314185715)** - **Which section holds #255 and #280:** "What 1.1.0 adds", because the milestone is Brett Heap's scope for the release and #237 with #247 already sit there. - **`<other-changes>` stays** as a closing placeholder after the drafted list, since this pull request itself lands after `a42946e`. - **How much to list:** the tests-only and migration-record lines stay through the tag, because the check that every pull request has a line depends on them. If Brett Heap wants a shorter body, they fold into one line that still lists every pull request number. - **Issues and pull requests:** the milestone lines cite both, and the area lines cite the pull request only. **Lane 3's re-check of `bebb77d`** (#293 6315668503) is MERGE AFTER FIXES. - **What holds:** every line lane 2 listed, the recount behind line 140 (44 of the 53 pull requests in `aaa7bc8..a42946e`, and 56 in `aaa7bc8..acc89ea`), the file's rules, and T023's verify commands. - **One SHOULD and two NITs, all wording:** - line 45's sentence on a dependency nested in a leg, where "one above it" reads as a directory above the leg, which is #272's case. The text was lane 3's own; - "One known gap" in the same line; - line 74's last clause. - **Why they wait:** lane 3 merges the notes as tested and carries the three fixes into the notes' final pass at the tag. A push here would cost another CI round while lane 2 is out of usage until 15:30Z, and the notes are edited again at the tag in any case. Lane: openRepoTools-2 Landed by lane openRepoTools-3, as queue prefix `lane3-queue-u/p2-293` (tree `9b879ca`; tests.yml run 39595166877, green on `ubuntu-24.04`), right after #296. Before the landing, lane 3 merged main into the branch, so that its own checks ran over main with #296; the content is unchanged. Brett Heap's word, of 2026-10-20T22:5xZ: "merge all when green for all merges thru v1.1.0. use this for all lanes" (#228 6303614082). Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
brettheap
pushed a commit
that referenced
this pull request
Oct 21, 2026
…scripts, each tool pinned by version and sha256, in a workflow of its own (#277) This completes the WIP commit b1c59e6, which added lint.yml alone. It is a branch for v1.2.0, with no PR and no label, and the job has not yet run on a GitHub runner: every result below was taken on one machine with the pinned tools, so the CI record is still to come. No job ran either tool, so a warning on a workflow or a shell script showed nowhere. Lane openRepoTools-2's review of #228's release.yml found three mutants that actionlint's shellcheck rule flags and the suite lets through (I4, I13 and N3), and nothing in CI would have said so. What changed - .github/workflows/lint.yml, one job `lint`, in a file of its own. tests.yml is the release gate's file: release.yml requires exactly its four jobs, tests/test_tests_workflow.py holds that, and rehearsal D rewrites it for the code leg. The job runs on pull requests, on main and release/v*, and by dispatch, and it is no part of the gate. It runs on ubuntu-24.04, as every other ubuntu job does since #296 (ubuntu-latest became Ubuntu 26.04 on 2026-10-21). - actionlint 1.7.12 and shellcheck 0.11.0, each a release archive checked with sha256sum --strict -c before it is unpacked. Each digest was computed from the downloaded archive and equals GitHub's asset digest, and actionlint's also equals upstream's checksums.txt. Neither tool comes from the runner image or from a package index, and both are static binaries. - actionlint runs over every workflow with the pinned shellcheck given by path, with no exclusion, no severity floor and no config file, and the step fails if actionlint reports its shellcheck rule disabled, which it does silently when it cannot start the binary. - shellcheck runs, one file at a time, on every tracked file whose first line is a bash or sh shebang, at the baseline below. That is 16 files on main, and 15 of them run. - tests/test_lint_workflow.py (17 tests, 21 cases) pins the file and runs its three steps under fakes instead of only reading them: the install step over a genuine archive, over a tampered archive of each tool (nothing is unpacked, and after a bad actionlint archive the shellcheck one is never asked for) and over a tool that says another version; the actionlint step under a fake actionlint (a finding, a disabled shellcheck rule, a shellcheck that is not the pinned one); the shellcheck step in a throwaway git repository (selection by shebang, the baseline's flags, every file checked after one fails, an empty selection fails). The header's table of codes is held to the step's list, and the baselined scripts are held to be tracked bash files. What the tools found on main a42946e - release.yml, tests.yml and lint.yml: nothing, at any severity. - The 16 shell scripts: no error. park, resume and status: nothing at all. The other twelve: 319 findings, 190 warnings and 129 notes. Warnings: SC2034 157, SC2088 14, SC2209 4, SC1007 4, SC2154 3, SC2069 2, SC2178 2, SC2128 2, SC2141 1, SC2318 1. Notes: SC2016 55, SC2018 18, SC2019 18, SC2295 11, SC2329 10, SC2086 5, SC2015 5, SC2094 4, SC2020 1, SC2012 1, SC2006 1. lanes-edit.sh holds 142 of the 319. - tests/test_lane_helpers.sh, which the job does not run: 43 warnings and 218 notes, and 16.2 GB of memory to find them. - Two of the warnings are latent bugs and not style: SC2141 in lanes-edit.sh's session_start_block (IFS='\t' is a backslash and a t, so a live-fork row id<TAB>4242<TAB>interactive reads as id<TAB>4242<TAB>in, erac and ive) and SC2318 in openRepoTools's wip_fetch_template_file (bash expands $rel before the local that sets it takes effect, so path carries the caller's rel, which is right only because wip_init calls it from a loop over its own rel). Neither is fixed here. Main has moved since, and the baseline holds on it. On main 50d05d4 (after #263, #289, #294, #296 and #293) the job's three steps, run as written over that tree, exit 0: actionlint finds nothing in release.yml, tests.yml and lint.yml, and shellcheck finds the same 190 warnings, in the same ten codes and the same counts, no error, and 132 notes (lanes-edit.sh gained two SC2016 and one SC2015). lanes-edit.sh peaks at 10.9 GB and takes about 90 to 130 s, which a 16 GB runner holds. What the baseline leaves out - The workflows: nothing. - park, resume, status and every script added later: nothing. - The other twelve scripts are held to --severity=warning less ten codes, so the 129 notes and the 190 warnings of SC1007, SC2034, SC2069, SC2088, SC2128, SC2141, SC2154, SC2178, SC2209 and SC2318 are left out, and any error or warning of another code fails. Each code, its count and the reason it is left out are in lint.yml's header. - tests/test_lane_helpers.sh is not run: it is the lane helpers' own suite, nothing ships it, and shellcheck needs 16.2 GB for it (measured), more than a 16 GB runner has. lanes-edit.sh is run: 10.5 GB and about two minutes. The three mutants, applied to release.yml in scratch copies (lane 2's own diffs), and run through the job's own actionlint step, on a42946e's file and again on 50d05d4's - I4 (3.2.*) made *)): SC2221 and SC2222, warning. - I13 (the link fingerprint check made `if false`): SC2034, warning. - N3 (exit 0 as the clean step's first line): SC2317, info. Each makes the step exit 1. N3 is only info, which is why the workflows have no severity floor. Tests, run only through tests/run.sh -k - -k 'test_lint_yml or test_no_committed_file_names_a_host_absolute_path or test_adoption_act_zero_is_cited_by_the_sha_that_landed': 23 passed. The last two scan every tracked file, so they read lint.yml and the new test. - Before the workflow existed (lint.yml set aside), -k test_lint_yml: 19 errors and 1 failure of its 21 cases. The 21st reads only tracked files and passed. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This was referenced Oct 21, 2026
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.



Closes #173
This PR does #173's last open item, c1 (comment 6013909513, from Copilot's fourth review of #171), and adds the test that #252's delta review 2 asked for under #173's unread marker. The rest of #173 is already on main, from #219 (
a7f09bd): the issue's own finding, by option 1 (the per-lane unread marker, so a first sync's unread lane and a held lane's kept rows both say NOT READ in the index), and items c2, c3 and c4. That leaves c1, so this PR closes the issue. It is lane openRepoTools-4's, under Brett Heap's 10-11 assignment of #90–#194, and it merges only on his word for this PR.Fix round 1 answers the independent review at
03b6299(LAND, no MUST). Its SHOULD-1 and SHOULD-2 and its N1 to N4 are done here, and the hung-indexer race it traced is fixed; its SHOULD-3 and SHOULD-4 are #290 and #291. See "Fix round 1" below.Fix round 2 answers the delta review r2 of fix round 1, at
ddf7f6e(LAND, no MUST). Its SHOULD-A, a lane'sdirread again for each lane with trees, and its NIT-1 to NIT-3 are done here. Its SHOULD-B, a bash 3.2 exit inlanes --worktreesthat main has too, is #292. See "Fix round 2" below.The defect
worktree_rowslists the lanes throughlanes_rows --all --closedand takes that listing as whole.dirplaces.lanes_rowsis a listing a person reads before a launch, so it may not refuse. When one of those reads fails, it says so on stderr and lists what the other reads gave. For the object-log listing it does not even say so, becauseknown_lanesanswers 0 either way.The inventory took that partial listing as whole.
lanes-index sync --source inventorythen removed the rows of every lane the listing could not name.Each row of the table below was reproduced at
21e0829against the test fixture's seed. In each case, a lane with a tree is named by one read alone, and that read's published object is made unreadable:0 upserted, 8 removed: the table emptieddironly its log recordsThe design
worktree_rowsnow asks each read the listing rests on:origin, the log directory, which must be a directory this account can list and search;dircomes. Both are taken from the warnings their read left, and the events are read once per process, so this is the read the listing used. Where those warnings could not be kept, whether a log failed is not known, and the read says so. Each lane'sdiris read there once: its control root, its trees and its lifecycle snapshot are all found under thatdir, and its log is not read again for them (fix round 2).PARTIAL, the workstation, and why.PARTIAL.lanes --worktreesprints it. The line shows(every lane)in the LANE column andlane listing NOT WHOLE:followed by the reason. A footer says that a lane missing from such a listing is NOT a lane with no worktrees.collect_inventoryrefuses a read that carries aPARTIALline.syncandreconcile --source inventory,--dry-runincluded, exit 1 withunread: the lane listing ... was not whole - (why) - ... - nothing written, andstatuskeeps that as the last error.syncedstamp. The first sync over a whole listing writes what moved in the meantime.--indexread says so too (fix round 1, worded in fix round 2). Where this workstation recorded an error for a source,lanes --index --worktreesprints(last error: <UTC> <why>)after that source'ssynced <UTC>. It is the last errorstatusshows: asyncor areconcileof the source that refused or failed records it, a--dry-runincluded, and asyncor areconcilethat is not a dry run clears it when it succeeds.lanes-index export --worktreescarries the error as a fifth field of the source'smetaline, and an older reader ignores that field. Another workstation's error is in its own status file, so a shared store's other sources never show one.Where this departs from the design it started from, and why
It refuses rather than holds. The design I was given, and the announcement on #173, held every stored lane missing from the read and wrote the rest. #219's marker exists so that a held lane does not read as current, so holding by listing would have needed four more pieces:
statusline for that listing marker;--indexfallback that knows about it, across every workstation in a shared store.Refusing follows rules the code already has:
collect_inventoryalready refuses a listing it could not read at all (a helper exit other than 0 or 8);next-freerefuses a position over this same partial read.A read that is not whole is the same failure, in part. The register, the archive and the logs belong to the workstation's one register checkout, so a failed read of them is never just one lane's problem.
It is a new line kind, not a lane-less
UNREAD. An indexer older than this PR reads any four-fieldUNREADas a lane. It would hold a lane named "", give it a marker, and still remove every other lane missing from the read. The same older indexer refuses a line kind it does not know ("a line this indexer does not read ... is the helper on PATH another version?"), so it writes nothing over a newer helper's partial read.Fix round 1
The independent review at
03b6299found no MUST. This round is two commits on03b6299:ca6b1b0, the tests alone on03b6299's code, andd26658d, the fix. Thencef454emerges maina42946e. After CI's first run, two more:ecfc523moves a 14-line test setup that the two log tests shared into one helper,_a_lane_found_through_its_log. SonarCloud's gate had counted it as duplicated new code: 4.9% atcef454e, where 3% is allowed, and 0 atddf7f6e. Neither test's assertions change.ddf7f6eupdates two comments inlanes-edit.shthat quote the--indexread line, for N2.PIN_ARCHIVE,PIN_LOGS), soarchive_textandknown_laneshand back the text the check read instead of reading again. (a)remote_log_eventsnotes a list of the logs it could not make (unlisted logs: ...), andworktree_rowsreads that note back, so a failure of the read everydircomes from is never silent. That did not make eachdirthe one used: a lane with trees still had its log read again, for its trees and its snapshot, until fix round 2 (review r2's SHOULD-A). (c)docs/README-lanes.mdsays what is still read twice.gitshim fails only the firstshowof the register, and mR is now killedlslisted anr--log directory (probe P12)-d,-rand-x, as the trees' directory is--indexread said nothing of a refused sync (probe P9)reconcile --dry-runover a partial listingtest_a_lane_listing_that_is_not_whole_removes_no_rowcases run it: exit 1, the reason, and no removalstests/test_lanes_index.py:631.argv(:633), as its sibling at:2155does, both lines atddf7f6eWhy a pin and not a cache for the process. The review suggested caching the archive and the log list per process, as the register is cached. A cache for the process must be dropped wherever the ref moves, and the register's is dropped in three places: a fetch, an
--indexread and a write's re-read. The archive has one more reader that needs it fresh.add-rowrescans the archive after its rebase (retired_identity_hits) to catch a position retired in the meantime, and a stale cache there would offer that position again. The pin is set byworktree_rowsfrom its own check and dropped as soon as the listing is made, so no other read sees it.What is still read twice (now also in the docs):
origin, the log directory is asked, then listed again for the names and again for the events. A log file in it that will not open leaves no warning naming it (A named worktree read answers "none" for a lane whose log or register could not be read (from #289's review) #290, item 4).origin/<branch>is there. Arev-parsethat failed in that read alone would read this checkout's logs in place of origin's.Fix round 2
The delta review r2 of fix round 1, at
ddf7f6e, found no MUST. This round is two commits onddf7f6e:d223430, the tests alone onddf7f6e's code, andf2723b1, the fix. Main is stilla42946e, whichcef454ealready merged.dirwas read again for each lane with trees, and a failure of that read removed the lane's rows (probe C1; also at21e0829)lane_trees_listandlane_state_readtake an optional second argument,lane_control_root's own payload, andworktree_rowshands all three reads the one payload it builds from the listing'sdir(its last sync failed: ...)also showed the error of a refusedreconcile --dry-run(last error: ...), the namestatusgives it, in the code, the README and this body. What a dry run records is unchangedlanes --worktreesexits with no output under bash 3.2, on main tooEvery other caller keeps its behaviour.
lane_state_of,lane_reconcile, and thelane-stateandlane-treesverbs pass the lane alone.lane-start,lane-handoff,lane-endand the lifecycle verbs reach these functions only through those verbs. For each of them"${2-}"is the empty payloadlane_control_rootwas handed before, so the root is found exactly as it was. No other file calls either function.Read counts. A probe estate with no
LANES_LANE_STATE_ROOT, whose log-only repoB-1 is found through itsdirand has a snapshot there, counted the git calls of one wholeworktrees --all:ddf7f6ef2723b1ls-treeoflanes/log/showof repoB-1's logshowof any log (the estate has two)showof the registershowof the archiveWith
LANES_LANE_STATE_ROOTset, the counts and the rows are the same at both heads. With only the secondshowof repoB-1's log failing:ddf7f6e,worktrees --allexits 8 with noPARTIAL;f2723b1, it exits 0 with repoB-1's tree,RUNNINGat generation 1.Through
lanes-index sync,ddf7f6eshows that log three times and writes0 upserted, 1 removed. The three are the events' read,lane_trees_list's read, which fails, and the indexer's ownlane-stateread of the lane's generation.f2723b1shows it once and writes nothing. Bash 3.2.57 gives the same counts and rows.Tests
The tests went in first, in their own commit
d2c26ae, whose code is21e0829's.test_a_lane_listing_that_is_not_whole_removes_no_row[archive]1 upserted, 1 removed, repoZ-1's row gonetest_a_lane_listing_that_is_not_whole_removes_no_row[register]4 upserted, 1 removed, repoC-1's row gonetest_a_lane_listing_that_is_not_whole_removes_no_row[log-listing]1 upserted, 1 removed, repoB-1's row gonetest_a_lane_listing_that_is_not_whole_removes_no_row[all-three]0 upserted, 8 removed, the rows are{}test_a_lane_whose_log_could_not_be_read_keeps_its_rows0 upserted, 1 removedtest_a_listing_whose_log_warnings_could_not_be_kept_is_not_wholePARTIALline ([] == [['PARTIAL', ...]])test_an_unlistable_log_directory_with_no_origin_is_a_partial_listing0 upserted, 1 removedtest_an_older_helpers_tree_with_no_path_and_a_markers_branch_is_a_treeCounts:
tests/run.sh -k test_lanes_indexatd2c26ae: 8 failed, 82 passed. Seven of the failures are the c1 cases above, each on its assertion and none on a crash. The eighth,test_a_hung_indexer_delays_no_writer_beyond_the_fork, is an existing race in that test's stub, fixed in fix round 1 (see "Fix round 1"). It passed in the green run, and also under mC and mC-whole, where the whole module ran.tests/run.sh -k "test_lanes_index or test_repo_hygiene"at03b6299: 325 passed.03b6299:tests,tests-no-submoduleandguard-launch-modeall passed.How a case makes a read fail. It moves the object's loose file aside in the clone, so a
git showorgit ls-treethat needs it fails, as on a damaged clone or a partial clone that cannot fetch it. Only the read under test fails.What each c1 case checks. Besides keeping every row, each case checks that:
statusandreconcilesay the same;lanes --worktreesprints theNOT WHOLEline and its footer;--indexread equals the source read again.Fix round 1's tests
The tests went in first, in
ca6b1b0, whose code is03b6299's.test_the_listing_names_lanes_from_the_archive_it_checked(P2: the shim fails every archiveshowafter the first)0 upserted, 1 removed, repoZ-1's row gonetest_a_log_list_that_fails_after_the_check_removes_no_row[the-next-read](the shim fails the secondls-treeoflanes/log/)0 upserted, 1 removed. That second list wasknown_lanes', so repoB-1 went unnamedtest_a_log_list_that_fails_after_the_check_removes_no_row[every-later-read](the shim fails everyls-treeoflanes/log/after the first: at03b6299, P11's read and the one before it)0 upserted, 1 removedtest_the_register_is_asked_before_the_listing(P3: the shim fails only the first registershow)test_an_unlistable_log_directory_with_no_origin_is_a_partial_listing[mode-400](P12)0 upserted, 1 removedtest_the_index_read_says_its_last_sync_failed(N2)synced <UTC>test_a_lane_listing_that_is_not_whole_removes_no_rowcases, now with N4's dry run, and[mode-000]In the two log-list cases no override names a control root, so repoB-1's trees are found through its log's
diralone, as in P11.Counts:
tests/run.sh -k test_lanes_indexatca6b1b0: 5 failed, 91 passed. The five are the FAILS above, each on its kept-row or read-line assertion and none on a crash.tests/run.sh -k "test_lanes_index or test_repo_hygiene or test_register_scan_hardening_138"atd26658d: 358 passed. Again atddf7f6e, after the refactor,-k "test_lanes_index or test_repo_hygiene": 333 passed.pull_requestrun 39467365169 onddf7f6epassedtests,tests-no-submodule,packageandguard-launch-mode, the two test jobs on the merge ofddf7f6einto maina42946e, and SonarCloud's quality gate passed.How a round-1 case makes a read fail. For that one call, a
gitshim onPATHcounts the calls whose arguments carry the read's text. It fails, with exit 128, only the counted calls the case names, and every other call is the real git._unreadablecannot do this, because it fails every read of the object. A probe at each head counted the calls a sync makes: the archive was shown 5 times at03b6299and once atd26658d, and the log list was listed 3 times and then twice. Under bash 3.2.57 (the musl build) the fix answered both probes as it does under 5.2.Fix round 2's tests
The tests went in first, in
d223430, whose code isddf7f6e's.test_a_lanes_log_that_fails_after_the_listing_removes_no_row(C1: repoB-1 found through its log'sdiralone, with a snapshot there; the shim fails only the secondshowof its log)0 upserted, 1 removed, repoB-1's row goneshowis the only one, and the sync writes nothingtest_the_listing_names_the_lane_whose_log_sorts_last(NIT-2: repoY-1 has a log alone, and it sorts last)test_the_index_read_says_its_last_sync_failed(N2, now looking for(last error: ...))(its last sync failed: ...)Besides the kept row, the C1 test checks that the store is byte-for-byte unchanged and that no lane is held. A snapshot read under the wrong root reads as generation 0, and a sync holds the lane's rows for that rather than write them. With no snapshot, both roots give the same answer, so the test gives repoB-1 one.
Counts:
tests/run.sh -k "test_lanes_index and (fails_after_the_listing or sorts_last or last_sync_failed)"atd223430: 2 failed, 1 passed. Each fails on the assertion above, and neither on a crash.tests/run.sh -k "test_lanes_index or test_repo_hygiene"atf2723b1: 335 passed, which is round 1's 333 and the two new tests.PATH),-k "test_lanes_index and (fails_after_the_listing or sorts_last or last_sync_failed or log_list_that_fails or log_could_not or not_whole)"atf2723b1: 7 passed, 4 failed. The four are thenot_wholec1 cases: theirlanes --worktreesexits 1 with no output at Under macOS's bash 3.2, a failingcommand <utility>in a list or an if condition exits a set -e script: lanes --worktrees dies silently (lanes:317), and wip's .gitignore step can stop (openRepoTools:4014) #292'slanes:321, as the review found atddf7f6e.pull_requestrun 39507250560 onf2723b1passedtests,tests-no-submodule,packageandguard-launch-mode, the two test jobs onc594a3a, a merge off2723b1into maina42946ewhose tree6e6f2aeis the merge ref's, and SonarCloud's quality gate passed.The mC test
test_an_older_helpers_tree_with_no_path_and_a_markers_branch_is_a_treeuses a wrappedLANES_EDITas a stand-in for a helper older than #252. The wrapper adds oneTREEline with an empty path and a branch that reads like the marker's. The test checks that the line:TREEline, so the--indexread is the source read;statusas a worktree;It passes at
21e0829, where a marker is its key.The mutant comes in two forms:
test_a_first_sync_that_cannot_read_a_lane_says_not_read_in_the_index, but only becausestatushas fetched just thelanecolumn since lanes-index follow-ups of #166 and #173: export reads one snapshot, history --index says its closing stderr count, a foreign source is refused before the lock, a damaged table reads as unusable, an unread lane stays NOT READ in the index, and the worktrees footer names the workstation #219, so no rule based on the branch can see a marker there.Mutants
Each mutant was applied alone to
03b6299. mC and mC-whole were run over the whole module (tests/run.sh -k test_lanes_index). The others were run over the new tests (-k "test_lanes_index and (not_whole or log_could_not or warnings_could_not or unlistable_log or older_helpers)"). Every mutant was killed.is_unread_markertakes 5bf29d9's rule (no path, and a branch beginningunreadable inventory () in place of the key--indexread is no longer the source read; and the existingtest_a_first_sync_that_cannot_read_a_lane_says_not_read_in_the_index, becausestatushas fetched onlylanesince #219. Whole module: 2 failed, 88 passedcmd_statusfetchingpathandbranchas it did at 5bf29d9worktree_rowsdoes not ask the archive[archive](repoZ-1's row removed);[all-three](the reason lacks the archive)[register](repoC-1's row removed);[all-three][log-listing](repoB-1's row removed);[all-three]origin, it does not ask the log directorytest_an_unlistable_log_directory_with_no_origin_is_a_partial_listing(row removed)test_a_lane_whose_log_could_not_be_read_keeps_its_rows(row removed)test_a_listing_whose_log_warnings_could_not_be_kept_is_not_whole(noPARTIALline)test_a_lane_listing_that_is_not_whole_removes_no_rowcases (NOT WHOLEin a named read)collect_inventoryreads past aPARTIALlineUNREAD, still refused by the indexerlanes --worktreesprints NOT READ, not NOT WHOLE) and the warnings test (the line's kind): 5[all-three](every row removed)lanesprints no line forPARTIAL, as an older renderer wouldlanesprints no footer for it[all-three](its reason gains "not known")Fix round 1's mutants were each applied alone to
cef454e(the fix, merged with main) and run over-k "test_lanes_index and (names_lanes_from_the_archive or log_list_that_fails or register_is_asked or last_sync_failed or unlistable_log or not_whole or log_could_not or warnings_could_not)", 13 tests. Every one was killed, each by a removed row or the read's line:remote_log_eventsdoes not note a list of the logs it could not makeworktree_rowsdoes not read it backarchive_textignores the pin, so the listing reads the archive againknown_lanesignores the pin, so the names come from a secondls-tree[the-next-read](repoB-1's row removed)lsagain[mode-400](repoB-1's row removed)--indexread's line drops the fifth fieldAfter
ecfc523's refactor, r1-a-note, r1-a-scan and r1-b-logs-pin were run again atddf7f6e, together with m4 rewritten for this round's code, over the two refactored tests (-k "test_lanes_index and (log_list_that_fails or log_could_not)"). Each was killed by the same tests as before, and m4 bytest_a_lane_whose_log_could_not_be_read_keeps_its_rows.Fix round 2's mutants were each applied alone to
f2723b1. The two marked broad ran over the sixteen tests of rounds 1 and 2 (-k "test_lanes_index and (names_lanes_from_the_archive or log_list_that_fails or register_is_asked or last_sync_failed or unlistable_log or not_whole or log_could_not or warnings_could_not or hung_indexer or fails_after_the_listing or sorts_last)"), and the others over the one test the table names:ddf7f6e:2942, with0 upserted, 1 removedand repoB-1's row gonelane_trees_list's call drops the payload:2942:0 upserted, 1 removedlane_state_read's call drops it:2944: the sync holds repoB-1, whose generation reads 0 against the 1 its rows were written atlane_trees_listignores the payload it is handed:2942, as m2-pass-treeslane_state_readignores it:2944, as m2-pass-state:2968, with repoY-1 not indexed (5 upserted, 0 removed)its last sync failedagain:3012Lane 3's terms
acquire_lock,release_lock,lock_tryorLOCK_HELD. The md5 of the 73 lines naming them is97878eb141e051c60a82e339cfe537c8at21e0829,03b6299,d26658d, maina42946e, the mergecef454e,ddf7f6e,d223430andf2723b1;git diff a42946e f2723b1has 0 such lines.lane-startandlane-handoffare not touched: both are main's atf2723b1.bash -npasses under GNU bash 3.2.57 (the musl build, run through its own loader) and under 5.2.21, onlanes-edit.shandlanesatd26658d,cef454eandddf7f6e, and onlanes-edit.shatf2723b1, the one shell file fix round 2 changes.cef454emerges maina42946e. Main moved from this branch's base21e0829by nine commits: lane-handoff's lifecycle read, Releases: annotated tags, release/vX.Y branches, and openrepotools on TestPyPI and PyPI from v1.1.0 #228's release series, The handoff names every inventory record that is not a whole schema-1 one, and a leg directory this account cannot search, or a dependency nested in one, is unreadable and never absent (fixes #255) #271, PR 3's re-check survivors are killed: tests/test_release_workflow.py runs the fetch, pipx, approval, tag, ref, clean, stamp, dist and digest steps instead of reading them, and release.yml changes only in comments (#228, PR 3b) #284 and The shell suite's wrapper prints the suite's timing table and teardown line on a pass, where CI's log can read them (#77, step 1b) #265. Of this PR's files, onlylanes-edit.sh(lane_reconcile's leg sweep) anddocs/README-lanes.md(the triad section) changed there, away from its hunks, and the merge is clean. Main has not moved since.refs/pull/289/mergeis nowca2410f, with first parenta42946eand second parentf2723b1, and its tree6e6f2aeisf2723b1's.Docs
docs/README-lanes.md, in theworktreestable section:diris read once);NOT WHOLEline, and the--indexread's(last error: ...).worktrees --allstill exits 0 with its rows, and thePARTIALline is now among them. Where the failed reads left the listing EMPTY, it used to exit 8 ("none"), and it now exits 0 with thePARTIALline alone. The indexer's refusal uses its existing exit 1.worktree_rows's comment,lanes --helpandlanes-index's docstrings.Not covered
Filed from the review: #290 (SHOULD-3 and the four items below that are marked with it) and #291 (SHOULD-4). All of them exist at
21e0829. From review r2: #292 (its SHOULD-B, on main too), under which the fournot_wholecases fail on bash 3.2, atlanes:321(:317on main).--allread worked each lane's control root out again from the lane's log, for its trees and its snapshot, and threw a failedgit showaway (review r2's SHOULD-A). Fix round 2 hands those two reads the listing'sdir, so the--allread no longer reads a lane's log a second time. A named read still answers "none" where its one read of the lane's log fails.origin, or underLANES_NO_GIT=1, a log FILE that cannot be read, as opposed to its directory, leaves no "unreadable log" warning, becauselog_eventsruns awk over the files.canon_lanecannot find the row's spelling. A lane asked for in another case (worktrees repoa-1forrepoA-1) answers "no worktree is inventoried" with exit 8.laneslisting itself (A named worktree read answers "none" for a lane whose log or register could not be read (from #289's review) #290). It still prints nothing when the list of the logs fails, and silently leaves out the lanes only a log names. Since fix round 1 the events note the failure, but the listing replays their warnings to/dev/null, and a probe atd26658dshowed an empty stderr.writer_livewith the register unreadable (A named worktree read answers "none" for a lane whose log or register could not be read (from #289's review) #290). In the source read it can be0rather than unknown, for a lane whose ids only the published row holds. The index never stores that value now, because the sync refuses.statusand now the--indexread say why. An unreadable log refuses the sync even where its lane's trees were found, because its binding (and sowriter_live) and itsdirare unknown.🤖 Generated with Claude Code
Summary by Sourcery
Protect inventory state from incomplete lane listings by reporting partial reads and refusing to write until a whole listing is available.
New Features:
Bug Fixes:
Enhancements:
Documentation:
Tests: