measurement: does the suite notice when a conformance check breaks - #57
Conversation
Fork-only. Nothing under the existing tree is modified; this adds one directory. For every Finding(..., Status.FAIL, ...) site in the conformance modules, rewrite it so the check can never fail, run the suite, count how many tests notice, restore. 23 of 33 failure paths are guarded. Ten are not, including all three of TR-TXN-001, which is the only enforcement of the Level 2 tool-transcript requirement since tool_transcript is absent from the schema's required array. None of the checks is wrong. This measures whether a regression would be caught. Signed-off-by: lywinged <48041247+lywinged@users.noreply.github.com>
|
Thank you for opening it, and the stale-install finding is a real hole rather than an environment quirk. It belongs in the same list as the three guards the docstring already claims, and it is the one that would have embarrassed the measurement rather than merely broken it. The three existing guards all defend against a mutation that did not take effect: a red baseline, a rewrite that changed nothing, an empty site list. Yours is the same failure one layer down — the mutation takes effect on a tree the suite never imports. The symptom is identical to the strongest possible result, every site reporting that nothing noticed, and 0 of 18 verified is exactly what a suite with no guarded checks at all would print. An instrument that cannot separate I measured nothing from there is nothing to measure has to refuse rather than report. The guard, in the same shape as the others, checked before the baseline rather than inferred after: def assert_suite_imports_this_checkout() -> None:
"""The suite must import the tree being mutated, not another copy of it.
The guards above defend against a mutation that did not take effect. This one
defends against it taking effect on a tree the suite never imports: an editable
install pointing elsewhere, a wheel earlier on sys.path, a stale .pth. The symptom
is indistinguishable from a perfect result at the other end, so it is a precondition
and not a diagnosis.
"""
probe = subprocess.run(
[sys.executable, "-c",
"import pathlib, trace_tests; print(pathlib.Path(trace_tests.__file__).resolve())"],
cwd=TRACE_TESTS, capture_output=True, text=True,
)
if probe.returncode != 0:
sys.exit(
"could not import trace_tests with the interpreter that runs the suite:\n"
+ probe.stderr.strip()
)
imported = Path(probe.stdout.strip())
expected = (TRACE_TESTS / "src" / "trace_tests").resolve()
if not (expected == imported.parent or expected in imported.parents):
sys.exit(
f"the suite imports trace_tests from {imported.parent}\n"
f"but this run mutates {expected}\n"
"Every site would report that nothing noticed, which is also what a suite "
"with no guarded checks looks like. Reinstall with `pip install -e .` from "
"this checkout, or run with PYTHONPATH=src."
)It uses
On delivery: |
…nverified The harness in measurement/ reported ten of thirty-three Finding(..., FAIL, ...) sites at margin zero: rewriting any of them so it could never fail left the whole suite green. Landing the instrument without the tests would have published a gap list against our own conformance suite and fixed nothing. tr_txn and tr_sca had no unit tests at all, which is why every one of their failure paths measured zero. TR-TXN-001 carried the most weight: it is the only place the Level 2 tool-transcript requirement is enforced anywhere in the suite. New: tests/unit/test_tr_txn.py, tests/unit/test_tr_sca.py. Extended: test_tr_sig.py with the two check_cmcp_runtime key-shape paths, the unsupported kty path, and the signature-present-but-uncheckable path; test_tr_anc.py with a URI that raises during parsing rather than parsing to a wrong scheme. The two TR-SIG-002 vectors are deliberately separable: an implementation that checks kty and crv without checking x passes one and fails the other, which is what makes them two vectors rather than one written twice. Re-measured: 18 of 18 checks and 33 of 33 sites verified, none unguarded. Eight checks sit at margin 1, which the report now names as the number to watch. REPORT.md and README.md updated to describe the state they measured rather than the state they found. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
bool is an int subclass, so call_count: true passed the non-negative integer check and reported as a call count of one, false as zero. A record that says true there is malformed, and a conformance suite that silently reads it as a number is answering a question nobody asked. Found by writing the TR-TXN-002 guard test, so the test and the fix land together. Same class as the issued_at case in agentrust-io/trace-spec#146. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…#59) The three guards this script already documents defend against a mutation that did not take effect: a red baseline, a rewrite that changed nothing, an empty site list. This is the same failure one layer down. The mutation takes effect, and the suite runs against a tree that never sees it. Reported on #57: run against a stale editable install, the harness returned 0 of 18 verified while rewriting the checkout's modules correctly the whole time, because pytest was importing `trace_tests` from somewhere else. Nothing fails, every site reports that nothing noticed, and that reads exactly like a suite with no guarded checks at all. An instrument that cannot separate "I measured nothing" from "there is nothing to measure" has to decline rather than report. `assert_suite_imports_this_checkout` probes through the same interpreter and working directory `run_suite` uses, so it resolves the import the way the measurement will rather than the way the script happened to be launched, and it runs before the baseline rather than diagnosing afterwards. Verified both directions: against this checkout it passes and exits 0; against a second checkout while the install still points at the first it exits 1 with both paths named. The full run is unchanged at 18 of 18 verified, 0 unverified, 8 at margin 1. Signed-off-by: lywinged <48041247+lywinged@users.noreply.github.com> Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
…62) Closes #53. #57 closed the first half of that issue: the ten unguarded conformance failure paths are now guarded, 33 of 33 sites verified. The second half was still open - tests/test_level0.py:7 restates the runtime.platform enum and holds nine of the schema's ten values, missing software-only. That is the value docs/trust-levels.md requires for Level 0. A Level 0 record as documented would fail test_runtime_platform_registered; nothing noticed because valid_level0.json uses intel-tdx. The value is added, and so is the general guard. Five set literals in this repository restate a schema enum: tr_rte._VALID_PLATFORMS runtime.platform tr_pol._VALID_ENFORCEMENT policy.enforcement_mode test_level0.VALID_PLATFORMS runtime.platform test_level0.VALID_ENFORCEMENT policy.enforcement_mode test_level0.VALID_APPRAISAL appraisal.status tests/test_enum_parity.py asserts each against schemas/trace-claim.json on every run, by equality rather than containment: a superset means the copy accepts a value the schema does not define, which is the same drift pointing the other way. Load-bearing, checked rather than assumed - removing software-only again fails exactly that parametrized case. measurement/scripts/enum_drift.py already reported this and exits 1. It walks the AST, which is what finds a copy nobody has listed yet; this file is the other half, so a known copy fails in the suite rather than waiting for someone to run the script. 167 pass. ruff reports the same 68 pre-existing errors either side of this change and none in the new file. Signed-off-by: lywinged <48041247+lywinged@users.noreply.github.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Refs #53. Authored by @lywinged, from their branch
lywinged/trace-tests:measurement, rebased onto current main. Their commit and authorship are intact. Opened as a maintainer because the branch had no PR.What it measures. Not whether the checks are right, they are. Whether a regression inside a conformance module would be caught. That distinction matters more here than in ordinary code: this repository's output is a conformance stamp, so a broken check does not produce a wrong answer, it produces a missing question, and implementations keep getting stamped without the property being checked.
mutate_modules.pyrewrites oneFinding(..., Status.FAIL, ...)site at a time so it can never fail, runs the suite, restores, and verifies the restore before continuing. It refuses to start on a non-green baseline, refuses a rewrite that did not change the file, and refuses an empty site list.I reproduced the numbers on current main rather than taking them from the report:
All three
TR-SIG-002andTR-TXN-001sites are unguarded.TR-TXN-001is the only place the Level 2 tool-transcript requirement is enforced, so today that requirement could stop being checked and every test would still pass.Why mutation rather than reading the tests, which is the part worth keeping: grepping test files for
TR-xxx-nnncodes and diffing against emissions reports 12 unguarded checks, mutation reports 3. Tests exercise modules throughcheck(...)and assert on findings without naming codes, so naming is a convention and changing outcome is the property. It cuts the other way too: five files mentiontool_transcript, which reads as coverage, but one re-implements the digest check inline, two assert on the JSON schema, and one only asserts the module ran.Scope. This lands the instrument and its report under
measurement/, not the ten missing tests and not a CI gate. Wiring it into CI is a separate decision: it takes about a minute to run, and it should probably ratchet rather than block on first failure.🤖 Generated with Claude Code