generated from coulomb/repo-seed
- Align agent files with on-disk workplan prefixes (infer from workplan ids) - Set workplan domain to registered domain_slug; add topic_slug where applicable - Repair frontmatter delimiter formatting; migrate legacy task status literals - Regenerate AGENTS.md, CLAUDE.md, and .claude/rules from State Hub templates
261 lines
7.9 KiB
Markdown
261 lines
7.9 KiB
Markdown
---
|
|
id: CE-WP-0003
|
|
type: workplan
|
|
title: "Form binding + visual guide — EvidenceLink, rect registry, SVG overlay"
|
|
domain: infotech
|
|
repo: citation-evidence
|
|
repo_id: a677c189-b4e2-4f2a-9e48-faa482c277e6
|
|
topic_slug: citation_evidence_mvp
|
|
topic_id: 96fa8e80-9f74-40f2-84cd-644e9747b9ec
|
|
state_hub_workstream_id: 7b5b7235-57e3-4835-8fa6-376bb518fe2d
|
|
status: done
|
|
owner: Bernd
|
|
created: 2026-05-24
|
|
updated: 2026-05-25
|
|
depends_on_workplan: CE-WP-0002
|
|
spec_refs:
|
|
- wiki/ProductRequirementsDocument.md
|
|
- wiki/ArchitectureOverview.md
|
|
- wiki/SharedContracts.md---
|
|
|
|
# CE-WP-0003 — Form Binding + Visual Guide
|
|
|
|
Build the evidence-backed form mode and the SVG visual guide overlay.
|
|
After this workplan, a user can:
|
|
|
|
1. Open a form next to the document viewer.
|
|
2. Drag (or click-to-link) an evidence item from the sidebar onto a form
|
|
field.
|
|
3. Click a form field → its linked evidence items appear → the active
|
|
evidence's source passage is scrolled into view and highlighted → an SVG
|
|
guide visually connects the field, the evidence card, and the highlight.
|
|
4. Cycle through multiple evidence items on the same field.
|
|
|
|
This is the workplan that stress-tests the rect-registry contract from
|
|
`wiki/SharedContracts.md` §7. The form, the evidence card, and the viewer's
|
|
highlight all need to publish rects to a single overlay that re-renders on
|
|
scroll/resize/focus.
|
|
|
|
## Dependency Order
|
|
|
|
```
|
|
T01 (EvidenceLink + EvidenceSet types + relation/status enums)
|
|
└─ T02 (binding service + in-memory link repo + active-state machine)
|
|
└─ T03 (rect registry — the contract from SharedContracts.md §7)
|
|
└─ T04 (form schema + simple field renderer)
|
|
└─ T05 (side-by-side layout + drag-or-click to link)
|
|
└─ T06 (active-evidence cycling on a field)
|
|
└─ T07 (SVG visual guide overlay)
|
|
└─ T08 (E2E test of PRD scenario steps 5-9)
|
|
```
|
|
---
|
|
|
|
## T01 — `EvidenceLink` + `EvidenceSet` types
|
|
|
|
```task
|
|
id: CE-WP-0003-T01
|
|
state_hub_task_id: 120b9b5a-9ca3-4dff-8c26-1b5c2e832dc4
|
|
priority: critical
|
|
status: done
|
|
```
|
|
|
|
Add under `src/shared/`:
|
|
|
|
- `src/shared/evidence-link.ts` — `EvidenceLink`, `EvidenceLink.status`
|
|
enum per SharedContracts §2.4, `EvidenceLink.relation` enum per §2.5,
|
|
`EvidenceTarget` generic shape
|
|
- `src/shared/evidence-set.ts` — `EvidenceSet` with `activeEvidenceItemId`
|
|
|
|
No services. Pure shapes.
|
|
|
|
Add a unit test asserting that the union of all enum values matches the
|
|
`SharedContracts.md` lists exactly — if someone adds a value without
|
|
updating the doc, the test fails.
|
|
|
|
---
|
|
|
|
## T02 — Binding service + in-memory link repo + active-state machine
|
|
|
|
```task
|
|
id: CE-WP-0003-T02
|
|
state_hub_task_id: f17e251d-4fd7-4ef3-b35c-e8e0dfb3a455
|
|
priority: high
|
|
status: done
|
|
depends_on: [T01]
|
|
```
|
|
|
|
Under `src/binder/`:
|
|
|
|
- `repos/in-memory-links.ts` — Map-backed `EvidenceLinkRepository`
|
|
- `services/bindings.ts` — `linkEvidenceToTarget`, `unlinkEvidence`,
|
|
`listEvidenceForTarget`, `setActiveEvidence`
|
|
- `state/active.ts` — a small machine tracking
|
|
`(activeTarget, activeEvidenceItem, activeAnnotation)`. Exposed as a React
|
|
context.
|
|
|
|
Emit the events from SharedContracts §4 (`EvidenceLinkCreated`,
|
|
`EvidenceItemActivated`, `FormFieldActivated`).
|
|
|
|
---
|
|
|
|
## T03 — Rect registry (the SharedContracts §7 contract)
|
|
|
|
```task
|
|
id: CE-WP-0003-T03
|
|
state_hub_task_id: d3b853ef-7afe-491f-b40b-b6e980a23478
|
|
priority: critical
|
|
status: done
|
|
depends_on: [T02]
|
|
```
|
|
|
|
Implement under `src/binder/visual-guide/`:
|
|
|
|
- `rect-registry.ts` — `RectRegistry` with `register`, `getRect`,
|
|
`subscribe` per SharedContracts §7
|
|
- `react-hooks.ts` — `useRegisterRect(kind, id, ref)` for components to
|
|
register a ref-derived rect
|
|
- `events.ts` — registry emits `rect-changed` events on
|
|
scroll/resize/focus/active-evidence-change (use ResizeObserver +
|
|
IntersectionObserver + window resize + window scroll listeners)
|
|
|
|
Unit tests: register a fake field, evidence card, and highlight; mutate
|
|
their bounding rects; assert subscribers fire with the new rects.
|
|
|
|
**This contract must not change after T03.** Three subsystems will depend on
|
|
it in T05/T06/T07.
|
|
|
|
---
|
|
|
|
## T04 — Form schema + simple field renderer
|
|
|
|
```task
|
|
id: CE-WP-0003-T04
|
|
state_hub_task_id: f42e1ecc-351c-4248-8872-1a25e79d3640
|
|
priority: medium
|
|
status: done
|
|
depends_on: [T01]
|
|
```
|
|
|
|
A deliberately minimal form schema lives in `src/app/forms/demo-schema.ts`:
|
|
|
|
```ts
|
|
type FormFieldSchema =
|
|
| { type: "text"; id: string; label: string }
|
|
| { type: "textarea"; id: string; label: string }
|
|
| { type: "date"; id: string; label: string };
|
|
```
|
|
|
|
JSON Schema is **not** used yet — defer that to a later ADR. The MVP form
|
|
just needs to render 3-4 fields and accept evidence links.
|
|
|
|
- `src/binder/FormRenderer.tsx` renders the schema as a basic form
|
|
(relocated from `src/work/` per `wiki/DependencyMap.md` §2/§5 — `work`
|
|
cannot import `binder`, but FormRenderer needs `useRegisterRect` from
|
|
`binder/visual-guide`. The "evidence-backed form" composition belongs
|
|
in `binder/`; `app/` mounts both `work` panes and `binder` panes
|
|
side-by-side.)
|
|
- Each field registers itself with the rect registry as kind `"field"` with
|
|
the field's `id`
|
|
|
|
---
|
|
|
|
## T05 — Side-by-side layout + link evidence to field
|
|
|
|
```task
|
|
id: CE-WP-0003-T05
|
|
state_hub_task_id: 100fb1ca-6168-4e5d-9dc5-f051e6f9ff61
|
|
priority: high
|
|
status: done
|
|
depends_on: [T02, T04]
|
|
```
|
|
|
|
A new app route `/forms/demo` shows the side-by-side layout from Architecture
|
|
§12.2:
|
|
|
|
- Left: `FormRenderer` with a demo schema (3 fields)
|
|
- Right: viewer (reusing `ViewerShell` from CE-WP-0002)
|
|
- Bottom strip or popover: evidence list
|
|
|
|
Linking interaction: click an evidence item, then click a field → link
|
|
created. (Drag-and-drop is a polish item, not MVP.) Visual indication on
|
|
linked fields (e.g. a chip showing the count of linked evidence items).
|
|
|
|
---
|
|
|
|
## T06 — Active-evidence cycling on a field
|
|
|
|
```task
|
|
id: CE-WP-0003-T06
|
|
state_hub_task_id: e3bdf1d3-c7a1-484c-8895-8d103e7f9fe6
|
|
priority: high
|
|
status: done
|
|
depends_on: [T05]
|
|
```
|
|
|
|
When a field is focused:
|
|
|
|
1. Binder loads the field's evidence set.
|
|
2. The first evidence item becomes active.
|
|
3. The viewer scrolls to and highlights its annotation.
|
|
4. Keyboard `Tab`/`Shift-Tab` within the field's evidence chips cycles
|
|
active evidence; viewer scrolls accordingly.
|
|
5. The evidence sidebar highlights the active evidence card.
|
|
|
|
Each evidence card registers itself with the rect registry as
|
|
`"evidence-card"`.
|
|
|
|
---
|
|
|
|
## T07 — SVG visual guide overlay
|
|
|
|
```task
|
|
id: CE-WP-0003-T07
|
|
state_hub_task_id: e2ec50be-d9c5-47dd-b801-9c1afb01e6fd
|
|
priority: high
|
|
status: done
|
|
depends_on: [T03, T06]
|
|
```
|
|
|
|
Implement `src/binder/visual-guide/Overlay.tsx`:
|
|
|
|
- Single absolutely-positioned SVG covering the viewport
|
|
- Subscribes to the rect registry
|
|
- On every change, redraws two curves: `field → evidence-card` and
|
|
`evidence-card → highlight`
|
|
- Active-only — only the currently active triple gets drawn
|
|
- Throttled to animation frames
|
|
|
|
Acceptance: scroll the viewer, resize the window, change active evidence —
|
|
the guide tracks every change without visible lag.
|
|
|
|
The viewer adapter from CE-WP-0002 must expose
|
|
`getHighlightClientRects(annotationId)` so the highlight's rect can be
|
|
registered.
|
|
|
|
---
|
|
|
|
## T08 — E2E test of PRD scenario steps 5-9
|
|
|
|
```task
|
|
id: CE-WP-0003-T08
|
|
state_hub_task_id: e6754c8e-f9e2-435a-af28-31a693c6d9a8
|
|
priority: high
|
|
status: done
|
|
depends_on: [T05, T07]
|
|
```
|
|
|
|
Extend the Playwright E2E from CE-WP-0002-T09:
|
|
|
|
5. Navigate to `/forms/demo`.
|
|
6. Link the previously-created evidence item to the "summary" field.
|
|
7. Click the "summary" field.
|
|
8. Assert the field, the evidence card, and the highlight all have an
|
|
`aria-current="true"` (or equivalent active marker).
|
|
9. Assert the SVG overlay contains exactly two `<path>` elements (one
|
|
field→card, one card→highlight).
|
|
10. Scroll the viewer; assert the SVG paths' endpoints update within the
|
|
next animation frame.
|
|
|
|
If this passes, the form-binding slice is complete and CE-WP-0004 may run
|
|
in parallel with any deferred polish work.
|