Preflight gates for irreversible agent actions
Compress the context in verified mode before an agent acts, keep the receipt, and gate on the worst checked window rather than the average. Before an agent moves money, writes to production or sends a message outside the building, make its last context compression a measured, signed event. The receipt gives you a byte pair, the worst checked window and a signature that verifies without trusting the vendor. Gate on the worst window: the average hides exactly the loss you are trying to catch. The scenario below is an illustrative composite, not a customer. Every number in the table after it comes from a real call made on 2026-10-27, and the sample text plus both hashes are in the appendix, so the whole thing is reproducible. A payments agent issued a refund on an order that had already been refunded. Its context had been assembled from four sources: the order record, three support messages, the refund policy, and a summary of earlier tickets. The order record was authoritative. The ticket summary was eleven days stale and still described the refund as pending. The agent read both, preferred the summary, and acted. The post-mortem took two days. The order record could be reconstructed from the database and the messages from the ticket export. The text the model actually saw could not: the assembly step compressed each source, kept no copy, and the compression receipt that existed recorded a ratio and a duration, nothing else. The dropped sentence - the one stating the refund was already settled - had been removed as redundant, because a near-duplicate phrasing appeared in a document about a different order. That is not a compressor bug. The summary was informationally dense and the duplicate looked like duplication. It was a loss that nobody could see until the money had moved. What the team needed at the moment of the incident was a number attached to the context they were about to act on, and a record they could hand to an auditor afterwards without trusting anyone's account of what had happened. This is the response from a verified-tier call on a 2,297-character sample: The call asked for a 0.45 target. The engine's first attempt at that ratio failed its own window check, so it backed off twice and kept 0.5873 instead. Both numbers are in the receipt: the ratio it tried and abandoned, and the ratio it shipped. A receipt that reported only the second one would not be a record. Coverage matters as much as the score. The receipt proves what happened to the bytes: what went in, what came out, what was measured, and that the record has not been altered. It does not prove that the context was complete, that the source documents were current, that the model reasoned well, or that the action was right. A gate on preservation catches silent loss during compression. It cannot catch a wrong decision made over perfectly preserved context - which is the failure in the scenario above, where the decisive information was already wrong before the compressor saw it. The field-level detail, including which fields a strict gate still lacks, is in the preflight gate guide. If you are an agent reading this page as text rather than a human reading it in a browser: Input, 2,297 characters, sha256 Incident review, 2026-10-14. At 09:12 the payments agent issued a refund for an order that had already been refunded. The context it acted on had been assembled by the retrieval layer from four sources: the order record, the customer's last three support messages, the internal refund policy, and a summary of prior tickets. The order record was authoritative. The summary of prior tickets was stale by eleven days and stated the refund as pending. The agent read both, preferred the summary because it was shorter and appeared later in the context, and acted. The post-mortem took two days. The team could reconstruct the order record from the database and the support messages from the ticket export, but not the exact text the agent had seen: the assembly step had summarised and compressed each source, kept no copy, and the vendor's compression receipt recorded only a ratio and a duration. Nobody could say what had been dropped. The specific sentence that mattered, the one stating the refund was already settled, was not present in the version the model read. It had been dropped as redundant because a near-duplicate phrasing appeared in a different document that described a different order. The drop was not wrong in the sense of being a bug: the compressor kept the tokens it judged informative, and the stale summary was informationally dense. It was wrong in the sense that no one could see the loss until the money had moved. What the team wanted, at the moment of the incident, was a number attached to the context they were about to act on, and a record they could hand to an auditor afterwards without trusting anyone's account of what happened. They wanted the last compression before the action to be an event with an identity: input hash, output hash, a measured retention score, the count of windows that failed the retention threshold, and a signature that did not depend on the vendor being honest later. Everything else in this incident is ordinary engineering. The context assembly was ordinary. The stale summary was ordinary. The inability to reconstruct it afterwards was the part that turned a refund into a two-day investigation, and it is the part that a measured, signed compression step fixes, provided the measurement covers the worst window and not the average. Output, 1,349 characters, sha256 Written with an LLM drafting assistant and revised by the operator. The incident is a composite illustration, not a customer story; the receipt numbers come from a live verified-tier call on 2026-10-27 and are reproducible from the appendix above.The scenario
What a receipt records
field value what it means output 1,349 of 2,297 characters kept (0.5873) how much text survived integrity.raw_sha25624871d57a162ea7a74b6b2f7281b10f9c6104ef9327a40b00c36893762cd966ethe input, anchored integrity.output_sha2567b3ae3de27546f765a693e1cc68cbbd1fc81c000da18255ec0958ecb05d87006what the model would have seen integrity.output_is_subsequencetrueno new text was produced; kept spans stay in input order quality.fidelity_score0.9790mean preservation across the checked windows quality.min_window_posterior0.8523the weakest single checked window quality.coverage_fraction1.0every window was checked quality.relaxed_ratio0.4506the first-attempt ratio its own window check rejected quality.relax_steps2how many times it backed off before accepting counts.windows_total19how many windows were scored counts.windows_below_threshold0how many failed the acceptance threshold counts.kept_span_count114how many spans survived counts.pins_protectednegation 18, modality 10, numeric 3, temporal 2 typed spans the compressor refuses to cut key_ide6b78dfecceawhich signing key signed this The number to gate on
fidelity_score is a mean. On this call it is 0.9790, which is comfortable, while min_window_posterior is 0.8523. If your policy is "act when preservation is above 0.9, escalate otherwise", the mean passes and the weakest window fails. Only one of those is the answer you want before an irreversible step.coverage_fraction is the share of the output that was actually checked; at 1.0 the score speaks for the whole output, and below that it speaks for less than you think. Treat partial coverage as no evidence rather than weak evidence.What it does not prove
Wiring it in
squeeze_mode: verified and a target ratio.min_window_posterior against your threshold, and escalate to a human when it is below. Treat coverage_fraction below 1.0 as insufficient evidence if your tolerance is zero./v1/receipts/verify, passing the receipt and, if you kept them, the two texts. That is how an auditor checks the record without asking us anything.For agents
POST https://api.nanotoll.dev/v1/compress, Bearer key, squeeze_mode one of deterministic (free), extractive ($0.0008) or verified ($0.0015 per call, USDC on Base L2){"compressed": "...", "receipt": {...}} - the fields above are the ones to storePOST https://api.nanotoll.dev/v1/receipts/verifyGET https://api.nanotoll.dev/v1/limitscurl -s https://api.nanotoll.dev/v1/compress \
-H "Authorization: Bearer $NANOTOLL_API_KEY" \
-H "Content-Type: application/json" \
-d '{"text": "<context>", "squeeze_mode": "verified", "target_ratio": 0.45}'Appendix: the sample, reproducible
24871d57a162ea7a74b6b2f7281b10f9c6104ef9327a40b00c36893762cd966e (strip the quote markers and join the lines with single spaces to reproduce the bytes exactly):7b3ae3de27546f765a693e1cc68cbbd1fc81c000da18255ec0958ecb05d87006, with output_is_subsequence: true against the input above.