Operator console Phase 0: warm SLO tiers, durable SLIs, named operators, honest copy - #692
Conversation
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Signed-off-by: xNet Test <test@xnet.dev>
Reuse React + Tailwind + @xnetjs/ui (zero @xnetjs/* deps) instead of hand-rolled HTML, and keep the operational record on xNet itself so the signed change log becomes the audit trail. Split: xNet for the record, REST for the readings — metrics stay off the change log (0323). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Signed-off-by: xNet Test <test@xnet.dev>
… ADR-31/32 Sixteen decisions settled by interview; 0431 stays as the research with a forward pointer. Adds two findings 0431 did not have: the tiers selling a 99.9% SLO are provisioned scale-to-zero (minInstances keys off the isolation tier, not the SLA), and four user-facing surfaces claim we cannot read data the hub indexes for FTS. Both ship before the console. ADR-31 records the ops-hub dependency, ADR-32 the support consent model, each with a tripwire. Site build verified locally since CI does not build site/ on PRs. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Signed-off-by: xNet Test <test@xnet.dev>
…lation tier The warm-instance rule keyed off isolation === 'dedicated-warm', which is the team plan — best-effort, so it can never burn an error budget. The three plans that DO publish an objective (community, company at 99.9%, enterprise at 99.95%) all provisioned scale-to-zero, and region-pinned was not handled at all. A cold start can spend a large fraction of a 43-minute monthly budget. availabilityObjective/requiresWarmInstance live in @xnetjs/entitlements beside PLAN_CATALOG so the provisioner and the control plane's SLO math read one mapping; slo.ts now delegates to it instead of a second switch. Exploration 0433 D1. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Signed-off-by: xNet Test <test@xnet.dev>
Modelling the cost delta caught a regression in the D1 fix: an objective-only rule would have dropped team (dedicated-warm but best-effort) to scale-to-zero. PLAN_PRICING models team with warm: true, so the price already covers that COGS and removing it would be a silent downgrade of a paying tier. Warmth is now a floor from both reasons. Cost delta recorded in 0433: ~$6/mo per SLO tenant, already assumed by the price list. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Signed-off-by: xNet Test <test@xnet.dev>
Five user-facing surfaces claimed xNet Cloud holds only encrypted bytes, or that the hub never sees plaintext. search-indexer.ts extracts plaintext from rich text to build the FTS index, and 0343 records that the trusted tier gives integrity but not confidentiality. The repo already holds this standard elsewhere — HonestyBox.astro and HonestMachine.astro explicitly refuse to overclaim E2EE — the cloud surface had drifted from it. Two of the five (an 'end-to-end encrypted workspace' claim and a second 'never sees plaintext') were found during implementation, not in the audit. privacy.astro is unchanged: 'we cannot read your data with it' scopes to the billing identity and is accurate. Exploration 0433 D2. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Signed-off-by: xNet Test <test@xnet.dev>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Signed-off-by: xNet Test <test@xnet.dev>
The in-memory ring held 2000 samples at a 60s probe interval — 33 hours of a window labelled 30 days — and died with the process, so every deploy handed the error budget back at 100%. rollout/engine.ts gates fleet upgrades on that budget, so a restart silently unfroze deploys. Buckets are one document per tenant per hour over the existing DocStore port: ~43 KB per tenant per 30 days, rolled to daily at 30 days and pruned at 13 months. windowState() distinguishes stale (measurement broken -> freeze) from young (new tenant -> excluded), so the gate can go red for the right reason without freezing on every signup. The probe now waits 30s instead of 5s and records a slow success as a cold start rather than an outage — sli.ts always documented that intent. The 30s is a placeholder: no cold-start figure exists in the repo (0433 open question 1), and the constant says so. Exploration 0433 Phase 0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Signed-off-by: xNet Test <test@xnet.dev>
publicStatus hardcoded control-plane: operational, which said only that the process answered THIS request, and reported an unmeasured hub fleet as operational. Both are the same defect as an empty sample window reading 100% available. Adds an unmeasured ComponentStatus ranked above operational but below degraded — it can displace a green banner without paging anyone over a missing probe. The control plane now reports from leased-job staleness; unwired job reporting renders unmeasured, never green. Also replaces === on the internal shared secret with a constant-time compare. Exploration 0433 decisions 10 and 11. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Signed-off-by: xNet Test <test@xnet.dev>
The shared secret named nobody, and /internal/account/recover clears a tenant's bound DID so the next device claims their hub — a fleet-wide takeover primitive with no attributable trace. Mutating internal routes now require an operator identity plus a typed reason and reject the shared secret outright; the three read routes keep it, so cloud-company-metrics.mjs is unchanged. audited() writes the durable entry BEFORE the action runs, so an action that fails is still attributable and cannot be suppressed by crashing. Tier 2 (signed node on the ops hub) publishes async and queues when unreachable; pendingCount() is the alertable gap. Operator identity splits authorisation (WorkOS role claim) from attribution (DID binding), and retired bindings stay resolvable so 12-month audit history outlives the key that signed it. Exploration 0433 decisions 4, 5 and 11; ADR-31. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Signed-off-by: xNet Test <test@xnet.dev>
…ble gate Adds the ops-hub publisher (audit entries become nodes signed by the operator DID, readable back through the hub's existing /audit/authors/:did/changes), a 12-hour operator session cookie kept distinct from the 7-day tenant one, and the WorkOS role claim reader. The gate negative control (0430's rule) plants five violations fleetGate MUST flag plus three it must NOT, and joins the existing check:gate-controls aggregate. Verified it goes red: removing the stale check from fleetGate fails the control, restoring it passes. Privacy policy now states what support can see, that content needs per-incident consent, and that the signed access log is kept 12 months and survives account deletion — so look-then-delete cannot erase its own evidence. siteMetrics.tests bumped 9600 -> 12000; the repo's real count (12050) had drifted and these tests pushed it past the 25% staleness gate. Exploration 0433 Phase 0; ADR-31, ADR-32. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Signed-off-by: xNet Test <test@xnet.dev>
Solves the bootstrap: the console requires a named operator, but there is no console through which to name the first one. Writes the binding directly and refuses when no GCP project is configured rather than seeding an in-memory store that vanishes on exit. --retire never deletes, so 12-month audit history keeps a resolvable key. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Signed-off-by: xNet Test <test@xnet.dev>
Decision 15's whole point: if the record vanished with the account, an operator could read someone's data and erase the evidence by deleting them. Also pins the entry shape so no field can carry tenant content. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Signed-off-by: xNet Test <test@xnet.dev>
…lan (12/20) Ship-first defects and all of Phase 0 landed. Phases 1-3 deferred: the ops hub is an operator action that does not exist yet, and Docker is unavailable so the plan's own flagged risk (workspace devDep in the image closure) cannot be discharged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Signed-off-by: xNet Test <test@xnet.dev>
…iality copy Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Signed-off-by: xNet Test <test@xnet.dev>
|
Warning Review limit reached
Next review available in: 21 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (38)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Preview removed for PR #692. |
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Signed-off-by: xNet Test <test@xnet.dev>
Signed-off-by: xNet Test <test@xnet.dev>
Implements exploration 0433 — the ship-first defects and all of Phase 0. The console itself (Phases 1–3) is deliberately deferred; see below.
The plan and its research (0431) are in this PR too, along with ADR-31 and ADR-32.
Two defects that shipped first
D1 — the tiers that sell an SLO were provisioned scale-to-zero.
minInstanceskeyed offisolation === 'dedicated-warm', which isteam— best-effort, so it can never burn an error budget. The three plans that do publish an objective (community,companyat 99.9%,enterpriseat 99.95%) all scaled to zero, andregion-pinnedfell through to0. A cold start can spend a large fraction of a 43-minute monthly budget.Warmth is now a floor built from both the published objective and the isolation tier. Modelling the cost caught a regression in the first attempt: an objective-only rule would have dropped
teamto scale-to-zero, andPLAN_PRICINGmodels itwarm: true. Cost delta is ~$6/mo per SLO tenant, already assumed by the price list.D2 — five surfaces claimed we cannot read data the hub indexes.
search-indexer.tsextracts plaintext to build the FTS index, and 0343 records that the trusted tier gives integrity but not confidentiality. The repo already holds this standard —HonestyBox.astroandHonestMachine.astroexplicitly refuse to overclaim E2EE — the cloud surface had drifted from it. Two of the five were found during implementation, not in the audit.privacy.astrois unchanged: "we cannot read your data with it" scopes to the billing identity and is accurate.Phase 0
rollout/engine.tsgates fleet upgrades on that budget, so a restart silently unfroze deploys. Now one document per tenant per hour, rolled to daily at 30 days, pruned at 13 months.windowStatedistinguishes stale from young. Stale (measurement broken) freezes; young (new tenant) is excluded. A gate that froze on every signup would get switched off.unmeasuredstatus.publicStatushardcodedcontrol-plane: operational— tautological, it said only that the process answered this request. The control plane now reports from leased-job staleness.cloud-company-metrics.mjsis unchanged.audited()writes the durable entry before the action runs. Tier 2 publishes signed nodes to the ops hub and queues visibly when unreachable.check:sli-gate --selftestplants five violationsfleetGateMUST flag plus three it must not, and joins the existingcheck:gate-controls. Verified it goes red: removing the stale check fails the control, restoring it passes.What is NOT here
Phases 1–3 (the React console, support view, consent flow). Two reasons, neither of them time:
operatorrole, seed script against real credentials. Every dependent path is built and unit-tested against its port, but nothing has talked to a real one.0433 is marked
[-]at 34/52 implementation, 12/20 validation.Verification
pnpm test— 12,249 passed, 1 skippedpnpm typecheck— cleanpnpm lint— clean for changed files (one pre-existing warning insync-gate.test.ts, untouched)pnpm check:gate-controls— passes, and demonstrably fails when the gate is brokensitebuilds; both ADRs render;validate:compare,validate:dist,validate:metricspasscheck:exploration-links/-fallow/visual-explorations— passsiteMetrics.testsbumped 9600 → 12000: the repo's real count had drifted and these tests pushed it past the 25% staleness gate.🤖 Generated with Claude Code