Repository navigation
T017: A tree record that names no absolute path makes its lane UNREAD, so a sync and a reconcile keep the lane's rows instead of swapping the tree's row for one keyed by the record's id (opensoft/openRepoTools#302) (part of opensoft/openRepoTools#186) - #6
Merged
Merged
Conversation
…lane UNREAD, so a sync and a reconcile keep the lane's rows instead of swapping the tree's row for one keyed by the record's id T017 continuation, in opensoft/openRepoTools-code, of the opensoft/openRepoTools branch fix/pathless-tree-record-302 at 01c83b70ebf3a91adea40cf76fe4f1d8a2eecf48 (issue opensoft/openRepoTools#302). It carries that branch's own change against 3e97ae5, the head of fix/control-root-unsearchable-291 it is stacked on, for the code leg's paths: lanes-edit.sh (worktree_rows and its two comment blocks), lanes-index (comments only), tests/test_lanes_index.py and tests/test_pathless_tree_record_302.py. Its one other path, docs/README-lanes.md (+22 -9), belongs to the spec leg and is not in this commit. worktree_rows collects the ids of tree records that were read and name no absolute path beside the ids opensoft/openRepoTools#291's part F collects, asks the record's own path before the id stands in for it, and gives the lane one UNREAD line that names both kinds. The subjects below are quoted from the originals; a bare #N in them is opensoft/openRepoTools#N. Old-to-new receipt (the original's own non-merge commits; e7f86b6fe02d also changes docs/README-lanes.md, whose part is the spec leg's): e094080de29f Add the tests that a tree record that is read and names no absolute path holds its lane's rows in the inventory index, as part F holds a record that could not be read (#302) d035807239e7 lanes-edit.sh worktrees names a lane UNREAD beside a tree record that was read and names no absolute path, so a sync keeps the lane's rows instead of swapping the tree's row for one keyed by the record's id (#302) e7f86b6fe02d The README and the lanes-index comments no longer say a sidecar with no path: is a tree with an empty path, and the README says what a record that names no absolute path costs its lane (#302) 01c83b70ebf3 Add the tests that the UNREAD line names every tree record that names no absolute path, and that the clause holds its own lane and no other (#302) Resolutions: none. The patch applied without conflict, at offsets only: lanes-edit.sh +97 and +118 lines, from opensoft/openRepoTools#295's and opensoft/openRepoTools#301's commits below it in this chain. Lane: openRepoTools-4 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Reviewer's GuideImplementationMark a lane UNREAD when a readable tree record names no absolute path, combining that reason with unreadable-record reasons in one lane-level line and updating the related code comments.
TestsUpdate the existing worktree-index test and add coverage for pathless records, lane-level row retention, combined unread reasons, reconciliation, and control cases.
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
This was referenced Nov 7, 2026
|
brettheap
changed the base branch from
fix/control-root-unsearchable-291
to
main
November 8, 2026 13:48
brettheap
marked this pull request as ready for review
November 8, 2026 13:48
|
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 6 days and 4 hours by commenting |
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.



What this is
This is the T017 continuation, in this leg (opensoft/openRepoTools-code), of the
opensoft/openRepoToolsbranchfix/pathless-tree-record-302at01c83b70ebf3, for opensoft/openRepoTools#302 (part of opensoft/openRepoTools#186). The original tree and branch stay as the archived original (lane 4's decision, opensoft/openRepoTools#186 comment 6548343086). One commit here,4ed3fd2ad6fe, carries it.It carries that branch's own change against
3e97ae5, the head offix/control-root-unsearchable-291it is stacked on (so against the previous PR of this chain), with no merge of main, for the code leg's paths:lanes-edit.sh(+41 −5,worktree_rowsand its two comment blocks only),lanes-index(+9 −5, comments only),tests/test_lanes_index.py(+24 −18) and the newtests/test_pathless_tree_record_302.py(+518). Its one other path,docs/README-lanes.md(+22 −9), is the spec leg's, in the paired PR.lane-startandlane-handoffhave no diff.What was wrong and what changed
What was wrong
A tree record is the file
<control root>/trees/<id>.yamlthatset-lane-treewrites. One that is read and names no absolute path (nopath:line, an emptypath:, a relativepath:, or a record of another schema with none) is listed byworktreesas aTREErow keyed by the record's id, or by its relative text, where the path would be. The inventory index keys each tree<lane>:<path>, so a sync took that row for the tree and removed the row the record had last given under the tree's real path: its path, branch, counts and last commit. Nothing said the lane was not read.Found by the writer of the opensoft/openRepoTools#291 fix, who put it to Brett Heap as a ruling and recommended a separate v1.2.0 issue (ruling 3 of opensoft/openRepoTools#291). It is at main before opensoft/openRepoTools#291. This change is stacked on opensoft/openRepoTools#291's and changes one function of
lanes-edit.sh,worktree_rows.A record with no
path:line is not a whole record (since opensoft/openRepoTools#252, opensoft/openRepoTools#115), and the helper lists it under its own id.worktree_rowsmakes it aTREErow with the branchmalformed sidecarand puts the record's id in the path column, on purpose: the header comment says the id stands where the path would be. The indexer keys the tree<lane>:<id>, so the row the record last gave, under its real path, is not in the listing. A sync removes it and writes the id-keyed row.worktree_rowsprinted noUNREADline for the lane, sorun_inventorydid not hold it.The writer's probe at
3e97ae5(a sandbox estate, one lane and one tree per case, a first sync, one record changed, then a second sync) printed1 upserted, 1 removedand noUNREADfor every shape below, and removed the tree's own row:path:line: the new row isrepoB-1:c0-repoB-1, branchmalformed sidecar;path:: the same;path:: the same key, branchunknown schema 2;path:: the key is the relative text, branchmalformed sidecar;path:and an empty file, which the issue's rule reaches.Controls at
3e97ae5: a malformed record or a schema 2 record that names an ABSOLUTE path keeps its key, and its row is rewritten in place (1 upserted, 0 removed); a whole record is upserted in place;lane-treesexits 0 with its<malformed>row in every case.What changed
worktree_rowscollectswr_nopathnext towr_unrec(the ids A lane control root that cannot be searched reads as "no trees", so an inventory sync removes its rows (from #289's review) openRepoTools#291's part F collects). In the<malformed>arm and in the other-schema arm,case "${t_p:-}" in /*)asks the record's own path BEFORE the id stands in for it. The order matters in the second arm:lane_trees_listgives a record of another schema the id it claims, so a claim that is itself absolute (tree: /x/y) would pass an ask made after the fallback.UNREADline per lane. The indexer keeps one reason per lane (unread[lane] = why), so a second line would replace the first. A lane with unreadable records and records that name no absolute path says both: part F's clause, then;, thenthese records under <root>/trees name no absolute path, so which tree each records is not known: <ids>. That is lane 3's wording (finding 522): it does not say "read" inside the indexer's own "its inventory could not be read (...)" prefix.lane_trees_list,lane_sidecar_schema_ok,lane-trees,lanes,lane-startandlane-handoffare untouched, andlanes --worktreesnow prints its NOT READ line and footer for such a lane.tests/test_lanes_index.py(test_a_tree_with_no_path_is_a_tree_and_not_an_unread_marker): it no longer files a record with nopath:, since its lane now reads as not read. It keeps the record that is not whole but names the whole tree's path; its counts go from 7 to 6 and from 3 to 2. The marker's key rule for a row with no path stays pinned by the forged-line tests beside it.lanes-index: comments only, atUNREAD_BRANCHand incollect_inventory(no code inlanes-indexchanges).worktree_rowswas unpinned, because every case put its record inrepoB-1, which is read last (762).test_the_line_names_every_record_that_names_no_absolute_pathandtest_a_record_that_names_no_absolute_path_holds_its_own_lane_and_no_otherclose both.Not in this PR
lane-treeskeeps its exit 0 and its<malformed>row for such a record, as the handoff reads it per record (The handoff's tree inventory names a record it could not read whatever its schema, and a leg directory it cannot search is never read as absent (#246 follow-up, before the cutover) openRepoTools#255).rename-laneandset-lane-state's fence) are A control root nobody can search reads as an empty one in two writers: rename-lane leaves the lifecycle records behind without a word, and set-lane-state's fence says 7 for a race that never happened (from #291) openRepoTools#309, not this PR.Inventory.normnote (A tree record with no path: line still swaps the tree's row in the inventory index for a row keyed by the record's id: the loss #291's part F fixes for an unreadable record is open for a malformed one openRepoTools#302 comment 6371844475) is not this PR's: twotest_lanes_indexcases fail whenever the run root contains a name such asc302-309-work, becauseInventory.normappliesTREE_IDbefore it replaces the root. They fail the same way at3e97ae5. Lane 3 keeps it for v1.2.0. In this leg it does not bite. The CODE writer's targeted run at this commit (-k "test_pathless_tree_record_302 or test_lanes_index", run root under.../sandbox-CODE/t) passed all 116 cases,test_lanes_index's among them, and the run at the chain's last commit (-k "test_named_read_unreadable_290 or test_lanes_index") passed 120. No commit of the chain touchesTREE_IDorInventory.norm(git diff main..tipoftests/test_lanes_index.pyhas no such line). It bites only where a path component of the run root has the formc<digits>-<name>: the pattern\bc[0-9]+-[A-Za-z0-9._-]+matches/tmp/c302-309-work/pytest-0/test_x0/iand matches none of the run roots checked here, the CODE writer's,/tmp/pytest-of-runner/pytest-0/test_x0/iand a runner workspace such as/home/runner/work/openRepoTools-code/openRepoTools-code. This chain neither fixes it nor makes it worse.Old to new: the receipt
The original's own non-merge commits in
opensoft/openRepoTools(3e97ae5..01c83b7), 4 in all, are carried by one commit in this leg,4ed3fd2ad6fe. The list is the commit's own body, and it equals the original's non-merge commits read from the chain'srefs/root/ref (checked).The subjects are the original's, byte for byte; a bare
(#N)in them names the root issue.Resolutions
None. The patch applied without conflict, at offsets only:
lanes-edit.sh+97 and +118 lines, from opensoft/openRepoTools#295's and opensoft/openRepoTools#301's commits below it in this chain.The pairing
The manual's part of this change (
docs/README-lanes.md, +22 −9) is the commit7c80dc826965onfix/pathless-tree-record-302in opensoft/openRepoTools-spec, its own PR, opensoft/openRepoTools-spec#9 (basefix/control-root-unsearchable-291). The code leg's checks read the manual throughOPENREPOTOOLS_SPEC_ROOT:tests/test_repo_hygiene.pyreadsdocs/README-lanes.md(call sites at lines 1373, 1404, 1423, 3139 and 3572 of the code leg'smain; 1404 is the tuple of surfaces that a loop reads throughdoc()) andtests/test_test_roots.pypins which manual a run reads. The code leg's own CI (OPENREPOTOOLS_COMPOSED: '0', no spec leg beside the checkout) skips those checks, so they bind only in a composed run or with the variable set to a spec clone. A search of the manual lines this change touches for the strings those checks pin (the rung-count heading, the two settlement quotes,every lane on this workstation, the exit-code section's two markers andlane-end <lane> --retire) finds none: read, not run. So the two PRs are one change in two repositories, and they land together, as a pair. The code PR goes first, so that the manual never describes behaviour the code lacks: this PR first, then its spec PR, opensoft/openRepoTools-spec#9. The state that order passes through, the code chain's tip beside the spec leg'smain, passed-k test_repo_hygienein the independent review (run (e) under Tests: 223 passed, 14 skipped; that run read the chains' tips, not this commit alone). The other order's state, the spec tip beside the code leg'smain, was not run. I found no check that turns either order red; that is a reading, not a run.Tests
Run by the CODE writer, in a sandbox clone, with
env -i(HOME, XDG_* and TMPDIR inside the sandbox),OPENREPOTOOLS_CODE_ROOTset andOPENREPOTOOLS_COMPOSED=0, as the leg's CI sets it. Each targeted run read this branch's own commit in its own worktree; that commit was2ca415e7cc76before the message amend, and the amend kept its tree, so the results stand for4ed3fd2ad6fe.bash -nonlanes-edit.sh,laneandlanes, at every commit of the chainpy_compileon every changed.pyfile and onlanes-indexrun.sh -k "test_pathless_tree_record_302 or test_lanes_index"shellcheck, over the whole chain (mainto the tip): errors 0 to 0 and warnings 108 to 108 (lane14 to 14,lanes8 to 8); notes up by 3, 2 and 2, all SC1003 on the literal'\'patterns of opensoft/openRepoTools#301's commit.The pair runs below are of the two chains' tips, so they cover this commit with every later commit of its chain; apart from the targeted run above, no run was made at this commit alone. They are lane 4's independent paired review, 2026-10-31 (the letters are the review report's own), with
OPENREPOTOOLS_SPEC_ROOTset to the spec clone shown,env -i,TMPDIR=/tmpand a 54-characterXDG_STATE_HOME.-k test_repo_hygiene5f2995d43893+ spec tip8104f2cf965c-k test_repo_hygiene, baselinemain2a057a6+ specmain9f8b21a-k lane_helpers-k test_repo_hygiene5f2995d43893+ specmain9f8b21aThe pair runs read the chains' tips as they were before the message amend (code
5f2995d43893, spec8104f2cf965c). The amend kept every tree (git difffrom each old commit to its new one is empty), so the runs stand for the amended tips, code2c15aa6613c3and spec430ea20784ac. No failure is new at the tips. Run (d), the manual-reading tests at each branch, was skipped under the review's brief, because none of the five branches' test files reads the manual.The CODE writer's first run of
-k lane_helpersat the chain's tip, with a 212-character run root, gave 5 FAILs in the shell suite (4870 ok, 5 FAIL, 3 skipped), becauserc_tree_idintests/test_lane_helpers.shlacks the 180-character cap thattree_id_forinlanes-edit.shhas, so at that length the two names differ and the planted records are never read; the chain changes neither, and run (c) above, with the 54-character state root, gave 0 FAIL.Not run: the suite at the leg's
mainfor comparison, bash 3.2, macOS and the assembly's composed check; the submodule was not initialized, so 6 tests skip.Test files this commit adds or changes:
tests/test_pathless_tree_record_302.py, new (+518): 18 cases from 10 test functions at the root head, on A lane control root that cannot be searched reads as "no trees", so an inventory sync removes its rows (from #289's review) openRepoTools#291's estate helpers. Eight shapes, one case each (the four the issue probed, the two its rule reaches, and finding 523's two); the reads and the reconcile (lanes --worktrees,lanes --index --worktrees,lane-treesexit 0,reconcile --source inventory); the cost (a second tree's change and a tree filed meanwhile stay out of the index); one line for both kinds; four controls that hold before and after; and lane 3's two (761, 762).tests/test_lanes_index.py, changed (+24 −18): the one existing testtest_a_tree_with_no_path_is_a_tree_and_not_an_unread_marker, as What changed says.The original's own record, from the root repository, at the root heads and not repeated in this leg: lane 3's red run at
3e97ae5(28 failed, 15 passedfor this file's first 13 cases and opensoft/openRepoTools#309's together; this file's were 9 red and 4 green, as the design predicted);18 passedfor-k test_pathless_tree_record_302at01c83b7; five mutants, each killed (lane 4's M3, M4 and M8, and lane 3's mA and mB, which the last two tests kill alone). In the shell suite-k lane_helpersgave 4889 ok and 2 FAIL, bothlane-startregister-row asserts whose expecteddirsits under the run root (opensoft/openRepoTools#304).Release notes (v1.2.0)
Proposed in lane 4's post to lane 3 (opensoft/openRepoTools#302 comment 6354092305). Not established: whether lane 3 accepts the line; it has not commented on it. Lane 3 ruled (opensoft/openRepoTools#301 comment 6352342484) that each line goes in the PR description.
A tree record that names no absolute path no longer swaps its tree's row in the index for one keyed by the record's id.
worktreesnames the laneUNREAD, solanes-index syncandreconcile --source inventorykeep the lane's rows and say why. One such record holds every row of its lane until it is put right. (opensoft/openRepoTools#302)The line is here, in the code PR of the pair, and only here: the paired spec PR, opensoft/openRepoTools-spec#9, repeats none.
Review
READY, lane 4's independent paired review of both chains, 2026-10-31. It found no MUST and no SHOULD against the commits, and three NITs. Report sha256:
4ac9e5441affc6aeac48e6d73419580f6786440dc0e5dd32722cc40b8070a682. The review read the chains before the message amend (tips5f2995d43893and8104f2cf965c, the same trees as the amended tips).lanes-indexlines 1904 to 1905, docstring only:lane_generation's docstring reads as the full list oflane-state's 10s, but since A lane control root that cannot be searched reads as "no trees", so an inventory sync removes its rows (from #289's review) openRepoTools#291 there is a third, a blocked lookup; optional, and the same text would arise when the root branches land.rc_tree_idlacks the 180-character cap, so the shell suite fails when the run root is longer than about 111 characters, and the shell suite does not setXDG_STATE_HOME, so run (c) left two files outside its run root.The original's recorded review, from the root repository; the comment ids are copied from the root draft, which lists them as the comments of opensoft/openRepoTools#302, and were not re-read (no network):
e7f86b6(comment 6371844475): READY AFTER FIXES, the two findings (761 and 762) SHOULD tests, with no source or doc change asked for; both are the original's last commit.01c83b7(comment 6375703768): READY TO LAND, after v1.1.0 and A lane control root that cannot be searched reads as "no trees", so an inventory sync removes its rows (from #289's review) openRepoTools#291, no finding. The root's CI run 40018484042 at01c83b7was green on all four jobs.Landing
It lands only on Brett Heap's word, PR by PR; nothing in this text is a landing.
fix/control-root-unsearchable-291(the code PR for A lane control root that cannot be searched reads as "no trees", so an inventory sync removes its rows (from #289's review) openRepoTools#291, T017: A lane control root that cannot be searched is read as not read, not as no trees: lane-state and lane-trees exit 10, the listing says UNREAD, and a sync keeps the lane's rows (opensoft/openRepoTools#291) (part of opensoft/openRepoTools#186) #5), which lands before it. The original is stacked the same way, and its patch applied here without conflict, at offsets only:lanes-edit.sh+97 and +118 lines, from A lane whose recorded dir has a space is missing from worktrees --all and the inventory index: worktree_rows hands lane_control_root the dir unquoted, and payload_subfield cuts it at the first space openRepoTools#295's and Three ways a stored lane sub-field is misread: a TAB in a recorded dir drops the lane from worktrees --all, payload_subfield expands backslash escapes through awk -v, and request-handoff writes its by host sub-field unquoted openRepoTools#301's commits below it in this chain.fix/control-root-unsearchable-291, the branch of T017: A lane control root that cannot be searched is read as not read, not as no trees: lane-state and lane-trees exit 10, the listing says UNREAD, and a sync keeps the lane's rows (opensoft/openRepoTools#291) (part of opensoft/openRepoTools#186) #5.mainshowsMerge pull request #1). A merge commit keeps this commit's message and its receipt byte for byte, and the stacked chain lands as built, each PR after the one its base names. A PR stacked on this one is retargeted tomainbefore this PR's branch is deleted: deleting a merged base branch first closes the dependent PR.33ce26dinto the branch at open", with its push and the PR's own CI record:33ce26dis the root's frozenmain, and this leg's ownmainis the base here (the head is the commit above, with nothing merged in).[REFRESH AT PR TIME ...]and[REFRESH AT LAND TIME ...]brackets, which name the root's own CI runs and the root landing; this leg's own checks at open are recorded when the PR is opened (see Tests).Closes #Nline and itsgh pr merge --squash --match-head-commit --body-filesteps, with theland-ort4.shandland-ort3.shnotes: the commit's own message stands in, byte for byte, andCloses #Nbecomes "part of", with no closing keyword.lanes-edit.sh, equal at the base and at the head, and a call-site diff that prints nothing), on git objects only. The md5 isb0809a1e84722f1f518941b0063c926d(65 lines), lane 3's own recorded value, at the leg'smain2a057a6d84e5and at every commit of the chain, this commit4ed3fd2ad6feamong them. The call-site diff from this PR's base (the commitca9b847f678eof A lane control root that cannot be searched reads as "no trees", so an inventory sync removes its rows (from #289's review) openRepoTools#291) to this commit prints no line, out of 46 changed lines oflanes-edit.sh, so the check is not vacuous; frommainto this commit it prints none either, out of 388. The term holds.Lane: openRepoTools-4
Claim: opensoft/openRepoTools#302 (comment 6349903174)
🤖 Generated with Claude Code
Summary by Sourcery
Keep inventory lanes intact when tree records do not identify an absolute path, and clearly report the records preventing a reliable tree mapping.
New Features:
Bug Fixes:
Enhancements:
Tests: