Docs/Reference

Reference

Asking a model, when shape cannot decide

How a gate asks a model for a judgement its input's structure cannot give, and what it does when no model answers.

How a gate asks a model for a judgement its input's structure cannot give, and what it does when no model answers.

Some rules are not about shape: whether a claim is grounded, whether a closing report hands work back to the operator. The decider there is a model, and Brama answers it by default. ports::model_judgement is the one route: model_judgement::object(prompt, name, schema, check) and model_judgement::choose(prompt, name, options) send the prompt through the product's own one-shot call, oko gateway object --prompt … --name … --schema … — run by the same Oko every hook asks, TAMA_OKO_CLI when set, else oko on PATH — which carries Oko's signed bearer to the gateway and prints the one object the model answered under the gate's strict JSON Schema, or — on a machine without Brama — goes to the OpenAI-compatible service declared with oko model-service set, with its declared model. No gate reads a line of prose. A question goes unanswered as Judgement::Unavailable(reason). An unavailable judgment is not evidence that the source violates a rule. Each gate must distinguish that failure from an actual model finding. Numeric review refuses an unreviewed write with the failed operation, not with an allegation about its source.

A judge Oko has recorded as not answering is not asked. Oko writes that record — judge-health.json beside its transcript index — from every verification pass and from oko tasks judge --probe, and the same probe lifts it. A question reads it first and returns Unavailable with Oko last saw the judge refuse at …: …; not asked again from a hook, because asking anyway costs Brama's whole retry wait inside the event, and a single refused proxy-call can take tens of seconds inside a stop gate. A record that exists and cannot be read or is not Oko's shape is not read as "never observed": the question writes model judgement: <path> cannot be read: …; the judge is asked on stderr and asks, and block-broken-judge, which reads the same record through the same reader, refuses oko tasks verify naming the record that could not be read and the probe that writes it again. The engine kills no hook for being slow, and the OMP adapter sets no wait of its own; OMP itself refuses a tool call whose handler has not answered within the time its own extension-handler setting allows, naming the extension. A hook the harness stopped waiting for is ended by the next event that proves it has no caller, as the runtime page describes, not by a clock.

A question the judge already answered is not asked again. The prompt is the whole question, the command or text it judges included, so the judge's answer to that exact prompt and schema is kept under Tama's state, in model-judgements/<SHA-256 of the prompt and schema> (TAMA_JUDGEMENT_MEMORY_DIR moves it for a test), and read back before the question is asked: a command many sessions run costs one model call, not one each, and while the judge is slow it stands inside one tool call instead of every one. Only answers are kept; an unanswered question is asked again. A kept answer that cannot be read is the question's Unavailable reason, naming the file; an answer that cannot be kept is still returned, and model judgement: the answer is not kept for the next ask: … on stderr says why.

A choice between named options

A gate that decides between named options does not read a line of prose. model_judgement::choose(prompt, name, options) asks through oko gateway object --prompt … --name … --schema … for one object whose choice is one of the options the gate names and whose reason is the judge's sentence, bound to a strict JSON Schema. The gate compares choice with its own option and uses reason in its refusal, so the words a model puts around its answer never decide whether a call passes. An answer that is not one of the options is an Unavailable judgement naming the answer, and the gate refuses it as below. The kept answer is keyed by the prompt and the schema together. These gates ask this way: block-inline-execution, block-one-off-repairs, block-keychain-prompt-commands, block-local-model-training, block-oko-trajectory-edits, block-subagent-spawn, block-external-source-edits, block-hook-scan-narrowing, block-device-level-tests-without-consent and check-humanized-actions choose PASS or BLOCK; block-background-execution chooses PASS, DETACH or WAIT; check-legacy-activation-bypass chooses READS or RUNS; check-merge-deletion-loss chooses UNDID or KEPT; and pre-bash chooses PASS or the one forbidden shape the command has (REVIEW, SCRATCH, SOURCE, SEARCH, BROWSER, WELES, CLOUD, QUARANTINE, HELPER, HOOKS or TRUNCATE) and refuses with the operator's sentence for that shape.

