Skip to content

Read the clause (c) TAIL case on a checkout at a short fixed path, and drive lane-start's row stamp at three checkout lengths, so the case no longer answers by the length of the run root (#180) - #215

Open
brettheap wants to merge 5 commits into
mainfrom
fix/row-stamp-tail-case-180

Conversation

@brettheap

@brettheap brettheap commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

Closes #180

What was wrong

tests/test_lane_helpers.sh's clause (c) TAIL case asserted that repoA11b-1's row stamp ends dir $HOME/projects/repoA11b; window a11start:3 @42. lane-start's stamp is ONE line under ratified decision O1's 240-character cap (Amendment 13(a)). cut_to_line cuts it at 230 and drops the last partial word. The tail is the checkout path, so the case only passed while $HOME was short. Under plain pytest's /tmp it was green. Under tests/run.sh's per-run root (TMPDIR about 71 characters, so $HOME about 91) the line passed 230, and the cut landed on the ; right after the path, so the path went whole: the row read … window renamed, no launch; dir .... On macOS's runner the case was at the edge.

Reproduced outside the shell suite with a real lane-start, started twice --no-launch, under a 92-character $HOME:

  • checkout under $HOME (107 characters): … window renamed, no launch; dir <107 chars>; .... The window is gone and the head is intact.
  • the same $HOME with the checkout passed as --dir /tmp/ort-tail.XXXXXXXX/repoZ (28 characters): … no launch; dir /tmp/ort-tail.…/repoZ; window testsess:0 @1, 197 characters in all.

Why (A), the test-side fix, and not (B)

The cut is behaving as designed. Nothing in the stamp is broken under long paths.

  • The design puts dir and window last on purpose. lane-start's Amendment 13(a) comment above the stamp (:3668-3677) orders the tail launch first, then dir and window, so "a line long enough to be cut loses what a reader can look up rather than what they cannot". Both facts are sub-fields of the same act's STARTED/RESUMED line in the lane's log, which lane-dir reads and the new test asserts in full. Both are also columns of Amendment 11's listing. No reader parses dir out of the state cell (checked with grep across lane-start, lane-end, lanes-edit.sh, lane, lanes, lane-rename, lane-worktrees, link-estates).
  • The cut is already routine in production. Any launching resume (launching claude --name <lane> --resume <uuid>) is past 230 before dir even starts. So "the stamp drops dir/window under a long line" is today's normal behaviour, not an edge case of long paths.
  • (B) would write a non-path after dir. Today a cut that lands inside the path drops it whole (dir ...), so the row never carries a truncated path that reads as a real one. (B)'s "truncate the dir, keep the facts" would put an elided path there. That changes the stamp format of a governed artefact, which is for the protocol to decide, not for a test fix.
  • (B) alone cannot fix this case. The case asserts the FULL dir $HOME/…, which cannot fit under the cap at run.sh's length whatever the stamp does.
  • cut_to_line is pinned. test_the_three_row_writers_carry_the_same_one_line_cut_byte_for_byte pins it byte for byte across lane-start, lane-end and lane-handoff.

So the case reads the tail on a checkout whose path has the same length wherever the suite runs. No product code changes. tests/run.sh is untouched: lane 1's #195 edits it.

What changed

