Part V · Contracts · Plate 07
Soma rubric · gate exit codes
5. Soma → Thalamus System 1 Oracle and the cns gate Exit Contract (S4, 2026-10-31)
5.1 Instrument note: S4 verdicts are not Series 15/16 verdicts
The Series 15/16 rubric pass rates were produced by experiment scripts that sent model: "jev-latest" (an alias of the clef-flash container at the time) directly to the System 1 server or through spark_lb.py, never through Thalamus, with re-authored task questions and hand-written criteria (run_fleet_benchmark.py:462-570, run_clef_flash_rubric). S4 verdicts come from soma concerns check --systemone: through Thalamus, with the model named by /admin/v1/status, the concern's question text verbatim, and criteria derived only from expect. They are a different instrument. A Series 15/16 number must not be compared with, or used to calibrate, an S4 verdict.
5.2 Request (writer: Soma soma-systemone; reader: Thalamus /v1/systemone, proxied verbatim to the System 1 server)
THALAMUS_URL is required: Soma names no model host, so unset means not evaluated. There is no default relay address (§1.1). --systemone-timeout-ms (default 45000) is one budget measured from the start of soma concerns check: the status read and the call share its deadline.
GET ${THALAMUS_URL}/admin/v1/status. The model ismodels[0]of the first (byname) entry ofplanes.verification[]withhealthy == true,draining == false,"system1.decide"incapabilities, and a non-emptymodels. None: not evaluated./v1/classify(the rerank handler) is never called.-
POST ${THALAMUS_URL}/v1/systemone, headerx-request-id: <32 hex>, body:{"model": "<models[0]>", "state": {"git_diff": "<unified diff base..head or working tree>", "changed_files": "<paths, newline-separated>"}, "questions": {"<concern-id>/<n>": {"type": "noul", "instructions": "<question text verbatim>", "criteria": {"true": "yes", "false": "no"}}}}<n>is 1-based within the concern. Only questions of concerns that fired are sent; nothing fired means no call (rubric: vacuous). Section 1.2's example keyquestionis not what Soma sends; Soma sendsinstructions+criteria, as Series 16 did. -
Polarity. A Questions bullet may start with
[expect: yes]or[expect: no](defaultyes). The marker is removed from the text. This is the one accepted syntax (revision 4): exactly[expect: yes]or[expect: no], lowercase, one space after the colon, first in the bullet, followed by whitespace and the question. Any other text that starts like a marker ([expect, in any case or spacing) anywhere in the bullet, including a trailing... [expect: no], is anunrecognised polarity marker:soma concerns validatefails,soma concerns checkrefuses (exit 2), andsoma concerns lint --polaritylists every one and exits 2. Nothing marker-like is ever sent as question wording or read as a silentyes. The one fixed mapping (soma_systemone::criteria_for) isyes -> {true: "yes", false: "no"},no -> {true: "no", false: "yes"}; its canonical JSON{"no":{"false":"yes","true":"no"},"yes":{"false":"no","true":"yes"}}hashes toexpect_map_sha = dac6eaec67864d2e8f89f3e7df411f20d7918d24a50cf05d6c8a9a53c82fae5c.
5.3 Response and verdict
200body{"model", "answers": {"<key>": {"type": "noul", "noul": <p>}}, "usage"};noulis P(criteria.true), i.e. already on theexpectside.x-thalamus-nodenames the member that served it.- A question fails when
noul < thresholdor its answer is malformed (non-numeric, not in [0, 1], not an object). Threshold 0.50 (Series 15/16's value);--rubric-thresholdis reserved for S10. - A concern's rubric verdict is conjunctive over its questions. A rubric failure adds red; a rubric pass never clears a structural fire. With
--check,critical/warningfires are red regardless of the rubric; aquestion-severity concern is red only when its rubric fails. - A
2xxreply is read only when itscontent-typeisapplication/jsonorapplication/*+json(case and parameters ignored). Any other content type, or none, is not evaluated even when the body parses (revision 4): an HTML error page or portal is never judged. This holds for/admin/v1/statusand/v1/systemone. Thalamus' status route is axumJson(application/json);/v1/systemonepasses the System 1 server's header through. This contract does not establish that a live upstream response has been observed. - Not evaluated (exit 3): status unreachable / non-2xx / not JSON / not served as JSON, no healthy member,
/v1/systemoneunreachable / timeout (default 45 s,--systemone-timeout-ms) / non-2xx / not JSON / not served as JSON,answersabsent or empty, any requested key missing, or the verdict log unwritable (<generated_dir>/rubric-verdicts.jsonl could not be written: <error>; the answers were fetched but cannot serve S5/S7 provenance). Extra unrequested answer keys are ignored and counted.
5.4 soma concerns check exit codes and output
| Exit | Meaning |
|---|---|
0 |
Every requested oracle ran; with --check, nothing red |
1 |
With --check: a critical/warning fire, an invalidated pin, or a rubric-red concern |
2 |
Refused (bad arguments, invalid registry) |
3 |
--systemone requested and not evaluated, whatever the structural result |
Markdown output ends with ## Oracles, one line oracles: structural; rubric: not evaluated (not requested) | oracles: structural; rubric: vacuous | oracles: structural; rubric: not evaluated (<reason>) | oracles: structural, systemone; rubric: pass|fail (...), then structural: pass | structural: red (<gating concern ids>[; pinned anchor invalidated]), and fired: <n>. The structural: line (revision 4) states the structural result on its own, because exit 3 outranks it. JSON output carries oracles, rubric and structural: {red, gating, pinInvalidated}.
5.5 Verdict log (writer: Soma; readers: S7 concern ledger, S5 provenance)
<generated_dir>/rubric-verdicts.jsonl (default .soma/rubric-verdicts.jsonl, git-excluded), one row per evaluated question, appended:
{ts, concern_id, question_idx, expect, score (null when malformed), pass, delta_sha (sha256 of state.git_diff), model, threshold, expect_map_sha, thalamus_url, thalamus_node (x-thalamus-node or null), request_id (= x-request-id sent)}. Unanswered questions are not logged (the run is exit 3).
5.6 cns gate (writer of a vitals.v1 row; reader: cns status [5])
- The rubric oracle is off unless the operator enables it. Enabling it explicitly authorizes live inference for this gate path:
CNS_ORACLES=structural,rubricin the environment, or a top-leveloracles = ["structural", "rubric"]in.cns/config.toml. The environment wins over the file; an unknown oracle name is exit 3 and contacts nothing.- Only a top-level TOML key counts. One inside any
[table]is ignored and the gate printsnote: ignored the oracles key inside [table] ...; a key inside a string or comment is not a key. - Multi-line arrays, comments, quoted keys and literal strings are accepted. A duplicate key, a value that is not an array of strings, or an unterminated string or array is exit 3 with a named reason.
- Disabled: no Thalamus request of any kind (not even
/admin/v1/status); the gate printsrubric: not evaluated (disabled by default)and exits by the structural result.cns gate --systemonewithout the opt-in exits 3. This covers the Pi extension's automatic gate; no Claude hook callscns gate.
- Only a top-level TOML key counts. One inside any
- Budget. The gate answers within
CNS_GATE_BUDGET_MS(default 30000, the Pisoma_verifytool's timeout). The/admin/v1/statusprobe is paid from it (budget − elapsed − 2000ms; revision 4, previously a fixed 3 s), and soma then gets--systemone-timeout-ms = budget − elapsed − 2000measured again after the probe; under 1000 ms left at either point, the oracle is not attempted. A slow oracle therefore yields exit 3not evaluated (... timed out ...), not a caller kill. A caller--systemone-timeout-mscan only shorten it. - Soma-initialised repo (
docs/somaor.soma/codemap.md):axon indexwhen.axon/axon.dbexists, thensoma verifyandsoma concerns check --check [--axon <AXON_BIN>] [--systemone --systemone-timeout-ms <ms>] [args], all unconditionally.--checkis never dropped by caller arguments;--axon-dbis never passed. - With the opt-in, the rubric is a requested oracle (revision 4; spec point 7 corrected in cns main e7b7120 after verification finding C-1).
--systemoneis appended when the caller passes it, or when/admin/v1/statusreports a healthy System 1 member (same predicate as 5.2). Otherwise the gate printsrubric: not evaluated (<reason>)and exits 3, never 0 and neverPASSED: Thalamus unreachable, status non-2xx, not served as JSON, body not JSON, no healthy member (including a System 1 member registered only on another plane), status slower than the budget, or too little budget left. Fail-closed is the point: an operator who wants structural-only gating turns the opt-in off. Only with the opt-in off does the gate exit by the structural result alone. - With the opt-in and
THALAMUS_URLunset, the gate contacts nothing, printsrubric: not evaluated (THALAMUS_URL not set)and exits 3 (revision 3; there is no default address). - Exit
0only when every requested oracle ran and passed;1structural or rubric red (includingsoma verifyfailing);3a requested oracle was not evaluated: soma binary missing, repo not Soma-initialised,axon indexfailed, soma refused, soma exited 3, or the opted-in rubric could not run.3wins over1whichever is raised first. When both occur the final line names both:==> CNS Gate NOT EVALUATED (exit 3: <reason>; also red: <red reason>); a red that only soma saw (soma exit 3) is taken from itsstructural: red (...)line. - Appends one
vitals.v1row with thecns hookkey set plusconcerns_fired(a count, ornullwhen soma did not run),oracles_requestedandoracles_evaluated(arrays of oracle names,structuralfirst;rubricis requested when opted in or when the caller passed--systemone; an unknown requested name is listed), andevaluated_red(true when an evaluated oracle was red, even if the exit is 3).cns statusrenders a row withoracles_requestednot contained inoracles_evaluated, or either field not an array, asNOT_EVALUATED(red), whatever itsexit; rows withoutoracles_requested(hook rows, older gate rows) are judged byexitas before (revision 4). The row also hasorgan: "soma",event: "gate",exit= the gate's exit,missing_binary: truewhen soma is absent. A quiet gate (concerns_fired: 0, exit 0) is a genuine clean result and rendersPASSED(green).vacuous: trueis reserved for a requested oracle that produced no verdict (every exit-3 gate), which renders red (revision 2; the first version marked quiet gates vacuous and turned status red).