feat(api): include sourceParagraphId in outbound references - #419
Conversation
GET /projects/:id/specs/:specId/references returned OutboundReference without the paragraph locator, unlike the inbound and broken-refs endpoints which already carry it. The web_ui_demo builds a per-paragraph reference index from that field (tree.js buildSheetCtx → refsByParagraph), so the index was always empty — silently disarming the removed-citation flow: editing citation text out of a paragraph never detected a removed tracked reference, so the "also remove the section?" dialog was unreachable and edits committed directly. The source_paragraph_id column already exists on spec_references and is NOT NULL; the inbound and broken queries already SELECT and expose it. Add it to the outbound query, its row/DTO types, and mapOutbound, and document it on the OutboundReference schema in openapi.yaml (same PR, per the contract gate). No migration — the column exists. The MCP get_references tool serializes the raw outbound array, so it now carries the field automatically; the REST↔MCP parity gate stays green. Closes #373 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (5)
📝 WalkthroughWalkthroughThe OutboundReference schema and query implementation now include a required sourceParagraphId field. The openapi.yaml contract, refs.ts row mapping/SQL projection, and related unit, integration, and MCP anchor tests are updated to carry paragraph-level locator data through outbound reference results. ChangessourceParagraphId propagation
Estimated code review effort: 2 (Simple) | ~10 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
|
@coderabbitai review |
✅ Action performedReview finished.
|
Why
GET /projects/:id/specs/:specId/referencesreturnedOutboundReferencewithoutsourceParagraphId, unlike the inbound and broken-refs endpoints which already carry it. Theweb_ui_demobuilds a per-paragraph reference index from that field (tree.js buildSheetCtx → refsByParagraph), so the index was always empty — silently disarming the removed-citation flow: editing citation text out of a paragraph (map textarea flow, the Editor's WYSIWYG blur/Enter/Tab paths, and the chip × for tracked refs) never detected a removed tracked reference, so the "This edit removes a cross-reference / also remove the section?" dialog was unreachable and edits committed directly.Discovered while verifying PR #370 pass 3 — the client machinery (occurrence-count diffing, the choice dialog, the cascade) all exists and is tested at the module level; it just never received paragraph-scoped references.
What
Add
sourceParagraphIdto the outbound reference rows and expose it through the API and MCP surfaces:src/db/queries/refs.ts—SELECT sr.source_paragraph_id, plus the field onOutboundReferenceRow, theOutboundReferenceDTO, andmapOutbound. Mirrors exactly howgetInboundReferences/getBrokenRefsalready do it.openapi.yaml—OutboundReferenceschema gainssourceParagraphId(string,format: uuid, required), matchingInboundReference's casing and nullability. Same PR, per the contract gate.get_referencestool serializes the raw outbound array, so it now carries the field automatically — no tool-shape change; the REST↔MCP parity gate (INV-1/2/3) stays green.Design decisions
source_paragraph_idcolumn already exists onspec_references(migration 008,NOT NULL, FK →paragraphs); this was purely a projection gap in the outboundSELECT.uuid, required in the schema — mirrorsInboundReference.sourceParagraphIdexactly, because the column isNOT NULL. No newnullcase to handle.Testing
pnpm test(1467 passed withDATABASE_URLset; the lone local miss wasopen-comments.test.tsaborting on an unsetDATABASE_URL, pre-existing and unrelated).contract.integration.test.ts(confirms the response now matches the updatedOutboundReferenceschema),refs.integration.test.ts,mcp/contract.integration.test.ts(parity gate),references.integration.test.ts,mcp/server.integration.test.ts— 65 passed.pnpm lint(eslint + tsc + prettier) andpnpm buildgreen.outbound references carry sourceParagraphId (was empty → demo removed-citation flow disarmed).🤖 Co-authored by Claude Opus 4.8. Closes #373.
Summary by CodeRabbit
New Features
Bug Fixes
Tests