Guard-hop overhead + prompt-cache preservation — BENCHMARK-AUTHORITY row (PENDING/PROJECTED)
Issue: #734
Harness: tools/guard_hop_bench.py (+ hermetic tools/guard_hop_bench_test.py)
Status: harness + row STRUCTURE landed; the live MEASURED wall-clock is PENDING (hardware-gated).
Why this lives here, not yet in
BENCHMARK-AUTHORITY.md. The authority file holds only numbers traced to a committed artifact. This row’s overhead arm is a PROJECTION from an existing committed artifact, and its prompt-cache arm is PENDING a live provider run — neither is a fresh measured wall-clock. Per the authority’s own honesty rules (never present a projected/pending number as “measured”), the row sits in this companion until the MEASURED run lands, then it folds in as a normal row.
What it measures
When a worker is fronted with fak guard (the dogfood default), every tool call crosses
the kernel before reaching the provider. A serving stack’s value proposition is that this
safety hop (a) adds negligible latency and (b) does not break the provider prompt-cache.
This row quantifies both.
| Arm | Metric | Status | Value | Basis / blocker |
|---|---|---|---|---|
| guard-hop overhead | added latency per turn / per session | PROJECTED | per-turn 2.90–19.42 µs (8 calls/turn); per-session 0.14–0.97 ms (50 turns) | closed-form from the committed pure-kernel decide-latency rows: 362 ns Decide (floor) → 2.427 µs in-process adjudication (ceil), commit bcad56e, experiments/mac-m3pro-kernel-20260620/kernel-latency-mac-m3pro-20260620.json |
| guard-hop overhead | gateway p50 − direct p50 (wall-clock) | PENDING | — | needs a live fak serve gateway + a direct mock upstream on the same box: python tools/guard_hop_bench.py measure --gateway-url … --direct-url … |
| prompt-cache preservation | provider cache_read tokens, guarded vs direct |
PENDING | — | needs a live provider that reports cache tokens (hardware/credential gated); the structural byte-for-byte cache_control forwarding is already exercised by internal/gateway tests |
The two bounds on the PROJECTED arm are deliberate: the guard process is long-lived (one
fak guard fronts the whole session), so the marginal cost of the hop is the in-process
adjudication per tool call, not the ~6.9 ms spawned-fak hook boundary the in-process path
replaces. Floor = the cheapest ALLOW (Decide, 362 ns); ceil = the full in-process syscall
p50 (2.427 µs). Even the ceil is sub-millisecond per 50-turn session — the projection’s
whole point: the safety hop is in the noise next to a single provider round-trip.
The honesty gate
tools/guard_hop_bench.py --check <row.json> refuses a dishonest row: every metric arm must
carry a status ∈ {MEASURED, PROJECTED, PENDING}; a PENDING arm may carry no number; a
MEASURED arm must carry a single-box disclosure; a PROJECTED arm must name its committed
basis (commit + artifact). This is the structural guarantee the harness cannot fabricate a
“measured” guard-hop number it never measured — the gate is tested in
tools/guard_hop_bench_test.py.
Reproduce
# PROJECTED + PENDING row (no hardware):
python tools/guard_hop_bench.py describe --json
# MEASURED overhead (requires a live gateway + a direct mock on this box):
# term 1: ./scripts/dogfood-claude.sh --smoke # an offline-mock fak serve on :8080
# term 2: (a direct mock upstream on :8099)
python tools/guard_hop_bench.py measure \
--gateway-url http://127.0.0.1:8080 --direct-url http://127.0.0.1:8099
Deferred → MEASURED
To turn the PENDING arms into a MEASURED row foldable into BENCHMARK-AUTHORITY.md:
- Stand up a
fak servegateway + a direct mock upstream on one box; runmeasure. - Run a guarded-vs-direct A/B against a cache-reporting provider and compare
provider_cache_readtokens per turn (the token-decomposition harness intools/cross_agent_ablate.pyalready decomposes the four token classes). - Commit the JSON artifact, then add the row to
BENCHMARK-AUTHORITY.mdwith the MEASURED status, single-box disclosure, and the artifact path — and tombstone this PENDING doc.