B-gate row 1's premise, made callable. Every path through the framework CLI constructs a chat
client, so an outside caller -- a human at a terminal, or an agent that is NOT po -- could not
reach a single run-path step without paying for a model. These four steps need no model at all.
One CLI, four subcommands, one core call each:
navigate-bundle --bundle-dir -> okf.navigate_bundle
cost-baseline --bundle-dir --project-id -> okf.derive_cost_baseline
retrieve-chunks --query --docs-dir [--top-k] -> datasource.retrieve_chunks
prepass-admit --payload --bundle-dir [--dimension] -> prepass.admit_payload
Each handler is a thin adapter: strings in, the SAME function the run path calls, JSON on stdout,
and an exit code that says what happened (0 ran, 2 malformed call, 3 the step refused, named).
A handler that computed anything of its own would be a second implementation of a run-path step,
and the outside caller would stop getting what the debate gets.
Dispatch is an explicit branch per command, not argparse's `set_defaults(handler=...)`: the table
hides the one thing a reader wants to see, and B-gate row 1 asks the same question of the source
(it walks the call graph from `main` down to the step's symbol), where a callable in a Namespace
is a hop neither can follow.
Probes (`tests/test_toolbox_doors.py`, 10 arms): each starts the door as a SUBPROCESS with the
subcommand in argv and asserts on what it wrote -- never by importing the core function, which is
the whole difference the gate exists to measure. The yardstick is outside the door in every arm:
the filesystem (navigate-bundle, including the one deliberate outside-bundle link), a table
transcribed from the priced fixture (cost-baseline), the in-process seam it must equal byte for
byte (retrieve-chunks), and the producer's own checked-in payload (prepass-admit). Every refusal
arm has an rc-0 control beside it.
`portfolio-optimiser-toolbox` is the THIRD console script, and the pin test now says why: it is
the door the other two cannot be used for. README and CLAUDE.md updated with the command and the
reason it exists; every documented invocation was run.
Row 1: 1 -> 5 of 17 (four subcommands + `gate`, which the class fix in e47be68 stopped rejecting
on a name technicality). No other row moved; exit 1.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
90 lines
4.4 KiB
Python
90 lines
4.4 KiB
Python
"""P4 pkt. 5 — the console entry points are part of the FROZEN install surface.
|
|
|
|
The README's central claim is "download -> run". Until now every documented invocation went
|
|
through ``uv run python -m portfolio_optimiser.<module>``, which works but is not an install
|
|
surface: nothing in the distribution metadata promised a command. This test pins the two commands
|
|
that the demo and the framework CLI are reached by.
|
|
|
|
Why read ``importlib.metadata`` and not ``pyproject.toml``: a ``[project.scripts]`` line that has
|
|
never been ``uv sync``-ed is a claim, not a command. The distribution metadata is what a fresh
|
|
clone materializes after ``uv sync``, so it is the only reading that can fail when the surface is
|
|
merely *declared*. The declaration is checked too (the TOML is the source the metadata is built
|
|
from), but the metadata assert is the load-bearing one.
|
|
|
|
Scope, stated so it is a decision and not an oversight: exactly THREE commands are exposed.
|
|
``run`` is the framework CLI (three documented modes), ``simulation`` is the offline end-to-end
|
|
proof the README points a newcomer at, and ``toolbox`` (added 2026-09-20) is the door an outside
|
|
caller reaches the run-path steps through WITHOUT a chat client — B-gate row 1's premise, and the
|
|
one thing the other two cannot be used for, since every path through ``run`` constructs a client.
|
|
``costsim`` / ``hitl`` / ``preflight`` keep the ``-m`` form — they are operator utilities, not the
|
|
product's front door, and every name added here is a name the freeze has to carry.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import importlib
|
|
import importlib.metadata
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
_DIST = "portfolio-optimiser"
|
|
|
|
# command name -> "module:function" target, verbatim as it must appear in the metadata.
|
|
_EXPECTED: dict[str, str] = {
|
|
"portfolio-optimiser": "portfolio_optimiser.run:main",
|
|
"portfolio-optimiser-demo": "portfolio_optimiser.simulation:main",
|
|
"portfolio-optimiser-toolbox": "portfolio_optimiser.toolbox:main",
|
|
}
|
|
|
|
|
|
def _console_scripts() -> dict[str, str]:
|
|
"""The installed distribution's console scripts, as ``{name: "module:function"}``."""
|
|
return {
|
|
ep.name: ep.value
|
|
for ep in importlib.metadata.distribution(_DIST).entry_points
|
|
if ep.group == "console_scripts"
|
|
}
|
|
|
|
|
|
@pytest.mark.parametrize(("name", "target"), sorted(_EXPECTED.items()))
|
|
def test_console_script_is_installed(name: str, target: str) -> None:
|
|
"""T-P4.5a: the command exists in the INSTALLED distribution and points at the right target.
|
|
|
|
RED when the ``[project.scripts]`` entry is removed (or when it is added to the TOML without a
|
|
re-sync — which is the same failure a fresh clone would hit for real).
|
|
"""
|
|
scripts = _console_scripts()
|
|
assert name in scripts, (
|
|
f"console script {name!r} is not installed; found {sorted(scripts)}. "
|
|
"Declare it under [project.scripts] in pyproject.toml and re-run `uv sync`."
|
|
)
|
|
assert scripts[name] == target
|
|
|
|
|
|
@pytest.mark.parametrize("name", sorted(_EXPECTED))
|
|
def test_console_script_target_resolves(name: str) -> None:
|
|
"""T-P4.5b: the INSTALLED target actually imports and is callable — a typo'd module or function
|
|
name installs a command that only fails when the operator runs it, which on demo day is on
|
|
stage. Resolves what the distribution says, not what this file expects: resolving ``_EXPECTED``
|
|
would only ever re-check a constant against itself."""
|
|
target = _console_scripts()[name]
|
|
module_name, _, func_name = target.partition(":")
|
|
module = importlib.import_module(module_name)
|
|
entry = getattr(module, func_name, None)
|
|
assert callable(entry), f"{target} (behind {name}) does not resolve to a callable"
|
|
|
|
|
|
def test_pyproject_declares_exactly_these_scripts() -> None:
|
|
"""T-P4.5c: the declaration in ``pyproject.toml`` matches the installed set exactly.
|
|
|
|
Guards the drift direction the metadata assert cannot see: a script installed from an older
|
|
sync but since deleted from the TOML would leave a command that a fresh clone never gets.
|
|
"""
|
|
pyproject = Path(__file__).resolve().parents[1] / "pyproject.toml"
|
|
try:
|
|
import tomllib
|
|
except ModuleNotFoundError: # pragma: no cover - Python 3.10 has no tomllib
|
|
pytest.skip("tomllib is 3.11+; the installed-metadata asserts cover the same surface")
|
|
declared = tomllib.loads(pyproject.read_text(encoding="utf-8"))["project"]["scripts"]
|
|
assert declared == _EXPECTED
|