Skip to content

T017: A dir with a TAB or a backslash is listed, indexed and reached as recorded, a stored sub-field reads back as written, and request-handoff refuses a host or container the fence rejects (opensoft/openRepoTools#301) (part of opensoft/openRepoTools#186) - #7

Merged
brettheap merged 1 commit into
mainfrom
fix/subfield-misreads-301
Nov 8, 2026

Conversation

@brettheap

@brettheap brettheap commented Nov 7, 2026 •

Copy link
Copy Markdown
Contributor

What this is

This is the T017 continuation, in this leg (opensoft/openRepoTools-spec), of the opensoft/openRepoTools branch fix/subfield-misreads-301 at f68030f466ad, for opensoft/openRepoTools#301 (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, 454f062c13a5, carries it.

It carries the spec-leg part of that branch's own change, which is its head against e0970a8, the head of fix/dir-space-listing-295 it is stacked on: docs/README-lanes.md, +1 −1, the lanes row of the reads table, which now names the escape on column 7. opensoft/openRepoTools#295 has no path in this leg, so this PR's base is main. The change's other four paths (lane, lanes, lanes-edit.sh and tests/test_subfield_misreads_301.py) are the paired commit in opensoft/openRepoTools-code.

What was wrong and what changed

What was wrong

The lanes row of the manual's reads table documents column 7 of the listing as the directory, and said nothing of an escape. opensoft/openRepoTools#301's code now escapes column 7 the way lane-worktrees' porcelain escapes a field, because a TAB in a recorded dir shifted the listing's tab-separated row and the lane dropped out of worktrees --all and the inventory index. Option C changed the lanes contract, and lane 3's finding 501 (a MUST) asked that the manual name the escape where column 7 is documented.

What changed

One table row of docs/README-lanes.md, +1 −1: the lanes-edit.sh lanes ... row of the reads table (line 1739 of this leg's main). After its sentence that no column is ever empty it now says, in the original's words:

Column 7, the directory, is escaped the way `lane-worktrees`' porcelain escapes a field (#301): a backslash is written `\\`, a TAB `\t`, a newline `\n` and a carriage return `\r`, so a directory holding a TAB is still one column and the row still seventeen. `lanes`, `lane` and `worktrees` decode it before they show it or take it for a path, and a directory holding none of the four is printed as it is.

(The row's other text is unchanged.) The manual's added text keeps the original's bare issue numbers, such as (#N), byte for byte. In this leg's manual they name opensoft/openRepoTools issues, as its other pre-split text does.

Not in this PR

Old to new: the receipt

The original's own non-merge commits in opensoft/openRepoTools (e0970a8..f68030f), 10 in all, are carried by one commit in this leg, 454f062c13a5. The list is the commit's own body, and it equals the original's non-merge commits read from the chain's refs/root/ ref (checked).

773a562bccd1 Add the tests that a recorded dir holding a TAB or a backslash, and a requesting host holding a space, are read back as they were written (#301)
dd361f3839cf The #301 tests split the listings they read on a newline alone, not on every line boundary Python knows (#301)
430ac8f0804b The lane listing escapes a lane's directory in its seventh column as lane-worktrees' porcelain escapes a field, and lanes-edit.sh, lane and lanes decode it, so a TAB in a recorded dir no longer shifts the row (#301)
647f4511b210 request-handoff refuses a requesting host that lanes_binding_value_ok rejects, on the request path and the --force path alike, before anything is planned or written (#301)
ae14da06a53f payload_subfield hands the payload to awk through ENVIRON instead of awk -v, so a stored sub-field holding a backslash reads back as it was written (#301)
c0491f1db6f6 Pin what item 2 moves: lane-start reaches a backslash lane's own checkout, lane-handoff writes its dir back byte for byte, and its lifecycle starts again at the new root while the index holds the old rows (#301)
567035fec28b request-handoff refuses a container that lanes_binding_value_ok rejects, on the request path and the --force path alike, before anything is planned or written (#301)
27253fe78a10 The #301 tests pin a carriage return in a recorded dir and the decoders' pass-through arm, and the lanes_rows contract comment says column 7 is escaped (#301)
e1d26e135cec The #301 tests now pin the fallback for a dir the encoder cannot escape, where a refused name came from, the free-lane answer before a bad host, and a container of the fence's alphabet (#301)
f68030f466ad The #301 tests now pin a capital letter in the binding fence's whole-alphabet row and pin that a free lane's request leaves the published register where it was (#301)

The subjects are the original's, byte for byte; a bare (#N) in them names the root issue.

Of these, the commit that touches docs/README-lanes.md (the original's range on that path) is 430ac8f0804b. The others change code-leg paths only, and their part is the paired code PR's.

Resolutions

None. The patch applied clean, with no offset, onto main (opensoft/openRepoTools#295 has no path in this leg).

The pairing

The code part of this change is the commit a04c937f1b96 on fix/subfield-misreads-301 in opensoft/openRepoTools-code, its own PR, opensoft/openRepoTools-code#4 (base fix/dir-space-listing-295). The code leg's checks read the manual through OPENREPOTOOLS_SPEC_ROOT: tests/test_repo_hygiene.py reads docs/README-lanes.md (call sites at lines 1373, 1404, 1423, 3139 and 3572 of the code leg's main; 1404 is the tuple of surfaces that a loop reads through doc()) and tests/test_test_roots.py pins 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 and lane-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: the paired code PR, opensoft/openRepoTools-code#4, first, then this one. The state that order passes through, the code chain's tip beside the spec leg's main, passed -k test_repo_hygiene in 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's main, was not run. I found no check that turns either order red; that is a reading, not a run.

Tests

The manual is tested from the code leg, not here: this leg has no code and no CI workflow of its own. tests/test_repo_hygiene.py reads docs/README-lanes.md through OPENREPOTOOLS_SPEC_ROOT (tests/test_test_roots.py pins which manual a run reads). The pair is fix/subfield-misreads-301 in opensoft/openRepoTools-code, commit a04c937f1b96.

The pair's hygiene runs, from lane 4's independent paired review (2026-10-31), with OPENREPOTOOLS_SPEC_ROOT set to the spec clone shown (env -i, TMPDIR=/tmp). They read the spec chain's tip, which carries this PR's commit with the later commits of the chain; none read the manual at this commit alone. The letters are the review report's own: (c) is the shell-suite run, in the paired code PR, and (d) was skipped.

run code + spec exit counts time
(a) -k test_repo_hygiene code tip 5f2995d43893 + spec tip 8104f2cf965c 0 223 passed, 14 skipped, 2944 deselected 11.1 s (33 s wall)
(b) -k test_repo_hygiene, baseline code main 2a057a6 + spec main 9f8b21a 0 223 passed, 14 skipped, 2772 deselected 9.2 s (10 s wall)
(e) -k test_repo_hygiene code tip 5f2995d43893 + spec main 9f8b21a 0 223 passed, 14 skipped 5.5 s

The pair runs read the chains' tips as they were before the message amend (code 5f2995d43893, spec 8104f2cf965c). The amend kept every tree (git diff from each old commit to its new one is empty), so the runs stand for the amended tips, code 2c15aa6613c3 and spec 430ea20784ac. No failure is new at the tips.

Release notes (v1.2.0)

The release-notes lines for this change are in the paired code PR, opensoft/openRepoTools-code#4 (fix/subfield-misreads-301 in opensoft/openRepoTools-code), once, in the PR that carries the code change. This PR 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 (tips 5f2995d43893 and 8104f2cf965c, the same trees as the amended tips).

The original's recorded review, from the root repository: lane 3's design review of opensoft/openRepoTools#301 (comment 6351735717) raised this sentence as finding 501 (MUST), and its review of the finished code (comment 6368074244) found it done, with column 7's bytes pinned. The comment ids are copied from the root draft and were not re-read (no network).

Landing

It lands only on Brett Heap's word, PR by PR; nothing in this text is a landing.

Lane: openRepoTools-4
Claim: opensoft/openRepoTools#301 (comment 6349895849)

🤖 Generated with Claude Code

Summary by Sourcery

Document the escaped directory-field format used by lane listings.

Enhancements:

  • Document escaping and decoding rules for directory values in lane listings so paths containing tabs, backslashes, newlines, or carriage returns remain a single readable column.

Documentation:

  • Update the lanes reference table to specify the directory-field encoding used by lane listings and its decoded presentation.

…ndexed and reached as recorded, a stored sub-field reads back as it was written, and request-handoff refuses a host or container the binding fence rejects

This is the T017 continuation, in this leg
(opensoft/openRepoTools-spec), of the original opensoft/openRepoTools
branch fix/subfield-misreads-301 at
f68030f466ad49c81f02edf8f21a58423a7f8173, issue
opensoft/openRepoTools#301. The original is stacked on
fix/dir-space-listing-295 (opensoft/openRepoTools#295, head
e0970a808af5), so its own change is its head against that head;
opensoft/openRepoTools#295 has no path in this leg. Spec-leg part of its
own change: docs/README-lanes.md (+1 -1, the lanes row of the reads
table, which now names the escape on column 7). Its other paths (lane,
lanes, lanes-edit.sh and tests/test_subfield_misreads_301.py) belong to
the code leg and are the paired commit there; the leg table sends docs/
to this leg with no rename.

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 in
opensoft/openRepoTools (e0970a8..f68030f):
773a562bccd1 Add the tests that a recorded dir holding a TAB or a backslash, and a requesting host holding a space, are read back as they were written (#301)
dd361f3839cf The #301 tests split the listings they read on a newline alone, not on every line boundary Python knows (#301)
430ac8f0804b The lane listing escapes a lane's directory in its seventh column as lane-worktrees' porcelain escapes a field, and lanes-edit.sh, lane and lanes decode it, so a TAB in a recorded dir no longer shifts the row (#301)
647f4511b210 request-handoff refuses a requesting host that lanes_binding_value_ok rejects, on the request path and the --force path alike, before anything is planned or written (#301)
ae14da06a53f payload_subfield hands the payload to awk through ENVIRON instead of awk -v, so a stored sub-field holding a backslash reads back as it was written (#301)
c0491f1db6f6 Pin what item 2 moves: lane-start reaches a backslash lane's own checkout, lane-handoff writes its dir back byte for byte, and its lifecycle starts again at the new root while the index holds the old rows (#301)
567035fec28b request-handoff refuses a container that lanes_binding_value_ok rejects, on the request path and the --force path alike, before anything is planned or written (#301)
27253fe78a10 The #301 tests pin a carriage return in a recorded dir and the decoders' pass-through arm, and the lanes_rows contract comment says column 7 is escaped (#301)
e1d26e135cec The #301 tests now pin the fallback for a dir the encoder cannot escape, where a refused name came from, the free-lane answer before a bad host, and a container of the fence's alphabet (#301)
f68030f466ad The #301 tests now pin a capital letter in the binding fence's whole-alphabet row and pin that a free lane's request leaves the published register where it was (#301)

Lane: openRepoTools-4
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@sourcery-ai

sourcery-ai Bot commented Nov 7, 2026

Copy link
Copy Markdown

Reviewer's Guide

Documentation

Document the escaped representation and decoding of column 7 in the lane listing.

  • docs/README-lanes.md L1739

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've reviewed your changes and they look great!

Sourcery assessment

Approved.


Sourcery is free for open source - if you like our reviews please consider sharing them ✨

brettheap pushed a commit that referenced this pull request Nov 8, 2026
…tree equals the tree its head was tested with: the head was cut from 4233c9a, and #7 to #10 changed the manual since (opensoft/openRepoTools#198)

The merge is clean. Its tree equals what `git merge-tree --write-tree` gave
for df909ba and aed1852 before the merge was made (70b0337), and
`docs/README-lanes.md` is the only file either side touched. No conflict was
resolved by hand, and no line of the slice's text was changed.

This is an added commit on the draft branch, not a rewrite: df909ba stays
an ancestor, so the push is a fast-forward.

Lane: openreposhape-2 (openRepoShape-2)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant