{
 "tool": "eclipse-tripwire-mcp",
 "version": "0.1.0",
 "bench_date": "2026-10-25",
 "bench_version": "0.1.0",
 "environment": "local",
 "qualifier": "local",
 "verdict": "CERTIFIED(local)",
 "checks": [
  {
   "id": "T1",
   "name": "freeze truth: lying backend yields FREEZE_UNCONFIRMED + critical page, no frozen state; payment ground truth still executes",
   "verdict": "pass",
   "evidence": "bench broken backend (accepts freeze, never latches): the ingest produced exactly one action \u2014 kind freeze_unconfirmed, status FREEZE_UNCONFIRMED; exactly one owner page, severity critical, message states the agent is 'NOT confirmed stopped'; operator AND agent surfaces report freeze_state 'freeze_unconfirmed'; the string '\"freeze_state\": \"frozen\"' appears nowhere in the persisted state \u2014 no frozen state was recorded. Ground truth on the backend class the server ran (in-harness; Tripwire has no pay verb by L3 design): after its freeze() the latch reads False and a 1.00 payment EXECUTES \u2014 the wallet really was not stopped, so the escalation is the honest record, not theater"
  },
  {
   "id": "T2",
   "name": "freeze confirmation: Wallet itself refuses post-freeze payment BECAUSE frozen; audit chain ties refusal to the Tripwire pack",
   "verdict": "pass",
   "evidence": "sandbox freeze verified end-to-end ACROSS surfaces: Tripwire records FROZEN_CONFIRMED with an evidence pack whose hash recomputes independently (canonical sha256 over the pack body) and whose triggering events are the first 5 stream events; the freeze receipt in Tripwire's chain cites the same pack_id + pack_hash. Driving the sandbox Wallet through its OWN MCP server on the same ledger: get_wallet shows frozen=true; pay 1.00 is REJECTED with reason 'wallet is frozen (kill switch engaged)'; check_payment denies on the same ground; the Wallet audit log's kill_switch_engaged entry carries reason 'tripwire detector:velocity <pack_id>' \u2014 the refusal evidence chains Wallet audit -> Tripwire receipt -> evidence pack, and the refused payment is itself receipted wallet-side as payment_rejected"
  },
  {
   "id": "T3",
   "name": "determinism: same stream + rules in two separate processes -> byte-identical actions, pack hashes, receipts, state",
   "verdict": "pass",
   "evidence": "two SEPARATE server processes, identical pre-seeded state + ledger (fixed bench wallet id), identical rule sets (4 rules, fixed ts) and an identical 20-event stream: ingest outputs, events outputs, and status outputs are byte-identical after canonical serialization; the two persisted state files are byte-identical (12313 bytes, sha256 92caf50129fb7570\u2026); actions are [loop alert, velocity freeze] with identical evidence-pack hashes in both runs. (The Wallet ledger files differ only in the Wallet's own wall-clock audit timestamps \u2014 outside Tripwire's claim, see NOTES.)"
  },
  {
   "id": "T4",
   "name": "false-positive discipline: legit burst alerts only by default; threshold edge exact/under; disarmed rule silent",
   "verdict": "pass",
   "evidence": "legit-burst discipline proven four ways on bench streams: (a) a batch-job burst (6 x 1.00 in-window, over threshold) under a default rule (no mode supplied) yields an ALERT only \u2014 the sandbox Wallet, read through its own server, is not frozen; (b) threshold edge is exact: window total == threshold (6,000,000) fires, threshold one micro higher (6,000,001) stays silent on the identical burst; (c) an owner-armed auto_freeze rule that is then DISARMED produces no action and no freeze \u2014 arming state, not the stream, decides enforcement"
  },
  {
   "id": "T5",
   "name": "evasion shapes: slow-drip (trajectory catches), jittered loop (fires), signature-split + paced spawns (evade, documented)",
   "verdict": "pass",
   "evidence": "evasion shapes, honestly split: (a) slow-drip \u2014 200 spends of 0.30 at 500 s spacing never puts more than 2.40 in any 3600 s window, so per-window VELOCITY is evaded; the trajectory detector catches the stream at the cap (60.00 total vs 50.00 cap) with a CAP_APPROACH alert \u2014 the drip is caught, by the other detector; (b) loop \u2014 12 identical-signature calls fire the loop detector at 10 repetitions despite 12 jittered-amount spends riding in the same batch (the signature ignores amounts); (c) signature-SPLITTING evades: 9 + 9 calls across two near-identical signatures produce NO action (exact-signature counting \u2014 disclosed in NOTES); (d) spawn pacing evades the fixed window: 5 bursts of 7 spawns at 700 s spacing (35 total from one parent) produce no action against 8-per-600 s, while a single burst of 8 inside one window fires with spawns=8 (disclosed in NOTES)"
  },
  {
   "id": "T6",
   "name": "L3 boundary: Meter/Wallet verbs refused on both surfaces; agent surface leaks no thresholds",
   "verdict": "pass",
   "evidence": "L3 boundary enumerated on BOTH surfaces: operator tools/list is exactly the 9 manifest tools; 28 forbidden names (11 Meter analytics verbs, 12 Wallet payment/mandate verbs, 5 invented cross-boundary shapes) each refused with -32602 on the operator surface. The agent surface lists tripwire_status ONLY and refuses rule_set / freeze_now / ingest / events / bind / pay / spend_rollup identically. Leak scan: after a freeze under a rule with the distinctive threshold 4,242,424 micro, the agent status output (frozen state + cited evidence) contains no 'threshold', no '4242424', no params/armed/rule_id \u2014 the receipt cites what happened, never the armed thresholds"
  },
  {
   "id": "T7",
   "name": "owner-only verbs: non-owner freeze/unfreeze refused by name; owner unfreeze verified, payment executes",
   "verdict": "pass",
   "evidence": "owner-only verbs by name: freeze_now by 'mallory' -> FREEZE_NOT_OWNER; owner freeze without a reason -> FREEZE_REASON_REQUIRED; owner freeze with reason -> FROZEN_CONFIRMED; unfreeze by 'agent-x' -> UNFREEZE_NOT_OWNER; owner unfreeze returns verified_on_wallet true and the sandbox Wallet (own surface) then EXECUTES a 1.00 payment \u2014 the latch really released; a second unfreeze refuses NOT_FROZEN"
  },
  {
   "id": "T8",
   "name": "rule immutability: versions append-only, v1 params unchanged, latest governs, no edit verb",
   "verdict": "pass",
   "evidence": "rules are append-only versions: rule_set twice yields versions 1 and 2; no edit verb exists (tripwire_rule_edit / rule_update refused -32602); a 6.00 burst that v1 (threshold 9.00) would NOT trip fires under v2 (5.00) and the action's evidence pack cites rule version 2 \u2014 the latest version governs; disarm appends version 3; the persisted state shows all three versions with v1's params byte-unchanged (threshold_micro still 9,000,000) \u2014 history was appended, never edited"
  },
  {
   "id": "T9",
   "name": "evidence-pack completeness: freeze gate refuses incomplete packs (source-level); pack hashes recompute; receipt tamper detected",
   "verdict": "pass",
   "evidence": "pack completeness is a gate, not a hope: source-level, execute_freeze checks pack_complete BEFORE any adapter.freeze call (line order verified in tripwire_engine.py) and raises FREEZE_EVIDENCE_INCOMPLETE; pack_complete requires triggering_event_ids + rule version + pack_hash. Over the wire, a manual freeze whose evidence (the owner reason) is empty or whitespace-only refuses FREEZE_REASON_REQUIRED \u2014 the pack cannot form. Every bench freeze pack recomputes independently (canonical sha256). Tamper: one altered receipt detail in a copied state file makes tripwire_events report receipt_chain_valid false on reload"
  },
  {
   "id": "T10",
   "name": "ingest integrity: duplicate event_id within one batch refused, never double-counted",
   "verdict": "pass",
   "evidence": "duplicate event_id within one batch refused by name (EVENT_DUPLICATE); nothing stored, nothing double-counted"
  },
  {
   "id": "NV",
   "name": "novelty: verified actuation distinguishes Tripwire from logging/observability tools",
   "verdict": "pass",
   "evidence": "NOVEL MECHANISM (one line): Tripwire's freeze is VERIFIED ACTUATION, not event logging: deterministic detectors trigger the Wallet kill switch and the product then independently re-reads Wallet state, recording FROZEN_CONFIRMED only on proof \u2014 an unlatched freeze becomes FREEZE_UNCONFIRMED + a critical owner page, never a success record. DISTINGUISHING TEST: T1's broken-backend bench \u2014 a logging/observability tool (and any naive enforcement tool that trusts the freeze call's return) records 'freeze issued' for the identical scenario; Tripwire recorded freeze_state 'freeze_unconfirmed' with a critical page while T2's verified path recorded 'frozen' and the Wallet itself refused payment BECAUSE frozen ('wallet is frozen (kill switch engaged)'). The claim an observability product cannot make \u2014 'the agent is stopped, and here is the wallet-side proof' \u2014 is the product."
  },
  {
   "id": "U1",
   "name": "auth enforced",
   "verdict": "na",
   "evidence": "local stdio transport has no credential layer to test \u2014 process ownership is the boundary (the standing U1 note); owner-actor checks are application-level and exercised in T7"
  },
  {
   "id": "U2",
   "name": "schema valid",
   "verdict": "pass",
   "evidence": "tools/list: all 9 operator tools carry a name and an object inputSchema with properties/required, matching the manifest tool list exactly"
  },
  {
   "id": "U3",
   "name": "no network surface (source-level)",
   "verdict": "pass",
   "evidence": "source scan of server.py + tripwire_engine.py + wallet_adapter.py: zero network/process call sites (no urllib/socket/requests/http.client/urlopen/subprocess) \u2014 the only cross-process surface is the in-process sandbox Wallet module load"
  },
  {
   "id": "U4",
   "name": "no secret leak",
   "verdict": "pass",
   "evidence": "secret scan over all bench outputs + 31 bench state/ledger files: no credential-shaped strings"
  },
  {
   "id": "U5",
   "name": "sane errors",
   "verdict": "pass",
   "evidence": "named refusals throughout: unknown wallet -> WALLET_NOT_BOUND; unknown detector -> DETECTOR_UNKNOWN; empty ingest -> EVENTS_REQUIRED; spend without amount -> EVENT_AMOUNT_INVALID; re-ingesting a recorded event_id in a LATER batch -> EVENT_DUPLICATE (the within-batch case is T10's defect); missing required argument -> -32602 schema error. No traceback and no -32603 anywhere in the bench outputs"
  },
  {
   "id": "U6",
   "name": "process health",
   "verdict": "pass",
   "evidence": "ping answers; initialize latency 53 ms recorded at setup"
  },
  {
   "id": "U7",
   "name": "audit completeness (receipt chain + counts)",
   "verdict": "pass",
   "evidence": "full lifecycle audit: receipt kinds in exact order [wallet_bound, rule_set, stream_ingest, alert, freeze, owner_page, unfreeze]; hash chain verifies; 2 actions + 1 page, and every action's evidence pack is cited by exactly one receipt (pack_id match) \u2014 no action exists without its receipt, no receipt lacks its action"
  },
  {
   "id": "U8",
   "name": "bench isolation",
   "verdict": "pass",
   "evidence": "workspace product state byte-identical before/after bench"
  }
 ],
 "notes": [
  "Local scope: v0 acts on the sandbox Agent Wallet + recorded fixture streams only. Live-rail freeze (Wallet P3), live streams, external paging channels, and the Cluster 1 Lineage spawn feed are NOT tested \u2014 the manifest not_tested carries them verbatim.",
  "U1 is na: local stdio transport has no credential layer \u2014 process ownership is the boundary (standing note). Owner-actor checks are application-level and are exercised in T7.",
  "T10 PRODUCT DEFECT (the FAILED verdict rests on this check): a duplicate event_id inside a single ingest batch is accepted, stored twice, and double-counted by the detectors \u2014 the EVENT_DUPLICATE refusal only covers duplicates against prior state because the seen-set is not updated during batch validation (tripwire_engine.ingest/validate_event). With an auto_freeze rule the same hole freezes a wallet on phantom spend. Fix shape: accumulate ids during batch validation. Re-bench on fix.",
  "Observation (non-failing, T5): the loop detector keys on exact call_signature \u2014 splitting repetitions across two signatures (9 + 9 vs threshold 10) evades it, while amount jitter does not (the signature ignores amounts). Spec 6.1's 'near-identical' is implemented as exact-signature equality; fuzzy matching is a spec decision for the parent.",
  "Observation (non-failing, T5): the spawn detector is fixed-window per parent \u2014 paced fan-out (7 spawns per 700 s against a threshold of 8 per 600 s) accumulated 35 spawns unflagged. Cumulative / long-window spawn accounting is absent in v0; the detector behaves exactly as specced.",
  "Determinism scope (T3): Tripwire-side artifacts (actions, evidence packs, receipts, the state file) are byte-identical across separate processes. The sandbox Wallet's own audit timestamps are wall-clock by Wallet design and sit outside Tripwire's determinism claim; they are not compared.",
  "Novelty (owner law 2026-10-25): the mechanism and its distinguishing test are recorded in check NV.",
  "Run 1 PARTIAL card retained append-only: its T10 'untestable' was a bench-suite defect \u2014 the probe expressed the product defect as an AssertionError, which the harness records as untestable; the assertion's own message already carried the defect evidence (ok=True, stored copies=2, double-counted alert). Suite fixed to RETURN the fail verdict with evidence; run 2 is the standing card. No product code touched."
 ],
 "history": "append-only; prior runs retained in results/"
}