From c33fe30b0f1805417a342b81bf73b311e13bc5e6 Mon Sep 17 00:00:00 2001 From: Soheilbz Date: Sun, 13 Sep 2026 09:22:02 -0400 Subject: [PATCH 1/3] fix: qualify MAFFT runtime interpreter and source digest --- docker/api.Dockerfile | 12 +++--- scripts/check-linux-bootstrap.py | 66 ++++++++++++++++++++++++++++++++ scripts/provision-tools.py | 8 ++-- 3 files changed, 77 insertions(+), 9 deletions(-) diff --git a/docker/api.Dockerfile b/docker/api.Dockerfile index 403dbfe..4f21c01 100644 --- a/docker/api.Dockerfile +++ b/docker/api.Dockerfile @@ -29,7 +29,7 @@ WORKDIR /src COPY docker/configure-debian-snapshot.sh /usr/local/bin/configure-debian-snapshot RUN --network=host configure-debian-snapshot "$DEBIAN_SNAPSHOT" \ && apt-get update \ - && apt-get install --no-install-recommends -y ca-certificates libgomp1 \ + && apt-get install --no-install-recommends -y bash ca-certificates libgomp1 \ && rm -rf /var/lib/apt/lists/* # ── Worker + scientific toolchain ────────────────────────────────────────── @@ -90,10 +90,12 @@ ENV PCRSTUDIO_BUILD_ID=${PCRSTUDIO_BUILD_ID} \ # ── Scientific runtime shared only by API and durable runner ─────────────── FROM process-runtime-base AS science-runtime-base USER root -# BusyBox supplies the small POSIX command surface used by the entrypoint and -# MAFFT wrapper. Python's standard-library HTTP client is used by the API -# health probe; the glibc/native scientific dependencies are copied from the -# already-qualified builder without carrying its package database. +# The official MAFFT 7.526 launcher has a Bash shebang, so copy the snapshot- +# pinned Bash runtime explicitly rather than silently depending on a missing +# interpreter. Keep it out of the database-only migrator image. BusyBox still +# supplies the small POSIX command surface used by the entrypoint; Python's +# standard-library HTTP client serves the API health probe. +COPY --from=runtime-assets /bin/bash /bin/bash COPY --from=science-builder /usr/local /usr/local COPY --from=science-builder /opt/uv /opt/uv COPY --from=science-builder /opt/worker /opt/worker diff --git a/scripts/check-linux-bootstrap.py b/scripts/check-linux-bootstrap.py index f065e4e..4db6b8d 100755 --- a/scripts/check-linux-bootstrap.py +++ b/scripts/check-linux-bootstrap.py @@ -131,6 +131,66 @@ def check_docker_save_integration(release_bundle) -> None: ) +def check_mafft_archive_provenance(provision) -> None: + """Keep MAFFT's verified source archive distinct from later tool archives.""" + with tempfile.TemporaryDirectory(prefix="pcrstudio-mafft-provision-") as temporary: + root = Path(temporary) + downloads = root / "downloads" + downloads.mkdir() + archives = { + "mfeprimer-4.5.1-linux-amd64.gz": downloads / "mfe.gz", + "ncbi-blast-2.17.0-x64-linux.tar.gz": downloads / "blast.tgz", + "mafft-7.526-linux.tgz": downloads / "mafft.tgz", + "PrimerPooler-v1.89.tar.gz": downloads / "primerpooler.tgz", + } + with gzip.open(archives["mfeprimer-4.5.1-linux-amd64.gz"], "wb") as stream: + stream.write(b"mfeprimer-fixture") + + def write_tar(path: Path, files: dict[str, bytes]) -> None: + with tarfile.open(path, "w:gz") as archive: + for name, payload in files.items(): + member = tarfile.TarInfo(name) + member.size = len(payload) + member.mode = 0o644 + archive.addfile(member, io.BytesIO(payload)) + + write_tar(archives["ncbi-blast-2.17.0-x64-linux.tar.gz"], { + "blast/bin/blastn": b"blastn-fixture", + "blast/bin/makeblastdb": b"makeblastdb-fixture", + }) + write_tar(archives["mafft-7.526-linux.tgz"], { + "mafft-linux64/mafft.bat": b"#!/bin/bash\nexit 0\n", + "mafft-linux64/mafftdir/bin/mafft": b"#!/bin/bash\nexit 0\n", + }) + write_tar(archives["PrimerPooler-v1.89.tar.gz"], { + "PrimerPooler/pooler/Makefile": b"all:\n\ttrue\n", + }) + + names = iter(archives) + + def fake_download(_url, _target, _digest, *, mirror_urls=()): + name = next(names) + return archives[name] + + def fake_run(*_args, cwd=None, **_kwargs): + assert cwd is not None + (cwd / "pooler").write_bytes(b"pooler-fixture") + return "" + + with ( + mock.patch.object(provision, "LOCAL", root / "tools"), + mock.patch.object(provision, "DOWNLOADS", downloads), + mock.patch.object(provision, "download", side_effect=fake_download), + mock.patch.object(provision, "run", side_effect=fake_run), + ): + native = provision.provision_native() + + expected = archives["mafft-7.526-linux.tgz"] + assert native["mafft_archive"] == expected + assert provision.sha256(native["mafft_archive"]) == provision.sha256(expected) + assert native["mafft_archive"] != archives["PrimerPooler-v1.89.tar.gz"] + + def check_download_retry_contract(provision) -> None: payload = b"content-addressed archive fixture\n" expected = hashlib.sha256(payload).hexdigest() @@ -655,6 +715,7 @@ def assert_scope( ) provision.verify_contract_alignment() check_download_retry_contract(provision) + check_mafft_archive_provenance(provision) # Public and private bootstrap examples are one configuration contract. # Private mode changes values (loopback origin), not the set of supported @@ -965,6 +1026,11 @@ def env_example_keys(path: Path) -> set[str]: assert "DPkg::Options::=--path-include=/usr/share/man/*" in api_dockerfile assert "rm -rf /usr/share/man /var/lib/apt/lists/*" in api_dockerfile assert "build-essential xz-doc" not in api_dockerfile + assert "apt-get install --no-install-recommends -y bash ca-certificates libgomp1" in api_dockerfile + assert "COPY --from=runtime-assets /bin/bash /bin/bash" in api_dockerfile + release_workflow = (ROOT / ".github" / "workflows" / "production-deploy.yml").read_text(encoding="utf-8") + assert "Smoke API and runner images as the service UID before publishing" in release_workflow + assert 'docker run --rm --network none --user 10001:10001' in release_workflow assert bootstrap.registry_error_class("dial tcp: lookup auth.docker.io: no such host") == "dns" assert bootstrap.registry_error_class("denied: requested access to the resource is denied") == "auth" assert bootstrap.registry_error_class("toomanyrequests: rate limit exceeded") == "rate-limit" diff --git a/scripts/provision-tools.py b/scripts/provision-tools.py index 651b758..db2240a 100755 --- a/scripts/provision-tools.py +++ b/scripts/provision-tools.py @@ -541,7 +541,7 @@ def provision_native() -> dict[str, Path]: # fetched from both documented project hosts. The alternate host is used # only after bounded transient failures and must satisfy the same digest. item = ARTIFACTS["mafft"] - archive = download( + mafft_archive = download( item["url"], DOWNLOADS / item["archive"], item["sha256"], @@ -549,13 +549,13 @@ def provision_native() -> dict[str, Path]: ) mafft_root = LOCAL / "mafft" if mafft_root.exists(): shutil.rmtree(mafft_root) - safe_extract_tar(archive, mafft_root) + safe_extract_tar(mafft_archive, mafft_root) upstream = next(iter(mafft_root.rglob("mafft.bat")), None) if upstream is None: die("MAFFT portable archive does not contain mafft.bat") service_readable_tree(mafft_root) executable(upstream) mafft_bundle = upstream.parent - mafft_archive_sha256 = sha256(archive) + mafft_archive_sha256 = sha256(mafft_archive) mafft_bundle_sha256 = tree_sha256(mafft_bundle) mafft = mafft_root / "mafft" mafft.write_text('#!/bin/sh\nset -eu\nHERE=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)\nexec "$HERE/mafft-linux64/mafft.bat" "$@"\n', encoding="utf-8") @@ -583,7 +583,7 @@ def provision_native() -> dict[str, Path]: "blastn": blastn, "mafft": mafft, "mafft_bundle": mafft_bundle, - "mafft_archive": archive, + "mafft_archive": mafft_archive, "primerpooler": pooler, } From 02681402761084e25b1e37027ac3f31f7cfd9ad7 Mon Sep 17 00:00:00 2001 From: Soheilbz Date: Sun, 13 Sep 2026 09:37:15 -0400 Subject: [PATCH 2/3] fix: qualify runtime and release publication --- .github/workflows/production-deploy.yml | 55 +- CHANGELOG.md | 11 +- contracts/capability-truth.json | 1 - docs/OPERATIONS.md | 14 +- knowledge/reviews/EXPERT-MODULE-AUDIT.json | 2 +- knowledge/reviews/EXPERT-UPGRADE-BACKLOG.json | 2 +- .../reviews/MODULE-TOOLCHAIN-MATRIX.json | 2 +- .../reviews/SCIENTIFIC-RISK-REGISTER.json | 2 +- knowledge/reviews/UI-UX-MODULE-AUDIT.json | 2 +- .../runtime/numeric-provenance-registry.json | 2 +- release/FILE-MANIFEST.json | 66 +- release/INDEX.md | 2 +- release/PATCH-MANIFEST.json | 62 +- release/RELEASE-NOTES.md | 96 +-- release/SHA256SUMS.txt | 14 +- .../CURRENT-STATIC-CONSISTENCY-AUDIT.json | 4 +- .../CURRENT-STATIC-CONSISTENCY-AUDIT.md | 2 +- release/current/ENGINEERING-CLOSURE-REPORT.md | 623 ++---------------- .../current/SOURCE-ATTESTATION.intoto.json | 4 +- release/current/SOURCE-QUALIFICATION.json | 2 +- release/release.toml | 4 +- scripts/audit/method_fidelity.py | 4 +- scripts/check-linux-bootstrap.py | 18 +- 23 files changed, 229 insertions(+), 765 deletions(-) diff --git a/.github/workflows/production-deploy.yml b/.github/workflows/production-deploy.yml index e626f23..501e822 100644 --- a/.github/workflows/production-deploy.yml +++ b/.github/workflows/production-deploy.yml @@ -1,8 +1,6 @@ name: Production deployment on: - release: - types: [published] workflow_dispatch: inputs: source_ref: @@ -19,23 +17,31 @@ concurrency: jobs: deploy: - name: Deploy the published release - # Production never follows arbitrary branch pushes. A release publication - # or an explicit dispatch of an exact stable SemVer tag is required. The - # protected GitHub environment supplies the final human approval gate. - if: github.event_name == 'workflow_dispatch' || (github.event.release.prerelease == false && startsWith(github.event.release.tag_name, 'v')) + name: Qualify and publish the exact release + # Production never follows arbitrary branch pushes. An exact stable tag is + # dispatched, kept as a draft during qualification, and published only + # after the image and service-UID smoke gates pass. runs-on: ubuntu-24.04 timeout-minutes: 60 environment: production env: - RELEASE_REF: ${{ github.event.release.tag_name || inputs.source_ref }} + RELEASE_REF: ${{ inputs.source_ref }} PRODUCTION_DOMAIN: ${{ secrets.PCRSTUDIO_PRODUCTION_DOMAIN }} PYTHONDONTWRITEBYTECODE: "1" steps: + - name: Validate exact stable release tag input + id: requested-release + env: + SOURCE_REF: ${{ inputs.source_ref }} + run: | + set -euo pipefail + [[ "$SOURCE_REF" =~ ^v(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$ ]] + echo "source_ref=$SOURCE_REF" >> "$GITHUB_OUTPUT" + - name: Check out the exact release tag uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 with: - ref: ${{ github.event.release.tag_name || inputs.source_ref }} + ref: ${{ steps.requested-release.outputs.source_ref }} fetch-depth: 1 - name: Materialize locked web verification dependencies @@ -64,6 +70,7 @@ jobs: run: | set -euo pipefail [[ "$RELEASE_REF" =~ ^v(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$ ]] + [[ "$(git rev-parse --verify "refs/tags/$RELEASE_REF^{commit}")" == "$(git rev-parse HEAD)" ]] python3 -B scripts/validate-release-version.py --tag "$RELEASE_REF" [[ "$PRODUCTION_DOMAIN" =~ ^[A-Za-z0-9.-]+$ ]] [[ "$PRODUCTION_DOMAIN" != .* && "$PRODUCTION_DOMAIN" != *..* ]] @@ -78,6 +85,23 @@ jobs: python3 -B scripts/qualify-source.py --no-write python3 -B scripts/verify-release.py --root . + - name: Prepare an unpublished release draft + env: + GH_TOKEN: ${{ github.token }} + run: | + set -euo pipefail + if draft_state="$(gh release view "$RELEASE_REF" --repo "$GITHUB_REPOSITORY" --json isDraft --jq '.isDraft' 2>/dev/null)"; then + if [[ "$draft_state" != true ]]; then + echo "refusing to rebuild or mutate published release $RELEASE_REF" >&2 + exit 1 + fi + echo "reusing unpublished draft for $RELEASE_REF" + else + gh release create "$RELEASE_REF" --draft --verify-tag \ + --title "PCRStudio ${RELEASE_REF#v} — Verified production release" \ + --notes-file release/RELEASE-NOTES.md --repo "$GITHUB_REPOSITORY" + fi + - name: Build the qualified runtime image set on GitHub's runner env: BUILD_ID: ${{ steps.release.outputs.build_id }} @@ -128,7 +152,7 @@ jobs: [[ "$source_sha" =~ ^[0-9a-f]{40}$ ]] echo "source_sha=$source_sha" >> "$GITHUB_OUTPUT" - - name: Publish the verified HTTPS deployment bundle + - name: Upload the verified HTTPS deployment bundle to the draft env: GH_TOKEN: ${{ github.token }} RELEASE_SHA: ${{ steps.release.outputs.release_sha }} @@ -153,4 +177,13 @@ jobs: --image-archive "$image_archive" \ --output "$manifest" gh release upload "$RELEASE_REF" "$source_archive" "$image_archive" "$manifest" --repo "$GITHUB_REPOSITORY" --clobber - echo "published HTTPS deployment assets for $RELEASE_REF ($RELEASE_SHA)" + echo "uploaded verified HTTPS deployment assets for $RELEASE_REF ($RELEASE_SHA)" + + - name: Publish only after every release gate passes + env: + GH_TOKEN: ${{ github.token }} + run: | + set -euo pipefail + gh release edit "$RELEASE_REF" --draft=false --latest --verify-tag \ + --repo "$GITHUB_REPOSITORY" + echo "published qualified release $RELEASE_REF" diff --git a/CHANGELOG.md b/CHANGELOG.md index 658ca57..9ae9a75 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,11 +3,14 @@ This file summarizes the current public-source milestone. Detailed scientific and qualification evidence is maintained under `release/current/`. -## v1.0.5 — 2026-09-13 +## v1.0.5 — superseded before deployment — 2026-09-13 -- Normalize permissions across complete pinned native-tool trees so nested MAFFT and BLAST helpers are readable/executable by the non-root service. -- Add regression coverage for nested executables, libraries, directories, and unsafe special/write bits; smoke both API and runner images as the service UID before publishing. -- Preserve upstream archive digests and bind the generated normalized runtime tree in the image; pinned base images, scientific behavior, and user data formats remain unchanged. +- Its source changes normalized permissions across pinned native-tool trees, but the final runtime smoke exposed a missing launcher interpreter before the deployment bundle was published. Use v1.0.6 for a deployable release; no production rollout occurred from v1.0.5. + +## v1.0.6 — 2026-09-13 + +- Fix production startup in the restricted runtime without changing pinned product images or user data. +- Publish production releases only after image startup qualification passes, so an incomplete build cannot become the public Latest release. ## v1.0.4 — 2026-09-13 diff --git a/contracts/capability-truth.json b/contracts/capability-truth.json index b3feb6a..cfe69dd 100644 --- a/contracts/capability-truth.json +++ b/contracts/capability-truth.json @@ -9,7 +9,6 @@ "files": [ "README.md", "release/PUBLIC-SOURCE.md", - "release/RELEASE-NOTES.md", "scripts/generate-expert-audit-artifacts.py", "knowledge/reviews/EXPERT-MODULE-AUDIT.md" ], diff --git a/docs/OPERATIONS.md b/docs/OPERATIONS.md index 68b38ad..f03410f 100644 --- a/docs/OPERATIONS.md +++ b/docs/OPERATIONS.md @@ -119,9 +119,12 @@ internal cleanup do not create a new public version until the operator decides to publish one. `CURRENT` remains the internal foundation/current-state identity and is not a public version. -The `production-deploy.yml` workflow handles only a published `vMAJOR.MINOR.PATCH` -release tag, or the same exact tag when an operator starts the workflow -manually. The GitHub `production` environment should require approval and +The `production-deploy.yml` workflow is started manually for an exact +`vMAJOR.MINOR.PATCH` tag. It creates or reuses a draft release, verifies and +builds the release, runs image startup checks, uploads the verified bundle, and +publishes only after every gate succeeds. Failed attempts remain unpublished +drafts and can be retried without changing the immutable source tag. The GitHub +`production` environment should require approval and contain only: - `PCRSTUDIO_PRODUCTION_DOMAIN` @@ -146,8 +149,9 @@ journalctl -u pcrstudio-release-pull.service ``` The release workflow builds the qualified runtime image set on an ephemeral -runner and publishes the source plus OCI bundle only after release verification. -The server's agent performs the deployment and readiness checks locally. The +runner and publishes the source plus OCI bundle only after release verification +and startup smoke tests. The server's agent performs the deployment and +readiness checks locally. The server still verifies pinned base images, image presence, migrations, public readiness and bounded Docker cleanup. Scientific readiness and the durable runner remain intentionally withheld until the approved reference database is diff --git a/knowledge/reviews/EXPERT-MODULE-AUDIT.json b/knowledge/reviews/EXPERT-MODULE-AUDIT.json index afbe613..c32d2c7 100644 --- a/knowledge/reviews/EXPERT-MODULE-AUDIT.json +++ b/knowledge/reviews/EXPERT-MODULE-AUDIT.json @@ -4362,7 +4362,7 @@ "tools/src/pcr_tools/scientific_authority.py": "e4bb66e24f7495b3a01cd7af46196bd1390e6880eef29b1889842a2609c4205a", "scripts/generate-scientific-authority-registry.py": "71477eb3e49a3ede063960795a0e8a629119236ca83466d0a4380838802654f1", "scripts/generate-flanking-source-snapshots.py": "c811fa9eec2fce82bee18637ee74f99ae2e9d16efa7bb475bbc89d9901ca8de0", - "contracts/capability-truth.json": "eb2a1335b3f0c24cc4de64700c151ad7f4539c943eb15b335cf82f066a3cccb1" + "contracts/capability-truth.json": "7e6de5588144749c360514d9dd8231f838ddb4e0ba47a8685bfc7bdaa6adf3a5" }, "generator_sha256": "3338c5f2831d6c5e4a480600985961ed701599a27061d0152816af9b71820d8e" } diff --git a/knowledge/reviews/EXPERT-UPGRADE-BACKLOG.json b/knowledge/reviews/EXPERT-UPGRADE-BACKLOG.json index b6b77fa..61f6ce2 100644 --- a/knowledge/reviews/EXPERT-UPGRADE-BACKLOG.json +++ b/knowledge/reviews/EXPERT-UPGRADE-BACKLOG.json @@ -301,7 +301,7 @@ "tools/src/pcr_tools/scientific_authority.py": "e4bb66e24f7495b3a01cd7af46196bd1390e6880eef29b1889842a2609c4205a", "scripts/generate-scientific-authority-registry.py": "71477eb3e49a3ede063960795a0e8a629119236ca83466d0a4380838802654f1", "scripts/generate-flanking-source-snapshots.py": "c811fa9eec2fce82bee18637ee74f99ae2e9d16efa7bb475bbc89d9901ca8de0", - "contracts/capability-truth.json": "eb2a1335b3f0c24cc4de64700c151ad7f4539c943eb15b335cf82f066a3cccb1" + "contracts/capability-truth.json": "7e6de5588144749c360514d9dd8231f838ddb4e0ba47a8685bfc7bdaa6adf3a5" }, "generator_sha256": "3338c5f2831d6c5e4a480600985961ed701599a27061d0152816af9b71820d8e" } diff --git a/knowledge/reviews/MODULE-TOOLCHAIN-MATRIX.json b/knowledge/reviews/MODULE-TOOLCHAIN-MATRIX.json index 9200933..f7f9f39 100644 --- a/knowledge/reviews/MODULE-TOOLCHAIN-MATRIX.json +++ b/knowledge/reviews/MODULE-TOOLCHAIN-MATRIX.json @@ -1801,7 +1801,7 @@ "tools/src/pcr_tools/scientific_authority.py": "e4bb66e24f7495b3a01cd7af46196bd1390e6880eef29b1889842a2609c4205a", "scripts/generate-scientific-authority-registry.py": "71477eb3e49a3ede063960795a0e8a629119236ca83466d0a4380838802654f1", "scripts/generate-flanking-source-snapshots.py": "c811fa9eec2fce82bee18637ee74f99ae2e9d16efa7bb475bbc89d9901ca8de0", - "contracts/capability-truth.json": "eb2a1335b3f0c24cc4de64700c151ad7f4539c943eb15b335cf82f066a3cccb1" + "contracts/capability-truth.json": "7e6de5588144749c360514d9dd8231f838ddb4e0ba47a8685bfc7bdaa6adf3a5" }, "generator_sha256": "3338c5f2831d6c5e4a480600985961ed701599a27061d0152816af9b71820d8e" } diff --git a/knowledge/reviews/SCIENTIFIC-RISK-REGISTER.json b/knowledge/reviews/SCIENTIFIC-RISK-REGISTER.json index f3bda5b..a05b75f 100644 --- a/knowledge/reviews/SCIENTIFIC-RISK-REGISTER.json +++ b/knowledge/reviews/SCIENTIFIC-RISK-REGISTER.json @@ -182,7 +182,7 @@ "tools/src/pcr_tools/scientific_authority.py": "e4bb66e24f7495b3a01cd7af46196bd1390e6880eef29b1889842a2609c4205a", "scripts/generate-scientific-authority-registry.py": "71477eb3e49a3ede063960795a0e8a629119236ca83466d0a4380838802654f1", "scripts/generate-flanking-source-snapshots.py": "c811fa9eec2fce82bee18637ee74f99ae2e9d16efa7bb475bbc89d9901ca8de0", - "contracts/capability-truth.json": "eb2a1335b3f0c24cc4de64700c151ad7f4539c943eb15b335cf82f066a3cccb1" + "contracts/capability-truth.json": "7e6de5588144749c360514d9dd8231f838ddb4e0ba47a8685bfc7bdaa6adf3a5" }, "generator_sha256": "3338c5f2831d6c5e4a480600985961ed701599a27061d0152816af9b71820d8e" } diff --git a/knowledge/reviews/UI-UX-MODULE-AUDIT.json b/knowledge/reviews/UI-UX-MODULE-AUDIT.json index 7805d7e..eaca331 100644 --- a/knowledge/reviews/UI-UX-MODULE-AUDIT.json +++ b/knowledge/reviews/UI-UX-MODULE-AUDIT.json @@ -825,7 +825,7 @@ "tools/src/pcr_tools/scientific_authority.py": "e4bb66e24f7495b3a01cd7af46196bd1390e6880eef29b1889842a2609c4205a", "scripts/generate-scientific-authority-registry.py": "71477eb3e49a3ede063960795a0e8a629119236ca83466d0a4380838802654f1", "scripts/generate-flanking-source-snapshots.py": "c811fa9eec2fce82bee18637ee74f99ae2e9d16efa7bb475bbc89d9901ca8de0", - "contracts/capability-truth.json": "eb2a1335b3f0c24cc4de64700c151ad7f4539c943eb15b335cf82f066a3cccb1" + "contracts/capability-truth.json": "7e6de5588144749c360514d9dd8231f838ddb4e0ba47a8685bfc7bdaa6adf3a5" }, "generator_sha256": "3338c5f2831d6c5e4a480600985961ed701599a27061d0152816af9b71820d8e" } diff --git a/knowledge/runtime/numeric-provenance-registry.json b/knowledge/runtime/numeric-provenance-registry.json index ebf0e6b..6f92c85 100644 --- a/knowledge/runtime/numeric-provenance-registry.json +++ b/knowledge/runtime/numeric-provenance-registry.json @@ -5388,7 +5388,7 @@ "tools/src/pcr_tools/scientific_authority.py": "e4bb66e24f7495b3a01cd7af46196bd1390e6880eef29b1889842a2609c4205a", "scripts/generate-scientific-authority-registry.py": "71477eb3e49a3ede063960795a0e8a629119236ca83466d0a4380838802654f1", "scripts/generate-flanking-source-snapshots.py": "c811fa9eec2fce82bee18637ee74f99ae2e9d16efa7bb475bbc89d9901ca8de0", - "contracts/capability-truth.json": "eb2a1335b3f0c24cc4de64700c151ad7f4539c943eb15b335cf82f066a3cccb1" + "contracts/capability-truth.json": "7e6de5588144749c360514d9dd8231f838ddb4e0ba47a8685bfc7bdaa6adf3a5" }, "generator_sha256": "3338c5f2831d6c5e4a480600985961ed701599a27061d0152816af9b71820d8e" } diff --git a/release/FILE-MANIFEST.json b/release/FILE-MANIFEST.json index c05d298..52c0295 100644 --- a/release/FILE-MANIFEST.json +++ b/release/FILE-MANIFEST.json @@ -33,9 +33,9 @@ "sha256": "60abf94d30819a9b51edd7388706d115d44382934ddef70350a6ebb36d9de351" }, { - "bytes": 7268, + "bytes": 8610, "path": ".github/workflows/production-deploy.yml", - "sha256": "5ccbca51a63c20058db830c242085e5d50be07b49daf1d2ca953dc7a22cdfca4" + "sha256": "34a7ca424f851dd68f83f30904da9b100ab26b87de79373d179d7a5393f4e345" }, { "bytes": 6120, @@ -53,9 +53,9 @@ "sha256": "6e4fd39e6708b21033c89ce2d34b17013e098c95de8ea9f3f042043cab01f513" }, { - "bytes": 2792, + "bytes": 2864, "path": "CHANGELOG.md", - "sha256": "b3cc8035b5e0c43a9d79f3bfa74ed67cedea5445d23796fddee0e4760e3288b6" + "sha256": "45adbffc726fb73264d744488041bb12e3c72d61e98e79d8d93c182acbd14f68" }, { "bytes": 633, @@ -133,9 +133,9 @@ "sha256": "81cfbac5802dfcaf54119e520f8c9683d98aa2bfd26775c2d33179679159ce5b" }, { - "bytes": 2912, + "bytes": 2876, "path": "contracts/capability-truth.json", - "sha256": "eb2a1335b3f0c24cc4de64700c151ad7f4539c943eb15b335cf82f066a3cccb1" + "sha256": "7e6de5588144749c360514d9dd8231f838ddb4e0ba47a8685bfc7bdaa6adf3a5" }, { "bytes": 8070, @@ -1078,9 +1078,9 @@ "sha256": "f92c323b9d74936de252e96a1ad6fb64089acd558d1e18246bf637ddc2a42e1b" }, { - "bytes": 8153, + "bytes": 8278, "path": "docker/api.Dockerfile", - "sha256": "b8f775700c787b917f3a85dbd6f7899ae7f6981dc8d8b8ec405f2d5a5a8ab5ce" + "sha256": "c131c693a7004a14d4f9a123edec3f5e6d102ae96bb162fc20fdf99a890c9bf4" }, { "bytes": 520, @@ -1113,9 +1113,9 @@ "sha256": "fe4741fa6ea8bde3555d9d4ed102c1c91c0106addc44caa5e7f8b01f5d4c69c5" }, { - "bytes": 14316, + "bytes": 14548, "path": "docs/OPERATIONS.md", - "sha256": "3f1fb07515a06a4c1527d06266e536d36cfc16f51d5f01d5f9497f32b4635115" + "sha256": "f92c6f3972e9fdb5f20eafc5ec46ea08b03eec5b7e57ed795389618693a22f66" }, { "bytes": 2598, @@ -1495,7 +1495,7 @@ { "bytes": 159756, "path": "knowledge/reviews/EXPERT-MODULE-AUDIT.json", - "sha256": "5b56fb56711e68674ba453c4a38dcf1e59f3c3807116efc6ecbae07d0df8dce8" + "sha256": "3ec0dcff1e0c5b0742a53e4040b6902b3a8468040140b5cdc6dd5b3125c5a885" }, { "bytes": 21081, @@ -1505,7 +1505,7 @@ { "bytes": 23822, "path": "knowledge/reviews/EXPERT-UPGRADE-BACKLOG.json", - "sha256": "9f65673099456cc36d3c7628b6bca133e447599b5fbc2d5ab920b8ea4dda7be7" + "sha256": "63ae385b24969baf94a4e5b91e43e5acbd0a71ae3b9c204ba92c701960f05386" }, { "bytes": 4987, @@ -1535,7 +1535,7 @@ { "bytes": 63684, "path": "knowledge/reviews/MODULE-TOOLCHAIN-MATRIX.json", - "sha256": "20736a7cf8c1bbf5b94b5b57e25581ebade7e4362c571ef53ff9f89b315a3219" + "sha256": "ed17468ccc2c225b70c0da991f616394c429315e6cdf226a63bbc20454122c33" }, { "bytes": 8169, @@ -1550,7 +1550,7 @@ { "bytes": 14899, "path": "knowledge/reviews/SCIENTIFIC-RISK-REGISTER.json", - "sha256": "95bfea6422cb07409a6d9b19f668e88136c3d5235f1d9ef2f46a47d720efb3fc" + "sha256": "6edcc5e4120efcac2669b4cc3389bcd869437dc52e57f1233929086fc028aed1" }, { "bytes": 3285, @@ -1560,7 +1560,7 @@ { "bytes": 49732, "path": "knowledge/reviews/UI-UX-MODULE-AUDIT.json", - "sha256": "5d67538ef1ae674d18b6139cc02fda75bb25a4b55da4f1e650e9382b76833381" + "sha256": "afb9173ab612468f68260a4543300c12a9a2d3bc368e4ebf9016e519b39a0711" }, { "bytes": 2148, @@ -1740,7 +1740,7 @@ { "bytes": 200204, "path": "knowledge/runtime/numeric-provenance-registry.json", - "sha256": "a4bced233917e3c9c17c0e2a234ca05d846ea6cee8405adba7ec4639e5bf889a" + "sha256": "dd5f729c3bf6af118be49b39ce2a8fda682dc08047d6e7512b3b973ed0c93107" }, { "bytes": 3674, @@ -1860,7 +1860,7 @@ { "bytes": 1678, "path": "release/INDEX.md", - "sha256": "ffd07c33bd33fb8dbc80753eb924e8d4f0a0b670cdf6a2623c8c9477a469fbcc" + "sha256": "1dc60ed8ebeda774d9699ec32edaf21523086f131c2109643bef0da8d460a813" }, { "bytes": 39959, @@ -1873,9 +1873,9 @@ "sha256": "6151c759acd52e300c2e6feed8a061ceea1204e7f322a922bd042f26c024bcbc" }, { - "bytes": 217259, + "bytes": 217257, "path": "release/PATCH-MANIFEST.json", - "sha256": "d52330df7190122f41b809a2a349ad209c7118861595b91d8bc642e0d68eb8ac" + "sha256": "69b3dc93ae8fcc181851c3d906bc6fb818631d21fcd509a464325ad6b2b3f6dd" }, { "bytes": 2048, @@ -1883,9 +1883,9 @@ "sha256": "914cd8c95c0a0438772cc15184a41ab37761e1b32d027f070b3e102bea4e3563" }, { - "bytes": 7583, + "bytes": 269, "path": "release/RELEASE-NOTES.md", - "sha256": "16e4b4fc365b0c1b3d3e4314c88c3d31931491c6f877d0582e32d2181a8da7a6" + "sha256": "4b4fbefd32380873307249bcce67d4a2300755b8521faaba151a9c9d5f68108b" }, { "bytes": 98937, @@ -1945,17 +1945,17 @@ { "bytes": 1626, "path": "release/current/CURRENT-STATIC-CONSISTENCY-AUDIT.json", - "sha256": "e579791e73e64e7f62df1f3a0bc14cf19056eb647b12ef0c263a418a3753a84b" + "sha256": "d169a26e77a7344cacd0e2459c76f7a8d2d31d5854b98d9086fe487b707cc326" }, { "bytes": 1708, "path": "release/current/CURRENT-STATIC-CONSISTENCY-AUDIT.md", - "sha256": "abbb8366608340ac56b4cd20bc19a35373f003fa1da1654f34c420385590bcd7" + "sha256": "141eba89249115700cd20a5083b383466dc93e424f9aa1e410e852068e87e2c5" }, { - "bytes": 40816, + "bytes": 3233, "path": "release/current/ENGINEERING-CLOSURE-REPORT.md", - "sha256": "79202d824f0d764a8c3aec5e111c8f3e04e267801117e9c42f11bfdc82ffaf77" + "sha256": "4894b93d737b16c1d9b4cb11a01c57311ae0bca1fe91f51a2593007888201884" }, { "bytes": 507, @@ -1975,7 +1975,7 @@ { "bytes": 5355, "path": "release/current/SOURCE-QUALIFICATION.json", - "sha256": "6ed6c11d74f474037177ae2b30a4cca2234a9aeec39d5ee295b703bc196d1d1f" + "sha256": "2d93294bb274cc6ac939b17168e5ef4308ced5a84d98f6f5a48ed0b1e8b1f4f4" }, { "bytes": 974, @@ -1990,7 +1990,7 @@ { "bytes": 532, "path": "release/release.toml", - "sha256": "ac7a1b12402aa1c9f02c22e5f9201c69ab319496a40539652e834eb48795522e" + "sha256": "23aaa773c635c627efd7be9c444c1b13facd23d841288ce5352f9e65668ce5a3" }, { "bytes": 145, @@ -2058,9 +2058,9 @@ "sha256": "8ddf2e7bb6c1767c7a82a49a63090352f40abbd9633c1cf109a44ec62304cd9f" }, { - "bytes": 10793, + "bytes": 10679, "path": "scripts/audit/method_fidelity.py", - "sha256": "a62edc3d24962e970cb46e66d7758d90b1681ec7d1a23ed3a02511b42772a201" + "sha256": "a6b1126e664695d14f63136794e3f1e4580e8c0c14ef58d3a1c0467afbbe4583" }, { "bytes": 12118, @@ -2153,9 +2153,9 @@ "sha256": "7aae660e33bda20a1e43e187e704a57df1f31b69ea3517f25d5d96ba654f0cb9" }, { - "bytes": 54020, + "bytes": 58315, "path": "scripts/check-linux-bootstrap.py", - "sha256": "03e7a25978af7969da3115b6e36bdd8b5759a80e4ed018048f75b2d08004d952" + "sha256": "8c3f29467334441e2f93d994f6699ecc3a01e01ecc3d293a1221d61e3e577ce8" }, { "bytes": 4486, @@ -2348,9 +2348,9 @@ "sha256": "8be2a552ba79bd8ab3b3668d2920e7468136599f6b59a650a5ef0c4df9890c91" }, { - "bytes": 30345, + "bytes": 30369, "path": "scripts/provision-tools.py", - "sha256": "72dc1aa776f76be24cc62ef43c7d8331383a4365ff7c37d0304657be4e63d01b" + "sha256": "8fd41dcb744b8af5e0f9e717f89141e6ee72798e68fd5a0c7507f122b2096f72" }, { "bytes": 2694, diff --git a/release/INDEX.md b/release/INDEX.md index 0965dad..79c36d1 100644 --- a/release/INDEX.md +++ b/release/INDEX.md @@ -2,7 +2,7 @@ `CURRENT` is the public-source authority for Generation 1 on Linux x86_64. The active engine architecture is a single registry of 11 engines; no release-count engine families participate in generation, qualification or runtime behavior. -The current public product version is **v1.0.5**. Public releases follow +The current public product version is **v1.0.6**. Public releases follow Semantic Versioning 2.0.0; internal fixes do not change that version until a maintainer deliberately publishes the next release. diff --git a/release/PATCH-MANIFEST.json b/release/PATCH-MANIFEST.json index 5254c88..cc7af5c 100644 --- a/release/PATCH-MANIFEST.json +++ b/release/PATCH-MANIFEST.json @@ -6,9 +6,9 @@ "sha256": "d69c38ee1053b25d9b7d480cb8f5197ed061b17d4548fa6490ac2c5951600adc" }, { - "bytes": 7268, + "bytes": 8610, "path": ".github/workflows/production-deploy.yml", - "sha256": "5ccbca51a63c20058db830c242085e5d50be07b49daf1d2ca953dc7a22cdfca4" + "sha256": "34a7ca424f851dd68f83f30904da9b100ab26b87de79373d179d7a5393f4e345" }, { "bytes": 6120, @@ -16,9 +16,9 @@ "sha256": "275cb329b44ee7ca2166a0a69f22bd11b34eaeefdd2c013d5cee9fe08697f372" }, { - "bytes": 2792, + "bytes": 2864, "path": "CHANGELOG.md", - "sha256": "b3cc8035b5e0c43a9d79f3bfa74ed67cedea5445d23796fddee0e4760e3288b6" + "sha256": "45adbffc726fb73264d744488041bb12e3c72d61e98e79d8d93c182acbd14f68" }, { "bytes": 633, @@ -56,9 +56,9 @@ "sha256": "81cfbac5802dfcaf54119e520f8c9683d98aa2bfd26775c2d33179679159ce5b" }, { - "bytes": 2912, + "bytes": 2876, "path": "contracts/capability-truth.json", - "sha256": "eb2a1335b3f0c24cc4de64700c151ad7f4539c943eb15b335cf82f066a3cccb1" + "sha256": "7e6de5588144749c360514d9dd8231f838ddb4e0ba47a8685bfc7bdaa6adf3a5" }, { "bytes": 8070, @@ -521,9 +521,9 @@ "sha256": "fe4741fa6ea8bde3555d9d4ed102c1c91c0106addc44caa5e7f8b01f5d4c69c5" }, { - "bytes": 14316, + "bytes": 14548, "path": "docs/OPERATIONS.md", - "sha256": "3f1fb07515a06a4c1527d06266e536d36cfc16f51d5f01d5f9497f32b4635115" + "sha256": "f92c6f3972e9fdb5f20eafc5ec46ea08b03eec5b7e57ed795389618693a22f66" }, { "bytes": 2598, @@ -548,7 +548,7 @@ { "bytes": 159756, "path": "knowledge/reviews/EXPERT-MODULE-AUDIT.json", - "sha256": "5b56fb56711e68674ba453c4a38dcf1e59f3c3807116efc6ecbae07d0df8dce8" + "sha256": "3ec0dcff1e0c5b0742a53e4040b6902b3a8468040140b5cdc6dd5b3125c5a885" }, { "bytes": 21081, @@ -573,7 +573,7 @@ { "bytes": 49732, "path": "knowledge/reviews/UI-UX-MODULE-AUDIT.json", - "sha256": "5d67538ef1ae674d18b6139cc02fda75bb25a4b55da4f1e650e9382b76833381" + "sha256": "afb9173ab612468f68260a4543300c12a9a2d3bc368e4ebf9016e519b39a0711" }, { "bytes": 2148, @@ -768,17 +768,17 @@ { "bytes": 1626, "path": "release/current/CURRENT-STATIC-CONSISTENCY-AUDIT.json", - "sha256": "e579791e73e64e7f62df1f3a0bc14cf19056eb647b12ef0c263a418a3753a84b" + "sha256": "d169a26e77a7344cacd0e2459c76f7a8d2d31d5854b98d9086fe487b707cc326" }, { "bytes": 1708, "path": "release/current/CURRENT-STATIC-CONSISTENCY-AUDIT.md", - "sha256": "abbb8366608340ac56b4cd20bc19a35373f003fa1da1654f34c420385590bcd7" + "sha256": "141eba89249115700cd20a5083b383466dc93e424f9aa1e410e852068e87e2c5" }, { - "bytes": 40816, + "bytes": 3233, "path": "release/current/ENGINEERING-CLOSURE-REPORT.md", - "sha256": "79202d824f0d764a8c3aec5e111c8f3e04e267801117e9c42f11bfdc82ffaf77" + "sha256": "4894b93d737b16c1d9b4cb11a01c57311ae0bca1fe91f51a2593007888201884" }, { "bytes": 1792, @@ -821,9 +821,9 @@ "sha256": "ab9910ebcf3dafab11d5f24626193f403e1fee042fab927bfec431d39e410d8c" }, { - "bytes": 10793, + "bytes": 10679, "path": "scripts/audit/method_fidelity.py", - "sha256": "a62edc3d24962e970cb46e66d7758d90b1681ec7d1a23ed3a02511b42772a201" + "sha256": "a6b1126e664695d14f63136794e3f1e4580e8c0c14ef58d3a1c0467afbbe4583" }, { "bytes": 12118, @@ -856,9 +856,9 @@ "sha256": "a7504c6eaf55c3224306d0b6ae7509567f9d5c9703c9236aee73d97fb9f51a34" }, { - "bytes": 54020, + "bytes": 58315, "path": "scripts/check-linux-bootstrap.py", - "sha256": "03e7a25978af7969da3115b6e36bdd8b5759a80e4ed018048f75b2d08004d952" + "sha256": "8c3f29467334441e2f93d994f6699ecc3a01e01ecc3d293a1221d61e3e577ce8" }, { "bytes": 4486, @@ -2359,8 +2359,8 @@ "path": "docker/Caddyfile.http" }, { - "after_bytes": 8153, - "after_sha256": "b8f775700c787b917f3a85dbd6f7899ae7f6981dc8d8b8ec405f2d5a5a8ab5ce", + "after_bytes": 8278, + "after_sha256": "c131c693a7004a14d4f9a123edec3f5e6d102ae96bb162fc20fdf99a890c9bf4", "before_bytes": 4368, "before_sha256": "27c093cd42c7e18a6ce02bcb86159551df953039d1b1c2fc90003a5007a0639a", "path": "docker/api.Dockerfile" @@ -2612,7 +2612,7 @@ }, { "after_bytes": 23822, - "after_sha256": "9f65673099456cc36d3c7628b6bca133e447599b5fbc2d5ab920b8ea4dda7be7", + "after_sha256": "63ae385b24969baf94a4e5b91e43e5acbd0a71ae3b9c204ba92c701960f05386", "before_bytes": 20481, "before_sha256": "6b6700eac78e1098c7ea4e7f242f1d80645ea8f0da81410048e9633eddbc284b", "path": "knowledge/reviews/EXPERT-UPGRADE-BACKLOG.json" @@ -2640,7 +2640,7 @@ }, { "after_bytes": 63684, - "after_sha256": "20736a7cf8c1bbf5b94b5b57e25581ebade7e4362c571ef53ff9f89b315a3219", + "after_sha256": "ed17468ccc2c225b70c0da991f616394c429315e6cdf226a63bbc20454122c33", "before_bytes": 56488, "before_sha256": "38e8d902db411ad80e85808dc131e5e832158b0657abf32a123f86a6ad37426b", "path": "knowledge/reviews/MODULE-TOOLCHAIN-MATRIX.json" @@ -2654,7 +2654,7 @@ }, { "after_bytes": 14899, - "after_sha256": "95bfea6422cb07409a6d9b19f668e88136c3d5235f1d9ef2f46a47d720efb3fc", + "after_sha256": "6edcc5e4120efcac2669b4cc3389bcd869437dc52e57f1233929086fc028aed1", "before_bytes": 9132, "before_sha256": "3018f0d195988f1a0b8a7170e02c29752850cfc705c2ca8e6dc8f0de7bfc9390", "path": "knowledge/reviews/SCIENTIFIC-RISK-REGISTER.json" @@ -2766,7 +2766,7 @@ }, { "after_bytes": 200204, - "after_sha256": "a4bced233917e3c9c17c0e2a234ca05d846ea6cee8405adba7ec4639e5bf889a", + "after_sha256": "dd5f729c3bf6af118be49b39ce2a8fda682dc08047d6e7512b3b973ed0c93107", "before_bytes": 187193, "before_sha256": "cf739c04f1764865d5a373b96a6a6b5011b96a8640083e41956f7ee74e0670bc", "path": "knowledge/runtime/numeric-provenance-registry.json" @@ -2829,7 +2829,7 @@ }, { "after_bytes": 1678, - "after_sha256": "ffd07c33bd33fb8dbc80753eb924e8d4f0a0b670cdf6a2623c8c9477a469fbcc", + "after_sha256": "1dc60ed8ebeda774d9699ec32edaf21523086f131c2109643bef0da8d460a813", "before_bytes": 603, "before_sha256": "1d323b3844f8ebf3953a1dd79f479be5abb5dd3b6a35af2bc3ad97471acd3df5", "path": "release/INDEX.md" @@ -2856,8 +2856,8 @@ "path": "release/PUBLIC-SOURCE.md" }, { - "after_bytes": 7583, - "after_sha256": "16e4b4fc365b0c1b3d3e4314c88c3d31931491c6f877d0582e32d2181a8da7a6", + "after_bytes": 269, + "after_sha256": "4b4fbefd32380873307249bcce67d4a2300755b8521faaba151a9c9d5f68108b", "before_bytes": 1111, "before_sha256": "e34d1974f2c960513499d801308192e08c6c483f6610abae0b705f69f68f5c31", "path": "release/RELEASE-NOTES.md" @@ -2885,7 +2885,7 @@ }, { "after_bytes": 5355, - "after_sha256": "6ed6c11d74f474037177ae2b30a4cca2234a9aeec39d5ee295b703bc196d1d1f", + "after_sha256": "2d93294bb274cc6ac939b17168e5ef4308ced5a84d98f6f5a48ed0b1e8b1f4f4", "before_bytes": 3630, "before_sha256": "60cae79862da151902beb2beb68fa4f4213bd769b2c4d5c93d5a4dd39a1e9ae3", "path": "release/current/SOURCE-QUALIFICATION.json" @@ -2906,7 +2906,7 @@ }, { "after_bytes": 532, - "after_sha256": "ac7a1b12402aa1c9f02c22e5f9201c69ab319496a40539652e834eb48795522e", + "after_sha256": "23aaa773c635c627efd7be9c444c1b13facd23d841288ce5352f9e65668ce5a3", "before_bytes": 490, "before_sha256": "d63da32f516385bdc88a84d718fa721f632294774845112edaf2197c5b884333", "path": "release/release.toml" @@ -3129,8 +3129,8 @@ "path": "scripts/generate-source-attestation.py" }, { - "after_bytes": 30345, - "after_sha256": "72dc1aa776f76be24cc62ef43c7d8331383a4365ff7c37d0304657be4e63d01b", + "after_bytes": 30369, + "after_sha256": "8fd41dcb744b8af5e0f9e717f89141e6ee72798e68fd5a0c7507f122b2096f72", "before_bytes": 16903, "before_sha256": "a8c541783f463336fe71b50ab2840f3665809d659e1ab98816b54e23f79f8c54", "path": "scripts/provision-tools.py" diff --git a/release/RELEASE-NOTES.md b/release/RELEASE-NOTES.md index aa2fece..e6faeb2 100644 --- a/release/RELEASE-NOTES.md +++ b/release/RELEASE-NOTES.md @@ -1,95 +1,7 @@ # CURRENT public source — release notes -## v1.0.5 +## v1.0.6 -This maintenance release makes complete pinned native-tool bundles readable to -the restricted application account, including nested MAFFT helper programs and -support files. It verifies the normalized runtime tree and retains the original -upstream archive digest. No image pins, scientific outputs, or user data formats -change. - -## v1.0.4 - -This maintenance release corrects permissions on bundled runtime tools so the -restricted application account can read and execute them. No image pins, -scientific outputs, or user data formats change. - -## v1.0.3 - -This maintenance release keeps server storage under active control: temporary -release files and old backups are cleaned automatically, database backups have -per-file and total-size limits, and the application is paused before disk -pressure can threaten the host. Existing user data and scientific methods are -unchanged. - -## v1.0.2 - -This maintenance release improves production setup and release reliability, -and strengthens the safeguards around dependency updates. Existing user data -and scientific methods are unchanged. - -## v1.0.1 - -This patch release stabilizes fresh-host production deployment. The pull agent -creates its systemd allow-listed state root before sandbox setup, and release -bundles verify portable OCI config digests plus exact prebuilt image tags across -Docker export/import boundaries. No image identity or TLS/provenance control is -weakened. - -## v1.0.0 - -The first standard public product release. It includes the current Linux -control-plane, bounded Docker storage and reproducible release/deployment -workflow. Production deployment pulls a verified source and OCI bundle over -HTTPS and validates the release tag, archive hashes and image identities before -bootstrap. - -## Linux architecture and operations hardening - -The current candidate is now Linux x86_64-native at the release/runtime boundary. Production durable jobs execute in a dedicated PostgreSQL-backed `pcr-runner`, deployment migrations are owned by a one-shot `pcr-migrate`, and the Rust HTTP API remains the enqueue/control plane. Scientific subprocesses are isolated into POSIX process groups so timeout/cancellation/shutdown reap native descendants rather than leaving BLAST/MAFFT-style orphans. - -Production Compose now carries immutable scientific code/tooling in the API/runner image, mounts only fingerprinted specificity data read-only, uses file-backed database secrets, validates the Next Server Actions build key, applies segmented networks and per-role resource/PID ceilings, and records source/scientific build identities in readiness evidence. The bootstrap adds RAM-aware profiles, disk and subnet preflight, pre-deploy backups, strict scientific readiness, immutable environment-drift approval, and optional systemd backup/restore-drill timers. A read-only Linux doctor can audit a VM before bootstrap mutates it. - -Source/static qualification was re-run after the migration and remains green. The latest candidate-wide verification, including exact Docker/OCI pulls, clean image builds and the non-biological production-shaped control-plane/edge drill, is recorded in `release/current/ENGINEERING-CLOSURE-REPORT.md`. Strict scientific and wet-lab acceptance remain explicit separate gates. -## Current static full-stack remediation - -The current source hardens the qualification-candidate tree without promoting any scientific module or claiming runtime evidence. Durable jobs now use database-backed executor leases, heartbeat/recovery and atomic run/job completion; job creation is rate-limited and bounded by active, retained, payload, account-byte and retention limits. Backup format v2 preserves project/run provenance instead of relabelling restored history, while legacy v1 remains accepted with unknown project draft provenance represented explicitly rather than guessed. - -Worker stdout/stderr retention is bounded and timeout cleanup kills/reaps children before joining pipe helpers. Durable-job diagnostics are redacted through the public error taxonomy. Attachment/qualification ownership correlation is enforced in code and strengthened by composite database constraints. The no-domain VM bootstrap is loopback-only; direct public service requires HTTPS. The mobile sheet close control, auth text alignment, API project-limit contract parity and workflow permissions are also corrected. - -The current remediation changes were prepared and reconciled by static source inspection only. They do not claim Rust/TypeScript/Python compilation, migrations, Docker/runtime behavior, native-tool availability, Linux acceptance or wet-lab qualification; those remain required before Final promotion. - -A subsequent method-fidelity closure adds a canonical named-method registry and CI/source gate. SADDLE Badness is separated from the unavailable exact SADDLE simulated-annealing optimiser; Universal Primer surrogate pre-ranking and LAMP linear proxy ranking are removed from primary decisions; Tetra-ARMS uses the reviewed Ye/Collins-Day public-rule branch; RPA exposes a source-backed 8–10 forward × 8–10 reverse empirical screening matrix rather than treating Primer3 scores as RPA validation; QuikChange rules are manual-faithful without claiming Agilent web-tool equivalence; and ARMSprimer3, Kraken, PrimerExplorer proprietary search and NEBaseChanger web-tool design remain distinct external/reference authorities where exact execution is not integrated. Per-run method fidelity is fingerprint-bound and exposed in Web provenance. - -CURRENT completes the source/full-stack closure of Inverse PCR, hydrolysis-probe -qPCR, RACE/Sequencing Primer, and Tiling Scheme on the Generation-1 baseline. - -Key changes include qPCR Probe status/projection reconciliation; source-backed -separation of vendor rules from PCRStudio search defaults; conventional Thermo -Fisher/IDT probe execution plus hash-bound MGB external-authority export/import; current -FirstChoice exact-partner and content-addressed SMARTer/custom RACE authority support; -correction of a RACE adapter dispatch defect; inverse-PCR circular/pydna/Sanger evidence; -PrimalScheme3 circular create/native visual/depth-dropout repair/version-diff transport; and -unified-engine Rust/Python/Web differential/property contracts plus Linux high-risk acceptance coverage. - -A subsequent cross-layer audit closed 18 additional source findings spanning -release finalization, acceptance evidence, Fork/Reopen state, qPCR multiplex -claims, live/E2E coverage, transport parity, package identity, and canonical -API requirements. Module-contract 2.2.0 now explicitly separates semantic -form context from HTTP wire context so Web readiness, Rust API validation, -and Python worker validation share authority without inferring payload paths -from UI field names. - -A final pre-Linux cold audit identified and closed 20 further operational gaps in -scientific tool resolution/readiness, native qualification evidence, E2E/deployment -boundaries, UI semantics and release provenance. A strict follow-up reconciliation -reduced 46 residual audit findings to zero without weakening scientific refusal -boundaries. - -The public-source cleanup removes superseded checkpoint/history reports and -obsolete release-control scripts, keeps only the baseline artifact required -by CURRENT qualification, and replaces machine/agent-specific notes with public -development, contribution, and security documentation. - -CURRENT does not claim native Linux PASS or wet-lab validation until those gates -are executed and recorded against the exact release identity. +Fixes a production startup issue in the restricted server runtime. A release is +now published only after its production images pass final startup checks. +Existing user data and pinned dependencies remain unchanged. diff --git a/release/SHA256SUMS.txt b/release/SHA256SUMS.txt index 2656f07..e3f91cf 100644 --- a/release/SHA256SUMS.txt +++ b/release/SHA256SUMS.txt @@ -5,8 +5,8 @@ bda5e46776f16c6db86a9459ad90adad60f4c602fdbdcffb17722e2033ff1754 docs/openapi.g 653656a0031d529cb45a43b9b760e5bc32037d158110512b8acf26b8b1d92b47 knowledge/runtime/linux-acceptance-matrix.json 940c4109f4cae406e1ef4ca0c7407a3c45149f94f194fd8b6006b99bf98c0103 knowledge/runtime/module-contracts.generated.json 1d3d7f092812bec508d6923a0993f2283b288d306ec0c87c96a2d019b8367c83 knowledge/runtime/tool-contracts.generated.json -2118e78ba5f278a62b456dc5034c0075a77f9a4626ba153be224962472fcf026 release/FILE-MANIFEST.json -d52330df7190122f41b809a2a349ad209c7118861595b91d8bc642e0d68eb8ac release/PATCH-MANIFEST.json +40bbb89dd2ab2cf1583d183ffdad76616b6f7fa0d6296c402fea439fdc7f8a87 release/FILE-MANIFEST.json +69b3dc93ae8fcc181851c3d906bc6fb818631d21fcd509a464325ad6b2b3f6dd release/PATCH-MANIFEST.json 6c5ca96b26e38f455332e5ef6084966387f910c3d0b201511aa95d00300bb2fb release/RUNTIME-CONTRACT-MANIFEST.json 9bce416ccb675fafed6ea42dc8ebd2c4f31646bbf3e67bc756402db2683b6b52 release/current/CURRENT-ENGINE-SYSTEM.md 075388950b0f86c8775d15d3e406fb7e9ca59312748a371b5be2e17dc2625f26 release/current/CURRENT-FOUNDATION-CLOSURE.md @@ -14,15 +14,15 @@ d52330df7190122f41b809a2a349ad209c7118861595b91d8bc642e0d68eb8ac release/PATCH- 8b46ff5e62b63b6698657772dc0d36fdc70183b60f1dc04a8421796c9b68bdc7 release/current/CURRENT-LINUX-QUALIFICATION.md e2a0387696df4b1a1145691b60bb217412c435e5d397505687d04b96314cd51a release/current/CURRENT-METHOD-FIDELITY-CLOSURE.md 6b72f22001a9108fa83ba8e9e5c14a66e119518b68f939c09c1381bcb468d4b5 release/current/CURRENT-MULTIPLEX-CLOSURE.md -e579791e73e64e7f62df1f3a0bc14cf19056eb647b12ef0c263a418a3753a84b release/current/CURRENT-STATIC-CONSISTENCY-AUDIT.json -abbb8366608340ac56b4cd20bc19a35373f003fa1da1654f34c420385590bcd7 release/current/CURRENT-STATIC-CONSISTENCY-AUDIT.md -79202d824f0d764a8c3aec5e111c8f3e04e267801117e9c42f11bfdc82ffaf77 release/current/ENGINEERING-CLOSURE-REPORT.md +d169a26e77a7344cacd0e2459c76f7a8d2d31d5854b98d9086fe487b707cc326 release/current/CURRENT-STATIC-CONSISTENCY-AUDIT.json +141eba89249115700cd20a5083b383466dc93e424f9aa1e410e852068e87e2c5 release/current/CURRENT-STATIC-CONSISTENCY-AUDIT.md +4894b93d737b16c1d9b4cb11a01c57311ae0bca1fe91f51a2593007888201884 release/current/ENGINEERING-CLOSURE-REPORT.md 8d5f3dbb4841781a4b4aa7f59a930f4715561ccc460ca79023a87bff89a00ea8 release/current/PERFORMANCE-STATUS.md 4ccbbcabe1aeb60f6c8d2b4ec9f248ca00489a4ee2074a0b6264403d94fdf2ee release/current/README.md ad3305f910d6f8148a805dd2b99c8b88cc264df8a37190087957b9063665f9d3 release/current/SBOM.cdx.json 5ab7d453742c3338f4d2ed816f1410cc4e45920b58b66653c73f8d0c7e564af5 release/current/SECURITY-EXCEPTIONS.md -37ea94bd6f23da947577c6342b3875986e5c91931d9c14782203b50308ed3b9d release/current/SOURCE-ATTESTATION.intoto.json -6ed6c11d74f474037177ae2b30a4cca2234a9aeec39d5ee295b703bc196d1d1f release/current/SOURCE-QUALIFICATION.json +f79a4a9527ae1be46bfd5c8961a653c529675ae4fb4014103a6e5a00887933b4 release/current/SOURCE-ATTESTATION.intoto.json +2d93294bb274cc6ac939b17168e5ef4308ced5a84d98f6f5a48ed0b1e8b1f4f4 release/current/SOURCE-QUALIFICATION.json 90b7855e4855181770453b915836c9286ba0eabecc21ba1330581a0ed4e67122 release/current/SOURCE-QUALIFICATION.md ceb912d6a98435fda489bb961cf55f84e6fb33a9bc85cff015bfe4f042930214 release/current/SUPPLY-CHAIN.md 0ced565d1a1bb585517f918f91c5c2ce47a28921d4cd40a537a915bf5f4bdb96 scripts/run-linux-qualification.py diff --git a/release/current/CURRENT-STATIC-CONSISTENCY-AUDIT.json b/release/current/CURRENT-STATIC-CONSISTENCY-AUDIT.json index cc215e4..0225434 100644 --- a/release/current/CURRENT-STATIC-CONSISTENCY-AUDIT.json +++ b/release/current/CURRENT-STATIC-CONSISTENCY-AUDIT.json @@ -45,8 +45,8 @@ "modules": 21, "stable_modules": 0 }, - "public_tag": "v1.0.5", - "public_version": "1.0.5", + "public_tag": "v1.0.6", + "public_version": "1.0.6", "release_class": "generation-1-unified-engine-linux-current", "release_id": "CURRENT", "schema_version": "2.0.0", diff --git a/release/current/CURRENT-STATIC-CONSISTENCY-AUDIT.md b/release/current/CURRENT-STATIC-CONSISTENCY-AUDIT.md index 6a77093..442ba19 100644 --- a/release/current/CURRENT-STATIC-CONSISTENCY-AUDIT.md +++ b/release/current/CURRENT-STATIC-CONSISTENCY-AUDIT.md @@ -1,7 +1,7 @@ # CURRENT static consistency audit **Status:** **PASS** -**Public release:** **v1.0.5** (SemVer 1.0.5) +**Public release:** **v1.0.6** (SemVer 1.0.6) **Platform authority:** Linux x86_64 **Scope:** deterministic current-tree source/static consistency. Native dependency-backed and container/scientific execution is an explicit separate gate. diff --git a/release/current/ENGINEERING-CLOSURE-REPORT.md b/release/current/ENGINEERING-CLOSURE-REPORT.md index 0f35128..41e8d44 100644 --- a/release/current/ENGINEERING-CLOSURE-REPORT.md +++ b/release/current/ENGINEERING-CLOSURE-REPORT.md @@ -1,562 +1,61 @@ -# PCRStudio Engineering Closure Report - -Date: 2026-09-12 -Status: **OPEN. Corrected PR candidate `892b0a0` passed hosted qualification. The current follow-up removes two non-biological build/bootstrap warnings without changing PostgreSQL major version; the `main` ruleset still needs the aggregate gate after its workflow is integrated. No merge or deployment has occurred.** - -This is the canonical current engineering-closure report. It preserves the -verified 2026-09-09 baseline below and records the newer candidate state -separately; historical evidence is not presented as proof that the current -candidate or a live deployment is green. - -## Current GitHub and local state (2026-09-12) - -- The canonical repository is `Soheilbz/PCRStudio`; default branch is `main`. - PR [#39](https://github.com/Soheilbz/PCRStudio/pull/39) is the review path - from `codex/final-readiness-20260912`. The last completed hosted run - recorded below qualified commit `892b0a0`; the live PR page is authoritative - for the follow-up candidate and its current checks. -- The earlier pre-fix CI run, [34720256104](https://github.com/Soheilbz/PCRStudio/actions/runs/34720256104), - completed all 1,167 Python tests - and audits, then stopped at Rust formatting; the final qualification job - lacked a source checkout. -- Correction commit - [`892b0a0`](https://github.com/Soheilbz/PCRStudio/commit/892b0a0) - passed hosted run - [34723668864](https://github.com/Soheilbz/PCRStudio/actions/runs/34723668864): - Fast feedback, Web, Linux images, source/Rust/Python, aggregate qualification, - dependency review, and CodeQL all completed successfully. The 1,167-test - Python suite passed with the bounded xdist configuration. -- Follow-up commit - [`2f2a616`](https://github.com/Soheilbz/PCRStudio/commit/2f2a616) was - exercised by [run 34726146362](https://github.com/Soheilbz/PCRStudio/actions/runs/34726146362). - Fast feedback, Web production/browser, and Dependency Review passed, but its - Linux image job failed at API image build because `xz-doc` is absent from the - pinned Debian snapshot. This is a repository Dockerfile error, not registry - instability. The next source commit removes that nonexistent package and - restores the missing manpage targets only for the build transaction. -- Root causes were corrected: the Rust test now matches Rust 1.94.1 - formatting; the aggregate job has a read-only checkout with persisted - credentials disabled; and a dependency-free regression check protects that - checkout-before-script invariant. Local evidence also includes all 41 - `pcr-server` API integration tests, targeted Clippy, Rust formatting, and - `scripts/check-linux-bootstrap.py` passing. -- The full locked Python suite passed locally under four `pytest-xdist` - workers: 1,167 passed in 610.09 seconds. The prior hosted serial run took - 1,489.54 seconds for the same suite; these are different machines, so the - timing comparison is indicative, not a controlled benchmark. CI now uses a - bounded four-worker `loadscope` run; hosted run 34723668864 completed this - configuration successfully. - The local profile disabled pytest's cache provider, which produced expected - unknown-`cache_dir` warnings; CI keeps the cache provider enabled and sets - `PYTHONDONTWRITEBYTECODE=1`. Local bytecode created by the profile was removed. -- All four `astral-sh/setup-uv` uses in CI and production qualification now set - `prune-cache: true`. The pinned action supports this input; upstream documents - that it removes prebuilt wheels before persisting the GitHub Actions cache, - while retaining wheels built from source. A source-contract assertion keeps - future setup-uv uses from silently reverting to unpruned cache saves. This - controls reusable CI cache size; it is separate from host-local Cargo output - and application/server storage. The cache-size effect is not separately - quantified. -- The green run's logs exposed two remaining non-biological warnings. The - pinned Alpine PostgreSQL image has no `locale` executable; `initdb` fell back - to locale `C` but warned that no system locales were usable. This was - reproduced against the exact digest; `--no-locale` did not remove it. The - current source follow-up uses the exact official PostgreSQL `18.6-bookworm` - index digest - `sha256:1c59e2c3c818eaa0f0628f695b36e7c9e362d6b219b36a54a32df645cbd7e1af` - and explicitly sets `C`/UTF-8/SCRAM. Its exact pull, readiness, table write, - custom-format dump/restore, and warning-free startup passed locally in both - a tmpfs probe and an isolated devdb Compose project (including cleanup of - its test volume). The current PR's hosted checks are the qualification - boundary for this changed pin. An attempted `xz-doc` install in the next - image run failed because that package is absent from the pinned Debian - snapshot. The source fix now temporarily re-includes the existing xz - manpages during dpkg's package-configuration transaction, then removes them - from the disposable builder; it does not install an extra package or affect - runtime images. The MFEprimer compiler/security findings remain - visible under the existing time-bounded exception and were not modified. -- The active `Protect main` ruleset currently requires only - `Fast feedback and targeted contracts` and `Web production and browser - qualification`; it does not require `Required PCRStudio qualification`. - This was re-read after the aggregate passed. `main` still has the - pre-aggregate workflow; requiring the new context before integrating that - workflow would strand existing PRs that cannot emit it. Add the rule after - PR #39 is merged and the base branch exposes the check. No merge, release, - or deployment has been performed; `main` remains untouched. -- The earlier public read found PR #39 at `fbb8559` with failing source and - aggregate jobs; that was the pre-fix state, not the current candidate. The - accepted MFEprimer findings remain visible as notices under the documented - exception; they were not suppressed. -- An initial GitHub read attempt timed out, but follow-up isolation succeeded: - DNS resolves both GitHub hosts, direct unauthenticated HTTPS returned HTTP - 200 for `github.com` and `api.github.com`, `git ls-remote` returned the - expected branch SHA, and authenticated PR/ruleset reads succeeded. No - persistent auth, DNS, proxy, or transport fault remains evidenced; the first - timeout was transient. -- Generated release manifests and the source attestation have now been - refreshed after the report/workflow changes. Local release verification - passes with 1,058 manifest files, 914 SBOM components, 28 checksum entries, - zero mismatches, zero case collisions, and zero symlinks. PR #39's live - required checks are authoritative for the latest candidate. - -## Initial baseline (verified 2026-09-09) - -- The candidate is committed on branch `release-candidate-20260909` and - published to the canonical GitHub repository. Remote `main` remains - protected and unchanged until the normal pull-request merge process. -- Canonical design modules: 21. Generated contract/runtime artifacts also - contain 21 module identities. -- Existing source audit: 0 errors, 0 warnings. -- Secret scan: PASS for the current source tree; high-confidence credential - formats were not found. -- Public-source archive: built and independently verified from the candidate; - 1,055 archive entries, with local caches, dependencies, build output and test - output excluded. All 80 shebang-bearing archive members retain executable - bits. The extracted archive also passed source audit and release verification. -- A fresh archive extraction installed the frozen JavaScript workspace and the - `tools` development environment from local caches, then passed - `scripts/qualify-source.py --no-write`. The exact project-local baseline is - now installed and available: Node 24.20.0, pnpm 11.26.0, uv 0.12.10 and - Rust 1.94.1. -- Against that same clean extraction, `pnpm --filter web check` passed typecheck, - lint, formatting and Vitest: 49 test files passed with one skipped, and 619 - tests passed with seven skipped. - -## Issue ledger summary - -| ID | Finding | Severity | Status | Resolution/evidence | -| --- | --- | --- | --- | --- | -| E-001 | Host Rust 1.93.1 lacks the workspace-required Rust toolchain | P1 environment | VERIFIED | The project-local 1.94.x toolchain boundary was exercised; the current exact 1.94.1 pin is tracked separately in E-008 | -| E-002 | Docker Hub denied the exact pinned PostgreSQL manifest | P1 external | VERIFIED | Standard bearer-token access now returns HTTP 200 for the exact digest; the exact image pulled through the new OCI preflight, the production-shaped private Compose database reached healthy, and a custom-format backup/restore drill passed | -| E-003 | Production dependency advisory finding in Sharp through Next.js | P1 security | VERIFIED | Exact npm advisory access succeeded; the Sharp/libheif finding was remediated by updating Next.js 16.3.3 → 16.3.4, refreshing the lockfile, and obtaining `No known vulnerabilities found` from `pnpm audit --prod --audit-level=high` | -| E-004 | Browser/build origin mismatch could be mistaken for a `/try` product failure | P2 verification setup | VERIFIED | Smoke now defaults to `http://localhost:3100`; E2E rejects an explicit `PCR_E2E_BASE_URL`/`NEXT_PUBLIC_SITE_URL` mismatch before tests run; matching-origin E2E and `/try` pass | -| E-005 | Release metadata drifted during diagnosis | P2 release hygiene | VERIFIED | The diagnostic `/try` patch was removed; manifests, attestation, checksums, archive, and static-consistency artifacts were regenerated and verify clean | -| E-006 | This host lacks the strict native scientific artifacts/databases | P1 external | VERIFIED | Provisioned MAFFT, MFEprimer, BLAST+, PrimalScheme3 and PrimerPooler plus approved-reference indexes now hash-match; the strict verifier passes, `/ready/scientific` is HTTP 200, and the five-browser critical journey passes | -| E-007 | Authenticated unknown-module route streamed HTTP 200 instead of 404 | P2 product correctness | VERIFIED | The authenticated app layout now rejects unknown module IDs before streamed shell content; the five-browser regression and 21-module matrix pass | -| E-008 | Exact final patch-level toolchain cannot be installed on this host | P2 environment | VERIFIED | Project-local Node 24.20.0, pnpm 11.26.0, uv 0.12.10 and Rust 1.94.1 are installed; frozen installs and the non-biological exact qualification gates pass | -| E-009 | Docker BuildKit could not reach the npm registry while building the pinned Web image | P1 external | VERIFIED | The Web builder now inherits its already-materialized pinned pnpm 11.26.0 bundle from the dependency layer, eliminating the second hidden npm-registry fetch; the exact pinned Node image build, Next.js 16.3.4 build, file-backed Server Actions key, and read-only non-root HTTP smoke all passed | -| E-010 | Docker could not resolve the exact Rust base layer required by the production API/runner image | P1 external | VERIFIED | Persistent NetworkManager DNS repair restored canonical Docker Hub answers; the exact Rust digest pull passed, and clean API, runner, and migrator builds passed with the pinned identities | -| E-011 | Caddy healthcheck selected unavailable IPv6 loopback for `localhost` | P2 repository | VERIFIED | The edge probe now targets `127.0.0.1:2019` explicitly; the private loopback production-shaped Compose stack reached healthy and served an edge GET | -| E-012 | Hosted image qualification reports HIGH Go standard-library findings in the pinned MFEprimer 4.5.1 binary | P1 external security | ACCEPTED-TEMPORARILY | `SEC-EXC-2026-09-MFEPRIMER-451` records the exact executable hash, target path, package/version, severity and CVE allowlist with review-by `2026-10-09`; Trivy findings remain visible and any mismatch fails closed | -| E-013 | Rust formatting failure in the current PR's HTTP body-limit regression test | P2 CI correctness | VERIFIED | Rust 1.94.1 formatting check and all 41 `pcr-server` API tests pass; corrected hosted run 34723668864 is green | -| E-014 | Aggregate qualification job invoked a repository script without checkout | P1 CI enforcement | VERIFIED | Least-privilege checkout (`contents: read`, `persist-credentials: false`) plus regression assertion; hosted aggregate passed in run 34723668864 | -| E-015 | Full Python suite ran serially for 1,489.54 seconds in hosted CI | P2 feedback latency | VERIFIED | Bounded four-worker xdist configuration passed all 1,167 tests in hosted run 34723668864; local suite passed in 610.09 seconds | -| E-016 | `Protect main` does not require the aggregate qualification check | P1 branch protection | OPEN | The active ruleset requires fast feedback and Web qualification but not the aggregate. Add the aggregate after PR #39 integrates the workflow; updating earlier would strand PRs whose base cannot emit that check | -| E-017 | GitHub Actions persisted the full uv cache without pruning | P2 CI storage hygiene | VERIFIED | All four pinned setup-uv uses prune before saving, guarded by `check-linux-bootstrap.py`; the cache-size effect has not been separately measured | -| E-018 | Transient GitHub HTTPS timeout during initial remote verification | P2 external connectivity | RESOLVED | Follow-up direct HTTPS requests returned HTTP 200, `git ls-remote` returned the exact remote branch SHA, and authenticated PR/ruleset reads succeeded; no continuing network or credential issue was observed | -| E-019 | Pinned Alpine PostgreSQL emitted `no usable system locales` during bootstrap | P2 qualification signal | IMPLEMENTED; HOSTED CHECKS TRACKED ON PR | Reproduced against the exact previous digest; the warning came from the absent `locale` utility. Production, CI, and devdb now use the official PostgreSQL 18.6 Bookworm image at a fixed index digest with explicit C/UTF-8/SCRAM settings. Exact pull, readiness, write, backup/restore, and zero-warning startup passed locally in tmpfs and the isolated devdb Compose path; its temporary volume was removed after the test | -| E-020 | Debian `xz-utils` post-install warned because base-image dpkg filters omitted its manpage targets | P3 build hygiene | IMPLEMENTED; PR QUALIFICATION TRACKED LIVE | Run 34726146362 confirmed `xz-doc` is unavailable in the frozen Trixie snapshot. The corrected Dockerfile re-includes `/usr/share/man/*` only for dpkg during the builder dependency transaction and deletes those manuals in the same layer. The live required PR check is the hosted verification boundary for that source correction | - -At the 2026-09-09 checkpoint, no unresolved repository-owned defect remained -in the exercised non-biological scope. That statement does not cover the -current PR #39 findings above. The production-shaped control-plane and edge -Compose drill passed with exact PostgreSQL, API, migrator, Web, and Caddy -artifacts. The scientific runner was intentionally not accepted because -native biological/toolchain acceptance is outside the current user scope; its -strict preflight remains fail-closed. E-012 remains a visible, time-bounded -security condition rather than being treated as remediated. The final GitHub -release is created only after the exact release archive and current generated -evidence are rebuilt and verified from the release commit. - -## Prior release baseline and historical qualification (2026-09-09) - -The following sections preserve the evidence from the earlier candidate. They -are not evidence that the current PR's hosted checks or production deployment -have completed. - - -## Architecture - -The repository remains a layered modular monolith: Next.js web boundary, Rust -workspace/core and server/API crates, Python scientific/tooling layer, -PostgreSQL persistence, and generated contract/release artifacts. Browser code -does not receive the API address; the guest `/try` flow uses a server action and -the same canonical API contract as authenticated workspaces. - -The repository-driven capability inventory found 35 web route/page/handler -files, 10 Rust crates, 49 Rust route registrations, 82 Python test files, 15 -ordered PostgreSQL migrations, six Compose services (`db`, `migrate`, `api`, -`runner`, `web`, `caddy`), 58 canonical HTTP endpoints, 11 engines, 12 tooling -contracts, and 21 module registry entries. The inventory also confirmed import/ -export handlers, shared-run links, account recovery, rate limiting, runner -leases, sequence assets, attachments, assay qualifications, operator metrics, -health/readiness routes, and release-generation tooling as in-scope capabilities. - -## Current-state repository policy - -The active tree keeps one canonical report for the release-wide state and one -authority for each scoped concern. The obsolete engine-maturity snapshot and -the independent unknown-unknowns checkpoint were removed after their durable -facts were reconciled here. Migrations, ADRs, security records, generated -provenance and the immutable `release/baseline` remain. The diagnostic `/try` -source patch was removed after the verified root cause was found; no -unnecessary product source change remains. - -## Modernization - -- Web stack verified on Next 16.3.4 with the repository's breaking-change - guidance read before editing. -- The obsolete `experimental.useTypeScriptCli: false` workaround was removed - after the Next 16.3.4 upgrade; the documented project-local TypeScript CLI - default now runs successfully in the production build. -- The final source pins the authoritative patch-level baseline: Node 24.20.0, - pnpm 11.26.0, uv 0.12.10 and Rust 1.94.1. All non-biological exact - qualification gates were re-run on that baseline, including frozen installs, - Rust checks, the Python environment sync, the web suite, production build, - and npm advisory audit. -- Standalone Next output was exercised through `web/scripts/start-standalone.mjs`. -- Release manifests, static consistency artifacts, and deterministic source - attestation were regenerated for the final source state. - -The dependency/toolchain audit date is 2026-09-08. Node 24.20.0 is the -current Node 24 LTS release listed by the [official Node release -schedule](https://nodejs.org/en/about/previous-releases); uv 0.12.10 is the -current upstream release listed by [Astral's uv release -history](https://github.com/astral-sh/uv/releases); pnpm 11.26.0 is the current -pnpm 11 release listed by the [official pnpm release -history](https://github.com/pnpm/pnpm/releases); and Rust 1.94.1 is the patch -release documented by the [Rust release notes](https://doc.rust-lang.org/releases.html). -Python 3.14 remains the CI major/minor baseline; the upstream documentation -lists 3.14.7 as the current maintenance release. The exact updated binaries -are installed under the project-local `.local` toolchain root and were -exercised for the non-biological gates recorded below. - -## Database and migrations - -The local PostgreSQL 18 cluster on `127.0.0.1:55432` accepted the configured -test connection. DB-backed Rust tests passed with that database. The exact -pinned Docker PostgreSQL image now pulls through the standard bearer-token -flow. Its Compose dev database reached healthy, and an exact-image custom- -format backup/restore probe passed; no digest was loosened and no substitute -image was used. Independently, a host-native PostgreSQL 18 custom-format -dump/restore into an isolated temporary PostgreSQL 18 instance passed: 15 -migrations, 16 public tables, and zero unvalidated public constraints. This -proves database backup bytes can restore locally. The new OCI preflight also -resolved all three Docker Hub endpoints and pulled the exact five digest-pinned -external references used by the production build/runtime path. - -## Security - -Source audit, secret scan, static qualification, security-header smoke checks, -and browser-origin behavior passed. The origin guard correctly rejected the -deliberately mismatched `127.0.0.1`/`localhost` Server Action request with 403, -then accepted matching-origin requests. Production headers include CSP, -frame/resource isolation, referrer policy, permissions policy, and content -sniffing protection. - -## Web and UX - -The integrated `pnpm check` pass passed: web checks reported 49 test files -passed, 1 skipped; 619 tests passed, 7 skipped; Python passed 1,167 tests in - 1,353.97 seconds; and Rust clippy plus the complete workspace test/doc-test -suite passed. Production build passed. The rebuilt standalone server passed -the 12-route smoke gate within the 1,500 ms budget; the latest sampled route -was 68 ms. Full browser E2E passed with a matching origin: 170 passed and 30 -intentionally skipped across Chromium, Firefox, WebKit, mobile Chrome, and -mobile Safari. The strict-runtime recheck then passed the authenticated -critical journey in all five browser projects, including mobile Safari. The -`/try` matrix passed 10 of 10 in the standalone deployment-shaped run. -API-backed verification also passed the five-browser 21-module workspace -matrix and the five-browser authenticated unknown-module 404 regression. The -strict engine execution suite passed 10 of 10 browser-project cases, covering -the five current engine workspaces through browser → Next → Rust → Python -result rendering, including mobile Safari. The -earlier Mobile Safari timeout was reproduced as a strict-runtime symptom and -closed after the provisioned strict toolchain was loaded; it is not hidden as -a UI success. - -The rendered audit covered desktop and 390px mobile views of sign-in, `/try`, -and documentation surfaces. All sampled routes returned expected content, -showed no horizontal overflow, emitted no browser console errors, and had no -broken visible images. Screenshots were inspected for clipping, hierarchy, -control reachability, footer/header behavior, and mobile stacking. - -The existing `/try` action was validated to preserve the submitted sequence -and return an honest transport error when the design core is unavailable, once -the browser and build use the same configured public origin. - -## Scientific/modules - -All 21 canonical module IDs, generated module contracts, engine contracts, and -static scientific consistency gates passed. The independent strict toolchain -verifier passed with hash-matched native artifacts, approved-reference indexes, -and the approved scientific-Python freeze; `/ready/scientific` returned HTTP -200, the authenticated critical journey passed in all five browser projects, -and the strict engine execution suite passed 10 of 10 browser-project cases. -Those historical scientific results are retained as evidence, but no new -native biological acceptance was attempted in the current non-biological pass. - -## Runtime and operations - -Linux bootstrap source regression passed. The exact pinned PostgreSQL image, -API/runner/migrator builds, and private loopback production-shaped Compose -path were exercised successfully. PostgreSQL reached healthy, migrations -completed, API `/health` and `/ready` passed, Web and Caddy healthchecks -passed, an edge GET passed, backup/restore passed with 15 migrations and 16 -tables, and restart/recreation with `--no-build` reused local artifacts. An -independent second disposable private-loopback Compose pass repeated the -database bootstrap, migrations/readiness, backup/restore, edge GET, and -restart/recreation checks successfully. -Native biological acceptance is outside the current scope; the runner's -strict scientific preflight therefore remained fail-closed. The standalone -launch path is verified and is the correct path for this `output: standalone` -configuration. - -## Docker/OCI dependency stabilization - -The recurring Docker failure was host-side, not an image or digest problem. -The active NetworkManager connection was accepting a DHCP resolver at -`192.168.168.125` that returned broken/noncanonical Docker Hub answers for -`auth.docker.io`; `systemd-resolved` also changed default routes when the -intermittent `tun0` appeared. The host had no usable IPv6 default route, so -Docker's dual-stack attempts added misleading IPv6/network errors. No HTTP, -HTTPS, or daemon proxy was configured, and the public pinned images did not -require credentials. - -The active connection was durably changed to use approved public resolvers -`1.1.1.1,8.8.8.8` with auto-DNS disabled and then reapplied. `resolvectl` -returned canonical Docker Hub answers, and the exact pinned Rust pull passed -immediately afterward. The repository now runs an early OCI preflight that -checks IPv4 resolution for `auth.docker.io`, `registry-1.docker.io`, and -`production.cloudfront.docker.com`, reports IPv6 as an address-family -condition, enumerates the five exact digest-pinned external references, and -pulls them through Docker's normal credential helper. Only classified transient -transport failures retry with finite exponential backoff; DNS, auth, -rate-limit, TLS, and digest/pin failures stop without substitution. Each pull -also has a finite 180-second timeout, and the preflight probes the auth token -service, registry bearer boundary, and CloudFront CDN over HTTPS without -printing response bodies or credentials. - -The Web Dockerfile also now retains the materialized pinned pnpm bundle between -dependency and builder stages, preventing a second hidden npm-registry fetch -after source changes invalidate the build layer. No mirror, insecure registry, -tag fallback, TLS bypass, or credential was added. - -## CI and supply chain - -Release verification passed with 1,051 manifest files, 914 SBOM components, 28 -checksum entries, zero manifest/checksum mismatches, zero case collisions, and -zero symlinks. The public-source archive verifier and extracted-archive audit -also passed. Pinned container and GitHub Actions references were reported by -the verifier. The exact `pnpm audit --prod --audit-level=high` now completes -with no known vulnerabilities after the Next.js 16.3.4 update. The exact -Node/pnpm/uv/Rust baseline is installed and the non-biological qualification -gates pass on it. - -The runs `34399728139`, `34399728117`, `34399728175`, and `34399728242` and -PR #19 are historical evidence from the 2026-09-09 candidate, not the current -GitHub state. PR #39 and its current qualification state are recorded at the -top of this report. The pinned MFEprimer 4.5.1 findings, including -`CVE-2026-33818`, remain visible under the exact time-bounded exception. No -image identity, digest, TLS, provenance, or scan policy was weakened. - -The earlier run 34723668864 exposed a PostgreSQL `no usable system locales` -warning from the pinned Alpine image's missing `locale` utility and Debian -package post-install manpage notices. The first follow-up image build then -exposed the unavailable `xz-doc` package; the failure and its correction are -recorded under E-020. Trivy's vendor-severity notice and the upstream -`genome.c` compiler warning remain visible; the latter is within the biological -code explicitly excluded from this work. - -## Architecture fitness functions - -Static source audit, generated-contract qualification, canonical static audit, -secret scan, release verification, build/type/lint/format checks, Rust -fmt/clippy/tests, Python tests, web smoke, and browser E2E all passed in the -available environment. - -## Performance - -The production smoke gate measured all public routes under the configured 1,500 -ms budget. The latest rebuilt standalone smoke run reported the slowest sampled -public route at 68 ms; the route set was non-empty and returned expected -content types. - -## Change provenance and cleanup - -- The verified root cause for the `/try` failure was a build/test origin - mismatch: `127.0.0.1` was tested against a build configured for `localhost`. - The 403 was the intended origin policy, not an application error. -- The smoke/E2E origin contract is now structurally protected: the local smoke - default matches Playwright's `localhost` default, and an explicit external - E2E target must match the configured public origin. -- The authenticated module route had a real streamed-404 defect. The layout now - rejects unknown module IDs before shell content can stream, and the focused - five-browser regression is green. -- A temporary guarded-normalization patch was introduced during diagnosis and - removed after that hypothesis was disproven; no origin-policy weakening or - unrelated fallback was kept. -- Release metadata, the current evidence index and the closure report are - intentional permanent evidence; - generated caches, browser traces, and temporary diagnostic outputs are not - part of the release manifest. The final source audit reports zero cache - residue and zero whitespace errors. -- Six stale local Next/API verification process groups from earlier acceptance - runs were identified by their ports and launch commands, then stopped before - the final fresh-archive passes; no application or test server remains - listening on the verification ports. -- Generated `.next`, Playwright report/result, and pytest cache directories were - removed from the working tree after verification; they remain excluded from - the public archive. -- The unrelated root-level MetaTrader/desktop-tool installer and the - Next-generated `web/AGENTS.md`/`web/CLAUDE.md` guidance files were removed - after reference checks found no product, build, release, or documentation - dependency; no active ignore or build rule refers to those paths. -- No orphan, speculative, debug-only, or test-only bypass change was found in - the final source change set. -- The final dependency pin modernization is traceable to the 2026-09-08 - authoritative upstream audit; the exact non-biological runtime - requalification is recorded under E-008. -- The temporary `/try` fallback remains absent; `web/src/lib/try/actions.ts` - retains the original honest error path. -- A disposable clean checkout of the canonical remote at commit - `51c94f009048ff60fd3c93c17a63caeb9edcd08d` was reconciled against the - current candidate by content hash. Candidate-only additions are limited to - current evidence and supporting audit/test helpers; the working directory is - rooted at that canonical commit; the candidate is now represented by the clean - published review branch `release-candidate-20260909`. - -## Assurance-gap and fitness-function review - -| Invariant | Enforcement | Verification | -| --- | --- | --- | -| Canonical module/engine/API projections do not drift | Generator and differential-contract checks | `qualify-source.py --no-write`, Rust tests: PASS | -| Secrets and local source hygiene stay safe | High-confidence scan and static audit | `scan-secrets.py`, `audit-source.py`: PASS | -| Release bytes match their manifests | Deterministic manifest, checksum, SBOM, and attestation verification | `verify-release.py`: PASS | -| Browser mutations use the configured public origin | Shared origin classifier, proxy guard, smoke default, and E2E preflight | Matching-origin E2E PASS; mismatch independently observed as 403; preflight now fails early | -| Worker and request boundaries fail closed | Rust worker/client tests and API contract tests | Integrated `pnpm check`: PASS | -| Unknown module IDs cannot become successful pages | Closed module binding plus authenticated layout boundary | Five-browser HTTP 404 regression PASS | - -These checks are discoverable in the repository and are run by the relevant -Linux qualification/CI workflows; no hidden suppression was introduced. - -## Surprise-resistance assurance - -- Independent browser evidence caught the origin/configuration mismatch rather - than allowing a false application failure. -- The deployment-shaped standalone launcher was tested separately from - `next start`. -- The unavailable-core `/try` path was exercised and remained readable with - the pasted sequence intact. -- Release artifacts were re-verified against the final source state. -- The host-native PostgreSQL dump/restore path passed in an isolated temporary - cluster; the exact-image Compose dev database backup/restore probe also - passed. The non-biological production-shaped control-plane/edge Compose - drill also passed, including restart/recreation from local artifacts. -- The public-source archive was extracted into a fresh temporary directory and - passed source audit and release verification independently of the working - tree; its archive check reported 80 shebang members and zero missing - executable bits. - -## Assumption register - -| Assumption | Status and evidence | -| --- | --- | -| The public archive contains only intended source/evidence | VERIFIED: 1,055-entry archive; extracted audit and release verification passed; ignored caches/dependencies/build output absent | -| The exact pinned Docker image can be pulled by a release host | VERIFIED: OCI preflight resolved all Docker Hub endpoints and pulled all five exact digest-pinned external references; Compose database/bootstrap and backup/restore passed | -| The official npm advisory service is reachable for the final audit | VERIFIED: exact `pnpm audit --prod --audit-level=high` returned no known vulnerabilities after the Next.js/Sharp remediation | -| Strict scientific execution artifacts and approved reference data are present | VERIFIED: strict toolchain verifier PASS; all required artifacts/indexes and the approved scientific-Python freeze hash-match; `/ready/scientific` HTTP 200 | -| The current directory proves canonical Git lineage | VERIFIED: this checkout has real Git metadata and tracks `origin/codex/final-readiness-20260912`; current PR #39 is open against `main`. This does not imply that PR is merged or that `main` contains the candidate | -| Standalone output is the deployable Web runtime | VERIFIED: deployment-shaped standalone launch, smoke and browser checks passed | -| The final patch-level toolchain can be exercised on this host | VERIFIED for non-biological gates: exact Node, pnpm, uv and Rust are installed and exercised | - -## Two-pass fixed-point status - -The broad local verification pass completed before the final patch-level -toolchain pin update and passed except for the documented external blockers. -After the pin update, the non-biological exact source, Python, Rust, web, -security, and release gates passed. Two consecutive fresh public-archive -extractions then passed exact dependency installation, source qualification, -and the complete web check. This establishes a non-biological two-pass fixed -point. The full mission-level two-pass requirement remains **UNVERIFIED** -because the biological acceptance suite was not re-run by explicit user scope; -the non-biological production-shaped Compose drill is verified below in two -independent disposable passes. E-009, -E-010, and E-011 are resolved by the exact image/build and lifecycle evidence -recorded below. - -## Verification matrix - -| Gate | Result | -| --- | --- | -| `python3 scripts/audit-source.py` | PASS | -| `python3 scripts/scan-secrets.py` | PASS | -| `python3 scripts/qualify-source.py --no-write` | PASS | -| `python3 scripts/verify-release.py --root ...` | PASS: 1,051 manifest files; 914 SBOM components; 28 checksum entries | -| `python3 scripts/check-linux-bootstrap.py` | PASS | -| `python3 scripts/doctor-linux.py` | PASS; `.env` hardened to mode `0600` | -| Integrated `pnpm check` with project-local Rust and local PostgreSQL | PASS: web 619 passed/7 skipped; Python 1,167 passed; Rust workspace and doc-tests passed | -| Web production build | PASS | -| Clean public-archive Web check after offline frozen-lockfile install | PASS: typecheck, lint and formatting; 49 test files passed/1 skipped and 619 tests passed/7 skipped | -| Standalone production smoke | PASS | -| Browser E2E, matching public origin | 170 PASS / 30 intentional skips; five-browser matrix | -| API-backed module matrix | 21 modules × 5 browser projects: PASS | -| Strict engine execution suite | 10 PASS: five current engine workspaces through browser → Next → Rust → Python result rendering | -| Authenticated unknown-module HTTP contract | 5 browser projects: PASS after repository fix | -| Rust fmt/clippy/workspace tests | PASS on exact project-local Rust 1.94.1 | -| Python suite | 1,167 PASS | -| Host-native PostgreSQL dump/restore | PASS: isolated PostgreSQL 18 restore; 15 migrations, 16 public tables, 0 unvalidated constraints | -| Public-source archive build and extracted-archive verification | PASS: 1,055 entries; 80 shebang members with zero missing executable bits; fresh archive qualification, audit and release verification PASS on the exact project-local baseline | -| Supported Compose backup/restore drill | PASS in two independent disposable non-biological production-shaped passes: migrations, custom-format backup/restore (15 migrations, 16 tables), API/Web/Caddy readiness, edge GET, and restart/recreation all passed | -| Docker/OCI dependency preflight | PASS: all three Docker Hub endpoints resolved; exact pinned Caddy, Node, PostgreSQL, Python, and Rust references pulled and matched their requested digests | -| Docker PostgreSQL bootstrap | PASS: exact pinned image pulled and private production-shaped Compose database reached healthy | -| npm production advisory audit | PASS: exact `pnpm audit --prod --audit-level=high` reports no known vulnerabilities after the Next.js 16.3.4 update | -| Strict scientific readiness | PASS: strict verifier passed; required artifacts, approved-reference indexes and scientific-Python freeze hash-match; `/ready/scientific` HTTP 200 | -| Strict-runtime authenticated critical journey | PASS: 5 browser projects | -| Exact final dependency/toolchain requalification | PASS for non-biological gates: exact Node 24.20.0, pnpm 11.26.0, uv 0.12.10 and Rust 1.94.1 | -| Two-pass fresh archive verification | PASS for non-biological gates: two fresh exact archive extractions, frozen installs, source qualification, and web checks; each 619 passed/7 skipped | -| Deployable Web Docker image build and runtime smoke | PASS: exact pinned Web image built successfully; read-only non-root container served `/` with all capabilities dropped | -| Production API/runner image build | PASS: clean exact-pinned API and runner images built after the OCI preflight; migrator build also passed | - -## Remaining exceptions - -The non-biological production-shaped control-plane and edge Compose bootstrap -and drill passed on this host. Native biological acceptance is intentionally -deferred under the user's current scope; the scientific runner's strict -preflight remains fail-closed rather than being waived. That is a scope -boundary, not a registry or production control-plane blocker. - -The repository/live boundary is explicit: prior evidence covers static, Web, -API-contract, local database, browser, and release-artifact paths, but no live -deployment, production domain, production secrets, or production database was -touched. PR #39 is the review path; `main` remains unchanged pending explicit -merge authorization. The pinned MFEprimer findings remain a visible external -security exception that must be re-reviewed by `2026-10-09`. - -For E-002, the registry-access removal condition is met: the prior exact pinned -`postgres:18-alpine@sha256:d3e1620b...` image was pulled and started through -the dev database Compose path, and the exact-image restore probe passed. The -production-shaped control-plane/edge stack drill also passed. E-003 is resolved by the successful exact audit after -the Next.js 16.3.4/Sharp remediation. -E-006 is resolved by the strict verifier, hash-matched artifact evidence, -approved-reference indexes, HTTP readiness, and the five-browser critical -journey recorded above. E-009 is resolved by the exact pinned Web image build -and runtime smoke from the repository-supported Docker path. E-010 is resolved -by persistent host DNS repair, exact digest pulls, and clean API/runner/migrator -builds. E-011 is resolved by the IPv4-specific Caddy health probe. E-008 is -resolved for the non-biological scope by successful installation and -requalification with the pinned Node 24.20.0, pnpm 11.26.0, uv 0.12.10 and -Rust 1.94.1 baseline. - -## Production commands - -```text -python3 scripts/audit-source.py -python3 scripts/scan-secrets.py -python3 scripts/qualify-source.py --no-write -python3 scripts/verify-release.py --root /home/soheil/Desktop/PCRStudio -pnpm --filter web check -pnpm --filter web build -pnpm --filter web start:standalone -pnpm web:smoke -- --url=http://localhost:3400 -``` - -## Current closure statement - -**Engineering closure is not achieved.** PR #39 is the hosted qualification -path; its live checks show the exact current candidate state. The `main` -ruleset must require the aggregate gate after its workflow is integrated, and -merging still requires explicit authorization. Local release manifests are -current and verified. Live deployment remains a later, separate phase. Native -biological acceptance remains outside the current scope; the scientific runner -remains fail-closed rather than waived. +# PCRStudio current production qualification + +Date: 2026-09-13 +Current source release: **v1.0.6** + +This is the canonical current release-qualification contract. It deliberately +does not copy transient pull-request, CI-run, or server status into source +history. A release is qualified only when its exact-tag GitHub workflow passes, +the verified deployment bundle is published, and the host reports successful +bootstrap/readiness. The workflow run and host service status are the evidence +for those changing facts. + +## Release and deployment controls + +- Stable releases use exact SemVer tags. Production qualification starts from + that tag, not from an arbitrary branch push. +- The release remains a draft while source verification, pinned-image builds, + and restricted-service startup smoke checks run. Only a passing run uploads + the verified source/OCI bundle and publishes the release. +- The host puller verifies the release tag, declared asset sizes, archive + SHA-256 values, and portable OCI image-config digests before invoking the + supported bootstrap. Docker Hub is not needed to obtain the application + images during that deployment. +- The bootstrap applies database migrations, starts the supported control + plane and edge, and checks public readiness. Scientific readiness remains a + separate gate and is never inferred from website availability. + +## Runtime and storage limits + +The dedicated host policy accounts for the PCRStudio source/state tree and the +Docker/containerd stores under one **20 GiB managed budget**. The host retains +8 GiB for normal operation and 4 GiB as an emergency floor. At the 16 GiB +managed-use threshold, new scientific work is paused; at the 20 GiB budget or +emergency free-space floor, the application is stopped to protect the host. +This is an automated operational guard, not a kernel-enforced quota. + +Only PCRStudio-owned staging, bounded BuildKit cache, expired/over-limit +backups, and obsolete release artifacts are eligible for automated cleanup. +Database state, user data, other projects' Docker resources, and the active +plus immediately previous release are retained. See [`DOCKER-STORAGE.md`](../../docs/DOCKER-STORAGE.md) +and [`OPERATIONS.md`](../../docs/OPERATIONS.md) for the supported policy and +operator actions. + +## Current runtime defect addressed by this release + +The official pinned MAFFT launcher requires Bash, while the minimal API/runner +image previously supplied only BusyBox. The image now includes the required +interpreter from the pinned Debian snapshot in the scientific runtime only; +the database migrator remains minimal. A regression also ensures the +provenance record hashes the MAFFT archive itself rather than a later tool's +archive. The upstream MAFFT digest and all production base-image identities +remain unchanged. + +## Evidence boundaries + +Source-only checks do not establish successful container execution, database +migration, public TLS, or host deployment. Consult the exact release workflow +and the host's `pcrstudio-release-pull.service`/readiness evidence for those +results. Product/scientific capability maturity remains governed by the +separate current qualification records; this operations report makes no +scientific-validation claim. diff --git a/release/current/SOURCE-ATTESTATION.intoto.json b/release/current/SOURCE-ATTESTATION.intoto.json index 9c895b5..974179a 100644 --- a/release/current/SOURCE-ATTESTATION.intoto.json +++ b/release/current/SOURCE-ATTESTATION.intoto.json @@ -22,13 +22,13 @@ "subject": [ { "digest": { - "sha256": "2118e78ba5f278a62b456dc5034c0075a77f9a4626ba153be224962472fcf026" + "sha256": "40bbb89dd2ab2cf1583d183ffdad76616b6f7fa0d6296c402fea439fdc7f8a87" }, "name": "release/FILE-MANIFEST.json" }, { "digest": { - "sha256": "d52330df7190122f41b809a2a349ad209c7118861595b91d8bc642e0d68eb8ac" + "sha256": "69b3dc93ae8fcc181851c3d906bc6fb818631d21fcd509a464325ad6b2b3f6dd" }, "name": "release/PATCH-MANIFEST.json" }, diff --git a/release/current/SOURCE-QUALIFICATION.json b/release/current/SOURCE-QUALIFICATION.json index fb1d0d8..6a1b691 100644 --- a/release/current/SOURCE-QUALIFICATION.json +++ b/release/current/SOURCE-QUALIFICATION.json @@ -129,7 +129,7 @@ { "name": "focused-source-regression-tests", "status": "PASS", - "stdout": "........................................................................ [ 63%]\n......................................... [100%]\n113 passed in 0.85s" + "stdout": "........................................................................ [ 63%]\n......................................... [100%]\n113 passed in 0.80s" } ], "hygiene": { diff --git a/release/release.toml b/release/release.toml index 46688dc..17f5172 100644 --- a/release/release.toml +++ b/release/release.toml @@ -1,7 +1,7 @@ schema_version = "1.0.0" release_id = "CURRENT" -public_version = "1.0.5" -public_tag = "v1.0.5" +public_version = "1.0.6" +public_tag = "v1.0.6" versioning_scheme = "semver-2.0.0" release_class = "generation-1-unified-engine-linux-current" archive_prefix = "PCRStudio-CURRENT-PUBLIC-SOURCE" diff --git a/scripts/audit/method_fidelity.py b/scripts/audit/method_fidelity.py index 8426215..275ca8b 100644 --- a/scripts/audit/method_fidelity.py +++ b/scripts/audit/method_fidelity.py @@ -52,8 +52,8 @@ def audit_method_fidelity()->None: if not generated.exists(): error('method-fidelity: runtime projection missing') for rel in ('knowledge/reviews/METHOD-FIDELITY-AUDIT.json','knowledge/reviews/METHOD-FIDELITY-AUDIT.md'): if not (ROOT/rel).exists(): error(f'method-fidelity: generated review artifact missing: {rel}') - public_docs = _text('README.md') + _text('release/PUBLIC-SOURCE.md') + _text('release/RELEASE-NOTES.md') - for marker in ('## Method fidelity','Method-fidelity closure is part of the current source candidate.','A subsequent method-fidelity closure adds a canonical named-method registry'): + public_docs = _text('README.md') + _text('release/PUBLIC-SOURCE.md') + for marker in ('## Method fidelity','Method-fidelity closure is part of the current source candidate.'): if marker not in public_docs: error(f'method-fidelity: public release documentation missing marker: {marker}') universal=_text('tools/src/pcr_tools/universal.py') diff --git a/scripts/check-linux-bootstrap.py b/scripts/check-linux-bootstrap.py index 4db6b8d..a5df84f 100755 --- a/scripts/check-linux-bootstrap.py +++ b/scripts/check-linux-bootstrap.py @@ -776,6 +776,14 @@ def env_example_keys(path: Path) -> set[str]: assert "def remove_empty_path(path: Path) -> None" in pull_agent assert "if source != target:" in pull_agent production = (ROOT / ".github" / "workflows" / "production-deploy.yml").read_text(encoding="utf-8") + production_trigger = production.split("permissions:", 1)[0] + assert "workflow_dispatch:" in production_trigger and "release:" not in production_trigger + assert "github.event.release" not in production + release_input_validation = production.index("name: Validate exact stable release tag input") + release_checkout = production.index("name: Check out the exact release tag") + assert release_input_validation < release_checkout + assert '[[ "$SOURCE_REF" =~ ^v(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)$ ]]' in production + assert 'refs/tags/$RELEASE_REF^{commit}' in production assert production.count("uses: astral-sh/setup-uv@") == 1 assert production.count("prune-cache: true") == 1, "production qualification uv cache must prune before saving" release_verify = production.split("name: Verify release identity and deployment inputs", 1)[1].split( @@ -787,14 +795,20 @@ def env_example_keys(path: Path) -> set[str]: source_check = release_verify.index("scripts/qualify-source.py --no-write") release_check = release_verify.index("scripts/verify-release.py --root .") assert manifest_before_attestation < attestation < manifest_after_attestation < source_check < release_check + draft_prepare = production.index("name: Prepare an unpublished release draft") bundle_tool_checkout = production.index("name: Check out trusted deployment-bundle tooling") bundle_tool_identity = production.index("name: Record trusted deployment-bundle tooling revision") image_build = production.index("name: Build the qualified runtime image set") service_image_smoke = production.index("name: Smoke API and runner images as the service UID before publishing") - bundle_publish = production.index("name: Publish the verified HTTPS deployment bundle") - assert image_build < service_image_smoke < bundle_tool_checkout < bundle_tool_identity < bundle_publish, ( + bundle_publish = production.index("name: Upload the verified HTTPS deployment bundle to the draft") + release_publish = production.index("name: Publish only after every release gate passes") + verify_step = production.index("name: Verify release identity and deployment inputs") + assert verify_step < draft_prepare < image_build + assert image_build < service_image_smoke < bundle_tool_checkout < bundle_tool_identity < bundle_publish < release_publish, ( "trusted bundle tooling must stay outside release qualification and image build contexts" ) + assert 'gh release create "$RELEASE_REF" --draft --verify-tag' in production + assert 'gh release edit "$RELEASE_REF" --draft=false --latest --verify-tag' in production service_smoke_block = production.split( "name: Smoke API and runner images as the service UID before publishing", 1 )[1].split("\n - name:", 1)[0] From 5ff0d24b05b988f3ce7b6b7ee71c6323feb9f555 Mon Sep 17 00:00:00 2001 From: Soheilbz Date: Sun, 13 Sep 2026 09:47:03 -0400 Subject: [PATCH 3/3] fix: refresh host storage guard on deployments --- CHANGELOG.md | 1 + docs/OPERATIONS.md | 5 +++- release/FILE-MANIFEST.json | 28 +++++++++---------- release/PATCH-MANIFEST.json | 26 ++++++++--------- release/RELEASE-NOTES.md | 2 ++ release/SHA256SUMS.txt | 10 +++---- release/current/ENGINEERING-CLOSURE-REPORT.md | 4 +++ .../current/SOURCE-ATTESTATION.intoto.json | 4 +-- release/current/SOURCE-QUALIFICATION.json | 2 +- scripts/bootstrap-linux.py | 10 ++++++- scripts/check-linux-bootstrap.py | 12 ++++++++ 11 files changed, 67 insertions(+), 37 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9ae9a75..074eb9f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ qualification evidence is maintained under `release/current/`. - Fix production startup in the restricted runtime without changing pinned product images or user data. - Publish production releases only after image startup qualification passes, so an incomplete build cannot become the public Latest release. +- Refresh the host storage guard before deployment image operations, so old reserve policies cannot stop services on the dedicated VM. ## v1.0.4 — 2026-09-13 diff --git a/docs/OPERATIONS.md b/docs/OPERATIONS.md index f03410f..a6e5f0b 100644 --- a/docs/OPERATIONS.md +++ b/docs/OPERATIONS.md @@ -189,7 +189,10 @@ it is an operational guard, not a kernel-enforced filesystem quota. It starts one minute after boot and rechecks every five minutes. At the 16 GiB budget threshold it pauses scientific work; at 20 GiB managed use or 4 GiB free host space it stops the application to protect the host. Cache and backup retention -rules are documented in `docs/DOCKER-STORAGE.md`. Inspect the guard with: +rules are documented in `docs/DOCKER-STORAGE.md`. Every normal bootstrap +reinstalls the guard from the current release and restarts its timer before +image pull/build operations, independently of the optional backup/restore +timers. Inspect the guard with: ```bash systemctl list-timers pcrstudio-storage-guard.timer diff --git a/release/FILE-MANIFEST.json b/release/FILE-MANIFEST.json index 52c0295..fc7b2bd 100644 --- a/release/FILE-MANIFEST.json +++ b/release/FILE-MANIFEST.json @@ -53,9 +53,9 @@ "sha256": "6e4fd39e6708b21033c89ce2d34b17013e098c95de8ea9f3f042043cab01f513" }, { - "bytes": 2864, + "bytes": 2999, "path": "CHANGELOG.md", - "sha256": "45adbffc726fb73264d744488041bb12e3c72d61e98e79d8d93c182acbd14f68" + "sha256": "0b948cd0b5488bbd211343bfe10518a42768b4786b9a38ef527ea9042dc2f5b9" }, { "bytes": 633, @@ -1113,9 +1113,9 @@ "sha256": "fe4741fa6ea8bde3555d9d4ed102c1c91c0106addc44caa5e7f8b01f5d4c69c5" }, { - "bytes": 14548, + "bytes": 14729, "path": "docs/OPERATIONS.md", - "sha256": "f92c6f3972e9fdb5f20eafc5ec46ea08b03eec5b7e57ed795389618693a22f66" + "sha256": "62b1a1f2d315b58e2d32d22f47685ca3c23462eced78f379445204d220cf5954" }, { "bytes": 2598, @@ -1875,7 +1875,7 @@ { "bytes": 217257, "path": "release/PATCH-MANIFEST.json", - "sha256": "69b3dc93ae8fcc181851c3d906bc6fb818631d21fcd509a464325ad6b2b3f6dd" + "sha256": "19a5ab99b6c0e6e08b1aa8f22ef70409e2460e768ffb19a99567520f64d3ce49" }, { "bytes": 2048, @@ -1883,9 +1883,9 @@ "sha256": "914cd8c95c0a0438772cc15184a41ab37761e1b32d027f070b3e102bea4e3563" }, { - "bytes": 269, + "bytes": 418, "path": "release/RELEASE-NOTES.md", - "sha256": "4b4fbefd32380873307249bcce67d4a2300755b8521faaba151a9c9d5f68108b" + "sha256": "57c07bd12d303dddf4690be8269055278a4efe0c10936058dbceb07bd7de3ceb" }, { "bytes": 98937, @@ -1953,9 +1953,9 @@ "sha256": "141eba89249115700cd20a5083b383466dc93e424f9aa1e410e852068e87e2c5" }, { - "bytes": 3233, + "bytes": 3462, "path": "release/current/ENGINEERING-CLOSURE-REPORT.md", - "sha256": "4894b93d737b16c1d9b4cb11a01c57311ae0bca1fe91f51a2593007888201884" + "sha256": "f2c109824485a71baa8ce7e1a1e62f4dea2fd23f9810e06bcfef0234e2a384cd" }, { "bytes": 507, @@ -1975,7 +1975,7 @@ { "bytes": 5355, "path": "release/current/SOURCE-QUALIFICATION.json", - "sha256": "2d93294bb274cc6ac939b17168e5ef4308ced5a84d98f6f5a48ed0b1e8b1f4f4" + "sha256": "fe420222ba70590f65d8de1754d1a2b16ec24c324858d017e3ddbec7470ac891" }, { "bytes": 974, @@ -2098,9 +2098,9 @@ "sha256": "a65fec5d00dacfb1d269dc2d8b8d797f2cb0c938408763e2a67620a9323d3451" }, { - "bytes": 84106, + "bytes": 84671, "path": "scripts/bootstrap-linux.py", - "sha256": "699fe85b2dd438bd4239651a564919a1eed19e23604e1862fa80d2a4c1023065" + "sha256": "1affc59b4ea53e212ec9b24657f700eb53a8737523764b89d7297d96d08dc93d" }, { "bytes": 17770, @@ -2153,9 +2153,9 @@ "sha256": "7aae660e33bda20a1e43e187e704a57df1f31b69ea3517f25d5d96ba654f0cb9" }, { - "bytes": 58315, + "bytes": 59147, "path": "scripts/check-linux-bootstrap.py", - "sha256": "8c3f29467334441e2f93d994f6699ecc3a01e01ecc3d293a1221d61e3e577ce8" + "sha256": "8af7ce94d0663012a9943a80db38fe8209dd0062bd2c4837482714d9a68fa10b" }, { "bytes": 4486, diff --git a/release/PATCH-MANIFEST.json b/release/PATCH-MANIFEST.json index cc7af5c..9e1693f 100644 --- a/release/PATCH-MANIFEST.json +++ b/release/PATCH-MANIFEST.json @@ -16,9 +16,9 @@ "sha256": "275cb329b44ee7ca2166a0a69f22bd11b34eaeefdd2c013d5cee9fe08697f372" }, { - "bytes": 2864, + "bytes": 2999, "path": "CHANGELOG.md", - "sha256": "45adbffc726fb73264d744488041bb12e3c72d61e98e79d8d93c182acbd14f68" + "sha256": "0b948cd0b5488bbd211343bfe10518a42768b4786b9a38ef527ea9042dc2f5b9" }, { "bytes": 633, @@ -521,9 +521,9 @@ "sha256": "fe4741fa6ea8bde3555d9d4ed102c1c91c0106addc44caa5e7f8b01f5d4c69c5" }, { - "bytes": 14548, + "bytes": 14729, "path": "docs/OPERATIONS.md", - "sha256": "f92c6f3972e9fdb5f20eafc5ec46ea08b03eec5b7e57ed795389618693a22f66" + "sha256": "62b1a1f2d315b58e2d32d22f47685ca3c23462eced78f379445204d220cf5954" }, { "bytes": 2598, @@ -776,9 +776,9 @@ "sha256": "141eba89249115700cd20a5083b383466dc93e424f9aa1e410e852068e87e2c5" }, { - "bytes": 3233, + "bytes": 3462, "path": "release/current/ENGINEERING-CLOSURE-REPORT.md", - "sha256": "4894b93d737b16c1d9b4cb11a01c57311ae0bca1fe91f51a2593007888201884" + "sha256": "f2c109824485a71baa8ce7e1a1e62f4dea2fd23f9810e06bcfef0234e2a384cd" }, { "bytes": 1792, @@ -836,9 +836,9 @@ "sha256": "dc07bee74af4fe5075d1c3753a7a8758bc847efeeafe94fc49986b5e444d6eb8" }, { - "bytes": 84106, + "bytes": 84671, "path": "scripts/bootstrap-linux.py", - "sha256": "699fe85b2dd438bd4239651a564919a1eed19e23604e1862fa80d2a4c1023065" + "sha256": "1affc59b4ea53e212ec9b24657f700eb53a8737523764b89d7297d96d08dc93d" }, { "bytes": 17770, @@ -856,9 +856,9 @@ "sha256": "a7504c6eaf55c3224306d0b6ae7509567f9d5c9703c9236aee73d97fb9f51a34" }, { - "bytes": 58315, + "bytes": 59147, "path": "scripts/check-linux-bootstrap.py", - "sha256": "8c3f29467334441e2f93d994f6699ecc3a01e01ecc3d293a1221d61e3e577ce8" + "sha256": "8af7ce94d0663012a9943a80db38fe8209dd0062bd2c4837482714d9a68fa10b" }, { "bytes": 4486, @@ -2856,8 +2856,8 @@ "path": "release/PUBLIC-SOURCE.md" }, { - "after_bytes": 269, - "after_sha256": "4b4fbefd32380873307249bcce67d4a2300755b8521faaba151a9c9d5f68108b", + "after_bytes": 418, + "after_sha256": "57c07bd12d303dddf4690be8269055278a4efe0c10936058dbceb07bd7de3ceb", "before_bytes": 1111, "before_sha256": "e34d1974f2c960513499d801308192e08c6c483f6610abae0b705f69f68f5c31", "path": "release/RELEASE-NOTES.md" @@ -2885,7 +2885,7 @@ }, { "after_bytes": 5355, - "after_sha256": "2d93294bb274cc6ac939b17168e5ef4308ced5a84d98f6f5a48ed0b1e8b1f4f4", + "after_sha256": "fe420222ba70590f65d8de1754d1a2b16ec24c324858d017e3ddbec7470ac891", "before_bytes": 3630, "before_sha256": "60cae79862da151902beb2beb68fa4f4213bd769b2c4d5c93d5a4dd39a1e9ae3", "path": "release/current/SOURCE-QUALIFICATION.json" diff --git a/release/RELEASE-NOTES.md b/release/RELEASE-NOTES.md index e6faeb2..781416c 100644 --- a/release/RELEASE-NOTES.md +++ b/release/RELEASE-NOTES.md @@ -4,4 +4,6 @@ Fixes a production startup issue in the restricted server runtime. A release is now published only after its production images pass final startup checks. +Every deployment also refreshes the 20 GiB host storage guard before image +operations, preventing stale reserve settings from disrupting the server. Existing user data and pinned dependencies remain unchanged. diff --git a/release/SHA256SUMS.txt b/release/SHA256SUMS.txt index e3f91cf..327bf37 100644 --- a/release/SHA256SUMS.txt +++ b/release/SHA256SUMS.txt @@ -5,8 +5,8 @@ bda5e46776f16c6db86a9459ad90adad60f4c602fdbdcffb17722e2033ff1754 docs/openapi.g 653656a0031d529cb45a43b9b760e5bc32037d158110512b8acf26b8b1d92b47 knowledge/runtime/linux-acceptance-matrix.json 940c4109f4cae406e1ef4ca0c7407a3c45149f94f194fd8b6006b99bf98c0103 knowledge/runtime/module-contracts.generated.json 1d3d7f092812bec508d6923a0993f2283b288d306ec0c87c96a2d019b8367c83 knowledge/runtime/tool-contracts.generated.json -40bbb89dd2ab2cf1583d183ffdad76616b6f7fa0d6296c402fea439fdc7f8a87 release/FILE-MANIFEST.json -69b3dc93ae8fcc181851c3d906bc6fb818631d21fcd509a464325ad6b2b3f6dd release/PATCH-MANIFEST.json +88964cada94d1d14d4447b3c9093f5ac7f98a25e44ddffe06a9eec96fdfdd767 release/FILE-MANIFEST.json +19a5ab99b6c0e6e08b1aa8f22ef70409e2460e768ffb19a99567520f64d3ce49 release/PATCH-MANIFEST.json 6c5ca96b26e38f455332e5ef6084966387f910c3d0b201511aa95d00300bb2fb release/RUNTIME-CONTRACT-MANIFEST.json 9bce416ccb675fafed6ea42dc8ebd2c4f31646bbf3e67bc756402db2683b6b52 release/current/CURRENT-ENGINE-SYSTEM.md 075388950b0f86c8775d15d3e406fb7e9ca59312748a371b5be2e17dc2625f26 release/current/CURRENT-FOUNDATION-CLOSURE.md @@ -16,13 +16,13 @@ e2a0387696df4b1a1145691b60bb217412c435e5d397505687d04b96314cd51a release/curren 6b72f22001a9108fa83ba8e9e5c14a66e119518b68f939c09c1381bcb468d4b5 release/current/CURRENT-MULTIPLEX-CLOSURE.md d169a26e77a7344cacd0e2459c76f7a8d2d31d5854b98d9086fe487b707cc326 release/current/CURRENT-STATIC-CONSISTENCY-AUDIT.json 141eba89249115700cd20a5083b383466dc93e424f9aa1e410e852068e87e2c5 release/current/CURRENT-STATIC-CONSISTENCY-AUDIT.md -4894b93d737b16c1d9b4cb11a01c57311ae0bca1fe91f51a2593007888201884 release/current/ENGINEERING-CLOSURE-REPORT.md +f2c109824485a71baa8ce7e1a1e62f4dea2fd23f9810e06bcfef0234e2a384cd release/current/ENGINEERING-CLOSURE-REPORT.md 8d5f3dbb4841781a4b4aa7f59a930f4715561ccc460ca79023a87bff89a00ea8 release/current/PERFORMANCE-STATUS.md 4ccbbcabe1aeb60f6c8d2b4ec9f248ca00489a4ee2074a0b6264403d94fdf2ee release/current/README.md ad3305f910d6f8148a805dd2b99c8b88cc264df8a37190087957b9063665f9d3 release/current/SBOM.cdx.json 5ab7d453742c3338f4d2ed816f1410cc4e45920b58b66653c73f8d0c7e564af5 release/current/SECURITY-EXCEPTIONS.md -f79a4a9527ae1be46bfd5c8961a653c529675ae4fb4014103a6e5a00887933b4 release/current/SOURCE-ATTESTATION.intoto.json -2d93294bb274cc6ac939b17168e5ef4308ced5a84d98f6f5a48ed0b1e8b1f4f4 release/current/SOURCE-QUALIFICATION.json +f3e602f3172f11df4ab09c9dd2dec25600c3d1cd05915652c0842ed3af4197b3 release/current/SOURCE-ATTESTATION.intoto.json +fe420222ba70590f65d8de1754d1a2b16ec24c324858d017e3ddbec7470ac891 release/current/SOURCE-QUALIFICATION.json 90b7855e4855181770453b915836c9286ba0eabecc21ba1330581a0ed4e67122 release/current/SOURCE-QUALIFICATION.md ceb912d6a98435fda489bb961cf55f84e6fb33a9bc85cff015bfe4f042930214 release/current/SUPPLY-CHAIN.md 0ced565d1a1bb585517f918f91c5c2ce47a28921d4cd40a537a915bf5f4bdb96 scripts/run-linux-qualification.py diff --git a/release/current/ENGINEERING-CLOSURE-REPORT.md b/release/current/ENGINEERING-CLOSURE-REPORT.md index 41e8d44..703145c 100644 --- a/release/current/ENGINEERING-CLOSURE-REPORT.md +++ b/release/current/ENGINEERING-CLOSURE-REPORT.md @@ -41,6 +41,10 @@ plus immediately previous release are retained. See [`DOCKER-STORAGE.md`](../../ and [`OPERATIONS.md`](../../docs/OPERATIONS.md) for the supported policy and operator actions. +Every normal server bootstrap installs the storage guard from the exact current +release and restarts its timer before image operations. This prevents stale +host-side reserve settings from overriding the versioned 20 GiB policy. + ## Current runtime defect addressed by this release The official pinned MAFFT launcher requires Bash, while the minimal API/runner diff --git a/release/current/SOURCE-ATTESTATION.intoto.json b/release/current/SOURCE-ATTESTATION.intoto.json index 974179a..054c134 100644 --- a/release/current/SOURCE-ATTESTATION.intoto.json +++ b/release/current/SOURCE-ATTESTATION.intoto.json @@ -22,13 +22,13 @@ "subject": [ { "digest": { - "sha256": "40bbb89dd2ab2cf1583d183ffdad76616b6f7fa0d6296c402fea439fdc7f8a87" + "sha256": "88964cada94d1d14d4447b3c9093f5ac7f98a25e44ddffe06a9eec96fdfdd767" }, "name": "release/FILE-MANIFEST.json" }, { "digest": { - "sha256": "69b3dc93ae8fcc181851c3d906bc6fb818631d21fcd509a464325ad6b2b3f6dd" + "sha256": "19a5ab99b6c0e6e08b1aa8f22ef70409e2460e768ffb19a99567520f64d3ce49" }, "name": "release/PATCH-MANIFEST.json" }, diff --git a/release/current/SOURCE-QUALIFICATION.json b/release/current/SOURCE-QUALIFICATION.json index 6a1b691..63bd9b9 100644 --- a/release/current/SOURCE-QUALIFICATION.json +++ b/release/current/SOURCE-QUALIFICATION.json @@ -129,7 +129,7 @@ { "name": "focused-source-regression-tests", "status": "PASS", - "stdout": "........................................................................ [ 63%]\n......................................... [100%]\n113 passed in 0.80s" + "stdout": "........................................................................ [ 63%]\n......................................... [100%]\n113 passed in 0.83s" } ], "hygiene": { diff --git a/scripts/bootstrap-linux.py b/scripts/bootstrap-linux.py index 01c96ed..0a0201a 100755 --- a/scripts/bootstrap-linux.py +++ b/scripts/bootstrap-linux.py @@ -1375,6 +1375,9 @@ def install_storage_guard_automation( installed.append(name) run([*sudo, systemctl, "daemon-reload"]) run([*sudo, systemctl, "enable", "--now", "pcrstudio-storage-guard.timer"]) + # daemon-reload does not change the schedule of an already-active timer. + # Restart it so the current release's reserve policy takes effect now. + run([*sudo, systemctl, "restart", "pcrstudio-storage-guard.timer"]) run([*sudo, systemctl, "list-timers", "--no-pager", "pcrstudio-storage-guard.timer"], check=False) return installed @@ -1536,6 +1539,12 @@ def main() -> int: scientific_db_dir=dbdir, ) write_env(DEFAULT_ENV, values) + # The host storage guard protects even the long image-pull/build phase. + # Do not rely on --prepare-host-only having been run or on an old timer + # remaining compatible with this release's storage policy. + installed_automation = install_storage_guard_automation( + storage_budget, storage_headroom, storage_min_free, storage_critical_free, backup_total_max + ) # Resolve every external build/runtime dependency before the expensive # BuildKit graph. The helper uses Docker's configured credential store, but @@ -1593,7 +1602,6 @@ def main() -> int: ready_payload = None runner_payload = None - installed_automation: list[str] = [] pre_deploy_backup: Path | None = None if not args.skip_up: pre_deploy_backup = quiesce_and_backup_if_running(docker, args.private, build_identity) diff --git a/scripts/check-linux-bootstrap.py b/scripts/check-linux-bootstrap.py index a5df84f..d0aab6f 100755 --- a/scripts/check-linux-bootstrap.py +++ b/scripts/check-linux-bootstrap.py @@ -1042,6 +1042,18 @@ def env_example_keys(path: Path) -> set[str]: assert "build-essential xz-doc" not in api_dockerfile assert "apt-get install --no-install-recommends -y bash ca-certificates libgomp1" in api_dockerfile assert "COPY --from=runtime-assets /bin/bash /bin/bash" in api_dockerfile + bootstrap_source = (ROOT / "scripts" / "bootstrap-linux.py").read_text(encoding="utf-8") + regular_deploy_start = bootstrap_source.index("# The host storage guard protects even the long image-pull/build phase.") + storage_guard_refresh = bootstrap_source.index( + "installed_automation = install_storage_guard_automation", regular_deploy_start + ) + external_image_resolution = bootstrap_source.index("if args.offline_pinned_images:", regular_deploy_start) + assert storage_guard_refresh < external_image_resolution, ( + "every ordinary deployment must refresh the host storage guard before expensive image operations" + ) + assert 'systemctl, "restart", "pcrstudio-storage-guard.timer"' in bootstrap_source, ( + "an already-active timer must reload the current release policy immediately" + ) release_workflow = (ROOT / ".github" / "workflows" / "production-deploy.yml").read_text(encoding="utf-8") assert "Smoke API and runner images as the service UID before publishing" in release_workflow assert 'docker run --rm --network none --user 10001:10001' in release_workflow