Skip to content

Sidecar-strip hardening (#442) + fix s0 suite crash from Comments v1 (bd-ddaqjb91) - #443

Merged
cscheid merged 4 commits into
mainfrom
bugfix/bd-ddaqjb91-commentblock-defensive
Jul 30, 2026
Merged

Sidecar-strip hardening (#442) + fix s0 suite crash from Comments v1 (bd-ddaqjb91)#443
cscheid merged 4 commits into
mainfrom
bugfix/bd-ddaqjb91-commentblock-defensive

Conversation

@cscheid

@cscheid cscheid commented Jul 30, 2026

Copy link
Copy Markdown
Member

Two related pieces of post-Comments-v1 hardening.

1. Strip captionS / citationIdS in commitSubtreeEdit (closes #442's immediate ask)

commitSubtreeEdit sends subtrees cloned from the untransformed AST to Rust's apply_node_edit, whose replacement doc carries no SourceInfo pool — any surviving pool-index sidecar fails the edit with InvalidSourceInfoRef (the bug #441 fixed for targetS on links). Two bare-index sidecars were still unstripped:

  • captionS (Table/Figure captions)
  • citationIdS (Cite citation objects)

The replacer is now a shared stripSourceInfoFields util that the test file imports (it previously tested a hand-copied duplicate), with new coverage for targetS, captionS, and citationIdS. Table-internal sidecars (headS/rowsS/…) are deferred with table editing — tracked in bd-d01m11aw, along with the systemic Rust-side option (tolerant completing-mode reader) and the sidecar schema doc #442 asks for.

2. Fix the s0-list-item-surfaces crash on main (bd-ddaqjb91)

ts-packages/preview-renderer's integration suite was failing 18/23 in s0-list-item-surfaces since the Comments v1 merge: CommentBlock became the registry's Block wrapper and dereferences resolved.sourceNode on every block render, and the s0 harness's resolveSource stub predated the current ResolvedSource shape (no sourceNode, invalid 'Reachable' class). Production was likely unaffected — the real resolveSource always supplies sourceNode.

  • Defensive guard (TDD'd): CommentBlock treats a malformed resolved entry as unresolvable → passthrough render, in both the chrome gate and resolveCommittable. New test proves the passthrough and that the guard isn't over-broad.
  • Honest stub: the s0 harness now satisfies ResolvedSource for real. 23/23 pass.
  • Systemic fix: test files are now type-checked (tsconfig.tests.json + npm run typecheck:tests in preview-renderer and preview-runtime, wired into cargo xtask verify step 11). The gate provably catches the original defect, and already surfaced real drift in preview-runtime (MockSyncClient missing applyEditorOperations from its interface) plus type errors in 6 other test files, all fixed here.

Plan/diagnosis: claude-notes/plans/2026-07-30-commentblock-defensive-resolvesource.md

Verification

  • preview-renderer: unit 542 passed / 36 skipped; integration 572 passed / 1 skipped (incl. s0 23/23)
  • preview-runtime: 74/74; both typecheck:tests clean
  • cd hub-client && npm run build:all
  • cargo xtask verify --skip-rust-tests ✓ (14/14 steps, including the new typecheck legs)
  • Not verified in a live browser session: citation/figure comment edits (unit-level only)

🤖 Generated with Claude Code

cscheid and others added 4 commits July 30, 2026 13:26
…eEdit (#442)

Extract the commitSubtreeEdit stripping replacer into a shared
stripSourceInfoFields util and extend it to remove the two remaining
bare-pool-index sidecar keys: captionS (Table/Figure captions) and
citationIdS (Cite citation objects). Subtrees cloned from the
untransformed AST carry pool indices that apply_node_edit cannot
resolve (the replacement doc has no pool), so any surviving sidecar
fails the whole edit with InvalidSourceInfoRef — the same failure
PR #441 fixed for targetS on links.

The test file now imports the real util instead of re-declaring a
copy, and gains coverage for targetS (Link/Image), captionS (Figure),
and citationIdS (Cite). Table-internal sidecars (headS/footS/bodiesS/
rowsS/cellsS/bodyS) are left as-is: their pool-carrying leaves are
s/a keys the recursive replacer already removes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…tests)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… s0 stub (bd-ddaqjb91)

The Comments v1 merge (a6fc44b) made CommentBlock the registry's Block
wrapper, so every block render now consults resolveSource and passes
resolved.sourceNode to sameCommentableKind without checking it exists.
The s0-list-item-surfaces harness's resolveSource stub predates the
current ResolvedSource shape (no sourceNode, invalid 'Reachable' class,
bogus sourceIndex prop), so 18/23 tests crashed with
"TypeError: Cannot read properties of undefined (reading 't')".

Two fixes, TDD'd:
- CommentBlock treats a resolved entry without sourceNode like an
  unresolvable block (passthrough render), in both the chrome gate and
  resolveCommittable. New defensive test proves passthrough for the
  malformed shape and that the guard is not over-broad.
- The s0 stub now satisfies ResolvedSource for real (sourceNode: node,
  reachabilityClass 'Descendable', typed sourceEntry). s0: 23/23 pass.

Production was likely unaffected: the real resolveSource in
PreviewRoot.tsx always supplies sourceNode.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… (bd-ddaqjb91)

The s0 breakage was invisible because nothing type-checks test files:
the package tsconfigs exclude *.test.* and vitest transforms with
esbuild. Close the gap:

- tsconfig.tests.json in both packages (extends base, noEmit;
  noUnusedLocals/noUnusedParameters off — lint-grade, not drift
  detection), exposed as `npm run typecheck:tests`.
- cargo xtask verify step 11 runs both typechecks before the suites.
- Fix the pre-existing type errors the new gate surfaced:
  - preview-renderer (6 test files): typed vi.fn generics, Mock import,
    missing setLocalAst props, a useContext type typo, tuple-typed pool
    fixtures, two documented narrow casts.
  - preview-runtime: MockSyncClient's interface was missing
    applyEditorOperations (the impl had it); typed the handler mocks;
    cast once at the _setClientForTesting test seam.

Reintroducing the stale s0 stub now fails the typecheck
(TS2322: '"Reachable"' is not assignable to 'ReachabilityClass').

Also updates the plan doc checkboxes
(claude-notes/plans/2026-07-30-commentblock-defensive-resolvesource.md).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@posit-snyk-bot

posit-snyk-bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Snyk checks have passed. No issues have been found so far.

Status Scan Engine Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues
Licenses 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

@cscheid
cscheid merged commit 7f086b1 into main Jul 30, 2026
8 checks passed
@cscheid
cscheid deleted the bugfix/bd-ddaqjb91-commentblock-defensive branch July 30, 2026 21:45
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.

What's targetS again?

2 participants