Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,15 @@ jobs:
- name: Storybook plugins shim conformance (0283)
run: pnpm check:storybook-shim

# Public durability copy may only state a figure the plan catalog backs.
# The pricing page shipped "99.9% best-effort availability" over a tier
# whose SlaLevel resolved to no objective at all — a promise the code
# declined to hold, invisible because `site/` cannot import @xnetjs/*.
# This regenerates the mirror and fails on drift or an unbacked claim.
# (Exploration 0425.)
- name: Durability claims match the plan catalog (0425)
run: pnpm check:durability-claims

# Workflow files themselves: an unparseable workflow made GitHub emit a
# phantom failed run on EVERY push for weeks (exploration 0283). Severity
# floor `warning` keeps shellcheck's style/info pedantry out of the gate.
Expand Down
8 changes: 6 additions & 2 deletions apps/cloud/src/observability/observability.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ describe('SLI math', () => {

describe('SLO catalog + budget policy', () => {
it('maps SLA levels to objectives', () => {
expect(sloForSla('99.5').objective).toBe(0.995)
expect(sloForSla('99.9').objective).toBe(0.999)
expect(sloForSla('custom').objective).toBe(0.9995)
expect(sloForSla('best-effort').objective).toBeNull()
Expand All @@ -69,8 +70,11 @@ describe('SLO catalog + budget policy', () => {
it('derives the SLO from the plan tier', () => {
expect(sloForPlan('community').objective).toBe(0.999) // dedicated-project, 99.9
expect(sloForPlan('company').objective).toBe(0.999)
expect(sloForPlan('team').objective).toBeNull() // best-effort
expect(sloForPlan('personal').objective).toBeNull() // best-effort
// `team` moved best-effort → 99.5 in 0425: the pricing page was publishing
// "99.9% best-effort", a figure no objective backed. It now publishes 99.5%
// and the SLO layer holds us to it.
expect(sloForPlan('team').objective).toBe(0.995)
expect(sloForPlan('personal').objective).toBeNull() // best-effort, published as no figure
expect(sloForPlan('enterprise').objective).toBe(0.9995)
})

Expand Down
51 changes: 11 additions & 40 deletions apps/cloud/src/observability/slo.ts
Original file line number Diff line number Diff line change
@@ -1,48 +1,19 @@
/**
* xNet Cloud — Service Level Objectives + error-budget policy (exploration 0193).
*
* Ties the plan catalog's declared `SlaLevel` to a concrete, measurable SLO and
* the Google-SRE error-budget policy that gates fleet upgrades: a healthy budget
* ships fast, a low budget slows down, an exhausted budget freezes risky deploys
* (security/reliability fixes are always exempt — enforced at the call site).
* The SLA-level → objective mapping moved to `@xnetjs/entitlements` (exploration
* 0425) so the *promise* and the *objective it is measured against* can be
* asserted against each other in one place; it is re-exported here so every
* existing call site keeps working.
*
* What stays here is the Google-SRE error-budget policy that gates fleet
* upgrades: a healthy budget ships fast, a low budget slows down, an exhausted
* budget freezes risky deploys (security/reliability fixes are always exempt —
* enforced at the call site). That is an operational choice about how *we*
* deploy, not part of the entitlement contract a self-hosted hub reads.
*/

import { PLAN_CATALOG, type PlanId, type SlaLevel } from '@xnetjs/entitlements'

export interface SloTarget {
/** Availability objective as a fraction (e.g. 0.999). `null` = no published SLO. */
objective: number | null
/** Rolling window the objective is measured over. */
windowDays: number
/** Human label for dashboards/status. */
label: string
}

/** Map a plan's declared SLA level to a measurable SLO. */
export function sloForSla(sla: SlaLevel): SloTarget {
switch (sla) {
case '99.9':
return { objective: 0.999, windowDays: 30, label: '99.9% uptime' }
case 'custom':
return { objective: 0.9995, windowDays: 30, label: '99.95% uptime (enterprise)' }
case 'best-effort':
return { objective: null, windowDays: 30, label: 'best-effort' }
case 'none':
default:
return { objective: null, windowDays: 30, label: 'no SLA' }
}
}

/** The SLO for a plan tier. */
export function sloForPlan(plan: PlanId): SloTarget {
return sloForSla(PLAN_CATALOG[plan].sla)
}

/** Allowed downtime over the window, in ms (the error budget as time). ∞ if no SLO. */
export function errorBudgetMs(slo: SloTarget): number {
if (slo.objective === null) return Number.POSITIVE_INFINITY
return (1 - slo.objective) * slo.windowDays * 24 * 60 * 60 * 1000
}
export { sloForSla, sloForPlan, errorBudgetMs, type SloTarget } from '@xnetjs/entitlements'

/**
* Error-budget policy state from the remaining fraction (0..1):
Expand Down
Loading
Loading