From 7eb6d52acf708e891169fa9ba25a0dd6850ec5a5 Mon Sep 17 00:00:00 2001 From: KeyffMS <124252104+KeyffMS@users.noreply.github.com> Date: Wed, 12 Aug 2026 16:56:20 +0200 Subject: [PATCH 01/15] Add final issues 1-9 closure automation --- automation/close_issues_1_9.sh | 263 +++++++++++++++++++++++++++++++++ 1 file changed, 263 insertions(+) create mode 100644 automation/close_issues_1_9.sh diff --git a/automation/close_issues_1_9.sh b/automation/close_issues_1_9.sh new file mode 100644 index 0000000..361a1b2 --- /dev/null +++ b/automation/close_issues_1_9.sh @@ -0,0 +1,263 @@ +#!/usr/bin/env bash +set -euo pipefail + +readonly MAIN_SHA="82748172d516cbd53161df58f37d4347fa817dbf" +readonly DELIVERY_SHA="0d44845630c22efc9675b1fd1b32abceaf75bfe3" +readonly ISSUE2_SHA="678def2b42e13c1099c7187c03637cb0e584e4ab" +readonly CANDIDATE_BRANCH="agent/issues-1-9-final-candidate" + +export PATH="${CARGO_HOME:-$HOME/.cargo}/bin:$PATH" +git config --global --add safe.directory "$GITHUB_WORKSPACE" +git config user.name "VFD Lantern contributors" +git config user.email "actions@users.noreply.github.com" + +git fetch --force origin \ + main:refs/remotes/origin/main \ + agent/issues-1-9:refs/remotes/origin/delivery \ + "$CANDIDATE_BRANCH":refs/remotes/origin/final-candidate + +test "$(git rev-parse refs/remotes/origin/main)" = "$MAIN_SHA" +test "$(git rev-parse refs/remotes/origin/delivery)" = "$DELIVERY_SHA" +git checkout --detach "$DELIVERY_SHA" + +cat > scripts/install-pinned-tools.sh <<'EOF' +#!/bin/sh +set -eu + +version_for() { + awk -F '[[:space:]]*=[[:space:]]*' -v key="$1" ' + $1 == key { + gsub(/"/, "", $2) + print $2 + found = 1 + exit + } + END { + if (!found) exit 1 + } + ' tools.lock.toml +} + +install_tool() { + crate="$1" + version="$(version_for "$crate")" + cargo install --locked --version "$version" "$crate" +} + +install_tool cargo-machete +install_tool cargo-deny +install_tool cargo-audit +install_tool cargo-vet +EOF +chmod +x scripts/install-pinned-tools.sh + +cat > scripts/check-supply-chain.sh <<'EOF' +#!/bin/sh +set -eu + +sh scripts/check-supply-chain-baseline.sh +cargo machete +cargo deny check +cargo audit +cargo vet check +EOF +chmod +x scripts/check-supply-chain.sh + +cat > .github/workflows/ci.yml <<'EOF' +name: CI + +on: + push: + branches: [main, "agent/**"] + pull_request: + +permissions: + contents: read + +concurrency: + group: ci-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + rust: + name: Debian 13 / Rust 1.97.1 / ${{ matrix.arch }} + strategy: + fail-fast: false + matrix: + include: + - arch: amd64 + runner: ubuntu-24.04 + - arch: arm64 + runner: ubuntu-24.04-arm + runs-on: ${{ matrix.runner }} + container: debian:trixie-slim@sha256:020c0d20b9880058cbe785a9db107156c3c75c2ac944a6aa7ab59f2add76a7bd + + steps: + - name: Install system dependencies + run: | + apt-get update + apt-get install --yes --no-install-recommends \ + build-essential \ + ca-certificates \ + git \ + libudev-dev \ + pkg-config \ + rustup + + - name: Check out repository + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + + - name: Install pinned Rust toolchain + run: | + rustup toolchain install 1.97.1 \ + --profile minimal \ + --component rustfmt \ + --component clippy \ + --component llvm-tools-preview + rustup default 1.97.1 + rustc --version + cargo --version + + - name: Validate lockfile and metadata + run: cargo metadata --locked --format-version 1 --no-deps >/dev/null + + - name: Build workspace + run: cargo build --workspace --all-features --locked + + - name: Check formatting + run: cargo fmt --all -- --check + + - name: Run Clippy + run: cargo clippy --workspace --all-targets --all-features --locked -- -D warnings + + - name: Run tests + run: cargo test --workspace --all-features --locked + + - name: Build documentation + run: cargo doc --workspace --all-features --no-deps --locked + + - name: Check architecture boundaries + run: sh scripts/check-architecture.sh + + - name: Check supply-chain baseline + run: sh scripts/check-supply-chain-baseline.sh + + supply-chain: + name: Pinned supply-chain tools + runs-on: ubuntu-24.04 + container: debian:trixie-slim@sha256:020c0d20b9880058cbe785a9db107156c3c75c2ac944a6aa7ab59f2add76a7bd + + steps: + - name: Install system dependencies + run: | + apt-get update + apt-get install --yes --no-install-recommends \ + build-essential \ + ca-certificates \ + git \ + libudev-dev \ + pkg-config \ + rustup + + - name: Check out repository + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + + - name: Install pinned Rust toolchain + run: | + rustup toolchain install 1.97.1 --profile minimal + rustup default 1.97.1 + + - name: Install and run pinned supply-chain tools + run: | + export PATH="${CARGO_HOME:-$HOME/.cargo}/bin:$PATH" + sh scripts/install-pinned-tools.sh + sh scripts/check-supply-chain.sh +EOF + +cat > docs/development/toolchain.md <<'EOF' +# Pinned development toolchain + +VFD Lantern targets Debian 13 (Trixie) on amd64 and arm64. Install `rustup` from +APT, then let `rust-toolchain.toml` select Rust 1.97.1. Do not use `curl | sh`. + +```sh +sudo apt-get update +sudo apt-get install --yes build-essential ca-certificates git libudev-dev pkg-config rustup +rustup toolchain install 1.97.1 --profile minimal \ + --component rustfmt --component clippy --component llvm-tools-preview +cargo build --workspace --all-features --locked +cargo test --workspace --all-features --locked +``` + +Direct crate versions are centralized in `[workspace.dependencies]`. Binary tool +versions are centralized in `tools.lock.toml`. Updates require a dedicated change +with a refreshed lockfile and the full CI suite. + +Install the exact supply-chain tool versions from the single tool manifest and run +the complete gate as follows: + +```sh +export PATH="${CARGO_HOME:-$HOME/.cargo}/bin:$PATH" +sh scripts/install-pinned-tools.sh +sh scripts/check-supply-chain.sh +``` + +The gate executes `cargo machete`, `cargo deny check`, `cargo audit`, and +`cargo vet check`. The initial `supply-chain/config.toml` exemptions freeze the +already accepted dependency graph; dependency updates must not silently add new +exemptions and should reduce them through recorded audits over time. The command is +`cargo vet check`, not the non-existent `cargo vet verify`. +EOF + +sh scripts/install-pinned-tools.sh +if [ ! -d supply-chain ]; then + cargo vet init +fi +sh scripts/check-supply-chain.sh + +cargo metadata --locked --format-version 1 >/dev/null +cargo build --workspace --all-features --locked +cargo fmt --all -- --check +cargo clippy --workspace --all-targets --all-features --locked -- -D warnings +cargo test --workspace --all-features --locked +cargo doc --workspace --all-features --no-deps --locked +sh scripts/check-architecture.sh +git diff --check "$MAIN_SHA" + +git add .github/workflows/ci.yml \ + docs/development/toolchain.md \ + scripts/install-pinned-tools.sh \ + scripts/check-supply-chain.sh \ + Cargo.lock \ + supply-chain + +git commit --fixup "$ISSUE2_SHA" +GIT_SEQUENCE_EDITOR=: git rebase -i --autosquash --committer-date-is-author-date "$MAIN_SHA" + +# Re-run every gate against the exact rewritten history before publishing it. +cargo metadata --locked --format-version 1 >/dev/null +cargo build --workspace --all-features --locked +cargo fmt --all -- --check +cargo clippy --workspace --all-targets --all-features --locked -- -D warnings +cargo test --workspace --all-features --locked +cargo doc --workspace --all-features --no-deps --locked +sh scripts/check-architecture.sh +sh scripts/check-supply-chain.sh +git diff --check "$MAIN_SHA" +test -z "$(git status --porcelain)" + +final_sha="$(git rev-parse HEAD)" +final_tree="$(git rev-parse HEAD^{tree})" +test "$(git rev-list --count "$MAIN_SHA"..HEAD)" -eq 9 +for number in 1 2 3 4 5 6 7 8 9; do + test "$(git log --format='%s' "$MAIN_SHA"..HEAD | grep -Ec "\\(#${number}\\)$")" -eq 1 +done +test -z "$(git log --format='%s' "$MAIN_SHA"..HEAD | grep '^fixup!' || true)" +test -z "$(git ls-files 'automation/**' '.github/workflows/close-issues-1-9.yml')" + +git push \ + --force-with-lease="refs/heads/$CANDIDATE_BRANCH:$DELIVERY_SHA" \ + origin "HEAD:refs/heads/$CANDIDATE_BRANCH" + +printf 'final_sha=%s\n' "$final_sha" >> "$GITHUB_OUTPUT" +printf 'final_tree=%s\n' "$final_tree" >> "$GITHUB_OUTPUT" From ec0fef13a4204830a2f6fe5811321887790c1504 Mon Sep 17 00:00:00 2001 From: KeyffMS <124252104+KeyffMS@users.noreply.github.com> Date: Wed, 12 Aug 2026 16:56:47 +0200 Subject: [PATCH 02/15] Add final issues 1-9 closure workflow --- .github/workflows/close-issues-1-9.yml | 127 +++++++++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 .github/workflows/close-issues-1-9.yml diff --git a/.github/workflows/close-issues-1-9.yml b/.github/workflows/close-issues-1-9.yml new file mode 100644 index 0000000..97f8774 --- /dev/null +++ b/.github/workflows/close-issues-1-9.yml @@ -0,0 +1,127 @@ +name: Close roadmap issues 1-9 + +on: + pull_request: + branches: ["agent/issues-1-9"] + paths: + - "automation/close_issues_1_9.sh" + - ".github/workflows/close-issues-1-9.yml" + +permissions: + contents: write + +concurrency: + group: close-issues-1-9 + cancel-in-progress: true + +jobs: + prepare: + name: Prepare and pre-validate rewritten history + runs-on: ubuntu-24.04 + container: debian:trixie-slim@sha256:020c0d20b9880058cbe785a9db107156c3c75c2ac944a6aa7ab59f2add76a7bd + outputs: + final_sha: ${{ steps.candidate.outputs.final_sha }} + final_tree: ${{ steps.candidate.outputs.final_tree }} + + steps: + - name: Install system dependencies + run: | + apt-get update + apt-get install --yes --no-install-recommends \ + build-essential \ + ca-certificates \ + git \ + libudev-dev \ + pkg-config \ + rustup + + - name: Check out automation branch + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + ref: ${{ github.event.pull_request.head.sha }} + fetch-depth: 0 + + - name: Install pinned Rust toolchain + run: | + rustup toolchain install 1.97.1 \ + --profile minimal \ + --component rustfmt \ + --component clippy \ + --component llvm-tools-preview + rustup default 1.97.1 + + - name: Build, autosquash, validate, and publish candidate branch + id: candidate + shell: bash + run: bash automation/close_issues_1_9.sh + + validate: + name: Validate exact candidate / ${{ matrix.arch }} + needs: prepare + strategy: + fail-fast: false + matrix: + include: + - arch: amd64 + runner: ubuntu-24.04 + - arch: arm64 + runner: ubuntu-24.04-arm + runs-on: ${{ matrix.runner }} + container: debian:trixie-slim@sha256:020c0d20b9880058cbe785a9db107156c3c75c2ac944a6aa7ab59f2add76a7bd + + steps: + - name: Install system dependencies + run: | + apt-get update + apt-get install --yes --no-install-recommends \ + build-essential \ + ca-certificates \ + git \ + libudev-dev \ + pkg-config \ + rustup + + - name: Check out exact candidate + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + ref: ${{ needs.prepare.outputs.final_sha }} + fetch-depth: 0 + + - name: Install pinned Rust toolchain + run: | + rustup toolchain install 1.97.1 \ + --profile minimal \ + --component rustfmt \ + --component clippy \ + --component llvm-tools-preview + rustup default 1.97.1 + + - name: Verify candidate identity and history + run: | + test "$(git rev-parse HEAD)" = "${{ needs.prepare.outputs.final_sha }}" + test "$(git rev-parse HEAD^{tree})" = "${{ needs.prepare.outputs.final_tree }}" + git fetch origin main:refs/remotes/origin/main + test "$(git rev-list --count origin/main..HEAD)" -eq 9 + for number in 1 2 3 4 5 6 7 8 9; do + test "$(git log --format='%s' origin/main..HEAD | grep -Ec "\\(#${number}\\)$")" -eq 1 + done + test -z "$(git log --format='%s' origin/main..HEAD | grep '^fixup!' || true)" + + - name: Run core quality gate + run: | + cargo metadata --locked --format-version 1 >/dev/null + cargo build --workspace --all-features --locked + cargo fmt --all -- --check + cargo clippy --workspace --all-targets --all-features --locked -- -D warnings + cargo test --workspace --all-features --locked + cargo doc --workspace --all-features --no-deps --locked + sh scripts/check-architecture.sh + sh scripts/check-supply-chain-baseline.sh + git diff --check origin/main...HEAD + + - name: Run full pinned supply-chain gate + if: matrix.arch == 'amd64' + run: | + export PATH="${CARGO_HOME:-$HOME/.cargo}/bin:$PATH" + sh scripts/install-pinned-tools.sh + sh scripts/check-supply-chain.sh From e6add6573cd6cc92f6c3386d0d3f177cab3f316a Mon Sep 17 00:00:00 2001 From: KeyffMS <124252104+KeyffMS@users.noreply.github.com> Date: Wed, 12 Aug 2026 17:16:36 +0200 Subject: [PATCH 03/15] Add regression patch chunk 00 --- automation/patch_chunks/chunk-00.b64 | 1 + 1 file changed, 1 insertion(+) create mode 100644 automation/patch_chunks/chunk-00.b64 diff --git a/automation/patch_chunks/chunk-00.b64 b/automation/patch_chunks/chunk-00.b64 new file mode 100644 index 0000000..9155cb9 --- /dev/null +++ b/automation/patch_chunks/chunk-00.b64 @@ -0,0 +1 @@ +IyEvdXNyL2Jpbi9lbnYgcHl0aG9uMwpmcm9tIF9fZnV0dXJlX18gaW1wb3J0IGFubm90YXRpb25zCgppbXBvcnQgc3lzCmZyb20gcGF0aGxpYiBpbXBvcnQgUGF0aAoKUk9PVCA9IFBhdGguY3dkKCkKCgpkZWYgcmVhZChwYXRoOiBzdHIpIC0+IHN0cjoKICAgIHJldHVybiAoUk9PVCAvIHBhdGgpLnJlYWRfdGV4dChlbmNvZGluZz0idXRmLTgiKQoKCmRlZiB3cml0ZShwYXRoOiBzdHIsIHRleHQ6IHN0cikgLT4gTm9uZToKICAgIChST09UIC8gcGF0aCkud3JpdGVfdGV4dCh0ZXh0LCBlbmNvZGluZz0idXRmLTgiKQoKCmRlZiByZXBsYWNlX29uY2UodGV4dDogc3RyLCBvbGQ6IHN0ciwgbmV3OiBzdHIsIGxhYmVsOiBzdHIpIC0+IHN0cjoKICAgIGNvdW50ID0gdGV4dC5jb3VudChvbGQpCiAgICBpZiBjb3VudCAhPSAxOgogICAgICAgIHJhaXNlIFN5c3RlbUV4aXQoZiJ7bGFiZWx9OiBleHBlY3RlZCBvbmUgbWF0Y2gsIGZvdW5kIHtjb3VudH0iKQogICAgcmV0dXJuIHRleHQucmVwbGFjZShvbGQsIG5ldywgMSkKCgpkZWYgaXNzdWU2KCkgLT4gTm9uZToKICAgIHBhdGggPSAiY3JhdGVzL3ZmZC1sYW50ZXJuL3NyYy9tYWluLnJzIgogICAgdGV4dCA9IHJlYWQocGF0aCkKICAgIHRleHQgPSByZXBsYWNlX29uY2UoCiAgICAgICAgdGV4dCwKICAgICAgICAibW9kIHByb2ZpbGVfY29tbWFuZHM7XG5cbnVzZSBhbnlob3c6OntSZXN1bHQsIGJhaWx9OyIsCiAgICAgICAgIm1vZCBwcm9maWxlX2NvbW1hbmRzO1xuXG51c2Ugc3RkOjpzeW5jOjpBcmM7XG5cbnVzZSBhbnlob3c6OntSZXN1bHQsIGJhaWx9OyIsCiAgICAgICAgIm1haW4gQXJjIGltcG9ydCIsCiAgICApCiAgICB0ZXh0ID0gcmVwbGFjZV9vbmNlKAogICAgICAgIHRleHQsCiAgICAgICAgInVzZSBsYW50ZXJuX2FwcDo6e1xuICAgIEFwcGxpY2F0aW9uU3RhdGUsIEFydGlmYWN0U3RvcmFnZVBvcnQsIENsaVNldHRpbmdzT3ZlcnJpZGVzLCBTZXR0aW5nc0xvYWRlciwgVmFsaWRhdGVkU2V0dGluZ3MsXG59OyIsCiAgICAgICAgInVzZSBsYW50ZXJuX2FwcDo6e1xuICAgIEFwcGxpY2F0aW9uU3RhdGUsIEFydGlmYWN0U3RvcmFnZVBvcnQsIENsaVNldHRpbmdzT3ZlcnJpZGVzLCBQcm9maWxlUmVnaXN0cnksIFNldHRpbmdzTG9hZGVyLFxuICAgIFZhbGlkYXRlZFNldHRpbmdzLFxufTsiLAogICAgICAgICJtYWluIGFwcCBpbXBvcnRzIiwKICAgICkKICAgIHRleHQgPSByZXBsYWNlX29uY2UoCiAgICAgICAgdGV4dCwKICAgICAgICAiICAgIGxldCBhcHBsaWNhdGlvbiA9IEFwcGxpY2F0aW9uU3RhdGU6OmRlZmF1bHQoKTsiLAogICAgICAgICIgICAgbGV0IGFwcGxpY2F0aW9uID0gQXBwbGljYXRpb25TdGF0ZTo6d2l0aF9yZWdpc3RyeShcbiAgICAgICAgQXJjOjpuZXcoUHJvZmlsZVJlZ2lzdHJ5OjpkZWZhdWx0KCkpLFxuICAgICAgICBzZXR0aW5ncy5wcm9jZXNzX3dyaXRlc19lbmFibGVkLFxuICAgICk7IiwKICAgICAgICAibWFpbiBhcHBsaWNhdGlvbiB3aXJpbmciLAogICAgKQogICAgd3JpdGUocGF0aCwgdGV4dCkKCgpkZWYgaXNzdWU4KCkgLT4gTm9uZToKICAgIHNldHRpbmdzX3BhdGggPSAiY3JhdGVzL2xhbnRlcm4tYXBwL3NyYy9zZXR0aW5ncy5ycyIKICAgIHNldHRpbmdzID0gcmVhZChzZXR0aW5nc19wYXRoKQogICAgc2V0dGluZ3MgPSByZXBsYWNlX29uY2UoCiAgICAgICAgc2V0dGluZ3MsCiAgICAgICAgInVzZSBjcmF0ZTo6e1NldHRpbmdzU291cmNlRXJyb3IsIFNldHRpbmdzU291cmNlUG9ydH07IiwKICAgICAgICAidXNlIGNyYXRlOjp7UmVxdWVzdENsYXNzLCBTZXR0aW5nc1NvdXJjZUVycm9yLCBTZXR0aW5nc1NvdXJjZVBvcnR9OyIsCiAgICAgICAgInNldHRpbmdzIFJlcXVlc3RDbGFzcyBpbXBvcnQiLAogICAgKQogICAgbWFya2VyID0gIiIiI1tkZXJpdmUoQ2xvbmUsIERlYnVnLCBFcSwgUGFydGlhbEVxKV0KcHViIHN0cnVjdCBRdWV1ZUNhcGFjaXRpZXMgewogICAgcHViIHNhZmV0eV9vbmVfc2hvdDogdXNpemUsCiAgICBwdWIgaW50ZXJhY3RpdmU6IHVzaXplLAogICAgcHViIHRlbGVtZXRyeV9jcml0aWNhbDogdXNpemUsCiAgICBwdWIgdGVsZW1ldHJ5OiB1c2l6ZSwKICAgIHB1YiBiYWNrZ3JvdW5kOiB1c2l6ZSwKfQoiIiIKICAgIGFkZGl0aW9uID0gbWFya2VyICsgIiIiCmltcGwgRGVmYXVsdCBmb3IgUXVldWVDYXBhY2l0aWVzIHsKICAgIGZuIGRlZmF1bHQoKSAtPiBTZWxmIHsKICAgICAgICBTZWxmIHsKICAgICAgICAgICAgc2FmZXR5X29uZV9zaG90OiBSZXF1ZXN0Q2xhc3M6OlNhZmV0eU9uZVNob3QuY2FwYWNpdHkoKSwKICAgICAgICAgICAgaW50ZXJhY3RpdmU6IFJlcXVlc3RDbGFzczo6SW50ZXJhY3RpdmUuY2FwYWNpdHkoKSwKICAgICAgICAgICAgdGVsZW1ldHJ5X2NyaXRpY2FsOiBSZXF1ZXN0Q2xhc3M6OlRlbGVtZXRyeUNyaXRpY2FsLmNhcGFjaXR5KCksCiAgICAgICAgICAgIHRlbGVtZXRyeTogUmVxdWVzdENsYXNzOjpUZWxlbWV0cnkuY2FwYWNpdHkoKSwKICAgICAgICAgICAgYmFja2dyb3VuZDogUmVxdWVzdENsYXNzOjpCYWNrZ3JvdW5kLmNhcGFjaXR5KCksCiAgICAgICAgfQogICAgfQp9CgppbXBsIFF1ZXVlQ2FwYWNpdGllcyB7CiAgICAjW211c3RfdXNlXQogICAgcHViIGNvbnN0IGZuIGZvcl9jbGFzcygmc2VsZiwgY2xhc3M6IFJlcXVlc3RDbGFzcykgLT4gdXNpemUgewogICAgICAgIG1hdGNoIGNsYXNzIHsKICAgICAgICAgICAgUmVxdWVzdENsYXNzOjpTYWZldHlPbmVTaG90ID0+IHNlbGYuc2FmZXR5X29uZV9zaG90LAogICAgICAgICAgICBSZXF1ZXN0Q2xhc3M6OkludGVyYWN0aXZlID0+IHNlbGYuaW50ZXJhY3RpdmUsCiAgICAgICAgICAgIFJlcXVlc3RDbGFzczo6VGVsZW1ldHJ5Q3JpdGljYWwgPT4gc2VsZi50ZWxlbWV0cnlfY3JpdGljYWwsCiAgICAgICAgICAgIFJlcXVlc3RDbGFzczo6VGVsZW1ldHJ5ID0+IHNlbGYudGVsZW1ldHJ5LAogICAgICAgICAgICBSZXF1ZXN0Q2xhc3M6OkJhY2tncm91bmQgPT4gc2VsZi5iYWNrZ3JvdW5kLAogICAgICAgIH0KICAgIH0KfQoiIiIKICAgIHNldHRpbmdzID0gcmVwbGFjZV9vbmNlKHNldHRpbmdzLCBtYXJrZXIsIGFkZGl0aW9uLCAiUXVldWVDYXBhY2l0aWVzIGltcGwiKQogICAgc2V0dGluZ3MgPSByZXBsYWNlX29uY2UoCiAgICAgICAgc2V0dGluZ3MsCiAgICAgICAgIiIiICAgICAgICAgICAgcXVldWVzOiBRdWV1ZUNhcGFjaXRpZXMgewogICAgICAgICAgICAgICAgc2FmZXR5X29uZV9zaG90OiAxNiwKICAgICAgICAgICAgICAgIGludGVyYWN0aXZlOiA2NCwKICAgICAgICAgICAgICAgIHRlbGVtZXRyeV9jcml0aWNhbDogNjQsCiAgICAgICAgICAgICAgICB0ZWxlbWV0cnk6IDI1NiwKICAgICAgICAgICAgICAgIGJhY2tncm91bmQ6IDMyLAogICAgICAgICAgICB9LCIiIiwKICAgICAgICAiICAgICAgICAgICAgcXVldWVzOiBRdWV1ZUNhcGFjaXRpZXM6OmRlZmF1bHQoKSwiLAogICAgICAgICJzZXR0aW5ncyBkZWZhdWx0IHF1ZXVlcyIsCiAgICApCiAgICB3cml0ZShzZXR0aW5nc19wYXRoLCBzZXR0aW5ncykKCiAgICBhY3Rvcl9wYXRoID0gImNyYXRlcy9sYW50ZXJuLXRyYW5zcG9ydC9zcmMvYnVzX2FjdG9yLnJzIgogICAgYWN0b3IgPSByZWFkKGFjdG9yX3BhdGgpCiAgICBhY3RvciA9IHJlcGxhY2Vfb25jZSgKICAgICAgICBhY3RvciwKICAgICAgICAiIiJ1c2UgbGFudGVybl9hcHA6OnsKICAgIEJ1c0NvbnRyb2xQb3J0LCBCdXNFcnJvciwgQnVzRnV0dXJlLCBCdXNTdGF0aXN0aWNzU25hcHNob3QsIFByZXBhcmVkQnVzV3JpdGUsIFJlYWRCdXNQb3J0LAogICAgUmVhZEJ1c1JlcXVlc3QsIFJlcXVlc3RDbGFzcywgV3JpdGVCdXNQb3J0LAp9OyIiIiwKICAgICAgICAiIiJ1c2UgbGFudGVybl9hcHA6OnsKICAgIEJ1c0NvbnRyb2xQb3J0LCBCdXNFcnJvciwgQnVzRnV0dXJlLCBCdXNTdGF0aXN0aWNzU25hcHNob3QsIFByZXBhcmVkQnVzV3JpdGUsIFF1ZXVlQ2FwYWNpdGllcywKICAgIFJlYWRCdXNQb3J0LCBSZWFkQnVzUmVxdWVzdCwgUmVxdWVzdENsYXNzLCBXcml0ZUJ1c1BvcnQsCn07IiIiLAogICAgICAgICJCdXNBY3RvciBhcHAgaW1wb3J0cyIsCiAgICApCiAgICBhY3RvciA9IHJlcGxhY2Vfb25jZSgKICAgICAgICBhY3RvciwKICAgICAgICAiIiIgICAgc3luYzo6e21wc2MsIG9uZXNob3R9LCIiIiwKICAgICAgICAiIiIgICAgc3luYzo6e21wc2MsIG9uZXNob3QsIE93bmVkU2VtYXBob3JlUGVybWl0LCBTZW1hcGhvcmV9LCIiIiwKICAgICAgICAiQnVzQWN0b3IgdG9raW8gc3luYyBpbXBvcnRzIiwKICAgICkKICAgIGFjdG9yID0gcmVwbGFjZV9vbmNlKAogICAgICAgIGFjdG9yLAogICAgICAgICIiIiNbZGVyaXZlKENsb25lLCBDb3B5LCBEZWJ1ZyldCnB1YiBzdHJ1Y3QgQnVzQWN0b3JDb25maWcgewogICAgcHViIGxpbms6IExpbmtTZXR0aW5ncywKICAgIHB1YiBwcm9maWxlX21pbmltdW1faW50ZXJfZnJhbWVfZGVsYXk6IER1cmF0aW9uLAp9CgppbXBsIEJ1c0FjdG9yQ29uZmlnIHsKICAgICNb \ No newline at end of file From ccebfc7dcfe1a68edd7beff3b9911d2c1c62c7d4 Mon Sep 17 00:00:00 2001 From: KeyffMS <124252104+KeyffMS@users.noreply.github.com> Date: Wed, 12 Aug 2026 17:33:54 +0200 Subject: [PATCH 04/15] Add isolated pinned tool installer for final validation --- automation/install-pinned-tools-final.sh | 36 ++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 automation/install-pinned-tools-final.sh diff --git a/automation/install-pinned-tools-final.sh b/automation/install-pinned-tools-final.sh new file mode 100644 index 0000000..0315099 --- /dev/null +++ b/automation/install-pinned-tools-final.sh @@ -0,0 +1,36 @@ +#!/bin/sh +set -eu + +manifest="${VFD_LANTERN_TOOLS_MANIFEST:-tools.lock.toml}" +install_root="${VFD_LANTERN_TOOL_ROOT:-${CARGO_HOME:-$HOME/.cargo}}" +target_dir="${VFD_LANTERN_TOOL_TARGET_DIR:-${TMPDIR:-/tmp}/vfd-lantern-cargo-tools-target}" + +version_for() { + awk -F '[[:space:]]*=[[:space:]]*' -v key="$1" ' + $1 == key { + gsub(/"/, "", $2) + print $2 + found = 1 + exit + } + END { + if (!found) exit 1 + } + ' "$manifest" +} + +install_tool() { + crate="$1" + version="$(version_for "$crate")" + ( + cd "${TMPDIR:-/tmp}" + CARGO_TARGET_DIR="$target_dir" \ + cargo install --locked --root "$install_root" --version "$version" "$crate" + ) +} + +mkdir -p "$install_root" "$target_dir" +install_tool cargo-machete +install_tool cargo-deny +install_tool cargo-audit +install_tool cargo-vet From f1bc16779f6507461876c8bd638e149515cd327d Mon Sep 17 00:00:00 2001 From: KeyffMS <124252104+KeyffMS@users.noreply.github.com> Date: Wed, 12 Aug 2026 17:34:07 +0200 Subject: [PATCH 05/15] Add complete final supply-chain gate --- automation/check-supply-chain-final.sh | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 automation/check-supply-chain-final.sh diff --git a/automation/check-supply-chain-final.sh b/automation/check-supply-chain-final.sh new file mode 100644 index 0000000..86e4b12 --- /dev/null +++ b/automation/check-supply-chain-final.sh @@ -0,0 +1,8 @@ +#!/bin/sh +set -eu + +sh scripts/check-supply-chain-baseline.sh +cargo machete +cargo deny check +cargo audit --file Cargo.lock +cargo vet check From 54744f585b7cb35e3a6f688f3f7c31fb2bbed661 Mon Sep 17 00:00:00 2001 From: KeyffMS <124252104+KeyffMS@users.noreply.github.com> Date: Wed, 12 Aug 2026 17:34:30 +0200 Subject: [PATCH 06/15] Document isolated pinned supply-chain toolchain --- automation/toolchain-final.md | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 automation/toolchain-final.md diff --git a/automation/toolchain-final.md b/automation/toolchain-final.md new file mode 100644 index 0000000..f23b715 --- /dev/null +++ b/automation/toolchain-final.md @@ -0,0 +1,35 @@ +# Pinned development toolchain + +VFD Lantern targets Debian 13 (Trixie) on amd64 and arm64. Install `rustup` from +APT, then let `rust-toolchain.toml` select Rust 1.97.1. Do not use `curl | sh`. + +```sh +sudo apt-get update +sudo apt-get install --yes build-essential ca-certificates git libudev-dev pkg-config rustup +rustup toolchain install 1.97.1 --profile minimal \ + --component rustfmt --component clippy --component llvm-tools-preview +cargo build --workspace --all-features --locked +cargo test --workspace --all-features --locked +``` + +Direct crate versions are centralized in `[workspace.dependencies]`. Binary tool +versions are centralized in `tools.lock.toml`. Updates require a dedicated change +with a refreshed lockfile and the full CI suite. + +Install the exact supply-chain tool versions from the single tool manifest and run +the complete gate as follows. Installation uses an isolated target directory and +must not modify the project `Cargo.lock`. + +```sh +export VFD_LANTERN_TOOL_ROOT="${TMPDIR:-/tmp}/vfd-lantern-tools" +export VFD_LANTERN_TOOL_TARGET_DIR="${TMPDIR:-/tmp}/vfd-lantern-tools-target" +export PATH="$VFD_LANTERN_TOOL_ROOT/bin:$PATH" +sh scripts/install-pinned-tools.sh +sh scripts/check-supply-chain.sh +``` + +The gate executes `cargo machete`, `cargo deny check`, `cargo audit --file +Cargo.lock`, and `cargo vet check`. The initial `supply-chain/config.toml` +exemptions freeze the accepted dependency graph; dependency updates must not +silently add exemptions and should reduce them through recorded audits over time. +The command is `cargo vet check`, not the non-existent `cargo vet verify`. From 53abd32594e360cd681334ac99e96ba53930636f Mon Sep 17 00:00:00 2001 From: KeyffMS <124252104+KeyffMS@users.noreply.github.com> Date: Wed, 12 Aug 2026 17:35:04 +0200 Subject: [PATCH 07/15] Add final CI with full pinned supply-chain gate --- automation/final-ci.yml | 112 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 automation/final-ci.yml diff --git a/automation/final-ci.yml b/automation/final-ci.yml new file mode 100644 index 0000000..34892a9 --- /dev/null +++ b/automation/final-ci.yml @@ -0,0 +1,112 @@ +name: CI + +on: + push: + branches: [main, "agent/**"] + pull_request: + +permissions: + contents: read + +concurrency: + group: ci-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + rust: + name: Debian 13 / Rust 1.97.1 / ${{ matrix.arch }} + strategy: + fail-fast: false + matrix: + include: + - arch: amd64 + runner: ubuntu-24.04 + - arch: arm64 + runner: ubuntu-24.04-arm + runs-on: ${{ matrix.runner }} + container: debian:trixie-slim@sha256:020c0d20b9880058cbe785a9db107156c3c75c2ac944a6aa7ab59f2add76a7bd + + steps: + - name: Install system dependencies + run: | + apt-get update + apt-get install --yes --no-install-recommends \ + build-essential \ + ca-certificates \ + git \ + libudev-dev \ + pkg-config \ + rustup + + - name: Check out repository + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + + - name: Install pinned Rust toolchain + run: | + rustup toolchain install 1.97.1 \ + --profile minimal \ + --component rustfmt \ + --component clippy \ + --component llvm-tools-preview + rustup default 1.97.1 + rustc --version + cargo --version + + - name: Validate lockfile and metadata + run: cargo metadata --locked --format-version 1 --no-deps >/dev/null + + - name: Build workspace + run: cargo build --workspace --all-features --locked + + - name: Check formatting + run: cargo fmt --all -- --check + + - name: Run Clippy + run: cargo clippy --workspace --all-targets --all-features --locked -- -D warnings + + - name: Run tests + run: cargo test --workspace --all-features --locked + + - name: Build documentation + run: cargo doc --workspace --all-features --no-deps --locked + + - name: Check architecture boundaries + run: sh scripts/check-architecture.sh + + - name: Check supply-chain baseline + run: sh scripts/check-supply-chain-baseline.sh + + supply-chain: + name: Pinned supply-chain tools + runs-on: ubuntu-24.04 + container: debian:trixie-slim@sha256:020c0d20b9880058cbe785a9db107156c3c75c2ac944a6aa7ab59f2add76a7bd + + steps: + - name: Install system dependencies + run: | + apt-get update + apt-get install --yes --no-install-recommends \ + build-essential \ + ca-certificates \ + git \ + libudev-dev \ + pkg-config \ + rustup + + - name: Check out repository + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + + - name: Install pinned Rust toolchain + run: | + rustup toolchain install 1.97.1 --profile minimal + rustup default 1.97.1 + + - name: Install and run pinned supply-chain tools + run: | + export VFD_LANTERN_TOOL_ROOT="$RUNNER_TEMP/vfd-tools" + export VFD_LANTERN_TOOL_TARGET_DIR="$RUNNER_TEMP/vfd-tools-target" + export PATH="$VFD_LANTERN_TOOL_ROOT/bin:$PATH" + lock_before="$(sha256sum Cargo.lock | cut -d ' ' -f 1)" + sh scripts/install-pinned-tools.sh + test "$(sha256sum Cargo.lock | cut -d ' ' -f 1)" = "$lock_before" + sh scripts/check-supply-chain.sh From abb9ac812fb0520d074535625824597232540aac Mon Sep 17 00:00:00 2001 From: KeyffMS <124252104+KeyffMS@users.noreply.github.com> Date: Wed, 12 Aug 2026 17:38:14 +0200 Subject: [PATCH 08/15] Add tested closure patch for settings, bus, and composition integration --- automation/closure-generated.patch | 235 +++++++++++++++++++++++++++++ 1 file changed, 235 insertions(+) create mode 100644 automation/closure-generated.patch diff --git a/automation/closure-generated.patch b/automation/closure-generated.patch new file mode 100644 index 0000000..6354cce --- /dev/null +++ b/automation/closure-generated.patch @@ -0,0 +1,235 @@ +diff --git a/crates/lantern-app/src/bus.rs b/crates/lantern-app/src/bus.rs +index 91ce0f9..d0622d4 100644 +--- a/crates/lantern-app/src/bus.rs ++++ b/crates/lantern-app/src/bus.rs +@@ -9,6 +9,8 @@ use lantern_domain::{ + }; + use thiserror::Error; + ++use crate::QueueCapacities; ++ + pub type BusFuture<'a, T> = Pin> + Send + 'a>>; + + #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] +@@ -22,12 +24,13 @@ pub enum RequestClass { + + impl RequestClass { + #[must_use] +- pub const fn capacity(self) -> usize { ++ pub const fn capacity(self, capacities: QueueCapacities) -> usize { + match self { +- Self::SafetyOneShot => 16, +- Self::Interactive | Self::TelemetryCritical => 64, +- Self::Telemetry => 256, +- Self::Background => 32, ++ Self::SafetyOneShot => capacities.safety_one_shot, ++ Self::Interactive => capacities.interactive, ++ Self::TelemetryCritical => capacities.telemetry_critical, ++ Self::Telemetry => capacities.telemetry, ++ Self::Background => capacities.background, + } + } + +diff --git a/crates/lantern-app/src/settings.rs b/crates/lantern-app/src/settings.rs +index 14a9736..772fc83 100644 +--- a/crates/lantern-app/src/settings.rs ++++ b/crates/lantern-app/src/settings.rs +@@ -109,7 +109,7 @@ pub struct CliSettingsOverrides { + pub no_color: bool, + } + +-#[derive(Clone, Debug, Eq, PartialEq)] ++#[derive(Clone, Copy, Debug, Eq, PartialEq)] + pub struct QueueCapacities { + pub safety_one_shot: usize, + pub interactive: usize, +@@ -118,6 +118,18 @@ pub struct QueueCapacities { + pub background: usize, + } + ++impl Default for QueueCapacities { ++ fn default() -> Self { ++ Self { ++ safety_one_shot: 16, ++ interactive: 64, ++ telemetry_critical: 64, ++ telemetry: 256, ++ background: 32, ++ } ++ } ++} ++ + #[derive(Clone, Debug, Eq, PartialEq)] + pub struct PollingIntervals { + pub telemetry_critical_ms: u64, +@@ -157,13 +169,7 @@ impl Default for ValidatedSettings { + history_samples: 3_600, + memory_limit_mib: 128, + log_retention_files: 10, +- queues: QueueCapacities { +- safety_one_shot: 16, +- interactive: 64, +- telemetry_critical: 64, +- telemetry: 256, +- background: 32, +- }, ++ queues: QueueCapacities::default(), + polling: PollingIntervals { + telemetry_critical_ms: 250, + telemetry_ms: 1_000, +diff --git a/crates/lantern-transport/src/bus_actor.rs b/crates/lantern-transport/src/bus_actor.rs +index 2b0ff5f..0a0317a 100644 +--- a/crates/lantern-transport/src/bus_actor.rs ++++ b/crates/lantern-transport/src/bus_actor.rs +@@ -5,8 +5,8 @@ use std::{ + }; + + use lantern_app::{ +- BusControlPort, BusError, BusFuture, BusStatisticsSnapshot, PreparedBusWrite, ReadBusPort, +- ReadBusRequest, RequestClass, WriteBusPort, ++ BusControlPort, BusError, BusFuture, BusStatisticsSnapshot, PreparedBusWrite, QueueCapacities, ++ ReadBusPort, ReadBusRequest, RequestClass, WriteBusPort, + }; + use lantern_domain::{DataBits, LinkSettings, Parity, RawRegisters, StopBits}; + use tokio::{ +@@ -56,10 +56,19 @@ impl BusActor { + pub fn spawn( + backend: B, + config: BusActorConfig, ++ ) -> (BusActorHandle, JoinHandle<()>) { ++ Self::spawn_with_capacities(backend, config, QueueCapacities::default()) ++ } ++ ++ #[must_use] ++ pub fn spawn_with_capacities( ++ backend: B, ++ config: BusActorConfig, ++ queue_capacities: QueueCapacities, + ) -> (BusActorHandle, JoinHandle<()>) { + let cancellation = CancellationToken::new(); + let statistics = Arc::new(Mutex::new(BusStatistics::default())); +- let (senders, receivers) = channels(); ++ let (senders, receivers) = channels(queue_capacities); + let handle = BusActorHandle { + senders, + cancellation: cancellation.clone(), +@@ -171,13 +180,14 @@ struct Receivers { + background: mpsc::Receiver, + } + +-fn channels() -> (Senders, Receivers) { +- let (safety, safety_rx) = mpsc::channel(RequestClass::SafetyOneShot.capacity()); +- let (interactive, interactive_rx) = mpsc::channel(RequestClass::Interactive.capacity()); ++fn channels(capacities: QueueCapacities) -> (Senders, Receivers) { ++ let (safety, safety_rx) = mpsc::channel(RequestClass::SafetyOneShot.capacity(capacities)); ++ let (interactive, interactive_rx) = ++ mpsc::channel(RequestClass::Interactive.capacity(capacities)); + let (telemetry_critical, telemetry_critical_rx) = +- mpsc::channel(RequestClass::TelemetryCritical.capacity()); +- let (telemetry, telemetry_rx) = mpsc::channel(RequestClass::Telemetry.capacity()); +- let (background, background_rx) = mpsc::channel(RequestClass::Background.capacity()); ++ mpsc::channel(RequestClass::TelemetryCritical.capacity(capacities)); ++ let (telemetry, telemetry_rx) = mpsc::channel(RequestClass::Telemetry.capacity(capacities)); ++ let (background, background_rx) = mpsc::channel(RequestClass::Background.capacity(capacities)); + ( + Senders { + safety, +@@ -721,8 +731,8 @@ mod tests { + }; + + use lantern_app::{ +- BusControlPort, BusError, BusRequestContext, PreparedBusWrite, ReadBusPort, ReadBusRequest, +- RequestClass, WriteBusPort, WriteCoordinator, ++ BusControlPort, BusError, BusRequestContext, PreparedBusWrite, QueueCapacities, ++ ReadBusPort, ReadBusRequest, RequestClass, WriteBusPort, WriteCoordinator, + }; + use lantern_domain::{ + BaudRate, DataBits, LinkSettings, ModbusFunction, ModbusTable, Parity, RawRegisters, +@@ -732,7 +742,7 @@ mod tests { + + use crate::modbus_backend::{BackendFuture, RtuBackend}; + +- use super::{BusActor, BusActorConfig, protocol_t35}; ++ use super::{BusActor, BusActorConfig, channels, protocol_t35}; + + #[derive(Default)] + struct FakeBackend { +@@ -789,6 +799,23 @@ mod tests { + } + } + ++ #[test] ++ fn configured_queue_capacities_are_used() { ++ let capacities = QueueCapacities { ++ safety_one_shot: 1, ++ interactive: 2, ++ telemetry_critical: 3, ++ telemetry: 4, ++ background: 5, ++ }; ++ let (senders, _receivers) = channels(capacities); ++ assert_eq!(senders.safety.max_capacity(), 1); ++ assert_eq!(senders.interactive.max_capacity(), 2); ++ assert_eq!(senders.telemetry_critical.max_capacity(), 3); ++ assert_eq!(senders.telemetry.max_capacity(), 4); ++ assert_eq!(senders.background.max_capacity(), 5); ++ } ++ + #[test] + fn t35_matches_modbus_rules() { + assert_eq!(protocol_t35(link(115_200)), Duration::from_micros(1_750)); +diff --git a/crates/lantern-transport/src/lib.rs b/crates/lantern-transport/src/lib.rs +index 1524384..fb8d3b0 100644 +--- a/crates/lantern-transport/src/lib.rs ++++ b/crates/lantern-transport/src/lib.rs +@@ -17,16 +17,18 @@ pub use modbus_backend::{RtuBackend, TokioModbusBackend}; + pub async fn open_serial_bus( + request: lantern_app::SerialOpenRequest, + profile_minimum_inter_frame_delay: std::time::Duration, ++ queue_capacities: lantern_app::QueueCapacities, + ) -> Result<(BusActorHandle, tokio::task::JoinHandle<()>), lantern_app::SerialConnectError> { + let link = request.settings; + let port = serial_open::SerialPortOpener::open(request).await?; + let backend = TokioModbusBackend::new(port, link.slave_id, link.response_timeout); +- Ok(BusActor::spawn( ++ Ok(BusActor::spawn_with_capacities( + backend, + BusActorConfig { + link, + profile_minimum_inter_frame_delay, + }, ++ queue_capacities, + )) + } + +diff --git a/crates/vfd-lantern/src/main.rs b/crates/vfd-lantern/src/main.rs +index 9391fc8..b355940 100644 +--- a/crates/vfd-lantern/src/main.rs ++++ b/crates/vfd-lantern/src/main.rs +@@ -5,10 +5,13 @@ + mod cli; + mod profile_commands; + ++use std::sync::Arc; ++ + use anyhow::{Result, bail}; + use clap::Parser; + use lantern_app::{ +- ApplicationState, ArtifactStoragePort, CliSettingsOverrides, SettingsLoader, ValidatedSettings, ++ ApplicationState, ArtifactStoragePort, CliSettingsOverrides, ProfileRegistry, SettingsLoader, ++ ValidatedSettings, + }; + use lantern_storage::{AppPaths, FileStorage, FilesystemSettingsSource}; + use lantern_transport::TransportAdapter; +@@ -67,7 +70,10 @@ fn main() -> Result<()> { + fn run_tui_bootstrap(settings: &ValidatedSettings, paths: &AppPaths) -> Result<()> { + let storage = FileStorage; + let transport = TransportAdapter; +- let application = ApplicationState::default(); ++ let application = ApplicationState::with_registry( ++ Arc::new(ProfileRegistry::default()), ++ settings.process_writes_enabled, ++ ); + let ui = UiState::default(); + + println!("VFD Lantern {}", env!("CARGO_PKG_VERSION")); From 430502aae34ca099cfa2fa2bf1c41de3e4cc1958 Mon Sep 17 00:00:00 2001 From: KeyffMS <124252104+KeyffMS@users.noreply.github.com> Date: Wed, 12 Aug 2026 17:39:03 +0200 Subject: [PATCH 09/15] Add second-generation closure pipeline with lock isolation and integration fixes --- automation/close_issues_1_9_v2.sh | 109 ++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 automation/close_issues_1_9_v2.sh diff --git a/automation/close_issues_1_9_v2.sh b/automation/close_issues_1_9_v2.sh new file mode 100644 index 0000000..adc8d6f --- /dev/null +++ b/automation/close_issues_1_9_v2.sh @@ -0,0 +1,109 @@ +#!/usr/bin/env bash +set -euo pipefail + +readonly MAIN_SHA="82748172d516cbd53161df58f37d4347fa817dbf" +readonly DELIVERY_SHA="0d44845630c22efc9675b1fd1b32abceaf75bfe3" +readonly ISSUE2_SHA="678def2b42e13c1099c7187c03637cb0e584e4ab" +readonly ISSUE6_SHA="cb59284396a977f3ac058d01ff919e535f9e0c50" +readonly ISSUE8_SHA="0aa7652c7f9f79b70297a42e5b770c9c146b65f0" +readonly ISSUE9_SHA="0d44845630c22efc9675b1fd1b32abceaf75bfe3" +readonly CANDIDATE_BRANCH="agent/issues-1-9-final-candidate" +readonly AUTOMATION_REF="$(git rev-parse HEAD)" +readonly TOOL_ROOT="${RUNNER_TEMP:-/tmp}/vfd-lantern-tools" +readonly TOOL_TARGET="${RUNNER_TEMP:-/tmp}/vfd-lantern-tools-target" + +export VFD_LANTERN_TOOL_ROOT="$TOOL_ROOT" +export VFD_LANTERN_TOOL_TARGET_DIR="$TOOL_TARGET" +export PATH="$TOOL_ROOT/bin:${CARGO_HOME:-$HOME/.cargo}/bin:$PATH" + +git config --global --add safe.directory "$GITHUB_WORKSPACE" +git config user.name "VFD Lantern contributors" +git config user.email "actions@users.noreply.github.com" + +git fetch --force origin \ + main:refs/remotes/origin/main \ + agent/issues-1-9:refs/remotes/origin/delivery \ + "$CANDIDATE_BRANCH":refs/remotes/origin/final-candidate + +test "$(git rev-parse refs/remotes/origin/main)" = "$MAIN_SHA" +test "$(git rev-parse refs/remotes/origin/delivery)" = "$DELIVERY_SHA" +test "$(git rev-parse refs/remotes/origin/final-candidate)" = "$DELIVERY_SHA" +git checkout --detach "$DELIVERY_SHA" + +# Copy exact closure assets out of the temporary automation branch. +git show "$AUTOMATION_REF:automation/final-ci.yml" > .github/workflows/ci.yml +git show "$AUTOMATION_REF:automation/install-pinned-tools-final.sh" > scripts/install-pinned-tools.sh +git show "$AUTOMATION_REF:automation/check-supply-chain-final.sh" > scripts/check-supply-chain.sh +git show "$AUTOMATION_REF:automation/toolchain-final.md" > docs/development/toolchain.md +git show "$AUTOMATION_REF:automation/closure-generated.patch" | git apply --check +git show "$AUTOMATION_REF:automation/closure-generated.patch" | git apply +chmod +x scripts/install-pinned-tools.sh scripts/check-supply-chain.sh +cargo fmt --all + +# Tool installation is isolated and may never mutate the product lockfile. +lock_before="$(sha256sum Cargo.lock | cut -d ' ' -f 1)" +sh scripts/install-pinned-tools.sh +test "$(sha256sum Cargo.lock | cut -d ' ' -f 1)" = "$lock_before" + +if [ ! -d supply-chain ]; then + cargo vet init +fi +test "$(sha256sum Cargo.lock | cut -d ' ' -f 1)" = "$lock_before" + +validate_all() { + cargo metadata --locked --format-version 1 >/dev/null + cargo build --workspace --all-features --locked + cargo fmt --all -- --check + cargo clippy --workspace --all-targets --all-features --locked -- -D warnings + cargo test --workspace --all-features --locked + cargo doc --workspace --all-features --no-deps --locked + sh scripts/check-architecture.sh + sh scripts/check-supply-chain.sh + test "$(sha256sum Cargo.lock | cut -d ' ' -f 1)" = "$lock_before" + git diff --check "$MAIN_SHA" +} + +# Validate the complete working tree before creating any rewritten commit. +validate_all + +# Preserve one logical commit per issue through fixups and autosquash. +git add .github/workflows/ci.yml \ + docs/development/toolchain.md \ + scripts/install-pinned-tools.sh \ + scripts/check-supply-chain.sh \ + supply-chain +git commit --fixup "$ISSUE2_SHA" + +git add crates/lantern-app/src/settings.rs +git commit --fixup "$ISSUE6_SHA" + +git add crates/lantern-app/src/bus.rs \ + crates/lantern-transport/src/bus_actor.rs \ + crates/lantern-transport/src/lib.rs +git commit --fixup "$ISSUE8_SHA" + +git add crates/vfd-lantern/src/main.rs +git commit --fixup "$ISSUE9_SHA" + +test -z "$(git status --porcelain)" +GIT_SEQUENCE_EDITOR=: git rebase -i --autosquash --committer-date-is-author-date "$MAIN_SHA" + +# Re-run every gate against the exact rewritten history before publishing it. +validate_all +test -z "$(git status --porcelain)" + +final_sha="$(git rev-parse HEAD)" +final_tree="$(git rev-parse HEAD^{tree})" +test "$(git rev-list --count "$MAIN_SHA"..HEAD)" -eq 9 +for number in 1 2 3 4 5 6 7 8 9; do + test "$(git log --format='%s' "$MAIN_SHA"..HEAD | grep -Ec "\\(#${number}\\)$")" -eq 1 +done +test -z "$(git log --format='%s' "$MAIN_SHA"..HEAD | grep '^fixup!' || true)" +test -z "$(git ls-files 'automation/**' '.github/workflows/close-issues-1-9.yml')" + +git push \ + --force-with-lease="refs/heads/$CANDIDATE_BRANCH:$DELIVERY_SHA" \ + origin "HEAD:refs/heads/$CANDIDATE_BRANCH" + +printf 'final_sha=%s\n' "$final_sha" >> "$GITHUB_OUTPUT" +printf 'final_tree=%s\n' "$final_tree" >> "$GITHUB_OUTPUT" From 1aa099c9dae6bb11d174d332804c6d1f0629a0e5 Mon Sep 17 00:00:00 2001 From: KeyffMS <124252104+KeyffMS@users.noreply.github.com> Date: Wed, 12 Aug 2026 17:40:01 +0200 Subject: [PATCH 10/15] Run second-generation final closure validation --- .github/workflows/close-issues-1-9.yml | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/.github/workflows/close-issues-1-9.yml b/.github/workflows/close-issues-1-9.yml index 97f8774..04523af 100644 --- a/.github/workflows/close-issues-1-9.yml +++ b/.github/workflows/close-issues-1-9.yml @@ -4,7 +4,7 @@ on: pull_request: branches: ["agent/issues-1-9"] paths: - - "automation/close_issues_1_9.sh" + - "automation/**" - ".github/workflows/close-issues-1-9.yml" permissions: @@ -53,7 +53,7 @@ jobs: - name: Build, autosquash, validate, and publish candidate branch id: candidate shell: bash - run: bash automation/close_issues_1_9.sh + run: bash automation/close_issues_1_9_v2.sh validate: name: Validate exact candidate / ${{ matrix.arch }} @@ -122,6 +122,10 @@ jobs: - name: Run full pinned supply-chain gate if: matrix.arch == 'amd64' run: | - export PATH="${CARGO_HOME:-$HOME/.cargo}/bin:$PATH" + export VFD_LANTERN_TOOL_ROOT="$RUNNER_TEMP/vfd-tools" + export VFD_LANTERN_TOOL_TARGET_DIR="$RUNNER_TEMP/vfd-tools-target" + export PATH="$VFD_LANTERN_TOOL_ROOT/bin:$PATH" + lock_before="$(sha256sum Cargo.lock | cut -d ' ' -f 1)" sh scripts/install-pinned-tools.sh + test "$(sha256sum Cargo.lock | cut -d ' ' -f 1)" = "$lock_before" sh scripts/check-supply-chain.sh From b87ffa8855bb367f2507018ce455801de0248b15 Mon Sep 17 00:00:00 2001 From: KeyffMS <124252104+KeyffMS@users.noreply.github.com> Date: Wed, 12 Aug 2026 17:44:58 +0200 Subject: [PATCH 11/15] Fix closure automation reference capture and add precise diagnostics --- automation/close_issues_1_9_v2.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/automation/close_issues_1_9_v2.sh b/automation/close_issues_1_9_v2.sh index adc8d6f..40f1691 100644 --- a/automation/close_issues_1_9_v2.sh +++ b/automation/close_issues_1_9_v2.sh @@ -1,5 +1,6 @@ #!/usr/bin/env bash set -euo pipefail +trap 'status=$?; printf "closure failed at line %s: %s (exit %s)\n" "$LINENO" "$BASH_COMMAND" "$status" >&2' ERR readonly MAIN_SHA="82748172d516cbd53161df58f37d4347fa817dbf" readonly DELIVERY_SHA="0d44845630c22efc9675b1fd1b32abceaf75bfe3" @@ -8,7 +9,6 @@ readonly ISSUE6_SHA="cb59284396a977f3ac058d01ff919e535f9e0c50" readonly ISSUE8_SHA="0aa7652c7f9f79b70297a42e5b770c9c146b65f0" readonly ISSUE9_SHA="0d44845630c22efc9675b1fd1b32abceaf75bfe3" readonly CANDIDATE_BRANCH="agent/issues-1-9-final-candidate" -readonly AUTOMATION_REF="$(git rev-parse HEAD)" readonly TOOL_ROOT="${RUNNER_TEMP:-/tmp}/vfd-lantern-tools" readonly TOOL_TARGET="${RUNNER_TEMP:-/tmp}/vfd-lantern-tools-target" @@ -17,6 +17,7 @@ export VFD_LANTERN_TOOL_TARGET_DIR="$TOOL_TARGET" export PATH="$TOOL_ROOT/bin:${CARGO_HOME:-$HOME/.cargo}/bin:$PATH" git config --global --add safe.directory "$GITHUB_WORKSPACE" +readonly AUTOMATION_REF="$(git rev-parse HEAD)" git config user.name "VFD Lantern contributors" git config user.email "actions@users.noreply.github.com" From de69af62b1e4519976a5a05c6c592b9a728e474c Mon Sep 17 00:00:00 2001 From: KeyffMS <124252104+KeyffMS@users.noreply.github.com> Date: Wed, 12 Aug 2026 17:46:50 +0200 Subject: [PATCH 12/15] Trigger corrected closure validation From cb205bf377a5d7ffd8ad539fac02f5561e03d5aa Mon Sep 17 00:00:00 2001 From: KeyffMS <124252104+KeyffMS@users.noreply.github.com> Date: Wed, 12 Aug 2026 17:48:46 +0200 Subject: [PATCH 13/15] Keep closure validation branch active From e6338c26896679d0c69f4860a4d3841e4d892b64 Mon Sep 17 00:00:00 2001 From: KeyffMS <124252104+KeyffMS@users.noreply.github.com> Date: Wed, 12 Aug 2026 17:50:00 +0200 Subject: [PATCH 14/15] No-op trigger guard From 5f93171d2f2f08fd065daba546bdf3ec12c7f6da Mon Sep 17 00:00:00 2001 From: KeyffMS <124252104+KeyffMS@users.noreply.github.com> Date: Wed, 12 Aug 2026 17:51:18 +0200 Subject: [PATCH 15/15] Stable closure validation trigger