Skip to content

Render orphan Drive-ID cards from text/XML import - #393

Merged
WilfordGrimley merged 2 commits into
masterfrom
yori/foreign-order-resilience-phase1
Jul 23, 2026
Merged

Render orphan Drive-ID cards from text/XML import#393
WilfordGrimley merged 2 commits into
masterfrom
yori/foreign-order-resilience-phase1

Conversation

@WilfordGrimley

Copy link
Copy Markdown

Summary

  • Foreign-order resilience Phase 1 (issue Foreign-order resilience: render orphan Drive IDs and turn them into source discovery #324, promoted high-priority 2026-07-23): the editor now renders cards addressed only by a Google Drive file ID it has never indexed, instead of silently dropping the selection or landing it in the Invalid Cards modal.
  • Adds [mpc:<id>] text-import token syntax (owner's exact reported repro: 1x Kharn [mpc:1FItgPw7VK_Tbv6dMiqdy5zd-jAoEC9mn]) alongside the pre-existing query@id syntax.
  • XML import already read raw <id>/<query> text verbatim (incl. the reported Back | b:null | <id> case, which is parseXmlImport's pre-existing "no matching <backs> entry -> fall back to the order's own <cardback>" path) - the actual root cause was listenerMiddleware.ts's invalid-identifier listener unconditionally clearing any selectedImage absent from the catalog's own search results, regardless of whether it was garbage or a genuinely-unindexed-but-real Drive file ID.
  • Orphan images render direct from Google (lh4.googleusercontent.com), never through our own image-CDN Worker/R2 bucket; two size tiers mirror the Worker's own small/large convention exactly, full-resolution only on an actual PDF export action.
  • Round-trips: re-exporting an orphan's XML keeps its raw <id> and the real (sanitized) query text, not a fabricated placeholder.
  • No tags/consensus surfaces or click-to-detailed-view for orphans; visually distinct "Your file" corner badge.

Deviations from the ratified spec (see docs/features/foreign-order-resilience.md for full detail)

  • Resolution-tier param shape: the owner's follow-up comment loosely specified =w<px>; implemented using the image-CDN Worker's own already-tested =h<px> convention/host instead, for exact parity rather than a second unverified shape.
  • [mpc:<id>] syntax isn't in the ratified issue body - designed fresh to match the owner's own exact repro line, additive to the pre-existing query@id syntax.
  • Phase 2 (source derivation + suggestion), the shared-deck opt-in consent UI, bleed normalization for orphans, and the "Download Images" bulk-export surface are all explicitly deferred - not touched in this pass.

Test plan

  • orphanCard.test.ts - Drive-ID regex, URL builder (small/large/full tiers), name sanitizer, synthesis
  • processing.test.ts - [mpc:<id>] bracket-token parsing incl. the owner's exact repro line
  • listenerMiddleware.test.ts - orphan-candidate skip + explicit regression guard (a known-but-filtered catalog card still gets invalidated)
  • ImportXML.test.ts - front + the b:null back-face case
  • downloadXML.test.ts - orphan round-trip export
  • Card.test.tsx - badge, no click-to-detail, error-degrade (not a stuck spinner)
  • Playwright tests/OrphanRendering.spec.ts - both reported symptoms end-to-end with real Google image fetches; caught and fixed a real CSS bug (Bootstrap's .ratio > * stretching the badge) that Jest/jsdom couldn't see
  • Full Jest suite (556 passed, 1 pre-existing unrelated infra failure - missing marked package)
  • tsc --noEmit clean (same pre-existing unrelated marked error)
  • prettier@2.7.1 --check clean
  • Regression pass: ImportText/ImportXML/CardSlot/CardImageStates/DeckbuilderConfirmAffordance/InvalidIdentifiersStatus/PDFGenerator/ExportXML/GridSelectorModal Playwright suites all green

Screenshots (desktop, from the Playwright run): text-import orphan tile shows the real fetched "Kharn the Betrayer" art + "Your file" badge; the b:null XML back-face orphan shows a real fetched card-back image + "Unindexed card" fallback name + "Your file" badge.

…lience Phase 1)

Fixes text-import [mpc:<id>] tokens and unindexed XML slots (incl. the
b:null back-face case) getting silently cleared or landing in Invalid
Cards, by synthesizing a client-side orphan CardDocument and skipping
the invalidation listener for identifiers that look like real Drive
file IDs. Orphan images load direct from Google, never our CDN.

Closes #324 (Phase 1 only - Phase 2 source-suggestion deferred).
…splay

Common Cardback panel showed "Card not found" for an orphan XML cardback
(ImportXML.tsx now seeds state.project.cardback when unset; listenerMiddleware.ts's
cardback listener gets the same orphan carve-out the per-slot listener already had).
OrphanRendering.spec.ts now verifies rendering on the unified /display page per
owner ruling, not the legacy /editor route.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@WilfordGrimley
WilfordGrimley merged commit bf78337 into master Jul 23, 2026
11 checks passed
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.

1 participant