CE-WP-0006/0007: Capture view polish, workplans, and UX refinements

- 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
This commit is contained in:
2026-06-08 00:37:34 +02:00
parent d25b01f6d5
commit 2fd085b65e
26 changed files with 1767 additions and 356 deletions

View File

@@ -0,0 +1,305 @@
---
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); T03T06 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 users 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 cards 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
(00010005 `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.

View File

@@ -0,0 +1,330 @@
---
id: CE-WP-0007
type: workplan
title: "Capture view polish — scroll stability, linking UX, layout, rename"
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: active
owner: Bernd
created: 2026-06-07
updated: 2026-06-08
depends_on_workplan: CE-WP-0006
planning_order: 7
planning_priority: high
spec_refs:
- wiki/ProductRequirementsDocument.md
- workplans/CE-WP-0006-forms-ux-refinements.md
state_hub_workstream_id: "988ee7c6-752a-492a-9ef9-76d33af9b2d6"
---
# CE-WP-0007 — Capture View Polish
Follow-on UX fixes after CE-WP-0006 manual demo use. Renames the Forms
mode tab to **Capture**, recentres the document column, and tightens linking
and visual-guide behaviour.
## User requirements (locked)
1. **Scroll stability** — selecting evidence further down the document must
not jump the viewport back to the beginning.
2. **Focus-gated linking** — only when a form field has focus does clicking
evidence in the strip link directly (no evidence-first staging flow).
3. **Unlink clears visualization** — removing a link removes the connection
lines immediately.
4. **Field badge tooltips** — mouseover on a field's evidence-count badge
shows the first 80 characters of linked evidence, with trailing `…` when
truncated.
5. **Softer guide lines** — connection indicator lines are grey and thinner.
6. **Centred document column** — Capture layout matches Review: collection |
**viewer (centre)** | form pane (right).
7. **Rename Forms → Capture** — top-bar tab label and user-facing copy.
8. **Add Field** — button to append new form fields to the demo schema.
9. **Field type + label on add/edit** — when adding a capture field, choose
`text` | `textarea` | `date` and set the label; existing fields expose a
✎ edit control (same interaction pattern as evidence cards in
`EvidenceSidebar`).
## Dependency order
```
T01 (scroll stability)
T02 (focus-gated linking) ─┬─ T03 (unlink clears viz)
└─ T04 (field badge tooltips)
T05 (grey guide lines) — parallel
T06 (layout swap) ── T07 (rename Capture)
T08 (Add Field) — after T06/T07
T09 (integration tests + README)
T10 (add-field type + label) ── T11 (field edit icon)
└─ T12 (tests)
```
---
## T01 — Fix viewport jump on evidence select
```task
id: CE-WP-0007-T01
priority: critical
status: done
state_hub_task_id: "23f8e8d0-4ccd-48e9-958c-cc8b756dcaec"
```
**Problem:** clicking an evidence item far down the PDF resets scroll to the
document start before (or instead of) centring the passage.
**Fix:**
- Harden `centerHighlightInViewer` with retried rAF passes until highlight
DOM rects are available.
- Ensure scroll requests do not remount `PdfSpikeViewer`.
- Avoid duplicate/conflicting scroll triggers from auto-activation + card click.
**Acceptance:** click evidence items on page 2+ — viewport stays near the
cited passage, never snaps to page 1 top.
---
## T02 — Link only when a form field has focus
```task
id: CE-WP-0007-T02
priority: high
status: done
depends_on: [T01]
state_hub_task_id: "289bed30-0bb0-42b7-ab6f-8c218133d3df"
```
**Remove** evidence-first staging (click card → click field). **Keep**
field-focus-gated direct link:
- Field receives focus → user clicks evidence card → immediate
`linkEvidenceToTarget`.
- Evidence click without focused field → activate + scroll only.
Remove evidence-staged banner and `stagedEvidenceId` state paths.
**Acceptance:** focus Summary → click strip card → link created. Click card
with no field focused → no link, no staging banner.
---
## T03 — Unlink removes connection visualization
```task
id: CE-WP-0007-T03
priority: high
status: done
depends_on: [T02]
state_hub_task_id: "328e8936-454f-4092-802b-9b0030d54ce5"
```
On `EvidenceLinkRemoved`, if the active triple no longer has a valid link
between field and evidence, clear `activeEvidenceItemId` / `activeAnnotationId`
(or select the next remaining link on the field).
**Acceptance:** unlink via strip badge → SVG paths disappear immediately.
---
## T04 — Field evidence badge hover preview
```task
id: CE-WP-0007-T04
priority: medium
status: done
depends_on: [T02]
state_hub_task_id: "af6a0c73-c323-4e24-85f7-64403658ae51"
```
On each field's `N evidence` chip in `FormRenderer`, set `title` to the
first 80 characters of the first linked evidence quote (italic), append `…`
when longer. Multiple links: join previews or show first link only (document
choice in commit).
**Acceptance:** hover field badge → tooltip shows truncated quote.
---
## T05 — Grey, thinner visual-guide lines
```task
id: CE-WP-0007-T05
priority: low
status: done
state_hub_task_id: "a415f7df-f641-49d8-9c21-13eb70684c64"
```
Update `Overlay` defaults (or Capture-mode props): stroke `#999` (or similar
grey), width `1` px. Update `Overlay.dom.test.tsx` if it asserts colour/width.
**Acceptance:** connection lines are visibly grey and thinner than before.
---
## T06 — Capture layout: document in centre column
```task
id: CE-WP-0007-T06
priority: high
status: done
state_hub_task_id: "1fa3cd2c-c264-4599-9e8a-bd1d74ac1faa"
```
Reorder `FormsApp` columns to match `ReviewLayout`:
```
Collection | ViewerShell | FormPane
```
Evidence strip remains full-width footer.
**Acceptance:** PDF viewer is the centre pane in Capture mode.
---
## T07 — Rename Forms view to Capture
```task
id: CE-WP-0007-T07
priority: medium
status: done
depends_on: [T06]
state_hub_task_id: "7c326eaa-839c-45ad-bef6-aab77b324332"
```
- Top-bar tab: `Forms``Capture`.
- User-facing strings in Capture mode (banners, empty hints).
- Internal route slug may remain `forms` for deep-link compat; update tests
that query the tab by visible label.
**Acceptance:** tab reads "Capture"; integration tests updated.
---
## T08 — Add Field button
```task
id: CE-WP-0007-T08
priority: medium
status: done
depends_on: [T06]
state_hub_task_id: "04586602-491b-46c2-9ced-48258d11bfed"
```
Add **Add field** control above the form. Appends a new `text` field with
auto-generated id (`field_<n>`) and editable label placeholder. Schema held
in React state (seeded from `DEMO_SCHEMA`); rect registry and linking use
dynamic field ids.
**Acceptance:** click Add field → new row appears; can link evidence to it.
---
## T09 — Tests and README index
```task
id: CE-WP-0007-T09
priority: high
status: done
depends_on: [T03, T04, T05, T07, T08]
state_hub_task_id: "823d4986-892d-467e-819e-54f0f2a363e8"
```
- Update integration tests for Capture label, layout, focus-gated linking.
- Add/adjust tests for unlink visualization and field badge tooltip.
- Update `workplans/README.md` with CE-WP-0007.
**Acceptance:** `npm run test` green.
---
## T10 — Add-field dialog: type selection + label
```task
id: CE-WP-0007-T10
priority: medium
status: todo
depends_on: [T08]
state_hub_task_id: "dab723e6-66a6-4587-8ab7-e0c5e4cb5d0a"
```
**Current:** **Add field** immediately appends a `text` field with a
generated label (`New field N`).
**Implement:**
- Click **Add field** → lightweight inline form or small modal (match
`EvidenceFormBody` / `InlineCaptureForm` styling, not a new design system).
- User picks field type: `text` | `textarea` | `date` (same union as
`FormFieldSchema`).
- User enters/edits the label before confirm.
- **Add** inserts the field; **Cancel** discards.
- Stable auto-id (`field_<n>`); label is user-facing only.
**Acceptance:** add a `date` field labelled "Hearing date" — row renders with
correct input type and label.
---
## T11 — Field edit icon (evidence-sidebar pattern)
```task
id: CE-WP-0007-T11
priority: medium
status: todo
depends_on: [T10]
state_hub_task_id: "c55541c7-57e2-4f5d-a4ef-ed54c470cbd9"
```
Mirror `EvidenceSidebar` edit UX (`✎` button, `data-testid` hooks,
inline editor, save/cancel):
- Each `FieldRow` in `FormRenderer` gets an upper-right **edit** control
(pencil icon, `aria-label`, stop propagation on click).
- Edit mode shows type selector + label input (reuse T10 controls).
- **Save** updates schema state in `FormsApp`; **Cancel** reverts.
- Changing type swaps the rendered input; field `id` stays stable so
existing `EvidenceLink` targets and rect registrations remain valid.
- Demo-schema seed fields are editable too.
**Acceptance:** edit "Summary of the matter" → rename + switch to `text`;
links and visual guide still resolve by field id.
---
## T12 — Tests for field add/edit UX
```task
id: CE-WP-0007-T12
priority: high
status: todo
depends_on: [T10, T11]
state_hub_task_id: "585b054e-eb5e-410e-90ee-84e698b13f7f"
```
Happy-dom integration or `FormRenderer` DOM tests:
- Add field with chosen type + custom label.
- Edit existing field label and type via pencil icon.
- Link to an added/edited field still works (focus-gated linking).
**Acceptance:** `npm run test` green.
---
## Acceptance for the workplan
After CE-WP-0007:
1. Evidence select does not jump viewport to document start.
2. Linking requires focused field; evidence click links directly.
3. Unlink clears visual guide lines.
4. Field badges show 80-char quote preview on hover.
5. Guide lines are grey and thin.
6. Capture mode centres the document viewer.
7. Tab reads "Capture".
8. Users can add form fields dynamically.
9. Add-field flow picks type and label; existing fields edit via ✎ control.

