Raised in review of #49 (P2, "Preserve historical capability definitions").
/api/v1/status/history passes the currently resolved capability specs into a query that spans the whole requested window, so changing a pool retroactively reinterprets every older sample.
Concretely: today ai_providers is {deepinfra, openrouter, groq} with min_available: 1. Add a fourth required member, or raise the threshold to 2, and days recorded before that member was ever measured are recomputed against the new definition — a day that was genuinely 100% available can be republished as 0%, because the samples for the new member do not exist.
That is the same class of defect as the ones this PR fixes: a number changing meaning under a reader who has no way to see that it did.
What it should do
The SLI for a past day should describe the call path that existed when those samples were collected. Options, roughly in order of cost:
- Persist the effective definition. A
capability_defs(id, members, min_available, effective_from) table written whenever the resolved spec differs from the current row; the rollup then selects the definition in force at each sample's timestamp. Config stays the source of truth for now; history keeps its own record of then.
- Version the spec.
status.capability.<id>.version authored by the owner, stored alongside each sample; the rollup groups by version and refuses to mix.
- Freeze on write. Store the capability id + member set on each
status_checks row. Simplest to reason about, worst on space (~21k rows/day already).
(1) is the natural fit for how the rest of this node works — the definition is CEG config, so its history is exactly the kind of thing the corpus is for.
Until then
Capability SLIs are only trustworthy back to the last change of a pool definition. Nothing currently records when that was, which is itself part of the problem.
Related: FSD/CAPABILITY_MONITORING.md §2.4, and #47 (probe once, project twice) which touches the same rollup path.
Raised in review of #49 (P2, "Preserve historical capability definitions").
/api/v1/status/historypasses the currently resolved capability specs into a query that spans the whole requested window, so changing a pool retroactively reinterprets every older sample.Concretely: today
ai_providersis{deepinfra, openrouter, groq}withmin_available: 1. Add a fourth required member, or raise the threshold to 2, and days recorded before that member was ever measured are recomputed against the new definition — a day that was genuinely 100% available can be republished as 0%, because the samples for the new member do not exist.That is the same class of defect as the ones this PR fixes: a number changing meaning under a reader who has no way to see that it did.
What it should do
The SLI for a past day should describe the call path that existed when those samples were collected. Options, roughly in order of cost:
capability_defs(id, members, min_available, effective_from)table written whenever the resolved spec differs from the current row; the rollup then selects the definition in force at each sample's timestamp. Config stays the source of truth for now; history keeps its own record of then.status.capability.<id>.versionauthored by the owner, stored alongside each sample; the rollup groups by version and refuses to mix.status_checksrow. Simplest to reason about, worst on space (~21k rows/day already).(1) is the natural fit for how the rest of this node works — the definition is CEG config, so its history is exactly the kind of thing the corpus is for.
Until then
Capability SLIs are only trustworthy back to the last change of a pool definition. Nothing currently records when that was, which is itself part of the problem.
Related:
FSD/CAPABILITY_MONITORING.md§2.4, and #47 (probe once, project twice) which touches the same rollup path.