ADR-006: Flat Schema for Usage Snapshots¶
Status: Accepted Date: 2026-01-11 (initial), 2026-01-16 (confirmed) PRs: #20, #172 Issue: #168 Milestone: v0.1.0, v0.4.0
Context¶
Usage snapshots aggregate consumption data (tpm, rpm, total_events) per entity/resource/time window. The Lambda aggregator uses UpdateItem with ADD for atomic counter increments. Initial implementation used nested data.M maps like other record types.
DynamoDB limitation discovered: You cannot SET a map path (#data = if_not_exists(#data, :map)) AND ADD to paths within it (#data.counter) in the same UpdateExpression. It fails with "overlapping document paths" error.
Decision¶
Use flat schema (top-level attributes) for usage snapshot records, diverging from the nested data.M pattern used elsewhere.
Snapshot structure:
{
"PK": "ENTITY#user-1",
"SK": "#USAGE#gpt-4#2024-01-01T14:00:00Z",
"resource": "gpt-4", # Top-level
"window": "hourly", # Top-level
"tpm": 5000, # Counter at top-level
"total_events": 10, # Counter at top-level
}
Consequences¶
Positive: - Atomic upsert with ADD counters works correctly - Single UpdateItem call creates or updates record - No pre-existence check required
Negative:
- Schema inconsistency with other record types (entities, buckets use nested data.M)
- Established pattern for v0.6.0 full schema flattening (see #180)
Alternatives Considered¶
- Two-step create-then-update: Rejected; race conditions, higher latency, more RCU/WCU
- Conditional expressions with retries: Rejected; complex error handling, still potential races
- Store in separate table: Rejected; loses single-table benefits, complicates transactions