Skip to content

fix(api,domain): idempotency/records/docs cleanup (#100, #105, #106, #107)#118

Merged
JumpTechCode merged 1 commit into
mainfrom
fix/idempotency-records-docs-cleanup
Jul 20, 2026
Merged

fix(api,domain): idempotency/records/docs cleanup (#100, #105, #106, #107)#118
JumpTechCode merged 1 commit into
mainfrom
fix/idempotency-records-docs-cleanup

Conversation

@JumpTechCode

Copy link
Copy Markdown
Contributor

A cluster of localized correctness and doc fixes.

#100 — commit/cancel/extend advertise a 402 they can never return

Only reserve can raise InsufficientBudget (it's the sole admission gate); commit records overage rather than denying, cancel only releases, extend touches no balances. commit/cancel/extend now use the no-402 response set (the constant is renamed _NO_BUDGET_DENIAL_RESPONSES and shared with meter/grace), so SDKs generated from the OpenAPI schema stop carrying dead 402-handling branches.

#105 — IdempotencyClaim.response was only shallowly immutable

response was wrapped in a top-level MappingProxyType, leaving nested lists/dicts mutably aliased. It's now deep-frozen (nested mappings → MappingProxyType, sequences → tuple), so the immutability guarantee matches the Mapping[str, Any] type even for a nested cached response.

#106 — reserve_fingerprint omitted the "command" discriminator

commit/cancel/meter/grace all fold a "command" key so two command kinds can't collide under one key; reserve now folds "command": "reserve" too — defense-in-depth even though reserve's field set is already structurally disjoint.

#107 — remaining review nits

  • find_lines returns lines already sorted in the canonical lock order (lock_order_key then period_start, the same key ordered_lines uses), so deadlock-freedom is self-enforcing at the source rather than resting on every caller re-sorting.
  • Idempotency-Key is trimmed of surrounding whitespace (a blank key → 422), so "k" and " k " are the same cache entry. Case is intentionally left intact (an idempotency key is an opaque token; lowercasing could collide distinct keys).
  • store_response raises on rowcount != 1 (an invariant breach — it only ever runs after claim inserted the row in the same tx) instead of silently dropping the response.
  • idempotency_repo docstring corrected: composite (principal_id, key) primary key and ON CONFLICT (principal_id, key) (the old text predated per-principal scoping, Idempotency keys are globally namespaced; scope them per principal #71).

The worker-backoff-overflow, SdkConfig-validation, and read-route-bound items of #107 were fixed in earlier PRs (#110, #108, #111); this closes the rest.

Tests

Unit: only-reserve-advertises-402; Idempotency-Key trimmed / blank rejected; deep-immutability of a nested claim response; reserve fingerprint folds the command discriminator. Integration: find_lines returns canonical order (lines inserted out of order); store_response on an unclaimed key fails loud.

Local gate: ruff, mypy --strict, import-linter, full unit (497), full integration (182) — all green.

Closes #100, #105, #106, #107.

…107)

- #100: only reserve can raise InsufficientBudget (402); commit records overage,
  cancel releases, extend touches no balance. Give commit/cancel/extend the no-402
  response set (renamed _NO_BUDGET_DENIAL_RESPONSES, shared with meter/grace), so
  SDKs generated from the OpenAPI schema stop carrying dead 402 branches.
- #105: IdempotencyClaim.response is now deep-frozen (nested mappings ->
  MappingProxyType, sequences -> tuple) instead of a shallow top-level view, so a
  nested cached response can't be mutated through the proxy.
- #106: reserve_fingerprint folds "command": "reserve" like every other command,
  so two command kinds can never collide under one key (defense-in-depth).
- #107 (remaining nits): find_lines returns lines already in the canonical lock
  order so deadlock-freedom is self-enforcing at the source; the Idempotency-Key
  header is trimmed of surrounding whitespace (a blank key is rejected) so padded
  variants dedupe; store_response fails loud on a rowcount != 1 instead of
  silently dropping the response; and the idempotency_repo docstring is corrected
  to the composite (principal_id, key) primary key / ON CONFLICT.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BjJ4QScUKbrMzF1jujL5Bg
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

OpenAPI: commit/cancel/extend advertise a 402 response they can never return

1 participant