Skip to content

fix(synthesis): member claims join by source_url, not the orbit filter#191

Merged
bryanmatthewsimonson merged 1 commit into
mainfrom
fix/case-synthesis-claim-join
Jul 18, 2026
Merged

fix(synthesis): member claims join by source_url, not the orbit filter#191
bryanmatthewsimonson merged 1 commit into
mainfrom
fix/case-synthesis-claim-join

Conversation

@bryanmatthewsimonson

Copy link
Copy Markdown
Owner

The bug

A real corpus run over a 129-article case surfaced ~2 claims to the LLM. Root cause: buildMemberUnits fed the map/reduce from deriveArticleRows' row.claims, and those rows attach only orbit claimsallClaims.filter(c => c.about.includes(caseEntityId)). Claims are authored about their subjects (SARS-CoV-2, EcoHealth, Fauci…), not the case container, so only the 2 claims someone tagged directly onto the case qualified.

Phase 20.1 made article membership a union (tag ∪ claim-about-case) but left claim-attachment on the old orbit-only definition — so every tag-member article joined with claims: []. Atomized claims were dropped before the model ever saw them.

Confirmed against a live workspace: the case "What is the origin of Covid?" has 2 of 1,882 claims about it; the rest reference 378 subject entities.

The fix (surgical, synthesis-only)

  • buildMemberUnits now joins each member's claims by normalized source_url against the full registry (data.claimsById), key-first/oldest-first for determinism. Restores ~1,882 claims across 91 articles.
  • The deterministic dossier's own deriveArticleRows attachment is left untouched (governed separately by CASE_DOSSIER_DESIGN.md).
  • synthesis-block.js derives the corpus staleness hash from the actual member-claim ids sent, not dossier.orbit.claim_ids, so adding/removing a claim on a member invalidates the stored brief. Stored briefs re-hash once and show "stale" — correct, the corpus definition changed.
  • The URL join also sidesteps the claim article_hash freeze (stamped at extraction, lags a re-publish): inclusion keys on URL and re-keys the unit to the member's current hash.

Not in this PR (surfaced, deferred)

  • 30 members with no local archive text can't feed the corpus (can't synthesize bytes you don't have). Recapture to include.
  • DIGEST_CLAIM_CAP = 150 still bounds the reduce stage's cross-article claim index (the per-article map stage sees each article's full set).

Verification

  • New test: buildMemberUnits joins by URL and excludes non-member claims.
  • npm test → 1971 pass · npm run build clean · npm run lint 0 errors.

🤖 Generated with Claude Code

Case synthesis fed the map/reduce from deriveArticleRows' row.claims,
which attach only orbit claims (about the case entity). Claims are
authored about their subjects, so a 129-article case surfaced ~2 of
~1,900 claims — Phase 20.1 unioned ARTICLE membership (tag ∪ claim) but
left claim-attachment on the orbit-only definition, so tag-member
articles joined with empty claims.

buildMemberUnits now joins each member's claims by normalized source_url
against the full registry (data.claimsById), key-first/oldest-first.
The deterministic dossier's deriveArticleRows attachment is untouched.
synthesis-block derives the staleness hash from the actual member-claim
ids sent (stored briefs re-hash once → correctly "stale").

- restores ~1,882 claims across 91 articles on the real corpus
- URL join sidesteps the claim article_hash freeze (lags re-publish)
- test: buildMemberUnits joins by URL, excludes non-member claims

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@bryanmatthewsimonson
bryanmatthewsimonson merged commit 0c9b109 into main Jul 18, 2026
1 check passed
@bryanmatthewsimonson
bryanmatthewsimonson deleted the fix/case-synthesis-claim-join branch July 18, 2026 15:14
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.

1 participant