Conversation
…reading the problem sentence oss_config already produced for it (#368) `oss_config.load()` deliberately returns an offending `default_branch` together with a sentence rather than stripping it. `resolve_base` treated a loaded config as a usable one and passed the value into `git fetch --quiet <remote> <branch>`, where argv position 4 is read as an option when the name starts with a dash. Three renderings disagreed about the same input: `blocked()` returned False and the process exited 0; `commands/tick.md` documents `could-not-resolve` as blocking with exit 3; and the `config warn:` line was rendered by `receipt()` after `git fetch` had already run -- accurate and late, the worst ordering. `resolve_base` now calls `oss_config.default_branch_problem()` before building any argv, returning `could-not-resolve` carrying that sentence. No second validation rule is added: one value keeps one rule (#345). The state word and exit 3 are unchanged, so `commands/tick.md` needed no edit -- and no consumer reads the exit code programmatically; it is read by agents from the receipt. `tests/test_lane_setup_368.py` asserts on the captured argv rather than on the exit code, since a version that ran the fetch and then failed would satisfy an exit-code assertion. Every silence assertion is paired with a positive control in the same fixture, including one that measures `branch_occupancy`'s prefixing rather than trusting the issue's prose about it. Closes #368 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015HuQoqn4iLmW2ULpvhKnwj
…ation the call site does not use Reviewer finding on 6139a98. `resolve_base` passes an explicit 300 to `_one_line`; the comment beside the head-comparison said 200, which is the function's default and not the limit in play. The comparison itself was already written to be independent of the limit -- only the sentence describing it was wrong. Co-Authored-By: Max <noreply>
…nd worktree_occupancy's third state was unreachable (#372, #373) #372 (forges, held the tag). receipt() printed config values raw, so a newline in one forged receipt lines a reader cannot tell from the tool's own -- in output SKILL.md and tick.md both instruct maintainers to paste verbatim into a developer brief. The file's own `_one_line` ("A newline in either forges a receipt line") was applied to `detail` and the board lines and skipped everywhere else. Four fields were measured forging, not the three the audit reached: `branch_pattern`, `worktree_root`, the `--repo` argv, and -- found while fixing those -- an oss_config **problem sentence** built from a hostile JSON *key*. That fourth one needs no hostile value anywhere, and oss_config cannot close it at its end without refusing to name the key that is wrong. So the guard is at the single point where the receipt is joined, not on a list of fields: a per-field guard closes what somebody enumerated and leaves the next field added unguarded. Deliberately not `_one_line` at that point. Its `" ".join(split())` collapses runs of spaces and every row is aligned by `_row`'s `{0:<10}` padding, so folding the assembled line through it turns `repo : x` into `repo : x`. Only the forging half is applied -- every character outside printable ASCII becomes `?` -- and a truncated line is marked, since a cut line rendering as a complete one is this repo's own defect class pointed at its own receipt. #373 (misreports). worktree_occupancy used `os.path.exists`, which swallows OSError, so an unreadable parent came back False and the receipt printed `[free]`. It now asks `os.stat` once and lets the exception in hand answer: FileNotFoundError/NotADirectoryError are absence, every other OSError is "could not look". No second question to the filesystem, no errno table -- Windows folds several Win32 codes onto ENOENT. doctor._dir_state (#363, same delta) answers `unreadable` on the identical path and was deliberately NOT lifted into a shared module: it asks "is this a directory" where this asks "is anything there", and it has four call sites and its own tests inside a 5,000-line diagnostic. What holds the two together is a test running both on one fixture that fails if either changes its mind -- not the prose saying they agree. Tests assert the rendered line count against a clean control rather than that a regex matched, and every deny is confirmed by attempting the exact operation, skipping loudly with the platform and what went untested when it does not take. Closes #372 Closes #373 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015HuQoqn4iLmW2ULpvhKnwj
… does not close Raised by the audit spawn on 8cb200e and judged real. CLAUDE.md's own measurement is that an over-long path arrives on Windows as FileNotFoundError, errno 2, winerror None -- no distinguishing signal -- so a derived path past MAX_PATH on a runner without LongPathsEnabled is classified as ordinary absence and printed [free], which is the confident absence #373 exists to close, reachable through the one exception type the fix treats as safe. Not closed here, and deliberately not by a length check: MAX_PATH is conditional on a machine setting, and a constant would be exactly the errno-table antipattern this function was rewritten to avoid. doctor._dir_state carries the identical gap by the identical argument, so closing it is one decision about two functions and belongs in its own change. Filed for the maintainer rather than fixed; ranked misreports, which ships behind a filed issue. Co-Authored-By: Max <noreply>
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 #368
Closes #372
Closes #373
Three defects in
scripts/lane_setup.py, all from thev0.7.0..be36015release audit. One held the tag.#368 -- resolve_base built git argv from a value oss_config had already refused
oss_config.load()deliberately returns an offendingdefault_branchtogether with a sentence rather than stripping it.resolve_base()treated a loaded config as a usable one and passed the value intogit fetch --quiet <remote> <branch>, where argv position 4 is read as an option when the name starts with a dash. Reproduced with_gitstubbed, so nothing executed:Three renderings disagreed:
blocked()returnedFalseand the process exited0;commands/tick.mddocumentscould-not-resolveas blocking with exit3; and theconfig warn:line was rendered, aftergit fetchhad already run.resolve_basenow callsoss_config.default_branch_problem()before building any argv. No second validation rule -- the existing one is consulted, so one value keeps one rule (#345).The judgment call the issue left open, checked rather than inherited. Every consumer of
lane_setup.pywas grepped and nothing shells it programmatically; its only callers arecommands/tick.mdandskills/manager/SKILL.md, both of which name the script for an agent to run and read the receipt from. So exit3is read as a stop, never as a crash by a script, and the existing state word was already right. No edit tocommands/tick.mdwas needed and none was made.#372 -- receipt() forged lines, and there were four fields, not three
Ranked
forges; this is the one that held the tag.receipt()printed config-sourced values raw, so a newline forged receipt lines a reader cannot tell from the tool's own -- in outputskills/manager/SKILL.mdandcommands/tick.mdboth instruct maintainers to paste verbatim into a developer brief. The file's own_one_line("A newline in either forges a receipt line") was applied todetailand the board lines and skipped everywhere else.The audit reached three fields. Measured here, four forge, each adding 2 lines:
branch_pattern.oss.json-- the filed caseworktree_root.oss.local.jsonrepo--repoargvoss_configproblem sentenceThe fourth is the one that decided the shape of the fix. It needs no hostile value anywhere -- only a hostile key -- and
oss_configcannot close it at its end without refusing to name the key that is wrong:So the guard is at the single point where the receipt is joined, not on a list of fields: a per-field guard closes what somebody enumerated and leaves the next field added unguarded.
Deliberately not
_one_lineat that point. Its" ".join(text.split())collapses runs of spaces, and every row is aligned by_row's{0:<10}padding -- folding the assembled line through it turnsrepo : xintorepo : xand destroys the column the receipt is read by. Only the forging half is applied: every character outside printable ASCII becomes?, which covers LF, CR, the C0 controls, DEL and U+2028/U+2029, and leaves spaces alone._one_linestill runs where it already ran, so this is additive.A truncated line is marked. A cut line rendering as a complete one is this repository's own defect class pointed at its own receipt.
Whether
oss_configshould also grow a content rule forbranch_patternis a separate question and is deliberately not answered here (#345).#373 -- worktree_occupancy's third state was unreachable
It rendered
already exists/free/unknownand usedos.path.exists, which swallowsOSError, so an unreadable parent came backFalseand printed[free].unknownwas reachable only whenpathwas falsy -- the one case it existed for could not produce it. Reproduced, deny confirmed by attempting the operation:Now
os.statis asked once and the exception in hand answers:FileNotFoundError/NotADirectoryErrorare absence, every otherOSErroris "could not look". No second question to the filesystem and no errno table -- Windows folds several Win32 codes ontoENOENT.doctor._dir_statewas deliberately not lifted into a shared module. It asks is this a directory where this asks is anything there; it has four call sites and its own tests inside a 5,000-line diagnostic; and the brief said to solve locally rather than refactor unreviewed. What holds the two together istest_the_two_classifiers_agree_on_the_same_path, which runs both on one fixture and fails if either changes its mind -- the second-measurement mechanism, not a test that states the same claim twice.One gap written down and not closed
The audit spawn raised it and it is real: on Windows an over-long path arrives as
FileNotFoundError, errno 2, winerror None-- no distinguishing signal -- so a derived path pastMAX_PATHon a runner withoutLongPathsEnabledis classified as ordinary absence and printed[free]. That is #373's own shape, reachable through the one exception type the fix treats as safe. Not closed here, and not by a length check:MAX_PATHis conditional on a machine setting and a constant would be the errno table this function was rewritten to avoid.doctor._dir_statecarries it identically, so it is one decision about two functions. Recorded in the docstring and handed back for filing; rankedmisreports, which ships behind a filed issue.Tests
27 new cases across three files. Assertions are on captured argv (#368) and on the rendered line count against a clean control (#372), not on exit codes or regex matches: a version that ran the fetch and then failed, or folded the value and printed it elsewhere, would satisfy the weaker form. Every "must not fire" case is paired with a "must fire" one in the same fixture, and #373's deny is confirmed by attempting the exact operation, skipping loudly with the platform and what went untested when it does not take.
Red and green were watched separately for each issue: #368
4 failed, 4 passedthen8 passed; #3728 failed, 3 passedthen11 passed; #3733 failed, 5 passedthen8 passed. In every red run the passing cases are the controls, which must pass in both states. Full suite2637 passed, 2 skipped, coverage 92.52%.Verified by the maintainer
Independent red re-run: all three new test files on
origin/mainin a detached worktree,scripts/lane_setup.pyuntouched.That is 4+8+3 failed and 4+3+5 passed — exactly the three per-issue splits the report claims,
reproduced in one run rather than three, so the controls are the same twelve in both readings.
The
misreportsgap this PR records and does not close — an over-long path on Windows arriving asFileNotFoundError, errno 2, winerror Noneand being classified as ordinary absence, in bothworktree_occupancyanddoctor._dir_state— has been filed as #380, so thereport-for-filingitem is discharged rather than left in a merged report nobody rereads.