fix(extractor): collapse ids repeated within a single LLM proposal (closes #41) - #52
Conversation
_merge seeds known_decisions / known_findings / known_work from the base state and never grows them, so an id the LLM emitted twice in one response passed the guard twice and was appended twice. A single proposal could therefore produce two decisions with the same decision_id. Each accepted id is now added to its set as it is appended, so the same guard that stops a proposal overwriting a recorded fact also stops it duplicating itself. Three call sites, one line each. First occurrence wins, which is the same direction the existing semantics already run: the base state beats the proposal, so earlier beats later. Tests: 6 added to tests/test_extractor.py. The three collapse cases (decision, finding, pending work) fail against pristine extractor.py. The other three are regression guards that must pass both before and after, and do: first-occurrence-wins, distinct ids in one proposal all survive, and a proposal repeating an already-recorded id still neither overwrites nor duplicates it. Gate: pytest 683 passed / 4 skipped (677 before); ruff check, ruff format --check and mypy (strict) all clean. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
@dchaudhari7177 is attempting to deploy a commit to the cyrax8590-gmailcom's projects Team on Vercel. A member of the Team first needs to authorize it. |
|
Thank you for this PR, and for closing the intra-proposal duplicate-id gap in the extractor! The fix is correct: it seeds each CI Check Analysis (run locally on the branch)
Code & Test Review Findings
Concern (not a defect): branch is stale relative to LGTM from a review standpoint, thank you for the contribution! |
Closes #41.
_mergeseedsknown_decisions/known_findings/known_workfrom the base state and never grows them, so an id the LLM emitted twice in one response passed the guard twice and was appended twice.Fix
One line per collection — add the accepted id to its set as it's appended:
That makes the guard that stops a proposal overwriting a recorded fact also stop it duplicating itself. All three collections had the same hole, so all three are fixed —
pending_workisn't in the issue's repro but has identical code, and fixing two of three would leave the same bug behind under a different name.First occurrence wins. That's the direction the existing semantics already run — the base state beats the proposal, so earlier beats later — and it's asserted rather than left implicit.
Tests
6 added to
tests/test_extractor.py.Three fail against pristine
extractor.py:Three are regression guards that must pass both before and after, and do:
test_the_first_occurrence_wins_within_a_proposal— pins which copy survives, not just that one doestest_distinct_ids_in_one_proposal_are_all_kept— the de-dup must not collapse genuinely different components, which is how this kind of fix usually goes wrongtest_a_proposal_repeating_a_recorded_id_still_cannot_overwrite_it—d1is already recorded; repeating it twice must neither overwrite nor duplicate, i.e. the existing protection still holds through the new code pathGate
Windows / Python 3.12, all three CI checks from CONTRIBUTING:
pytest— 683 passed, 4 skipped (677 before this branch)ruff check src/ tests/andruff format --check src/ tests/— cleanmypy src/continuum(strict) — no issues in 44 source files🤖 Generated with Claude Code