Skip to content

Commit c193f53

Browse files
committed
docs(_plans): record B1 progress + requeue-semantics decision
Master plan Progress tracking now reflects 709d2f5. Captures the score-equals-createdAt invariant decision (requeue keeps original score; createdAt is immutable across retries) so future sessions don't relitigate the Q1 underspec.
1 parent 709d2f5 commit c193f53

1 file changed

Lines changed: 8 additions & 3 deletions

File tree

_plans/2026-05-19-mollifier-api-parity.md

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@
1313
| Merge of origin/main | ✅ Done | `8c01cf0eb` | 8 conflicts resolved; phase-3 versions kept; picked up one doc comment from main about shadow-mode counter writes |
1414
| Design docs + parity script | ✅ Done | `c8d036aa0` | 6 plan docs + `scripts/mollifier-api-parity.sh` |
1515
| **Phase A — read endpoints** |**Done** | `6b8a54e43`, `e21dbee5e` | See "Phase A patterns established" below |
16-
| Phase B — shared infrastructure | ⏳ Next || ZSET migration, drainer ack semantics, mutateSnapshot Lua, helpers |
16+
| **Phase B1 — ZSET migration** |**Done** | `709d2f5af` | Score = `createdAtMicros`; requeue keeps original score (createdAt immutable across retries) — see decision below |
17+
| Phase B2-B6 — drainer ack + mutateSnapshot + helpers | ⏳ Next || Drainer ack semantics, mutateSnapshot Lua, SyntheticRun extension, mutateWithFallback, idempotency |
1718
| Phase C — mutation endpoints | ⏳ Pending || cancel first (drives B), then tags/metadata-put/reschedule/replay |
1819
| Phase D — dashboard internals | ⏳ Pending || reuse C paths |
1920
| Phase E — listing endpoints | ⏳ Pending || Q1 design |
@@ -72,13 +73,17 @@ If Phase B/C endpoints need additional fields from the buffer snapshot, extend `
7273

7374
Q2 (replay) explicitly calls out the synthesiser extension — when implementing Phase C5 (replay), extend `SyntheticRun` with the full set of fields `ReplayTaskRunService` reads.
7475

75-
## Phase B — shared infrastructure (NEXT)
76+
## Phase B — shared infrastructure (in progress)
7677

7778
Start here. Implements the building blocks that unblock Phase C. Detailed in [`2026-05-19-mollifier-listing-design.md`](2026-05-19-mollifier-listing-design.md) (Q1), [`2026-05-19-mollifier-mutation-race-design.md`](2026-05-19-mollifier-mutation-race-design.md) (Q3), and [`2026-05-19-mollifier-idempotency-design.md`](2026-05-19-mollifier-idempotency-design.md) (Q5).
7879

80+
### B1 — Decision recorded (commit `709d2f5af`)
81+
82+
Q1 underspecified the requeue case. Resolution: **ZSET score == `createdAtMicros`, immutable across retries.** Requeue does not bump the score, so a retried entry continues to pop next (oldest first). The drainer's `maxAttempts` bounds the retry loop. This keeps the listing-pagination invariant (score == createdAt) clean — no need for a separate "lastQueuedMicros" field. The existing "requeue lands at back" test was inverted to assert "requeue lands at front" — that's the correct behavior under this invariant.
83+
7984
Order:
8085

81-
- **B1.** ZSET migration in `packages/redis-worker/src/mollifier/buffer.ts`. `acceptMollifierEntry` Lua → `ZADD queue createdAtMicros runId`. `popAndMarkDraining` Lua → `ZPOPMIN`. `requeueMollifierEntry` Lua → `ZADD`. Listing read goes via `ZREVRANGEBYSCORE`. **Forward-compat:** ship drainer-side changes first, API-side second.
86+
- **B1.** ✅ Done (`709d2f5af`). ZSET migration in `packages/redis-worker/src/mollifier/buffer.ts`. `acceptMollifierEntry` Lua → `ZADD queue createdAtMicros runId`. `popAndMarkDraining` Lua → `ZPOPMIN`. `requeueMollifierEntry` Lua → `ZADD` reusing the original createdAtMicros. Listing read via `ZREVRANGE`. **Forward-compat note for rollout:** new entries carry the `createdAtMicros` hash field; pre-deploy in-flight entries lack it and would fail schema parse — handle via Phase F4 forward-compat tests when deploying.
8287
- **B2.** Drainer ack semantics — replace `DEL entry` with atomic `HSET materialised=true; EXPIRE +30s`. Touches `MollifierBuffer.ack` + the underlying Lua.
8388
- **B3.** `MollifierBuffer.mutateSnapshot(runId, patch)` — atomic Lua. Three return codes: `applied_to_snapshot`, `not_found`, `busy`. Patch types: `append_tags`, `set_metadata`, `set_delay`, `mark_cancelled`. Idempotency-key patch comes in Q5 work.
8489
- **B4.** Snapshot-to-TaskRun synthesiser extension — extend `SyntheticRun` in `readFallback.server.ts` to include the fields `ReplayTaskRunService` reads (see Q2 doc table). The Phase C5 work depends on this.

0 commit comments

Comments
 (0)