{
  "schemaVersion": 1,
  "kind": "preregistration",
  "experiment": {
    "id": "EXP 007",
    "slug": "blueprint-floor",
    "title": "Which of your gate's rules need a model at all?",
    "summary": "For every rule the eight plugins ship that meets the inclusion test (51 items excluded, listed; hunch's 1,011 spec rules sampled 30), how much could a deterministic checker decide on its own, before any model is asked?",
    "status": "pre-registered",
    "statusText": "Pre-registered, not yet run",
    "authoredOn": "2026-09-30",
    "note": "This record fixes stage 1, the census, before any census call is made: the rules, the translator's inputs and its output, the checks that can only lower its answer, the scorer, the controls and the bar that would refute the premise. Stage 2, the cascade with Jev, is pre-registered by a dated amendment before any paid Jev call."
  },
  "question": "Take the rules that eight listed Jev plugins ship with their own code. For each rule, can a deterministic static checker (bce-engine 0.3.1, no model) decide it as written (expressible), decide a strict part of it and leave the rest to a model (partial), or decide no non-trivial part of it (not)? Per plugin, what share of its rules is expressible, and what is the median share across the plugins?",
  "stage": "1 of 2 (census); stage 2 pre-registered by amendment before any paid Jev call",
  "lineage": {
    "exp005": {
      "resultsSha256": "7388556049b7639e2a251edcf3fb8feb782213b78e71a02cddb687f12b09dccd",
      "lintMissedRed": 0,
      "redItems": 30,
      "finding": "In EXP 005 a model-free line linter written from the same seven architecture rules missed none of the 30 drift items, and Jev missed one, so its criterion against the better model-free baseline was refuted. Those rules were ones a static check can decide."
    },
    "motivation": "If many of the rules a gate asks a model about are decidable by a static check, a gate could settle those first, for nothing, and ask the model only about the rest. EXP 007 first counts how many such rules the gates people actually ship contain."
  },
  "plugins": [
    {
      "plugin": "hunch",
      "repo": "Kelbie/hunch",
      "sha": "c2c680ed2c12c42c8a1b668a4b0b0858c5f463a6",
      "license": "MIT",
      "copyright": "Copyright (c) 2026 Kelbie",
      "rulesFile": "experiments/blueprint-floor/rules/hunch.json",
      "rulesFileSha256": "3a3877d4e2f9ce977b609695a71c7e5abe99ae989a60bc094fa5971cb1ef3455",
      "primary": 8,
      "secondary": 30,
      "excluded": 0
    },
    {
      "plugin": "jev-pref",
      "repo": "doeixd/jev-pref",
      "sha": "9d77ea6069123a0b3eedf465ec39781842722b0a",
      "license": "MIT",
      "copyright": "Copyright (c) 2026 jev-pref contributors",
      "rulesFile": "experiments/blueprint-floor/rules/jev-pref.json",
      "rulesFileSha256": "0c865bc3d55227ce8690ddcb2d66ffb082d8564fa74a59dc443e68863cf72639",
      "primary": 4,
      "secondary": 0,
      "excluded": 0
    },
    {
      "plugin": "abide",
      "repo": "coldteadotai/abide",
      "sha": "ea6d0976a0cbac70f71a460ece348bd68d777350",
      "license": "MIT",
      "copyright": "Copyright (c) 2026 Coldtea AI",
      "rulesFile": "experiments/blueprint-floor/rules/abide.json",
      "rulesFileSha256": "68160f8b5c01da7551183b91933474b992810185d5c53ce8adc49727ae2fb7d0",
      "primary": 43,
      "secondary": 0,
      "excluded": 0
    },
    {
      "plugin": "limpet",
      "repo": "noplan-inc/limpet",
      "sha": "7a841b006900cb48df74ad68167dbed17afc504f",
      "license": "MIT",
      "copyright": "Copyright (c) 2026 no plan inc.",
      "rulesFile": "experiments/blueprint-floor/rules/limpet.json",
      "rulesFileSha256": "17e93bdde655e68ad8838f50f651f66c7d1ac90db88d2ca5821a28a76f43e172",
      "primary": 10,
      "secondary": 0,
      "excluded": 0
    },
    {
      "plugin": "jev-belay",
      "repo": "valentynkit/jev-belay",
      "sha": "ef719db7eaadc56aa4def86c4da4ffff5bcbca35",
      "license": "MIT",
      "copyright": "Copyright (c) 2026 Valentyn Kit",
      "rulesFile": "experiments/blueprint-floor/rules/jev-belay.json",
      "rulesFileSha256": "ef35a1382489f9491931c5939e33d22f0f875c9e2d085d579bc81a71c5465134",
      "primary": 0,
      "secondary": 0,
      "excluded": 4
    },
    {
      "plugin": "jev-engineering",
      "repo": "eugeniughelbur/jev-engineering",
      "sha": "82655a6d16cedf6e31c0e493cc701e20c8d06798",
      "license": "MIT",
      "copyright": "Copyright (c) 2026 Eugeniu Ghelbur",
      "rulesFile": "experiments/blueprint-floor/rules/jev-engineering.json",
      "rulesFileSha256": "163e64a1113d83a215b0b632938659dc20a2cf0adbcb762088f00858b1fde849",
      "primary": 16,
      "secondary": 0,
      "excluded": 23
    },
    {
      "plugin": "pi-verdict",
      "repo": "jesset/pi-verdict",
      "sha": "1b37e5f2dff6414f31a009592074ce528453f0e1",
      "license": "MIT",
      "copyright": "Copyright (c) 2026 Jesset",
      "rulesFile": "experiments/blueprint-floor/rules/pi-verdict.json",
      "rulesFileSha256": "a72b20ca299fad54ed8d4a6970e129a0aee24492440accb81e478c0eea0d639c",
      "primary": 41,
      "secondary": 0,
      "excluded": 4
    },
    {
      "plugin": "jev-axi",
      "repo": "shiftynick/jev-axi",
      "sha": "044fae73a05d5699c4b5c47073f1ffc29d9aa82d",
      "license": "MIT",
      "copyright": "Copyright (c) 2026 Nicholas Underwood (shiftynick)",
      "rulesFile": "experiments/blueprint-floor/rules/jev-axi.json",
      "rulesFileSha256": "b6856f2e723a3c76d6ac5aac7377b44585136cd66a4aeb0cf27e83a389a2e375",
      "primary": 23,
      "secondary": 0,
      "excluded": 20
    }
  ],
  "excludedPlugins": [
    {
      "plugin": "DiffJury",
      "reason": "no license"
    },
    {
      "plugin": "Blink",
      "reason": "no public repository or license found"
    },
    {
      "plugin": "jev-guard",
      "reason": "MIT, but not named by the council verdict; kept out to hold the council's 6 to 8 range (out of scope, not a finding)"
    }
  ],
  "selection": {
    "file": "experiments/blueprint-floor/rules/selection.json",
    "inclusionTest": "An item is a rule of the primary stratum when its answer by itself gates, blocks, flags or denies an action or a change. Locators, triage, category, severity and kind classifiers, score-only dials that feed a combined decision, and templated questions with runtime placeholders are excluded and listed with their reasons. Allow-rules (fast paths, allowlists) are excluded: the bce vocabulary is forbid-only and an allow-rule is a different decision.",
    "granularity": "One regex, one question, one prose line or one rubric entry is one rule.",
    "textField": "The translator sees one field per rule: the field named textField for its source. Every other field of the source item is stored under withheld and never reaches a translator or adjudicator prompt.",
    "inputKinds": "The input kind is assigned per source hook or event, never per rule: a pull-request or commit diff is diff, a pre-tool-use call is toolCall, a stop hook or a session transcript slice is stopTranscript, a document handed to a scanner is file.",
    "regexFlags": "The flags of a regex rule are recorded in flags. bce forbiddenPattern compiles its pattern without flags. An /i rule is made case-insensitive by construction: the adapter lower-cases its input before the checker runs, and the mechanical flags check refuses any pattern with an upper-case letter, literal or escaped, or an escape it cannot verify (which could never match); a refusal lowers the class like teeth (failedCheck flags). g and d change no verdict. Any other flag (m, s, u, v, y) cannot be verified mechanically: an expressible answer (which by the schema has no residual) with any other flag (m, s, u, v, y) drops to not, and such a rule reaches partial only when the translator itself answers partial with a residual.",
    "hunchSecondary": "hunch's specification rules (rules/bips-spec.json, nips-spec.json, nuts-spec.json) are a secondary stratum: a seeded sample of 30 (seed 7007; the sampling code is committed in extract.mjs), reported separately and never in the median."
  },
  "files": {
    "experiments/blueprint-floor/adapter.mjs": "d35854970e69ff73424bff23c7a480b566a2893e4d82953635ccc835ea30cfb2",
    "experiments/blueprint-floor/whitelist.mjs": "ccdebf36d6344842de0903876ada39dbf02a228cf3a98c2ba1871bd5f05d2300",
    "experiments/blueprint-floor/whitelist.json": "bf8115d21d3c34771d7a9370e6da73141b028aa978ca0492e8a96749cbecf54d",
    "experiments/blueprint-floor/contract.md": "62a0fde91db4f74bb4ab4d1173d72f4f0469a3a67b9381bf5c01eec8b4b48178",
    "experiments/blueprint-floor/contract-module-graph.md": "ba244156d2bfafe6f4ecbbef734a9a6ff457f606ae1544cb5c97cd25daff06bc",
    "experiments/blueprint-floor/prompts/translator.md": "c2b016bf0b2f0dd81655fa57f04ad79201760058ef1fec8c772953c4af237fb6",
    "experiments/blueprint-floor/prompts/adjudicator.md": "b67fa1081ec39c3258b2139d04100cf85bde8e132c82ddf4d0ab901be64e9ee4",
    "experiments/blueprint-floor/protocol.mjs": "ec6bfe573e6eda48784cea76fc1f57d84c55f2e535845c990afbe75fce0026bf",
    "experiments/blueprint-floor/protocol.md": "cfb567f26f0c3c415c94b4cc298f286257c2ad0056dfed20e9c3c9dd7a9a876a",
    "experiments/blueprint-floor/scorer.mjs": "f2113f3666ec288aebc420750d9b16c3b2eb8fac2078296acad1afdee0d2f351",
    "experiments/blueprint-floor/fixtures/scorer.json": "6311bfd945d162906bc675c98be3e211f57d3a42f6f69e478164294a2ba304f1",
    "experiments/blueprint-floor/engine-matrix.json": "fdcedad2e99b562e1f0652e35daf48f143976aa2d9654b0e435b8a85a2ca5e9f",
    "experiments/blueprint-floor/matrix.mjs": "dbf413ab7348440410585bf4c11d0575d5c21e5a0fcb32fc60710c3df0177b73",
    "experiments/blueprint-floor/extract.mjs": "62c3dc7c2d8912855b8f6350fdffc998eb4f8e406007ff040842b10f702b7164",
    "experiments/blueprint-floor/rules/selection.json": "049193ecaaee466bad0bbaaa335efb49cf5b76ddcd489d2bdf6dca6bf3e6be65",
    "experiments/blueprint-floor/rules/SELECTION.md": "cda94e533e64a48d6b8afa7c1f2806a3e3e556b997a39d936036f19a4705f1d0",
    "experiments/blueprint-floor/rules/hunch.json": "3a3877d4e2f9ce977b609695a71c7e5abe99ae989a60bc094fa5971cb1ef3455",
    "experiments/blueprint-floor/rules/jev-pref.json": "0c865bc3d55227ce8690ddcb2d66ffb082d8564fa74a59dc443e68863cf72639",
    "experiments/blueprint-floor/rules/abide.json": "68160f8b5c01da7551183b91933474b992810185d5c53ce8adc49727ae2fb7d0",
    "experiments/blueprint-floor/rules/limpet.json": "17e93bdde655e68ad8838f50f651f66c7d1ac90db88d2ca5821a28a76f43e172",
    "experiments/blueprint-floor/rules/jev-belay.json": "ef35a1382489f9491931c5939e33d22f0f875c9e2d085d579bc81a71c5465134",
    "experiments/blueprint-floor/rules/jev-engineering.json": "163e64a1113d83a215b0b632938659dc20a2cf0adbcb762088f00858b1fde849",
    "experiments/blueprint-floor/rules/pi-verdict.json": "a72b20ca299fad54ed8d4a6970e129a0aee24492440accb81e478c0eea0d639c",
    "experiments/blueprint-floor/rules/jev-axi.json": "b6856f2e723a3c76d6ac5aac7377b44585136cd66a4aeb0cf27e83a389a2e375",
    "experiments/blueprint-floor/controls/positive.json": "6d9c6ea150aaeecea4492f3fac63a72ab6aa5cb7bdd783dfdb674a42cc8bab88",
    "experiments/blueprint-floor/controls/negative.json": "ad0b6bc24d8d8679f18c538a4e4ba2224bb4d54eb0e028852ba394b6c54f6b2c",
    "experiments/jev-gate/bce-contract.mjs": "ca9ea8860b5fe5502c32b102c3db5fcc19e3474bdde9cc4104d3da89364f2004",
    "experiments/jev-gate/rules.txt": "87186d652a7cf8a4c8e71966236c4fe6837c4bd22799fc49a15d437a083b2562",
    "scripts/blueprint-floor-rules.mjs": "262e732eb9bb0f3f155369416ddb489e93508f0f780988b4999f5a22117e3c34",
    "package.json": "f6727111f219ee47f40d77bd7a5a4d2902cb2bb8062d8993ede710d31f40817d",
    "pnpm-lock.yaml": "3d04442a268a1f5dbb0fc852ece2ff0044a229ae0e6688f5acbe8fabbb06648d"
  },
  "engine": {
    "package": "bce-engine",
    "version": "0.3.1",
    "files": {
      "package.json": "27e9667bda7c7564924ba9f13d4c8dae086f220f207259dc7e6d12fa9b7e389a",
      "src/report.ts": "ec4bcb7f7cca250c12caf64ace6150764267ef255a9a182ed821394079246aeb",
      "src/schema.ts": "d7b2347570373b2291f3d179809b98f95f12b34675e0be48ab75e00bf5b04b85",
      "src/extractors.ts": "f48047f6955d3d788a6ac4376a2ac0cd9dfcf2ee348535407df3dbf9a4fc2a8f",
      "dist/cli.js": "6ffe4c23913a6813b9d9d4a2f4ca29b5405a65bbcec9cb4489cfef0326a52648"
    },
    "pluginVocabulary": [
      "forbiddenDependency",
      "forbiddenFile",
      "forbiddenPattern",
      "forbiddenEgress"
    ],
    "controlVocabulary": [
      "forbiddenDependency",
      "requiredDependency",
      "requiredComponent",
      "forbiddenPath",
      "forbiddenFile",
      "forbiddenPattern"
    ],
    "excludedTypes": [
      "behavioralInvariant",
      "requiredEvidence",
      "minimumMetric",
      "customPolicy"
    ],
    "rule": "The vocabulary is the constraint types bce-engine 0.3.1's evaluate() implements and grades statically on the pinned profile, derived from the installed engine source and cited by file and line in whitelist.json with the engine files' sha256. package.json and the lockfile pin 0.3.1 and are unchanged; any engine change is an operator decision.",
    "customPolicy": "customPolicy is declared by 0.3.1's schema but evaluate() has no branch for it, so it enforces nothing; the adapter refuses it (and every other type outside the vocabulary) with a typed error."
  },
  "adapter": {
    "profiles": "Plugin rules run on the plugin-surface profile with the ast extractor, scanning .floor/** and src/**/*.ts for diff inputs and .floor/** otherwise, with minFiles equal to the files the engine resolves for the materialised input. The positive controls run as EXP 005 ran them: typescript-module-graph over src/**/*.ts. Scoring reuses EXP 005's contract (bce-contract.mjs: materialise, run, interpret), imported, not copied.",
    "inputs": [
      "diff: EXP 005's base tree after the patch, plus .floor/diff.patch (verbatim), .floor/added-lines.txt (the added lines with a +++ <path> header per changed file; the path without a b/ prefix or tab-separated date; deleted files contribute nothing) and .floor/added/<path> (each changed file's added lines alone, so a file-scoped rule can glob them).",
      "toolCall: .floor/tool-call.json (the hook input, pretty-printed) and .floor/command.txt (tool_input.command verbatim, else empty).",
      "stopTranscript: .floor/transcript.jsonl (one event per line) and .floor/final-message.txt.",
      "file: the document at .floor/files/<path>.",
      "An /i rule is graded case-insensitively by construction: its input's .floor files and, for a diff, its scanned post-patch sources are lower-cased before the checker runs (paths are not); judge and teeth both see the folded input."
    ],
    "judge": "judge() takes the rule's final class: expressible gives pass or fail from the engine; partial gives fail from the engine and otherwise abstains; not always abstains. A rule with an empty constraint set abstains.",
    "teeth": "teeth(constraints, {violating, compliant}) passes only if every violating probe (one input or a list) makes the constraints FAIL, the compliant probe makes them PASS, and each constraint alone makes at least one violating probe FAIL, through the adapter and the real engine. A vacuous constraint fails teeth, alone or beside a real one.",
    "base": "Every diff input is a patch against EXP 005's base tree (experiments/jev-gate/base), committed as EXP 005's scoring contract commits a tree (baseCommit; baseTree is its git tree id). Its file list, not its contents, is in the translator's contract, so probes add files.",
    "baseCommit": "2c55f16e20ccc27e60d5c53e25661acafb82133f",
    "baseTree": "957b5e10c099ef2c86bb4543a8560aba59290d62"
  },
  "classes": {
    "expressible": "the constraints alone decide the rule as written on every input of its kind (no residual)",
    "partial": "the constraints decide a strict, non-empty subset (e.g. the flagrant forms) and a residual question is required for the rest",
    "not": "no whitelisted constraint decides any non-trivial part"
  },
  "translator": {
    "input": "Exactly: an opaque id (item-<first 12 hex of sha256(\"exp007-census-v1:\" + ruleId)>, mapped back to the ruleId by the runner), the rule's verbatim text (the single text field pinned per plugin in selection.json), its input kind, its regex flags when it is a regex, the rule's match target and application condition as an 'Applies to' line where the source defines one (the context field, one factual sentence per source group plus the rule's own file globs, where a glob that names the rule's own plugin shows that name as <tool>), and the materialisation contract with the accepted constraint types (the whitelist) and one generic example each (contract.md; contract-module-graph.md for the positive controls); plus the pinned system prompt.",
    "never": "Any case, any label, any plugin evaluation file, abide's own type field, another rule's class, or any result. Every other field of a source item is stored under withheld in the rule file and never rendered into a prompt.",
    "output": "One JSON object: {ruleId, class: expressible | partial | not, constraints: [bce constraint objects], coverage, residual (a yes/no question when the class is partial or not, otherwise empty), probes: {violating, compliant} (empty when the class is not), rationale of at most 80 words}.",
    "blindness": "The prompt builder (protocol.mjs) reads exactly five fields of a rule, {ruleId, text, inputKind, flags, context}, and shows the ruleId only as the opaque id. A test hands it a rule whose other fields throw when read, and renders both prompts for every rule to show that no plugin name, no stratum or control word and no segment of the ruleId appears outside the rule's own text (six generic words of the fixed contract and system prompt are listed as exceptions)."
  },
  "mechanical": {
    "checks": [
      "the answer is one JSON object with a valid class, matching the output schema",
      "every constraint type is in the vocabulary",
      "bce validate passes on a blueprint holding the constraints",
      "for a regex rule with /i, the flags check: no forbiddenPattern carries an upper-case letter, literal or escaped, nor an escape the check cannot verify (an identity escape of a letter, \\p, \\P, \\k) (the adapter lower-cases an /i rule's input, so such a letter could never match); g and d change no verdict; any other flag cannot be verified mechanically: an expressible answer (which by the schema has no residual) with any other flag (m, s, u, v, y) drops to not, and such a rule reaches partial only when the translator itself answers partial with a residual",
      "teeth passes through the adapter: every violating probe makes the constraints FAIL, the compliant probe makes them PASS, and each constraint alone makes at least one violating probe FAIL",
      "a pinned class cap from the rule's source group (pi-verdict's 8 write-only path rules: at most partial, because a line checker cannot join a tool's name to its path); an expressible answer, which by the schema has no residual, drops to not, so such a rule reaches partial only when the translator itself answers partial with a residual"
    ],
    "downgrade": "The first failing check lowers the class once: expressible becomes partial if a residual was given, else not; partial becomes not. Each downgrade is recorded with the failing check.",
    "engineLimit": "A pattern the engine's safe-compile guard refuses fails validation and is counted in a separate engine-limit category.",
    "error": "An answer that is not a JSON object with a valid class, a timeout, a model id other than the pin, or any other harness failure is class error, counted as not (conservative) and listed."
  },
  "adjudicator": {
    "input": "A separate process on a different pinned model, no tools. Exactly what the prompt builder sends: the pinned system prompt; the same opaque id; the input kind; the 'Applies to' line (the rule's match target and application condition, where the source defines one); the regex flags (regex rules only); the rule's verbatim text; the translator's answer verbatim; a mechanical summary with schema, vocabulary, the checker's validation, teeth, the flags check (flagged rules only), the translator's class and the class after the checks; the flag-semantics sentence (flagged rules only); and the stated class to confirm or dispute. No case.",
    "output": "{ruleId, verdict: confirm | dispute, proposedClass, reason of at most 80 words}.",
    "finalClass": "Confirmed: the class after the mechanical checks. Disputed: the lower of that class and the proposed class (not < partial < expressible), so a dispute can only lower expressibility.",
    "agreement": "Translator-adjudicator agreement is reported as Cohen's kappa over the three classes, with the number of rules it is computed on and the list of disputes: rules whose translator or adjudicator call ended in error are excluded; computed over all census rules including controls."
  },
  "controls": {
    "positive": "EXP 005 rules.txt rules 2 to 8, verbatim (controls/positive.json): the EXP 005 blueprint enforces each of them with bce 0.3.1.",
    "negative": "Six semantic control rules, each needing the meaning or intent of the input (controls/negative.json), graded on the same path as the plugin rules.",
    "calibrationBar": "At least 6 of 7 positive controls final expressible or partial, and at most 1 of 6 negative controls final expressible.",
    "miss": "A miss is published and the census reported as \"translator uncalibrated\"; the run continues and nothing is silently re-run. Controls are outside every median.",
    "counts": {
      "positive": 7,
      "negative": 6
    }
  },
  "metrics": [
    {
      "id": "expressibleShare",
      "definition": "Per plugin: final expressible / rules in its primary stratum, with n."
    },
    {
      "id": "partialShare",
      "definition": "Per plugin: final partial / rules in its primary stratum, reported beside the expressible share."
    },
    {
      "id": "headline",
      "definition": "The median across plugins of the expressible share (strict). A plugin whose primary stratum is empty has no share: it is listed and not counted."
    },
    {
      "id": "preDisputeMedian",
      "definition": "The same median computed on the classes after the mechanical checks and before the adjudicator, reported because disputes can only lower."
    },
    {
      "id": "sensitivity",
      "definition": "The median with partial counted as 0.5; reported, not decisive."
    },
    {
      "id": "secondary",
      "definition": "hunch's secondary sample: its class counts and expressible share, reported separately."
    },
    {
      "id": "agreement",
      "definition": "Cohen's kappa between the translator's class after the mechanical checks and the adjudicator's class, over the three classes, with n and the dispute list: rules whose translator or adjudicator call ended in error are excluded; computed over all census rules including controls."
    },
    {
      "id": "abideComparison",
      "definition": "For abide's rules, agreement of the final class with abide's own type field (lint ~ expressible, model ~ partial or not); unenforceable and deferred reported as they are. The type field is read only by this comparison. Caution: the presence and shape of a rule's \"Applies to\" line correlates with abide's own type (its model rules carry a \"Checked ...\" sentence, its lint rules a scope only, unenforceable and deferred rules none), so the translator can partly infer the type; the agreement is reported with that caveat."
    },
    {
      "id": "lists",
      "definition": "Downgrades with their failing check, engine-limit rules, and errors, each listed by ruleId."
    },
    {
      "id": "breakdown",
      "definition": "pi-verdict's command (bash), path and question rules, each with its own counts and expressible share, reported apart; not part of the median."
    }
  ],
  "census": {
    "primaryRules": 145,
    "secondaryRules": 30,
    "secondaryPopulation": 1011,
    "controls": 13,
    "rules": 188,
    "calls": 376,
    "pluginsInMedian": 7,
    "pluginsWithoutRules": [
      "jev-belay"
    ]
  },
  "calls": {
    "translatorModel": "claude-opus-5-5",
    "adjudicatorModel": "claude-sonnet-5",
    "client": "Claude Code",
    "clientVersion": "2.1.280",
    "effort": "high",
    "attempts": 1,
    "command": "claude -p --model <pin> --effort high --tools \"\" --strict-mcp-config --setting-sources project --no-session-persistence --system-prompt-file <pinned prompt file> --output-format json",
    "workingDirectory": "A fresh empty temporary directory outside any repository (no CLAUDE.md in its ancestors), which is also the child's TMPDIR.",
    "environment": "Built from an allowlist: HOME, PATH, USER, LOGNAME, LANG, LC_*, SHELL, TERM and TMPDIR; nothing else (no CLAUDE_*, CLAUDECODE, ODIN_*, *_KEY, *_TOKEN or *_SECRET). No fallback model. API-billing environment variables are refused.",
    "billing": "Calls run under subscription auth. total_cost_usd is then an API-equivalent figure, and the $100 cap applies to that figure, not to cash (the convention of EXP 005 and EXP 006).",
    "modelAssertion": "The runner asserts that the result's modelUsage has exactly one key and that it equals the pin; otherwise the call is an error (charged its cost, class error, counted as not).",
    "canary": "Before any counted call, one practice call per model asks what experiment, repository, rule set, label or prior conversation is in its context; an answer naming a pinned term fails the canary and stops the run.",
    "bareRejected": "The client's --bare mode is not used: it forces API-key authentication, which this setup does not use."
  },
  "killCriteria": {
    "stage1": "Median expressible share below 25%: the premise is refuted, stage 2 is cancelled, and the census is the result.",
    "verbatim": "Kill criteria (pre-registered, published either way): median expressible share < 25% → premise refuted, census is the result;\n  cascade adds false rejects > 2 pts over plugin-alone, or avoids < 20% of Jev calls → refuted.",
    "discriminatingNegativesVerbatim": "Discriminating negatives: sham floor must collapse to Jev-alone; floor must abstain on ≥95% of non-expressible rules;\n  lint-floor tie is published as \"any deterministic floor works\".",
    "source": "The council verdict adopted by the founder on 2026-09-30, quoted verbatim, line break included. The stage-2 criteria and negatives are stated now and bind the stage-2 amendment.",
    "publication": "Every outcome is published, including \"premise refuted\" and \"translator uncalibrated\"."
  },
  "spend": {
    "capUsd": 100,
    "censusCeilingUsd": 40,
    "ledger": "experiments/blueprint-floor/spend-ledger.jsonl",
    "rules": [
      "Every metered paid call of EXP 007 (census translator and adjudicator, labellers, Jev, probes, canaries, dry runs) appends one line to the ledger, in dollars to 7 decimal places.",
      "A call whose cost is unknown is charged its upper bound; there is never a $0 line; an unpaid round gets no line.",
      "The census runner refuses a call when the spend so far plus the reserve would exceed the $40 census ceiling; exceeding the $100 cap is an operator decision.",
      "Session sub-agent labour (implementers, refuters) is not metered per call; it is disclosed with token counts and never presented as $0."
    ],
    "bundle1": "This record was built with no model call and no paid call: spend $0.0000000, and no ledger line.",
    "plain": "Stage 1 calls no Jev model. Two Claude calls per rule, a translator and an independent adjudicator, are metered against the experiment's $100 cap.",
    "wording": "\"$0 / no model\" in COUNCIL-VERDICT STAGE 1 and STEER S5 = no Jev and no paid call before the stage-1 prereg is live; the census translator + adjudicator are METERED model calls under the $100 cap (council's cost line counts them as agent labour).",
    "unknownCost": "The unknown-cost bound is three times the largest observed cost per role, at least $0.5000000."
  },
  "notBefore": "No counted call before the merge time of the odin-rnd pull request that adds this file (gh pr view <n> -R odin-labs-ai/odin-rnd --json mergedAt, UTC), and only while the site serves this record byte for byte.",
  "runnerGuard": "Every counted-call runner refuses unless the pre-registration on disk has the sha256 frozen at run start, which must equal the one published.",
  "limits": [
    "The target language is bce-engine 0.3.1's static vocabulary and nothing more: four constraint types for plugin rules. A newer engine or a different checker may decide more.",
    "The adapter maps non-diff inputs to files (a tool call to JSON and command text, a transcript to JSON lines and a final message, a document to a file). That mapping is a choice we made; another mapping could change what is expressible.",
    "The checker parses every read file as TypeScript, the .floor files included [m01, m03, m07, m15]. forbiddenDependency fires where that text parses as code: import, require and import() in plain prose [m01], a final message [m03], a command [m07] and the removed lines of .floor/diff.patch [m15]; not inside comments or string literals [m13, m14], so never from transcript.jsonl or tool-call.json values [m05, m06] or a quoted shell argument [m08], and not after an apostrophe earlier on a prose line [m02]; a type-only import never fires [m12]. forbiddenEgress fires on fetch, http.request, request(), axios.get, new Client() and got with a literal host [m18, m19, m20, m21, m22, m23], in prose too [m27], not on curl, lookalike hosts, string literals or non-literal hosts [m24, m26, m28, m38], and takes no file scope [m27]. A constraint that should judge only what a change adds must be scoped to post-patch src/** or .floor/added/** [m16, m17]. For tool calls, transcripts and documents, forbiddenPattern and forbiddenFile remain the precise vocabulary.",
    "A partial floor still needs a model for its residual; expressible is the only class that removes the model for that rule.",
    "The translator is itself a model. The adjudicator and the mechanical checks guard it, but teeth is self-consistency (the translator writes both the constraint and its probes), not proof over every input.",
    "The dispute rule can only lower a class, which biases the census toward the kill criterion; the median before disputes is reported beside it.",
    "Some plugins have few rules (jev-pref has 4), so their shares move in large steps.",
    "Which items count as rules is our application of the pinned inclusion test. At the pin jev-belay has no rule that decides by itself (its four questions feed one combined decision), so its primary stratum is empty and the median runs over the other plugins.",
    "The positive controls are shown the module-graph contract (their materialisation differs), so a translator could tell them apart from plugin rules; the controls are outside every median.",
    "A line checker cannot join a tool's name to its path argument or resolve the working directory and real path, so pi-verdict's 8 write-only path rules are capped at partial mechanically: an expressible answer (no residual) drops to not, and they reach partial only when the translator answers partial with a residual. They can never be expressible, so the cap moves the partial-as-0.5 sensitivity figure, not the strict median; the adjudicator is told the condition in the rule's 'Applies to' line.",
    "The positive controls run on the module-graph path, so they do not calibrate the plugin-surface diff path the plugin rules take.",
    "Blinding hides names, not families: input kind and regex-versus-prose correlate with the plugin (limpet's rules are all stopTranscript; toolCall regexes come only from pi-verdict and jev-engineering), so a translator can guess a rule's family.",
    "One rule's verbatim text names its own plugin (abide/key-write-targets); the blindness check excludes a rule's own text, which is shown verbatim by design.",
    "The negative controls were written by the experimenters; the positive controls come from EXP 005, whose rules were written for bce.",
    "Case folding uses JavaScript's toLowerCase (Unicode default) and the source regexes are JavaScript /i (pi-verdict); the two fold a few special cases differently (e.g. the Turkish dotted I, the German sharp s), so a rare input could be matched by one and not the other.",
    "Each line is matched on its own, so a construct spread over several lines (a multi-line signature, a string split across lines) cannot be matched as one [m31].",
    "The checker matches one line at a time [m31], while the source regexes (and jev-engineering's re.search) run over the whole command; a multi-line command can be matched differently.",
    "jev-engineering's patterns are Python regular expressions and the checker compiles JavaScript ones; where the dialects differ, only the mechanical checks on the translator's own probes can catch it, and only when a probe exercises the difference.",
    "Probe patches can only add files, because the contract lists the base tree's files but not their contents.",
    "One translator model, one adjudicator model, one attempt per rule and one client version.",
    "Upstream plugin labels, where stage 2 uses them, are written by each plugin's authors and are not independent.",
    "pi-verdict's command rules and path rules are also reported apart; that breakdown does not change the median.",
    "The \"Applies to\" line's presence and shape correlate with abide's own type (model rules carry a \"Checked ...\" sentence, lint rules a scope only, unenforceable and deferred none); the abide comparison is reported with that caveat."
  ],
  "sources": [
    {
      "id": "awesome",
      "label": "awesome-jev-tools",
      "url": "https://github.com/v-modal/awesome-jev-tools",
      "claim": "The list the eight plugins were taken from."
    },
    {
      "id": "bce",
      "label": "bce (blueprint-conformance/bce)",
      "url": "https://github.com/blueprint-conformance/bce",
      "claim": "The checker whose 0.3.1 release is the target vocabulary."
    },
    {
      "id": "bce-npm",
      "label": "bce-engine 0.3.1 on npm",
      "url": "https://www.npmjs.com/package/bce-engine/v/0.3.1",
      "claim": "The released package this repository pins."
    },
    {
      "id": "exp005",
      "label": "EXP 005, Jev as a fast gate",
      "url": "https://odin-labs-ai.github.io/odin-rnd/journal/jev-as-a-fast-gate.html",
      "claim": "The experiment whose linter finding motivates this one, and whose base tree and controls are reused."
    }
  ],
  "engineMatrix": {
    "file": "experiments/blueprint-floor/engine-matrix.json",
    "url": "https://github.com/odin-labs-ai/odin-rnd/blob/main/experiments/blueprint-floor/engine-matrix.json",
    "statement": "Bracketed ids such as [m01] refer to rows of the engine matrix, each run through the real checker in the repository's tests."
  }
}
