Skip to content

Commit 5d44d30

Browse files
Trecekclaude
andcommitted
test(execution/backends): add strength matrix meta-tests
Adds three meta-tests that validate the serialized hook_deny_strength_matrix.json produced by the probe harness: - test_matrix_combination_count: row count must equal EXPECTED_NON_INERT_COMBINATIONS (inert probes are not recorded) - test_works_as_is_hooks_have_soft_or_better: each works-as-is hook must have at least one soft/hard row in the matrix - test_not_applicable_hooks_appear_only_as_inert: not-applicable hooks must be absent from the matrix entirely (since their probes are inert) All three tests skip gracefully when the matrix JSON is absent. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent 36680d5 commit 5d44d30

1 file changed

Lines changed: 78 additions & 0 deletions

File tree

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
"""Meta-tests for the PreToolUse deny-mechanism strength matrix.
2+
3+
The matrix is written to ``.autoskillit/temp/hook_deny_strength_matrix.json``
4+
by the probe harness conftest once probes complete. When the JSON is absent
5+
(e.g., when only these meta-tests are collected), all three tests skip
6+
gracefully — the probe suite must be run first to populate the matrix.
7+
"""
8+
9+
from __future__ import annotations
10+
11+
import json
12+
from pathlib import Path
13+
14+
import pytest
15+
16+
from autoskillit.hook_registry import HOOK_REGISTRY
17+
from tests.execution.backends.conftest import EXPECTED_NON_INERT_COMBINATIONS
18+
19+
pytestmark = [pytest.mark.layer("execution"), pytest.mark.medium]
20+
21+
22+
_MATRIX_PATH = (
23+
Path(__file__).resolve().parents[3]
24+
/ ".autoskillit"
25+
/ "temp"
26+
/ "hook_deny_strength_matrix.json"
27+
)
28+
29+
30+
def _load_matrix() -> dict:
31+
"""Load the serialized strength matrix, skipping if absent."""
32+
if not _MATRIX_PATH.exists():
33+
pytest.skip("probe suite was not run — matrix JSON absent")
34+
return json.loads(_MATRIX_PATH.read_text(encoding="utf-8"))
35+
36+
37+
def test_matrix_combination_count() -> None:
38+
"""The matrix must contain exactly EXPECTED_NON_INERT_COMBINATIONS rows.
39+
40+
Inert probes return early without calling ``record_probe_row``, so the
41+
matrix holds only non-inert combinations.
42+
"""
43+
matrix = _load_matrix()
44+
assert len(matrix["combinations"]) == EXPECTED_NON_INERT_COMBINATIONS
45+
46+
47+
def test_works_as_is_hooks_have_soft_or_better() -> None:
48+
"""For each works-as-is hook, at least one matrix row must be soft or hard.
49+
50+
A "works-as-is" hook claims codex parity — its guard must produce a
51+
non-inert outcome (``soft`` or ``hard``) for at least one matrix row.
52+
"""
53+
matrix = _load_matrix()
54+
rows = matrix["combinations"]
55+
56+
works_as_is_stems: set[str] = {
57+
Path(hd.scripts[0]).stem for hd in HOOK_REGISTRY if hd.codex_status == "works-as-is"
58+
}
59+
seen_stems: set[str] = set()
60+
for row in rows:
61+
if row["hook"] in works_as_is_stems and row["strength"] in {"soft", "hard"}:
62+
seen_stems.add(row["hook"])
63+
64+
missing = works_as_is_stems - seen_stems
65+
assert not missing, f"works-as-is hooks missing soft/hard rows: {missing}"
66+
67+
68+
def test_not_applicable_hooks_appear_only_as_inert() -> None:
69+
"""Not-applicable hooks must be absent from the matrix (inert probes are not recorded)."""
70+
matrix = _load_matrix()
71+
rows = matrix["combinations"]
72+
73+
not_applicable_stems: set[str] = {
74+
Path(hd.scripts[0]).stem for hd in HOOK_REGISTRY if hd.codex_status == "not-applicable"
75+
}
76+
matrix_stems: set[str] = {row["hook"] for row in rows}
77+
leaked = not_applicable_stems & matrix_stems
78+
assert not leaked, f"not-applicable hooks appeared in matrix: {leaked}"

0 commit comments

Comments
 (0)