Skip to content

chore(quota-history): persist the clock repair, and strengthen two fixtures #207

Description

@Nanako0129

Deferred from #206, which repairs a clock-led quota-pace history store in memory rather than quarantining it.

The repaired store does not always reach disk

before is cloned from the already-repaired store, so the transaction's save-if-changed check sees no difference when the body is a no-op or rejects a stale observation. The read path (read_series_at_path_with_mode) never saves at all, by design — quota_curve_read_path_never_reaches_atomic_save (lib.rs:1476) asserts it.

Consequences, neither a correctness defect in shipped behaviour:

Repair re-runs on every load Harmless — it is a proven fixed point, and a current reader always sees a correct store
The file never self-heals for a provider that stops recording A logged-out provider's series keeps its future-dated bytes indefinitely
A downgraded build still quarantines Persisting eagerly would make the on-disk store safe for an older reader

Not fixed in #206 because both halves of the obvious remedy overreach. Making the read path save would break the asserted invariant above and put a write lock on every quota-curve read. Adding a repaired/dirty flag to the transaction path reintroduces the typed load disposition and forced write-back that #206's design evaluated and rejected, and would need its own verification round rather than riding along.

Worth doing as its own change if the self-heal or downgrade property matters.

Fixture strength

Two behaviours in #206 are pinned more weakly than the code allows:

  • the last_activity_at > upper_bound gate is pinned by a direct call to repair_store_at, not through the loader;
  • the cycle-boundary exclusion from rollover detection needs a compound mutation to fail.

Both are production-reachable through load_store_at_with_mode in a multi-series store — one series leading the ceiling while a sibling sits in the healthy band — and end-to-end fixtures dying on a single mutation were available. They were not written because adding them after outcome verification would have invalidated its coverage of those bytes.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions