Skip to content

feat(release): the pre-check reads envelope 3 records and the release head's artifact declaration - #29

Merged
sinkog merged 1 commit into
develfrom
feat/precheck-envelope3
Nov 2, 2026
Merged

sinkog merged 1 commit into
develfrom
feat/precheck-envelope3

Conversation

@sinkog

@sinkog sinkog commented Nov 2, 2026

Copy link
Copy Markdown
Member

What

tools/release_candidate_precheck.py still described the world of the envelope 2 compiler: it failed any record below 12 of 12 pinned files and kept an OPEN gate saying a record digests "at most 6 of the 12 by construction". Since #24-#28 that is no longer true. This PR moves the pre-check to envelope 3. It does not change the compiler, the contract, the reference verifier or any release.

  • record mode. An envelope 3 record keeps its own digest of a file in artifacts.files as sha256: + 64 lowercase hex of the raw blob bytes. That is the only place read for envelope 3. Envelope 1, 2 and records without an envelope keep the old places (spec meta_hash, provenance.grammar_*); artifacts is not read for them, so the frozen v0.2.0 negative evidence is unchanged (the 51 existing tests pass untouched).
    A digest in any other form (uppercase, no prefix, other algorithm, base64, wrong length, trailing newline, not a string), a path listed twice, an unknown release.envelope (4, "3", 3.0, true) or an envelope 3 record without an artifacts.files list is a failure and never coverage. source_commit stays mandatory and is still checked file by file.
  • candidate mode. With --release-head the tool reads compiler_settings.release_artifacts.paths from the project.yaml at that head. A pinned path that is not declared (spelled exactly) fails. A head with no declaration (a head of an earlier release) keeps the old gate and its old reason.
  • Gates. No gate turns into a pass. record digest coverage (candidate) stays OPEN: the declaration only says what the compiler will digest, record mode shows what the record carries. digest encoding stays OPEN with a reworded reason: the record side is a contract now, the receipt side is still the Forms unit. readiness is never ready.
  • The tool says on every envelope 3 run that it does not check the artifacts block itself (order, uniqueness, manifest_digest, signatures): that is tools/release_record_conformance.py.

Evidence

  • On the real v0.2.1 record (release commit 5e8c3219b52399e3e764b0b0bb27de710f5445a4, source 106965b8cea7cce2081beb77008753af21e68b46, record SHA-256 e5d8268a...cf63): record gives 12 of 12 present and equal, exit 0, readiness: checks_passed_gates_open. Before this change the same record failed with "6 of 12". The record is frozen in a test by commit id and digest, not by the tag (same pattern as v0.2.0; skipped without the full history, a failure where CIC_REQUIRE_RELEASE_HISTORY=1).
  • 45 new tests (each breaks one thing in a small git repository and reads the message). The expected values are computed in the test with hashlib and plain git, not with the tool.
  • 18 planted defects (check weakened, branch crossed, gate turned into a pass) run in subprocesses against mutated copies of the tool; every one fails the suite, every mutant is compiled first, and the unmutated copy passes.
  • The new tests found a real defect in my first version of the tool: an anchored re.match accepted sha256:<hex>\n. Fixed with fullmatch.
  • Full suite: 858 passed, 0 skipped (794 before).

Found on the way, NOT changed here

tools/release_record_conformance.py (the reference verifier, #25) has the same pattern: DIGEST_RE.match and COMMIT_RE.match on ^...$ patterns accept a trailing newline, so sha256:<64 hex>\n and <40 hex>\n pass the record layer. The consequence is bounded (the blobs layer compares the strings, build_hash covers the bytes, the v0.2.1 record is not affected), but it is a conformance gap in the yardstick, which is frozen by tests/fixtures/envelope3/FROZEN.sha256. It needs its own change (vector, planted defect, deliberate update of the frozen list), so it is left out of this PR. compiler.py SOURCE_COMMIT_RE.match has the same shape on a git rev-parse output.

Not part of this PR

No release, signing, tag, receipt or trust-gate step. Merge is for the owner.

… head's artifact declaration

record mode: an envelope 3 record keeps its own digest of a file in artifacts.files as
sha256:<64 lowercase hex> of the raw blob bytes, and only there is read; envelope 1, 2 and
records without an envelope keep the old places (spec meta_hash, provenance) and artifacts is
not read for them, so the frozen v0.2.0 negative evidence is unchanged. A digest in any other
form, a path listed twice, an unknown release.envelope (3.0, true, "3") or a missing
artifacts.files list is a failure, never coverage. The artifacts block itself is the reference
verifier's job and the tool says so.

candidate mode: with --release-head, compiler_settings.release_artifacts.paths is read from the
project.yaml at that head; a pinned path that is not declared fails, a head with no declaration
keeps the old open gate. The record digest coverage and digest encoding gates stay OPEN with
reworded reasons; no gate turns into a pass.

Tests: 45 new (each breaks one thing and reads the message), 18 planted defects that the suite
must fail on, and the v0.2.1 record frozen by commit id and SHA-256 (12 of 12). The suite found
a real defect in the first version: an anchored regex accepted a trailing newline.

---
[signing-metadata]
key = cic-my-sign-key
signature = vault:v1:MEQCIA4uGbQiOTupEcIFliv7/yYS7iV6nfEz6kAhPty8FKI8AiAdsS/dxca7DE7hg73B/3rxJ6UTwM082tdeqXbW/+WYsw==
hash-algorithm = sha256
digest = IyTYS7b9p+Ysz/DV7vwU1+kvI64PjRkpGOufVrzorF4=

[certificate]
-----BEGIN CERTIFICATE-----
MIICBjCCAaygAwIBAgIUSnRMR6RPnEbg296XWPOqq/u5PCwwCgYIKoZIzj0EAwIw
QzELMAkGA1UEBhMCSFUxGTAXBgNVBAoMEENlbnRyYWxJbmZyYUNvcmUxGTAXBgNV
BAMMEENJQyBEZXZlbG9wZXIgQ0EwHhcNMjYwMzIwMTMyMjU5WhcNMjYxMjMxMTMy
MjU5WjBFMQswCQYDVQQGEwJIVTEZMBcGA1UECgwQQ2VudHJhbEluZnJhQ29yZTEb
MBkGA1UEAwwSR2Fib3IgWm9sdGFuIFNpbmtvMFkwEwYHKoZIzj0CAQYIKoZIzj0D
AQcDQgAEIG2CVmTfmLB9pLLclj7YmP2eedAjklpy4LGrU2ijoiy6Xqpuybv7OgJe
i+ez31s65NEV8+X/ByeX1cstR988z6N8MHowCQYDVR0TBAIwADAdBgNVHQ4EFgQU
yZN6AIX/TNnIJ9GwAa/NRN3ujHAwHwYDVR0jBBgwFoAUXn6CHYzPUqU4JVP8g+OS
WeDYjhcwDgYDVR0PAQH/BAQDAgeAMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEF
BQcDBDAKBggqhkjOPQQDAgNIADBFAiEA+bFzXRoJ4PCQbhAAtpkcMjt0vNj5rEW0
lOMBGDNyaWkCIB1vmM7PcZzv/c9bIrxF5kqv6QXomouhByUfeNUTbpKW
-----END CERTIFICATE-----
@sinkog
sinkog merged commit 296df8a into devel Nov 2, 2026
1 check passed
@sinkog
sinkog deleted the feat/precheck-envelope3 branch November 2, 2026 21:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant