portfolio-optimiser-claude/tests/test_method_spec_loadbearing.py
Kjell Tore Guttormsen fae5b22578 test(loadbearing): positive controls for the static-guard half of the sibling-vacuity class
Point 2 of the sweep, enumerated rather than assumed. STATE's total was right and
its distribution was not: 86 hits confirmed (`assert not X` 41 / `== []` 42 /
`== {}` 2 / `== set()` 1), but per file measured `test_cli_paritet` 13 (STATE said
19), `test_preflight` 10 (11), `test_step7` 4 (6).

AST triage split the 86: 55 hits sit in 50 tests whose assertions are ALL
negative; the other 31 already have a positive sibling assert in the same test.

Two negative results worth recording, because they bound the remaining work:

- The `test_preflight` "clears" family (`_check_credentials(...) == []` and
  friends) is NOT vacuous. Each sits beside a sibling in the same class that
  asserts refusals are non-empty, so a no-op checker turns the sibling red.
  Class-level pairing is a real control; these need no change.
- `test_method_spec_loadbearing.py` already models the right pattern for
  detectors — explicit `test_guard_red_when_*` red-proofs against a mutated COPY.

This commit fixes the class that had no control at all: static/AST guards that
assert an absence without ever showing the scanner can detect a presence.

1. TAUTOLOGICAL RED-PROOFS (both spec guards). `test_guard_red_when_spec_missing`
   asserted a file is absent from a fresh `tmp_path` — true by construction of the
   fixture, and it never called the guard it is named for. It would have stayed
   green with `test_spec_is_present` deleted outright. Both now exercise the same
   `_spec_is_present` predicate the guard calls, in both directions.

2. MISSING RED-PROOF. `test_spec_keeps_structure_markers` had none, unlike its
   toolkit and contract-field siblings: with `_STRUCTURE_MARKERS` emptied or
   `_missing_markers` stubbed to `[]` it reported green forever. Added
   `test_guard_red_when_marker_removed`, parametrized over all 21 markers.

3. BLIND IMPORT SCANNERS (costsim x2, okf, preflight, notify). Every one asserted
   `not names & {forbidden}` or `outside == set()` with nothing showing `names`
   was non-empty — an empty scan satisfies them exactly as well as real purity.
   `test_okf_is_pure_stdlib`'s subset check is likewise trivially true of the
   empty set, so it did not guard its neighbour either. Each now asserts a
   known-present module first. The notify guard gets the strongest form
   available: it proves the detector DOES match a network import inside the seam,
   so the matcher itself is shown to work rather than only its silence.

Value-proved, not merely detach-proved. Seven vacuity mutations run against the
NEW tests: all seven RED, each dying on the intended control line. The same
mutations run against the PRE-CHANGE tests (session edits stashed): all five
applicable ones GREEN — blind to the vacuity they were meant to catch. Green
before, red after, same mutation, is the value-proof.

Harness held original bytes in memory, restored in `finally`, sha256-verified
every restore, and checked each run ACTUALLY RAN (a wrong test id yields rc!=0
and mimics red). `git status` clean before and after.

Remaining in the class and NOT closed here: ~45 all-negative tests, mostly CLI
refusal (`calls == []` after a refused invocation) and empty-default
(`missing dir -> []`). Listed in STATE, not silently dropped.

Suite 690 -> 711.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DJmse16bEkaSBtvXhncEUc
2026-08-01 20:01:21 +02:00

187 lines
6.7 KiB
Python

