113 lines
4.2 KiB
Markdown
113 lines
4.2 KiB
Markdown
---
|
|
id: "02-batch-message-frame-mutations"
|
|
title: "Batch message frame mutations"
|
|
status: completed
|
|
wave: 2
|
|
depends_on:
|
|
- "01-coalesce-browser-diagnostic-work"
|
|
plan: "plan.md"
|
|
requirements:
|
|
- REQ-PLATFORM-BOUNDED-TASK-STATUS-DELIVERY-001
|
|
acceptance_criteria:
|
|
- AC-PLATFORM-BOUNDED-TASK-STATUS-DELIVERY-001.7
|
|
- AC-PLATFORM-BOUNDED-TASK-STATUS-DELIVERY-001.9
|
|
system_design:
|
|
- ../../specs/platform/system-design/bounded-task-status-delivery.md
|
|
---
|
|
|
|
# Task 02: Batch Message Frame Mutations
|
|
|
|
## Summary
|
|
|
|
Apply all accepted replacement messages from one animation frame in one
|
|
Zustand and Immer transaction. Preserve message merge and barrier behavior.
|
|
|
|
## Failing regression first
|
|
|
|
Add a scheduler test named `applies different message keys with one bulk store
|
|
action`. Enqueue two message keys, flush one frame, and prove that the store
|
|
receives one ordered array instead of two `updateMessage` calls.
|
|
|
|
Add a real-store test named `notifies subscribers once for one replacement
|
|
frame`. Seed two messages, subscribe to the session message array, apply the
|
|
bulk action, and prove that both messages change after one notification.
|
|
|
|
## In scope
|
|
|
|
- Add `updateMessages(messages)` to the session slice type and implementation.
|
|
- Share partial-field merge logic with `updateMessage(message)`.
|
|
- Convert, settle, and stale-filter frame payloads before one store action.
|
|
- Preserve first-key insertion order from the scheduler map.
|
|
- Preserve add, delete, and turn-settle barriers.
|
|
- Keep unaffected session arrays and message objects stable.
|
|
- Extend scheduler and slice tests for multi-session frames.
|
|
|
|
## Out of scope
|
|
|
|
- Backend lifecycle or gateway coalescing changes.
|
|
- Protocol payload or timestamp changes.
|
|
- Incremental transcript grouping or virtualization.
|
|
- A replacement for Zustand or Immer.
|
|
|
|
## Acceptance
|
|
|
|
- Several accepted message keys in one frame cause one bulk store call.
|
|
- A real store emits at most one subscriber notification for that frame.
|
|
- Final message fields match the current single-update behavior.
|
|
- Stale payloads remain rejected.
|
|
- Add and delete events cannot be reordered around pending replacements.
|
|
|
|
## Verification
|
|
|
|
```bash
|
|
cd apps && pnpm --filter @kandev/web test -- lib/ws/handlers/messages.test.ts lib/state/slices/session/session-slice.update-messages.test.ts lib/state/slices/session/session-slice.merge-messages.test.ts
|
|
cd apps && pnpm --filter @kandev/web run typecheck
|
|
cd apps/web && pnpm exec eslint lib/ws/handlers/messages.ts lib/ws/handlers/messages.test.ts lib/state/slices/session/types.ts lib/state/slices/session/session-slice.ts lib/state/slices/session/session-slice.update-messages.test.ts
|
|
```
|
|
|
|
## Files likely touched
|
|
|
|
- `apps/web/lib/ws/handlers/messages.ts`
|
|
- `apps/web/lib/ws/handlers/messages.test.ts`
|
|
- `apps/web/lib/state/slices/session/types.ts`
|
|
- `apps/web/lib/state/slices/session/session-slice.ts`
|
|
- `apps/web/lib/state/slices/session/session-slice.update-messages.test.ts`
|
|
|
|
## Dependencies
|
|
|
|
- Task 01 completes first so the later comparison trace can attribute logger
|
|
and store work separately.
|
|
|
|
## Risks
|
|
|
|
- Payload conversion inside the mutation can observe different turn state.
|
|
- A multi-session frame can accidentally replace an unaffected session array.
|
|
- Partial updates can clear known fields if undefined values are merged.
|
|
- Barrier tests can pass with mocks while real subscriber count still grows.
|
|
|
|
## Parallelism
|
|
|
|
`sequential`
|
|
|
|
## Inputs
|
|
|
|
- Bounded task status delivery acceptance criteria 7 and 9.
|
|
- The accepted replaceable session stream decision.
|
|
- Existing message scheduler and session slice tests.
|
|
|
|
## Results
|
|
|
|
Implemented the bulk replacement action and scheduler batching. Accepted
|
|
replacement payloads are converted and settled before one `updateMessages`
|
|
transaction, while add, delete, and turn-settle events remain ordered barriers.
|
|
The shared merge helper preserves partial-field behavior and unaffected session
|
|
state remains stable. The stale-snapshot regression now asserts that neither the
|
|
legacy single-update action nor the production bulk action is called.
|
|
|
|
Targeted verification passed:
|
|
|
|
- `lib/ws/handlers/messages.test.ts`
|
|
- `lib/state/slices/session/session-slice.update-messages.test.ts`
|
|
|
|
The broader work-order verification remains in the package-level check.
|