188 Commits

Author SHA1 Message Date
e6ecc723cc Merge exam-canvas form badge
Some checks failed
app-ci-deploy / test-build-deploy (push) Has been cancelled
2026-07-02 23:55:43 +00:00
0f44dc614c Exam canvas: show recognised response FORM on each ghost
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>
2026-07-02 23:55:43 +00:00
1bb2011e58 Merge exam-bank corpus coverage UI
Some checks failed
app-ci-deploy / test-build-deploy (push) Has been cancelled
2026-07-02 22:35:35 +00:00
f4be133069 Exam bank: corpus coverage dashboard (/exam-marker/corpus)
New "Exam bank" page displaying the state of the collected past-paper corpus:
per-specification coverage of question papers / mark schemes / examiner reports,
with global + filtered rollups, board/level/subject filters, a "sciences only"
default, and an expandable per-session table (QP/MS/ER present ✓/–). Reads
GET /api/exam/corpus. Dashboard gets an "Exam bank" entry point.

examRepository.getCorpus + corpus types. tsc clean on the changed files.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 22:35:35 +00:00
d47e0205c9 Merge mode-3 bank crop thumbnails
Some checks failed
app-ci-deploy / test-build-deploy (push) Has been cancelled
2026-07-02 22:19:08 +00:00
11d19778d6 Mode-3: crop thumbnails on question bank cards
Render a preview per bank question, client-side, from the source PDF cropped to
the question's bounds — makes the bank visually browsable like the spike cockpit.

bankCrops.ts: renders each template's PDF once (cached) via the existing pdf.js
loader (already at the 780px coordinate space the bounds live in), then crops the
page image to (bounds.x, bounds.y - pageTop, w, h) → a small PNG data-URL; decoded
page images are cached too. QuestionBankPage: a lazy <QuestionCrop> at the top of
each card (spinner → image, or "no preview" when a question has no bounds/PDF).

No API/infra change. tsc clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 22:19:08 +00:00
a80bdea140 Merge mode-3 question bank UI
Some checks failed
app-ci-deploy / test-build-deploy (push) Has been cancelled
2026-07-02 22:09:28 +00:00
905626f494 Mode-3: Question bank page + custom-paper assembly UI
New /exam-marker/bank page: browse leaf questions across your papers, filter by
spec point (the spec-planning surface) and subject via facet chips, select
questions into a basket, and "Create paper" → POST /custom-papers → opens the new
template in setup. Dashboard gets a "Question bank" entry point.

examRepository.getBank + createCustomPaper; BankQuestion/BankResponse/custom-paper
types. tsc clean. Pairs with the mode-3 API endpoints (already merged).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 22:09:28 +00:00
b52f6c54ba Merge fx-5-scan-ingestion
Some checks failed
app-ci-deploy / test-build-deploy (push) Has been cancelled
2026-07-02 21:48:32 +00:00
e6a2480818 Merge fx-8-response-area-attach 2026-07-02 21:48:32 +00:00
2b33aa80eb Merge fx-4-confirm-dismiss 2026-07-02 21:48:32 +00:00
CC Worker
7a1dd4dccc FX-5: scan-ingestion UI on the marking page
The marking flow read student_submissions but there was no way to create them —
print→scan→mark could not be completed in-app. Add an "Upload scans" control to
the marking queue that posts PDFs to the existing POST /batches/{id}/scans and
refreshes the queue.

- examRepository.uploadScan(batchId, file, {studentId?, matchingMethod?}): multipart
  upload (axios sets the boundary), returns the created/updated StudentSubmission.
- ExamMarkingPage: "Upload scans" button + hidden multi-file PDF input; uploads each
  with matching_method='ordered' (fills the roster in order; unmatched scans become
  reconcilable submissions), then reloads the queue with a success/failure summary.

No API or schema change (endpoint already existed). tsc clean; behaviour is covered
by the cc-browser-tester card (FX-V).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 21:44:04 +00:00
CC Worker
4001772d5e FX-8: stop dropping / mis-attaching response areas on save
serializeCanvasShapes recomputed each region's owner purely from geometry,
ignoring the persisted question_id: a region with no enclosing part (or any
region when a template had no parts) was silently dropped, and one overflowing
its part by a pixel re-parented to parts[0].

Resolve the owner in order: geometric containment (a drag into a part re-attaches)
-> persisted question_id if it still points at a saved question (survives drift /
no-container) -> nearest part on the page -> first part -> first question of any
kind. exam_response_areas.question_id is NOT NULL, so a region is never dropped
while any question exists.

Tests: never drops a region with no enclosing part; persisted question wins over
geometric nearest. Full model.test.ts suite (6) passes; tsc clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 21:40:11 +00:00
CC Worker
f72ea7189c FX-4: confirm/dismiss UI for AI ghost suggestions
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>
2026-07-02 21:08:38 +00:00
CC Worker
7bd66fbaf0 fix(exam): stop placeholder guide shapes flashing before template loads
Some checks failed
app-ci-deploy / test-build-deploy (push) Has been cancelled
seedGuide() ran in onMount via the 'else' branch while template was still null during the async
fetch, creating 5 example shapes (Q1 start/end, part, response, context) that flashed on screen
until the real template + PDF loaded. Only seed the guide for a genuinely-empty template after load.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 19:19:15 +00:00
9c3a5f97cc docs(admin): clarify exam-corpus reset warning
Some checks failed
app-ci-deploy / test-build-deploy (push) Has been cancelled
2026-06-08 00:58:03 +01:00
CC Worker
2ccfb9ccd6 fix(dev): route Supabase same-origin via /__supabase proxy
Some checks failed
app-ci-deploy / test-build-deploy (push) Has been cancelled
app-dev built with --mode production was baking the PROD Supabase URL (.env)
into the bundle, so browser auth went cross-origin to supa.classroomcopilot.ai
and was CORS-blocked (and hit the wrong user store). Mirror the /__ccapi fix:
- Dockerfile: nginx /__supabase/ -> dev Supabase .94:8000 (+WS upgrade for realtime)
- supabaseClient.ts: resolve a leading-slash VITE_SUPABASE_URL against
  window.location.origin so supabase-js gets an absolute same-origin URL
- docker-compose.dev.yml: bake VITE_SUPABASE_URL=/__supabase (like VITE_API_BASE)
Browser now talks only to the app host (Tailscale or LAN), no CORS, dev .94 store.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 21:20:57 +00:00
CC Worker
ef13a124dd Merge S5-7 G6 review wiring
Some checks failed
app-ci-deploy / test-build-deploy (push) Has been cancelled
# Conflicts:
#	src/pages/exam/setup/ExamTemplateSetupPage.tsx
#	src/pages/exam/setup/examCanvasShapes.tsx
#	src/utils/exam-canvas/model.ts
2026-06-07 20:06:45 +00:00
CC Worker
ffa0ad85ac Merge S4-11: marking flow + class results + same-origin API proxy fix
Some checks failed
app-ci-deploy / test-build-deploy (push) Has been cancelled
2026-06-07 20:04:07 +00:00
92f9dfef82 S5-7: basic G6 review wiring (dashed/translucent AI shapes, confidence, flags)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 20:56:57 +01:00
824031f2c0 feat(exam): add auto-map PDF canvas refresh
Some checks failed
app-ci-deploy / test-build-deploy (push) Has been cancelled
2026-06-07 20:46:41 +01:00
7db852aaff [verified] route app-dev API through same-origin proxy 2026-06-07 20:43:20 +01:00
CC Worker
afc0371dd9 Merge S5-6 layout/provenance types + repository (App)
Some checks failed
app-ci-deploy / test-build-deploy (push) Has been cancelled
# Conflicts:
#	src/utils/exam-canvas/model.ts
2026-06-07 19:22:24 +00:00
7326b9f3be [verified] fix app-dev api proxy and build env 2026-06-07 20:20:42 +01:00
cd8ac38d39 Merge remote-tracking branch 'origin/master' into agent/s4-11-marking-results 2026-06-07 20:13:43 +01:00
469bcc0517 [verified] align app exam layout payloads 2026-06-07 20:05:49 +01:00
e899af303d Make exam boundaries page-width lines
Some checks failed
app-ci-deploy / test-build-deploy (push) Has been cancelled
2026-06-07 20:01:54 +01:00
7a01b3e8f6 Merge remote-tracking branch 'origin/master' into agent/s4-11-marking-results
# Conflicts:
#	src/AppRoutes.tsx
#	src/pages/exam/index.ts
#	src/services/exam/examRepository.ts
#	src/types/exam.types.ts
2026-06-07 19:58:38 +01:00
bff91a4b17 feat(exam): S4-11 marking flow and class results 2026-06-07 19:50:20 +01:00
CC Worker
66f35b8ae4 fix(exam): compact top bar, collapsible guide panel
Some checks failed
app-ci-deploy / test-build-deploy (push) Has been cancelled
Top bar reduced to single-line height: Back becomes an icon button, caption
line removed (detail lives in the guide), Save button size=small. Guide
panel defaults collapsed and toggles via a ? icon button at bottom-right
so it doesn't occupy permanent canvas real estate.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-07 13:37:47 +00:00
CC Worker
fe5dbe7fa8 feat(exam): doc-view camera constraints and sidebar layout
Some checks failed
app-ci-deploy / test-build-deploy (push) Has been cancelled
Replaces infinite-canvas free-pan with a constrained vertical-scroll doc
view: tldraw setCameraOptions with behavior='contain', fit-x-100, and top
origin so the PDF never drifts side-to-side. Layout restructured from
floating overlays to flex column (top bar + sidebar/canvas row). Tool
panel is now a left sidebar, guide panel overlays canvas bottom-right.

PAGE_START_X changed from 260 → 0 so pages are flush left; camera
applyDocViewConstraints() called incrementally as pages stream in and
with resetZoom() once all pages are loaded.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-07 12:36:21 +00:00
CC Worker
15a519748d fix(exam): keep region shapes overlaid on PDF in setup canvas
Some checks failed
app-ci-deploy / test-build-deploy (push) Has been cancelled
Three z-order fixes in ExamTemplateSetupPage:

1. loadShapes: early-return before deletion when models is empty, so
   seed guide shapes aren't wiped for a fresh template that has no
   saved regions yet.

2. Incremental PDF loading (onPageReady): replace per-page sendToBack
   (unreliable when all shapes are moving — reorderToBack no-ops) with
   bringToFront on existing domain shapes after each page is added.

3. Final load sequence: call bringDomainShapesToFront after syncPdfPages
   + loadShapes to guarantee correct z-order regardless of how tldraw's
   fractional indexer placed newly created shapes. Also called from
   onMount for the same reason.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-07 10:12:16 +00:00
CC Worker
3389fdcb5b feat(exam): S4-11 marking flow, results table, CSV, ResultsWidget
Some checks failed
app-ci-deploy / test-build-deploy (push) Has been cancelled
- /exam-marker/:batchId/mark — ExamMarkingPage: student queue, per-part mark entry, upsert marks
- /exam-marker/:batchId/results — ExamResultsPage: results table with absent rows, CSV download
- ResultsWidget on ClassDetailPage: last batch summary, class average, absent count, batch creation
- New types: MarkingBatch, StudentSubmission, BatchQueueResponse, BatchResultsResponse, MarkUpsertPayload
- New repo methods: createBatch, listBatches, getBatchQueue, getBatchResults, getBatchCsv, upsertMark

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-07 04:35:34 +00:00
CC Worker
ab35193be1 Merge S4-10: mark scheme editor + SpecPoint picker
Some checks failed
app-ci-deploy / test-build-deploy (push) Has been cancelled
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-07 04:31:02 +00:00
CC Worker
b3f71c5749 Merge S4-10: mark scheme editor + SpecPoint picker
- Add /exam-marker/:templateId/marks route with MarkSchemePage
- Per-Part mark scheme editor: points/levels/parts/checklist/free forms
- SpecPoint picker via GET /api/exam/specs/{spec_code}/points (falls back to manual spec_ref when endpoint 404s)
- Manual neo4j-sync button; ASSESSES edge verified in cc.public.exams
- Edit marks button on each template card in dashboard
- Merge-resolved: AppRoutes, index.ts, exam.types.ts, ExamDashboardPage (kept grouped UI + added Edit marks button)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-07 04:30:41 +00:00
CC Worker
b396af96b9 Merge S4-9c: exam canvas UX polish — icons, dark/light palette tokens, multi-page boundary hint
Some checks failed
app-ci-deploy / test-build-deploy (push) Has been cancelled
2026-06-07 04:10:15 +00:00
3eac792ced feat(exam-setup): UX polish — icons, dark/light palette tokens, multi-page boundary hint 2026-06-07 05:10:11 +01:00
CC Worker
8e8a345e61 fix: incremental PDF page rendering for exam setup backdrop
Some checks failed
app-ci-deploy / test-build-deploy (push) Has been cancelled
Rendering a 36-page AQA exam PDF sequentially created 36 large canvas
elements, causing memory pressure and keeping pdfStatus='loading' for
60–120s in headless Chrome. Two changes:

