Enrollment metadata: editable via add-key/value (frontend-only, no schema change)
failedSlack thread 1780496985.991259 (Richie DM 2026-06-03 14:29 UTC). Make the metadata key/value bag in the EnrollmentDetailDrawer editable via an inline 'add new key/value' affordance. Existing keys stay read-only (no edit, no delete). New keys/values flow through the existing updateEnrollment mutation, which merges into the JSON column — non-destructive.
Scope locked with Richie (msg ts 1780498631.570459):
- Existing metadata rows: read-only display (no inline edit, no delete)
- Add 'Add metadata' affordance opening inline row [key input] [value input] [save/cancel]
- On save: updateEnrollment(metadata: { ...existing, [newKey]: newValue })
- Apollo cache update via mutation update() callback to refresh drawer view; refetch as fallback
- Reject duplicate-key adds in client (inline validation, don't send mutation)
- Single frontend-only PR
Files to touch (per investigation in Slack thread):
- apps/dashboard/components/EnrollmentDetailDrawer.tsx — replace read-only StatList around L742-750 with new EnrollmentMetadataSection component
- apps/dashboard/components/EnrollmentMetadataSection.tsx (new) — copy patterns from EnrollmentTagsSection.tsx (196 lines, closest analog)
- apps/dashboard/components/EnrollmentMetadataSection.test.tsx (new) — tests for: render existing metadata read-only, open add affordance, reject duplicate-key, successful add updates cache
- Maybe small dashboard GraphQL query touch if Enrollment.metadata isn't in the existing fragment
No backend changes. Backend updateEnrollment merge semantics in domains/program/src/repositories/enrollment/updateEnrollment.ts already work for add+update; we accept the 'no delete' limitation per Richie 2026-06-03 14:54 UTC.
Needs Linear issue under BOLT before PR is opened. Branch: winston/bolt-XXXX-enrollment-metadata-add
Local checks: yarn typecheck (dashboard), yarn test (EnrollmentMetadataSection.test.tsx), yarn build (dashboard), yarn lint, yarn biome:check. Standard commit trailer Co-authored-by: Richie Casto <[email protected]>.
Event Timeline
created
subagent_spawned
spawn claim: enrollment-metadata-add-key-frontend
status_change
queued → in_progress
failed
lease expired — re-queued for retry
in_progress → queued
status_change
queued → in_progress
failed
lease expired — re-queued for retry
in_progress → queued
subagent_completed
subagent done: sub-agent crashed during gateway restart after implementation; parent taking over local gates/PR
status_change
queued → in_progress
failed
lease expired — max retries reached, marking failed (poison pill)
in_progress → failed