"""Spec-integrity seam for the method spec (method-spec §11, row "Spec integrity").
The sibling of ``test_ingest_spec_loadbearing.py``: this repo is built from
``shared/method-spec.md`` alone (pulled unchanged from commons), and this test keeps that
contract honest — it goes RED when the spec goes missing, names a concrete agent toolkit
(the framework-neutrality rule), loses a structural section/step marker, or stops
documenting a contract field this implementation consumes (§12 completeness).
Precision note (lesson from the ingest guard's detach spot-check): a substring-anywhere
assertion does not detach when only the §12 table row is removed but the field is still
mentioned in running text. The field assertions here are therefore scoped to the §12
cross-check block and require the backticked form, so removing a table row alone turns
the guard red. All assertions are presence-only (no forbidden-new-sections semantics),
so a commons amendment that ADDS sections or fields keeps the guard green.
Red-proofs run against a mutated COPY of the spec in ``tmp_path`` — never against
``shared/`` itself.
"""
from __future__ import annotations
from pathlib import Path
import pytest
SPEC = Path(__file__).resolve().parents[1] / "shared" / "method-spec.md"
# Concrete agent toolkits / vendor stacks the framework-neutral spec MUST NOT name
# (same list as the ingest-spec guard).
_FORBIDDEN_TOOLKITS = (
"claude",
"anthropic",
"openai",
"gpt",
"gemini",
"llama",
"langchain",
"autogen",
"crewai",
"semantic kernel",
"microsoft agent framework",
"agent sdk",
"bedrock",
"vertex",
"foundry",
"maf",
)
# Structural markers the spec must keep: the twelve normative sections, the eight loop
# steps, and RFC 2119 normative language.
_STRUCTURE_MARKERS = tuple(
[f"## {n}." for n in range(1, 13)] + [f"### Step {n}" for n in range(1, 9)] + ["MUST"]
)
# Every §12 contract field this implementation consumes (src-consumed per the 2026-07-16
# review's consume-list; the last four — outcome, modelled_saving_nok, gap_source,
# context_key — are golden/test-consumed only, guarded all the same).
_CONTRACT_FIELDS = (
"decision",
"marker",
"rationale",
"id",
"proposal_features",
"affected_codes",
"measure_type",
"claimed_saving_nok",
"description",
"project_id",
"measure",
"affected_items",
"code",
"quantity",
"unit_cost",
"assumptions",
"validates",
"nominal_feasible",
"p10",
"p50",
"p90",
"realization_rate",
"expected_actual_saving_nok",
"type",
"approved",
"rejected",
"approved_with_adjustment",
"outcome",
"modelled_saving_nok",
"gap_source",
"context_key",
)
def _named_toolkits(text: str) -> list[str]:
low = text.lower()
return [tok for tok in _FORBIDDEN_TOOLKITS if tok in low]
def _missing_markers(text: str) -> list[str]:
return [marker for marker in _STRUCTURE_MARKERS if marker not in text]
def _section12_block(text: str) -> str:
start = text.find("## 12.")
if start == -1:
return ""
end = text.find("\n## ", start + 1)
return text[start:] if end == -1 else text[start:end]
def _undocumented_fields(text: str) -> list[str]:
block = _section12_block(text)
return [field for field in _CONTRACT_FIELDS if f"`{field}`" not in block]
# --- The guard itself (against the real spec) ---------------------------------------
def _spec_is_present(path: Path) -> bool:
"""The presence predicate itself, so the red-proof can exercise THE SAME one."""
return path.is_file()
def test_spec_is_present() -> None:
# RED if the spec goes missing (the method stops being implementable from spec alone).
assert _spec_is_present(SPEC), "method-spec.md missing — subtree pull the commons contract"
def test_spec_keeps_structure_markers() -> None:
missing = _missing_markers(SPEC.read_text(encoding="utf-8"))
assert not missing, f"structural markers gone from the spec: {missing}"
def test_spec_names_no_agent_toolkit() -> None:
present = _named_toolkits(SPEC.read_text(encoding="utf-8"))
assert not present, f"framework-neutral spec names a concrete toolkit: {present}"
@pytest.mark.parametrize("field", _CONTRACT_FIELDS)
def test_spec_documents_contract_field(field: str) -> None:
undocumented = _undocumented_fields(SPEC.read_text(encoding="utf-8"))
assert field not in undocumented, (
f"contract field {field!r} is no longer documented (backticked) in the §12 block"
)
# --- Red-proofs: the guard MUST fail on a detached spec (mutated copy, never shared/) --
def test_guard_red_when_spec_missing(tmp_path: Path) -> None:
# Was VACUOUS: it asserted a file is absent from a fresh ``tmp_path`` — true by
# construction of the fixture, and it never touched the guard it is named for.
# It would have stayed green with ``test_spec_is_present`` deleted outright.
# Now it exercises THE SAME predicate the guard calls, both directions.
# Positive control first: without it, "False for a missing path" would also
# hold for a predicate that is False for everything.
assert _spec_is_present(SPEC)
assert not _spec_is_present(tmp_path / "method-spec.md")
@pytest.mark.parametrize("marker", _STRUCTURE_MARKERS)
def test_guard_red_when_marker_removed(tmp_path: Path, marker: str) -> None:
# The structure-marker guard had NO red-proof, unlike its toolkit and
# contract-field siblings: with ``_STRUCTURE_MARKERS`` emptied or
# ``_missing_markers`` stubbed to ``[]``, it would report green forever.
# Positive control: the REAL spec is missing no marker, so the detection
# below is the mutation being caught, not a spec that was already broken.
assert _missing_markers(SPEC.read_text(encoding="utf-8")) == []
mutated = SPEC.read_text(encoding="utf-8").replace(marker, "")
assert marker in _missing_markers(mutated)
@pytest.mark.parametrize("toolkit", _FORBIDDEN_TOOLKITS)
def test_guard_red_when_toolkit_injected(tmp_path: Path, toolkit: str) -> None:
mutated = SPEC.read_text(encoding="utf-8") + f"\n\nBuilt on {toolkit}.\n"
copy = tmp_path / "method-spec.md"
copy.write_text(mutated, encoding="utf-8")
assert toolkit in _named_toolkits(copy.read_text(encoding="utf-8"))
@pytest.mark.parametrize("field", _CONTRACT_FIELDS)
def test_guard_red_when_field_removed_from_section12(tmp_path: Path, field: str) -> None:
text = SPEC.read_text(encoding="utf-8")
block = _section12_block(text)
mutated = text.replace(block, block.replace(f"`{field}`", ""))
copy = tmp_path / "method-spec.md"
copy.write_text(mutated, encoding="utf-8")
assert field in _undocumented_fields(copy.read_text(encoding="utf-8"))