Repository navigation
lane-handoff reads the lane lifecycle whole and parses it afterwards, so an awk that exits early can no longer turn lanes-edit.sh's SIGPIPE into a lifecycle that could not be read (fixes #280) - #283
Conversation
… so a filter that exits early can no longer turn the producer's SIGPIPE into a lifecycle that could not be read (#280) lane-handoff read `lanes-edit.sh lane-state` as `lane-state | awk '… { print $2; exit }'` under `set -o pipefail`. That awk exits at the line it wants, so a lane-state that wrote once more after it - the builtin printf hands a multi-line snapshot to the pipe in pieces - died of SIGPIPE, the substitution's status was 141, and the case on it took that for a read that failed: "the lane lifecycle could not be read", no fence, no inventory and no RUNNING -> SWAPPING -> SWAPPED, on timing alone (CI run 39322387035). The reader had stopped listening; the read had not failed. Both lifecycle reads - the state, and the operation of a lane still SWAPPING - now capture lane-state's whole output first, take the status from that command alone, and parse the variable with the same awk filter. A lane-state that exits 0 gives the values the old pipeline gave whenever it did not race, 8 and every other status keep their meanings, and the note texts are unchanged. The other 32 early-exit pipelines in lane-handoff (30 `awk … exit`, 2 `head -n 1`) were audited and left: none has a command producer that can write after its consumer stops and a status that is read (a printf of one variable, one short line, a status never read, or a consumer that reads to the end). Two tests next to T018's hold the race every time: a lane-state that prints its state line, waits 0.3 s and prints the rest, in front of the old read shape (premise: `RUNNING 141`) and in front of the handoff. mawk, this workstation's awk, hands its first record over only at EOF or after hundreds of KB, so the old pipeline cannot race on a snapshot this small there; the command under test gets an awk that does not wait (`mawk -W interactive`, or the system's own where it is not mawk). Lane: openRepoTools-3 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…ping, so the old read's 141 no longer depends on timing, and the awk shim goes (#280) The review of fc061fe came back LAND with one SHOULD and three NITs; this takes them all, in the test file only. fc061fe is not touched. SHOULD - the premise was a race of its own. The fake lane-state wrote its state line, slept 0.3 s and wrote the rest, so an awk that stalled for longer than the pause read it all, the old read gave `RUNNING 0`, and the premise assertion failed on correct code. It now writes the state line, 1.5 MiB of padding and then the rest of the record. The padding's key, `pad`, is no field lane-state prints, so no filter in lane-handoff can take it for one. A pipe holds 64 KiB, so that producer is still writing when a reader that stops at the first line has closed: its next write gets SIGPIPE, the wrapper dies of it, and the old read gives 141 whatever the timing and whatever the awk. Plain mawk is included - it reads ahead until its buffer is full (the end of input at 255 KiB or less, an early stop at 320 KiB or more), and the padding is far above that. The quick-awk shim, its PATH entry and the wrapper's PATH reset are gone, and the premise assertion (the old read shape gives `RUNNING 141`) stays and is now deterministic. NIT 2 - the tests no longer set LANES_NO_FETCH=1 for the whole handoff; lane-handoff sets it on its own reads. The premise script, which reproduces the old line, carries it as that line did. NIT 3 - the second test's docstring says what it pins: the note's content and the first read on a SWAPPING lane. It cannot pin the second read's own fix, whose status was never read, so reverting that site alone still passes. NIT 4 - quick_awk's docstring went with the shim. Lane: openRepoTools-3 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Reviewer's GuideFixes a CI flake in lane-handoff by buffering each lane-state response before parsing, ensuring producer status is not replaced by SIGPIPE from an early-exiting awk; deterministic tests reproduce the failure and verify lifecycle transitions and SWAPPING diagnostics. File-Level Changes
Assessment against linked issues
Possibly linked issues
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
|
Lane openRepoTools-3, 2026-10-20T01:2xZ: the independent review of this PR is LAND, at Round 1, at
Round 2, at
Why CI hit the race and Eagle did not.
Follow-up: the same shape in Lane: openRepoTools-3 |
|
There was a problem hiding this comment.
Hey - I've reviewed your changes and they look great!
Sourcery assessment
Needs a human reviewer. Capturing the full lane-state output avoids treating the reader's SIGPIPE as a failed read, allowing the handoff to write lifecycle transitions into the lane record. If the read or parse is wrong, those persisted transitions may need to be reset or repaired; reverting restores the old read behavior but does not undo records already written.
… one, and a leg directory this account cannot search, or a dependency nested in one, is unreadable and never absent (fixes #255) (#271) A follow-up to #246 (T018 of feature 004, the triad lane tooling) that must land **before the triad cutover (#186)**. It fixes the two sections of #255. **The handoff names every inventory record that is not a whole schema-1 one, and a leg directory this account cannot search is unreadable, never `absent`.** Both gaps broke #246's own rule, Amendment 7(d): a read that failed is never an empty one. These readers run only in an assembly, a checkout whose `project.yaml` declares a leg, so main is not exposed before the cutover. **What it fixes** - **Section 1, the handoff's tree inventory** (`lane-handoff`, `paired_inv` and `pi_bad`): - **Before:** a `lane-trees` row counted as unreadable only where its path was empty. A record of another schema keeps its path, so it read as a record with an empty checkout, and the paired tree it names was polled as this lane's writer, with no NOT POLLED note. - **Now:** the row's schema, field 13, decides. A row whose schema is not `1` is named in the NOT POLLED note by its id, its schema and any path it keeps, the lane stays SWAPPING, and the row never reaches `paired_inv`. The `lane-trees` row format is untouched. - **Section 2, a leg directory with no search permission:** - **Before:** its `.git` could not be tested, and each reader's `.git` test failed there exactly as for a leg that is not checked out. The sweep listed it `absent` and exited 0. `lane-reconcile` gave no TREE row. The handoff said nothing and re-recorded the leg's tree under the assembly. `lane-end` ENDED the lane over the lane's unpushed commit in the leg. - **Now,** in one set of words ("its directory cannot be searched, so whether it has a .git of its own could not be tested, and git could not read it: <git's first line>"): - **`lane-worktrees`' `probe_leg`** asks lstat for `<leg>/.git`. Only ENOENT or ENOTDIR is a leg with no `.git`, and any other failure sets `read_error`, so the leg counts `unreadable`: the sweep's exit 3, `lane-end`'s refusal, and the report's legs section. - **`lane-handoff` and `lanes-edit.sh`'s `lane_reconcile`** take their unreadable-leg branch where the `.git` test fails and the leg directory fails `-x`. The handoff gets an UNREADABLE LEG line, a count and a withheld tree. The reconciliation gets a TREE row `unreadable` that requires recovery. - **A leg directory that is not there at all** is still `absent`. **What the fold-in adds.** Lane 3's independent review found the same failure in a reader the issue does not name. After the cutover, `code/upstream/openRepoShape` is exactly this kind of dependency. - **A dependency nested in an unsearchable directory (`aae85a2`, the review's finding 1):** - **Before:** git lists a dependency nested in a leg as `-` (not initialized) and exits 0, not only where it was never initialized but also where it cannot search the directory: at mode 000, at read-without-search, or under a directory it cannot search. `assembly_checkouts` skipped every `-` line before it probed anything, so such a dependency got no row, the code leg read clean, the sweep exited 0, and `lane-end` ended the lane over the lane's unpushed commit in it. - **Now:** a `-` line is parsed as an initialized one is, and probed (`probe_uninitialized`). It becomes a row only where the read failed, an `unreadable` row, counted, in the words `probe_leg` already gives. A directory that is not there, or one that is empty and can be searched, is a dependency never initialized and still adds none. - **A dependency cloned by hand (`a16e534`, i):** a clone made into the directory of a deinitialized dependency is still listed `-`, so the sweep skipped it and `lane-end` ended the lane over the lane's unpushed commit in it (measured). It is now read like an initialized dependency: a row, `unpushed` there, counted, exit 3. - **The describe-suffix trim (`a16e534`, ii):** git prints a describe suffix only on a ` ` or `+` line, never on a `-` line. A dependency never initialized at `upstream/dep (1)` was read as `upstream/dep`, which made a second row for the initialized dependency beside it and left `dep (1)` unread. The trim now applies to the initialized branch only. - **The review's two test gaps (`c67f7a6`):** - **MS6:** the unknown-schema test now runs for schemas `2` and `10`, so a rule that matched the schema by its first character reads `10` as a schema-1 record and fails. - **MS5:** a record that files a tree id and no path is named in the NOT POLLED note by its id and schema, its tree is no writer of the lane's, and nothing is filed over it. A record this account cannot read (`<unreadable>`, no path) is named the same way. - **The docs (`c67f7a6`, `a16e534`):** `docs/README-lanes.md` says what the sweep does with a dependency git lists as not initialized, and #255's own added text is reflowed where its insertion left ragged lines. **The branch.** `fix/255-unreadable-inventory-and-leg-pr` is `a16e534` on main `55aae16`: 7 files, 674 insertions and 30 deletions. - **Lane openRepoTools-2's two commits, cherry-picked:** - `13397aa` (from `ba13d21`): the two fixes, in `lane-handoff`, `lane-worktrees` and `lanes-edit.sh`, with four tests; - `e678c61` (from `523b381`): `docs/README-lanes.md`'s T018 section, `docs/triad-lane-tooling-analysis.md` section 7 item 11 naming opensoft/openBenches#166, and `lane-handoff`'s T018 section heading, now `3b`. - **Lane 3's three fold-in commits:** `aae85a2`, `c67f7a6` and `a16e534`. - **Why a cherry-pick:** #246 landed as the squash `55aae16`, so a merge of main into lane 2's branch conflicts in all seven files. The PR is the two commits cherry-picked onto main, with no force-push anywhere. Their diff equals `git diff 5dd0df0 523b381` (the same patch-id), and their tree at `e678c61` is `1a46c72`, the tree the reviewer computed. **Tests.** There are 11 `test_255_` functions: lane 2's four, and the fold-in's seven. Under **Runs**, six of the seven fail under a mutant of the code they hold. The seventh, the unreadable record, needs no #252. - **Lane 2's four,** each failing on `5dd0df0`'s tools and passing here: - `tests/test_triad_lane_tooling.py`: `test_255_a_leg_directory_that_cannot_be_searched_is_unreadable_and_holds_lane_end`; - `tests/test_triad_lane_tooling_handoff.py`: `test_255_a_leg_directory_that_cannot_be_searched_is_unreadable_in_the_handoff_and_reconcile`, `test_255_an_unknown_schema_record_is_named_in_the_handoffs_not_polled_note` and `test_255_a_malformed_record_is_named_in_the_handoffs_not_polled_note`. The `<malformed>` row comes from a fake `lanes-edit.sh`, so this test does not wait for #252. - **The fold-in's seven:** - `tests/test_triad_lane_tooling.py`: a nested dependency's directory at mode 000 and at 0600, and beneath a directory that cannot be searched, each holding the sweep and `lane-end`; a dependency never initialized, which adds no row; a dependency cloned by hand, read as `unpushed`; and a dependency at `upstream/dep (1)`, read by that path; - `tests/test_triad_lane_tooling_handoff.py`: the tree id with no path, and the unreadable record. - **Where they live:** the issue asked for them beside T018's cases in `tests/test_lane_helpers.sh`. T018's fixtures live in the two Python modules, so the tests are there (the review's ruling). **The order with #252 (the review's NIT 5).** `<malformed>` is #252's row, so the handoff names a truncated record only where lane 4's #252 is on main. The review asked for #252 first, and that is what happened: #252 merged as `00d52ae` at 2026-10-19T18:14Z, and q6k is built on it. With this PR on today's main, `<malformed>` records are named (the review measured it with #252 and #255 together, under **Review**). **Follow-ups, not in this PR:** - a declared leg under an unsearchable parent (the review's ruling on lane 2's doubt: a follow-up); - a leg at mode 0100, searchable and not listable, which reads `clean` (finding 4, estate-wide; lane 3 proposes it to Brett Heap for v1.2.0, #255 6272494888); - the top block's contradiction for a paired tree that only a broken record names (finding 3; proposed for v1.2.0 in the same comment); - the handoff's wording on #252's refusal code (NIT 8; lane 3 proposes it as a v1.2.0 item, #255 6272494888). **Runs** - **The record, q6k** (branch `lane3-queue/q6k-255-on-q5k`: q5k + this head `a16e534`, on main `677acc0`, tree `1149aeb`, with its conflict with #283 resolved as in `fcd3cce`): `tests.yml` run 39373762988, green. This is the run of record for the landing. - **An early read, q3a** (`dce6ffb`, branch `lane3-queue/q3a-255-on-q2f`: PR 2's prefix q2f, `aeadabe`, + lane 2's two commits alone, at `e678c61`; tree `47413c4`; on main `55aae16`): run 39289273676, green on every job, the shell suite included. - **The fold-in writer's selection at `a16e534`:** `-k "test_255 or triad or lane_worktrees or repo_hygiene"` gave 421 passed (logs in `briefs/ort3-255-should1-work/` in lane 3's tree). - **The fold-in's mutants:** the writer ran seven and each fails a `test_255_` test. - The finding-1 fix reverted (FX0), and two variants of it: every `-` line a row (FX1), and a `-` line asked of `probe_leg` alone (FX2). - The two later rulings reverted one at a time: the hand-cloned case (RV1) and the describe-suffix trim (RV2). - The reviewer's MS5 and MS6. **Review.** Lane 3's independent reviewer gave **LAND** on `523b381` (`briefs/rv-255-final-20261019.md` in lane 3's tree, posted on #255 as 6272494888). Both fixes do what sections 1 and 2 ask, in every reader named. - **What it ran:** - the four new tests fail on `5dd0df0` for the right reason and pass on `523b381`; - 17 of 19 mutants are killed, and the two survivors, MS5 and MS6, are low-impact (the fold-in's tests now kill both); - with #252 (`3ffefce`) the fix merges cleanly, and against the real `lanes-edit.sh` the handoff names the `<malformed>` record, in 5 of 5 cases. On that tree, main + #252 + #255, the selection `-k 'test_255 or triad or lifecycle_fail_open or repo_hygiene or lane_worktrees'` gave 457 passed; - the shell suite on that tree gave 4889 passed and 2 failed, `test_lane_helpers.sh:1269` and `:8548`, both in `lane-start`'s row stamp. The reviewer takes them as its sandbox's 106-character path reaching the 240-character `ROW_STATE_CAP`, and neither #255 nor #252 touches `lane-start` or the cap. q3a is green on every job, the shell suite included. - **What lane 3 did with the findings:** - finding 1, a SHOULD, and NITs 6 and 7: folded in, above; - finding 2, a SHOULD: the cherry-pick, above; - findings 3 and 4, and NIT 8: the follow-ups, above; - NIT 5: the order with #252, above. - **The reviewer's re-check of `e678c61..a16e534` is LAND (#271 6277159862).** **Landing:** Brett Heap's decision 4 on #228 ("Yes, merge when green (Recommended)"), and his word of 2026-10-18T20:3xZ, "use this as approval to merge when green for all merges thru v1.1.0". - Lane openRepoTools-3 lands the queue in one order: #262, PR 2, PR 3, PR 4, T025's docs PR, then #255. - This PR squash-merges after an independent review, once Linux CI is green on the exact tree main will have after its squash. The record is a queue run of `tests.yml` on lane 3's prefix branch, under **Runs**. - #255 is last in the queue. q6k is q5k plus this head, so PRs 2 to 4 and T025 are beneath it. - When its turn comes, lane 3 pushes a head that merges main into `a16e534` with q6k's tree, as a fast-forward, so the tree under review is the tree that was tested. Lane: openRepoTools-3 Landed by lane openRepoTools-3 as queue prefix q6k (tree 1149aeb, tests.yml run 39373762988 green), on Brett Heap's word of 2026-10-18T20:37:07Z: "use this as approval to merge when green for all merges thru v1.1.0". Its conflict with #283 in tests/test_triad_lane_tooling_handoff.py is resolved as in the tested tree fcd3cce, which keeps both blocks. Independent re-check of the fold-in round e678c61..a16e534: LAND (#271 6277159862). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…271) into act 2's slice 1a (#198) One conflict, in lanes-edit.sh's lane_state_follow, at the check of a snapshot this helper cannot read: this branch releases the workstation's sidecar lock (sidecar_release); main released W's mutex where the follow took it (lsf_own) and gave a new note naming $LSS_WHY. Resolved as the PR says: keep sidecar_release, take main's note. No line of main's that merged on its own uses lsf_own or release_lock inside lane_state_follow, and main's lanes-edit.sh changes since 55aae16 add no lock call. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…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>
… 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>
…4.04 with an awk that acts at the first record, and no longer says that awk is gawk, which is not confirmed (#253) The completion review of 2be60ea (its NIT C) found that the comment at tests/test_lane_helpers.sh:14985 said ubuntu-24.04's awk is gawk, and that nothing on record says so: - the runner-images manifest at tag ubuntu24/20261012.334, the image of the two red runs, has no gawk, mawk or awk entry, and its apt table has no gawk; a grep of all 123 files under images/ubuntu/{scripts,toolsets} at that tag gives no hit; - no CI log prints awk's flavor; - lane 3's "manifest lists gawk" (#280 comment 6280603973) is not borne out at that tag; - the image of the lane5-ci/253 run, 20261018.339.1, has no published tag. What the two red runs do show is the 141 signature. Plain mawk reads an 11-line snapshot to its end, so it cannot give that signature, and an awk that acts at the first record does, as real gawk 5.3.2 and `mawk -W interactive` did in the first review's runs. The comment now says that, and nothing more about which awk the image carries. WHAT CHANGES is the comment at tests/test_lane_helpers.sh:14985-14989 and nothing else: "whose awk is gawk" reads "with an awk that acts at the first record (which awk is not confirmed)", and "gawk hands the `state` line" reads "Such an awk hands the `state` line". The words need one more comment line, so every line below moves down by one: the padding line is now :15017, the unasserted set-lane-state :15035 and the premise :15038. THE PROOF is of a comment-only change, so no test was run for this commit; CI runs the whole suite after the push. Against 2be60ea: - the diff is 5 lines added and 4 removed, and every one is a full-line comment (hunk -14985,4 +14985,5); - with the comments stripped the file is byte-identical, by two methods. Removing every full-line comment leaves 790849 bytes, sha256 9331f2fd…, in both. The whole file as a function body, read by bash's own parser and printed by `declare -f`, gives 837924 bytes, sha256 8a1115d0…, in both, and the same method differs when one code byte is changed (32768 to 32769) and when one byte is changed inside a heredoc's comment line; - `bash -n tests/test_lane_helpers.sh` exits 0 and `git diff --check` is clean. 2be60ea's message carries the same wording. The squash body replaces it with the corrected one, and corrects the CI counts (NIT A), adds what the 13 red runs share (NIT B) and stops calling the padding #283's technique (the first review's NIT 1). Lane: openRepoTools-5 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>



This fixes the CI flake in #280. It must land before the triad rehearsal's freeze (#186), because every PR's
testsjob runs the T018 handoff test that the flake turned red at random.What it fixes
lifecycle_begin(lane-handoff:1490-1491at21e0829) pipedlanes-edit.sh lane-state "$lane"intoawk -F"\t" '$1 == "state" { print $2; exit }', underset -uo pipefail.lanes-edit.shis still writing. gawk, CI's awk, does this.case "$lcb_rc" in 0 | 8)reads that as a failed read.lane-state's whole output into a variable first, so the status islane-state's own.printf '%s\n' "$lcb_raw" | awk …, the formri_loaduses.:1505-1506), is made the same way for uniformity. Its status was never read, so it could not fail.[ -n "$lcb_now" ] || lcb_now=nonestays;lane-statecalls is the same;The audit
lane-handoffwhose reader stops early was checked. None of them combines a command as the producer, a reader that stops early, and a status that is used.lane-startis lane-start: a reader that stops early, under set -euo pipefail, can end lane-start with no message, or take the minted-transcript branch for a session it has recorded (the shape of #280) #281, filed for v1.2.0.lanes-edit.shsets nopipefail, and none oflane-end's sites can race.The branch:
fix/280-lane-state-sigpipeis two commits on main21e0829. It changeslane-handoff(+17 −5) andtests/test_triad_lane_tooling_handoff.py(+134 −2).fc061fe: the fix and two tests.ae752a7: the review's SHOULD and NITs 2 to 4. The test's fakelane-statepads the pipe instead of sleeping, and the awk shim goes.Tests.
test_280_a_lifecycle_read_whose_producer_writes_after_the_filter_exits_is_still_a_readandtest_280_a_swapping_lane_read_the_same_way_still_names_the_operation_it_supersedessit beside T018's tests.lanes-edit.shexecs the bench's real one for every verb exceptlane-state. For that, it prints thestateline, then 1.5 MiB of padding, then the rest of the record.RUNNING 141, and then that the handoff records RUNNING -> SWAPPING -> SWAPPED;21e0829'slane-handoff, both fail with "exited 141". On this head, both pass.Review. Lane 3's independent review gave LAND on
fc061fe, with one SHOULD and three NITs.The SHOULD: the original 0.3 s pause made the premise itself a race.
All four were taken in
ae752a7, and the review gave LAND onae752a7with no new findings.The old and new
lifecycle_begingave byte-identical results in 27 of 28 cases. The 28th is a NUL byte, whichlane-statecannot emit.Mutants: each of these fails both tests:
:1490fix reverted;Reverting the
:1505fix alone passes, because no test can see that site.Runs
256b9a1, treefcd3cce, branchlane3-queue/q7c-280r2-on-q6c):tests.ymlrun 39350684622, pending.f4af690) plus this PR. q6c is the main that openRepoTools becomes the openrepotools package: pipx installs the wheel with the whole payload, --install leaves pipx's link to pipx, --version names the release, and every count line says where the other commands come from (#228, PR 1 of 4) #262 and Every push proves the package builds, installs and runs: tests.yml gains a package job and runs on release/v* pushes, the two hash locks come from openRepoShape v1.1.0, and AGENTS.md names the four jobs (#228, PR 2 of 4) #267 to 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 leave.efedb60, treea9bceb1): run 39350687383, pending. This is the record for whichever of this PR and PR 3b lands second.-k "test_280 or test_t018 or triad or lifecycle_fail_open": 82 passed;-k repo_hygiene: 235 passed;Landing. This lands after lane 3's queue (#262, #267 to #271), on Brett Heap's word of 2026-10-18T20:37:07Z: "use this as approval to merge when green for all merges thru v1.1.0".
Fixes #280.
Lane: openRepoTools-3
🤖 Generated with Claude Code
Summary by Sourcery
Make lane-handoff reliably read lane lifecycles without allowing early parsing termination to corrupt the command status.
Bug Fixes:
Enhancements:
Tests: