fix: emit user-visible DEGRADED RUN WARNING on bare named-entity calls
The stderr [Planner] warning from PR #285 doesn't reach the user because Claude and other reasoning agents hide stderr from their synthesis. The 2026-04-19 Hermes Agent Use Cases Run 1 produced source=deterministic and the user never saw it. Adds a user-visible stdout block that the model's LAW 5 pass-through contract forces into the response. Fires only when plan_source is deterministic AND no pre-research flags were passed AND the topic is pre-research-eligible (named entity). Cron jobs on abstract topics don't trigger it. Position: BEFORE the EVIDENCE FOR SYNTHESIS envelope so the model sees it as the first non-badge content. Wrapped in a new USER-VISIBLE BANNER envelope matching the EVIDENCE/PASS-THROUGH envelope pattern from Unit 1 of PR #285. Runtime-agnostic language: explicitly enumerates Claude Code, Codex, Hermes, Gemini so the hosting reasoning model recognizes itself regardless of runtime. pipeline.py now persists plan_source to report.artifacts so the renderer can consume it. Adds 7 tests covering fire conditions, suppression conditions (external/llm plan source, flags present, abstract topic), and correct position relative to the evidence envelope.
This commit is contained in:
@@ -462,5 +462,66 @@ class RenderBestTakesCompactTests(unittest.TestCase):
|
||||
self.assertNotIn("## Best Takes", text)
|
||||
|
||||
|
||||
class DegradedRunBannerTests(unittest.TestCase):
|
||||
"""Unit 1: DEGRADED RUN WARNING surfaces bare named-entity invocations
|
||||
in user-visible stdout. LAW 7 backstop. 2026-04-19 Hermes Agent Use
|
||||
Cases Run 1 failure mode.
|
||||
"""
|
||||
|
||||
def _bare_named_entity_report(self) -> schema.Report:
|
||||
report = sample_report()
|
||||
report.topic = "Hermes Agent"
|
||||
report.artifacts["plan_source"] = "deterministic"
|
||||
report.artifacts["pre_research_flags_present"] = False
|
||||
return report
|
||||
|
||||
def test_banner_appears_on_bare_named_entity_deterministic_run(self):
|
||||
text = render.render_compact(self._bare_named_entity_report())
|
||||
self.assertIn("## DEGRADED RUN WARNING", text)
|
||||
self.assertIn("<!-- USER-VISIBLE BANNER:", text)
|
||||
self.assertIn("<!-- END USER-VISIBLE BANNER -->", text)
|
||||
self.assertIn("YOU ARE", text)
|
||||
# Runtime-agnostic enumeration: all host runtimes appear.
|
||||
for runtime_name in ("Claude Code", "Codex", "Hermes", "Gemini"):
|
||||
self.assertIn(runtime_name, text)
|
||||
|
||||
def test_banner_positioned_before_evidence_envelope(self):
|
||||
text = render.render_compact(self._bare_named_entity_report())
|
||||
banner_idx = text.index("## DEGRADED RUN WARNING")
|
||||
envelope_idx = text.index("<!-- EVIDENCE FOR SYNTHESIS:")
|
||||
self.assertLess(banner_idx, envelope_idx,
|
||||
"DEGRADED RUN banner must appear BEFORE evidence envelope so pass-through catches it.")
|
||||
|
||||
def test_banner_suppressed_when_plan_source_external(self):
|
||||
report = self._bare_named_entity_report()
|
||||
report.artifacts["plan_source"] = "external"
|
||||
text = render.render_compact(report)
|
||||
self.assertNotIn("## DEGRADED RUN WARNING", text)
|
||||
|
||||
def test_banner_suppressed_when_plan_source_llm(self):
|
||||
report = self._bare_named_entity_report()
|
||||
report.artifacts["plan_source"] = "llm"
|
||||
text = render.render_compact(report)
|
||||
self.assertNotIn("## DEGRADED RUN WARNING", text)
|
||||
|
||||
def test_banner_suppressed_when_pre_research_flags_present(self):
|
||||
report = self._bare_named_entity_report()
|
||||
report.artifacts["pre_research_flags_present"] = True
|
||||
text = render.render_compact(report)
|
||||
self.assertNotIn("## DEGRADED RUN WARNING", text)
|
||||
|
||||
def test_banner_suppressed_on_non_eligible_abstract_topic(self):
|
||||
report = self._bare_named_entity_report()
|
||||
# Multi-word lowercase abstract phrase is NOT pre-research-eligible.
|
||||
report.topic = "how to deploy containers in the cloud"
|
||||
text = render.render_compact(report)
|
||||
self.assertNotIn("## DEGRADED RUN WARNING", text)
|
||||
|
||||
def test_banner_mentions_law_7_and_plan_flag(self):
|
||||
text = render.render_compact(self._bare_named_entity_report())
|
||||
self.assertIn("LAW 7", text)
|
||||
self.assertIn("--plan", text)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
Reference in New Issue
Block a user