The linter printed the column the hooks withhold, and said in the README that it did not (#124, #125) - #129
Merged
Merged
Conversation
…ld (#124, #125) layer directory name are text a stranger picked. `jit-dry-run.sh` echoed both verbatim at fifteen sites, while `print_untrusted()` -- the one function in that file whose job is framing tree text -- was called on patterns alone. Third instance of one channel: #35 in pre-tool-hook.sh, #113 across five reports in rebuild-tsv.sh, and now the linter jit_refusal_notice() recommends by name. That notice locates a refused row BY POSITION so its file-name column never reaches the model, then closes by telling the reader to run the command that printed it. jit_report_name() moves from rebuild-tsv.sh to common.sh and every name site in jit-dry-run.sh goes through it. Same policy, one copy: a second, subtly different answer to this question would itself be the defect. rebuild-tsv.sh is another lane file this hour and keeps its copy, which sources cleanly and is pinned to the same behaviour by tests/test-report-names.sh. A newline in a name forged a whole REFUSED row in the tool own voice. An index row cannot carry one; a layer directory and an entry file on disk both can, and the STALE report and the whole-body budget read those from the filesystem. Both reproduced on APFS before the fix. The linter keeps its reason to exist: the pattern is still verbatim on its own `untrusted>` line, and check_entry_file() -- whose whole class is unprintable, since a name carrying a separator is never a plain name either -- now closes with the row position, worded as jit_row_id() words it for the hooks. README.md claimed this tool "prints that text framed as untrusted". That described a note above the output, not containment, and it was the sentence a reader checked before trusting the report. tests/test-jit-dry-run.sh asserted the same superseded claim; that section is reversed rather than deleted. stdout, which is the report. A redirected report captured "SKIPPED -- the file is empty" into the findings file under no heading. The three refusals built inside the awk END block are routed by buffering the run and choosing the stream from its exit code -- not `print > "/dev/stderr"`, because Git Bash is a leg nobody here can observe and an awk that opened it as a real file would abort where it does not exist. --help is not a refusal and keeps stdout. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Three review findings, all applied. report_hook() -- the sample-call half of the report -- reads entry names back out of the hook own injected output rather than from an index row, so a sweep of the index readers missed it. It printed them raw, under a note claiming to describe every line below it. The channel is narrower (the grep stops at a space) and not closed: a hyphenated instruction needs no space, and nothing bounded the length. Display goes through jit_report_name(); the real name is kept everywhere it is used to look something up, and the dedup list moved off the rendered string because two withheld names render identically and would collapse into one row. common.sh and tooling.md both said tests/test-report-names.sh pinned the two copies of jit_report_name() to each other. It does not -- it only drives rebuild-tsv.sh. Nothing enforced the claim. tests/test-dry-run-names.sh now extracts the rebuild-tsv.sh copy and drives both over eleven cases including both sides of the 64-byte cap; verified by injecting a 64 -> 32 drift and watching it go red. The jit-misses.sh comment claimed exit 2 could only be its own refusal. gawk and one-true-awk both exit 2 on a fatal. The behaviour is right and the reasoning was not: an awk that aborted mid-report produced a PARTIAL report, and a partial report on stdout reads as a complete one. Both cases land on stderr with status 2, which is what the header already promises for a log that could not be evaluated. Refused: a row position for the STALE report. There is none to give -- that loop walks a glob, not an index -- and the remedy is the difference. A refused entry-file row is found and renamed one row at a time; a stale row is fixed by the rebuild the next line already names, for every stale entry at once. Written into the code rather than argued here. Two fixture gaps closed with it: a STALE name that is hostile without a newline, so that assertion is driven on a filesystem that refuses control characters too, and the second reachable awk END refusal in jit-misses.sh. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
fdaviddpt
added a commit
that referenced
this pull request
Aug 14, 2026
…ing at the wrong pair (#131) (#142) #129 left rebuild-tsv.sh's #113 copy in place because that file was owned by another lane. The lane cleared, so the copy is deleted: rebuild-tsv.sh sources common.sh and every bash call site there is now the one definition. Driven both directions through the tool afterwards -- a plain entry name still prints, a name carrying a space is still withheld -- and the report is byte-identical apart from its timing line. tests/test-dry-run-names.sh compared the two bash copies and anticipated the deletion with a NOT EVALUATED block. Neither offered option was right: a block that can only ever say it did not run is decoration, and deleting it outright would have thrown away eleven boundary cases that DO still have a subject. rebuild-tsv.sh builds three reports inside awk, awk cannot source a bash file, and JIT_AWK_REPORT_NAME restates the same character set in another language -- so of the two pairs, the one that was pinned was the one about to stop existing. The loop now drives bash against awk, and the two positive controls moved out of the conditional so a failed extraction cannot take them down with it. tooling.md's note that the copy exists went stale with it, and is rewritten in the same commit. Body-only edit; the frontmatter is untouched, so no index rebuild. Co-authored-by: Florian DAVID <fdavid@digital-village.fr> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
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 #124
Closes #125
#124
jit-dry-run.shprinted the index's entry-file column raw. That column is chosen by whoever wrote the repository you cloned — the third instance of one channel: #35 inpre-tool-hook.sh, #113 across five reports inrebuild-tsv.sh, now the linter the hooks' own refusal notice sends authors to.README.md:507claimed this tool "prints that text framed as untrusted", which was false for that column — a reader who checked the documentation before trusting the output got the wrong answer.Every entry-name, layer-directory, tool-column and sample-call name now routes through
jit_report_name().check_entry_file()gained the row position, so a withheld name still leaves the author a handle.This repository's own tree still names all 8 entries and exits 0.
A correction to the brief, which changed the shape of the fix.
jit_report_name()is not incommon.sh— #113 landed it insidescripts/rebuild-tsv.sh, which another lane owns right now, andjit-misses.shdoes not sourcecommon.shat all. Rather than move a function under another agent's feet, the canonical copy is appended tocommon.shandrebuild-tsv.shis left untouched: it sourcescommon.shand then redefines, so its copy wins there and the conflict surface is zero. A drift test pins the two, verified by injecting a 64-to-32 change into therebuild-tsv.shcopy and watching it go red, andtooling.mdrecords that the duplicate should be deleted once that lane clears.#125
jit-misses.shwrote its refusals to stdout whiletooling.mdpromises stderr. Stdout is the report: a caller redirecting it captured the refusal as though it were a finding. All six refusal paths now go to stderr.The three inside
awk ENDare routed by buffering the run and choosing the stream from the exit code — deliberately not the/dev/stderrfilename. All three awks here special-case that name, but an awk that opened it as a real file would abort where it does not exist, trading a stream bug for a silent tool.Verification
Red, before the implementation existed:
test-dry-run-names.sh12 passed, 8 failed;test-jit-misses.sh127/142, 15 failed.Maintainer re-ran both against a clean checkout of
main: 15 passed, 13 failed and 128/146, 18 failed — more failures than reported on both, not fewer.Green: 28/28 and 148/148;
bash tests/run-all.shall suites passed;shellcheck -S warningclean;assemble_changelog.py --checkrc 0.Both directions in one tree: a hostile rule is withheld while an ordinary one is named;
jit-missesputs the refusal on stderr with an empty report file, and an ordinary run's report on stdout with 0 bytes on stderr.Two assertions in
test-jit-dry-run.shwere reversed — they asserted the superseded README claim.Review: flagged 5, fixed 4, refused 1
report_hook()printed fired entry names raw in Phase 2, underneath the new note claiming to describe the whole report. Real, and now pinned by a test.common.shandtooling.mdboth claimed an existing test pinned the twojit_report_name()copies. It did not. The drift test was written in response.jit-misses.shexit-code comment claimed 2 was only ours; gawk and one-true-awk both exit 2 on a fatal. Behaviour was right, reasoning wrong.prompts == 0branch and a newline-free hostile STALE name.rebuild-tsv.sh, which fixes every stale row in the layer at once, so there is nothing to hand-edit; a glob ordinal would be a handle that moves when the directory does and that no other tool agrees with. The reason is now written into the code, since the reviewer's confusion is evidence it was not.Adjacent
Fixed in blast radius: the index's
toolcolumn was also raw tree text on the substring-rule line.For filing:
rebuild-tsv.shshould lose its duplicatejit_report_name()once the other lane lands — one hunk, and the drift test declares itself NOT EVALUATED loudly the moment it disappears.Worth knowing, and it bit the maintainer writing this PR: this repository's own
no-shell-writes-to-the-index.mdblock rule fires on a heredoc body that merely mentions a redirect beside the generated index filename. It made authoring the fixture impossible from inside a session running the plugin, and it blocked this description on the first attempt. Writes routed through a variable and documented in the test header. That is #92's stated non-goal, so it is left alone.🤖 Generated with Claude Code