Pre-1.0 Design Spike Records¶
The roadmap requires two pre-freeze checks — not implementations, decisions. Recorded here so the freeze doesn't rest on unwritten conclusions.
Spike 1 — Weighted / composite quotas (deferred to 1.1, additive)¶
Question: does freezing today's Limiter surface preclude weighted
acquisition (an item consuming N tokens) or composite budgets
(requests/min AND tokens/min acquired atomically)?
Conclusion: no — extension is purely additive. The reasoning:
- Today's public
Limitersurface is three methods:wait(timeout=),wait_async(),pause(seconds). Weighted acquisition adds an optional parameter (wait(weight=1)) with a default that preserves every existing call site — no signature breaks. - Composite budgets compose around the current type: a future
Limiter.all(rpm_limiter, tpm_limiter)(or aCompositeLimiter) can implement the same three-method protocol; the engines call only that protocol (_as_limiternormalizes at the boundary), so engine code needs zero changes. - Atomic multi-budget acquisition without leaks is an implementation concern inside such a composite (acquire-all-or-release), invisible to the engine contract.
- The one surface that would have blocked this — per-call weight needing
to reach the limiter from
parallel_map— already has a home: a futurerate_weight=per-call option or a weight callable, both additive keywords under the existing presence-sentinel rules.
Therefore: the Limiter protocol freezes as-is at 1.0; weighted /
composite lands additively in 1.1 if demand materializes.
Spike 2 — Streaming checkpoint (deferred, contract required first)¶
Question: why doesn't parallel_iter take checkpoint=?
Conclusion: deferred until an at-least-once contract can be stated crisply — shipping it sooner would undermine the reliability positioning. The core problem:
- In collected maps, "row committed to SQLite" and "result delivered to the caller" happen inside one call — the checkpoint's claim ("this item is done") is unambiguous.
- In streaming, the caller consumes results as a side effect (writing to a sink). A resumed stream must choose: skip checkpointed items (then a sink that crashed after compute but before its own write loses data silently) or re-yield them (then every consumer must be idempotent — at-least-once delivery).
- "Cached computation" ≠ "sink committed." Any honest design must make
the consumer's idempotency obligation explicit — e.g.
parallel_iter(..., checkpoint=..., replay="none" | "cached")with documentation thatreplay="none"trusts the sink andreplay="cached"requires idempotent writes.
Required before implementation (1.1 at the earliest): the replay
semantics above, a decision on whether cached re-yields carry
attempts=0 metadata (consistent with item_results()), and tests
proving no delivery state is claimed that the engine cannot know.
Until then the documented guidance stands: streaming resume is the
sink's job (skip rows whose output already exists), or use
parallel_map with checkpoint= over a bounded window_size.