fix(mention-open): a bare #N the pane guesses is now overridable too - #1387
Merged
Conversation
#1380 closed the shape where the pane's guess was ALONE (`audit-pr N`) and deliberately left the bare `#N` two-row picker alone, writing the trade down in both the handler and `test_a_bare_hash_N_that_the_PANE_already_attributes_does_NOT_get_the_universe`: burying two good rows under several hundred looked like "a regression dressed as a feature". The operator overruled it on 2026-09-08 — "fix the bare-#N and any other cases left unfixed" — because when the pane guess is wrong the right repository is unreachable, which is the same defect one rung along. So the offer is now scoped to `repo_source == default` alone, not to that rung PLUS being the only row. The MEASURED rows keep their positions — clawgate, then the pane's GitHub repo — so the common case is still one Enter, and the fuzzy universe is appended beneath them. Two things the widening required: * `guessed_note` grew a `rank`. Its multi-row wording said "The FIRST row is a guess", true of `audit-pr N` and FALSE of a bare `#N`, where row 1 is the clawgate task. Naming the wrong row is worse than saying nothing. * the append is guarded on what it actually ADDS, not on the universe being non-empty. A host whose whole universe is the pane's own repo dedupes to nothing, and `offered_universe` would then have claimed rows that were not in the list — to the auto-open guard as well as to the note. DELIBERATELY UNCHANGED, each verified rather than assumed: `owner/repo#N` and `repo#N` still open with zero keystrokes (they are evidence about the REFERENCE); `#282828` is still a named toast; `--print` still refuses and never lists a repository; a bare `#N` nothing attributed keeps PASS 3's own arm and its silent picker. Superseded on purpose, not deleted: the two tests that pinned the old behaviour are rewritten to assert the new intent and to record who asked and when, keeping the half of their claim that survives (the measured rows come FIRST, in that order). Test matrix — 9 red at 18bc150, 185 green at HEAD; invariant guards labelled as such in their own docstrings. Mutation rows K45/K46/K47 added and watched to kill for their stated reason, with P1 as the positive control. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E1h5KrSQj42u746XYVWiGh Claude-Session-Id: 3495c5a1-5b5f-491d-b47c-606eafc05a61
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.
The defect, and what #1380 left open
A candidate the handler offers can come from several rungs of
mention_scan'sattribution ladder. In the terminal profile only three occur:
explicit(the operator wrote
owner/repo#N),mapped(the text named the repo, themapping supplied the owner) and
default(the repo came fromtmux_pane_repo()or--default-repo). The first two are evidence about thereference;
defaultis evidence about the window, and it is frequentlywrong.
The defect class is a guessed repository the operator cannot override.
#1380 closed it for the shape where the guess was alone (
audit-pr N) anddeliberately left the bare
#Nalone, writing the trade down in the handlerand in
test_a_bare_hash_N_that_the_PANE_already_attributes_does_NOT_get_the_universe:burying two good rows under several hundred looked like "a regression dressed
as a feature", and the choice belonged to the operator.
The operator made it on 2026-09-08 — "fix the bare-#N and any other cases
left unfixed" — because when the pane guess is wrong the right repository is
unreachable. Same defect, one rung along.
What changed
The offer is now scoped to
repo_source == defaultalone, not to that rungplus being the only row. Everything already in the list keeps its position;
the fuzzy universe is appended beneath it.
Two things the widening required:
guessed_notegrew arank. Its multi-row wording opened "The FIRST rowis a guess" — true of
audit-pr N, false of a bare#N, where row 1 isthe clawgate task and the guess is row 2. Pointing the operator at the wrong
row is worse than saying nothing: they would distrust the task and trust the
guess. The note now names the measured row number.
non-empty. A host whose whole universe is the pane's own repo dedupes to
nothing, and
offered_universewould then have claimed rows that were not inthe list — to the auto-open guard as well as to the note.
guessed_noteiskeyed on
below(rows genuinely searchable under the guess) rather than a rowcount for the same reason: "type to search" is nonsense with nothing to
search.
The whole class, enumerated and classified
Every terminal path through
main(). "Unoverridable?" means: does the handleract on, or offer without alternatives, a repository the operator cannot correct?
868abc123(ClickUp)owner/repo#Nexplicitrepo#N, mapping resolvesmappedrepo#N, mapping does not resolveuniverse_note#N+ pane repodefault#N, no pane repoaudit-pr N+ pane repodefaultaudit-pr N, no pane repo--default-repo Xwith 5 or 7default#282828(six digits)--print <unresolvable>--print <resolvable>--no-discoveryNot fixed, on purpose
Case 3,
mapped. A stale or wrong mapping row is an answer the operatorcannot override in the picker — but I think it is correct as-is, and I did not
change it:
reference, not about the window. That is the whole distinction the
suppression is built on;
regen-known-repos.pydrops a bare name two owners share rather thanpicking one (measured there: 7 collisions, 14 repos), so a
mappedhit isunique on this host by construction — it is not a coin flip;
staleness_note()firespast
STALE_MAPPING_DAYSand names the failing refresh unit, anduniverse_notecarries the generation date above every universe picker;repo#N, which is exactly what theexplicitnegative control forbids.The residual — a mapping that is silently wrong — is answered by writing
owner/repo#N(already the advicerefuse()prints) or regenerating. Flaggingit rather than changing it.
Case 6,
#Nwith no pane repo, gets the universe with no note. Thepicker's rows are a real clawgate task plus a list, with nothing being
recommended, so there is no guess to explain — but the several-hundred-row list
is arguably unexplained. Left alone: it is a cosmetic question, not the defect
class, and it is a separate decision from the one asked for.
Case 12 observation, not changed:
--print '#N'with a pane repo prints thepane-guessed GitHub URL alongside the clawgate one.
--printis non-interactiveand prints every candidate by contract; it never gets the universe (pinned).
Recording it here rather than silently altering a machine-readable contract.
Superseded, not deleted
Two tests pinned the old behaviour on purpose. Both are rewritten to assert the
new intent and to record who asked and when, keeping the half of their claim
that survives — the measured rows come FIRST, in that order:
test_a_bare_hash_N_that_the_PANE_already_attributes_does_NOT_get_the_universe→
test_a_bare_hash_N_that_the_PANE_attributes_gets_the_universe_BELOW_ittest_the_note_is_NOT_attached_to_the_ordinary_bare_hash_N_picker→
test_the_bare_hash_N_picker_SAYS_the_github_row_is_a_guesstest_the_ORDINARY_picker_gets_no_notekeeps its name but its docstring isrewritten: it used to claim the bare
#Npicker never carries a note, whichis now false on a real host. What it pins now is the degenerate universe its
fixture builds.
Test matrix — base
18bc1500, headb21905369 red at base, all 185 green at head. Measured by extracting
18bc1500withgit archive | tar -xand dropping the NEW test file on the PRISTINE basehandler (blob
7afe7396, verified bygit hash-object). Every one is a realassertion FAILURE at base, not a collection error.
Two of these were vacuous on the first attempt and were strengthened after
watching them pass at base: the ordering test and the dedupe test are both
satisfied by a two-row picker (nothing at index 2 can be out of order; two rows
have no duplicates). Both now assert a row-count floor first, and both go red.
The remaining new tests are INVARIANT GUARDS, labelled as such in their own
docstrings — green at base too, by design: the auto-open suppression, the
degenerate-universe boundary, the untouched
#N-with-no-pane neighbour, and thethree negative controls.
Negative controls (all green at base and head)
owner/repo#Nandrepo#Nstill open with zero keystrokes, driven with aWRONG pane repo loaded so a guess leaking into those paths would be visible.
#282828still produces the named colour-literal toast, no picker, with apane repo loaded.
--print '#N'prints exactly its 2 candidates, raises no picker, and nouniverse token reaches stdout.
Disclosure
test_the_universe_reaches_ROFI_AND_NO_OTHER_SINK_on_the_bare_hash_N_pathdrives the widened arm through the real
notify()and folds stdout, stderrand every
notify-sendargv through_every_sink, then asserts_no_universe_token_anywhereplus the threeUNIVERSE_ONLYspellings. Itspositive control asserts a universe row really did reach the picker rows, so
it cannot pass by scanning an empty universe. The note itself is checked with
_no_universe_token_anywheretoo.Mutation coverage
Three rows added to
scripts/tests/mutation_battery_mentions.py, anchorsverified unique by
test_mutation_battery_anchors.py, and watched to kill:Tree restored afterwards and verified by
git hash-object, not by thebattery's own
restore: OKline.Gate — both tiers, on the MERGED tree
origin/mainis18bc1500and this branch fast-forwards from it, so the mergedtree is
b2190536. Both tiers run against that sha.Dev host —
nix develop <worktree> --command bash scripts/gate.sh --tier both:Sandbox (the tier Tekton runs), extracted with
git archive HEAD | tar -xinto a dir with no
.git, built one derivation at a time:🔴 The 7 pytest failures are PRE-EXISTING RED ON
main, not this change —and that is a measurement, not a theory. The discriminating control was run in
both tiers against base
18bc1500:7 failed, 406 passed);nix build path:<base>#…pytests→FAIL scripts/tests (collected=12863 passed=12856 skipped=0 failed=7 errors=0).Base vs head in the sandbox tier: collected +14, passed +14, failed unchanged
at 7 — the +14 is exactly this PR's new tests.
The 7 are
age-version behaviour and anopencode-version pin, in files thisdiff does not touch:
They are a real problem on
mainand somebody should own them; they are notthis diff's, and the delta above is what says so.
Live click path — measured, nothing raised
rofi,xdg-openandnotify-sendreplaced by stubs onPATH(rofi dumpsstdin and exits 1 = dismissed), against the REAL host mapping, universe and tmux
pane. No window was raised and no workspace was switched. The handler blob
probed is
c30ee598, byte-identical toHEAD:scripts/mention-open.py. Rows arejoined with
\n, so the counts below add the onewc -lunder-reports.audit-pr 1291github 1291 — …/innovation-upstream/devrc/issues/1291(the pane guess)#1291clawgate task 1291 — https://clawgate.zacx.dev/tasks/1291(unchanged)civitai/talos-infra#1065xdg-open https://github.com/civitai/talos-infra/issues/1065, rc 0#282828The
#1291row is the fix: 2 rows → 393, with row 1 and row 2 unmoved, sothe common case is still one Enter and the wrong guess is now escapable.
🤖 Generated with Claude Code
https://claude.ai/code/session_01E1h5KrSQj42u746XYVWiGh