The Recovea Score
This page explains the 0-100 Recovea Score in the right rail of the Unit economics page, served by GET /platform/v1/roi/score on Growth and above. No workspace has a score today.
What it is
The Score is an in-product spend hygiene index for one workspace, 0-100, higher is healthier. It is the plain integer average of a set of named factors, each itself 0-100. It is not a rating of a model, a provider, or a vendor, and it is not a public badge. No badge surface exists in phase 0. Every response carries beta: true and a link to this page.
How it is computed
The Score carries no money. Its inputs are factor integers from the scoring engine. No float touches any path here.
- Factors. The ROI store returns an ordered list of
{ name, score }.nameis an opaque label.scoreis an integer, documented range 0-100. - Absent is null. No factor list, or an empty one, returns
score: nullwithfactors: []. We never substitute a zero, a default, or an average over a partial set. - Headline. With
sumthe factor total andcounttheir number,headline = (sum + count / 2) / count. Both divisions truncate toward zero, socount / 2floors before it is added. For an even count this is round-half-up. For an odd count an exact half cannot occur, so the rule is round-half-up in every case. - Payload. The headline is
score, factors return verbatim in engine order,betaistrue, andmethodologycomes from one link registry, structurally tested to resolve to a publicrecovea.ai/researchpage. - Gate. Below Growth the endpoint returns the plan fence carrying real captured measured spend, not a score. Reading requires the
ReadObservabilitycapability.
Worked example, the vector pinned by our test suite:
| Factor | Score |
|---|---|
| attribution coverage | 71 |
| cache discipline | 58 |
| route concentration | 63 |
sum = 192, count = 3, count / 2 = 1, (192 + 1) / 3 = 193 / 3 = 64 after truncation. The rail would render 64/100. Those three names are test fixtures, not a shipped factor set. No factor definition exists in the codebase.
Money elsewhere in the product is integer micro-USD at 1,000,000 to the dollar. Receipts and ledger rows chain under recovea-chain-v1, the only recipe production writes: SHA-256 over canonical field strings joined with U+001F, lowercase hex. A second recipe, recovea-receipt-v1, is published with golden vectors, but nothing in the API writes it.
What it does not include
- Output quality. Nothing here inspects a completion.
- Provider invoices, credits, discounts, committed-use terms, taxes, or your Recovea subscription.
- Prompts, completions, header values, raw paths.
- Traffic that did not pass through the Recovea gateway.
- Any verified figure.
Basishas noVerifiedvariant in phase 0. - Any cohort, percentile, or benchmark against other workspaces.
Limits and current status
- The engine is not shipped.
SqlxRoiStore::score_factorshard-returnsOk(None). There is no score table, no score column, and no scoring job in any migration. Every Growth workspace receivesscore: nullandfactors: [], and the rail renders-/100. No workspace has ever had a score. - The factor range is documented, not enforced.
scoreis au8with no clamp, and the headline is not clamped either. A factor above 100 would pass through and overflow the UI bar. Nothing can produce one today, because nothing produces factors at all. - Budgets. Only workspace-scoped caps reach the gateway. The cap snapshot message is workspace-scoped by construction, and the snapshot query filters
scope_kind = 'workspace'. Key- and project-scoped budgets can be created and stored, but nothing enforces them in path yet. - Alerts. The sweep clock is
rate(1 minute), so a fast burst can cross a threshold and reach a cap between checks. Alerts warn on the way up. They are not an ordering guarantee. - Counterfactual. Savings are measured with
appliedhard-false. An absent lever row means off, and no lever is activated in any deployed environment, so the realized model always equals the baseline. - CPSO. Figures are at list price. The
live/settledbadge is a calendar comparison only: a row readssettledthe moment the month ends, whether or not anything reconciled. Invoice reconciliation at period close is planned, not wired. - Spend and attribution layer drift. The same money is read from different tables depending on caller. Workspace-scope budget spend sums
rollup_daily, key-scope budget spend sumsreceipts, and project scope returnsNone, so a project budget is skipped rather than assumed zero. CPSO and route spend readreceipts; attribution cuts readrollup_cutsandrollup_tag_cuts. The rollups are written inside the ingest transaction, so they should agree, but nothing continuously proves it, and the CPSO query ignores thecost_statecolumn. The request feed'senvis hardcoded tolive, becausereceiptshas no environment column.
Where to check us
- Call the endpoint. On a Growth workspace it returns
score: null,factors: [],beta: true. That is the whole truth today. A non-null score without a matching update to this page is our bug. - Re-derive the headline when factors ship. Sum
factors[].score, addfloor(count / 2), divide bycountwith integer truncation. It must equalscoreexactly. - Re-derive the money underneath. Export with the key-authed
GET /v1/ledger/export?period=YYYY-MM&format=csv. Rows carryrecipe,previous_hash,row_hash,cost_micro_usd,price_list_version, and token counts. Re-price each row from its tokens and pinned price version, then re-derive eachrow_hashwith SHA-256 and confirm the links. A published price version never changes, and verification never calls home. The session routeGET /platform/v1/ledger/exportserves the same rows in camelCase; the field map for both is on the ledger page.