Core — Live Notes
PATCH /meetings/:id notes field update, debounced write semantics, and EntityChangedEvent broadcast to the owner's other sessions.
Core — Live Notes
Owner: Core Engineer Domain: core Complexity: S Prerequisite: Milestone 03 merged (shared note components)
When this slice is complete, PATCH /meetings/{id} accepts a notes field update at any time — including during an active recording — persists every edit immediately (there is no separate save/commit call), echoes the stored value in the response, and broadcasts EntityChangedEvent { entity: "meeting", action: "updated", fields: ["notes"] } to the owner's other sessions while excluding the originating Client-Session-Id. Notes are never touched by any ML write-back path (PUT /synthesis, POST /talking-points, PUT /tasks/system) or by service-auth field updates such as the generated headline.
Required Capabilities
-
PATCH /meetings/{id}accepts{"notes": string | null}and persists it immediately, with no separate save/commit call. - The response echoes the saved
notesvalue. -
GET /meetings/{id}andGET /meetings(list shape) carrynotes. - Every successful notes
PATCHbroadcastsEntityChangedEvent { entity: "meeting", action: "updated", fields: ["notes"] }to the owner's other WebSocket sessions. - The originating
Client-Session-Iddoes not receive an echo of its own edit. -
PUT /meetings/{id}/synthesis,POST /meetings/{id}/talking-points,PUT /meetings/{id}/tasks/system, and the service-auth headlinePATCHnever modifynotes. - An invalid
notesbody (non-string, non-null) is rejected with422without altering the previously saved value. - A
PATCHagainst a meeting that does not exist, or that belongs to another user, is rejected (404/403) without altering the previously saved value.
Dependencies
- Milestone 03 (
reusable-note-components) must be merged — this slice reuses the shared note rendering components on the finalized meeting page. - Milestone 04 (
live-transcript-to-final-rebuild) must be merged — the live recording WebSocket session used to exercise the autosave path during an active recording.
Domain Notes
Notes are a plain field on meetings, not a generated artifact — they are the one piece of state on the recording session that no ML write-back path is allowed to touch. There is no autosave endpoint distinct from the ordinary PATCH: durability comes from every PATCH being immediately persisted, so a debounced client can fire as many of them as it likes and only the latest write wins.
| Write-back path | Touches notes? |
|---|---|
PATCH /meetings/{id} (user) | Yes — this is the only path that writes notes |
PUT /meetings/{id}/synthesis (ML) | No |
POST /meetings/{id}/talking-points (ML) | No |
PUT /meetings/{id}/tasks/system (ML) | No |
PATCH /meetings/{id} (service, headline) | No — updates headline only |
Test Cases
Test cases map to tests/bets/meeting-recording/test_milestone_06_live_notes.py. Run via ./dev test bet meeting-recording.
| Test | Location | Assertion |
|---|---|---|
test_user_can_edit_private_notes_while_recording | test_milestone_06 | Three successive PATCH /meetings/{id} calls during an active recording each persist and echo their notes value, and the owner's other WebSocket session receives one entity.changed(meeting, fields=["notes"]) per edit. |
test_notes_autosave_without_manual_save | test_milestone_06 | Five rapid PATCH calls tagged with a Client-Session-Id leave the last value stored with no explicit save call; the owner's other session sees all five entity.changed events, and the originating session receives none of its own. |
test_notes_restore_after_refresh_during_recording | test_milestone_06 | A brand-new client (GET /meetings/{id} and GET /meetings) sees the latest saved notes while the recording is still active. |
test_notes_survive_stop_and_finalization | test_milestone_06 | After stop and finalization, GET /meetings/{id} returns the unchanged notes alongside the completed final synthesis. |
test_generated_artifacts_do_not_overwrite_notes | test_milestone_06 | PUT /synthesis, POST /talking-points, PUT /tasks/system, and the service PATCH headline update all succeed without changing notes. |
test_note_save_failure_does_not_corrupt_saved_content | test_milestone_06 | An invalid body (422), a save against a non-existent meeting (404/403), and a save by a different user (403/404) all leave the previously saved notes intact; a subsequent valid save still succeeds. |
Completion Checklist
- Code merged and deployed
- Bet progress tests pass (
./dev test bet meeting-recording) - Permanent service tests implemented per testing strategy
- Code review completed
- API review completed (
PATCH /meetings/{id}notes semantics) - Testing review completed
- System documentation updated (API reference, architecture docs as applicable)