deterministic screens — TypeScript, not prompts
columns read — and nothing else
LLMs in the decision path
screens ship agent-executable steps
Run it twice, diff the output
$ bayeto run --objective cost.json
$ bayeto run --objective cost.json
$ diff run-1/decisions.json run-2/decisions.json
∅ — byte-identicalHeld, not sold
Any move with an unmeasured quality risk on a critical surface is held and shown with its reason — never offered as a win, at any price. Every held move is visible in the public demo, reason attached.
The full method, section by section
A deterministic decision path — no language model in it
The path from your telemetry to a recommendation is Telemetry → Architecture Graph → Objective → Rules → Recommendation, and it contains no language model at any step. The same telemetry under the same objective produces byte-identical recommendations, every run — our CI pins the serialized decision output of the reference datasets by hash, so an unintended change to any decision is a failed build, not a surprise. Language models are used for exactly one thing: phrasing the explanation of a decision the engine already made. The phrased narrative is stored as a visibly separate section of the decision record; it can be regenerated without changing a single number.
Reasoning in layers you can inspect
Every recommendation decomposes into four independently inspectable layers: Observations (facts measured from your telemetry, each with its sample size) → Evidence (observations that bear on your objective, each with a strength) → Inference (the judgment drawn, clearly separated from the facts) → Recommendation (the move, with its projected impact). A fact is never presented as a judgment, and each recommendation also carries its own critical review: the assumptions it rests on, alternative explanations, the evidence that is missing, and the concrete conditions under which it would be wrong.
Objectives first, and “why not?” answered
The objective is the root object: recommendations answer “given THIS objective, what is the next best move?” — maximize business value subject to latency, quality, compliance, budget, and privacy constraints. Different objectives over the same telemetry yield different recommendations. Alternatives the engine rejected are listed with the reason (dominated on cost, quality risk past your floor, not Pareto-optimal), so “why not X?” always has an explicit answer.
Derived confidence — never a vibe
Confidence is computed from sample size, effect size, and Optimization Memory (measured outcomes of prior implementations) — never hand-assigned. It is shown next to context completeness, which is a different question: confidence is how sure the engine is on the evidence it has; completeness is how much of the evidence that could change the conclusion is present at all. Risky moves on surfaces you declared critical (or never declared — undeclared is treated as critical) are held and shown with their reason, never sold as wins.
How value is counted — four terms, never conflated
Every € figure in Bayeto belongs to exactly one of four categories, and the UI names which: Bayeto-validated captured value (a hypothesis that passed the measured loop — implemented, observed ≥7 active days and ≥100 calls, prediction graded against measured per-call cost); observed external optimization (a change you already made without Bayeto, detected and measured from telemetry — it counts toward “value captured”, never toward “validated”); measured-window cost delta (the raw difference across the observation window); and annualized run-rate estimate (a windowed figure scaled to a year — always labeled as annualized).
Bayeto never ingests your provider invoices, and no figure here is reconciled against invoice line items. Every € is measured in your own telemetry and priced by a pinned rate catalog. The strongest claim we make is the first category above: telemetry-measured, graded against a prediction recorded before the change was made.
“Calibrated” is a different thing again — an input, never a verification. If you declare your monthly provider spend (one figure, entered by you), telemetry-priced costs are scaled so the totals match it, and that scaling is inherited by every € on the page and printed beside them. Declaring it is optional; without it figures stay on the raw telemetry basis. A declared figure changes the cost basis of a measurement. It never turns a measurement into a verification.
Simulation — a scenario assumption, published
The Simulate card projects a move’s effect on your observed traffic mix as a deterministic reprice — and applies a scenario realization assumption (sim-v1): realization = 0.7 + 0.3 × confidence, shown with downside, base, and upside separately. This is deliberately not a statistical expected value. The 0.7 floor encodes implementation shortfall: in practice even a certain, fully-evidenced move rarely captures 100% of its base saving at rollout — traffic drifts, adoption is partial, edge cases get excluded — so the projection floors at 70% of base rather than pretending precision below it. The formula, its inputs, and its version are printed on the card and in the decision record; when the measured loop has accumulated enough outcomes, sim-v2 will replace the assumption with a fitted distribution.
Pinned pricing catalogs with provenance
Every € figure is priced against a dated, immutable catalog snapshot — never a live scrape. Each snapshot records where every rate came from and is append-only: recomputing an old analysis uses the exact catalog it was produced with. When a model cannot be priced from the pinned catalog, the engine declines to recommend (you see “not enough pricing data”) rather than inventing a figure. The current snapshot is public at bayeto.ai/catalog.
One ledger, every surface reconciles
Every count and € total on every page derives from one canonical opportunity ledger — a disjoint, exhaustive partition of the engine’s recommendations (leads, historical, alternatives, held, rejected, validated). The briefing, the recommendations list, the executive summary, and the exports all quote the same ledger. Surfaces can still present different views of one move — a provider-bill saving, or one that also prices time saved — so the same move can appear as a different figure on different pages. Each surface also shows the ledger’s version — a deterministic fingerprint of the partition — and the same hash appears in the CSV header, the decision record, and the engine’s manifest. If a number cannot be reconciled to engine output, it does not ship.
What that fingerprint covers, and what it does not. The version is a hash of the ledger partition, so it detects any disagreement between surfaces that read the ledger. It says nothing about a surface derived some other way — the pilot report is built from your implementation marks and your telemetry, not from the ledger, and quotes no ledger version. That surface is held by a separate assertion instead: a move whose measured verdict is in and attributable cannot sit in an open lane, and cannot carry a decision record saying the engine has no prior implementations for it. Where a verdict exists but its window is contaminated, the two deliberately diverge and both say so.
Ledger version format v2. v1 ledger hashes remain valid for the data they were issued against; a v1/v2 mismatch indicates a format-version change, not a change in figures. The format changed when the ledger gained cohort freshness, so that two workspaces differing only in whether an application has stopped reporting can no longer fingerprint identically.
Applications that stop reporting
Value is only counted where the work is still happening. Each application cohort carries when it was first and last seen, how many days it was active, and a lifecycle state derived from those facts — judged against the end of your telemetry window, never against the clock, so a stored decision reproduces identically a year later.
A cohort quiet for a week is marked declining and still counts — a holiday shutdown is not a dead service. A cohort silent for two weeks or more is marked stale and stops contributing to identified value, to “still on the table”, and to anything shown as pursuable. It stays visible as historical evidence, with the excluded amount stated, because a figure that silently disappears is worse than one that is explained. A cohort too new to project from is marked provisional and still counts: a young service is not a dead one.
The same exclusion applies to the spend a fee could ever be quoted on. Your monitored spend is everything observed — it is what reconciles against your provider invoice. The fee basis is the narrower figure covering active cohorts only, and the difference between them is itemised rather than absorbed. An annual run-rate is a projection, and projecting forward from an application that no longer exists would quote a fee against spend that will never recur.
The measured loop — the engine grades itself
When you implement a recommendation and mark it, Bayeto observes the incoming telemetry and, after at least 7 active days and 100 calls, grades its own prediction against the measured per-call cost. The baseline is the 30 calendar days before your implementation date — a fixed window, so an older regime cannot contaminate the comparison. Because that window lies in the past, a thin baseline is cured by uploading history (backfill), never by waiting — the product says so wherever it applies. The result — including a miss — is shown, and it feeds Optimization Memory, adjusting the confidence of future recommendations of the same kind. Prediction accuracy is a first-class, visible metric, and every yearly figure names the window it was extrapolated from.
How long before you see something
With an export, initial analysis is immediate. Upload it and the briefing is there — applications, models, providers and the ranked recommendations, from whatever window the file covers. Below 7 active days the annualized figures are marked provisional, because scaling a short window to a year is an estimate and is labeled as one. The recommendations themselves are not withheld while you wait.
With a live connection, the connection itself is verified in minutes — and recommendations are not held back while volume builds; the engine judges from the first calls it can reason over. Only the annualized € figures wait: they are stated once there are 200 calls across 3 active days behind them, and stay marked provisional under 7 active days.
Validating a saving takes longer, and must. Declaring value verified — the only state that can ever carry a fee — requires 7 active days and 100 eligible calls after the change, compared against the 30 days of your telemetry immediately before the implementation date you declared. That is a minimum evidence floor, not a sufficiency test: where seasonality or sample adequacy demands longer, Bayeto names the outstanding condition rather than declaring a result early.
That baseline is recomputed, not stored: it is derived from your telemetry each time the result is read, anchored on the implementation date you declared. Changing that date moves the window the comparison is made over.
Bayeto does not verify quality. A recommendation whose quality impact is unmeasured is withheld on any surface you have declared critical, and what was withheld is disclosed to you with the reason. Quality is a constraint on what Bayeto will offer you, never a check Bayeto claims to have run.
Reproducibility you can take with you
Every recommendation exports a canonical decision record (JSON): the deterministic decision block, the run context (engine and catalog versions, fixed FX rates, formula versions), and the LLM-phrased narrative as a separate, clearly labeled section. An auditor can re-run the engine on the same inputs and diff the output byte-for-byte. This is demonstrable right now, no account needed: open any recommendation in the public Thornbury demo and use “Download the canonical decision record (JSON)” — the file carries the measured-window boundaries, the exact pricing rows and catalog version, the fixed FX rates with their effective date, the simulation’s inputs and intermediates, the mutual-exclusivity group, and the ledger version shown on every page.
Since format v3 the record also carries a decisionHash — a SHA-256 over the deterministic decision block, canonicalized with RFC 8785 (JCS) and domain-separated as bayeto:decision:v3. We publish a standard rather than our own canonical form for one reason: you can recompute it with a JCS library you already trust, instead of reimplementing ours. The procedure is the whole of it — canonicalize the decision block, then hash domain || 0x00 || canonical.
v3 is additive. Records you already hold at v2 remain valid and remain re-derivable: no v2 field changed meaning, moved, or was removed. This page says so because the record is published without an account, so v2 files are already in the wild and cannot be recalled — a version bump that quietly invalidated them would break exactly the promise the record exists to make.
What Bayeto does not do
No recommendation content is ever seeded, templated from marketing copy, or hand-written: change the telemetry and the recommendations change — a property covered by tests. There is no “AI advisor” free-associating over your data. Prompt content is never read or stored (only usage metadata — the exact field list is in the security overview), and uploads are parsed in your browser so non-schema columns never leave your machine.