A gate whose answer is more than one choice writes its own schema and asks model_judgement::object(prompt, name, schema, check), which reads the answer as the type the gate names and hands it to the gate's check; an answer that does not fit, or that the check refuses, is neither kept nor returned but is the Unavailable judgement naming it. block-unregistered-build-or-restart asks for the list of steps the command performs, each a kind (build or restart) and the directory or service it named; block-one-off-commands asks for one verdict per declared command, each naming the command, choosing PASS or BLOCK and giving its reason, and an answer that leaves a command without a verdict is no answer.

When a shell or write gate's question goes unanswered

A rule a model enforces is not off while the model is. Every gate that judges a shell command or a write by model — pre-bash, block-inline-execution, block-one-off-repairs, block-unregistered-build-or-restart, block-keychain-prompt-commands, block-background-execution, block-local-model-training, block-subagent-spawn, block-external-source-edits, block-device-level-tests-without-consent, block-oko-trajectory-edits, block-hook-scan-narrowing, check-humanized-actions, check-legacy-activation-bypass and check-merge-deletion-loss — hands an Unavailable judgement to model_judgement::unanswered::refusal, which refuses the call:

TAMA_HOOK_INFRASTRUCTURE: <hook>: review unavailable: <why nobody answered>

The cause is the judge's recorded state (Oko last saw the judge refuse at …: …), the held question, the missing Oko program or the gateway's own failure; a write or merge gate adds (judging <file>). oko tasks judge --probe asks the judge one question and lifts the record when it answers. Two calls pass instead, each saying so on stderr:

  • any call on a machine whose operator declared no model with tama model-provider set --none: <hook>: no model is asked on this machine, the call passes: …;
  • a shell line whose every command runs a program the judge stands on — this Tama, the Oko it asks (TAMA_OKO_CLI, else oko) and every product stado product catalog declares that Oko depending on, at any depth — so the judge can be repaired: <hook>: no judgement (…); the command only runs what the judge stands on, and passes. When that catalog cannot be read the call is refused with both causes: …: review unavailable: …; and which programs the judge stands on cannot be read: ….

The stop gates that judge a closing answer keep their own rule. The journey cargo test --manifest-path rust/Cargo.toml -p tama-cli --test model_judgement_judge_repairs runs the built hook with the judge recorded as not answering and the real catalog: a line of oko and stado passes saying why, and the same line with python3 -c is refused naming the judge's state. Each gate's own journey requires the refusal with the judge down.

pre-write-edit never asks the numeric reviewer from the edit callback. When numeric candidates need review, it retains the exact prompt and refuses immediately with tama hook check-unsubstantiated-constants --review <request>. Run that operation outside the edit callback; it asks model_judgement::object through oko gateway object for {"findings": [N, …]}, the numbers of the candidates that are unexplained tuning choices, each bound by the schema to one of the listed candidates, and an empty list when none is. Shared child-output collection prints czekam for Oko's gateway operation and retains that object or the failure, including the executable, exit status and actual cause. Repeat the unchanged edit after a valid answer. The answer is bound to the complete file, path, candidates, review instructions and recorded justification; changed input cannot inherit the previous verdict, and a retained answer that does not fit the findings schema refuses the edit naming it.

Requests and results live under session-control/numeric-reviews in Tama state; TAMA_SESSION_CONTROL_ROOT scopes isolated journeys. Concurrent review operations refuse an already owned request rather than starting another model call. A missing answer, unreadable record, malformed reply or actual model failure remains a refusal. No background process is detached from the edit and no timer retries the reviewer. The CLI and the attached editor's decision surface show the same request and cause; Desktop Session and Posture show that recorded hook decision, not a claimed model success. Review-operation success means an answer was retained, not that the source passed: the repeated write applies the numeric findings.

tests/numeric-review/retained.rs, registered as numeric_review_retained, drives the built hook with a real persisted request and a genuinely missing Oko executable. It retains the declared candidate, binary digest, command, input, exit status, output and elapsed time under Cargo's ignored build directory, through its pending, failed, changed-input and malformed-justification cases.

check-substantiation-with-model uses the model gateway. That is also the route for a judgment about prose that cannot be decided from the input's structure; an embedded word list is not a substitute.