Skip to content

review: adjudicated-corpus suppression drops its same-path key - #366

Merged
jwbron merged 7 commits into
mainfrom
agent/pra11-adjudicated-crossfile
Aug 24, 2026
Merged

review: adjudicated-corpus suppression drops its same-path key#366
jwbron merged 7 commits into
mainfrom
agent/pra11-adjudicated-crossfile

Conversation

@jwbron

@jwbron jwbron commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

The adjudicated-corpus suppression was path-keyed, and that key is what let the webapp#41290 duplicate families re-post for two weeks after the author had adjudicated them: a settled defect's rephrasing routinely re-anchors on another file (the spec instead of the implementation, the test instead of the function), and every re-anchoring escaped the corpus. So let's just drop the same-path key in the adjudicated pass only.

The change is measured, not argued. On the frozen 41290 corpus (12 adjudicated threads, 33 hand-labeled candidates: true variants, vocabulary-sharing hard negatives, controls; kept privately in the planning tree since it's verbatim webapp text):

  • path-keyed: 2/12 true variants suppressed, 1 false suppression (a same-path pair folding two distinct findings whose wording shares the file's vocabulary, a mistake the current matcher makes too)
  • key dropped: 6/12 at the same single false suppression, correct family attribution on every match, controls clean

Tripled recall, zero added false suppressions. The remaining 6 escapees are heavily reworded members token floors can't reach at any key width; they're deliberately not chased (the corpus memory self-heals: an escapee that posts gets downvoted or acknowledged once and joins the corpus itself).

What licenses the wide match is the corpus's membership rule plus the blocking exemption: every member carries an explicit human act (a resolve or a 👎), a suppression here only ever eats a non-blocking candidate, and a defect that matters enough to block re-presents at blocking severity and posts. Everything else is unchanged: the open-thread corpus stays path-keyed (there a false cross-file match hides an undecided finding), and the other #332 fail-closed guards hold. Mechanically it's an ignorePath option on bestOpenThreadMatch whose only caller is the adjudicated pass, plus tests pinning the cross-file suppression, the blocking exemption, and the open-corpus asymmetry.

Most of the diff by line count is a module split, not behavior: dedup.ts sat at 1021 lines against the repo's 1000-line max-lines budget, so open-thread suppression moved out to a new dedup-threads.ts, following the dedup-cluster.ts/dedup-text.ts precedent; nothing still imports a moved symbol from ./dedup. The behavior change itself is the one-line key drop plus its guards.

The review round tightened four things: an adjudicated thread staged without a usable path now stays inert under ignorePath instead of becoming a PR-wide matcher; the cross-file floor choice is documented as measured (every cross-file negative on the corpus fails jaccard at 0.168 against the 0.2 floor, the weakest true match sits at 7 shared bigrams, so the pr-level tier's floor of 8 would cost a true variant for no measured precision) and pinned by a fixture in the 6-8 bigram band where the two floors disagree; the interaction with the cross-file merge ordering is documented as deliberate and pinned in both directions (an open thread takes only its own file's copy and the sibling posts alone, an adjudicated thread takes the near-identical sibling copy too); and the changeset bumps review as a minor, matching the 1.17.0 precedent. The exact final diff was re-validated against the private fixture through the production pass: recall 6/12, the same single false suppression, correct attribution throughout. A later round added the precision half's fixture: a cross-file hard negative built against the real tokenizer to land where only the jaccard guard rejects (6 shared bigrams, exactly the floor; overlap 0.444; jaccard 0.157 against 0.2), so a loosened floor now fails CI instead of silently dropping findings, and the floor docs in dedup-text.ts name the second (cross-file) calibration basis.

KORE-2468

…ssion drops its same-path key

A human-settled defect's rephrasing routinely re-anchors on another
file (the spec instead of the implementation, the test instead of the
function), and the path key is what let the webapp#41290 duplicate
families re-post for two weeks after the author adjudicated them.

Measured on that frozen corpus (12 adjudicated threads, 33 labeled
candidates, kept privately in the planning tree): path-keyed matching
scores 2/12 true variants suppressed with 1 false suppression (a
same-path vocabulary-split pair); with the key dropped, 6/12 at the
same single false suppression and correct family attribution on every
match. Tripled recall, zero added false suppressions.

The asymmetry that licenses the wide match is the corpus's human
membership signal: a false match here eats a finding a human already
settled, and never a blocking one. The open-thread corpus stays
path-keyed (there a false cross-file match hides an undecided finding);
blocking candidates are still never suppressed; every other #332
fail-closed guard is unchanged.
@changeset-bot

changeset-bot Bot commented Aug 20, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 1b12133

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
review Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@khan-actions-bot
khan-actions-bot requested review from a team, jaredly and jeresig and removed request for a team August 20, 2026 22:48
@github-actions

github-actions Bot commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Review live A/B

No reviewable delta: review.md is byte-identical in both arms (baseline origin/main, sha 604183e7637f), so the extracted prompts and the orchestrator body match and no arms were run. Pass --force-arms for a deliberate wobble control.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Changes requested — see inline comments.
Note: claim validation not assessed this run (claim-validator output unavailable).

review details review-v1.17.1 | schema 2 | depth full | re-review scoped blocking-only | enable holistic,completeness,test-adequacy,first-principles,conventions,documentation

Comment thread workflows/review/lib/dedup-adjudicated.ts
Comment thread .changeset/pra11-adjudicated-crossfile.md
Comment thread .changeset/pra11-adjudicated-crossfile.md
Comment thread workflows/review/lib/dedup.ts Outdated
Comment thread workflows/review/lib/dedup.ts Outdated
Comment thread workflows/review/lib/dedup-adjudicated.ts
Comment thread workflows/review/lib/dedup-adjudicated.ts
Comment thread .changeset/pra11-adjudicated-crossfile.md
Comment thread workflows/review/lib/dedup-adjudicated.test.ts Outdated
Comment thread .changeset/pra11-adjudicated-crossfile.md Outdated
- the changeset now bumps review (minor, matching the 1.17.0 precedent
  for a suppression-behavior change)
- an adjudicated thread staged without a usable path stays inert under
  ignorePath instead of becoming a PR-wide matcher, with a test pinning
  both the undefined and empty-path shapes
- the cross-file floor choice is documented as measured (every cross-file
  negative on the frozen corpus fails jaccard at 0.168 vs the 0.2 floor;
  the weakest true match sits at 7 shared bigrams, so the pr-level floor
  of 8 would cost a true variant for no measured precision) and pinned by
  a fixture in the 6-8 bigram band where the two floors disagree
- the sibling-copy interaction with the cross-file merge ordering is
  documented in dedup-crossfile.ts as deliberate and pinned in both
  directions (open corpus: tracked file's copy exits, sibling posts;
  adjudicated corpus: the settled thread takes the near-identical
  sibling copy too), plus a best-match-across-files attribution test
- the circular asymmetry sentence is rewritten (a false match eats an
  undecided finding; what licenses the reach is the membership rule plus
  the blocking exemption), vocabulary-split is spelled out, the stale
  module-header pointer is fixed, and the README feedback contract now
  says any file
@jwbron

jwbron commented Aug 21, 2026

Copy link
Copy Markdown
Contributor Author

Pushed 33479df addressing the round; inline replies aren't available from this session, so per finding:

The changeset (both blocking comments plus the conventions/documentation echoes): frontmatter now bumps review as a minor. On the level, the 1.17.0 precedent is the closer authority than the major-version line in the README: the downvote-adjudication change was the same kind of suppression-behavior widening and shipped as a minor, and this change only ever affects non-blocking candidates, so a consumer pinned to review-v1 keeps the contract that matters (what can block).

The cross-file floor (holistic/correctness/first-principles): turns out the corpus answers this directly, so I re-derived instead of arguing from the convention. Every cross-file negative pair on the frozen 41290 corpus fails jaccard, not bigrams: the strongest scores 0.168 against the 0.2 floor while reaching 13 shared bigrams, so jaccard is the guard that holds and a bigram-keyed CROSS_FILE_FLOOR polices the wrong axis. The weakest true cross-file match sits at exactly 7 shared bigrams, so the pr-level tier's floor of 8 drops recall from 6/12 to 5/12 and suppresses zero additional negatives. The floor stays at OTHER_LINE_FLOOR, but the calibration is now written into bestOpenThreadMatch's doc (re-derive, don't nudge, same as the other tiers) and pinned by a new fixture scoring 7 bigrams, inside the band where the two floors disagree, which also covers the test-adequacy suggestion about both floors being cleared by a wide margin.

The suppress-before-merge ordering (the correctness blocker): the interaction is real and it's deliberate, so it's now explicit rather than implied. The ordering rationale still holds for the open corpus, which stays path-keyed. For the adjudicated corpus, a settled thread on file A taking B's near-identical copy is the corpus's semantics: the human declined that exact ask once, the reach is capped at non-blocking, and a blocking re-presentation posts. Note the path key never protected the matching same-file case either; a fresh same-file instance of a settled defect was already suppressed, so this widens the reach of an accepted risk rather than adding a new failure class. mergeCrossFileDuplicates's ordering doc now says all of this (which also clears the stale-premise note), and dedup-crossfile.test.ts pins both directions: open thread on A suppresses A's copy and B posts alone; adjudicated thread on A takes both copies and nothing reaches the merge.

The anchorless-thread suggestion was a genuine catch: under ignorePath a corpus member staged without a path would have become a PR-wide matcher, flipping openThreadsFromStaged's documented fail-closed degradation open. The thread side now keeps a gate (no usable path, no match), tested for both the undefined and empty-string shapes, and the changeset names the guard.

The rest:

  • best-match attribution across files has its own test now: two corpus members on different files both clear the floor, the higher-jaccard one wins, and the reversed staging order is asserted as a control
  • the asymmetry sentence was circular as written, agreed; rewritten so the licensing is the membership rule (an explicit human act) plus the blocking exemption, not a claim that false matches are free
  • the README's resolve bullet now says any wording, any line, any file, with the re-anchoring reason
  • the module-header pointer and the coined "vocabulary-split" are fixed; the false pair folds two distinct same-file findings whose wording shares the file's vocabulary, and the doc, changeset, and PR body all spell it out now
  • the pathless-claim doc branch: reworded so bestOpenThreadMatch's doc states the only ignorePath caller exempts pathless claims first, making OTHER_LINE_FLOOR the only live floor there

On the private corpus (the reproducibility question): it's verbatim webapp thread text and it leaked into this public repo once already on a deleted branch, so it stays in the planning tree. What's re-runnable here: the qualitative behaviors are pinned as fixtures (now including the floor band and both ordering directions), and the doc carries the exact numbers as the re-derivation target. The final diff was re-validated by running the frozen corpus through the production adjudicatedThreadsFromStaged + suppressAdjudicatedDuplicates path: recall 6/12, the same single same-path false suppression, correct family attribution on every match.

@github-actions

This comment has been minimized.

jwbron added 2 commits August 21, 2026 11:25
…sion out of dedup.ts

The merge with main put dedup.ts at 1021 lines, over eslint's max-lines
budget of 1000 (each side was under it alone; CI lints the merge commit).
Open-thread suppression is a self-contained concern dedup.ts hosted
beside the merge tiers, so it moves to dedup-threads.ts whole, following
the dedup-text.ts and dedup-cluster.ts precedent. The calibrated
similarity floors move to dedup-text.ts beside the primitives they are
calibrated against, which is what keeps the two consumers (dedup.ts and
dedup-threads.ts) cycle-free. No behavior change; importers now name the
new module, and prose references elsewhere are repointed (including
threads.ts's adjudicatedThreadsFromStaged pointer, which named dedup.ts
while the function lives in dedup-adjudicated.ts).
@github-actions

Copy link
Copy Markdown
Contributor

Guidance for reviewers

Triage notes for reviewers: risky files by owning team, repeated changes, and files excluded from review.

github-actions (6 files)
File Reason
dedup-adjudicated.ts Carries the hunk that actually widens suppression ({ignorePath: true}), so a mis-calibration silently eats non-blocking findings repo-wide rather than only on the settled file.
dedup-threads.ts New home of bestOpenThreadMatch, the matcher both suppression corpora run through, and the file carrying the new ignorePath branch; a bug here decides what is dropped before validation sees it.
dedup-text.ts Now owns the calibrated similarity floors every dedup and suppression tier reads, so it is the single point where a nudged floor changes suppression on every consumer PR.
dedup.ts The ~460 removed lines are a verbatim move to dedup-threads.ts/dedup-text.ts, so the residual risk is a dropped export rather than a rule change.
dedup-crossfile.ts Enforcement layer, but the change is import rewiring to dedup-threads.ts plus the ordering-rationale doc, so a mistake surfaces as a broken import that typecheck catches.
dispatch.ts The dispatcher's re-export surface that downstream lib modules and tests import from; the change is a re-export split with the same symbol set.

Common patterns

4 files: Import path repointed from ./dedup to ./dedup-threads for open-thread-suppression exports (suppressOpenThreadDuplicates, openThreadsFromStaged, stagedThreadShapeFailure, threadSuppressionUnavailableWarning, ThreadSuppression) following the module split.

- import {suppressOpenThreadDuplicates} from "./dedup";
+ import {suppressOpenThreadDuplicates} from "./dedup-threads";

5 files: Comment/doc cross-references to dedup.ts updated to dedup-threads.ts following the module split (sole change in each file).

- * text-similarity comparison (dedup.ts's `threadProse`). Every posted
+ * text-similarity comparison (dedup-threads.ts's `threadProse`). Every posted
Excluded from review (8 files)

Not individually reviewed — generated, formatting-only, or
fully explained by a common pattern above:

  • workflows/review/lib/attribution.ts — pattern-only
  • workflows/review/lib/dedup-cluster.ts — pattern-only
  • workflows/review/lib/dedup-pr-level.test.ts — pattern-only
  • workflows/review/lib/dedup.test.ts — pattern-only
  • workflows/review/lib/forwarded-warnings.ts — pattern-only
  • workflows/review/lib/stage-pr.ts — pattern-only
  • workflows/review/lib/stage-threads.test.ts — pattern-only
  • workflows/review/lib/threads.ts — pattern-only
review details review-v1.17.1 | schema 2 | depth full | re-review scoped blocking-only | enable holistic,completeness,test-adequacy,first-principles,conventions,documentation

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

All 16 prior review threads are resolved.
Note: divergence tripwire re-armed a full review (unreviewed share 0.97).

review details review-v1.17.1 | schema 2 | depth full | re-review scoped blocking-only | enable holistic,completeness,test-adequacy,first-principles,conventions,documentation

Comment thread workflows/review/lib/dedup-adjudicated.test.ts
Comment thread workflows/review/lib/dedup-text.ts Outdated
Comment thread workflows/review/lib/dedup-adjudicated.ts
Comment thread workflows/review/lib/dedup-threads.ts
Comment thread workflows/review/lib/dedup-text.ts
Comment thread workflows/review/lib/dedup-threads.ts Outdated
jwbron added 3 commits August 24, 2026 09:30
…s review feedback

The widened adjudicated match had only its recall side pinned: the sole
negative fixture was same-path and died on bigrams, so the jaccard 0.2
floor (the guard that actually holds cross-file, measured at 0.168 on the
frozen corpus's strongest negative) had no CI coverage, and a false
cross-file suppression drops a finding silently. The new fixture was built
against the real tokenizer to land where only jaccard rejects: 6 shared
bigrams (exactly the floor), overlap 0.444, jaccard 0.157.

Also from the review: OTHER_LINE_FLOOR's definition-site doc now names its
second (cross-file) calibration basis, the moved PR_LEVEL_FLOOR doc no
longer says 'this module scores' about a module that scores nothing, and
bestOpenThreadMatch's options bag is a defaulted parameter like every other
trailing options bag in the lib.
@khan-actions-bot
khan-actions-bot requested review from a team and somewhatabstract and removed request for a team August 24, 2026 17:29

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Approved — no blocking issues found.
All 6 prior review threads are resolved.

Non-blocking observations (4)
  • workflows/review/lib/dedup-text.ts:68 suggestion (non-blocking, documentation): The new OTHER_LINE_FLOOR paragraph restates the calibration figures it then points at. (documentation)
  • workflows/review/lib/dedup-adjudicated.test.ts:342 suggestion (non-blocking): The hard-negative fixture's calibration band (6 bigrams / 0.444 overlap / 0.157 jaccard) is documented in a comment but never asserted. (correctness-reviewer)
  • workflows/review/lib/dedup-adjudicated.test.ts:265 question (non-blocking): A human resolve can mean "I fixed this file", not only "I decline this ask". (first-principles)
  • workflows/review/lib/dedup-threads.ts:290 suggestion (non-blocking): The corpus measured only path-keyed and no-key; a directory-scoped key was not measured. (first-principles)
Note: re-review ran at scoped depth (re-review mode scoped, blocking-only).
review details review-v1.18.0 | schema 2 | depth scoped | re-review scoped blocking-only | enable holistic,completeness,test-adequacy,first-principles,conventions,documentation

@jwbron
jwbron merged commit 1326331 into main Aug 24, 2026
11 checks passed
@jwbron
jwbron deleted the agent/pra11-adjudicated-crossfile branch August 24, 2026 17:42
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.

2 participants