feat(#87): IMP-87 u1~u5 empty_shell honesty gate + BLOCKED exit

EMPTY_SHELL_NO_CONTENT overall enum + 3-marker detection (frame_template_id="__empty__"
OR label="empty_shell" OR merge_type="empty_shell") routes empty-placeholder-only
slides to BLOCKED CLI exit 1 + red final_status.html, blocking fake PASS reports
(feedback_artifact_status_naming). Coverage accounting split: legacy covered_section_ids
preserved + new content_rendered_section_ids / empty_shell_section_ids. mdx05 Case B
(zero V4 evidence) honestly classified instead of synthesizing fabricated rank-1 reject
frames. IMP-30 u6/u7 stale empty-shell PASS assertions inverted (29 tests). IMP-85 smoke
parametrize: mdx05 removed from exit-0 list + dedicated BLOCKED exit test added (4 tests).
No production behavior change for chain_exhausted Case A; no AI route activation; no
mdx-id hardcoding. 53 targeted + 76 adjacent Phase Z tests PASS.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-23 20:40:54 +09:00
parent c53722ad0b
commit 842a46144c
4 changed files with 731 additions and 18 deletions

View File

@@ -1012,11 +1012,15 @@ def test_u6_empty_shell_unit_listed_with_empty_identifiers():
assert entry["selection_path"] == "empty_shell"
assert entry["fallback_reason"] == "no_v4_rank_1_for_any_section"
assert entry["v4_rank"] is None
# full_mdx_coverage holds because shell.source_section_ids covers every
# aligned section id — u4 deliberately sets this so coverage stays True
# under the terminal first-render invariant.
assert status["full_mdx_coverage"] is True
assert status["overall"] == "PASS"
# IMP-87 u4 — honesty defect inversion. The shell.source_section_ids
# still feeds legacy covered_section_ids for display, but the content-
# rendered axis (u1) excludes empty-shell units, so full_mdx_coverage
# MUST flip to False. Overall (u2) MUST elevate to
# EMPTY_SHELL_NO_CONTENT before the legacy ladder, otherwise a slide
# whose sole rendered unit is __empty__ would be reported as PASS —
# the exact Stage 1 mdx05 honesty defect this issue exists to fix.
assert status["full_mdx_coverage"] is False
assert status["overall"] == "EMPTY_SHELL_NO_CONTENT"
# ─── u6 case 4 : mixed selection — provisional + normal units coexist ──
@@ -1357,10 +1361,14 @@ def test_u7_e2e_zero_v4_empty_shell_status_surface(u7_patch_selector_deps):
assert shell_entry["phase_z_status"] == "empty_shell"
assert shell_entry["frame_template_id"] == "__empty__"
assert shell_entry["source_section_ids"] == ["S1", "S2"]
# Coverage check — both sections counted as covered by the shell unit
# (rendered=True path; PASS enum unchanged by provisional qualifier).
assert status["full_mdx_coverage"] is True
assert status["overall"] == "PASS"
# IMP-87 u4 — honesty defect inversion. The shell unit still attaches
# both sections to legacy covered_section_ids (display preserved), but
# the content-rendered axis (u1) excludes empty-shell units, so
# full_mdx_coverage MUST flip to False. Overall (u2) MUST elevate to
# EMPTY_SHELL_NO_CONTENT before the legacy 4-way ladder, so a zero-V4
# slide cannot disguise itself as PASS through visual-overflow alone.
assert status["full_mdx_coverage"] is False
assert status["overall"] == "EMPTY_SHELL_NO_CONTENT"
# ─── u7 case 3 : e2e normal path unchanged when opt-in flags both on ─────