Status
Built + tested locally (29/29 + 114/114 ecosystem regression). Branch: feat/citation-synthesis-backfill. PR pending.
Problem
KG Phase 2 reads reports.content WHERE report_key='consolidated-footnotes' to produce citation nodes + CITES/SOURCED_FROM/REFERENCES edges. When citation-validator's output is truncated by Sonnet 4.6's 64K output token cap (observed on SpaceX-May 2026-05-16-1778951162), only the CITATION VALIDATION SUMMARY header persists — no footnote inventory. Phase 2 produces 0 citation nodes → ~1,100 lost edges (~80% of the SpaceX-vs-DigitalBridge KG disparity).
Solution
Transparent pre-step inside the existing /api/admin/sessions/:key/rebuild-kg endpoint (sibling to v6.12.0 entity synthesis). When detection heuristic identifies a truncated consolidated-footnotes, deterministically rebuild it from section-IV-* reports — zero LLM, zero new endpoints, zero schema changes.
Architecture — 4 deterministic stages
- Per-section miner with format auto-detection (
[^N]: and N.); heading-anchored or last-15-KB fallback; sub-threshold fail-soft (<3 footnotes/section = no match)
- Global consolidator with provenance tags (
[Original section: IV.X]) for Phase 2 SOURCED_FROM edge construction
- Canonical Format A emitter (Phase 2's strongest parse path) + regenerated summary header + citation-map.md sidecar
- Persistence: UPDATE
reports.content + filesystem write + audit-backup INSERT into report_artifacts (ON CONFLICT DO NOTHING preserves original truncated state)
Detection — structural, not string-dependent
Trigger fires when:
- Section files have ≥50 parseable footnotes (signal sufficient), AND
- Consolidated has <30% of section footnote count
Independent of producer prompt header text / summary structure. Will not fire on healthy sessions (DigitalBridge regression-gated). Will not fire on intentionally small sessions.
Section-level truncation cross-check
detectSectionTruncation cross-checks narrative [^48] references against [^48]: definitions. >2 orphans = section file itself was truncated (e.g., memo-section-writer also hit 64K). Surfaced in audit payload + Prometheus gauge.
Observability — 3 Prometheus gauges
claude_citation_synthesis_fired_total{outcome="synthesized|skipped|failed"} — running counter; sustained "synthesized" = citation-validator producer regression
claude_citation_synthesis_footnotes_recovered{session_key} — last-value per session; healthy: 300-500
claude_citation_synthesis_section_orphan_refs{section} — section-level truncation signal
Files
Runtime:
src/utils/citationSynthesis.js (NEW, ~330 LoC)
src/utils/sdkMetrics.js (+3 gauges)
src/server/adminRouter.js (+70 LoC pre-step in /rebuild-kg, after v6.12.0 entities block)
Tests:
test/sdk/citation-synthesis.test.js (NEW, 29 tests, 9 groups)
Expected impact
| Metric |
SpaceX-May Now |
Post-v6.13.0 |
| consolidated-footnotes size |
6.5 KB summary |
~80-150 KB full inventory |
| Citation nodes |
0 |
~350-450 |
| Total edges |
409 |
~1,500 (close to DigitalBridge baseline minus deal-shape) |
citations_source in response |
— |
"synthesized" |
| Session class |
Behavior |
| Pre-truncation legacy sessions (SpaceX-May, etc.) |
First /rebuild-kg synthesizes; subsequent rebuilds detect healthy state and skip |
| Healthy v6.11.0+ sessions (DigitalBridge, SpaceX-Apr) |
Detection returns false → no-op → citations_source: "native" |
| Future sessions where citation-validator truncates |
Synthesizer auto-fires, recovers the citation graph |
Validation gauntlet (post-deploy)
Properties
- Zero LLM dependency
- Zero new endpoints (extends
/rebuild-kg)
- Zero frontend changes
- Zero DB schema changes
- Idempotent on re-run (UPDATE always; audit INSERT preserves original via ON CONFLICT)
- Fail-soft throughout
- Pre-state preserved indefinitely in
report_artifacts
Risk
4/10 — one level higher than v6.12.0 because UPDATE on canonical reports.content. Offset by structural detection + DigitalBridge regression gate + audit backup.
Rollback
Revert adminRouter.js pre-step block (~70 LoC). citationSynthesis.js becomes dead code. ~5 min.
Related
🤖 Generated with Claude Code
Status
Built + tested locally (29/29 + 114/114 ecosystem regression). Branch:
feat/citation-synthesis-backfill. PR pending.Problem
KG Phase 2 reads
reports.content WHERE report_key='consolidated-footnotes'to produce citation nodes + CITES/SOURCED_FROM/REFERENCES edges. When citation-validator's output is truncated by Sonnet 4.6's 64K output token cap (observed on SpaceX-May2026-05-16-1778951162), only the CITATION VALIDATION SUMMARY header persists — no footnote inventory. Phase 2 produces 0 citation nodes → ~1,100 lost edges (~80% of the SpaceX-vs-DigitalBridge KG disparity).Solution
Transparent pre-step inside the existing
/api/admin/sessions/:key/rebuild-kgendpoint (sibling to v6.12.0 entity synthesis). When detection heuristic identifies a truncated consolidated-footnotes, deterministically rebuild it fromsection-IV-*reports — zero LLM, zero new endpoints, zero schema changes.Architecture — 4 deterministic stages
[^N]:andN.); heading-anchored or last-15-KB fallback; sub-threshold fail-soft (<3 footnotes/section = no match)[Original section: IV.X]) for Phase 2 SOURCED_FROM edge constructionreports.content+ filesystem write + audit-backup INSERT intoreport_artifacts(ON CONFLICT DO NOTHINGpreserves original truncated state)Detection — structural, not string-dependent
Trigger fires when:
Independent of producer prompt header text / summary structure. Will not fire on healthy sessions (DigitalBridge regression-gated). Will not fire on intentionally small sessions.
Section-level truncation cross-check
detectSectionTruncationcross-checks narrative[^48]references against[^48]:definitions. >2 orphans = section file itself was truncated (e.g., memo-section-writer also hit 64K). Surfaced in audit payload + Prometheus gauge.Observability — 3 Prometheus gauges
claude_citation_synthesis_fired_total{outcome="synthesized|skipped|failed"}— running counter; sustained "synthesized" = citation-validator producer regressionclaude_citation_synthesis_footnotes_recovered{session_key}— last-value per session; healthy: 300-500claude_citation_synthesis_section_orphan_refs{section}— section-level truncation signalFiles
Runtime:
src/utils/citationSynthesis.js(NEW, ~330 LoC)src/utils/sdkMetrics.js(+3 gauges)src/server/adminRouter.js(+70 LoC pre-step in/rebuild-kg, after v6.12.0 entities block)Tests:
test/sdk/citation-synthesis.test.js(NEW, 29 tests, 9 groups)Expected impact
citations_sourcein response/rebuild-kgsynthesizes; subsequent rebuilds detect healthy state and skipcitations_source: "native"Validation gauntlet (post-deploy)
/rebuild-kgfor SpaceX session2026-05-16-1778951162→ expectcitations_source: "synthesized",citations_audit.total_footnotes≥ 400kg_nodes WHERE node_type='citation'count ≥ 350kg_edges≥ 1,200SELECT OCTET_LENGTH(content) FROM reports WHERE report_key='consolidated-footnotes' AND session_id=$1≥ 80 KBreport_artifactshas new row withcategory='audit',source='citation-backfill-pre-v6.13.0'/rebuild-kgfor DigitalBridge2026-03-31-1774972751→ expectcitations_source: "native", NO synthesis, KG counts unchanged (1,083/2,062)Properties
/rebuild-kg)report_artifactsRisk
4/10 — one level higher than v6.12.0 because UPDATE on canonical
reports.content. Offset by structural detection + DigitalBridge regression gate + audit backup.Rollback
Revert
adminRouter.jspre-step block (~70 LoC).citationSynthesis.jsbecomes dead code. ~5 min.Related
🤖 Generated with Claude Code