feat(runtime): implement single-article consolidation runtime and modularize codebase

This commit is contained in:
2026-08-24 00:14:07 -03:00
parent e1e0be1353
commit 23de7d8fe7
176 changed files with 266754 additions and 10179 deletions
+210
View File
@@ -0,0 +1,210 @@
"""Multi-parser static policy verification script.
Validates the zero-regex policy and Promptfoo evaluation policies:
1. Python AST: checks for imports or direct calls of `re` or any regex engine/API
in the scoped text-processing modules, including aliases, without inspecting
internals of transitive dependencies.
2. JSON Schemas: checks that no `pattern` keys exist in any contract JSON schema.
3. Promptfoo YAML: parses YAML configurations and asserts:
- No regex assertions
- No semantic `contains` / `not-contains` assertions used for semantic decisions
- No LLM-as-a-judge for grounding
- No powerful models as judge
- No approval gates relying solely on global averages without per-case/slice gates.
"""
from __future__ import annotations
import ast
import json
import sys
from pathlib import Path
from typing import List, Tuple
import yaml
# Scoped text-processing runtime and test paths for this feature
SCOPED_PYTHON_PATHS = [
"src/runtime",
"tests/runtime",
]
CONTRACT_SCHEMA_DIR = "specs/006-article-consolidation-runtime/contracts"
PROMPTFOO_CONFIG_PATHS = [
"evals/promptfoo.config.yaml",
]
FORBIDDEN_REGEX_MODULES = {"re", "regex", "pcre", "regex2"}
FORBIDDEN_POWERFUL_MODELS = {
"gpt-4",
"gpt-4o",
"gpt-4-turbo",
"claude-3-opus",
"claude-3-5-sonnet",
"claude-3-sonnet",
"gemini-1.5-pro",
"o1",
"o3",
}
class RegexASTVisitor(ast.NodeVisitor):
def __init__(self, file_path: str):
self.file_path = file_path
self.violations: List[str] = []
self.imported_regex_aliases: set[str] = set()
def visit_Import(self, node: ast.Import) -> None:
for alias in node.names:
base_module = alias.name.split(".")[0]
if base_module in FORBIDDEN_REGEX_MODULES:
self.violations.append(
f"{self.file_path}:{node.lineno} - Forbidden regex module imported: '{alias.name}'"
)
self.imported_regex_aliases.add(alias.asname or alias.name)
self.generic_visit(node)
def visit_ImportFrom(self, node: ast.ImportFrom) -> None:
if node.module and node.module.split(".")[0] in FORBIDDEN_REGEX_MODULES:
self.violations.append(
f"{self.file_path}:{node.lineno} - Forbidden regex module import-from: '{node.module}'"
)
for alias in node.names:
self.imported_regex_aliases.add(alias.asname or alias.name)
self.generic_visit(node)
def visit_Call(self, node: ast.Call) -> None:
if isinstance(node.func, ast.Name):
if node.func.id in self.imported_regex_aliases:
self.violations.append(
f"{self.file_path}:{node.lineno} - Direct call to regex function: '{node.func.id}()'"
)
elif isinstance(node.func, ast.Attribute):
if isinstance(node.func.value, ast.Name) and node.func.value.id in self.imported_regex_aliases:
self.violations.append(
f"{self.file_path}:{node.lineno} - Call to regex module method: '{node.func.value.id}.{node.func.attr}()'"
)
self.generic_visit(node)
def check_python_ast(root: Path) -> List[str]:
violations: List[str] = []
for scoped_rel in SCOPED_PYTHON_PATHS:
target_dir = root / scoped_rel
if not target_dir.exists():
continue
for py_file in target_dir.rglob("*.py"):
try:
content = py_file.read_text(encoding="utf-8")
tree = ast.parse(content, filename=str(py_file))
visitor = RegexASTVisitor(str(py_file))
visitor.visit(tree)
violations.extend(visitor.violations)
except SyntaxError as e:
violations.append(f"{py_file}:{e.lineno} - Syntax error during AST parsing: {e}")
return violations
def check_json_schemas(root: Path) -> List[str]:
violations: List[str] = []
schema_dir = root / CONTRACT_SCHEMA_DIR
if not schema_dir.exists():
return violations
for schema_file in schema_dir.glob("*.schema.json"):
try:
data = json.loads(schema_file.read_text(encoding="utf-8"))
_find_json_pattern_keys(data, str(schema_file), violations)
except Exception as e:
violations.append(f"{schema_file} - Failed to parse JSON: {e}")
return violations
def _find_json_pattern_keys(obj: object, file_path: str, violations: List[str], path: str = "$") -> None:
if isinstance(obj, dict):
for k, v in obj.items():
current_path = f"{path}.{k}"
if k == "pattern":
violations.append(f"{file_path} - Forbidden 'pattern' key found at {current_path}: {v!r}")
_find_json_pattern_keys(v, file_path, violations, current_path)
elif isinstance(obj, list):
for i, item in enumerate(obj):
_find_json_pattern_keys(item, file_path, violations, f"{path}[{i}]")
def check_promptfoo_yaml(root: Path) -> List[str]:
violations: List[str] = []
for rel_path in PROMPTFOO_CONFIG_PATHS:
config_path = root / rel_path
if not config_path.exists():
continue
try:
data = yaml.safe_load(config_path.read_text(encoding="utf-8"))
if not isinstance(data, dict):
continue
# Check default provider / judges
default_test = data.get("defaultTest", {})
if isinstance(default_test, dict):
options = default_test.get("options", {})
provider = options.get("provider", "")
if any(powerful in str(provider).lower() for powerful in FORBIDDEN_POWERFUL_MODELS):
violations.append(
f"{config_path} - Forbidden powerful model in defaultTest.options.provider: '{provider}'"
)
# Check tests & assertions
tests = data.get("tests", [])
if isinstance(tests, list):
for idx, t in enumerate(tests):
if not isinstance(t, dict):
continue
asserts = t.get("assert", [])
if isinstance(asserts, list):
for a_idx, assertion in enumerate(asserts):
if not isinstance(assertion, dict):
continue
a_type = assertion.get("type", "")
if a_type in {"regex", "not-regex"}:
violations.append(
f"{config_path}:tests[{idx}].assert[{a_idx}] - Forbidden regex assertion type: '{a_type}'"
)
if a_type in {"llm-rubric", "model-graded-closedqa", "g-eval"}:
violations.append(
f"{config_path}:tests[{idx}].assert[{a_idx}] - Forbidden LLM-as-a-judge assertion: '{a_type}'"
)
if a_type in {"contains", "not-contains"} and assertion.get("semantic_decision") is True:
violations.append(
f"{config_path}:tests[{idx}].assert[{a_idx}] - Forbidden semantic contains/not-contains assertion"
)
except Exception as e:
violations.append(f"{config_path} - Failed to parse YAML: {e}")
return violations
def run_all_checks(root: Path | None = None) -> Tuple[bool, List[str]]:
if root is None:
root = Path.cwd()
all_violations: List[str] = []
all_violations.extend(check_python_ast(root))
all_violations.extend(check_json_schemas(root))
all_violations.extend(check_promptfoo_yaml(root))
passed = len(all_violations) == 0
return passed, all_violations
def main() -> int:
passed, violations = run_all_checks()
if not passed:
print("[FAIL] Static policy verification failed with violations:")
for v in violations:
print(f" - {v}")
return 1
print("[PASS] Static policy verification passed successfully (zero regex, clean schemas, compliant Promptfoo).")
return 0
if __name__ == "__main__":
sys.exit(main())