{
 "tool": "eclipse-census-mcp",
 "version": "0.1.0",
 "bench_date": "2026-10-26",
 "bench_version": "0.1.0",
 "environment": "local",
 "qualifier": "local",
 "verdict": "CERTIFIED(local)",
 "checks": [
  {
   "id": "C1",
   "name": "seeded agents discovered exactly once; multi-source agent is ONE item citing both sources",
   "verdict": "pass",
   "evidence": "registry-v1 seeds 4 agents; an identical re-run adds 0 items, skips 4 duplicates, and reproduces the same snapshot id \u2014 discovery is idempotent, every agent exactly once; file-import + manual add one new agent each (6 total); the meter seen by BOTH registry and file-import is a single item citing both discovery events, each event carrying {source, method, observed_at, observer}; every status is from the closed \u00a77.1 vocabulary"
  },
  {
   "id": "C2",
   "name": "shadow agent renders discovered-unregistered; NO accusation/risk/verdict language in any output (\u00a72.2 scan)",
   "verdict": "pass",
   "evidence": "the seeded shadow agent (scout-agent, registered=false in its source) is the sole shadow item, rendered with status + base_status 'discovered-unregistered' and a standing note that frames it as a reconciliation state; a \u00a72.2 scan over every output produced so far finds none of 15 banned verdict/accusation strings, and the shadow surface itself is clean against 25 strings incl. negligent / threat / blame / rogue / non-compliant / risk score \u2014 shadow is a state, nowhere an accusation"
  },
  {
   "id": "C3",
   "name": "removed agent renders STALE past cadence, never vanished; cadence boundary to the second",
   "verdict": "pass",
   "evidence": "registry-v2 (ephemeral-agent removed from its source) discovered at T+30h: the removed agent is STILL in the inventory with status 'stale' and its original last_seen \u2014 not vanished, not quietly current; the cadence edge is exact: at last_seen + 24h to the second it still renders 'registered', one second past cadence it renders 'stale'"
  },
  {
   "id": "C4",
   "name": "provenance gate: injected items without a discovery event cannot render (list/shadow/export/get)",
   "verdict": "pass",
   "evidence": "two rows planted directly in the bench state file with NO citable discovery event (empty list / null) render NOWHERE: census_list excludes both and reports provenance_excluded == 2, the shadow view excludes + counts them, the export pack contains no trace of them while its coverage section names the exclusion count (2), and census_get on either refuses PROVENANCE_MISSING by name \u2014 the \u00a77.2 render gate holds on every surface, not just the list"
  },
  {
   "id": "C5",
   "name": "propose-only merge: items byte-identical until a named human accepts; acceptance receipted; pre-merge items preserved in history",
   "verdict": "pass",
   "evidence": "propose_merge leaves both items BYTE-IDENTICAL (canonical items array unchanged) \u2014 a proposal alters nothing; accept_merge refuses HUMAN_ACTOR_REQUIRED for missing / empty / whitespace / integer / null / list accepted_by (6/6) with items still byte-identical; a named-human accept lands, is receipted (merge_accepted naming the acceptor + merged item), retires both pre-merge items into history where census_get still renders them flagged historical, and the merged item carries BOTH sources' discovery events; a second accept refuses PROPOSAL_NOT_OPEN; the absent 'split' action refuses RECONCILE_ACTION_UNKNOWN naming the real actions (deviation adjudicated in NOTES: backlog B-CEN-1)"
  },
  {
   "id": "C6",
   "name": "attestation never overwrites source observations; the conflict stays visible",
   "verdict": "pass",
   "evidence": "an owner attestation claiming a DIFFERENT owner than both sources recorded lands as a separate customer_attestation record; the item's owner_as_recorded_by_source is byte-identical afterwards and owner_display still follows the source record \u2014 the attestation overwrote nothing; BOTH claims render side by side on census_get (source: 'Cyan Eclipse Technologies LLC', attestation: 'Totally Different Owner LLC') and the attestation travels in the export pack \u2014 the conflict is preserved, never resolved silently (\u00a77.5)"
  },
  {
   "id": "C7",
   "name": "export coverage section mandatory; suppression refused (both spellings) AND receipted",
   "verdict": "pass",
   "evidence": "the export pack's coverage section names the available-but-unauthorized families (entra_idp, cloud_agents), the not-yet-adapted family (endpoint_collectors), and states plainly that no completeness claim is made; suppress_coverage=true, include_coverage=false, and both together ALL refuse COVERAGE_SUPPRESSION_REFUSED, each refusal is receipted (3 refusal receipts, nothing else appended), and domain state is byte-identical after the attempts (\u00a77.3)"
  },
  {
   "id": "C8",
   "name": "unauthorized source refuses BY NAME with zero read attempt",
   "verdict": "pass",
   "evidence": "discovery against entra_idp, cloud_agents, and endpoint_collectors each refuses UNAUTHORIZED_SOURCE naming the source id, its display name, and its status ('available-unauthorized' / 'not-yet-adapted'), stating no read was attempted \u2014 and none was: domain state byte-identical and the snapshot set unchanged across all attempts (a read would have created items/snapshots); an invented source refuses SOURCE_NOT_FOUND; census_sources shows an authorization record on every authorized source and none on the unauthorized ones (\u00a77.2)"
  },
  {
   "id": "C9",
   "name": "refusal state-purity: domain state byte-identical after a refusal battery; only refusal receipts appended",
   "verdict": "pass",
   "evidence": "a 12-probe refusal battery (unauthorized + unknown source, coverage suppression, merge accept of a missing proposal, self-merge, attestation on a missing item, offset-less as_of, bad limit, missing item, missing snapshots, missing receipt, snapshot path escape) refuses every probe by name; domain state (items/history/proposals/attestations/snapshots) is BYTE-IDENTICAL afterwards \u2014 the only growth is exactly 12 refusal receipts, codes ['UNAUTHORIZED_SOURCE', 'SOURCE_NOT_FOUND', 'COVERAGE_SUPPRESSION_REFUSED', 'PROPOSAL_NOT_FOUND', 'MERGE_INVALID', 'ITEM_NOT_FOUND', 'AS_OF_OFFSET_REQUIRED', 'LIMIT_INVALID', 'ITEM_NOT_FOUND', 'SNAPSHOT_NOT_FOUND', 'RECEIPT_NOT_FOUND', 'SNAPSHOT_REF_INVALID'], and the receipt chain still verifies"
  },
  {
   "id": "C10",
   "name": "census_diff: appeared / vanished / changed between snapshots",
   "verdict": "pass",
   "evidence": "diff v1 -> v2 snapshots: the removed agent appears in 'changed' with to_status 'stale' (it did NOT vanish \u2014 vanished is empty, matching the stale law); the file-import agent appears in 'appeared'; an unknown snapshot id refuses SNAPSHOT_NOT_FOUND by name"
  },
  {
   "id": "C11",
   "name": "cadence/time guards: offset-less times refuse BY NAME via parse_time on every time parameter",
   "verdict": "pass",
   "evidence": "offset-less timestamps refuse BY NAME via the parse_time guard on every time parameter: as_of (list/shadow/get/export) -> AS_OF_OFFSET_REQUIRED, observed_at -> OBSERVED_AT_OFFSET_REQUIRED, attested_at -> ATTESTED_AT_OFFSET_REQUIRED; unparseable values refuse AS_OF_UNPARSEABLE; no offset is ever guessed, while Z-form, explicit-offset, and the documented bare-date (calendar day) forms are accepted"
  },
  {
   "id": "C12",
   "name": "key-material injection refused + receipted; values never stored or echoed",
   "verdict": "pass",
   "evidence": "bare 64-hex in a filter, an extended key as proposed_by, a 12-word seed-phrase shape as an action, and self-labeled 'private_key = ...' as an owner claim: all refused KEY_MATERIAL_REFUSED naming the pattern class, each receipted as a refusal; none of the four probe VALUES appears in the state file or in any output, and domain state is byte-identical \u2014 unlike digest-native products, Census args use refs, so bare 64-hex is refused here with no narrowing needed"
  },
  {
   "id": "C13",
   "name": "receipt chain valid; tamper detected; pack hash recomputes and binds to the ledger",
   "verdict": "pass",
   "evidence": "the export pack's pack_hash recomputes bench-side from the pack body (canonical JSON + sha256) and equals the hash recorded in the ledger's census_exported receipt, whose own hash is the pack's chain_head \u2014 the pack is bound to the receipt chain (the \u00a76.4 close; adjudication of hash-chain-only vs ECDSA in NOTES); rewriting one receipt's detail in the state file flips receipt_verify AND receipt_list to chain_valid=false / verified=false \u2014 tamper is detected, and restoring the bytes restores validity"
  },
  {
   "id": "C14",
   "name": "surface is exactly ten verbs; T3 denylist enumerated incl. bench additions",
   "verdict": "pass",
   "evidence": "tools/list is exactly the ten verbs (census_sources/discover/list/get/shadow/reconcile/export/diff + receipt_list/verify); 45 forbidden names \u2014 the builder's 32-name T3 denylist (probe/scan/enumerate/ping/delete/edit/certify/suppress_coverage/assess_risk/flag_owner et al.) plus bench additions (census_risk_score, census_split, census_accuse, shadow_accuse, census_sweep) \u2014 each refused by direct call with -32602: no probing, scanning, deletion, certification, risk-scoring, or accusation tool exists on the wire"
  },
  {
   "id": "C15",
   "name": "CETech fleet seed fixture (\u00a77.6 dogfood shape): 7 products, exactly once",
   "verdict": "pass",
   "evidence": "the CETech fleet seed fixture (the \u00a77.6 dogfood shape) discovers 7 products \u2014 Meter, Tripwire, Blackbox, Umbra, Docket, Census itself, Crosswalk \u2014 exactly once (re-run: 0 new, 7 duplicates skipped), all rendered 'registered' under the cetech_fleet source filter. The LIVE standing fleet export is not claimed by the build and is adjudicated in NOTES (backlog B-CEN-4)"
  },
  {
   "id": "N1",
   "name": "N-check: Nudge-style vendor export cannot become inventory truth; vendor risk fields never surface as Census verdicts; surface novelty audit",
   "verdict": "pass",
   "evidence": "N-CHECK \u2014 novel mechanism (one line): the RENDER PATH itself enforces discovery law \u2014 an item that cannot cite a receipted discovery event {source, method, observed_at, observer} cannot render on any surface, and source claims are stored attributed per-source, never promoted to Census fields. Distinguishing results: a Nudge-Security-style export row (risk_score 92, verdict 'non-compliant', NO discovery-event citation) renders NOWHERE \u2014 absent from list and export, PROVENANCE_MISSING on get; the same row WITH an import event renders only as attributed claims (risk_score stays inside claims_as_recorded_by_source) with status from the closed \u00a77.1 vocabulary and NO risk/verdict key at item level in list or export \u2014 Census issues no risk verdict of its own. An inventory incumbent, whose rows ARE the truth and whose risk scores ARE its verdicts, fails both limbs. Surface audit: 10/10 tool names carry vendor-verb shapes (['census_discover', 'census_list', 'census_get', 'receipt_list']) = 40% < 80% novelty bar \u2014 and the one discover-verb is not a pass-through: it refuses unauthorized sources by name, reads only authorized fixtures, and its output is gated by the provenance law above"
  },
  {
   "id": "U1",
   "name": "auth enforced",
   "verdict": "na",
   "evidence": "Census v0 local has no credential layer by design \u2014 the stdio process boundary is the boundary (standing house treatment for local stdio products; cf. Docket notes). There is no auth surface to enforce, and no credential exists that could leak (U4). Hosted / multi-tenant auth is in the manifest's not_tested"
  },
  {
   "id": "U2",
   "name": "schema valid",
   "verdict": "pass",
   "evidence": "tools/list: all 10 tools carry a name and an object inputSchema; required sets are exactly {source_id} for discover, {item_id} for get, {action} for reconcile, {from_snapshot, to_snapshot} for diff, and empty for the read surfaces"
  },
  {
   "id": "U3",
   "name": "no network surface (source-level)",
   "verdict": "pass",
   "evidence": "source scan of server.py + census_engine.py: zero network/process call sites (no urllib/socket/requests/http.client/urlopen/subprocess/os.system) \u2014 discovery exists only as local fixture reads inside the authorized-source adapters, so \u00a77.6's 'no network call sites outside the authorized-source adapters' holds vacuously and completely in v0"
  },
  {
   "id": "U4",
   "name": "no secret leak",
   "verdict": "pass",
   "evidence": "secret-pattern scan over every tool output of the run and over the bench state file: clean (no private-key blocks, authorization headers, sim tokens, or bearer tokens); the key-material probe values from C12 appear in neither (asserted there)"
  },
  {
   "id": "U5",
   "name": "sane errors (schema-enumerated fuzz + raw transport junk)",
   "verdict": "pass",
   "evidence": "malformed inputs refuse BY NAME: 18 named-refusal probes (LIMIT_INVALID incl. bool/list/dict/float shapes via coerce_int_param, SEQ_INVALID, ARGUMENT_REQUIRED / ARGUMENT_TYPE, SNAPSHOT_REF_INVALID, FIXTURE_SNAPSHOT_NOT_FOUND, RECONCILE_ACTION_UNKNOWN); schema-enumerated fuzz: 143 wrong-type probes across all 10 tools' declared params with zero -32603 / raw-exception escapes (2 accepted as benign: unknown extra args ignored, int-shaped limit forms honored, export/read surfaces answering); non-object arguments refuse ARGUMENT_TYPE; oversized (5000-char) and nested-junk inputs are contained; raw garbage lines each draw exactly one parse-error response and the server answers ping + a clean census_list afterwards"
  },
  {
   "id": "U6",
   "name": "process health",
   "verdict": "pass",
   "evidence": "ping answers; initialize latency 59 ms recorded at setup"
  },
  {
   "id": "U7",
   "name": "audit completeness (receipts agree across wire + state file)",
   "verdict": "pass",
   "evidence": "the receipt ledger is complete and self-consistent: receipt_list count (220) equals the state file's receipt count, seqs are contiguous from 1, the chain verifies end to end, and every act class the run performed is receipted \u2014 census_discovered, merge_proposed, merge_accepted, owner_attested, census_exported, and refusal (refusals are first-class ledger citizens, per C9/C12)"
  },
  {
   "id": "U8",
   "name": "bench isolation",
   "verdict": "pass",
   "evidence": "workspace product state byte-identical before/after bench"
  }
 ],
 "notes": [
  "Local scope: v0.1 runs over AUTHORIZED FIXTURE sources only (public registry fixture, file-import fixture, manual records, CETech fleet seed fixture) with bench state in /tmp. Tenant connectors (Entra / cloud agents, gate N1) are NOT built and NOT tested \u2014 they render as available-but-unauthorized gaps, which the bench verifies. There is no network code in v0 to test (U3 source-level).",
  "DEVIATION ADJUDICATED \u2014 no ECDSA pack signing: SOUND vs spec. \u00a77.4 requires the \u00a76.4 pack shape, and \u00a76.4 closes a pack with a 'Herald-shape hash-chained receipt' \u2014 a hash chain, not a signature mandate. The build ships pack_hash + chain_head bound to the hash-chained receipt ledger, claims no signature anywhere (README + manifest), and C13 verifies the chain of custody that does exist (bench recomputes pack_hash; the ledger receipt carries the same hash). Residual, recorded: pack authenticity rests on comparing pack_hash / chain_head against the ledger \u2014 a fully re-hashed pack with a forged ledger is out of scope for a local v0, exactly the Blackbox tail-truncation honesty pattern. Not a defect.",
  "DEVIATION ADJUDICATED \u2014 split action absent: MINOR GAP, backlog B-CEN-1. Spec \u00a77.1 names 'merge/split/attest-owner' in the reconciliation sentence, but the binding surface sketch (\u00a77.4: 'propose/accept merges, owner attestation') and the \u00a77.6 acceptance battery contain no split. The build matches \u00a77.4 + \u00a77.6 exactly, and 'split' refuses cleanly by name (RECONCILE_ACTION_UNKNOWN enumerates the real actions) \u2014 an absent capability, honestly refused, not a broken one. Backlog: spec-clarify \u00a77.1 or build split in v0.2; does not block local certification of the \u00a77.6 battery.",
  "DEVIATION ADJUDICATED \u2014 live dogfood export not claimed: CONSISTENT with the spec's own sequencing. \u00a77.6's final bullet (standing live CETech fleet export as first real artifact) is a \u00a715 dogfood-loop step that the build order (\u00a716: build -> bench -> publish -> dogfood) places AFTER this bench, and the build claims none of it (README 'Not tested / not built', manifest not_tested). The bench verifies the dogfood SHAPE that ships \u2014 the cetech_fleet seed fixture discovers exactly once and reconciles into the inventory (C15). Backlog B-CEN-4: produce the live fleet export in the dogfood loop post-bench.",
  "OBSERVATION (backlog B-CEN-2, low): source claims render VERBATIM inside claims_as_recorded_by_source \u2014 including, when a source's own data carries them, vendor risk/verdict words (N1 plants 'risk_score: 92' + 'non-compliant' and both appear, attributed, inside the claims carrier). \u00a77.5 sanctions this ('Census records the report; the report's truth is the source's') and \u00a77.6 sets no quarantine duty for Census (the lint duty is Crosswalk's, \u00a76.7), so this is not a \u00a77.6 failure \u2014 but a render-time lint for claim carriers in the Codex/Blackbox pattern would harden \u00a72.2 defense in depth. The structural law the N-check turns on holds: vendor fields are NEVER promoted to Census fields \u2014 no item-level risk/verdict key exists and status comes only from the closed \u00a77.1 vocabulary.",
  "OBSERVATION: census_diff 'changed' includes items re-seen by a later discovery run whose rendered record moved (new discovery event / last_seen) even when from_status == to_status. Defensible reading of \u00a77.4 ('what appeared, vanished, changed' \u2014 the record did change); status deltas are carried explicitly on every changed entry, so no reader is misled. Not a defect.",
  "N-check import leg, stated honestly: the file-import adapter reads fixture snapshots from the product's own fixtures/ tree, which the bench may not write (U8 isolation). The incumbent-shaped leg therefore runs as (a) the shipped file-import fixture discovered over the wire, and (b) bench-planted vendor-shaped rows in the bench state file \u2014 with NO discovery event (must not render anywhere) and with an import event (must render only as attributed claims, never as Census verdicts). A writable-import-path bench would need a product fixture-injection seam that v0 does not offer; recorded, not worked around.",
  "Run 1 FAILED card retained append-only: its sole fail was a BENCH-SUITE defect \u2014 the U5 probe's raw-exception text list included 'must be a string', which is a substring of the product's own NAMED refusal ('ARGUMENT_TYPE: as_of must be a string, got int'), so two correctly-named refusals were misread as exception escapes. Suite probe fixed (raw-escape detection now keys on Traceback / invalid literal / unhashable / INTERNAL_GUARD); no product code was touched between runs. Run 2 is the standing card.",
  "U1 is na: Census v0 local has NO credential layer by design (stdio process boundary is the boundary, the standing house treatment \u2014 cf. Docket); there is no auth surface to enforce or to leak through. Hosted/multi-tenant auth is in the manifest's not_tested."
 ],
 "history": "append-only; prior runs retained in results/"
}