"""P18/C1 — ``--docs-dir`` is optional once ``--bundle-dir`` is given.
P16 FUNN 2: the documented stress command names the same directory twice
(``--docs-dir --bundle-dir ``), because single-project mode demanded ``--docs-dir``
even on the bundle path — where it is never read. Retrieval, the chunk tool and the "no citable
content" check all live in the ROAD branch (``run.py``); the bundle branch builds its citations
from the navigated base. So the flag was required for a path that ignores it, and the published
command had to satisfy the requirement by repeating itself.
**This is not the "--docs-dir omvei"** (feeding project documents through retrieval INSTEAD of
ingesting them into a knowledge base), which STATE forbids and this order forbids again. No such
path is opened: the road branch still refuses without a real ``--docs-dir``, and the value is
bound ONCE from ``--bundle-dir`` — byte-identically what the README already tells an operator to
type by hand, so every existing invocation, the two-flag form included, is unchanged.
"""
from __future__ import annotations
import json
import shutil
from pathlib import Path
from typing import Any
import pytest
from portfolio_optimiser import run
_FIXTURES = Path(__file__).parent / "fixtures"
_PRICED = _FIXTURES / "k2-prisskjema-SYNTETISK"
_IR_PROJECTION = {
"project_id": "K2",
"measure": "energy_efficiency",
"claimed_saving_nok": 1000.0,
"affected_codes": ["01.1"],
}
def _runnable(tmp_path: Path) -> str:
root = tmp_path / "base"
shutil.copytree(_PRICED, root)
(root / "validator-input.json").write_text(json.dumps(_IR_PROJECTION), encoding="utf-8")
return str(root)
def test_a_bundle_run_needs_no_docs_dir(tmp_path: Path, capsys: pytest.CaptureFixture[str]) -> None:
"""(a) The fix. A free dry run on ``--bundle-dir`` alone is ACCEPTED and reaches the bundle
path — asserted on the run-config the dry run prints, not on rc alone, since rc 0 is also what
a run that silently took the road path would return."""
rc = run.main(["K2", "--bundle-dir", _runnable(tmp_path), "--live-dry-run"])
assert rc == 0
assert "LIVE-DRY-RUN OK" in capsys.readouterr().out
def test_the_documented_two_flag_form_still_works(
tmp_path: Path, capsys: pytest.CaptureFixture[str]
) -> None:
"""(b) The CONTROL that this is a widening, not a change. The README's form — the same
directory twice — must be byte-for-byte as accepted as it was before."""
base = _runnable(tmp_path)
rc = run.main(["K2", "--docs-dir", base, "--bundle-dir", base, "--live-dry-run"])
assert rc == 0
assert "LIVE-DRY-RUN OK" in capsys.readouterr().out
def test_neither_flag_is_still_refused_by_name(capsys: pytest.CaptureFixture[str]) -> None:
"""(c) The half that must NOT be relaxed: the road path has no base to fall back to, so an
argv naming neither is refused, and the refusal names BOTH doors rather than only the one it
used to name."""
rc = run.main(["K2", "--live-dry-run"])
assert rc == 1
err = capsys.readouterr().err
assert "run refused" in err and "--docs-dir" in err and "--bundle-dir" in err
def test_the_road_path_still_requires_a_real_docs_dir(
tmp_path: Path, capsys: pytest.CaptureFixture[str]
) -> None:
"""(d) The anti-omvei arm. With no bundle, ``--docs-dir`` is still the only door AND it is
still read: a directory holding nothing citable is refused by the road branch's own check, so
nothing here turns retrieval into a substitute for ingestion."""
empty = tmp_path / "tomt"
empty.mkdir()
rc = run.main(["P1", "--docs-dir", str(empty), "--live-dry-run"])
assert rc == 1
assert capsys.readouterr().err.strip(), "the road path must say why, not fail silently"
def test_the_bundle_value_is_bound_once_and_reaches_run_project(
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
"""(e) The SEAM. rc 0 above would also be satisfied by a CLI that never forwarded the value, so
the argument ``run_project`` actually receives is recorded — one binding, both dispatch sites."""
base = _runnable(tmp_path)
seen: dict[str, Any] = {}
async def _record(project_id: str, profile: Any, **kw: Any) -> Any:
seen.update(kw)
raise SystemExit(0)
monkeypatch.setattr("portfolio_optimiser.run.run_project", _record)
with pytest.raises(SystemExit):
run.main(["K2", "--bundle-dir", base, "--live-dry-run"])
assert seen["docs_dir"] == base == seen["bundle_dir"]