View File

@@ -1,22 +1,27 @@
# MVP Workplans
These four workplans implement the **first reference scenario** from
`wiki/ProductRequirementsDocument.md` §20 — end-to-end PDF evidence
capture → form binding → citation card export — entirely inside the
`citation-evidence` repository.
MVP workplans for the citation-evidence umbrella repo. CE-WP-0001..0006
delivered the PRD §20 reference scenario and Forms/Review UX polish.
CE-WP-0007 Capture-view polish is active (field add/edit UX in progress).
| Workplan | Title | Status |
|----------|----------------------------------------|--------|
| `CE-WP-0001` | Foundations — scaffold, folders, lint rules, normalize, fixtures | todo |
| `CE-WP-0002` | PDF review slice — engine types, anchor, source, viewer, sidebar | todo |
| `CE-WP-0003` | Form binding + visual guide — EvidenceLink, rect registry, overlay | todo |
| `CE-WP-0004` | Citation card export — Markdown + HTML renderers, sidebar export | todo |
| `CE-WP-0001` | Foundations — scaffold, folders, lint rules, normalize, fixtures | done |
| `CE-WP-0002` | PDF review slice — engine types, anchor, source, viewer, sidebar | done |
| `CE-WP-0003` | Form binding + visual guide — EvidenceLink, rect registry, overlay | done |
| `CE-WP-0004` | Citation card export — Markdown + HTML renderers, sidebar export | done |
| `CE-WP-0005` | Demo sessions — uploads, named sessions, ZIP export/import | done |
| `CE-WP-0006` | Forms & review UX refinements — blob fix, scroll centre, linking | done |
| `CE-WP-0007` | Capture view polish — scroll, linking, layout, rename, field UX | active |
## Order
Strictly sequential. `CE-WP-0002` depends on the folder/lint scaffolding from
`CE-WP-0001`. `CE-WP-0003` and `CE-WP-0004` depend on the engine types,
viewer adapter, and sidebar from `CE-WP-0002`.
CE-WP-0001..0004 are strictly sequential. CE-WP-0005 depends on 0004.
CE-WP-0006 depends on 0005. CE-WP-0007 depends on 0006:
```
/ralph-workplan workplans/CE-WP-0007-capture-view-polish.md
```
## How to run a workplan