Expand description
Truth Gate: a narrow Stop-hook check for responses that claim completion while leaving work unfinished or deferred. It is not a fact-checker.
Deterministic rules (default):
- match whole words only (
incompleteis notcomplete,alreadyis notready); - ignore a completion word or placeholder that is negated just before it
(
not done,no placeholder text remains); - ignore fenced and inline code, where TODOs are usually quoted legacy code;
- normalize first (Unicode NFC, curly apostrophes, zero-width characters, every whitespace character except newline to a space) and use ASCII word boundaries, so the Rust and Python implementations agree on unusual Unicode;
- block only when an un-negated completion claim co-occurs with an un-negated unfinished marker or a first-person future-work promise;
- a word that names a thing is not a marker:
todo,tbdorfixmefollowed by a feature noun such aslistorapp(the TODO list widget),coming soonfollowed by a UI word such asbadgeorpage, andplaceholderafterinput,searchorfield. Each still counts when the rest of its clause says it is open (remains,left,pending,still needs).todo,tbdorfixmefollowed bycommentoritemnames a thing only when the rest of its clause says it was dealt with (the TODO comment in proxy.ts is now handled) and nothing in the clause says it is open, becauseI left a TODO commentis open work.placeholderbeforetext(the older rule) is always UI. A term right after an opening quote is mentioned (the badge reads "Coming soon"), except marker syntax ("TODO: retries",FIXME(), which always counts; - a clause ends at
.,!,?,;or a newline, but not at a.directly followed by a letter or digit (proxy.ts,v2.1); - a promise left to the user is an offer, not deferred work: an idiom asking for the user’s
permission or trigger (
if you want,once you approve,when you're ready,let me know if you'd like,would you like) in the promise’s own comma-delimited segment or opening the segment before it (If you want, I'll ...). A condition about product behaviour (when you visit /old,if you add two plans) is not one, and a condition cannot reach across a coordinated clause (..., and I'll ...), past a neighbouring promise, or past a clause end.
Optional engine mode: a typed decision engine (for example Jev) estimates the probability that
the completion claim would fail verification (a test run of the requested change). The gate
blocks when the rules block or p >= threshold. By default the deterministic rules are a
hard floor an engine cannot lift, and the engine can only add blocks. Opting in with a lift
value (GateSettings::lift, HIKMAH_HOOK_ENGINE_LIFT) lets an admitted engine answer with
p < lift remove a rules block; nothing removes an engine block. Any engine failure,
abstention, or rejected response leaves the rules’ verdict in place.
Why this question and threshold: on 600 held-out real agent “done” messages (harness-bench run 1), the rules caught 1 of 295 false completions, the previous engine question (“does the message admit unfinished work?”) caught 8.5%, and this outcome question caught 16.3% with a 7.9% false-block rate at 0.60, a threshold chosen on a separate dev set. The message alone cannot catch most false completions; treat this as a screen, not a verifier.
Opt-in measurement: with a record store (HIKMAH_HOOK_RECORD), every probability the engine
answers is appended there as a prediction trace (family truth_gate.false_completion.v2)
after the verdict is written, so outcomes recorded later can set the threshold from data
(hikmah gate-threshold). Recording is best effort and never changes the verdict.
hooks/truth_gate_cases.json holds golden cases shared with the Python fallback.
Structs§
- Gate
Settings - How the Truth Gate combines its rules with an engine’s answer.
- Gate
Verdict - Full explanation of one Truth Gate decision (what
hikmah gate-explainprints).
Enums§
- Gate
Path - Which path produced a Truth Gate verdict.
Constants§
- DEFAULT_
ENGINE_ THRESHOLD - Chosen on harness-bench run 1 dev (300 messages; highest recall with a false-block rate of at
most 10%) and confirmed on its held-out test split. Re-measure on your own traffic with
HIKMAH_HOOK_RECORD,hikmah outcome, andhikmah gate-threshold. - GATE_
FAMILY - Calibration family of the v2 outcome question. Calibration must not mix it with v1.
Functions§
- evaluate_
message - Decide one message. The Stop hook and
hikmah gate-explainboth call this, so the benchmark measures exactly the code path the hook runs. - explain_
batch hikmah gate-explain --batch: one JSON object per input line ({"id": ..., "last_assistant_message": ...}), one verdict per output line, input order kept.- explain_
stop_ event hikmah gate-explain(without--batch): the verdict the Stop hook reaches for this stdin, through the same parsing and the sameevaluate_message. When the hook would allow without judging,skippedsays why and nothing is sent to an engine.- false_
completion_ request - The question an engine answers in engine mode: would this completion claim fail verification? The wording is the one benchmarked in harness-bench; changing it invalidates that evidence.
- rules_
verdict - Deterministic verdict:
truemeans block. - run_
stop_ hook - Rules-only Stop hook (the default).
- run_
stop_ hook_ recording - Stop hook that can also record the engine’s answer. When
recordnames a memory store and the engine answered, the prediction is appended there after the verdict is written and flushed. Any recording failure (or panic) is swallowed: it can never change the verdict, the output, or the exit status. - run_
stop_ hook_ with - Stop hook with an optional decision engine. Always prints valid JSON.