fix(composer): key docs fingerprints to the file, not the hunk - #28
Closed
klaidliadon wants to merge 1 commit into
Closed
klaidliadon wants to merge 1 commit into
klaidliadon wants to merge 1 commit into
Conversation
A finding on a docs path fingerprinted on its hunk id, which is a hash of diff geometry. Any later push to the file re-keyed the finding, its posted marker no longer matched, and the same unfixed defect opened a second thread. Code keeps its enclosing symbol across pushes; prose has no symbol table, so the file is the finest locator that survives an edit elsewhere in it. - Distinct same-category findings in one docs file now share a thread.
klaidliadon
force-pushed
the
fix/docs-fingerprint-stability
branch
from
September 23, 2026 08:09
971f851 to
82631ed
Compare
Collaborator
|
Thanks @klaidliadon for the contribution, detailed investigation, and regression tests! We used your reproduction and test cases to implement the fix on the current codebase in #35. The replacement matches unchanged documentation comment content across shifted anchors while keeping distinct findings in the same document separate. It also adds deterministic synthetic evals runnable with Closing this PR as replaced by #35. Thank you again for finding and documenting the issue! |
pkieltyka
added a commit
that referenced
this pull request
Sep 24, 2026
…ors (#35) Address the repeated documentation threads reported in PR #28 at publication rather than assigning every finding in a document the same location identity. Composer grouping and existing code fingerprints retain their current semantics, so unrelated same-category findings and executable examples under docs/ remain separate. For Markdown, MDX, reStructuredText and text files, match the complete sanitized comment body on the same path and diff side. Store its content fingerprint before the inline size cap and read existing comments without that marker by their body. Changed wording, missing content and ambiguous truncated legacy comments remain eligible for posting instead of suppressing a potentially different issue. Use the validated publication anchor during duplicate detection, including anchors supplied only by the posting plan. Require a known anchor for prose matching. Adapt both PR #28 regression fixtures: preserve unchanged comment identity across a seven-line shift while explicitly keeping distinct documentation findings apart. Add coverage for code under docs/, existing markers, missing anchors, proximity, changed content and full-body identity beyond the display truncation boundary. Introduce evals/synthetics and make evals with 13 deterministic scenarios covering real diff parsing, publication, persisted markers, GitHub response parsing and duplicate detection through a scripted transport. Include these scenarios in the normal test suite and TypeScript checks; document their scope and conservative wording policy. Validation: pnpm test (1,390 tests across 63 files), make evals (13 scenarios), pnpm run check, pnpm build and git diff --check all passed.
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.
Push a fix to a doc, and codegenie comments on the same problem again in a new thread. It happened twice in a row on one pull request here, for a finding whose text never changed between the pushes. The cause is that a prose finding has no stable identity, so it gets a new one on every push.
Why it happens
The fingerprint answers one question: is this the same finding I already reported? For code it answers by asking which function the finding sits in, and that survives edits elsewhere in the file. Prose has no functions. So it falls through to the hunk id, which is a hash of line numbers and offsets, and those move the moment anyone edits anything above. The fallback below that, the packet id, is built from hunk ids, so it moves too. There was no stable rung on the ladder.
Duplicate detection then has nothing to match on. The exact-fingerprint arm misses, and the fuzzy arm only catches a prior comment within 5 lines on the same path and side. The two comments here were 7 lines apart.
The fix
One guard in
fingerprintLocationIdentity. When the finding sits on a docs path, the location component becomes a fixed<file>scope instead of diff geometry.The symbol path and the hunk-id path are untouched, so no code finding changes fingerprint. Nothing on an open pull request gets re-keyed by this.
What it costs
Two findings in the same docs file, same category and same lens, now share a fingerprint and merge onto one thread instead of two. That is because
fingerprintFindingis the grouping key inside a run as well as the dedup key across runs, so coarsening it for stability also coarsens grouping. With location fixed per file,categoryandlensIdare the only discriminators left.A test pins that so it stays visible. I took it over the current behavior, which opens a fresh thread for every unfixed docs finding on every push.
Transition
Comments already posted carry old fingerprints. On the first run after this lands, a docs finding on an in-flight pull request will not match its own existing comment and will open one more thread. From the run after that, the fingerprint holds still. Code findings are unaffected in either direction.
Detail: evidence, the approach I backed out, tests, and #26
Evidence
Two review comments on the same design document, in consecutive runs, both reporting that one value named in a Markdown table is not a member of the enum the surrounding prose claims already carries it.
The two runs saw different commits. The bullet and the table row are byte-identical in both. The diff between those commits adds 14 lines and removes 23 elsewhere in the file, which moved this section up by 7 lines. The finding did not change. Its geometry did.
Note what that rules out. The two runs anchored the same defect to two different pieces of text, so no line-level or content-level key would have matched them either. Only a file-level key can.
How the ids are built
fingerprintFindinginsrc/pipeline/composer.tshashes path, location identity, category and lens. The hunk id issha256(path, oldStart, newStart, header, added and deleted line numbers)(src/git/diff-parser.ts:416). The packet id is a hash of the path plus its sorted hunk ids and kind.The approach I backed out
I first tried the general form: drop geometry for every symbol-less finding, and generalize multi-symbol hunks to a sorted symbol set. It broke
final finding fingerprints are stable across model rewordinganddoes not merge unanchored findings from different hunks in one coalesced packet.Those encode a real invariant rather than the bug, since coarsening the key merges distinct findings inside a single run. A code hunk spanning two functions has no unique symbol and would have collapsed to file scope. Gating on the path role keeps that invariant, and it also avoids keying identity on
symbolFactsbeing empty for a transient reason such as a parse failure or a missing grammar, which would be unstable in its own right.That leaves one case with the same root cause unfixed: a hunk spanning two or more symbols still falls back to the hunk id and is still unstable across pushes. Fixing it would move fingerprints for code findings on every open pull request, so it is a candidate follow-up rather than part of this change.
Tests
Both are in
tests/pipeline-phase5.test.tsand both fail on master.keeps docs fingerprints stable when a later push shifts the hunkcomposes the same docs finding twice with different hunk ids and line numbers and asserts a single fingerprint. On master the two runs produce different hashes.merges same-category docs findings from one file onto a single threadpins the trade above. On master it sees two findings instead of one.pnpm testpasses 851 of 853. The two failures arepackage-build.test.tsandreview-command.test.ts, both macOS/privatesymlink path assertions that fail identically on a clean master checkout.pnpm run checkandpnpm run buildare clean. Six further tests time out locally under load at the default 5s timeout and pass at--testTimeout=60000; that is unrelated to this change.Conflict risk with #26
#26 edits
src/pipeline/composer.tsdirectly abovefingerprintFinding, replacingcompactEvidenceand the evidence-block helpers. It does not touchfingerprintLocationIdentity,symbolForHunk,uniquePacketSymbolorinferredHunkId, and its newsrc/pipeline/finding-location.tsis about anchor clarification, not identity. The overlap is adjacent context lines. #26 also editstests/pipeline-phase5.test.ts; my additions sit at the end of two existing blocks, so a rebase should be mechanical.This branch is based on master and does not depend on #26. No version bump here, since #26 already moves the package to 0.6.0.