generated from coulomb/repo-seed
- Blob URL stability, scroll centre, strip-only visual guide - Focus-gated linking, unlink clears overlay, field badge tooltips - Capture layout (viewer centre), grey guide lines, Add field button - Workplans CE-WP-0006 (done) and CE-WP-0007 (T01-T09 done, T10-T12 todo) - Integration tests and viewer-url helpers
305 lines
11 KiB
Markdown
305 lines
11 KiB
Markdown
---
|
||
id: CE-WP-0006
|
||
type: workplan
|
||
title: "Forms & review UX refinements — blob stability, scroll-center, linking, visual guide"
|
||
domain: citation_evidence
|
||
repo: citation-evidence
|
||
repo_id: a677c189-b4e2-4f2a-9e48-faa482c277e6
|
||
topic_slug: citation_evidence_mvp
|
||
topic_id: 96fa8e80-9f74-40f2-84cd-644e9747b9ec
|
||
status: done
|
||
owner: Bernd
|
||
created: 2026-06-07
|
||
updated: 2026-06-07
|
||
depends_on_workplan: CE-WP-0005
|
||
planning_order: 6
|
||
planning_priority: high
|
||
spec_refs:
|
||
- wiki/ProductRequirementsDocument.md
|
||
- wiki/ArchitectureOverview.md
|
||
- wiki/SharedContracts.md
|
||
- history/2026-06-07-ecosystem-state-assessment.md
|
||
state_hub_workstream_id: "97493fdb-a793-4e79-bc7c-6a56b6085873"
|
||
---
|
||
|
||
# CE-WP-0006 — Forms & Review UX Refinements
|
||
|
||
User-facing polish before architectural expansion (Markdown/HTML, citation
|
||
recovery, subsystem extraction). Addresses six issues observed during manual
|
||
demo use on `http://localhost:5173/`.
|
||
|
||
## User requirements (locked)
|
||
|
||
1. **PDF blob load failure on evidence capture** — saving a new evidence item
|
||
with commentary triggers
|
||
`Unexpected server response (0) while retrieving PDF "blob:http://…"`.
|
||
2. **Center cited region on evidence select** — clicking an evidence item must
|
||
scroll the document viewport so the marked passage is centred, not merely
|
||
brought into view at an edge.
|
||
3. **Visual guide from footer strip only** — in Forms mode, connection lines
|
||
must originate from the bottom evidence strip cards, not duplicate cards
|
||
below the form. The field end of each line should attach to the **bottom
|
||
edge of the form pane** to reduce overlap with field inputs.
|
||
4. **Evidence strip visibility filter** — the bottom row supports an optional
|
||
filter (`all` | `attached`). Focusing a form field switches the filter to
|
||
`attached` (evidence linked to that field only).
|
||
5. **Bidirectional linking** — linking must work both ways:
|
||
- evidence → field (existing staged flow), and
|
||
- field → evidence (select/focus field, then click evidence card to link).
|
||
6. **Link indicators on evidence cards** — connected cards show one or more link
|
||
symbols in the upper-right. Hover shows a tooltip listing connected form
|
||
field titles. Clicking a symbol removes that specific link.
|
||
|
||
## Scoping decisions
|
||
|
||
- **No architecture extraction** in this workplan — all changes stay in the
|
||
umbrella repo under existing `src/{work,binder,app,anchor,source}/` folders.
|
||
- **Review mode and Forms mode** both benefit from T01 (blob stability) and T02
|
||
(scroll centre); T03–T06 are Forms-mode focused.
|
||
- **ActiveEvidenceChips** (`src/app/forms/ActiveEvidenceChips.tsx`) is removed
|
||
from the form pane layout; its rect-registration responsibility moves to the
|
||
footer `EvidenceStrip`. The module may remain as a thin helper or be inlined
|
||
— but it must not render duplicate cards below the form.
|
||
- **Unlink** uses `bindings.unlinkEvidence(linkId)` (hard delete per current
|
||
MVP semantics in `src/binder/services/bindings.ts`).
|
||
|
||
## Dependency order
|
||
|
||
```
|
||
T01 (blob URL stability)
|
||
└─ T02 (viewport centre on evidence select)
|
||
T03 (strip-only visual guide + remove duplicate chips)
|
||
├─ T04 (strip filter: all | attached)
|
||
├─ T05 (bidirectional linking)
|
||
└─ T06 (link badges + tooltip + unlink)
|
||
└─ T07 (integration tests)
|
||
T08 (update workplans/README.md) — parallel once file exists
|
||
```
|
||
|
||
---
|
||
|
||
## T01 — Fix PDF blob URL failure during evidence capture
|
||
|
||
```task
|
||
id: CE-WP-0006-T01
|
||
priority: critical
|
||
status: done
|
||
state_hub_task_id: "3cc6a93a-e506-4477-8ef7-8c6dee405bc8"
|
||
```
|
||
|
||
**Problem:** uploaded PDFs are served via ephemeral `blob:` URLs minted by
|
||
`PdfByteStore` and stamped onto `document.uri`. A full viewer remount (e.g.
|
||
`ViewerShell` re-keyed on `scrollVersion`) or persistence round-trip can leave
|
||
PDF.js fetching a revoked or stale blob URL.
|
||
|
||
**Investigate and fix:**
|
||
|
||
- `ViewerShell` should resolve the viewer URL from the live `PdfByteStore`
|
||
entry for `document.id` when bytes are present; treat persisted `document.uri`
|
||
blob URLs as hints only, never as the sole source after reload.
|
||
- Avoid unnecessary full `PdfSpikeViewer` remounts when only scroll-target
|
||
changes (split scroll trigger from component `key` if that is the root cause).
|
||
- Ensure `captureSnapshot` / restore does not persist blob URLs that cannot be
|
||
rehydrated, or re-mint blob URLs from stored bytes on session/engine restore
|
||
when ZIP import or upload repopulates the byte store.
|
||
- Add a regression test reproducing capture-after-upload without blob error
|
||
(`src/work/` or `tests/integration/`).
|
||
|
||
**Acceptance:** upload a PDF, select text, add commentary, save evidence — no
|
||
PDF.js blob fetch error; viewer remains usable.
|
||
|
||
---
|
||
|
||
## T02 — Centre viewport on marked region when selecting evidence
|
||
|
||
```task
|
||
id: CE-WP-0006-T02
|
||
priority: high
|
||
status: done
|
||
depends_on: [T01]
|
||
state_hub_task_id: "e09d8fa1-862e-4c83-b1c4-19c6826e4610"
|
||
```
|
||
|
||
**Problem:** `scrollToHighlight` brings the passage into view but does not
|
||
centre it. Users lose context when the highlight lands at the viewport edge.
|
||
|
||
**Implement:**
|
||
|
||
- Extend the viewer adapter scroll contract (`PdfSpikeViewer` /
|
||
`react-pdf-highlighter-plus` utils) so scroll-to-annotation centres the
|
||
highlight rect vertically (and horizontally when wider than viewport).
|
||
- Wire through `useScrollToAnnotation` callers:
|
||
`EvidenceSidebar`, `ViewerShell` highlight click, `ScrollBridge` in Forms
|
||
mode.
|
||
- Unit test for scroll math helper if extracted; DOM integration test asserting
|
||
scroll request includes centre intent (mock utils acceptable per ADR-0004).
|
||
|
||
**Acceptance:** click any evidence item in Review or Forms — the cited passage
|
||
appears centred in the document pane.
|
||
|
||
---
|
||
|
||
## T03 — Visual guide from footer evidence strip; remove duplicate form cards
|
||
|
||
```task
|
||
id: CE-WP-0006-T03
|
||
priority: high
|
||
status: done
|
||
depends_on: [T02]
|
||
state_hub_task_id: "f30df6ee-a1c4-4a1b-80e0-d44e54f7b9b6"
|
||
```
|
||
|
||
**Problem:** `FormPane` renders `ActiveEvidenceChips` below the form while
|
||
`EvidenceStrip` already shows the same cards at the bottom. The SVG overlay
|
||
(`Overlay.tsx`) draws field→card→highlight using rects registered by the
|
||
duplicate chips.
|
||
|
||
**Implement:**
|
||
|
||
- Remove `ActiveEvidenceChips` from `FormPane` in `FormsApp.tsx`.
|
||
- Register `kind="evidence-card"` rects from `EvidenceStrip` buttons instead
|
||
(one registration per visible card).
|
||
- Update `Overlay` path geometry:
|
||
- field end → **bottom-centre** of the active field row (or bottom of form
|
||
pane when no specific field is active),
|
||
- card end → top-centre of the strip card,
|
||
- highlight end → unchanged.
|
||
- Adjust `forms-overlay-e2e.dom.test.tsx` expectations for the new anchor
|
||
points and single card location.
|
||
|
||
**Acceptance:** only one evidence card row (footer strip); visual guide connects
|
||
form bottom → strip card → PDF highlight with no duplicate cards under the form.
|
||
|
||
---
|
||
|
||
## T04 — Evidence strip filter (all vs attached-to-active-field)
|
||
|
||
```task
|
||
id: CE-WP-0006-T04
|
||
priority: medium
|
||
status: done
|
||
depends_on: [T03]
|
||
state_hub_task_id: "1dafa73d-1d8c-43b6-8934-2fbf038fc3be"
|
||
```
|
||
|
||
**Implement in `EvidenceStrip`:**
|
||
|
||
- Filter state: `all` (default) | `attached`.
|
||
- UI toggle in the strip header (e.g. "All" / "Linked to field").
|
||
- When a form field receives focus (`FormFieldActivated` or
|
||
`useActiveState().activeTarget`), set filter to `attached` and show only
|
||
evidence items with an `EvidenceLink` to that target.
|
||
- When no field is active, `attached` filter shows evidence linked to any field
|
||
in the demo schema, or falls back to `all` — pick the less surprising option
|
||
and document it in the task commit message.
|
||
- Clearing field focus returns filter to user’s last explicit choice (not forced
|
||
back to `all`).
|
||
|
||
**Acceptance:** focus "Summary" field → strip shows only evidence linked to
|
||
`summary`; toggle restores full list.
|
||
|
||
---
|
||
|
||
## T05 — Bidirectional evidence ↔ field linking
|
||
|
||
```task
|
||
id: CE-WP-0006-T05
|
||
priority: high
|
||
status: done
|
||
depends_on: [T03]
|
||
state_hub_task_id: "2d7c9278-1ecc-4b59-ae3b-1a5d1e513885"
|
||
```
|
||
|
||
**Current:** evidence-first only — stage card in strip, then click field.
|
||
|
||
**Add field-first:**
|
||
|
||
- Click/focus a form field → enter "field staged for linking" state (banner
|
||
parallel to existing evidence-staged banner).
|
||
- Click an evidence card in the strip → `bindings.linkEvidenceToTarget` with
|
||
the staged field as target; clear staging.
|
||
- Evidence-first path remains unchanged.
|
||
- Mutual exclusion: staging evidence clears field staging and vice versa.
|
||
- Emit existing `EvidenceLinkCreated` event; link count chips on fields update.
|
||
|
||
**Acceptance:** link works via evidence→field and field→evidence; cancel clears
|
||
staging; duplicate link to same target is prevented or noop with user feedback.
|
||
|
||
---
|
||
|
||
## T06 — Link badges on evidence cards (tooltip + unlink)
|
||
|
||
```task
|
||
id: CE-WP-0006-T06
|
||
priority: high
|
||
status: done
|
||
depends_on: [T05]
|
||
state_hub_task_id: "064f6e48-e791-4cf5-9d04-df3fb7a11e48"
|
||
```
|
||
|
||
**On each evidence card in `EvidenceStrip`:**
|
||
|
||
- Query `bindings.listTargetsForEvidence(item.id)`.
|
||
- Render one link icon per connected form field in the card’s upper-right
|
||
(stack or count badge when >3).
|
||
- `title` / `aria-label` on hover: field label from `DEMO_SCHEMA` (fallback to
|
||
`targetId`).
|
||
- Click icon → `bindings.unlinkEvidence(linkId)` for that target; refresh strip
|
||
and field link counts.
|
||
- Do not trigger link-staging when clicking the unlink control (stop
|
||
propagation).
|
||
|
||
**Acceptance:** linked cards show indicators; tooltip names fields; click removes
|
||
link without staging a new one.
|
||
|
||
---
|
||
|
||
## T07 — Integration tests for refined Forms UX
|
||
|
||
```task
|
||
id: CE-WP-0006-T07
|
||
priority: high
|
||
status: done
|
||
depends_on: [T04, T05, T06]
|
||
state_hub_task_id: "c50f9700-9902-4520-b8e2-6a010431b7ef"
|
||
```
|
||
|
||
Extend or add happy-dom integration tests:
|
||
|
||
- `tests/integration/forms-link-flow.dom.test.tsx` — bidirectional linking.
|
||
- `tests/integration/forms-overlay-e2e.dom.test.tsx` — strip-only rects, bottom
|
||
anchor geometry (path count / data attributes).
|
||
- `tests/integration/app-prd-scenario.dom.test.tsx` — capture-after-upload no
|
||
blob error (if not covered in T01 unit test).
|
||
- New or extended test for strip `attached` filter behaviour.
|
||
|
||
**Acceptance:** `pnpm test` green; tests document the six user requirements.
|
||
|
||
---
|
||
|
||
## T08 — Update workplans README index
|
||
|
||
```task
|
||
id: CE-WP-0006-T08
|
||
priority: low
|
||
status: done
|
||
state_hub_task_id: "715edb39-9b97-4d7f-b89b-71a0130326e8"
|
||
```
|
||
|
||
Update `workplans/README.md` to list CE-WP-0001..0006 with correct statuses
|
||
(0001–0005 `done`, 0006 `active`).
|
||
|
||
**Acceptance:** README table matches workplan frontmatter.
|
||
|
||
---
|
||
|
||
## Acceptance for the workplan
|
||
|
||
After CE-WP-0006:
|
||
|
||
1. Evidence capture on uploaded PDFs does not break the viewer.
|
||
2. Selecting evidence centres the cited passage in the document viewport.
|
||
3. Forms visual guide uses footer strip cards only; lines attach to form bottom.
|
||
4. Evidence strip supports all/attached filter; field focus narrows to attached.
|
||
5. Linking works evidence→field and field→evidence.
|
||
6. Linked evidence cards show unlinkable field indicators with tooltips. |