From ae95d0e355d41fa5d721cc940a40eabac6d04c96 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sun, 13 Sep 2026 02:32:56 +0900 Subject: [PATCH 1/2] fix: reject finish report schema placeholders --- strix/tools/finish/tool.py | 27 +++++++++++++++++++-------- tests/test_finish_coverage_gate.py | 28 +++++++++++++++++++++++++++- 2 files changed, 46 insertions(+), 9 deletions(-) diff --git a/strix/tools/finish/tool.py b/strix/tools/finish/tool.py index 9484a4539..dd2bb1cec 100644 --- a/strix/tools/finish/tool.py +++ b/strix/tools/finish/tool.py @@ -33,15 +33,26 @@ def _do_finish( ), } + report_sections = ( + ("Executive summary", executive_summary, "Business-level summary for leadership."), + ("Methodology", methodology, "Frameworks, scope, and approach."), + ( + "Technical analysis", + technical_analysis, + "Consolidated findings + systemic themes.", + ), + ( + "Recommendations", + recommendations, + "Prioritized, actionable remediation.", + ), + ) errors: list[str] = [] - if not executive_summary.strip(): - errors.append("Executive summary cannot be empty") - if not methodology.strip(): - errors.append("Methodology cannot be empty") - if not technical_analysis.strip(): - errors.append("Technical analysis cannot be empty") - if not recommendations.strip(): - errors.append("Recommendations cannot be empty") + for section_name, section_text, schema_description in report_sections: + if not section_text.strip(): + errors.append(f"{section_name} cannot be empty") + elif " ".join(section_text.split()) == schema_description: + errors.append(f"{section_name} cannot be a schema description placeholder") if errors: return {"success": False, "error": "Validation failed", "errors": errors} diff --git a/tests/test_finish_coverage_gate.py b/tests/test_finish_coverage_gate.py index 52a19a7d9..ac84b85d4 100644 --- a/tests/test_finish_coverage_gate.py +++ b/tests/test_finish_coverage_gate.py @@ -7,7 +7,7 @@ from typing import TYPE_CHECKING import pytest from strix.tools.coverage.tools import _record_impl, hydrate_coverage_from_disk -from strix.tools.finish.tool import _coverage_summary +from strix.tools.finish.tool import _coverage_summary, _do_finish if TYPE_CHECKING: @@ -63,3 +63,29 @@ def test_an_empty_ledger_still_warns_first() -> None: assert summary["coverage_recorded"] == 0 assert "No coverage was recorded" in summary["coverage_warning"] + + +@pytest.mark.parametrize( + ("field_name", "placeholder"), + [ + ("executive_summary", "Business-level summary for leadership."), + ("methodology", "Frameworks, scope, and approach."), + ("technical_analysis", "Consolidated findings + systemic themes."), + ("recommendations", "Prioritized, actionable remediation."), + ], +) +def test_finish_rejects_schema_description_placeholders( + field_name: str, placeholder: str +) -> None: + report_fields = { + "executive_summary": "No material exposure was confirmed.", + "methodology": "The scoped paths were reviewed and exercised.", + "technical_analysis": "Observed controls held under the tested cases.", + "recommendations": "Retest after material changes.", + } + report_fields[field_name] = f" \n{placeholder}\t" + + result = _do_finish(parent_id=None, agent_graph={}, **report_fields) + + assert result["success"] is False + assert "placeholder" in " ".join(result["errors"]).lower() From 5394c79c2d6db4fbf7595fbab80d5fad6554859a Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sun, 13 Sep 2026 02:51:27 +0900 Subject: [PATCH 2/2] test: bind placeholder cases to tool schema --- tests/test_finish_coverage_gate.py | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/tests/test_finish_coverage_gate.py b/tests/test_finish_coverage_gate.py index ac84b85d4..3ad69e61f 100644 --- a/tests/test_finish_coverage_gate.py +++ b/tests/test_finish_coverage_gate.py @@ -7,7 +7,7 @@ from typing import TYPE_CHECKING import pytest from strix.tools.coverage.tools import _record_impl, hydrate_coverage_from_disk -from strix.tools.finish.tool import _coverage_summary, _do_finish +from strix.tools.finish.tool import _coverage_summary, _do_finish, finish_scan if TYPE_CHECKING: @@ -66,23 +66,22 @@ def test_an_empty_ledger_still_warns_first() -> None: @pytest.mark.parametrize( - ("field_name", "placeholder"), + "field_name", [ - ("executive_summary", "Business-level summary for leadership."), - ("methodology", "Frameworks, scope, and approach."), - ("technical_analysis", "Consolidated findings + systemic themes."), - ("recommendations", "Prioritized, actionable remediation."), + "executive_summary", + "methodology", + "technical_analysis", + "recommendations", ], ) -def test_finish_rejects_schema_description_placeholders( - field_name: str, placeholder: str -) -> None: +def test_finish_rejects_schema_description_placeholders(field_name: str) -> None: report_fields = { "executive_summary": "No material exposure was confirmed.", "methodology": "The scoped paths were reviewed and exercised.", "technical_analysis": "Observed controls held under the tested cases.", "recommendations": "Retest after material changes.", } + placeholder = finish_scan.params_json_schema["properties"][field_name]["description"] report_fields[field_name] = f" \n{placeholder}\t" result = _do_finish(parent_id=None, agent_graph={}, **report_fields)