From af1885751334cc8c18335e73f2e618c276c840f3 Mon Sep 17 00:00:00 2001 From: Eva Date: Wed, 17 Jun 2026 13:44:10 +0700 Subject: [PATCH 1/3] qa: sync root-cause taxonomy with structural_completeness + narration_no_ooc_leak checks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The taxonomy-drift guard test (qa/test_root_cause_analyzer.py:: test_taxonomy_matches_real_gate_check_names) was RED on main: two chk() names added to qa/assert_behavioral.py were never mirrored into the root-cause taxonomy. - structural_completeness (ENGINE_INVARIANT) — FATAL duo-lane check that a >=10-beat companion session engaged a core relationship/quest system; mapped to the companion/server/questgen engine surfaces, consistent with the sibling party_traveled / world_advanced_time structural checks. - narration_no_ooc_leak (DM_ADHERENCE, #972) — player-facing OOC-leak gate; mapped to the FICTION-ONLY mandate in skills/dungeon-master/SKILL.md + the duo DM prompt, with the leak-regex in assert_behavioral.py as the false-positive tuning point. Pure metadata sync; assert_behavioral.py untouched. Test now 19/19 green. --- qa/BEHAVIORAL_GATE_TAXONOMY.json | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/qa/BEHAVIORAL_GATE_TAXONOMY.json b/qa/BEHAVIORAL_GATE_TAXONOMY.json index 6be3e8de..85fb72fc 100644 --- a/qa/BEHAVIORAL_GATE_TAXONOMY.json +++ b/qa/BEHAVIORAL_GATE_TAXONOMY.json @@ -32,6 +32,12 @@ "retest": "bash qa/run_duo.sh duo-retest", "hint": "Zero quoted dialogue across the whole run with a companion present — a log, not a scene. The DM narrated only atmosphere. Strengthen the DM prompt's dialogue mandate; it is FATAL only when a companion is in the party." }, + "narration_no_ooc_leak": { + "category": "DM_ADHERENCE", + "likely_code_locations": ["skills/dungeon-master/SKILL.md", "qa/play_dm_duo.txt", "qa/assert_behavioral.py"], + "retest": "bash qa/run_duo.sh duo-retest", + "hint": "Player-facing DM prose leaked OUT-OF-CHARACTER craft-scaffolding / first-person authoring preambles / raw system vocab (e.g. 'Now let me seat as the player character', 'Continuity check — let me correct that') — a felt-quality defect the LLM story scorer blends away. Fix at the source: the DM's FICTION-ONLY voice mandate in skills/dungeon-master/SKILL.md (and the duo DM prompt qa/play_dm_duo.txt). Proportionate severity: 0 leaks pass, 1-2 incidental leaks WARN, >=3 in a substantial run (dm_text>=MIN_BEATS) is a pervasively-broken player surface => RED. If a clean in-fiction beat is mis-flagged, tighten the _NARRATION_LEAK_RE patterns in qa/assert_behavioral.py." + }, "dm_beat_honesty": { "category": "HARNESS_WIRING", "likely_code_locations": ["qa/lib_beat_driver.sh", "qa/run_duo.sh", "qa/dm_narration_fallback.py"], @@ -164,6 +170,12 @@ "retest": "bash qa/run_duo.sh duo-retest", "hint": "The party visited <2 locations after a substantial session — it never left the opening scene. Either the DM never called travel_to/add_location(make_current=True) (DM adherence) or the location.visited flag never set (engine). Check travel.py's visited-marking write." }, + "structural_completeness": { + "category": "ENGINE_INVARIANT", + "likely_code_locations": ["servers/engine/companion.py", "servers/engine/server.py", "servers/engine/questgen.py"], + "retest": "bash qa/run_duo.sh duo-retest", + "hint": "A >=10-beat session with a companion never engaged a core relationship/quest system: either no companion's attitude_value moved off 0 AND no camp/long_rest happened, or an active quest was left open across a >=2-location arc with no quest-resolution call. Either the DM never invoked the relationship/quest tools (record_decision approval_tags / adjust_attitude / camp_scene / complete_quest evolves_to — DM adherence) or those engine writes never landed (engine). Check the approval/attitude write in companion.py, the record_decision/camp_scene/complete_quest handlers in server.py, and the quest-resolution/evolution path in questgen.py. FATAL (skipped in the combat-sprint lane); validate at >=24 beats so an authored campaign quest has room to resolve." + }, "world_peopled": { "category": "DM_ADHERENCE", "likely_code_locations": ["qa/play_dm_duo.txt", "servers/engine/npc.py", "servers/engine/server.py"], From abb0df1c99f57ba082a8417405cb6d023b14a27d Mon Sep 17 00:00:00 2001 From: Eva Date: Wed, 17 Jun 2026 13:48:12 +0700 Subject: [PATCH 2/3] qa: close gate-corpus coverage gap for narration_no_ooc_leak (TODO entry) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit test_behavioral_gate_corpus.py::test_manifest_covers_every_fatal_check was RED on main (independent of the taxonomy drift): narration_no_ooc_leak is a FATAL gate check (chk(... fatal=_leak_red)) with no corpus fixture and no TODO manifest entry, so the anti-goalpost coverage audit failed. Ran the canonical sync — python qa/gate_corpus/builder.py — which deterministically regenerated all 18 fixtures (byte-identical, zero churn) and auto-added the TODO__narration_no_ooc_leak manifest entry (a faithful minimal OOC-leak fixture is deferred work). Both guard suites now green: test_behavioral_gate_corpus.py + test_root_cause_analyzer.py = 38 passed, 1 skipped. --- qa/gate_corpus/manifest.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/qa/gate_corpus/manifest.json b/qa/gate_corpus/manifest.json index f26c2cb1..6fae63ec 100644 --- a/qa/gate_corpus/manifest.json +++ b/qa/gate_corpus/manifest.json @@ -178,6 +178,12 @@ "state.json" ], "real_red_provenance": "" + }, + { + "case_dir": "TODO__narration_no_ooc_leak", + "expected_red_check": "narration_no_ooc_leak", + "todo": true, + "reason": "no faithful minimal fixture constructed yet (auto-flagged by builder)" } ] } From a921a1949b4cbcb676b3139b51db0c88850dfd73 Mon Sep 17 00:00:00 2001 From: Eva Date: Wed, 17 Jun 2026 14:06:49 +0700 Subject: [PATCH 3/3] qa: correct structural_completeness location hints (adversarial-review fix) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A 3-agent verification of this PR flagged two MAJOR inaccuracies in the structural_completeness location hints that would misdirect an agent reading a RED gate: - questgen.py was named for the 'quest-resolution/evolution path' but holds ZERO such code (it is the quest-SEED-generation layer; 0 hits for evolves_to/complete_quest). The rule-of-three evolution (_maybe_schedule_quest_evolution, evolves_to write) lives in server.py. Replaced questgen.py with models.py (the field defs). - companion.py was credited with 'the approval/attitude write' but is a deliberately PURE module with no campaign I/O — every attitude_value/adjust_attitude write is in server.py. Kept companion.py but reworded the hint to its real role: it only surfaces approval CAUSES (approval_tags) for the DM to apply. Also disambiguated the 10-beat gate trip (STRUCTURAL_MIN_BEATS) from the >=24-beat authored-campaign validation recommendation. No key/category change; guards still 38 passed, 1 skipped. --- qa/BEHAVIORAL_GATE_TAXONOMY.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qa/BEHAVIORAL_GATE_TAXONOMY.json b/qa/BEHAVIORAL_GATE_TAXONOMY.json index 85fb72fc..82548042 100644 --- a/qa/BEHAVIORAL_GATE_TAXONOMY.json +++ b/qa/BEHAVIORAL_GATE_TAXONOMY.json @@ -172,9 +172,9 @@ }, "structural_completeness": { "category": "ENGINE_INVARIANT", - "likely_code_locations": ["servers/engine/companion.py", "servers/engine/server.py", "servers/engine/questgen.py"], + "likely_code_locations": ["servers/engine/server.py", "servers/engine/models.py", "servers/engine/companion.py"], "retest": "bash qa/run_duo.sh duo-retest", - "hint": "A >=10-beat session with a companion never engaged a core relationship/quest system: either no companion's attitude_value moved off 0 AND no camp/long_rest happened, or an active quest was left open across a >=2-location arc with no quest-resolution call. Either the DM never invoked the relationship/quest tools (record_decision approval_tags / adjust_attitude / camp_scene / complete_quest evolves_to — DM adherence) or those engine writes never landed (engine). Check the approval/attitude write in companion.py, the record_decision/camp_scene/complete_quest handlers in server.py, and the quest-resolution/evolution path in questgen.py. FATAL (skipped in the combat-sprint lane); validate at >=24 beats so an authored campaign quest has room to resolve." + "hint": "A >=10-beat session with a companion never engaged a core relationship/quest system: either no companion's attitude_value moved off 0 AND no camp/long_rest happened, or an active quest was left open across a >=2-location arc with no quest-resolution call. Either the DM never invoked the relationship/quest tools (record_decision / adjust_attitude / camp_scene / complete_quest evolves_to — DM adherence) or those engine writes never landed (engine). All those tool handlers + the attitude_value/quest-status writes live in server.py (adjust_attitude, record_decision, camp_scene, complete_quest, and the rule-of-three evolution _maybe_schedule_quest_evolution / evolves_to); the field definitions are in models.py; companion.py only surfaces approval CAUSES (approval_tags) for the DM to apply — it never writes state itself. The gate trips at >=10 beats (STRUCTURAL_MIN_BEATS); when validating authored campaigns run >=24 beats so the main quest has room to resolve, else the unresolved-arc sub-check false-REDs. FATAL; skipped in the combat-sprint lane." }, "world_peopled": { "category": "DM_ADHERENCE",