Skip to content

feat(example): editor + constellation tabs in web_ui_demo - #370

Merged
thewrz merged 9 commits into
mainfrom
feat/demo-editor-constellation
Jul 6, 2026
Merged

feat(example): editor + constellation tabs in web_ui_demo#370
thewrz merged 9 commits into
mainfrom
feat/demo-editor-constellation

Conversation

@thewrz

@thewrz thewrz commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Why

The web_ui_demo had no view where a spec writer actually works in the document — the map and audit views operate around the spec. This ports the "CSI MasterFormat Specification Editor" Claude Design project into the demo as two new workspace views, exercising the paragraph-edit, project-membership, and reference APIs end-to-end.

What

Editor tab — a WYSIWYG writing surface for one section at a time, matching the reference design's pop-into-text interaction:

  • Inline editing: click into any paragraph, article, or part heading and edit in place (contenteditable segment model — editable text runs around non-editable citation chips). Changes save when you click away via the real PATCH /specs/:id/paragraphs/:nodeId; Escape commits; editability-locked paragraphs stay read-only with a chip; the focused row shows the design's EDITING · SAVES WHEN YOU CLICK AWAY state.
  • Enter starts a new paragraph of the same CSI level below the focused one (a new article when pressed in an article heading), caret ready, sheet renumbered — parts are guarded to preserve CSI's three-part format.
  • Tab / Shift+Tab indent & renumber, including articles: outline semantics through the CSI tier ladder (indent under the previous sibling with subtree tier-shift capped at pr7; outdent carries following siblings as children; pr1 ⇄ article promotion/demotion, with a hover ⇥ on article bars). Labels are render-derived, so the whole sheet renumbers live.
  • Local preview overlay: the API has no restructure (feat(api): paragraph restructure endpoint — retype/reparent with renumber (WYSIWYG Tab/Shift+Tab) #371) or paragraph-creation (feat(api): paragraph creation endpoint — insert sibling of same tier (WYSIWYG Enter) #372) endpoint, so Tab/Shift+Tab moves and Enter-drafts are held in an explicitly-labeled LOCAL PREVIEW (with RESET) replayed over server truth — drafts wear a DRAFT · LOCAL tag, accept text (stored in the op), never receive server-only affordances, and never leak into Map/Report. Text edits on real paragraphs persist for real, including type-then-Tab/Enter in one gesture (capture-before-blur keeps them from flashing stale).
  • Citation chips carry the verbatim matched text; × removal runs through the removed-reference dialog for tracked refs (currently unreachable because outbound references lack sourceParagraphId — filed as feat(api): include sourceParagraphId in project outbound references #373) or a plain confirm otherwise.
  • Project TOC rail grouped by MasterFormat division (add-from-masters via POST /projects/:id/specs; flag-for-removal review queue staging DELETE /projects/:id/specs/:id behind CONFIRM) and a CITES / CITED BY inspector rail.

Constellation tab — the whole project corpus as division solar systems: the umbrella section (NN 00 00) is the sun (brighter with more cross-division citations) or a black hole when undefined (click → add from masters); planets sized by inbound citations; orphans amber-dashed; flagged sections amber; broken citations as red severed lanes ending in ✕ (amber ghost dot when the target sits in a source library); hover-to-trace; a focused per-division view with portals; lane filters. Clicking a sightline opens the citing paragraph in the Editor.

Consistency: one renderer + shared styles mean the spec fixtures render identically across Project Spec Map, Report, and Editor (the reference design's 3px row treatment moved into the shared sheet styles; the citation matcher was extracted to refs-text.js shared by read mode and the WYSIWYG editor; every local-state cue — preview chip, draft tags — speaks the same amber-dashed language).

Both views read the same client state as the Reference Web, so edits, flags, additions, and removals reshape the map immediately. Demo-only — no changes under src/ (per the demo charter). Design features with no backend support (collaborator simulation, review locks) were deliberately not faked. Backend gaps discovered and filed: #371 (restructure), #372 (paragraph creation), #373 (sourceParagraphId on outbound refs).

Three 4-/2-lens adversarial review workflows (33 verification agents total) ran across the three passes; all 19 confirmed findings are fixed — notably SVG hit-lane z-ordering, dense-division layout, flag-queue reconciliation, a Tab-handler ordering bug that defeated the optimistic text mirror, a mid-edit board refresh that could eat in-progress typing, pr6/pr7 labels missing from the demo renderer, a cancelled-dialog path that could poison client state, and a crypto.randomUUID secure-context crash in the advertised LAN mode.

Testing

  • Repo lint green (eslint src/ && tsc --noEmit && prettier --check src/)
  • Demo tests pass (17/17, node --test)
  • Manual verification (Playwright against live API + Postgres): inline edit persisted on blur, on Tab-with-pending-text, and on Enter-with-pending-text (no stale flash); Enter inserted a same-tier draft (list renumbered "3." → new "3.", old → "4."), chained drafts, draft-article via Enter on a heading, part guard toast; draft text survived view switches and reloads; Tab/Shift+Tab renumbered live incl. pr1→article "1.2" and ⇥ demote; LOCAL PREVIEW survived a text-save reload and RESET restored server truth; drafts never leaked into Map/Report; chip × confirm/cancel; flag → CONFIRM REMOVAL → re-add round-trip; constellation sightline click landed on the citing paragraph; sheet chrome identical across Map / Report / Editor — all with zero console errors
  • CI green

🤖 Co-authored by Claude Fable 5. Closes #369.

Summary by CodeRabbit

  • New Features
    • Added Editor view for in-place paragraph editing with Tab/Shift+Tab restructure, draft local preview, and live renumbering.
    • Added Constellation view with interactive “systems” map, citation sightlines, filtering, and synchronized detail panels.
    • Added paragraph insertion after an anchor (new REST endpoint and matching MCP tool).
  • Bug Fixes
    • Improved inline citation link status rendering and reference-removal behavior during edits.
  • Documentation
    • Expanded the Web UI demo README with detailed Editor and Constellation interaction guides.
  • Tests
    • Added/updated integration tests covering the new paragraph insertion endpoint and tool behavior.

Two new workspace views ported from the "CSI MasterFormat Specification
Editor" Claude Design project:

- Editor: full-page document editing for one section — project TOC rail
  grouped by MasterFormat division (add-from-masters via
  POST /projects/:id/specs, flag-for-removal review queue backed by
  DELETE /projects/:id/specs/:id), the live tree.js sheet in the middle
  (same paragraph PATCH / reversible-removal affordances as the map),
  and a CITES / CITED BY inspector rail.
- Constellation: the project corpus as division solar systems — umbrella
  section (NN 00 00) as the sun, black hole when undefined, planets
  sized by inbound citations, orphan/flagged styling, broken citations
  as red severed lanes (amber ghost when the target is one click away in
  a source library), hover-to-trace, focused per-division view with
  portals, and click-a-sightline → citing paragraph in the Editor.

Both views read the same client state as the Reference Web, so edits,
flags, additions, and removals reshape the map immediately. Demo-only:
no changes under src/.

Closes #369

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 6, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 9902421c-a029-41d5-9dbf-b715c31f4ce7

📥 Commits

Reviewing files that changed from the base of the PR and between 1c99046 and 195567c.

📒 Files selected for processing (4)
  • examples/web_ui_demo/js/constellation.js
  • examples/web_ui_demo/js/editor.js
  • src/db/queries/paragraph-insert.integration.test.ts
  • src/db/queries/paragraph-insert.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/db/queries/paragraph-insert.ts
  • src/db/queries/paragraph-insert.integration.test.ts
  • examples/web_ui_demo/js/editor.js

📝 Walkthrough

Walkthrough

Adds an Editor tab and Constellation tab to the web UI demo, plus shared inline-editing utilities and a new paragraph insertion API, database query, and MCP tool path.

Changes

Web UI demo

Layer / File(s) Summary
Shared text, division, and restructure helpers
examples/web_ui_demo/js/refs-text.js, examples/web_ui_demo/js/divisions.js, examples/web_ui_demo/js/inline-edit.js, examples/web_ui_demo/js/restructure.js, examples/web_ui_demo/js/labels.js
Adds shared citation parsing, division/umbrella helpers, inline-edit helpers, client-side restructuring logic, and a label-variant switch adjustment.
Tree rendering and inline-edit integration
examples/web_ui_demo/js/tree.js
Updates tree rendering to use the shared helpers, adds local draft rendering, and changes collapsible heading rendering for inline-edit mode.
Editor panel, styles, and workspace wiring
examples/web_ui_demo/js/editor.js, examples/web_ui_demo/css/editor.css, examples/web_ui_demo/css/app.css, examples/web_ui_demo/js/app.js, examples/web_ui_demo/index.html, examples/web_ui_demo/js/api.js, examples/web_ui_demo/js/features.js, examples/web_ui_demo/README.md
Adds the editor controller, editor shell styling, view containers, demo API helper and feature flag, workspace wiring, and documentation.
Constellation panel and styles
examples/web_ui_demo/js/constellation.js, examples/web_ui_demo/css/constellation.css, examples/web_ui_demo/js/app.js, examples/web_ui_demo/index.html, examples/web_ui_demo/README.md
Adds the constellation controller, SVG layouts and interactions, stylesheet rules, panel wiring, and documentation.

Paragraph insertion API and MCP support

Layer / File(s) Summary
Insert paragraph schema exports
src/ast/paragraph-schemas.ts, src/ast/index.ts
Adds the insertable node-type enum and the paragraph insertion request-body schema, then re-exports them from the AST barrel.
Paragraph insertion query
src/db/queries/paragraph-insert.ts, src/db/queries/paragraphs.ts, src/db/index.ts
Adds the database insertion primitive, its transaction wrapper, exported query types, and the supporting paragraphs exports.
HTTP endpoint and contract
src/api/paragraphs.ts, src/api/router.ts, openapi.yaml, src/api/contract.integration.test.ts, src/api/paragraph-insert.integration.test.ts
Wires the new POST route into the API router, implements the handler, updates the OpenAPI spec, and adds endpoint tests and contract coverage.
MCP tool registration
src/mcp/capabilities.ts, src/mcp/contract-map.ts, src/mcp/paragraph-handlers.ts, src/mcp/paragraph-tools.ts, src/mcp/paragraph-tools.integration.test.ts
Adds the insert-paragraph MCP handler, capability mapping, REST-to-tool mapping, tool registration, and integration tests.

Estimated code review effort: 4 (Complex) | ~75 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant tree.js
  participant inline-edit.js
  participant restructure.js
  participant editor.js

  User->>tree.js: open paragraph or heading
  tree.js->>inline-edit.js: renderInlineText() / makeCollapsible()
  User->>inline-edit.js: blur, Enter, Tab, or Shift+Tab
  inline-edit.js->>restructure.js: tryRestructure() or applyRestructureOps()
  inline-edit.js->>editor.js: commit callbacks or preview refresh
  editor.js->>tree.js: re-render editor sheet and inspector
Loading
sequenceDiagram
  participant Client
  participant paragraphs.ts
  participant paragraph-insert.ts
  participant PostgreSQL

  Client->>paragraphs.ts: POST /specs/:id/paragraphs
  paragraphs.ts->>paragraph-insert.ts: insertParagraphAfter(specId, input)
  paragraph-insert.ts->>PostgreSQL: lock anchor, shift positions, insert row
  PostgreSQL-->>paragraph-insert.ts: created / not-found / wrong-spec / invalid-type
  paragraph-insert.ts-->>paragraphs.ts: result
  paragraphs.ts-->>Client: 201 or mapped error
Loading

Possibly related issues

Possibly related PRs

  • wrzonance/SpecR#197: Related optimistic-concurrency and edit-gate handling for paragraph writes, which the new insert flow also uses.
  • wrzonance/SpecR#212: Related OpenAPI and contract-test updates for paragraph API coverage.
  • wrzonance/SpecR#334: Related REST-to-MCP mapping and capability-tier wiring for new tools.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The PR adds backend/API/db/openapi/MCP changes under src/, which are outside [#369]'s demo-only web_ui_demo scope. Remove the src/openapi/mcp/db changes or split them into a separate PR, leaving only examples/web_ui_demo updates.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: adding Editor and Constellation tabs to web_ui_demo.
Linked Issues check ✅ Passed The Editor and Constellation tabs plus live sync behaviors match [#369]'s core requirements.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/demo-editor-constellation

Comment @coderabbitai help to get the list of available commands.

… tab

Second pass at the reference design: the Editor's sheet now edits like the
design instead of swapping textareas.

- Inline editing: paragraph, article, and part text is contenteditable in
  place (segment model — editable text runs around non-editable citation
  chips). Changes save on blur via the existing paragraph PATCH; Enter/Escape
  commit; editability-locked paragraphs stay read-only with a chip; the
  focused row shows the design's EDITING · SAVES WHEN YOU CLICK AWAY state.
- Citation chips carry the verbatim matched text (data-raw) so reconstruction
  never leaks the display format into stored text; × removal runs through the
  existing removed-reference dialog, or a plain confirm for untracked
  (self/unindexed) citations.
- Tab / Shift+Tab restructures through the CSI tier ladder with outline
  semantics (js/restructure.js): indent under the previous sibling with
  subtree tier-shift (pr7 cap), outdent carrying following siblings as
  children, pr1 ⇄ article promotion/demotion (hover ⇥ demotes an article).
  Labels are render-derived, so the sheet renumbers live. No restructure
  endpoint exists yet (#371), so ops are held as an explicit RENUMBER
  PREVIEW overlay (with RESET) replayed over server truth — text edits
  inside a preview persist for real and the preview survives reloads.
- Consistency: the citation matcher moved to refs-text.js (shared by tree.js
  and inline-edit.js); the reference-design 3px row rule now applies to the
  shared sheet styles so Map, Report, and Editor render fixtures identically.

Closes nothing new; extends #369 (PR #370). Backend gap filed as #371.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Pressing Enter in an editable run starts a new empty paragraph of the same
CSI tier immediately below (a new article when pressed in an article
heading), caret ready, sheet renumbered live. Parts are guarded — CSI's
three-part format stays intact.

The API has no paragraph-creation endpoint (filed as #372), so Enter-drafts
join the same structure-op overlay as Tab/Shift+Tab moves: an 'insert' op
carries the draft's id, tier, and text; drafts render with a DRAFT · LOCAL
tag and an amber dashed rule, take text edits (stored in the op, replayed
across reloads), can be restructured, and never receive server-only
affordances (⊘ removal) or leak into the Map/Report views. The preview chip
is now LOCAL PREVIEW · n, covering both op kinds; RESET drops everything.

Typing + Enter in one gesture mirrors the committed text onto the base tree
before the re-render (same capture-before-blur ordering as Tab), so the text
never flashes stale while its PATCH is in flight.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@thewrz
thewrz marked this pull request as ready for review July 6, 2026 05:46

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
examples/web_ui_demo/js/constellation.js (1)

263-263: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Extract the hub/bright threshold into a named constant.

The magic number 3 (inbound-citation threshold for "hub" stars and "bright" suns) is repeated in three separate spots. A shared constant would keep the threshold consistent if it's ever tuned.

♻️ Suggested constant
 const FOCUS_H = 780;
+const HUB_INBOUND_THRESHOLD = 3;
-    const core = svgEl('circle', { cx, cy, r: 10, class: `cst-sun-core${crossIn >= 3 ? ' is-bright' : ''}` });
+    const core = svgEl('circle', { cx, cy, r: 10, class: `cst-sun-core${crossIn >= HUB_INBOUND_THRESHOLD ? ' is-bright' : ''}` });

Also applies to: 294-294, 422-422

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@examples/web_ui_demo/js/constellation.js` at line 263, The hub/bright
threshold is hardcoded as the repeated magic number 3 in the constellation
rendering logic. Introduce a shared named constant for this inbound-citation
threshold and update the relevant checks in the constellation code (including
the class assignment and the other hub/bright comparisons) to use that constant
so the value stays consistent in one place.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@examples/web_ui_demo/js/editor.js`:
- Around line 268-270: The draft text update path in editor.js only mutates the
existing base node, so local draft content from node.meta.localDraft can be lost
on the next render. Update the insert-op handling in the pendingText flow so
drafts are written back to the operation itself, not just base.tree.parts, and
make the guard check pendingText !== null instead of a truthy check so empty
edits are preserved. Apply the same fix in the matching insert/update path
referenced by findBaseNode and the render replay logic.
- Around line 499-517: The refRow helper is leaving unloaded/ghost references as
enabled button elements without any click behavior, which makes them appear
interactive when they are not. Update refRow to treat the non-loaded branch as
non-interactive by either rendering a non-button element or explicitly disabling
the existing button, while preserving the loaded branch behavior that attaches
openSection(section) and the active title.

---

Nitpick comments:
In `@examples/web_ui_demo/js/constellation.js`:
- Line 263: The hub/bright threshold is hardcoded as the repeated magic number 3
in the constellation rendering logic. Introduce a shared named constant for this
inbound-citation threshold and update the relevant checks in the constellation
code (including the class assignment and the other hub/bright comparisons) to
use that constant so the value stays consistent in one place.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: b8f548c3-37df-4e36-8d84-4e2316067e58

📥 Commits

Reviewing files that changed from the base of the PR and between 0b58523 and e2d6155.

📒 Files selected for processing (14)
  • examples/web_ui_demo/README.md
  • examples/web_ui_demo/css/app.css
  • examples/web_ui_demo/css/constellation.css
  • examples/web_ui_demo/css/editor.css
  • examples/web_ui_demo/index.html
  • examples/web_ui_demo/js/app.js
  • examples/web_ui_demo/js/constellation.js
  • examples/web_ui_demo/js/divisions.js
  • examples/web_ui_demo/js/editor.js
  • examples/web_ui_demo/js/inline-edit.js
  • examples/web_ui_demo/js/labels.js
  • examples/web_ui_demo/js/refs-text.js
  • examples/web_ui_demo/js/restructure.js
  • examples/web_ui_demo/js/tree.js

Comment thread examples/web_ui_demo/js/editor.js
Comment thread examples/web_ui_demo/js/editor.js
A 3px dashed left border on a ~27px row renders as two or three fragments —
the "vertical line" reads as broken. The row rule is now solid amber; the
dashed not-persisted language stays on the DRAFT · LOCAL chip.

Verified via Playwright: draft rows compute `3px solid rgb(217,119,6)`,
editing rows `3px solid rgb(37,99,235)` after the 140ms transition, and the
blur-save round-trip still persists.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
thewrz and others added 2 commits July 6, 2026 08:01
The paragraph-creation primitive (#372): inserts a new node immediately
after anchorNodeId, under the same parent, shifting later siblings'
positions — CSI labels are render-derived, so consumers renumber
automatically. nodeType defaults to the anchor's own type; only article,
pr1–pr7, and continuation are insertable (never part — CSI keeps its
three-part shape — and never note, which materializes via accept-as-note).
Generalizes the insertNoteSibling mechanic (reclassify.ts) with the same
lock order (spec gate before paragraph FOR UPDATE), the composed edit gate
(ADR-018) with optional expectedVersion, and a content_version bump.
Responds 201 with the created SpecNode.

Contract lockstep in the same commit: openapi.yaml operation
(insertParagraph) and the insert_paragraph MCP tool (write tier,
contract-map entry) so INV-1/2/2b/3 stay green (ADR-044/045).

Immediate consumer: the web_ui_demo WYSIWYG editor's Enter gesture
(PR #370) persists its drafts through this. The merge engine's added-op
apply (#374) is designed to reuse the same DB primitive.

Closes #372

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
With #372's endpoint cherry-picked into this branch (430097d), the demo
wires the WYSIWYG Enter gesture to real persistence: a draft POSTs as soon
as it has non-empty text and a server-side anchor, the insert op is dropped
and any ops referencing the draft id (moves on it, drafts chained after it)
are remapped to the real node, and chained drafts cascade as their anchors
persist. The draft tag and LOCAL PREVIEW chip clear on the follow-up
re-render (the persist pipeline's own repaint runs while the op still
exists, so the loop requests a deferral-aware render after the remap).

Capability-gated as API_FEATURES.paragraphCreate — against an older API
build the editor degrades to the previous DRAFT · LOCAL behavior, and the
"no endpoint" notice only shows then.

Verified live: Enter → type → blur round-tripped to Postgres, the sheet
renumbered with the new row in place, no draft residue, zero console
errors.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@thewrz

thewrz commented Jul 6, 2026

Copy link
Copy Markdown
Contributor Author

Pass 4: the paragraph-creation endpoint from #376 (cherry-picked here as 430097d) is now wired into the Editor — Enter-drafts persist for real via POST /specs/:id/paragraphs as soon as they have text and a server-side anchor (chained drafts cascade; capability-gated behind API_FEATURES.paragraphCreate with graceful fallback to the DRAFT · LOCAL preview). Also fixed the draft row's left rule rendering as broken dashes (now a continuous amber line, Playwright-verified).

Note for merge sequencing: #376 should land first; this branch then rebases cleanly (the cherry-picked commit deduplicates).

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/db/queries/paragraph-insert.ts`:
- Around line 56-59: Add a regression test in
paragraph-insert.integration.test.ts that covers the uppercase UUID spec path
for the paragraph-insert flow, because the normalization fix in the spec
comparison needs a symptom-based assertion. Use the paragraph insertion/query
path that exercises the anchor.spec_id to specId match and verify that an
uppercase specId no longer returns wrong-spec/false-403 when it should succeed,
so the case-insensitive behavior is pinned by the test.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 738d1954-c522-4555-9244-d13158b58bb2

📥 Commits

Reviewing files that changed from the base of the PR and between 5e6b30e and 1c99046.

📒 Files selected for processing (21)
  • examples/web_ui_demo/README.md
  • examples/web_ui_demo/js/api.js
  • examples/web_ui_demo/js/app.js
  • examples/web_ui_demo/js/editor.js
  • examples/web_ui_demo/js/features.js
  • openapi.yaml
  • src/api/contract.integration.test.ts
  • src/api/paragraph-insert.integration.test.ts
  • src/api/paragraphs.ts
  • src/api/router.ts
  • src/ast/index.ts
  • src/ast/paragraph-schemas.ts
  • src/db/index.ts
  • src/db/queries/paragraph-insert.integration.test.ts
  • src/db/queries/paragraph-insert.ts
  • src/db/queries/paragraphs.ts
  • src/mcp/capabilities.ts
  • src/mcp/contract-map.ts
  • src/mcp/paragraph-handlers.ts
  • src/mcp/paragraph-tools.integration.test.ts
  • src/mcp/paragraph-tools.ts
✅ Files skipped from review due to trivial changes (2)
  • src/db/queries/paragraphs.ts
  • examples/web_ui_demo/README.md
🚧 Files skipped from review as they are similar to previous changes (2)
  • examples/web_ui_demo/js/editor.js
  • examples/web_ui_demo/js/app.js

Comment thread src/db/queries/paragraph-insert.ts
thewrz and others added 3 commits July 6, 2026 09:38
…raphAfter

Two regression/coverage cases CodeRabbit flagged on the insertParagraphAfter
DB query:

- uppercase specId: pg returns spec_id lowercased while z.uuid() preserves an
  uppercase input, so the raw string compare would false-403 a valid write.
  Pins the case-folding fix (verified red without it).
- multi-follower shift: anchor the FIRST sibling so two followers shift, not
  just the single trailing one the existing test covers.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Codex (adversarial review, #370/#376) found insertParagraphAfter only checked
that an explicit nodeType was *insertable*, not that it was valid beside the
anchor. A part anchor (parent_id NULL) with nodeType:'article' slipped past the
insertable check and persisted an article at parent_id = NULL — a root node the
renderers mislabel as a PART, breaking round-trip.

A part's only valid sibling is another part, which is deliberately non-
insertable, so refuse any insert after a part outright. The default path stays
safe (defaulted type == anchor type, always a valid sibling). Pinned with a
regression test; broader cross-level explicit-type validation (e.g. pr1 beside
an article) is a separate CSI-hierarchy decision left as follow-up.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Two CodeRabbit findings on the editor/constellation demo:

- refRow rendered an unloaded ('ghost') citation as an enabled <button> with no
  click handler — a focusable control that does nothing. Render ghosts as a
  plain <div> (the .ed-ref CSS is tag-agnostic; is-ghost already sets
  cursor:default), keeping the button only when the target is loaded.
- Extract the repeated inbound-citation magic number 3 into a named
  HUB_INBOUND_THRESHOLD constant across the three hub/bright checks.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
thewrz added a commit that referenced this pull request Jul 6, 2026
Codex (adversarial review, #370/#376) found insertParagraphAfter only checked
that an explicit nodeType was *insertable*, not that it was valid beside the
anchor. A part anchor (parent_id NULL) with nodeType:'article' slipped past the
insertable check and persisted an article at parent_id = NULL — a root node the
renderers mislabel as a PART, breaking round-trip.

A part's only valid sibling is another part, which is deliberately non-
insertable, so refuse any insert after a part outright. The default path stays
safe (defaulted type == anchor type, always a valid sibling). Pinned with a
regression test; broader cross-level explicit-type validation (e.g. pr1 beside
an article) is a separate CSI-hierarchy decision left as follow-up.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@thewrz

thewrz commented Jul 6, 2026

Copy link
Copy Markdown
Contributor Author

Review items addressed (this push):

  • CodeRabbit body nitpick — constellation.js hub/bright magic number 3: extracted into a named HUB_INBOUND_THRESHOLD constant across all three sites (fixed in 195567c).
  • Codex (adversarial review) [P2]insertParagraphAfter accepted an explicit nodeType that was merely insertable, not valid beside the anchor: a part anchor + nodeType:'article' persisted an article at parent_id = NULL (a root node the renderers mislabel as a PART). Now any insert after a part is refused (a part's only valid sibling is another part, which is non-insertable). Fixed + regression-tested in ed5b29c. Empirically confirmed the pre-fix bug and the fix against a live DB.
    • Follow-up (out of scope here): broader cross-level explicit-type validation (e.g. pr1 beside an article) is a genuine CSI-hierarchy decision that warrants its own issue/ADR — left for a follow-up rather than guessing the rules (continuation/note interleaving is ambiguous).

@thewrz
thewrz merged commit 238141b into main Jul 6, 2026
13 checks passed
@thewrz
thewrz deleted the feat/demo-editor-constellation branch July 6, 2026 17:44
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.

feat(example): full-page document editor + constellation map tabs in web_ui_demo

1 participant