From 6f5f4db4a79c6178a7621f750063b6840e129fd8 Mon Sep 17 00:00:00 2001 From: yaojingang Date: Sun, 14 Jun 2026 14:46:44 +0800 Subject: [PATCH] refactor: share falsey-safe html rendering --- Makefile | 7 ++++-- scripts/ci_test.py | 1 + scripts/html_rendering.py | 14 +++++++++++ scripts/prepare_output_review_kit.py | 6 +---- scripts/prepare_world_class_submission_kit.py | 6 +---- .../render_world_class_operator_runbook.py | 6 +---- tests/verify_html_rendering.py | 23 +++++++++++++++++++ 7 files changed, 46 insertions(+), 17 deletions(-) create mode 100644 scripts/html_rendering.py create mode 100644 tests/verify_html_rendering.py diff --git a/Makefile b/Makefile index f92f1469..4def1d40 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ PYTHON ?= python3 LOCAL_SKILL_INSTALL_DIR ?= $(HOME)/.agents/skills.disabled/yao-meta-skill ACTIVE_SKILL_INSTALL_DIR ?= $(HOME)/.agents/skills/yao-meta-skill -.PHONY: eval eval-suite route-scorecard route-confusion-check description-optimization judge-blind-eval description-optimization-check promotion-check python-compat-check architecture-maintainability-check yao-cli-check skill-overview-check skill-report-metrics-check skill-report-charts-check skill-ir-check compiler-check output-eval-check output-execution-check output-review-kit-check output-review-adjudication-check runtime-conformance-check runtime-permission-check trust-check skill-atlas-check registry-audit-check package-verify-check install-simulation-check upgrade-check review-viewer-check review-studio-check skill-os2-audit-check skill-os2-coverage-check world-class-evidence-check world-class-ledger-check world-class-intake-check world-class-submission-review-check world-class-runbook-check world-class-claim-guard-check benchmark-reproducibility-check feedback-check adoption-drift-check telemetry-import-check telemetry-emit-check telemetry-hooks-check telemetry-native-host-check review-waivers-check review-annotations-check baseline-compare-check reference-scan-check github-benchmark-scan-check intent-confidence-check reference-synthesis-check output-risk-profile-check artifact-design-profile-check prompt-quality-profile-check system-model-check iteration-directions-check description-drift-history iteration-ledger results-panel regression-history context-reports portability-report portability-check failure-regression-check package-check package-failure-check security-boundary-check local-install-sync-check snapshot-check validate lint governance-check resource-boundary-check quality-check sync-local-install sync-active-install test ci-test clean +.PHONY: eval eval-suite route-scorecard route-confusion-check description-optimization judge-blind-eval description-optimization-check promotion-check python-compat-check architecture-maintainability-check yao-cli-check skill-overview-check skill-report-metrics-check skill-report-charts-check html-rendering-check skill-ir-check compiler-check output-eval-check output-execution-check output-review-kit-check output-review-adjudication-check runtime-conformance-check runtime-permission-check trust-check skill-atlas-check registry-audit-check package-verify-check install-simulation-check upgrade-check review-viewer-check review-studio-check skill-os2-audit-check skill-os2-coverage-check world-class-evidence-check world-class-ledger-check world-class-intake-check world-class-submission-review-check world-class-runbook-check world-class-claim-guard-check benchmark-reproducibility-check feedback-check adoption-drift-check telemetry-import-check telemetry-emit-check telemetry-hooks-check telemetry-native-host-check review-waivers-check review-annotations-check baseline-compare-check reference-scan-check github-benchmark-scan-check intent-confidence-check reference-synthesis-check output-risk-profile-check artifact-design-profile-check prompt-quality-profile-check system-model-check iteration-directions-check description-drift-history iteration-ledger results-panel regression-history context-reports portability-report portability-check failure-regression-check package-check package-failure-check security-boundary-check local-install-sync-check snapshot-check validate lint governance-check resource-boundary-check quality-check sync-local-install sync-active-install test ci-test clean eval: $(PYTHON) scripts/trigger_eval.py --description-file evals/improved_description.txt --cases evals/trigger_cases.json --baseline-description-file evals/baseline_description.txt @@ -46,6 +46,9 @@ skill-report-metrics-check: skill-report-charts-check: $(PYTHON) tests/verify_skill_report_charts.py +html-rendering-check: + $(PYTHON) tests/verify_html_rendering.py + skill-ir-check: $(PYTHON) tests/verify_skill_ir.py @@ -235,7 +238,7 @@ sync-local-install: package-check sync-active-install: package-check $(PYTHON) scripts/sync_local_install.py --install-dir "$(ACTIVE_SKILL_INSTALL_DIR)" -test: eval eval-suite route-scorecard route-confusion-check description-optimization description-optimization-check promotion-check python-compat-check architecture-maintainability-check yao-cli-check skill-overview-check skill-report-metrics-check skill-report-charts-check skill-ir-check compiler-check output-eval-check output-execution-check output-review-adjudication-check runtime-conformance-check runtime-permission-check trust-check skill-atlas-check registry-audit-check package-verify-check install-simulation-check upgrade-check review-viewer-check review-studio-check skill-os2-audit-check skill-os2-coverage-check world-class-evidence-check world-class-ledger-check world-class-intake-check world-class-submission-review-check world-class-runbook-check world-class-claim-guard-check benchmark-reproducibility-check feedback-check adoption-drift-check telemetry-import-check telemetry-emit-check telemetry-hooks-check telemetry-native-host-check review-waivers-check review-annotations-check baseline-compare-check reference-scan-check github-benchmark-scan-check intent-confidence-check reference-synthesis-check output-risk-profile-check artifact-design-profile-check prompt-quality-profile-check system-model-check iteration-directions-check description-drift-history iteration-ledger regression-history context-reports portability-report portability-check failure-regression-check package-check package-failure-check security-boundary-check local-install-sync-check snapshot-check validate lint governance-check resource-boundary-check quality-check +test: eval eval-suite route-scorecard route-confusion-check description-optimization description-optimization-check promotion-check python-compat-check architecture-maintainability-check yao-cli-check skill-overview-check skill-report-metrics-check skill-report-charts-check html-rendering-check skill-ir-check compiler-check output-eval-check output-execution-check output-review-adjudication-check runtime-conformance-check runtime-permission-check trust-check skill-atlas-check registry-audit-check package-verify-check install-simulation-check upgrade-check review-viewer-check review-studio-check skill-os2-audit-check skill-os2-coverage-check world-class-evidence-check world-class-ledger-check world-class-intake-check world-class-submission-review-check world-class-runbook-check world-class-claim-guard-check benchmark-reproducibility-check feedback-check adoption-drift-check telemetry-import-check telemetry-emit-check telemetry-hooks-check telemetry-native-host-check review-waivers-check review-annotations-check baseline-compare-check reference-scan-check github-benchmark-scan-check intent-confidence-check reference-synthesis-check output-risk-profile-check artifact-design-profile-check prompt-quality-profile-check system-model-check iteration-directions-check description-drift-history iteration-ledger regression-history context-reports portability-report portability-check failure-regression-check package-check package-failure-check security-boundary-check local-install-sync-check snapshot-check validate lint governance-check resource-boundary-check quality-check ci-test: $(PYTHON) scripts/ci_test.py diff --git a/scripts/ci_test.py b/scripts/ci_test.py index e29fb1b6..c4aad45e 100644 --- a/scripts/ci_test.py +++ b/scripts/ci_test.py @@ -36,6 +36,7 @@ DEFAULT_TARGETS = [ "skill-overview-check", "skill-report-metrics-check", "skill-report-charts-check", + "html-rendering-check", "skill-ir-check", "compiler-check", "output-eval-check", diff --git a/scripts/html_rendering.py b/scripts/html_rendering.py new file mode 100644 index 00000000..afb7f750 --- /dev/null +++ b/scripts/html_rendering.py @@ -0,0 +1,14 @@ +#!/usr/bin/env python3 +"""Shared HTML rendering helpers for static report generators.""" + +import html +from typing import Any + + +SCRIPT_INTERFACE = "internal-module" +SCRIPT_INTERFACE_REASON = "Used by report renderers to escape HTML while preserving meaningful falsey values." + + +def html_text(value: Any) -> str: + """Escape text for HTML without dropping 0 or False values.""" + return html.escape("" if value is None else str(value), quote=True) diff --git a/scripts/prepare_output_review_kit.py b/scripts/prepare_output_review_kit.py index 2e513487..1244d070 100644 --- a/scripts/prepare_output_review_kit.py +++ b/scripts/prepare_output_review_kit.py @@ -2,7 +2,6 @@ """Prepare a reviewer-facing blind A/B output review kit.""" import argparse -import html import json from pathlib import Path from typing import Any @@ -15,6 +14,7 @@ from adjudicate_output_review import ( load_json, normalize_variant, ) +from html_rendering import html_text ROOT = Path(__file__).resolve().parent.parent @@ -238,10 +238,6 @@ def render_markdown(payload: dict[str, Any]) -> str: return "\n".join(lines).strip() + "\n" -def html_text(value: Any) -> str: - return html.escape("" if value is None else str(value), quote=True) - - def status_label(status: str) -> str: return { "awaiting-decision": "Awaiting", diff --git a/scripts/prepare_world_class_submission_kit.py b/scripts/prepare_world_class_submission_kit.py index 1d0ed4ab..92d5f119 100644 --- a/scripts/prepare_world_class_submission_kit.py +++ b/scripts/prepare_world_class_submission_kit.py @@ -1,7 +1,6 @@ #!/usr/bin/env python3 import argparse import hashlib -import html import json import shlex import shutil @@ -9,6 +8,7 @@ from datetime import date from pathlib import Path from typing import Any +from html_rendering import html_text from render_world_class_evidence_intake import build_intake from world_class_evidence_contract import DISALLOWED_REAL_ARTIFACTS from world_class_source_checks import build_source_checklist, summarize_source_checklist @@ -35,10 +35,6 @@ def write_json(path: Path, payload: dict[str, Any]) -> None: path.write_text(json.dumps(payload, ensure_ascii=False, indent=2) + "\n", encoding="utf-8") -def html_text(value: Any) -> str: - return html.escape("" if value is None else str(value), quote=True) - - def has_glob_pattern(value: str) -> bool: return any(token in value for token in ("*", "?", "[")) diff --git a/scripts/render_world_class_operator_runbook.py b/scripts/render_world_class_operator_runbook.py index c9cb4c33..456eb58e 100644 --- a/scripts/render_world_class_operator_runbook.py +++ b/scripts/render_world_class_operator_runbook.py @@ -1,11 +1,11 @@ #!/usr/bin/env python3 import argparse -import html import json from datetime import date from pathlib import Path from typing import Any +from html_rendering import html_text from render_world_class_evidence_intake import build_intake from render_world_class_evidence_ledger import build_ledger from render_world_class_submission_review import build_submission_review @@ -23,10 +23,6 @@ def rel_path(path: Path, root: Path) -> str: return str(path.resolve()) -def html_text(value: Any) -> str: - return html.escape("" if value is None else str(value), quote=True) - - def by_key(items: list[dict[str, Any]], key_name: str) -> dict[str, dict[str, Any]]: return {str(item.get(key_name, "")): item for item in items if item.get(key_name)} diff --git a/tests/verify_html_rendering.py b/tests/verify_html_rendering.py new file mode 100644 index 00000000..32fb436e --- /dev/null +++ b/tests/verify_html_rendering.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python3 +import json +import sys +from pathlib import Path + + +ROOT = Path(__file__).resolve().parent.parent +sys.path.insert(0, str(ROOT / "scripts")) + +from html_rendering import html_text # noqa: E402 + + +def main() -> None: + assert html_text(None) == "" + assert html_text(0) == "0" + assert html_text(False) == "False" + assert html_text("") == "" + assert html_text("&") == "<tag data-x="1">&</tag>" + print(json.dumps({"ok": True}, ensure_ascii=False, indent=2)) + + +if __name__ == "__main__": + main()