Round-trip fix (item 5): serializeCanvasShapes no longer re-derives the question
tree from boundary pairs (which flattened 3-deep → 2-tier). The whole tree is now
carried as 'part' shapes that hold parentId + isContainer + depth; save preserves
the real parent_id chains (persisted parent wins; geometry is only a fallback for
manually-drawn shapes). Boundary-pair synthesis is kept but attaches to a covering
container box when one exists. New test locks a 3-deep Q→part→subpart round-trip.
Draw structure (item 4): shapesFromTemplate now draws containers too (were skipped),
each with nesting depth. examCanvasShapes renders container frames (transparent,
depth-hued border), PRINTS MARKS on part/container boxes (◆N pill; were never
drawn), and NAMES context figures (figure name as label + description tooltip +
'→ Q' tether pill; was an anonymous purple box). Context name/description round-trip
via exam_response_areas.meta.
Threads new shape props through the tldraw util + setup page + types. Adds meta to
ExamResponseArea + replace payload. tsc: no new errors; 7/7 model tests pass.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GruxHXxfdp4kZCgAMVFgvV
The extraction service types every answer space (multiple choice, draw-on, table,
ruled lines…), but the canvas rendered them all as a generic blue 'Response' box.
Add a small form badge (bottom-right) so the recognition is legible at a glance;
context regions show their type too. Colour-by-kind is unchanged.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The S5-7 review layer could surface unconfirmed AI shapes but had no way to
resolve them (confirmed was never set true), so the only "dismiss" was deletion
and the unconfirmed count never dropped. Add the resolution loop:
- A floating review-actions panel (shown while unconfirmed > 0): Accept selected,
Reject (delete) selected, and Accept all AI on the page. Accept flips
props.confirmed = true.
- Human edit = implicit confirm: nudging/resizing an AI ghost marks it confirmed
(R3.3 — a teacher who adjusts a suggestion has reviewed it). Geometry-only
trigger, so the confirmed-only update can't recurse.
- Confidence-driven opacity: unconfirmed ghosts fade by confidence instead of a
constant 0.72; confirmed AI renders solid with its kind icon (like manual).
- Live review counts read straight off the canvas so the unconfirmed chip/panel
update immediately on accept/reject (the old count reflected only saved state).
Persists through the existing PUT (confirmed already round-trips). No schema or
API change.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>