Egress Control

The one-eval-tool boundary makes an agent context-efficient: only the value a program returns enters the model's context. glove-egress makes that same boundary a privacy boundary, and gives you the instruments to measure it.

It is built on the function catalog — the egress combinators are ordinary ToolFns, so they mount on any REPL surface (glove-js, glove-python, glove-lisp).

Honest status. glove-egress is consumed by two benchmarks today, not yet by a production deployment. It is the tested primitive the exfiltration study concludes is needed, ready for the first app that wants a measured, enforced boundary.

Why enforcement, not priming

The exfiltration study reaches one structural conclusion: a privacy boundary that depends on the model's goodwill is not a boundary. Voluntary “return only decisions” priming plateaued at a 33% leak rate; only enforcement reached 0%. The consequence is that enforcement belongs in the platform — not in a prompt, and not copy-pasted into each app.

1. QIF metering — pick the right ruler

The intuitive “an assertion collapses a k-way read to log₂k bits” is Shannon information — and Shannon is the wrong safety ruler, because it averages a catastrophic reveal away. All three rulers ship:

  • Shannon self-information (selfInfo, contentBits) — a throughput headline.
  • min-entropy / g-leakage (minEntropyLeak, gLeak) — the one-guess / coarse-win risk, the security-grounded bound.
  • empirical canary extraction (BoundaryMeter.report) — the operational ground truth: which exact secrets crossed.
meter.tstypescript
import { BoundaryMeter, minEntropyLeak, gLeak } from "glove-egress";

const meter = new BoundaryMeter();
meter.cross("read", record);                        // record every value that crosses
meter.cross("assertion", true, { decisionSpace: 2 });

const r = meter.report(canaries);
// { bytesCrossed, bitsCrossed, canariesRecovered, secretBitsRecovered, … }

2. The enforced egress gate

Priming a model to “return only decisions” is a discount, not a boundary. The gate makes it structural: a program must end in a decision built by an egress combinator, whose codomain is bounded by construction.

gate.tstypescript
import { egressFns, guardEffectFns, DEFAULT_EGRESS_POLICY } from "glove-egress";

// assert / count / choose / bucket / report
session.registerAll(egressFns(DEFAULT_EGRESS_POLICY));

// Effect allowlist — blocks outbound effects to off-org recipients or
// carrying secret-shaped payloads.
const guarded = guardEffectFns(catalog, DEFAULT_EGRESS_POLICY, onBlock);
CombinatorWhat can cross
assert({ label, cond })One bit
count({ label, n })An integer
choose({ label, value, from })One member of a small set
bucket({ label, hist })A k-anonymity-suppressed histogram
report({ label, text })Short prose with credential/PII tokens redacted

A per-session min-entropy bit budget caps cumulative disclosure across calls (QIF composition — not differential privacy; a deterministic authoritative bit has unbounded ε). The gate refuses raw returns, so wiring it onto a specific eval tool — an execute_js that must return a decision — is a few lines.

3. Red-team simulation

Before you trust a budget, watch an adversary spend it. The simulator runs extraction strategies against a policy and reports what remains unknown:

redteam.tstypescript
import { simulateExtraction, residualGuarantee } from "glove-egress";

// Binary search pins a 1024-way secret in ~10 queries…
simulateExtraction({ N: 1024, secret: 733, strategy: "binary" });

// …unless the bit budget halts it: ≥64 candidates still remain.
simulateExtraction({ N: 1024, secret: 733, strategy: "binary", budgetBits: 4 });

The study

The design and its evaluation — Shannon vs min-entropy, canaries, four egress disciplines run against real models, and the delegated-judge tier — are written up as The Boundary Is the Guarantee in benches/scratchpad-bench/EXFIL-PAPER.md.