From 4b323224b211156379a63ce0f8a28080433530b7 Mon Sep 17 00:00:00 2001 From: Michel Paulissen <862400+MichelPaulissen@users.noreply.github.com> Date: Fri, 3 Jul 2026 23:12:37 +0200 Subject: [PATCH] Add public CLI-first acceptance gate --- DISASMER_PUBLIC_TREE.json | 4 +- scripts/acceptance-cli-first.sh | 73 ++++++++++++++++++++++++ scripts/acceptance-doc-contract-smoke.js | 6 +- scripts/cli-first-contract-smoke.js | 63 ++++++++++++++++++-- scripts/cli-local-run-smoke.js | 1 + scripts/docs-smoke.js | 3 + 6 files changed, 143 insertions(+), 7 deletions(-) create mode 100755 scripts/acceptance-cli-first.sh diff --git a/DISASMER_PUBLIC_TREE.json b/DISASMER_PUBLIC_TREE.json index a9e8b01..e4ad97d 100644 --- a/DISASMER_PUBLIC_TREE.json +++ b/DISASMER_PUBLIC_TREE.json @@ -1,7 +1,7 @@ { "kind": "disasmer-filtered-public-tree", - "source_commit": "d7700a764f26f3f6963a12f20395e361c66d2a83", - "release_name": "dryrun-d7700a764f26", + "source_commit": "9da7b61194a857d9c16464f07d11ca7ea5c299a0", + "release_name": "dryrun-9da7b61194a8", "filtered_out": [ "private/**", "experiments/**", diff --git a/scripts/acceptance-cli-first.sh b/scripts/acceptance-cli-first.sh new file mode 100755 index 0000000..901b53f --- /dev/null +++ b/scripts/acceptance-cli-first.sh @@ -0,0 +1,73 @@ +#!/usr/bin/env bash +set -euo pipefail + +repo="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +cd "$repo" + +if [[ "${DISASMER_PUBLIC_RELEASE_DRYRUN_E2E:-}" == "1" ]]; then + echo "CLI-first acceptance does not run final public-release e2e; unset DISASMER_PUBLIC_RELEASE_DRYRUN_E2E" >&2 + exit 1 +fi + +if [[ "${DISASMER_PUBLIC_RELEASE_DRYRUN_FINAL:-}" == "1" ]]; then + echo "CLI-first acceptance does not run final public-release evidence; unset DISASMER_PUBLIC_RELEASE_DRYRUN_FINAL" >&2 + exit 1 +fi + +node scripts/acceptance-report.js cli-first +node scripts/cli-first-contract-smoke.js +node scripts/acceptance-report-smoke.js +node scripts/acceptance-doc-contract-smoke.js +node scripts/acceptance-environment-contract-smoke.js +node scripts/acceptance-evidence-contract-smoke.js +node scripts/public-private-boundary-smoke.js +node scripts/release-blocker-smoke.js +node scripts/resource-metering-contract-smoke.js +node scripts/hostile-input-contract-smoke.js +node scripts/tenant-isolation-contract-smoke.js +node scripts/public-story-contract-smoke.js +node scripts/public-release-dryrun-contract-smoke.js +node scripts/public-browser-login-contract-smoke.js +node scripts/self-hosted-coordinator-smoke.js +node scripts/public-local-demo-matrix-smoke.js +scripts/release-source-scan.sh + +if [[ "${DISASMER_CLI_FIRST_PREPARE_PUBLIC_RELEASE:-1}" == "1" ]]; then + node scripts/prepare-public-release-dryrun.js +fi + +cargo fmt --all --check +cargo test --workspace +cargo build --workspace --bins + +node scripts/docs-smoke.js +node scripts/cli-output-mode-smoke.js +node scripts/cli-login-smoke.js +node scripts/cli-error-exit-smoke.js +node scripts/cli-browser-login-flow-smoke.js +node scripts/cli-install-smoke.js +node scripts/user-session-token-boundary-smoke.js +node scripts/sdk-spawn-runtime-smoke.js +node scripts/node-lifecycle-contract-smoke.js +node scripts/wasmtime-node-smoke.js +node scripts/podman-backend-smoke.js +node scripts/vscode-extension-smoke.js +node scripts/vscode-f5-smoke.js +node scripts/node-attach-smoke.js +node scripts/local-services-smoke.js +node scripts/cancellation-smoke.js +node scripts/cli-local-run-smoke.js +node scripts/artifact-download-smoke.js +node scripts/artifact-export-smoke.js +node scripts/operator-panel-smoke.js +node scripts/source-preparation-smoke.js +node scripts/scheduler-placement-smoke.js +node scripts/windows-best-effort-smoke.js +node scripts/windows-validation-contract-smoke.js +node scripts/quic-smoke.js +node scripts/dap-smoke.js +node scripts/flagship-demo-smoke.js + +if [[ "${DISASMER_CLI_FIRST_INCLUDE_PRIVATE:-0}" == "1" ]]; then + scripts/acceptance-private.sh +fi diff --git a/scripts/acceptance-doc-contract-smoke.js b/scripts/acceptance-doc-contract-smoke.js index dcd38c9..e2d8c47 100755 --- a/scripts/acceptance-doc-contract-smoke.js +++ b/scripts/acceptance-doc-contract-smoke.js @@ -35,10 +35,12 @@ function assertNoOpenCriteria(source, name) { const phase2 = read("acceptance_criteria_phase2.md"); const base = read("acceptance_criteria.md"); +const cliFirst = read("cli_acceptance_criteria.md"); const docsSmoke = read("scripts/docs-smoke.js"); const releaseBlockerSmoke = read("scripts/release-blocker-smoke.js"); const publicAcceptance = read("scripts/acceptance-public.sh"); const privateAcceptance = read("scripts/acceptance-private.sh"); +const cliFirstAcceptance = read("scripts/acceptance-cli-first.sh"); const publicSplit = read("scripts/verify-public-split.sh"); assert.match( @@ -60,12 +62,13 @@ assert.match( for (const [source, name] of [ [base, "acceptance_criteria.md"], [phase2, "acceptance_criteria_phase2.md"], + [cliFirst, "cli_acceptance_criteria.md"], ]) { assertEveryCriterionHasStatus(source, name); assertNoOpenCriteria(source, name); } -for (const file of ["MVP.md", "acceptance_criteria.md", "acceptance_criteria_phase2.md"]) { +for (const file of ["MVP.md", "acceptance_criteria.md", "acceptance_criteria_phase2.md", "cli_acceptance_criteria.md"]) { assert( docsSmoke.includes(`"${file}"`), `docs smoke must include ${file} as user-facing acceptance context` @@ -100,6 +103,7 @@ for (const [source, name] of [ for (const [scriptName, script] of [ ["public acceptance", publicAcceptance], ["private acceptance", privateAcceptance], + ["CLI-first acceptance", cliFirstAcceptance], ["public split", publicSplit], ]) { assert( diff --git a/scripts/cli-first-contract-smoke.js b/scripts/cli-first-contract-smoke.js index b9a3b2d..50c5acd 100644 --- a/scripts/cli-first-contract-smoke.js +++ b/scripts/cli-first-contract-smoke.js @@ -33,6 +33,7 @@ function expect(source, name, pattern) { const criteria = read("cli_acceptance_criteria.md"); const cli = read("crates/disasmer-cli/src/main.rs"); const coordinator = read("crates/disasmer-coordinator/src/service.rs"); +const cliFirstAcceptance = read("scripts/acceptance-cli-first.sh"); const outputModeSmoke = read("scripts/cli-output-mode-smoke.js"); const errorExitSmoke = read("scripts/cli-error-exit-smoke.js"); @@ -71,10 +72,64 @@ for (const line of lines) { const openCriteria = lines.filter((line) => /\*\*Open(?::| \()/.test(line)); assert.deepStrictEqual( openCriteria, - [ - "- [ ] **Open:** Every criterion in this document is validated end-to-end or with integration-style coverage, preferably against a realistic NixOS deployment that can pretend to be live hosted infrastructure.", - ], - "only the full CLI-first verification gate should remain Open while command/API facts are Partial" + [], + "CLI-first criteria should not leave Open items once the non-e2e gate exists; remaining unfinished facts stay Partial" +); + +expect( + criteria, + "CLI-first non-e2e gate wording", + /scripts\/acceptance-cli-first\.sh[\s\S]*final public-release e2e remains intentionally excluded/ +); +expect( + cliFirstAcceptance, + "CLI-first acceptance report", + /node scripts\/acceptance-report\.js cli-first/ +); +expect( + cliFirstAcceptance, + "CLI-first acceptance refuses final e2e", + /DISASMER_PUBLIC_RELEASE_DRYRUN_E2E[\s\S]*does not run final public-release e2e/ +); +expect( + cliFirstAcceptance, + "CLI-first acceptance refuses final evidence", + /DISASMER_PUBLIC_RELEASE_DRYRUN_FINAL[\s\S]*does not run final public-release evidence/ +); +expect( + cliFirstAcceptance, + "CLI-first acceptance composes public API contracts", + /node scripts\/cli-output-mode-smoke\.js[\s\S]*node scripts\/cli-login-smoke\.js[\s\S]*node scripts\/cli-error-exit-smoke\.js[\s\S]*node scripts\/cli-browser-login-flow-smoke\.js/ +); +expect( + cliFirstAcceptance, + "CLI-first acceptance composes service boundary checks", + /node scripts\/local-services-smoke\.js[\s\S]*node scripts\/cli-local-run-smoke\.js/ +); +expect( + cliFirstAcceptance, + "CLI-first acceptance composes self-hosted checks", + /node scripts\/self-hosted-coordinator-smoke\.js/ +); +expect( + cliFirstAcceptance, + "CLI-first acceptance composes debug and artifact checks", + /node scripts\/vscode-f5-smoke\.js[\s\S]*node scripts\/artifact-download-smoke\.js[\s\S]*node scripts\/artifact-export-smoke\.js/ +); +expect( + cliFirstAcceptance, + "CLI-first acceptance composes DAP checks", + /node scripts\/dap-smoke\.js/ +); +expect( + cliFirstAcceptance, + "CLI-first acceptance can include private hosted gate", + /DISASMER_CLI_FIRST_INCLUDE_PRIVATE[\s\S]*scripts\/acceptance-private\.sh/ +); +assert.doesNotMatch( + cliFirstAcceptance, + /node scripts\/public-release-dryrun-e2e\.js|node scripts\/public-release-dryrun-final-evidence\.js/, + "CLI-first non-e2e gate must not invoke final public release e2e or final evidence verifier" ); for (const [name, pattern] of [ diff --git a/scripts/cli-local-run-smoke.js b/scripts/cli-local-run-smoke.js index d9ce170..8bfa97c 100755 --- a/scripts/cli-local-run-smoke.js +++ b/scripts/cli-local-run-smoke.js @@ -123,6 +123,7 @@ function runCli(args, env = {}) { assert.strictEqual(report.plan.entry, "build"); assert.deepStrictEqual(report.plan.session, { AgentPublicKey: { + agent: "agent", public_key_fingerprint: sha256(agentPublicKey), browser_interaction_required: false } diff --git a/scripts/docs-smoke.js b/scripts/docs-smoke.js index f63529f..4af5666 100644 --- a/scripts/docs-smoke.js +++ b/scripts/docs-smoke.js @@ -11,6 +11,7 @@ const userFacingDocs = [ "MVP.md", "acceptance_criteria.md", "acceptance_criteria_phase2.md", + "cli_acceptance_criteria.md", ].map((file) => [file, fs.readFileSync(path.join(repo, file), "utf8")]); const publicAcceptance = fs.readFileSync( path.join(repo, "scripts/acceptance-public.sh"), @@ -48,6 +49,8 @@ const requiredReadmePatterns = [ ["artifact download smoke", /node scripts\/artifact-download-smoke\.js/], ["artifact export smoke", /node scripts\/artifact-export-smoke\.js/], ["acceptance report smoke", /node scripts\/acceptance-report-smoke\.js/], + ["CLI-first acceptance gate", /scripts\/acceptance-cli-first\.sh/], + ["CLI-first acceptance before e2e", /CLI-first non-e2e gate before any final public-release e2e attempt/], ["public private boundary smoke", /node scripts\/public-private-boundary-smoke\.js/], ["release blocker smoke", /node scripts\/release-blocker-smoke\.js/], ["explicit export", /attached receiver node or user-provided\s+storage integration/],