v1.0.1 — Holders for the last three surfaces
Added
-
The three surfaces 1.0 left out of the freeze now have something holding them, and are frozen:
check --format json,detect-version --format json(with the MCP tooldetect_python_version), and exit codes. They were excluded for one reason — nothing compared them against a documented shape — and the fix had to start with the comparison rather than the declaration.checkanddetect-versionare held by a recursive field-path comparison against the examples in design.md, using==rather than the<=the three existing JSON surfaces use. That direction matters: deleting a field from design.md shrinks the documented set, and a smaller subset still fits, so the older comparisons hold the serializer to the document but not the document to the serializer — measured, not assumed. Walking the whole value rather than the top-level names is what putstarget_python.sourceandmatches[].dependency_compatibility.statusunder the freeze; a comparison of outermost keys would let either vanish. Thesourcelabels are frozen as a vocabulary too, compared againstPythonVersionSourcefrom the schema section alone — the precedence section already lists all five, so a file-wide search would have reported agreement no matter what the schema section said — and separately checked by running one input per label, because aLiteralenforces nothing at runtime and a documented label no input produces would otherwise pass. Exit codes are frozen as the rows of a table, not as semantics in general. Comparing a table against a set of scenarios shows the document and the tests agree; it cannot show no other exit exists, and reading the exits out of the source would not help either, sincesetupanduninstallexit with a variable, argparse produces its own, and a signal never reaches the interpreter. What falls outside is written beside the table: argparse's exits, termination by signal, uncaught exceptions, andhook, whose status the PostToolUse contract already holds.BrokenPipeError → 0is not among the guarantees —main()restores the defaultSIGPIPEdisposition, so a closed pipe terminates the process by signal (141 as a shell reports it,-SIGPIPEin a parent reading the raw status) and theexceptclause is not what a caller observes. Adding an exit condition is not treated as additive the way a new JSON field is: an old client ignores a field, but a new condition can change what an existing input returns. (closes #224) -
The two places the version is written —
pyproject.tomlandsrc/modern_python_guidance/__init__.py— are compared. They are edited by hand and nothing read them back against each other; a bump that updated only the first has shipped before, putting a wheel on PyPI whose--versionreported the previous release and spending a version number to correct it. Every other packaging check derives frompyproject.tomlalone, so all of them stayed green while the two disagreed. The comparison uses the imported value rather than the file's text, since what a caller sees is whatimportproduced.
Changed
-
design.md's rule that the CLI "defaults to JSON when piped" now names its exception.
detect-versiontakes--format json|plainrather thanjson|humanand defaults toplainwhether or not a pipe is attached, because the plain version string is what scripts read. The behaviour is unchanged; what changes is that the general rule no longer contradicts it — freezing the surface while the document described it wrongly would have frozen the contradiction. -
The README listed five frozen surfaces; it lists six, and points at the two distinctions VERSIONING now draws — which side of each JSON surface is actually compared, and why exit codes are frozen row by row rather than as semantics. A list kept in two places drifts in one of them, which is what it did between the change that added the sixth surface and this release.
No behaviour changed. The only difference the wheel carries over 1.0.0 is the version string itself — skills/ and rules/ are untouched, and the sole edit under src/ is __version__. What actually moved is the documentation of what the version number promises, which the source distribution carries and the wheel does not.