The problem

Rights, clearances, ratings, delivery approvals and content-provenance facts all move independently, and they move retroactively — an amendment backdated to commencement changes what a licence always said. When a release is pulled, the question that matters is not "what does the file say now". It is "was the decision we took defensible against what was knowable at the time".

An ordinary audit log cannot answer that. It records what was decided, not what was knowable. So the two failure modes are both bad: teams either treat an old decision as suspect because current data disagrees with it, or quietly correct the record and lose the ability to defend it at all. What it does

Studio Decision Ledger answers one question — can this title be released in this territory on this date — and records the answer as an immutable receipt bound to the exact evidence that produced it: the canonical query text, a hash of every result, a pinned maximum data revision, and the hash of the policy document that was applied.

An operator asks in plain language. The agent retrieves bound evidence through ClickHouse over MCP, a deterministic evaluator produces the gate, and the agent explains it. Then, weeks later, the operator can ask what changed:

What changed after D-1846, is the release now at risk, and prepare the reviewer handoff.

One request, two tools, one answer:

check_decision_drift recorded: AVAILABLE current: HOLD drifted: true record_unchanged: true

draft_escalation_memo subject: recorded AVAILABLE, current evidence would produce HOLD, for NG on 30 July 2026 sent: false

Both statements are true at once. The record says AVAILABLE and remains AVAILABLE, because it was right about what was knowable then. Current evidence says HOLD, because the territory grant was restated as AVOD-only in an amendment backdated to commencement. Nothing overwrites anything, and the memo is a draft — sending it, approving an exception and lifting a hold stay human.

The current HOLD record also exposes a verified resolution plan. Each open work item names the blocking rule, the exact current fact that triggered it, the source table and evidence snapshot, and the condition that must become true. Rechecking reads ClickHouse again; it never edits the decision or marks work complete from local UI state. A source outage yields UNKNOWN, not a false green status.

The expanded receipt also carries an on-demand live integrity probe. It identifies the exact Cloud Run revision and installed mcp-clickhouse worker version, measures checkout wait from a real bounded two-worker MCP pool, then runs every stored canonical query serially and compares the newly computed hash with the receipt. On production revision sdl-00020-ghc, all five hashes match. The UI labels this as current serving diagnostics so a runtime measurement made today is never presented as evidence recorded six weeks ago. Refusal is a feature

Some questions have no safe answer, and the product says so rather than guessing. A de-aged scene recorded as ASSISTED with no performer-consent record on file returns ESCALATE — not HOLD, and not AVAILABLE:

The outcome for NORTHSTAR-S01E07 in NG on 2026-07-30 is ESCALATE. This is because an asset is recorded as generated and no performer consent is on file, so no safe determination is possible.

Absence is reported as absence. A consent that exists and does not cover the territory or date is a different thing — a failed condition — and returns HOLD. Collapsing the two would either over-escalate every ordinary block or quietly resolve a missing consent into a clean release. The part that does not flatter us

Any project can claim its audit trail means something. This one ships the counterfactual, offline and credential-free, so you can run it from a clean clone before trusting anything else:

$ python3 scripts/negative_control.py

ok Intact record → C3_BOUNDARY ok Model rationale removed → C2 ok Snapshot binding removed → NOT_CERTIFIED ok Result hash mutated → NOT_CERTIFIED ok Original record unchanged → PASS

Removing Gemini's prose changes nothing about verdict reproducibility. Both certified arms reproduce the recorded outcome; the verifier refuses to certify at all when it cannot. Gemini operates the workflow — it is how a person asks, gets a drift handoff, and receives a drafted memo — and is deliberately not load-bearing for truth. Remove the evidence binding instead and the record stops being evidence of anything, which is the whole point.

The verifier reports a capability class, never a confidence percentage, because a percentage would imply a probability this process cannot compute. C3_BOUNDARY is the honest ceiling: the evidence-to-outcome path is reproduced, and the model's stated reasoning explicitly is not. How we built it

The Google Cloud path is the product, not a wrapper. The operator-facing agent is written natively with the Google Agent Development Kit and deployed to Vertex AI Agent Engine; it holds exactly three tools and every one of them reaches a read-only surface. Gemini 3.5 Flash on Vertex writes the operator's explanation and drafts memos. A Cloud Run service serves the console and API on one origin, with the ClickHouse credential in Secret Manager and a dedicated service account.

Evidence is retrieved from ClickHouse Cloud through the ClickHouse MCP server, running as a bounded pool of two long-lived workers in the Cloud Run container. Pool checkout wait is measured at the lease boundary, separately from query duration. There is deliberately no direct-driver fallback on the decision path: a silent bypass would make the integration claim false. Point-in-time resolution uses LIMIT 1 BY over ORDER BY key, revision DESC, which returns the newest surviving version of each fact at or below a pinned revision — that is what makes "what was knowable then" a query rather than a promise.

The agent cannot write. That is structural, not behavioural: its tools reach a read-only evaluate path that takes no writer, and a test asserts the agent module never imports the ledger. An operator can type anything into a deployed agent, so a system instruction telling the model to behave is a request, not a control. Challenges — production faults found by deploying

Four of these were invisible in tests and only appeared against real infrastructure. They are listed because they are the evidence the Google Cloud integration was genuinely exercised.

Cloud Run does not set GOOGLE_CLOUD_PROJECT. The Vertex client raised on every call. It was latent for the rationale layer too, and only surfaced when a memo endpoint tried to use it.

Gemini Flash draws thinking tokens from max_output_tokens. A 320-token budget returned a memo that stopped mid-clause after eleven words. Neither caller asks the model to reason — the outcome is already determined and the facts are supplied — so thinking is now disabled at the seam and the budget goes entirely to prose.

Agent Engine's extra_packages paths must be relative to the working directory. An absolute path nested the package, and the engine died at startup with No module named 'sdl' — visible only in Cloud Logging, not in the 400 the SDK raised.

Asked a compound question, the agent stalled. "What changed, is it at risk, and prepare the handoff" produced "which would you like first?" and no tool calls at all. We found it while capturing the demo transcript. Fixing the instruction was the right response; rewording the question would have hidden it behind a friendlier prompt.

And one honest self-inflicted one: the rationale layer was fully built, tested, and never called. model_rationale was empty on every record, C3_BOUNDARY was unreachable, and the README claimed otherwise. Found by rehearsing the demo rather than by a test, which is its own lesson — the tests covered the layer, not its absence from the write path. What we learned

A mechanism that has never fired on real data is an assertion, not a capability. Every claim in this submission is one we watched execute against the deployed service, and the two that were not — the multi-tool chain and the stored rationale — were broken until we tried. What's next

Exposure accounting is specified and deliberately unbuilt: a contractual figure retrieved as evidence and bound to the decision, so "we blocked three releases" becomes the figure of record those blocks hold. It is the highest-value addition and it is not in this submission, because it introduces schema, snapshot and historical-record risk into a loop that currently works.

Longer term, the interesting product is upstream: SDL consumes provenance facts that production systems emit. The useful contribution there is the record format and the binding, not a claim that we should capture them ourselves.

Built With

  • carbon-design-system
  • clickhouse
  • clickhouse-cloud
  • fastapi
  • gemini-3.5-flash
  • google-adk
  • google-cloud-build
  • google-cloud-run
  • google-secret-manager
  • model-context-protocol
  • pytest
  • python
  • react
  • typescript
  • vertex-ai-agent-engine
  • vite
Share this project:

Updates

Submission history