027a573d89
Retires the defect class behind #129. The engine's state store returns "" for a key nothing writes — no error, no warning, no log. That is how the agentic path's crisis-escalation input scored 0 on every real conversation for two days afterff421d3moved conversation history behind conv_hist_key(session_id) and left one consumer reading the old "conv_history" bucket by hand. scripts/verify-state-keys.sh is the gate; scripts/state-key-audit.py is the El reader behind it. Two checks: DEAD-READ a state_get whose key resolves to something no state_set in the tree produces. HAND-ROLLED a literal that belongs to a namespace a helper owns, accessed without the helper. This is #129's actual shape, and DEAD-READ alone does NOT catch it: the dead handle_chat() still writes "conv_history" through conv_hist_key(""). Stating that plainly because a gate that only appears to work is worse than none. WHY IT DOES NOT CRY WOLF. Keys are usually computed, so a literal-matching script would flood and be switched off in a day. The resolver handles concatenation (matched on the static prefix), helper functions (resolved to their possible returns, with guard conditions folded so conv_hist_key("") does not falsely claim to produce the session_hist_ namespace), keys built into a local, and keys arriving as a parameter (resolved through the call sites). 278 of 278 sites on this tree resolve: UNRESOLVED 0, FINDINGS 0. Unresolvable keys would be listed and would NOT fail the build. TWO-LEG PROOF, one variable — agentic_safety_screen's single line: pre-fix scripts/verify-state-keys.sh --root <scratch> chat.el:2536 state_get("conv_history") conv_hist_key() owns this key namespace (EXACT 'conv_history') FAIL: 1 state-key finding(s) exit 1 as-is scripts/verify-state-keys.sh FINDINGS (0) ... PASS exit 0 INDEPENDENT CONFIRMATION: run read-only against origin/feat/soul-openai-tools-v2, which carries the same defect on its own, the gate reported chat.el:2937 — the exact line 43d0449's message had named by hand, with no prior knowledge. Against origin/fix/129-on-openai-tools: PASS. PRODUCER-MOVED CONTROLS: renaming the sole writer of an EXACT key (soul_model) orphans 3 readers across 3 files; renaming the sole writer of a PREFIX namespace (agent_workspace_root_*) orphans 3 readers, including when the producer moves to a NARROWER namespace — a case an earlier, more permissive prefix rule let through. That rule is now directional, with the reason written next to it. FOUND ON ITS FIRST RUN, unprompted: soul.el's state_set("soul_identity", ...) was deleted 2026-05-13 inb163fa6(a commit about awareness/ISE writes) and five readers in chat.el were left behind — build_system_prompt, the vision handler, the agentic system prompt and two council handlers have prefixed "" for ~3 months. studio.el:57 emits "principal":"" and never had a producer. Both are recorded in state-key-baseline.txt with dates and causes so the gate can be turned on today; they are DEBT, not false positives, and every run prints them. Baseline signatures carry no line number (an unrelated edit must not un-mute an accepted finding) but do carry a count, so a GROWTH in a baselined finding still fails the build. Engine behaviour unchanged: this commit adds scripts only, no .el is touched. CI is deliberately NOT wired here — .gitea/workflows/ci.yaml has changes in flight from someone else, and turning the gate on would immediately red feat/soul-openai-tools-v2 (correctly). That flip should be deliberate. Rung reached: RUNS — the gate executes (0.15s), discriminates on four independent test pairs, and its verdicts are quoted above. Not wired to CI, and no engine binary was built from this branch. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
17 lines
1.2 KiB
Plaintext
17 lines
1.2 KiB
Plaintext
# state-key-external.txt — state keys the engine READS but deliberately never
|
|
# WRITES, because a host outside the El tree sets them (an operator, the
|
|
# installer, a deployment env). Read scripts/verify-state-keys.sh for why this
|
|
# list has to exist and why it has to stay short.
|
|
#
|
|
# THE RULE FOR ADDING A LINE: the read site must already treat "" as a defined
|
|
# default (`if str_eq(x, "") { <default> }`) AND the source must say so in a
|
|
# comment. "I could not find the writer" is NOT a reason — that is the #129
|
|
# defect, and it belongs in state-key-baseline.txt with a date, not here.
|
|
#
|
|
# format: exact|prefix <key> # why, and where the source says so
|
|
#
|
|
exact soul_rate_limit # routes.el:59-61 — "configurable via soul state key ... Falls back to 60 req/min if not set."
|
|
exact web_search_tool_version # chat.el:1884-1910 — version lives in state "so a future bump is a config write, not a recompile"; defaults to web_search_20250305
|
|
exact platform_auth # stewardship.el:92 — host-set capability flag; fail-CLOSED (anything but "true" denies the platform tool)
|
|
exact security_research_authorized # awareness.el:991-996 — state override for env SECURITY_RESEARCH_TOKEN; fail-closed, defaults false
|