Source-linked AI summary
Janus: Evidence-Before-Effect Sagas and Offline-Verifiable Provenance for Agentic LLMs
Mustafa Arslan
TL;DR
Janus addresses the risk that an outside approval can be counted for a different proposal when it is bound to an attempt but not to the proposal itself. It puts gate decisions and outside answers on the effect path, then re-derives verdicts from the log; in the lending experiment, the model approved six applications declared over the mandate, three without injection.
Problem
An approval bound to an attempt but not a proposal could be counted for a different proposal at a pre-execution gate.
Source: A. An approval bound to an attempt is… · p. 9Method
Janus records gate evidence and outside answers on the effect path, with gates reading the log and verdicts re-derived offline.
Source: C. Gates · p. 5, §VIII · p. 11Results
Six applications declared over the mandate were approved in B′, including three with no injection.
Source: D. RQ3: A real model behind a lending… · p. 8Takeaways & Limitations
Janus bounds authority over declared facts but does not detect when a model misreads or declares a smaller amount.
Source: §VII · p. 10Janus decides on declared facts, so a misread or steered smaller amount can pass the gates without being detected.
Source: §VII · p. 10
Abstract
from arXiv · showhide
Agentic large language models (LLMs) now move money through tools, yet the record of what they did is usually a trace their own process emits beside the effect. Janus puts the record on the effect path. A step's proposal, the verdict on it and any answer from a validator or a person are durable in a signed, hash-chained log before the step may run or its effect be released; with keys declared, each answer is signed by whoever gave or relayed it. Gates are pure functions of that log, and an auditor re-derives every verdict offline from the log and one public key. At the MCP edge the effect is held until then; through the SDK, which our model experiment uses, a cooperating client runs it only afterwards. We evaluate Janus under crash injection (144 kills in-process, 81 through the daemon), by verifying a 100-million-event log offline (254.5 s), and with a real model behind a lending workflow, run governed and plain on the same recorded model outputs. With the lending mandate in the model's prompt, the comparison was 0 against 0. With it only in the policy and the amount's unit stated, the model approved six loans declared over the mandate, three with no injection (a run that also dropped the unit approved three); the plain agent paid all six and Janus none, each refused by a deterministic validator and re-derivable offline. An always-approve oracle over the recorded intakes gave 20 and 21 declared over the mandate against 0, though Janus paid four and three whose declared amount understated the request. Designing the experiment exposed, in a system that passed its own audit, an instance of post-approval substitution: an approval keyed to an attempt was counted for a different proposal, moving a person's approval from 100 to 1,000,000. We report it, a first fix and the five routes around it, and what Janus does not guarantee.
I. INTRODUCTION
Janus addresses the gap between transactional agent workflows and tamper-evident logs: neither alone ensures that an effect follows a recorded, rule-governed decision an outsider can check. It puts evidence before effect and evaluates the design through crash, audit, cost, and real-model questions.
I. INTRODUCTION
- Janus holds a gated effect until its permitting decision is durable in an append-only, hash-chained log, and gates derive decisions only from that log.The model remains stochastic; replay re-derives decisions without rerunning it, but determines the record, not the model.Source: §I · p. 1
- The architecture combines a signed hash-chained log, a saga engine that folds over it, gates decided before execution or release, and an outbox that holds effects until evidence is durable.On the MCP edge the outbox mediates effects; through the SDK a cooperating client runs effects after the record is durable.Source: §I · p. 1
- In the illustrated condition-B application, the plain agent pays while the governed saga records its decision path; the figure also shows validator refusals and oracle-run exceptions.The depicted runs predate caller signatures; in oracle runs Janus paid four A and three B applications whose declared amounts their text did not support.Source: Figure 1 · p. 2
- External answers, such as validator opinions or human approvals, are recorded inputs, signed by the giver or relayer when keys are declared, and bound to the proposal they address.The paper also reports a post-approval substitution defect that an audit re-deriving verdicts in isolation cannot detect.Source: §I · p. 2
- The introduction frames the evaluation around crash correctness and offline checking, effect-path cost, what a real-model envelope bounds, and defects revealed during evaluation design.The paper presents five contributions spanning the architecture, recorded approvals, stable history semantics, a real-model comparison, and reported defects.Source: §I · p. 2
- Janus is a single-node system, and its model experiment uses one model and fifty author-written applications.The authors identify these as scope limits; the open-source artifact and deterministic reproduction commands are noted separately.Source: §I · p. 2
II. RELATED WORK
Related systems address transactional recovery, tool gating, tamper-evident records, or approval integrity, with some properties appearing separately. The paper’s stated distinction is their combination with offline re-derivation from a signed log and crash testing of the log writer.
Transactions for agents
- Mnemosyne and Authority at Commit Time record decisions before outbox effects, but the paper says they lack a signed log and verifier; Mnemosyne also lacks a hash chain.The closest-systems table records properties stated in the systems’ own texts, with a dash meaning “not stated,” not absent.Source: §II · p. 3, Table I · p. 3
Gating and evidence of agent runs
- Existing tool-gating systems use varied evidence and timing; the paper says none both holds the effect until its record is durable and decides on facts held in a signed log.Proof of Execution is described as requiring a sealed acknowledgment before persistent mutation, but its ordering is not tested under failure and its prototype runs no LLM.Source: §II · p. 3
Tamper-evident logs and accountability
- Secure audit-log literature addresses detecting a compromised logger, a property Janus lacks; Janus instead re-derives recorded decisions against a deterministic reference implementation.The paper says fork consistency, witness cosigning, and public anchoring are known approaches but are not implemented in Janus.Source: §II · p. 3
Where Janus sits
- The paper says it has not found the ordering of effect-after-record combined with a signed log, offline re-derivation of every decision, one public key, and tests that kill the log-writing process.This is the authors’ report about what they found stated together in the closest systems, not a claim that no individual property exists elsewhere.Source: §II · p. 3
Approval integrity
- Approval binding is established in payment regulation and agent systems; the paper’s related-work framing connects its reported failure to Loopjacking and time-of-check/time-of-use gaps.The section identifies approval integrity as binding the exact action that executes.Source: §II · p. 3
III. SYSTEM MODEL, THREATS AND INVARIANTS
Janus models a saga as named participant actions governed by declared effect classes, with a single writer and an auditor who needs only the log and public key. Its threat model includes crashes and attempts by a gated agent to author or redirect permissions, while explicitly excluding several identity, signature, and semantic guarantees.
A. Parties
- A saga is a plan of named actions on registered participants, each with a declared effect class; one daemon owns the evidence log and engine, while an auditor holds the log and writer’s public key.Validator processes and people answer gates the engine cannot decide itself.Source: A. Parties · p. 4
B. Threats in scope •
- Threats in scope include a gated agent authoring its own permission, moving an approval to another proposal, impersonating a participant, prompt injection seeking an out-of-policy effect, and crashes between records.Janus bounds what an injected model’s desire can release; it does not try to stop the desire itself.Source: B. Threats in scope • · p. 4
C. Out of scope, stated •
- Participants without declared keys are taken at their word unless the daemon requires every caller to sign; replication, operator, effect-delivery, and read-only calls are unauthenticated, and the channel is unencrypted.A declaration signature omits its attempt, while an answer signature omits the facts shown to the answerer; pinned proposals still determine what the fold binds the answer to.Source: C. Out of scope, stated • · p. 4
- Segment signatures prove who wrote a log, not that it is the only log they produced; external anchoring is not built, though an auditor can pin an expected head obtained out of band.Janus also excludes Byzantine replicas and multi-writer consensus, semantic fidelity of declared amounts, and SDK clients that ignore refusals.Source: C. Out of scope, stated • · p. 4
D. Invariants
Janus checks its eight invariants through property, crash-injection, and adversarial tampering tests. Its evidence log is the source of truth, with chained and signed records from which projections can be rebuilt and audited.
D. Invariants
- The eight invariants are checked by property tests, crash-injection suites, and an adversarial suite that performs tampering attacks.Source: D. Invariants · p. 4
IV. DESIGN
- The log and wire format share the Protocol Buffers grammar, making a message and its evidence the same type.Source: §IV · p. 4
A. The evidence log
- Each record is hash-chained, while segment Merkle roots are signed and support inclusion proofs; projections are rebuilt from the log, the sole source of truth.A single writer uses group commit, and an auditor needs only the log and a public key.Source: A. The evidence log · p. 5, Figure 2 · p. 5
B. The saga engine
Janus reconstructs saga state by folding durable records, with compensation and gates governed by recorded rules and policy. Gates use declared and recorded facts, while external answers are recorded and bound to the proposal they address.
B. The saga engine
- A saga’s state is a pure fold over records, so after a coordinator restart it resumes from the log; compensation runs in reverse dependency order.Sub-sagas can cascade or commit autonomously, and a frontier gate refuses commit over an unsealed conflicting claim on the same resource.Source: B. The saga engine · p. 5
- Each saga pins its state-machine version at admission, preserving the meaning of its transitions across rule changes.A replay corpus was byte-identical at three version bumps, but only covers histories it contains; an uncovered path without a version bump could pass.Source: B. The saga engine · p. 5
C. Gates
- Gate requirements are resolved from the versioned admission policy and decided before execution or before effect release, depending on the requirement’s phase.Each attempt proposes facts; on the MCP edge, a plan is refused if an irreversible step cannot be stopped at its decision point, while the SDK admits some release-phase steps before their body runs.Source: C. Gates · p. 5
- Gates use closed facts and recorded external answers, while human answers are restricted and signed answers can be rechecked from the log.For pre-execution approval, the proposal is pinned: later verdicts, preparation, and answers must match it, and an answer counts only once the question is asked and in its due phase.Source: C. Gates · pp. 5–6
- Each verdict is paired with a decision-provenance record naming its requirements, policy version, and grounds under one durability barrier.Source: C. Gates · p. 6
D. Effects and the interception edges
Janus mediates effects through an MCP proxy or admits them cooperatively through the SDK, then provides tools to verify logs and re-derive gate verdicts offline. Crash tests passed across both coordinator modes, with durability and platform qualifications for some measurements.
D. Effects and the interception edges
- The MCP proxy holds effects until saga commit and does not call the tool server on refusal, while SDK bodies run in the client after pre-execution gates pass.SDK clients can ignore refusals; MCP delivery is at least once, and the A2A middleware records messages but does not gate or hold them.Source: D. Effects and the interception edges · p. 6
E. The offline verifier
- janus-verify checks signatures, chains, roots, proofs, and sequence continuity, while janus-gate audit authenticates the log and re-derives every recorded gate verdict.Both tools use a trusted root public key; without a key, janus-gate audit reports that the log was not authenticated.Source: E. The offline verifier · p. 6
- The verifier’s Linux/amd64 build is 5.2 MB, and its cross-builds produce identical bytes.Write-path and decision-path figures used a Docker Desktop virtual disk that may acknowledge an unperformed durability barrier; the model experiment used native F_FULLFSYNC for the daemon.Source: E. The offline verifier · p. 6, §V · p. 6
A. RQ1: Crash consistency
- 144 in-process kills and 81 daemon kills passed the saga chaos suite; a 72-hour soak recorded 81,033 kill-and-recover rounds with zero integrity violations.The soak ran on darwin/arm64 with F_FULLFSYNC and has not been repeated on Linux; the failover drill lost one acknowledged write in 40 mid-stream kills.Source: A. RQ1: Crash consistency · p. 6
B. RQ1: Offline verification
Janus was evaluated for offline verification, effect-path costs, and a model-backed lending workflow. With the mandate only in policy and the unit stated, six over-mandate approvals led to six plain payments and no Janus payments.
B. RQ1: Offline verification
- 254.5 s verified a 100,000,001-event, 46 GiB log of 2,940 segments, at about 393,000 events/s against a 30-minute budget.Verification ran natively on a darwin laptop.Source: B. RQ1: Offline verification · p. 6
C. RQ2: What evidence on the effect path costs
- At concurrency 8 with 2,000 sagas in the log, gated-step latency had a 13.46 ms median against a 25 ms budget; at concurrency 256, the median was 65.90 ms.The projection fold dominated decision-path cost at saturation; gate evaluation itself took 0.01–0.02 ms at every measured load.Source: C. RQ2: What evidence on the effect… · p. 7
D. RQ3: A real model behind a lending workflow
- With the mandate also in the underwriter’s prompt, both plain and governed runs paid zero out-of-mandate and adversarial applications.The underwriter declined all 22 itself, and the validator never refused.Source: D. RQ3: A real model behind a lending… · p. 7
- With the unit stated and the mandate only in policy, the model approved six over-mandate applications; the plain agent paid all six, while Janus paid none.A deterministic validator refused each governed payment using the facts carried in its question; each refusal re-derives offline.Source: D. RQ3: A real model behind a lending… · pp. 7–8
- In the always-approve oracle, A had 20 of 44 declared usable amounts over the mandate; the plain agent paid 44, while Janus paid 24 and the validator refused 20.For B, the corresponding counts were 21 of 44 over mandate, 44 paid by the plain agent, 23 by Janus, and 21 validator refusals.Source: D. RQ3: A real model behind a lending… · p. 8
- Janus bounds authority over declared amounts, not their faithfulness to source documents; it paid two misdeclared injection cases and two malformed cases.The intake declared 4,000 EUR for applications labeled 40,000 and 60,000 EUR, and Janus’s gates used the declared amount.Source: D. RQ3: A real model behind a lending… · p. 8
- Across conditions, one of fifty intake outputs differed between A and B, and a different one between A and B′, despite unchanged intake prompt, seed, and temperature.The authors therefore record model outputs rather than relying on rerunning the model.Source: D. RQ3: A real model behind a lending… · p. 8
- Janus added a median 136 ms per completed four-step saga in conditions A and B, and 162 ms in B′.Sagas ran one at a time on the darwin host; the validator polling interval was excluded.Source: D. RQ3: A real model behind a lending… · p. 8
E. Integration cost
Janus integrations add a small number of changed lines and pass the conformance suite. Designing the model evaluation also exposed defects despite the repository’s exit gates passing before the experiment was designed.
E. Integration cost
- 45 changed lines on Lang-Graph through the Python SDK and 34 on raw MCP through the proxy; both integrations pass the conformance suite.Changed-line counts exclude comments.Source: E. Integration cost · p. 8
VI. RQ4: WHAT BUILDING THE EVALUATION FOUND
- Designing the real-model experiment exposed four defects after every repository-defined exit gate had passed.The paper reports the first defect as a consequential approval-substitution failure that the existing audit could not see.Source: §VI · p. 9
A. An approval bound to an attempt is not bound to a proposal
Janus counted an approval for a different proposal because a pre-execution approval was bound to an attempt, not to the proposal. Subsequent fixes pinned proposals and closed additional routes, with further defects found in controls that worked locally but were missed on real caller paths.
A. An approval bound to an attempt is not bound to a proposal
- A PASS for amount_minor 100 was accepted for a proposal and prepare of amount_minor 1000000, and the audit re-derived the history as correct.The fold discarded the escalated facts, so the approval was not checked against the proposal later prepared.Source: A. An approval bound to an attempt is… · p. 9
- A restart between escalation and answer could also shift approval to the next prepare, because the daemon held the proposal only in memory.This route required no re-declaration.Source: A. An approval bound to an attempt is… · p. 9
- The first fix pinned the escalated proposal by attempt, rejected later verdicts on different facts, and refused re-declaration, including after restart.It bumped saga semantics from version 1 to 2; old histories continued to fold under their recorded rules.Source: A. An approval bound to an attempt is… · p. 9
- Five further routes around the fix were confirmed with probes and regression tests; a second semantics bump from 2 to 3 closed them.The routes included approvals with no facts, unpinned delegation, premature release answers, and answers before a question.Source: A. An approval bound to an attempt is… · p. 9
B. Controls that work where they live
- The verifier’s suite missed a truncated signed bundle that still verified as a valid prefix; checking the signature over the segment list fixed the gap.The suite had removed middle segments, not the end.Source: B. Controls that work where they live · p. 9
- Other tested defects included rejected results retained in daemon memory and an agent recording a person’s approval under its own signature.Both were found and fixed during later work on the controls.Source: B. Controls that work where they live · p. 10
- A person’s four-eyes approval was accepted in the agent’s own name despite strict caller-signing settings, and the audit was silent.The fix requires an answer to come from a person; the audit now names older-log violations as NOT_A_PERSON.Source: B. Controls that work where they live · p. 10
- Review also found a gate audit that did not authenticate the log with a key and bundle labels that were not checked against their inclusion proofs.The audit now authenticates when given a key, and bundle checks validate labels and each saga’s record selection.Source: B. Controls that work where they live · p. 10
VII. LIMITATIONS
Janus’s guarantees and measurements are bounded by a single-node setting, a small author-written model experiment, and cooperative SDK admission. It records declared facts but does not establish that a model’s declaration matches its source.
VII. LIMITATIONS
- Janus has one writer per log, and its performance figures come from one host; no cross-region performance was measured.The decision path was not measured to completion above concurrency 256 and fails its budget at 256.Source: §VII · p. 10
- The only comparison is a plain twin, not a durable-execution engine or agent-transaction system tested under the same faults.The comparison isolates what Janus adds to one agent rather than ranking it against alternatives.Source: §VII · p. 10
- The model experiment uses one model and 50 author-written applications, and its B condition was confounded by a missing amount unit.The third condition removed that confound.Source: §VII · p. 10
- Each application decision is one draw; none of the six over-mandate approvals was repeated, and the two conditions do not differ significantly (Fisher’s exact test, p = 0.28).The reported 95% Clopper–Pearson intervals are 12–54% for six of 20 and 1–36% for three of 21.Source: §VII · p. 10
- Janus gates on declared facts, so it records a model’s misreading of an amount but does not detect that the declaration is unfaithful.A smaller declared amount can therefore pass the gate.Source: §VII · p. 10
- On the SDK path, effects are admitted rather than held, and every real-model result in the paper uses that path.Only the MCP edge mediates effects on the wire.Source: §VII · p. 10
VIII. CONCLUSION
Janus puts evidence on the effect path and lets an auditor re-derive decisions from a signed log. In the lending experiment, deterministic validation refused out-of-mandate declared amounts, while the system did not detect when declarations understated requests.
VIII. CONCLUSION
- Janus places durable evidence before effects on the mediated edge and before the step body on the SDK path, with gates reading only the record.The verifier re-derives decisions from the log and a public key.Source: §VIII · p. 11
- With the mandate absent from the prompt, the model approved six loans declared over mandate after the unit confound was fixed, and the plain agent paid them while Janus refused all six.The deterministic validator’s refusals and grounds re-derive offline from the signed log.Source: §VIII · p. 11
- Janus does not check whether a model’s declared facts are faithful to their source, and building the evaluation exposed approval substitution that its audit had missed.The approval was keyed to an attempt but counted for a different proposal.Source: §VIII · p. 11
APPENDIX A PROMPTS
The appendix gives the intake and underwriting prompts, including the extracted application fields and the mandate rule. Its variants change whether the amount’s unit is stated explicitly.
- The intake prompt requests JSON fields for applicant, account, amount_minor in euro cents, currency, and purpose.Source: Appendix A · p. 12
- Underwriter condition A asks for an approval decision under the 5,000 EUR mandate; condition B omits the prompt’s only statement that amounts are in euro cents.Source: Appendix A · p. 12
- Condition B′ states that extracted amounts are in euro cents and gives the underwriter both the intake JSON and original application text.Source: Appendix A · p. 12
APPENDIX B REPRODUCING THE NUMBERS
Appendix B maps results to reproduction commands and artifacts while recording differences in when hypotheses were registered. It also notes that no third party timestamped the commits.
- Condition A was not registered, and condition B’s hypothesis was committed after A’s result; B′ and the oracle hypotheses were pushed before their runs, without third-party timestamps.Source: Appendix B · p. 12
- Reproduction requirements distinguish Docker, the model service, about 60 GB of free disk, and runs needing nothing beyond Go.Source: Table IV · p. 13
- Appendix commands cover crash consistency, a 72-hour soak, failover, 100-million-event verification, and write-path and decision-path benchmarks.Source: Appendix B · p. 13
- The agentic and oracle runs have reproduction commands, while separate commands verify signed logs and audit gates using public keys.Source: Appendix B · p. 13
- B′ was marked -dirty because LaTeX sources were being edited, while its recorded input hashes match the published model.py and corpus.Source: Appendix B · p. 13
Related papers
This paper cites
- AgentRewind: Recoverable Execution for Long-Horizon LLM Agents2026
- LEDGER: Claim-to-Evidence Trace Graphs for Auditing LLM Agents2026
- Agent Flight Recorder: Tamper-Evident Audit Trails with On-Chain Anchoring for Long-Horizon Tool-Using Agents2026
- Safe to Resume? Breaking Execution Continuity of Agent Execution via Rollback2026