1. pdfLoader.ts: reuse a single canvas (reduces peak memory from ~120MB
   to ~4MB) and fire onPageReady callback after each page so callers can
   stream pages to the canvas as they render.

2. ExamTemplateSetupPage.tsx: use the callback to add each PDF page
   shape to the tldraw canvas the moment it renders, making the first
   page visible within a few seconds rather than after all pages load.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-07 03:35:09 +00:00
CC Worker
2de3e29179 fix: serve .mjs files as application/javascript for pdfjs module worker
Some checks failed
app-ci-deploy / test-build-deploy (push) Has been cancelled
nginx:alpine mime.types only covers .js, not .mjs. The pdfjs-dist v4
worker is output as pdf.worker-*.mjs; without the correct MIME type the
browser refuses to execute it as a module worker and pdfjs throws
'Network Error', blocking the PDF backdrop from rendering.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-07 03:21:44 +00:00
CC Worker
29390d30ca Merge S4-9b: PDF backdrop on ExamCanvas from source-pdf endpoint
Some checks failed
app-ci-deploy / test-build-deploy (push) Has been cancelled
Renders template source PDFs as locked image shapes behind the exam
setup regions. Adds page geometry abstraction so shape coordinates
map to real PDF page dimensions rather than fixed PAGE_HEIGHT math.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-07 02:59:17 +00:00
aa2f35e467 feat(exam): render template PDFs behind setup canvas 2026-06-07 03:56:09 +01:00
CC Worker
61a189a7a2 fix: tldraw user prefs colorScheme and indicator method for shape utils
Some checks failed
app-ci-deploy / test-build-deploy (push) Has been cancelled
- updateUserPreferences: isDarkMode → colorScheme ('dark'|'light') per
  tldraw 3.6.1 TLUserPreferences type (isDarkMode is read-only computed)
- BaseBoxShapeUtil subclasses: add required indicator() method returning
  bounding rect; fixes non-abstract class missing abstract member error

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-07 02:30:57 +00:00
CC Worker
ab6f0b09d7 fix: remove duplicate bindingUtils causing tldraw arrow double-registration
Some checks failed
app-ci-deploy / test-build-deploy (push) Has been cancelled
Tldraw 3.6.1 Tldraw component already registers defaultBindingUtils
internally; passing them explicitly via the bindingUtils prop caused
"Binding type 'arrow' is defined more than once" runtime crash.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-07 02:21:32 +00:00
CC Worker
16ae3aa089 fix(exam): setup toolbar crash — MUI Button color 'default' is invalid in v5
Some checks failed
app-ci-deploy / test-build-deploy (push) Has been cancelled
Select + Furniture tool buttons used color='default', which MUI v5 resolves to
theme.palette.default (undefined) -> TypeError reading 'main'/'dark' at render,
tripping the ErrorBoundary ('Template setup canvas crashed'). Use 'inherit'.

Caught by live browser-verify t_11f5a049; model-level tests never rendered the toolbar.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 01:03:08 +00:00
CC Worker
496ec2cbf9 merge: ExamCanvas core setup page /exam-marker/:templateId/setup (S4-9a)
Some checks failed
app-ci-deploy / test-build-deploy (push) Has been cancelled
2026-06-07 00:54:55 +00:00
dea3275f23 [verified] Add exam template setup canvas 2026-06-07 01:27:44 +01:00
CC Worker
f067db3eb8 Merge remote-tracking branch 'origin/agent/s4-8-2-template-versioning'
Some checks failed
app-ci-deploy / test-build-deploy (push) Has been cancelled
2026-06-07 00:12:25 +00:00
1ab8aab43c feat(exam): add mark scheme editor 2026-06-07 00:34:56 +01:00
fdbc19cf0d feat(exam): version templates on dashboard 2026-06-07 00:33:06 +01:00
CC Worker
adc7a2a05b merge: exam-marker app dashboard + /exam-marker route (S4-8)
Some checks failed
app-ci-deploy / test-build-deploy (push) Has been cancelled
New ExamDashboardPage + examRepository seam; dashboard nav entry; removes the old
CCExamMarker viewer + dead CCExamMarkerPanel wiring (R1.1). Build green; route tests pass.
2026-06-06 19:50:23 +00:00