One question: is the thing this project says about itself checkable?
No new capability. Three claims that were prose became tests, and each of the three was false or
incomplete when the test was written, which is the milestone's whole argument.
Changed
-
The module map is acyclic, and
ARCHITECTURE.md§6's rule is now a test. §6 has said
dependencies point downward only since v0.1, and from v0.7 it was false: a review found
state -> receipt -> policy -> authority -> stateand the sentence was amended to record the
cycle rather than fix it. Nothing broke at run time, because the two edges out ofpolicy.py
are function-level, soimport ctrlrunresolved in one order and the suite passed for five
milestones.Broken in two places.
DecisionandPOLICY_UNAPPROVEDmoved toctrlrun.decision, which
imports nothing from the package: that was the whole of what a receipt needed from the decider,
and an evidence type reaching up into it is the edge that most contradicts §6's table. Then
the policy document grammar -- schemas, the strict YAML loader, the condition parser and
evaluator, type-strict equality -- moved toctrlrun.grammar, soauthority.pyno longer
importspolicy.pyat all.SPEC-v0.3.md§4.5 requires the two axes to share one condition
evaluator, and that is better served than before: the one evaluator is owned by neither axis.No public name moved.
policy.pyre-exports all thirty-four, so
from ctrlrun.policy import Decision, Condition, parse_conditionsresolves to the same objects
andSPEC-v0.1.md§8's frozen__init__block is unchanged.tests/test_module_graph.pywalks every module's AST and separates two questions §6 kept
conflating: the import-order graph, which is module-level imports, and the layering
graph, which counts deferred imports and is what the table describes. The recorded cycle is
invisible to the first, so a guard built only on module-level imports passes on 0.11.0's
tree. Writing it found a second cycle nobody had recorded,jwt_identityandrevocation
sharing a security-critical redirect handler through a deferred import;_NoRedirectsmoved
down torevocation.pyand keeps logging underctrlrun.policy's logger name so no operator's
handler is re-routed. -
The gateway told MCP clients to call a Python API. A
-41002relayed
str(ApprovalRequired)verbatim, and that exception carries the decorator's wording: "run
ctrlrun approve …, then retry insidectrlrun.with_approval(…)". On the one path where the
caller may be in any language, and is often a model reading the error as text, it pointed at a
context manager the caller cannot reach. It now says what the gateway's own documentation
already said: a human approves and this same call runs.
Added
-
Property tests over generated inputs (
tests/test_properties.py,hypothesis). The
invariant that matters is the one v0.11 item 1 violated: every break a tamper reports names a
row the store actually holds. That defect reportedcontent_altered 99andmissing 100on
an eight-row chain, because position came from the document rather than theseqcolumn.
Reinstating it fails these tests immediately.The first version of that property was one tamper is one break, and hypothesis falsified it on
its second example: altering rownalso breaks the link atn + 1. Two is correct and the
expectation was wrong, which is the same mistake the file exists to catch.derandomize=True,
so a counterexample found in CI reproduces locally by construction. -
A CycloneDX SBOM of the wheel, measured from the wheel (
scripts/sbom.sh). Generated by
installing the built wheel into an empty environment and recording what resolves, not by reading
pyproject.toml: a manifest-derived SBOM is the project's opinion of its own dependencies. The
answer is two,PyYAMLandclick. CI generates and checks it on every pull request, and
release.ymlwrites it intodist/before the attestation step, so it is signed with the
distributions and attached to the release.The seed packages are removed before the scan, and that is not cosmetic:
python -m venvadds
pip, and on 3.11 setuptools too, and a scanner cannot tell "ctrlrun needs this" from "the venv
came with this". The first version removed only pip, passed on 3.12 and went red in CI on 3.11
with['PyYAML', 'click', 'setuptools']. The assertion compares by equality, which is why it
caught a document that would have overstated what a consumer takes on.
Fixed
-
A shared-directory race in the cookbook tests. Two tests ran the same recipe in
examples/cookbook/<name>/on different xdist workers; one'srm -f verify-report.jsonlanded
between the other's write and read, andbash -euo pipefailturned it into a failure with
nothing wrong in the library. Measured at four concurrent runs: shared directory 2 of 4 fail,
one copy per run 4 of 4 pass. Each test now runs in its own copy, and the suite stops writing
into the working tree. -
Both adapter READMEs failed on copy-paste. Their examples show
identity=...as an
ellipsis, and dropping it leaves the first call refused withno principal is available. Both
now state the requirement and say why it is fail-closed. -
adapters/PUBLISHED.tomlhad gone stale in the other direction. 0.11.0 published both
adapters at 1.2.0 with<0.12and never updated the record, so the file spent a release
claiming 1.1.0 /<0.11. Both adapters go to 1.3.0 withctrlrun>=0.5,<0.13, because the
published 1.2.0 excludes this kernel, andRECORDEDnow freezes 1.2.0's range too.