Release scope
August 7, 2026 · View on GitHub
Written before the release, per the release gate in RELEASE.md. It says what is in, what is explicitly out, and why — one reason per line, each survivable against the SemVer question a PATCH has to answer: no semantic change, no new obligation, no changed behaviour at a public interface.
No date and no cadence. 3.7.1 goes out when it can answer the release gate, not when a window opens.
In
| Item | Why it is patch-safe |
|---|---|
Doc alignment for the harness digest and the absence rule (docs/upstream/eval-result.md, docs/IN_TOTO_PROFILE.md) | Documentation only. It removes a contradiction with our own upstream submission, where the predicate already carries the optional harness DigestSet and the absence rule. No code path changes. |
The CI work from PR #134 (pyproject.toml: pin the ruff rule set, cap <0.17, mypy<3) | Build tooling only, not shipped behaviour. Merged 2026-08-07 as 6a3011f, 22/22 checks green. The measurement that justifies it is recorded in pyproject.toml itself: on the identical tree, ruff 0.15.x applies 59 default rules and exits 0 over all 258 tracked .py, ruff 0.16.x applies 413 and reports 1168 findings. |
The version-consistency gate (scripts/check_version_and_changelog.py extension + tests) | A check, not a shipped code path. Nothing in src/ changes. Its first job is to verify its own release. |
The release gate section in RELEASE.md and this scope file | Process documentation. |
The post-tag drift fix (b48e52b): anchor check 3 on the last release tag | A check, not a shipped code path. It was not planned — it fell out of writing the changelog entry, because the check had stopped applying: git describe --tags returned a corpus review tag, _semver_tuple read it as (0, 0, 0), and every real version compared as bumped past it. One non-trivial commit had been sitting undelivered since v3.7.0 under that blind spot. |
The invariant tests for the two in-toto docs (2c5e7a5) | Tests only. Aligning the docs fixed the instance; nothing kept them aligned, which is how they drifted apart in the first place. |
The asymmetry non-claim in both in-toto copies (b6f9395) | Documentation only. The submitted spec gained a third ## Non-claims paragraph on 2026-08-07 (35c83da); both copies described a predicate that claimed more than the one actually submitted. Measured: the other five upstream changes were already carried by 871453c. |
Check 6 of the version gate + the truth list (768e299, docs/version_truth_list.md) | A check and a document, not a shipped code path. Check 6 finds places that claim a current version without being declared — its first finding was the truth list itself. |
SUPPORT.md and COMPATIBILITY.md | New documentation, no obligation added. Both write down what already holds: SUPPORT.md repeats SECURITY.md's supported-version sentence rather than softening it, COMPATIBILITY.md spells out what the existing SemVer commitment already implies. |
docs/openssf_best_practices_self_assessment.md | Documentation. States the measured Scorecard value (6.5/10, v5.5.0, 2026-08-07) and the honest per-criterion state. No application filed. |
Two of these five were not in the first version of this list. That is the point of writing a scope list down rather than remembering it: on 2026-08-07 at 19:19 the list said four items while the branch carried seven commits, and the two missing ones were the two that had been found rather than planned. A list that does not contain what actually ships is the thing it was built against.
Out, and why
| Item | Why not in 3.7.1 |
|---|---|
ResourceDescriptor for harness/suite, the profile matrix, the exact score as its own profile | All three touch field semantics. That is at least a MINOR, and each deserves its own upstream discussion after in-toto PR 575 lands. |
| A second independent validator implementation | New surface, not a fix. |
| The conformance corpus as its own repository | Repository-level change with its own release and licence questions. |
| K2 and K3 acceptance criteria | Architecture work with executable criteria still to be written; nothing to ship yet. |
stash@{0} — targetSubjectDigest in the per-edge result entry | Measured, not assumed. It is out. See below. |
stash@{1} — if False: in evalclaim.py | A planted defect from an adversarial probe. It disables the check that samples.n matches the claim's n. Never ships, and deliberately has no safety branch: a branch whose only content is the removal of a check is worse than no branch. |
The stash question, answered by measurement
The audit asked it because one stash touches src/proofbundle/relation.py, and the honest answer
decides whether it may ride along in a PATCH. Measured on 2026-08-07 against main at cf39e9f:
stash@{0} applies cleanly (git apply --check, rc 0) — and that is exactly what makes it a
problem. It adds a targetSubjectDigest key to the entry dict built in
verify_relationship_edges. main already validates and cross-checks targetSubjectDigest
elsewhere (declaration validation, resolution against the attached target, the fail-closed codes from
PB-2026-0717-01), but it does not surface the field in the per-edge result. So this is not a
fix for something broken; it is new output.
And that output is not internal: relation_statement.py:260 puts the result of
verify_relationship_edges into r["lineage"] of a relation statement — a structure that gets
signed. A new key changes emitted bytes. New behaviour at a public interface is a MINOR, not a
PATCH. It stays out of 3.7.1, preserved on
safety/stash-relation-targetsubjectdigest-20260807, and belongs in the same discussion as the rest
of the relation/v0.1 surface.
stash@{2} is test-only and does apply. It adds test_no_secret_value_ever_reaches_output to
tests/test_fork_pr_secret_isolation.py: a reachability proof that the fork-PR guard reports secret
names (public YAML identifiers) but can never emit a secret value — the triage for a CodeQL
clear-text-logging finding. Measured: applies to main, suite goes 34 → 35 tests, all green. No
src/ change, no semantics. It is patch-safe and may ride along; it is not required for the
release. Preserved on safety/stash-forkpr-secret-value-test-20260807.
External surfaces to pull after the release
| Surface | What has to follow | Who |
|---|---|---|
| PyPI | follows automatically from the release workflow (build once, attest, digest-gated upload) | release workflow |
| README badge | live shields.io badges — nothing to edit. Measured: README hard-codes no version string, so it cannot go stale | nobody, by design |
b7n0de.com/proofbundle | the version number and the "checked on" line; both string tables (EN and DE) — the gate compares every PyPI latest <code>X.Y.Z</code> occurrence, so one translated string left behind is a finding | Owner (the page is an outward surface and needs its own GO) |
| Description of in-toto PR #575 | stated 3.6.2; corrected to 3.7.0 on 2026-08-07 under QITEM-PB-AUDIT-P0-01. Must be pulled again on every release while the PR is open | whoever releases |
CITATION.cff, RELEASE.md, docs/readiness_pack/PROGRESS.md | in-repo, enforced by the gate — listed here so the list is complete, not because they need a human | the gate |
What the gate does not touch, deliberately
Historical statements stay as they are: since v3.7.0 in INTEGRATIONS.md, as of v3.7.0 in
CROSS_IMPLEMENTATION_REPORT.md and the two docs/readiness_pack/ files, every older CHANGELOG.md
heading, and everything under audit_artifacts/370/. They record when something became true.
Bumping them would turn a fact into a false claim, which is a worse failure than the drift the gate
exists to catch.