tests/test_lane_helpers.sh (edited in place, never at the end; ranges are at this head):

  • :66-67: A11T_ROOT="" beside SANDBOX=, before the traps, so cleanup never acts on an inherited value.
  • cleanup() :101-103: removes $A11T_ROOT. It runs on EXIT, INT and TERM. Open PR A silent tmux is no longer read as a dead window, the companion verdict is read off the lane's live window from any window, and the guard's cure for a lane named before Rule 4 says what it cannot fill in (#73) #222 (at 2946a41) also adds a line to cleanup() here, so the two conflict in this one hunk of tests/test_lane_helpers.sh (~:101). The resolution is to keep both lines, and it falls to whichever PR lands second.
  • clause (c) block :5356-5389: replaces the old :5351-5356.
    • repoA11b-1's second start keeps its exit, , no launch and head assertions. These do not depend on the root. One description now reads "…and its stamp says what actually happened" because its antecedent moved.
    • The TAIL assertion moves to a new lane repoA11t-1, whose checkout is mktemp -d <base>/ort-a11t.XXXXXX + /repoA11t. <base> is the sandbox's own $TMPDIR when that is at most 40 characters (plain pytest on Linux, where the checkout then lives inside $SANDBOX), and /tmp when it is not (run.sh, macOS). So the checkout is at most 65 characters, an assertion holds it there, and the line stays under about 210 wherever the root is. It runs in its own fake window a11tail:5 @43, which nothing else in the suite uses.
    • Only a SIGKILLed run under a long root leaves an ort-a11t.* behind, and it is in /tmp, outside run.sh's per-run root. Any other exit is cleaned up by cleanup.
    • The lane is started with --dir, then started again, and the second start reads the checkout back from the lane's log, the same shape as before.
    • repoA11b-1 keeps $HOME/projects/repoA11b as its recorded directory, because the later DIRECTORY PRECEDENCE dry-run (:5668) reads it back.

tests/test_lane_start_row_stamp.py (new): three parametrized cases, each a real lane-start started twice --no-launch in a sandbox whose $HOME is at least run.sh's length. The checkout is at an exact length under a /tmp mkdtemp, so the answer does not depend on pytest's own basetemp. The workspace seed is a data table written in a loop, which also clears SonarCloud's duplication gate against tests/test_lane_start_claude_current.py:

All three also assert the head, the 240 cap, and the lane log's full dir …; window ….

Tests

  • Local, under the shared lock (flock -w 1800 ${TMPDIR:-/tmp}/openrepotools-pytest.lock, lock taken 20:40:57Z, at the fix round's tree):
  • CI at 085a234 (before this fix round): the Linux tests job passed, 1422 passed and 9 skipped. Two sibling PRs on the same base that add no pytest cases show 1419 passed and 9 skipped, so the difference is the three new cases. The shell suite's wrapper passed too. Every other job passed, except tests-macos, which waits for the ready label.
  • SonarCloud at 085a234 failed its quality gate on 4.7% new-code duplication: the register seed, :164-177, against tests/test_lane_start_claude_current.py:198-211. The seed is restructured at this head.

🤖 Generated with Claude Code

Summary by Sourcery

Stabilize lane row-stamp coverage by testing checkout paths at controlled lengths instead of relying on the surrounding run root.

Bug Fixes:

  • Make the clause (c) TAIL test independent of the run-root and home-directory path length by using a short fixed checkout path.
  • Add coverage for row-stamp behavior across short, boundary-length, and long checkout paths, verifying paths are dropped whole rather than truncated.

Enhancements:

  • Preserve validation of the complete directory and window details in the lane log while testing the capped row stamp.

Tests:

  • Add parametrized integration tests that start lanes twice with real checkout paths and verify row-stamp caps, preserved heads, and path-dependent tail cuts.

Brett Heap and others added 2 commits October 13, 2026 18:25
… is a measured design and not a run root's accident

The stamp's tail (Amendment 11(c)'s dir and window) is what cut_to_line
takes first under ratified decision O1's cap; its length is the checkout
path's, not the run root's. A real lane-start, started twice --no-launch
under a $HOME at least as long as tests/run.sh's, with the checkout at a
short fixed path (tail intact), at 100 characters (window lost, #180's
shape) and at 160 (the path dropped whole, never truncated); the head,
the 240 cap and the log's full facts are asserted in all three.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… its answer no longer depends on the run root (#180)

Under $HOME/projects the stamp's line outgrew the 230 the cut keeps once
the run root was tests/run.sh's, and the window ref was cut: red locally,
green under CI's plain pytest. The tail is now read on a lane whose
checkout is /tmp/ort-a11t.XXXXXX/repoA11t (29 characters anywhere);
repoA11b-1's second start keeps its exit, no-launch and head assertions,
and cleanup removes the one fixture outside $SANDBOX.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@sourcery-ai

sourcery-ai Bot commented Oct 13, 2026

Copy link
Copy Markdown

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 22 hours and 56 minutes by commenting @sourcery-ai review. Upgrade to get a review now.

@sourcery-ai

sourcery-ai Bot commented Oct 13, 2026

Copy link
Copy Markdown

Reviewer's Guide

The PR fixes flaky clause (c) TAIL coverage by decoupling the full-tail assertion from variable $HOME/run-root lengths, without changing product code, and adds isolated parametrized tests that document and verify how lane-start stamps are cut at short, boundary, and long checkout paths.

File-Level Changes

Change Details Files
Make the shell-suite TAIL assertion independent of the run-root length by using a short, fixed checkout path.
  • Move the full dir/window TAIL assertion to a dedicated checkout under /tmp.
  • Start the replacement lane twice so the second invocation reads the checkout from its log, preserving the original scenario.
  • Add cleanup for the fixture created outside the suite sandbox while retaining the existing assertions on the original lane’s head and launch status.
tests/test_lane_helpers.sh
Add deterministic coverage for row-stamp truncation behavior across checkout path lengths.
  • Build an isolated workstation, register, fake tmux, and Git environment for real lane-start executions.
  • Exercise short, 100-character, and 160-character checkout paths with two --no-launch starts.
  • Verify the 240-character cap, intact stamp head, expected tail retention or whole-path omission, and full dir/window facts in the lane log.
tests/test_lane_start_row_stamp.py

Assessment against linked issues

Issue Objective Addressed Explanation
#180 Make the clause (c) TAIL case pass independently of the length of the test run root by reading the row stamp on a checkout at a short, fixed path. ✅
#180 Exercise lane-start’s row-stamp behavior at checkout lengths that fit, partially exceed, and exceed the stamp’s available space, verifying the head remains intact and the directory is not misleadingly truncated. ✅

Possibly linked issues


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

Brett Heap and others added 2 commits October 13, 2026 20:42
…ases by what the cut takes

SonarCloud counted the register seed as a 14-line copy of
test_lane_start_claude_current.py's (4.7% new-code duplication against
a 3% gate); it is now one table written in a loop, the register text
byte-identical. The 100-character case was labelled #180's shape, but
#180's row read `... no launch; dir ...`, the path dropped whole: the
ids are now window-cut-dir-kept and path-dropped-whole-as-in-180, and
the docstring says which is which.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…kout in the sandbox wherever its TMPDIR is short

An inherited A11T_ROOT would have been removed by cleanup had the suite
died before the clause (c) case. The checkout now goes under the
sandbox's own $TMPDIR when that is at most 40 characters, and under
/tmp only when it is not, with an assertion that it is at most 65
characters, so the line stays under about 210 wherever the root is.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tamp test's docstring

Since c19150f the clause (c) case's checkout goes under the sandbox's
own TMPDIR when that is short and under /tmp when it is not, so its
length is bounded at 65 characters rather than fixed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@sonarqubecloud

Copy link
Copy Markdown

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.

tests/run.sh: a long run root truncates the row stamp so test_lane_helpers.sh's clause (c) TAIL case fails locally while CI's plain pytest passes

1 participant