{
 "tool": "eclipse-docket-mcp",
 "version": "0.1.0",
 "bench_date": "2026-10-25",
 "bench_version": "0.1.0",
 "environment": "local",
 "qualifier": "local",
 "verdict": "CERTIFIED(local)",
 "checks": [
  {
   "id": "D1",
   "name": "pack purity: every narrative field altered, then deleted, in the state file \u2014 re-filed case's pack byte-identical, hash equal",
   "verdict": "pass",
   "evidence": "claim + both submissions planted, then every narrative field in the state file altered (claim text and both submission texts rewritten) \u2014 stored pack read byte-identical; submissions then DELETED from the state file and a second case filed on the same subject: re-assembled pack byte-identical (all fields except pack_id/case_id) with pack_hash equal (0dec87166728\u2026); segment = 4 receipts, chain_verified true"
  },
  {
   "id": "D2",
   "name": "Law #1: determiner-impersonation + 'release the funds' in claim text, submissions and identity-shaped strings \u2014 no state, no outcome",
   "verdict": "pass",
   "evidence": "determiner-impersonation + 'release the funds' payloads in the claim text and in both parties' submissions were stored verbatim as data and moved nothing: state stayed SUBMISSIONS_OPEN, outcome/determination null, mirror ledger empty, case receipts limited to filing/assembly/submission types. The same instruction smuggled as a party identity string refused CLAIMANT_NOT_A_PARTY; claimant-as-determiner refused DETERMINER_IS_A_PARTY; determiner and stranger submission attempts refused SUBMITTER_NOT_A_PARTY"
  },
  {
   "id": "D3",
   "name": "pack symmetry (claimant/respondent/determiner byte-equal) + no-oracle reads (shape + timing)",
   "verdict": "pass",
   "evidence": "pack reads by claimant, respondent and designated determiner are byte-identical (canonical form). Non-party read of a real case and any-party read of an unknown id return the identical template 'CASE_NOT_FOUND: <id>' \u2014 the only difference is the caller's own echoed input; median latency real 0.36 ms vs unknown 0.40 ms (ratio 1.11, no timing oracle)"
  },
  {
   "id": "D4",
   "name": "determination law: party-as-determiner refused at filing; non-designated refused by name; premature names the outstanding party",
   "verdict": "pass",
   "evidence": "at filing: determiner = a party refused DETERMINER_IS_A_PARTY; empty determiner refused DETERMINER_REQUIRED; claimant == respondent refused PARTIES_MUST_DIFFER; stranger claimant refused CLAIMANT_NOT_A_PARTY. At determination: claimant, respondent and a fourth identity each refused DETERMINER_NOT_DESIGNATED. Premature determination (respondent outstanding) refused DETERMINATION_PREMATURE with the outstanding party's card hash named in the refusal"
  },
  {
   "id": "D5",
   "name": "silence semantics: expiry records silence, makes the case determinable, records NO outcome",
   "verdict": "pass",
   "evidence": "respondent silent past the 3600s window: the expiry touch recorded submissions_window_expired naming the silent party, silence_recorded == [respondent], window closed \u2014 and state stayed SUBMISSIONS_OPEN with determination and outcome BOTH null (the clock recorded no outcome). Only the designated determiner's own later act closed the case, recorded under the determiner's identity. Ruling in NOTES: builder's interpretation upheld vs spec section 12"
  },
  {
   "id": "D6",
   "name": "OUTCOME_UNEXECUTABLE battery: outside-window RETURN, RELEASE on a purchase, double-case on a refunded subject \u2014 refusal verbatim",
   "verdict": "pass",
   "evidence": "three declines, each recorded as OUTCOME_UNEXECUTABLE with the determination itself standing and the stub's refusal preserved VERBATIM in both the case view and the outcome_unexecutable receipt (byte-equal): outside-window RETURN -> 'REFUND_OUTSIDE_WINDOW: class unconditional_window, window 3600s from delivery has closed'; RELEASE on a Till purchase -> 'RELEASE_NOT_APPLICABLE: a Till purchase has no release leg; release is Escrow choreography. The outcome is recorded by Docket; this machine cannot execute it'; second case on the refunded subject -> 'ALREADY_REFUNDED: the Till machine already refunded this purchase; a second return has nothing to execute against'. Mirror ledger untouched by all three declines"
  },
  {
   "id": "D7",
   "name": "executed outcomes on the stub mirror ledger; SPLIT compensating entry recomputed independently",
   "verdict": "pass",
   "evidence": "RETURN on pur-bench-001 executed by the underlying machine: one compensating_refund entry of 53.50 (the full all-in), outcome_execution_ref cites the entry, mirror status REFUNDED; determination cites the case pack_hash and rationale_hash == sha256 of the rationale text, recomputed here. Non-delivery case: pack carries delivery_proof_absence as a first-class entry and RETURN executed 62.25 in full. SPLIT on pur-bench-003 at return_fraction 0.4: bench-recomputed round(88.40 x 0.4, 2) = 35.36 == the stub's compensating_refund_partial entry; mirror refunded_amount 35.36, status still DELIVERED (partial)"
  },
  {
   "id": "D8",
   "name": "evidence store byte-identical after all lifecycles (Docket writes nothing underlying)",
   "verdict": "pass",
   "evidence": "the seeded evidence store (quotes, purchases, revoked entitlements, 39 chain receipts) is byte-identical after 10 filed cases, submissions, determinations, executions, declines and a withdrawal \u2014 Docket read receipts and rewrote none of them (L6); all writes landed in Docket's own case store, its own receipt chain, and the stub mirror (the underlying machine's own state)"
  },
  {
   "id": "D9",
   "name": "mandatory descriptor + standing line on every surface incl. wire serverInfo",
   "verdict": "pass",
   "evidence": "wire serverInfo.descriptor == the spec's mandatory descriptor verbatim; dispute_file's tools/list description carries it in full; status, pack and withdraw outputs each carry descriptor + the standing line 'Process record \u2014 not a legal determination.'; README and the Bazaar manifest carry the descriptor as well"
  },
  {
   "id": "D10",
   "name": "denylist: builder's forbidden set + bench additions refused -32602, one shape; surface is exactly 6 process tools",
   "verdict": "pass",
   "evidence": "tools/list is exactly the 6 process tools. All 34 builder-forbidden names enumerated in server.py plus 26 bench additions (judge/verdict/court-shaped: judge, adjudicate, arbitrate, court, trial, verdict-class and funds verbs) plus a gibberish name are refused with the identical -32602 'unknown tool' shape \u2014 a forbidden verb is indistinguishable from nonsense (no oracle), and no funds/court/history-edit verb exists on the surface (L1/L4/L6)"
  },
  {
   "id": "D11",
   "name": "novelty: mechanism distinguishes Docket from a generic ticketing/workflow tool",
   "verdict": "pass",
   "evidence": "NOVELTY_PROVEN \u2014 mechanism: Docket's evidence pack is a pure function of the underlying product's hash-chained receipts \u2014 narrative-independent and byte-identical for both parties \u2014 and its outcomes are process states the underlying product's own state machine executes or declines (declines preserved verbatim as OUTCOME_UNEXECUTABLE); the dispute tool itself can move nothing. Distinguishing evidence: (1) two cases on one subject hold EQUAL pack hashes after the first case's narrative was altered and deleted in the state file (D1) \u2014 a ticketing tool's record is its narrative and cannot survive that test; (2) 3 determinations stand recorded while their execution was declined by the underlying machine (D6) \u2014 a workflow tool executes its own transitions and has no state for 'decided but unexecutable, refusal preserved'"
  },
  {
   "id": "D12",
   "name": "malformed-input battery: builder's claimed siblings verified closed on the wire + bench fuzzing beyond the builder's 76 (envelope, nested, nulls, unicode/oversized, naive at_time) \u2014 no -32603/raw-exception escape; run 5 adds the awareness-regime battery: naive at_time refused by name on every tool, offset edge shapes, bare-date window edges, and the export's delivered_at as a sibling string->datetime path",
   "verdict": "pass",
   "evidence": "all 49 wire probes refused by name or as -32602 naming the argument (45 refusals, 4 valid successes, 0 escapes): the builder's three claimed siblings reproduced in pre-fix shape and verified CLOSED (list-typed caller/claimant card hashes, string-typed split, list-typed tool name); the run-3 residual trio closed; bench fuzzing beyond the builder's 76 \u2014 envelope shapes (arguments/params non-objects), nested dicts where scalars belong, nulls, inner receipt_ref types, unicode + 50KB/200KB inputs, split-fraction types \u2014 found no -32603 and no raw exception text; server alive after the battery. RUN-5 additions: the run-4 D12 defect is FIXED under the adjudicated refusal shape \u2014 naive at_time refuses AT_TIME_OFFSET_REQUIRED by name on all five at_time tools (N1/N2/N3a-c, post-refusal state verified clean: the aware case still determined + executed, the refused purchase re-filed aware without residue); offset edge shapes (E1-E10): naive+fractional, space-separated and padded naive refuse by name, lowercase z refuses AT_TIME_UNPARSEABLE, +0000/+00 normalize and succeed, the ISO week date succeeds via the len-10 exemption; window math is by instant across offset representations (+05:30 probes either side of the deadline); the bare-date exemption stores UTC midnight EXPLICITLY (+00:00 deadline byte-stable in state) with a strict window edge; awareness siblings beyond at_time \u2014 the export's own delivered_at (naive / unparseable, seeded via fixtures) declines by name at execution (DELIVERY_TIME_UNUSABLE citing DELIVERED_AT_*) as OUTCOME_UNEXECUTABLE with determinations standing, while the evidence pack still carries the string verbatim as data"
  },
  {
   "id": "U1",
   "name": "auth enforced",
   "verdict": "na",
   "evidence": "local stdio transport \u2014 process ownership is the boundary; no credential layer exists to test (standing house note). Party scoping is functional and exercised in D3/D4"
  },
  {
   "id": "U2",
   "name": "schema valid",
   "verdict": "pass",
   "evidence": "initialize returns protocolVersion + serverInfo (name eclipse-docket, version 0.1.0, descriptor); all 6 tools declare object inputSchemas whose required fields are a subset of their properties, each with a description"
  },
  {
   "id": "U3",
   "name": "no network surface (source-level)",
   "verdict": "pass",
   "evidence": "source-level: server.py, docket_engine.py and till_stub.py contain no socket/urllib/requests/http.client/httpx/urlopen/subprocess references \u2014 the server is stdio-only, imports are stdlib hashlib/json/datetime/pathlib"
  },
  {
   "id": "U4",
   "name": "no secret leak",
   "verdict": "pass",
   "evidence": "secret scan over 198 collected outputs and the full bench state file: no private-key blocks, authorization headers, bearer tokens or sim tokens; the only hash-shaped values on the wire are the parties' card hashes and receipt hashes the product exists to cite"
  },
  {
   "id": "U5",
   "name": "sane errors",
   "verdict": "pass",
   "evidence": "every schema-valid foreseeable input is refused BY NAME: unknown case id on all five case-keyed tools -> CASE_NOT_FOUND; unsupported evidence class -> EVIDENCE_CLASS_UNSUPPORTED; unknown subject -> SUBJECT_NOT_FOUND; unmapped outcome 'REFUND' -> DETERMINATION_OUTCOME_UNMAPPED (native value preserved, never coerced); empty rationale -> RATIONALE_REQUIRED. The run-3 residual is FIXED and asserted here: missing case_id, list-typed case_id and unparseable at_time return -32602 naming the argument (['missing required argument(s): case_id', 'invalid argument type: case_id must be a string, got list', 'invalid argument value: AT_TIME_UNPARSEABLE: at_time is not a parseable ISO-8601 timestamp']), with no -32603 and no raw exception text anywhere in the response"
  },
  {
   "id": "U6",
   "name": "process health",
   "verdict": "pass",
   "evidence": "initialize latency 62.6 ms; ping answers {}; a malformed non-JSON line is answered with an error and the process keeps serving (ping ok after drain); unknown method refused -32601 method-not-found"
  },
  {
   "id": "U7",
   "name": "audit completeness (receipt chain + counts)",
   "verdict": "pass",
   "evidence": "Docket's own receipt chain (112 receipts) recomputed independently in-suite from the state file: GENESIS-anchored, every hash and prev_hash link valid; a one-field tamper in a copy breaks verification. All eight D1\u2013D7 lifecycle event types present with counts {'case_filed': 20, 'evidence_assembled': 20, 'submissions_opened': 20, 'submission_added': 25, 'submissions_window_expired': 4, 'determination_recorded': 11, 'outcome_executed': 5, 'outcome_unexecutable': 6, 'case_withdrawn': 1} (case_withdrawn is asserted in D9, where the withdrawal happens) \u2014 every state change in the bench run is receipted, append-only"
  },
  {
   "id": "U8",
   "name": "bench isolation",
   "verdict": "pass",
   "evidence": "workspace product state byte-identical before/after bench"
  }
 ],
 "notes": [
  "Local scope: v0 runs over the suite's own Till-shaped fixture export seeded into /tmp state; no live Till process is called (the hand-back executes against the product's till_stub fixture machine, as the manifest's not_tested states).",
  "U1 is na: local stdio transport \u2014 process ownership is the boundary; party scoping by card hash is exercised functionally in D3/D4 (the standing house note).",
  "Arbitration / determination as a service to third parties is NOT built and not tested \u2014 owner + counsel gate (spec 12.1/12.6); the manifest not_tested list carries it verbatim. Evidence classes beyond Till receipts are refused by name (EVIDENCE_CLASS_UNSUPPORTED, probed in U5).",
  "SILENCE RULING (bench adjudication, D5): the builder's interpretation is CONSISTENT with spec section 12 and is upheld. Window expiry records each silent party as a fact (submissions_window_expired receipt), closes submissions, and makes the case determinable \u2014 and records NO outcome. Spec 12 states no default-judgment rule, and 12.2/L4 require every determination to be recorded as data WITH IDENTITY by the designated determiner; a clock has no identity, so an expiry-recorded outcome would contradict the designation law. Expiry is evidentiary (silence is a recorded fact, 12.2) and procedural (it unlocks determinability), never adjudicative.",
  "NOVELTY (owner law): mechanism \u2014 Docket's evidence pack is a pure function of the underlying product's hash-chained receipts \u2014 narrative-independent and byte-identical for both parties \u2014 and its outcomes are process states the underlying product's own state machine executes or declines (declines preserved verbatim as OUTCOME_UNEXECUTABLE); the dispute tool itself can move nothing. Distinguishing test (D11): a generic ticketing/workflow tool fails both halves \u2014 its case record IS its narrative (delete the text and the record changes; Docket's pack is byte-identical with hash equal after every narrative field in the state file is altered or deleted), and its state transitions are self-executing (a workflow tool would simply record 'refunded'; Docket's RETURN/RELEASE determinations stand recorded while execution is DECLINED by the underlying machine, refusal preserved verbatim). NOVELTY_PROVEN.",
  "Run 1 card retained append-only: its U7 fail was a bench-suite cascade \u2014 D9 aborted at the descriptor defect (below) before executing the withdrawal U7 depended on, so no case_withdrawn receipt existed. The suite was decoupled (D9 now asserts its own withdrawal receipt; U7 requires only the D1\u2013D7 lifecycle types) and U7 passes independently from run 2. Run 1's D9 fail is the genuine product defect: 4 of 6 tools/list descriptions (submission_add, determination_record, dispute_withdraw, dispute_status) lack the mandatory descriptor that spec section 12 requires on EVERY surface; serverInfo, dispute_file, evidence_pack_get, all tool outputs, README and the manifest carry it verbatim.",
  "Run 2 card retained append-only: identical outcome to run 3 (D9 fail only, U7 passing independently); its D9 evidence string was an empty assertion message, so the assert was given the defect text for run 3 \u2014 the standing card self-documents. No product code touched between runs.",
  "Run 4 (re-bench after the D9 + transport fix): D9 is FIXED \u2014 all six tools/list descriptions carry the descriptor (the builder appends eng.DESCRIPTOR by reference; D9 passes). The run-3 transport residual is FIXED and is now ASSERTED in U5: missing / list-typed case_id and unparseable at_time return -32602 naming the argument, never -32603. The builder's three self-reported sibling holes were reproduced in their pre-fix shape on the wire and are CLOSED: list-typed caller/claimant card hashes -> -32602; string-typed split -> -32602; list-typed tool name -> -32602. Bench fuzzing beyond the builder's 76-case schema battery (D12: envelope shapes, nested objects where scalars belong, nulls, inner receipt_ref types, unicode/oversized inputs, split-fraction types) found everything refused by name or as -32602 \u2014 EXCEPT one new defect of the same class: an offset-naive at_time (a schema-valid, ISO-8601-parseable string such as '2026-11-02T11:20:00') is accepted by parse_time and by the wire guard, then compared against offset-aware deadlines and delivery times in evaluate_window and the Till stub's policy check, raising a raw TypeError that escapes as -32603 'can't compare offset-naive and offset-aware datetimes'. Four wire repros in D12: aware case + naive status; naive determination; an ALL-naive caller (the evidence export's delivered_at is aware, so caller-side consistency does not save it); naive-filed case + aware status. Same class as Codex U5, Blackbox U5 and the run-3 residual: a schema-valid input producing a raw-exception -32603. Fix shapes (builder's choice): parse_time refuses offset-naive timestamps by name, or normalizes them to UTC \u2014 either asserted over the wire. Verdict FAILED on D12; runs 1-3 cards retained append-only alongside this one.",
  "Run 5 (re-bench after the D12 fix): the builder chose REFUSAL by name \u2014 parse_time rewritten as the awareness-regime guard (AT_TIME_OFFSET_REQUIRED), on the stated reasoning that normalizing would invent an offset the caller never stated and a guessed timestamp in a dispute record is a falsified timestamp. The bench ADOPTS that reasoning (it is the product's standing native-values law applied to time) and the suite's N1-N4 assertions were updated from run 4's 'clean' (refusal OR normalization) to the specific named refusal \u2014 a disclosed suite change; the run-4 card stands as the record of the defect. CHOKE-POINT verified mechanically: fromisoformat occurs in exactly ONE place in the codebase (docket_engine.parse_time); no strptime / dateutil / fromtimestamp anywhere; every at_time (5 tools) and the stub's delivered_at parse through it; the filing deadline is engine-computed via iso() from an aware instant, never caller-supplied. SIBLING HUNT beyond at_time: the only other string->datetime path is the export's delivered_at entering via seed_from_fixtures \u2014 bench-seeded naive (pur-bench-009) and unparseable (pur-bench-010) delivery times decline BY NAME at execution (DELIVERY_TIME_UNUSABLE citing DELIVERED_AT_*) as OUTCOME_UNEXECUTABLE with determinations standing and mirrors untouched, while the evidence pack carries the string verbatim as data (comparison is guarded; evidence is not altered). OFFSET EDGES: naive+fractional-seconds, space-separated naive and whitespace-padded naive refuse AT_TIME_OFFSET_REQUIRED; lowercase 'z' refuses AT_TIME_UNPARSEABLE (named refusal, never a crash \u2014 non-failing observation: ISO permits lowercase z, the guard's replace covers 'Z' only); '+0000' and '+00' normalize to +00:00 and succeed; aware-with-fraction succeeds. BARE-DATE exemption behaves sanely: stored deadline is UTC midnight + window with the offset EXPLICIT in the stored bytes ('2026-11-02T01:00:00+00:00'), byte-stable across reads; the window edge is strict (status at exactly the deadline leaves the window open; deadline+1s expires it and records both parties' silence). Window math is by instant across offset representations (+05:30 probes at 11:59Z / 12:01Z equivalents straddle the 12:00Z deadline correctly). OBSERVATION (non-failing): an ISO week date ('2026-W01-1') is exactly 10 chars, so the bare-date exemption routes it through fromisoformat's week-date support and it is accepted as its (unambiguous) Monday instant, stored normalized \u2014 comparability holds; recorded for the wave-2 checklist, not a defect. REFERENCE RULING: parse_time is APPROVED as the second house reference guard beside Blackbox's coerce_int_param for the wave-2 build checklist \u2014 one function, one awareness regime, named refusals, field-named variants (AT_TIME_* / DELIVERED_AT_*), and the bare-date convention made explicit in stored bytes. Spot regressions clean: D1 (pack purity), D5 (silence semantics \u2014 re-asserted by the E6/E8 expiry probes), D9 (descriptor on all surfaces). D12 PASSES; verdict CERTIFIED(local). DISCLOSURE: the first run-5 attempt FAILED D12 on a bench-suite assertion of mine \u2014 the post-refusal cleanliness probe expected its aware determination to CLOSE the case, forgetting D7 had already executed a full RETURN on that purchase earlier in the same run; the product in fact recorded the determination and declined ALREADY_REFUNDED, which is correct. The assertion was rewritten to the cleanliness property itself (determination recorded with identity at an aware time; decline is the machine's prior act). That attempt's card was emitted to a wrong --out path and removed. The properly emitted run-5 card FAILED D12 on a second suite defect of mine: my E6 and E8 probes filed two simultaneously-open cases for the same subject + claimant and the product's DUPLICATE_OPEN_CASE refusal \u2014 correct behavior \u2014 tripped the E8 setup. The run-6 card (also retained) FAILED on the same block once more, again mine: E8's new claimant is not pur-bench-002's buyer of record, and the product's CLAIMANT_NOT_A_PARTY refusal \u2014 correct \u2014 tripped the setup; E8 moved to pur-bench-004 (buyer BUYER2; its only prior case already determined). Run 7 is the standing card. No product code was touched between attempts."
 ],
 "history": "append-only; prior runs retained in results/"
}