Status: The storage model for runs/events/receipts, and the learning-data policy (per-tenant default, cross-tenant aggregation, opt-out) — Developer preview (designed, not built). The PII pseudonymization pipeline in section 2 — Available today: implemented, tested code, not a promise.Scope: what the fabric stores and why, the pipeline that turns a captured production issue into a test case without carrying a customer’s identifying content forward, and the learning-data policy that governs what, if anything, crosses tenant boundaries. Sources:
docs/superpowers/specs/2026-07-30-maas-execution-fabric-design.md
(design spec) §§1, 2, 4, 6; src/lib/platform-corpus/normalize.ts.
What is stored
Three kinds of durable record:- Runs —
task_runs: the execution record behindPOST /v1/execute(or its internal equivalent), including leases, attempt counts, budgets, and a first-classwaiting_approvalstate. - Events —
task_run_events: an append-only log of what happened during a run, sequenced soGET /v1/runs/:id/eventscan resume from aLast-Event-IDwithout re-delivering or skipping anything. - Receipts — a per-run summary of what ran, the policy version applied,
approvals granted (referenced by digest), and cost. Full contents in
receipts-and-audit.md. The hash-chained evidence ledger behind receipts, and their PDF/SIEM export, is a named, not-yet-shipped build item (design spec §4, workstream S3).
Turning production issues into test cases without keeping customer content
src/lib/platform-corpus/normalize.ts is implemented, tested code — not a
design commitment. It sits alongside its own test suite
(normalize.test.ts, sanitizer-parity.test.ts, corpus-replay.test.ts,
equivalence.test.ts) in src/lib/platform-corpus/. It is the mechanism
that turns a captured event stream into a comparable, replayable fixture —
for the locked-behavior corpus and shadow-equivalence testing that back the
platform’s migration work — without carrying the original customer’s
identifying content forward into that fixture. Every normalized batch is
re-validated against the platform’s own event schema
(AiPlatformEventV1Schema) before use, so a bad substitution can’t silently
produce an invalid fixture.
Six pseudonymization categories
sanitizeText() runs six pattern-matched categories, in a fixed order
chosen so an earlier, narrower substitution can’t be re-caught by a later,
broader one:
Order matters: timestamps and IPs are scrubbed before hostnames so the
hostname pattern — the broadest of the six — never gets a chance to match a
timestamp’s tail or a raw IP literal; emails are scrubbed before hostnames so
a hostname embedded inside an email address is already gone by the time the
hostname pattern runs. Already-safe values (
localhost, *.example.test,
an email already ending @example.test) are recognized and left alone,
which also makes the function idempotent — running it twice on already-
sanitized output changes nothing further.
Substitution is stable within a single normalization run: a lookup table
plus per-category counters means the same original value always maps to the
same pseudonym for the batch of events being normalized together. A test
case built this way can still show “this is the same user across three
events” — the referential structure survives — without that identifier ever
being the real one.
Structural fields versus content
The normalizer treats position differently. At the top level, a fixed set of structural/discriminator fields —type, sequence, requestId,
replayed, toolCallId, approvalId, memoryId, schemaId, model,
code, finishReason, status, retryable, apiVersion — is left
completely untouched, because these are protocol shape, not content, and
altering them would break the comparison the corpus exists to do. The at
timestamp is always zeroed to the same epoch constant used above. Every
other string — top-level or nested at any depth — passes through the
six-category scrubber; at depth 1 and below there are no key-name
exceptions, so every string value gets sanitized without exception.
Streamed text: an extra option, not a weaker guarantee
Fortext.delta events, the normalizer supports two postures, chosen by
comparison mode:
semantic/intentionally_changedmode — the delta’s actual text is discarded outright and replaced with a length-only marker (⟨len:N⟩). The content itself does not survive normalization in this mode; only its length does.exactmode — the delta text is retained, because an exact-mode comparison needs to check output byte-for-byte, but it still passes through the same six-category scrubber as any other string.
semantic/intentionally_changed mode reduces message
text to a length marker. A test case that must not carry any message text
forward at all needs semantic mode specifically, not just the scrubber.
Learning: per-tenant by default
This section describes design intent (design spec §3.5). There is no evidence of a live routing-policy learning system in the product today — model routing currently runs on static effort/cost lanes and failover ladders, not a learned one — so treat everything below as target behavior for a system not yet built, not a description of something already running.- Per-tenant learning only, by default. A tenant’s own history informs its own future routing, not another tenant’s.
- Cross-tenant signal, where it exists at all, is metadata only — task-class → model/tool success priors, latency/cost distributions — aggregated. Never content, never memory, never raw context. The design states this as a deliberate anti-move, not an oversight: raw context or state is not sold or shared across tenants.
- Opt-out-able and contractual. A tenant can decline participation in cross-tenant aggregation, on contractual terms, not just a UI toggle with nothing backing it.
- Consent labels from the first write. Every receipt is designed to carry consent/training-eligibility labels starting at creation, so that data captured for debugging can never be retroactively reclassified as training data after the fact.
- Policy updates are eval-gated and reversible. Any learned
routing-policy update is designed to ship versioned, gated by
bun run eval:agenticplus Langfuse contract evals, and to be reversible — policy learning gated like a code change, never applied silently.
See also
security-model.md— trust boundaries and credential handling.receipts-and-audit.md— receipt contents and export paths.