From e4d358eb4534a75f375b007065d332be3f76aea4 Mon Sep 17 00:00:00 2001 From: David Ahmann <46606159+davidahmann@users.noreply.github.com> Date: Tue, 15 Sep 2026 18:11:49 -0400 Subject: [PATCH] fix: publish v0.6.1 directly to latest Signed-off-by: David Ahmann <46606159+davidahmann@users.noreply.github.com> --- AGENTS.md | 7 ++-- README.md | 30 ++++++++------- docs/release.md | 17 ++++++--- docs/releases/v0.6.1.md | 21 ++++++++++ docs/repository-settings.md | 18 ++++----- package-lock.json | 4 +- package.json | 2 +- product/PLAN.md | 11 +++--- product/impacts/RELEASE_V0_6_1.yaml | 33 ++++++++++++++++ product/release-v0.6.1.md | 39 +++++++++++++++++++ product/tasks/RELEASE_V0_6_1.yaml | 59 +++++++++++++++++++++++++++++ scripts/release-workflow-policy.mjs | 15 +++++++- src/version.ts | 2 +- test/release-workflow.test.ts | 15 ++++++++ 14 files changed, 231 insertions(+), 42 deletions(-) create mode 100644 docs/releases/v0.6.1.md create mode 100644 product/impacts/RELEASE_V0_6_1.yaml create mode 100644 product/release-v0.6.1.md create mode 100644 product/tasks/RELEASE_V0_6_1.yaml diff --git a/AGENTS.md b/AGENTS.md index bc6c472..a1f20fa 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -289,9 +289,10 @@ needs its own source authority, environment-policy authorization, and provider readback; never use a wildcard or bypass the reviewer gate. Main branch protections remain unchanged. -The current public version, npm channel pointers, GitHub Latest record, support -tuple, and expiry belong in the current `docs/releases/vX.Y.Z.md` record and -provider readback. They are distribution facts, not authority to broaden +The current npm channel pointers, GitHub Latest record, support tuple and expiry +belong in the protected workflow's final release-evidence asset and provider +readback. New immutable `docs/releases/vX.Y.Z.md` records state only the source +candidate's scope. These are distribution facts, not authority to broaden supported stacks or autonomy. The v0.1.5 verifier remains the workflow's independently pinned policy; do not silently replace it with the newest version. diff --git a/README.md b/README.md index 2f5e59f..0ea82bf 100644 --- a/README.md +++ b/README.md @@ -12,13 +12,14 @@ candidate. A separate read-only pass reviews that exact commit. Only the attended shipper can use your GitHub identity. Draft-only is the default; repositories may explicitly enable a separately approved, exact-plan merge. -Mill `0.6.0` is the published public alpha and GitHub Latest release. npm's -`alpha` tag resolves to `0.6.0`; its `latest` tag still resolves to `0.4.0`. The -tagged `0.5.0` candidate failed before publication because its workflow received -malformed qualification input; its tag and failed run remain preserved evidence. -See the [v0.5.0 release record](docs/releases/v0.5.0.md). The `v0.1.5` genesis -release remains the historical trust root; the `v0.2.0` tag remains preserved -prepublication evidence. +Release channels and exact artifact evidence are facts of a particular +publication. Read the +[latest GitHub release](https://github.com/davidahmann/mill/releases/latest), +its attached `release-evidence-final.json`, and +`npm view @davidahmann/mill dist-tags --json` before selecting a version. GitHub +Latest and npm `latest` are separate provider pointers. The `v0.1.5` genesis +release remains the historical trust root; failed release candidates remain +preserved evidence. ## Why Mill @@ -140,11 +141,13 @@ qualified web recipe. ## Install -Install the current public alpha at its exact version with lifecycle scripts -disabled: +Inspect the available channels, choose a released version, and pin that exact +version with lifecycle scripts disabled. Do not install a floating tag into an +existing repository. ```sh -npm install --save-dev --ignore-scripts @davidahmann/mill@0.6.0 +npm view @davidahmann/mill dist-tags --json +npm install --save-dev --ignore-scripts @davidahmann/mill@ npx --no-install millctl --version ``` @@ -161,11 +164,10 @@ PATH="$node_bin_dir:$PATH" "$node_bin_dir/npm" run build node dist/cli.js --version ``` -The `alpha` tag resolves to `0.6.0`; `latest` still resolves to `0.4.0`. -Downstream repositories should pin the exact version so a later release cannot -alter their delivery machinery implicitly. Updating an existing Mill +Downstream repositories should pin the exact selected version so a later release +cannot alter their delivery machinery implicitly. Updating an existing Mill installation is deliberate: preserve state and repository snapshots, inspect the -release notes, and requalify the changed toolchain. There is no automatic +release evidence, and requalify the changed toolchain. There is no automatic upgrade or proven general downgrade path for operational state. ### Policy starters for downstream repositories diff --git a/docs/release.md b/docs/release.md index eeded34..74eab12 100644 --- a/docs/release.md +++ b/docs/release.md @@ -200,11 +200,18 @@ publishes the normal GitHub Release. ### 5. Close the release -Record the workflow run, tag commit/tree, tarball digest/integrity, npm tarball -and provenance, GitHub Release URL and asset digest, qualification digest, -support tuple, and canary window. Reinstall the exact newly qualified version in -an empty directory with lifecycle scripts disabled and confirm its version and -help. +The protected workflow attaches `release-evidence-final.json` to the normal +GitHub Release after provider readback. It records the workflow runs, tag +commit/tree, tarball digest/integrity, npm tarball and provenance, GitHub +Release URL and asset digests, qualification digest, support tuple, and canary +window. That asset is the canonical provider closure. Reinstall the exact newly +qualified version in an empty directory with lifecycle scripts disabled and +confirm its version and help. + +The immutable `docs/releases/vX.Y.Z.md` file records source scope before +tagging. Do not add a source-only follow-up merely to repeat provider facts +after publication. Link users to the release evidence and require an exact +version pin. The release becomes the trust root for qualifying the next candidate. It does not qualify a new stack, host tuple, worker profile, model identity, or forge. diff --git a/docs/releases/v0.6.1.md b/docs/releases/v0.6.1.md new file mode 100644 index 0000000..13b251e --- /dev/null +++ b/docs/releases/v0.6.1.md @@ -0,0 +1,21 @@ +# Mill v0.6.1 + +`0.6.1` is a public-alpha maintenance-release candidate. It exercises the +protected npm OIDC path that publishes a newly qualified artifact directly to +`latest`. It also makes installation guidance release-stable: users inspect the +live release evidence, choose an exact version, and pin it in their repository. + +## Candidate scope + +The release does not alter Mill's supported recipe, delivery authority, worker +boundary, or public-alpha limits. It does not modify the published `0.6.0` +artifact or its npm tags. It does not create or use a bypass-2FA token. + +## Prepublication record + +This file is part of the immutable release candidate. It records intended scope +before tag creation and publication. The protected release workflow attaches +`release-evidence-final.json` to the public GitHub Release after it verifies the +preserved artifact, npm provenance, registry requalification, the `latest` +channel, and GitHub asset readback. That immutable asset is the canonical +provider closure for this release. diff --git a/docs/repository-settings.md b/docs/repository-settings.md index e13587a..7889854 100644 --- a/docs/repository-settings.md +++ b/docs/repository-settings.md @@ -97,12 +97,12 @@ admission change, not a protection bypass or an npm token grant. Future release tags require their own explicit policy authorization; do not replace the exact tag rules with a wildcard or an unrestricted environment. -## Current distribution channels - -The current release record captures GitHub Latest, npm channel values, and the -named public release identity from provider readback. A later correction to an -existing channel uses the provider's supported maintainer authentication. Do not -create a bypass-2FA token for that purpose. A draft and public release can share -a tag, so recovery must use the public release identity rather than a tag-only -lookup. Channel labels do not expand Mill's qualified public-alpha support tuple -or authorize republishing. +## Distribution channels + +The protected workflow attaches final release evidence with GitHub Latest, npm +channel values and public release identity after provider readback. A later +correction to an existing channel uses the provider's supported maintainer +authentication. Do not create a bypass-2FA token for that purpose. A draft and +public release can share a tag, so recovery must use the public release identity +rather than a tag-only lookup. Channel labels do not expand Mill's qualified +public-alpha support tuple or authorize republishing. diff --git a/package-lock.json b/package-lock.json index 66ad758..9751939 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@davidahmann/mill", - "version": "0.6.0", + "version": "0.6.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@davidahmann/mill", - "version": "0.6.0", + "version": "0.6.1", "bundleDependencies": [ "typescript" ], diff --git a/package.json b/package.json index 1de17ea..eabbc06 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@davidahmann/mill", - "version": "0.6.0", + "version": "0.6.1", "description": "Local-first software factory for new and existing codebases. Turns approved product intent into tested, reviewed PRs with repo-native evidence and explicit human approval for delivery and merge.", "license": "Apache-2.0", "author": "David Ahmann", diff --git a/product/PLAN.md b/product/PLAN.md index 8c8e799..1b9c634 100644 --- a/product/PLAN.md +++ b/product/PLAN.md @@ -48,12 +48,11 @@ reference, confines a second repair to one fixture, limits the packed public API to CLI and schemas, and validates release input encoding. It preserves the v0.5.0 failed candidate as evidence and does not add a GitHub App, second worker, general retry increase, daemon, MCP service, or public support claim. -Version `0.6.0` completed candidate qualification, protected OIDC publication, -registry requalification, and a normal GitHub Release on 2026-09-15. Its npm -`alpha` tag resolves to `0.6.0`; the existing `latest` tag remains `0.4.0` -because npm rejected the later tag change without a TOTP. Mill stores no bypass -token. Future fresh releases publish directly to `latest` through the protected -OIDC workflow. +The v0.6.0 release record retains its candidate qualification, protected OIDC +publication, registry requalification, normal GitHub Release and unchanged npm +channel state. Mill stores no bypass token. Future fresh releases publish +directly to `latest` through the protected OIDC workflow, whose final release +evidence is the canonical provider closure. 1. **Foundation:** repository constitution, exact-version CLI, compact schemas, static source/repository inspection, native CI, and security/release design. diff --git a/product/impacts/RELEASE_V0_6_1.yaml b/product/impacts/RELEASE_V0_6_1.yaml new file mode 100644 index 0000000..10f0707 --- /dev/null +++ b/product/impacts/RELEASE_V0_6_1.yaml @@ -0,0 +1,33 @@ +schemaVersion: "2" +id: mill-release-v0.6.1 +status: approved +approved_by: davidahmann +approval_source: >- + Attended Codex conversation on 2026-09-15: “Ok do what is needed until all is + green,” following explicit authorization for Mill release, npm publication, + GitHub Release creation, documentation updates, and provider readback. +source_base: 3ba27571af6447abf3100b2b35e673031e82fcb7 +authority: product/release-v0.6.1.md +affected_invariants: + - INV-HUMAN-AUTHORITY + - INV-EXACT-EVIDENCE + - INV-DOWNSTREAM-INDEPENDENT +material_changes: + - Advances the package and CLI identity to v0.6.1. + - Exercises protected OIDC publication directly to npm latest with one + preserved qualified artifact. + - Keeps public installation guidance release-stable and assigns exact provider + facts to final release evidence. +affected_surfaces: + - package and CLI version identity + - public installation, release, repository-settings and operator guidance + - exact release authority, npm environment admission and public distribution +verification: + - native check, exact-candidate audit, clean PR review and required checks + - exact annotated-tag identity and two independent candidate builds + - independent policy, registry package, npm provenance/latest and GitHub asset + readback +exceptions: + - The attended maintainer may add the exact v0.6.1 npm-environment tag rule, + create and push the annotated tag, publish one preserved artifact, and + create the normal GitHub Release only as bound by the authority record. diff --git a/product/release-v0.6.1.md b/product/release-v0.6.1.md new file mode 100644 index 0000000..2fb6151 --- /dev/null +++ b/product/release-v0.6.1.md @@ -0,0 +1,39 @@ +# v0.6.1 attended release authority + +## Authorization + +David Ahmann authorized this release in the attended Codex conversation on +2026-09-15: “Ok do what is needed until all is green.” This follows the earlier +explicit authorization for release, npm publication, GitHub Release creation, +and documentation updates. + +The authorization covers one fresh `v0.6.1` public-alpha release from the +reviewed source candidate: an exact GitHub `npm` environment tag rule, an +annotated tag, candidate and protected publish workflows, one preserved npm +artifact, a normal GitHub Release, and provider readback. The source change +prepares version-stable installation and closure documentation. + +It does not authorize a wildcard, bypass-2FA token, weaker trusted publishing, a +change to an existing npm dist-tag, a republish, a change to an older tag or +release, or a broader support claim. + +## Scope and stop conditions + +The source candidate starts from reviewed `main` commit +`3ba27571af6447abf3100b2b35e673031e82fcb7`. Its package and CLI version are +`0.6.1`. The exact annotated tag must bind the reviewed resulting-main tree. + +Stop before publication if the candidate tag, source tree, preserved artifact, +candidate run, qualification, npm provenance, registry readback, `latest` +channel, or GitHub asset identity differs. A failed candidate or uncertain +external effect requires a new reviewed version. It never permits retagging, +republishing, or updating the published `0.6.0` package. + +## Required closure + +The protected workflow must attach `release-evidence-final.json` to the normal +GitHub Release only after provider readback. It records the tag commit and tree, +candidate and publish runs, tarball digest and integrity, qualification digest, +npm provenance and channels, GitHub Release identity and asset digests, and the +exact support tuple. That release asset is the canonical closure; no later +source commit may rewrite the tagged candidate or duplicate provider facts. diff --git a/product/tasks/RELEASE_V0_6_1.yaml b/product/tasks/RELEASE_V0_6_1.yaml new file mode 100644 index 0000000..162aec7 --- /dev/null +++ b/product/tasks/RELEASE_V0_6_1.yaml @@ -0,0 +1,59 @@ +schemaVersion: "2" +task_id: mill-release-v0.6.1-source-preparation +status: closed +owner: davidahmann +base_commit: 3ba27571af6447abf3100b2b35e673031e82fcb7 +execution_mode: approved_native_maintainer +authority: product/release-v0.6.1.md +impact_manifest: product/impacts/RELEASE_V0_6_1.yaml +objective: >- + Prepare the exact v0.6.1 public-alpha source candidate and release-stable + documentation for protected OIDC publication directly to npm latest. +allowed_paths: + - package.json + - package-lock.json + - src/version.ts + - scripts/release-workflow-policy.mjs + - test/release-workflow.test.ts + - README.md + - AGENTS.md + - docs/release.md + - docs/repository-settings.md + - docs/releases/v0.6.1.md + - product/PLAN.md + - product/release-v0.6.1.md + - product/impacts/RELEASE_V0_6_1.yaml + - product/tasks/RELEASE_V0_6_1.yaml +authority_preparation_paths: + - product/** + - docs/releases/** +acceptance_items: + - R061-01 package and CLI identify v0.6.1 + - R061-02 public installation guidance requires a live provider check and an + explicit exact version pin rather than a hard-coded current version + - R061-03 the release runbook, repository settings and operator contract name + final release evidence as the canonical provider closure + - R061-04 native check, exact-candidate audit, complete review and required PR + checks pass + - R061-05 only the release authority may add the exact tag rule, tag, publish + one preserved artifact and create the normal GitHub Release +validation_commands: + - npm run check + - node dist/cli.js --json --cwd . audit + - MILL_RELEASE_TAG=v0.6.1 node scripts/verify-release-tag.mjs +required_reviews: + - required PR checks and GitHub review feedback on the complete committed Mill + release-preparation diff +constraints: + - single attended maintainer writer + - exact v0.6.1 environment-tag admission only; no wildcard or bypass + - preserve all historical tags, npm versions, releases and evidence +stop_conditions: + - ambiguous tag, tree, artifact, candidate-run, provenance or provider effect + - unavailable independent verification or recurring P0/P1 release finding +closure: + status: source_candidate_prepared + provider_closure: >- + The protected release workflow must attach final evidence after its own + provider readback. No post-release source update may alter the tagged + candidate or duplicate those provider facts. diff --git a/scripts/release-workflow-policy.mjs b/scripts/release-workflow-policy.mjs index 205dc71..e14a8a7 100644 --- a/scripts/release-workflow-policy.mjs +++ b/scripts/release-workflow-policy.mjs @@ -139,15 +139,28 @@ export function releasePublicationFailures(jobs) { "publish: GitHub release must be a plainly labelled normal public-alpha release", ); } + const finalEvidenceUpload = + 'gh release upload "$RELEASE_TAG" "$RUNNER_TEMP/release-evidence-final.json"'; + const finalRelease = 'gh release edit "$RELEASE_TAG" --draft=false'; if ( typeof finalize?.run !== "string" || - !finalize.run.includes('gh release edit "$RELEASE_TAG" --draft=false') || + !finalize.run.includes(finalRelease) || finalize.run.includes("--prerelease") ) { failures.push( "publish: final GitHub release must remain a normal public-alpha release", ); } + if ( + typeof finalize?.run !== "string" || + !finalize.run.includes(finalEvidenceUpload) || + finalize.run.indexOf(finalEvidenceUpload) > + finalize.run.indexOf(finalRelease) + ) { + failures.push( + "publish: final release evidence must be attached before publication", + ); + } return failures; } diff --git a/src/version.ts b/src/version.ts index 9bbd7df..760f0d4 100644 --- a/src/version.ts +++ b/src/version.ts @@ -1,3 +1,3 @@ export const MILL_PACKAGE = "@davidahmann/mill"; -export const MILL_VERSION = "0.6.0"; +export const MILL_VERSION = "0.6.1"; export const RESULT_SCHEMA_VERSION = "1"; diff --git a/test/release-workflow.test.ts b/test/release-workflow.test.ts index 34324e1..fc889a3 100644 --- a/test/release-workflow.test.ts +++ b/test/release-workflow.test.ts @@ -99,6 +99,21 @@ describe("release verifier preparation policy", () => { ); }, ); + it("rejects a public release that omits final release evidence", async () => { + const workflow = await fixture(); + const finalize = workflow.jobs.publish?.steps.find( + (entry) => + entry.name === "Read back GitHub Release and finalize evidence", + ); + if (!finalize?.run) throw new Error("missing release finalization fixture"); + finalize.run = finalize.run.replace( + 'gh release upload "$RELEASE_TAG" "$RUNNER_TEMP/release-evidence-final.json"', + "true", + ); + await expect(check(workflow)).rejects.toThrow( + "final release evidence must be attached before publication", + ); + }); it.each(["alpha", "missing-readback"])( "rejects a %s npm latest publication contract", async (mutation) => {