Skip to content

docs(document-api): source-grounded citations feature page (SD-3209)#3387

Open
caio-pizzol wants to merge 2 commits into
mainfrom
caio-pizzol/SD-3209-source-grounded-citations-doc
Open

docs(document-api): source-grounded citations feature page (SD-3209)#3387
caio-pizzol wants to merge 2 commits into
mainfrom
caio-pizzol/SD-3209-source-grounded-citations-doc

Conversation

@caio-pizzol
Copy link
Copy Markdown
Contributor

New feature page at apps/docs/document-api/features/anchored-metadata.mdx, the final piece of the trio (SD-3215 demo migration, SD-3216 minimal example, SD-3209 docs).

Framing

  • URL: /document-api/features/anchored-metadata (stable, primitive-aligned with /document-api/reference/metadata/*).
  • Visible title: "Source-grounded citations in DOCX" — the customer-facing problem.
  • sidebarTitle: "Source-grounded citations" — the nav surfaces the customer ask, not the platform primitive.
  • Primitive name "metadata anchors" appears in the first paragraph and is used throughout. The page does not look legal-only, and the API mapping to editor.doc.metadata.* stays obvious.

Storage model first

The page leads with the file shape, in concrete XML. Direct answer to the "how are pointers embedded in XML, concrete or fuzzy?" question: it's a hidden inline SDT with w:tag + w15:appearance="hidden" in the body, plus a namespaced custom XML payload keyed by the same id. Any backend that produces this file shape works.

Two creation paths (not equal)

  1. Supported ergonomic path: editor.doc.metadata.* on the browser editor, the Node SDK, or the CLI. Same operation IDs.
  2. Pure file-shape generation (no SDK): framed as the storage contract for backends that build DOCX entirely offline. Mentioned, not centered, so the page doesn't encourage hand-authored OOXML where the runtime API would do.

Custom UI binding

ui.metadata.getRect, ui.metadata.scrollIntoView, and ui.viewport.entityAt + metadata.get for hover. Matches the surface the composed demo uses post-SD-3215.

Links only to existing artifacts

No links to future promises, no Linear IDs in public copy. Lifecycle gap framed as "apps should treat metadata.resolve === null as 'anchor gone, hide from UI'."

Audit traceable

  • Em-dash-free.
  • Icons all valid (braces swap for brackets-curly, layout-template for layout after icon validator caught my first guesses).
  • MDX imports valid.
  • docs.json JSON valid; new page registered under Document API > Features.
  • Mintlify dev preview confirmed: page renders, nav entry appears, code blocks highlight, anchor links resolve. Walked the cold-onboarding path: from docs nav into the page, both the example link and demo link from the storage-contract/custom-UI sections opened to the merged-on-main artifacts.

Closes the trio

SD-3215, SD-3216, SD-3209 collectively answer the source-grounded citation question end-to-end: storage model in docs, copy-paste primitive in examples/, composed reference in demos/. A Harvey-shaped consumer landing on this page now finds what they asked for and a path to working code.

Follow-up work (separate tickets): SD-3217 (audit and classify demos/examples), SD-3112 (server-side SDK), SD-3113 (tracked-edit AI suggestions), SD-3200 (anchor lifecycle policy).

New page at apps/docs/document-api/features/anchored-metadata.mdx.
URL stays /document-api/features/anchored-metadata (primitive
alignment with the generated /document-api/reference/metadata/*);
visible title is customer-facing ('Source-grounded citations in
DOCX'); sidebarTitle is 'Source-grounded citations'. The primitive
name 'metadata anchors' is named in the first paragraph.

Storage model first: shows the file shape directly (hidden inline
SDT with w:tag + w15:appearance='hidden' in the body, plus a
namespaced custom XML payload keyed by the same id). Answers the
'how do pointers live in XML, concrete or fuzzy' question with the
concrete pointer.

Two paths after the storage contract:
- Supported ergonomic path: editor.doc.metadata.* on the browser
  editor, the Node SDK, or the CLI.
- Pure file-shape generation: produce the OOXML directly when
  generating DOCX entirely outside SuperDoc. Framed as 'what your
  backend must produce', not as an equal ergonomic path, to avoid
  encouraging hand-authored OOXML where the runtime API would do.

Custom UI binding section uses ui.metadata.getRect,
ui.metadata.scrollIntoView, and the entityAt + metadata.get pattern
that the composed demo now exercises post-SD-3215.

Links only to existing artifacts: examples/document-api/
metadata-anchors (SD-3216), demos/custom-ui (SD-3215),
tests/doc-api-stories/tests/word-roundtrip (SD-3201), generated
/document-api/reference/metadata.

Lifecycle gap framed without Linear IDs in public copy: apps treat
metadata.resolve === null as 'anchor gone, hide from UI'.

Registered under Document API > Features in apps/docs/docs.json
next to content-controls.
@caio-pizzol caio-pizzol requested a review from a team as a code owner May 19, 2026 16:04
@linear-code
Copy link
Copy Markdown

linear-code Bot commented May 19, 2026

SD-3209

@github-actions
Copy link
Copy Markdown
Contributor

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a319befecb

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +106 to +107
if (hit.entityType === 'contentControl') {
const info = editor.doc.metadata.get({ id: hit.entityId });
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Use viewport hit fields that map to metadata ids

ui.viewport.entityAt() does not return entityType/entityId; it returns ViewportEntityHit with type and id (and tag for contentControl), and for content controls the hit id is the SDT node id, not the metadata id (packages/super-editor/src/ui/types.ts). In this snippet, editor.doc.metadata.get({ id: hit.entityId }) will therefore never resolve citation payloads in real hover flows, so readers copying this pattern will fail to render previews. Use the content-control hit’s tag (or ui.metadata.*) when looking up metadata payloads.

Useful? React with 👍 / 👎.

The hover snippet used hit.entityType / hit.entityId, but the actual
ViewportEntityHit shape uses hit.type and hit.id (plus hit.tag for
content controls). The example as written compiled fine but never
matched a hit, so consumers copy-pasting it saw no preview.

Use hit.tag for the metadata.get lookup. For metadata-attached
anchors, the adapter sets w:tag to the id passed to metadata.attach,
so the tag IS the metadata id. hit.id is the internal SDT node id
and would not resolve through metadata.get.

Matches the working pattern in demos/editor/custom-ui CitationPopover.tsx.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant