scripts.factory_fastpath
Reference › scripts › factory_fastpath
The command-line interface for the SPEC-033 B12 fast-path classifier (ADR-0023). It shares its evaluator and evidence handling with factory_anchors, through evaluation and gate. The factory narrative describes the subsystem. No module or test imports it.
Invocation: main has two subcommands. structural computes a structural proof for a change (_cmd_structural, printed through _structural_to_dict). classify decides whether a change can take the fast path, loading an anchor evidence file (_load_evidence) and running the default evaluators (_default_evaluators); the anchor gate verdict is included in the output (_anchor_verdict_to_dict). Comma-separated lists of options are split by _split_csv. Each handler returns the exit code.
At a glance
| Source | scripts/factory_fastpath.py |
| Lines of code | 250 |
| Classes | 0 |
| Functions | 11 |
| Imports (internal) | orchestrata_ultimate.factory.anchors.evaluation, orchestrata_ultimate.factory.anchors.gate, orchestrata_ultimate.factory.anchors.store, orchestrata_ultimate.factory.fastpath.classifier |
| Imported by | none |
| Tests that import it | none |
Class diagram
No classes; see Functions.
Dependency diagram
API
Functions
| Function | Signature | Summary |
|---|---|---|
_default_evaluators |
_default_evaluators() -> list[AnchorEvaluator] |
The three built-in evaluators (one per anchor class), same as factory_anchors.py. |
_load_evidence |
_load_evidence(evidence_path: Path) -> AnchorEvidence |
Load an AnchorEvidence from a JSON file. |
_split_csv |
_split_csv(raw: str) -> list[str] |
Split a comma-separated CLI value into a list, dropping empty entries. |
_structural_to_dict |
_structural_to_dict(proof: StructuralProof) -> dict[str, Any] |
|
_anchor_verdict_to_dict |
_anchor_verdict_to_dict(verdict: AnchorGateVerdict | None) -> dict[str, Any] | None |
|
_cmd_structural |
_cmd_structural(args: argparse.Namespace) -> int |
|
_cmd_classify |
_cmd_classify(args: argparse.Namespace) -> int |
|
_add_structural_parser |
_add_structural_parser(sub: argparse._SubParsersAction) -> None |
|
_add_classify_parser |
_add_classify_parser(sub: argparse._SubParsersAction) -> None |
|
_build_parser |
_build_parser() -> argparse.ArgumentParser |
|
main |
main(argv: list[str] | None = None) -> int |
Parse argv and dispatch to the matching subcommand handler. |
Source
#!/usr/bin/env python3
"""CLI for the SPEC-033 B12 fast-path classifier (ADR-0023).
Subcommands
-----------
structural Run only the structural half (within-contract: same public
surface, no new outbound edges) -- cheap, stdlib ``ast`` only.
classify Run the combined ADR-0023 decision: structural first, then
(only if structural passed) the B15b anchor gate. Emits a
JSON ``FastPathDecision`` including the worked ``CostTrace``.
Examples
--------
python scripts/factory_fastpath.py structural --repo-root . \\
--base HEAD~1 --files src/pkg/mod.py
python scripts/factory_fastpath.py classify --repo-root . \\
--base HEAD~1 --files src/pkg/mod.py --requirements REQ-033-C5 \\
--registry anchors.json --evidence evidence.json \\
--changed-anchors ANC-xxxxxxxxxxxx
WORKED EXAMPLE (real numbers, captured while building this classifier by
actually running the two commands above against a scratch git repo seeded
from this project's own ``orchestrata_ultimate.factory.anchors.models``
module -- not fabricated)
-------------------------------------------------------------------------
Base commit ``d50e24b5``; HEAD is a body-only edit (the module docstring
changed, public surface untouched); one RATIFIED, SATISFIED, unchanged
EXAMPLE anchor on the touched requirement. The real ``classify()`` JSON
output (structural passed, so anchors were evaluated too -- the fast path
fired, exit code 0):
{
"eligible": true,
"structural": {
"within_contract": true,
"new_public_symbols": [],
"removed_public_symbols": [],
"changed_signatures": [],
"new_outbound_imports": [],
"non_python_changes": []
},
"anchor_verdict": {
"fast_path_eligible": true,
"blocking": [],
"edited_anchor_ids": [],
"results": [
{
"anchor_id": "ANC-379c0437113d",
"klass": "example",
"satisfaction": "satisfied",
"detail": "k='1' matches expected '1'"
}
]
},
"cost_trace": {
"structural_seconds": 0.003735624995897524,
"anchors_seconds": 0.0002003879999392666,
"anchors_evaluated": 1,
"files_classified": 1,
"route": "fast"
}
}
The number that matters for the ROI argument: structural (~3.7ms, one
``git show`` subprocess + two ``ast.parse`` calls) dominates anchor
evaluation (~0.2ms, a single in-memory comparison) by ~19x on this file --
and on the slow path (structural fails), the anchor number is never even
paid at all (``anchors_seconds`` is ``None``, not merely small).
"""
from __future__ import annotations
import argparse
import json
import sys
from pathlib import Path
from typing import Any
# Ensure repo src is on path when run directly (mirrors factory_anchors.py /
# kg_schema.py / run_ast_pipeline.py).
_repo_src = Path(__file__).resolve().parent.parent / "src"
if str(_repo_src) not in sys.path:
sys.path.insert(0, str(_repo_src))
from orchestrata_ultimate.factory.anchors.evaluation import ( # noqa: E402
AnchorEvaluator,
AnchorEvidence,
ExampleEvaluator,
OracleEvaluator,
PropertyEvaluator,
)
from orchestrata_ultimate.factory.anchors.gate import AnchorGateVerdict # noqa: E402
from orchestrata_ultimate.factory.anchors.store import AnchorRegistry # noqa: E402
from orchestrata_ultimate.factory.fastpath.classifier import ( # noqa: E402
StructuralProof,
classify,
structural_within_contract,
)
def _default_evaluators() -> list[AnchorEvaluator]:
"""The three built-in evaluators (one per anchor class), same as factory_anchors.py."""
return [ExampleEvaluator(), PropertyEvaluator(), OracleEvaluator()]
def _load_evidence(evidence_path: Path) -> AnchorEvidence:
"""Load an ``AnchorEvidence`` from a JSON file.
Expected shape: ``{"observed_outputs": {...}, "differential": {...}}``
(both optional, default to ``{}``).
"""
with open(evidence_path, encoding="utf-8") as f:
data = json.load(f)
return AnchorEvidence(
observed_outputs=data.get("observed_outputs", {}),
differential=data.get("differential", {}),
)
def _split_csv(raw: str) -> list[str]:
"""Split a comma-separated CLI value into a list, dropping empty entries."""
return [item for item in raw.split(",") if item]
def _structural_to_dict(proof: StructuralProof) -> dict[str, Any]:
return {
"within_contract": proof.within_contract,
"new_public_symbols": proof.new_public_symbols,
"removed_public_symbols": proof.removed_public_symbols,
"changed_signatures": proof.changed_signatures,
"new_outbound_imports": proof.new_outbound_imports,
"non_python_changes": proof.non_python_changes,
}
def _anchor_verdict_to_dict(verdict: AnchorGateVerdict | None) -> dict[str, Any] | None:
if verdict is None:
return None
return {
"fast_path_eligible": verdict.fast_path_eligible,
"blocking": verdict.blocking,
"edited_anchor_ids": verdict.edited_anchor_ids,
"results": [
{
"anchor_id": result.anchor_id,
"klass": result.klass.value,
"satisfaction": result.satisfaction.value,
"detail": result.detail,
}
for result in verdict.results
],
}
def _cmd_structural(args: argparse.Namespace) -> int:
repo_root = Path(args.repo_root)
files = _split_csv(args.files)
proof = structural_within_contract(repo_root, args.base, files)
print(json.dumps(_structural_to_dict(proof), indent=2))
return 0 if proof.within_contract else 1
def _cmd_classify(args: argparse.Namespace) -> int:
repo_root = Path(args.repo_root)
files = _split_csv(args.files)
requirements = _split_csv(args.requirements)
changed_anchor_ids = set(_split_csv(args.changed_anchors or ""))
registry = AnchorRegistry(Path(args.registry))
try:
evidence = _load_evidence(Path(args.evidence))
except (OSError, ValueError) as exc:
print(f"error: {exc}")
return 1
decision = classify(
repo_root,
args.base,
files,
requirements,
registry,
evidence,
_default_evaluators(),
changed_anchor_ids=changed_anchor_ids,
)
output = {
"eligible": decision.eligible,
"structural": _structural_to_dict(decision.structural),
"anchor_verdict": _anchor_verdict_to_dict(decision.anchor_verdict),
"cost_trace": decision.cost_trace.to_dict(),
}
print(json.dumps(output, indent=2))
return 0 if decision.eligible else 1
def _add_structural_parser(sub: argparse._SubParsersAction) -> None:
structural_p = sub.add_parser(
"structural", help="Run only the ADR-0023 structural (within-contract) half."
)
structural_p.add_argument("--repo-root", required=True)
structural_p.add_argument("--base", required=True)
structural_p.add_argument("--files", required=True, help="comma-separated paths")
def _add_classify_parser(sub: argparse._SubParsersAction) -> None:
classify_p = sub.add_parser(
"classify",
help="Combined ADR-0023 decision: structural first, anchors second.",
)
classify_p.add_argument("--repo-root", required=True)
classify_p.add_argument("--base", required=True)
classify_p.add_argument("--files", required=True, help="comma-separated paths")
classify_p.add_argument(
"--requirements", required=True, help="comma-separated requirement ids"
)
classify_p.add_argument("--registry", required=True)
classify_p.add_argument("--evidence", required=True)
classify_p.add_argument(
"--changed-anchors",
dest="changed_anchors",
default="",
help="comma-separated anchor ids edited by this change",
)
def _build_parser() -> argparse.ArgumentParser:
parser = argparse.ArgumentParser(
prog="factory_fastpath",
description="SPEC-033 B12 fast-path classifier CLI (ADR-0023).",
)
sub = parser.add_subparsers(dest="command", required=True)
_add_structural_parser(sub)
_add_classify_parser(sub)
return parser
def main(argv: list[str] | None = None) -> int:
"""Parse ``argv`` and dispatch to the matching subcommand handler."""
parser = _build_parser()
args = parser.parse_args(argv)
dispatch = {
"structural": _cmd_structural,
"classify": _cmd_classify,
}
handler = dispatch[args.command]
return handler(args)
if __name__ == "__main__":
sys.exit(main())