befdaa3ca9
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 7s
ci / lint (pull_request) Successful in 17s
ci / build (pull_request) Successful in 37s
ci / smoke-install (pull_request) Successful in 55s
ci / unit-tests (pull_request) Successful in 1m36s
ci / responsiveness-e2e (pull_request) Successful in 1m44s
Adds the missing de-bake CI guardrails (the existing G2/G5 already live in
test_prompt_files_ssot.py / test_mcp_render_openclaw_failclosed.py) plus a
meta self-test that PROVES each guardrail catches its bug.
G0 (runtime half) — tests/test_prompt_filename_ssot_g0.py: build_system_prompt's
no-prompt_files fallback is the canonical filename "system-prompt.md" (the
same literal core's subst/probe/allowlist/default-config converge on), with a
NEGATIVE fixture: prompt_files pointing at an unshipped file => identity LOST
(not silently wrong). Core half pinned by the companion Go guardrail.
G1 — tests/test_prompt_channel_ssot_g1.py: the SINGLE prompt-delivery channel is
config.system_prompt. _common_setup publishes it from the one build; with the
channel = MARKER-A and system-prompt.md on disk = MARKER-B, an executor reads
the channel (A), never re-reads the file (B). Guards that the executor-facing
setup pipeline does NOT call the legacy per-runtime get_system_prompt re-read.
Pairs with task #76.
G6 — tests/test_mcp_render_completeness_g6.py: every runtime in the kind=platform
allowlist {claude-code, codex, openclaw} has a CONCRETE mcp_render._RUNTIME_SPECS
entry (not the _DEFAULT_RUNTIME claude fallback) — its own native MCP-config
path + renderer + present-reader; no #3159 cross-runtime mis-attribution.
Guardrail self-test — tests/test_guardrail_self_test.py + the runnable driver
scripts/run_guardrail_self_test.py: for G0/G1/G2/G5/G6, inject the known
regression into a throwaway fixture/patched module and assert the guardrail
goes RED, then revert. "How do we test the guardrails work?" — run the driver.
NO-BYPASS: all files are tests/test_*.py collected by the unit-tests CI job
(pytest -q --ignore=tests/integration) with no paths: filter and no
continue-on-error — merge-blocking by construction.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>