diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index d477b50..a33af98 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -5,7 +5,7 @@ }, "metadata": { "description": "Content-readiness lint with an evidence-bounded SEO experiment ledger", - "version": "0.10.0" + "version": "0.11.0" }, "plugins": [ { diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json index d28b347..e59fa2b 100644 --- a/.claude-plugin/plugin.json +++ b/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "geoptimize", "description": "Content-readiness lint with an evidence-bounded SEO experiment ledger", - "version": "0.10.0", + "version": "0.11.0", "author": { "name": "Te-Shu Wang" }, diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6e3a8eb..ee559ca 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -113,7 +113,7 @@ jobs: with: path: .github/fixtures/action-low min-score: '100' - package-spec: ./geoptimize-0.10.0.tgz + package-spec: ./geoptimize-0.11.0.tgz - name: Validate Action outputs env: @@ -130,7 +130,7 @@ jobs: uses: ./ with: path: examples/github-action-sample/site - package-spec: ./geoptimize-0.10.0.tgz + package-spec: ./geoptimize-0.11.0.tgz - name: Validate sample outputs env: @@ -149,7 +149,7 @@ jobs: path: .github/fixtures/action-low min-score: '0' fail-on-low-score: 'true' - package-spec: ./geoptimize-0.10.0.tgz + package-spec: ./geoptimize-0.11.0.tgz - name: Validate blocking outputs env: @@ -169,7 +169,7 @@ jobs: path: .github/fixtures/action-low min-score: '100' fail-on-low-score: 'true' - package-spec: ./geoptimize-0.10.0.tgz + package-spec: ./geoptimize-0.11.0.tgz - name: Invalid choice is rejected id: invalid-choice @@ -178,7 +178,7 @@ jobs: with: path: .github/fixtures/action-low fail-on-low-score: sometimes - package-spec: ./geoptimize-0.10.0.tgz + package-spec: ./geoptimize-0.11.0.tgz - name: Out-of-range threshold is rejected id: invalid-threshold @@ -187,7 +187,7 @@ jobs: with: path: .github/fixtures/action-low min-score: '101' - package-spec: ./geoptimize-0.10.0.tgz + package-spec: ./geoptimize-0.11.0.tgz - name: Assert expected failures env: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 15cd707..6a0586f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -64,7 +64,7 @@ jobs: subject-path: ${{ runner.temp }}/release-assets/geoptimize-*.tgz - name: Stage all assets in a draft release run: | - gh release create "$RELEASE_TAG" --verify-tag --draft --title "geoptimize ${RELEASE_TAG#v}" --notes-file docs/release-notes-v0.10.md + gh release create "$RELEASE_TAG" --verify-tag --draft --title "geoptimize ${RELEASE_TAG#v}" --notes-file docs/release-notes-v0.11.md gh release upload "$RELEASE_TAG" "$RUNNER_TEMP/release-assets/"*.tgz "$RUNNER_TEMP/release-assets/SHA256SUMS" "$RUNNER_TEMP/release-assets/"*.spdx.json - name: Publish the verified tarball using npm OIDC run: | diff --git a/CHANGELOG.md b/CHANGELOG.md index a51746d..aadcf9c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ All notable user-visible changes will be documented here. The project follows Semantic Versioning after the v0.6 evidence baseline is released. -## Unreleased +## 0.11.0 (2026-09-13) ### Added @@ -24,8 +24,8 @@ All notable user-visible changes will be documented here. The project follows Se ### Documentation -- Updated current-state documentation after the verified v0.10.0 publication. -- Aligned migration, maintainer-security, OpenSSF, Action sample, and plugin descriptions with the published release. +- Updated installation and migration instructions for v0.11.0 while retaining historical release evidence. +- Aligned CLI, plugin, and Action versions with v0.11.0. - Completed both Claude Code installation steps in the English and translated guides and recorded directory submission results. - Replaced the unsupported hosted-platform price estimate with vendor-specific pricing wording. diff --git a/README.md b/README.md index 7615cff..727972b 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ npx geoptimize audit https://example.com --json npx geoptimize audit-site https://example.com --max-pages 20 --json ``` -The next release adds a terminal menu for scanning a target and saving an HTML report. See [the interactive CLI guide](docs/interactive-cli.md) for development-checkout usage; published `0.10.0` uses the explicit commands above. +Version 0.11.0 adds a guided terminal menu for scanning a target and saving an offline HTML report. See [the interactive CLI guide](docs/interactive-cli.md) for `npm install` and `npx` usage; explicit commands remain available for scripts and non-TTY environments. For measured Google Search experiments, initialize the separate SEO ledger: @@ -201,7 +201,7 @@ node -e "const r=require('./geoptimize-report.json'); process.exit(r.overall.tot The [GitHub Marketplace Action](https://github.com/marketplace/actions/geoptimize-content-readiness-check) is advisory by default. It reports findings without blocking the workflow: ```yaml -- uses: cucuwang/geoptimize@v0.10.0 +- uses: cucuwang/geoptimize@v0.11.0 with: path: dist ``` @@ -209,7 +209,7 @@ The [GitHub Marketplace Action](https://github.com/marketplace/actions/geoptimiz Projects can explicitly choose blocking mode after accepting a baseline: ```yaml -- uses: cucuwang/geoptimize@v0.10.0 +- uses: cucuwang/geoptimize@v0.11.0 with: path: dist fail-on-low-score: 'true' @@ -333,13 +333,13 @@ npx skills add cucuwang/geoptimize ## Project status -Version 0.10.0 is published on [npm](https://www.npmjs.com/package/geoptimize) and [GitHub](https://github.com/cucuwang/geoptimize/releases/tag/v0.10.0). It adds a separate, evidence-bounded SEO experiment ledger while retaining the existing readiness score and audit contracts. Release acceptance and rollback are documented in [docs/release-v0.10.md](docs/release-v0.10.md); longer-term adoption work remains in [ROADMAP.md](ROADMAP.md). +Version 0.11.0 adds a guided terminal menu for saving offline HTML reports, updates supported dependencies, and improves public release verification. The readiness score and existing audit contracts remain unchanged. See the [release notes](https://github.com/cucuwang/geoptimize/releases/tag/v0.11.0), [release runbook](docs/release-v0.11.md), and [roadmap](ROADMAP.md). Contributions are welcome. Rule changes require an evidence note and positive/negative fixtures; see [CONTRIBUTING.md](CONTRIBUTING.md). Report vulnerabilities through the process in [SECURITY.md](SECURITY.md). ## Release integrity and security maintenance -The v0.10 trust-hardening and release path is documented in [the v0.10 runbook](docs/release-v0.10.md). +The v0.11 release path is documented in [the v0.11 runbook](docs/release-v0.11.md). The v0.10 runbook remains the historical record for the verified v0.10.0 release. CI validates Node 22/24 tarballs, package contents and CLI/Action contracts; the release preparation exports SHA-256 checksums and an SPDX production-dependency SBOM. Repository settings and npm authorization remain explicit [maintainer gates](docs/maintainer-security-settings.md). diff --git a/ROADMAP.md b/ROADMAP.md index 313967e..2f42919 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -39,3 +39,11 @@ Version 0.10.0 is published with npm OIDC provenance, an SSH-signed immutable ta SHA-256 checksums, an SPDX SBOM and a GitHub artifact attestation. OpenSSF Passing remains pending assessment. Bundled Action runtime evaluation is tracked separately to preserve the package-spec contract. See [release-v0.10](docs/release-v0.10.md). + +## v0.11 Guided terminal reports + +Version 0.11.0 adds a terminal menu for choosing a scan target and saving an offline +HTML report. Explicit commands and the existing scoring and JSON contracts remain +available. The release also updates supported dependencies and adds bounded npm +visibility polling to the existing publication verifier. See the +[v0.11 release runbook](docs/release-v0.11.md). diff --git a/SECURITY.md b/SECURITY.md index 06ddaea..2d18da1 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -22,6 +22,6 @@ triage. Configuration alone does not establish a clean scan or certification. Automated releases use npm OIDC, tarball attestations, checksums and a locked production SBOM. Version 0.10.0 is the first release published through this path. -Follow [release verification](docs/release-v0.10.md) and [maintainer security +Follow [release verification](docs/release-v0.11.md) and [maintainer security settings](docs/maintainer-security-settings.md). Earlier releases are not retroactively signed or attested. No long-lived npm credential is required. diff --git a/action.yml b/action.yml index 16fdccc..854a41a 100644 --- a/action.yml +++ b/action.yml @@ -21,7 +21,7 @@ inputs: package-spec: description: npm package spec to install; keep the default outside prerelease testing required: false - default: 'geoptimize@0.10.0' + default: 'geoptimize@0.11.0' outputs: score: diff --git a/action/action.yml b/action/action.yml index cdb7b57..0287317 100644 --- a/action/action.yml +++ b/action/action.yml @@ -20,7 +20,7 @@ inputs: package-spec: description: npm package spec to install; keep the default outside prerelease testing required: false - default: 'geoptimize@0.10.0' + default: 'geoptimize@0.11.0' outputs: score: diff --git a/docs/interactive-cli.md b/docs/interactive-cli.md index 78a35e3..74d98f9 100644 --- a/docs/interactive-cli.md +++ b/docs/interactive-cli.md @@ -1,8 +1,13 @@ # Interactive CLI -**Unreleased development checkout.** The interactive flow described here is not included in the published `geoptimize@0.10.0` package. +The guided flow is included in `geoptimize@0.11.0`. Install the package and run the bare command: -When the CLI is run directly with no arguments, and both standard input and standard output are TTYs, it offers a short guided flow for scanning one target and writing an offline HTML report: +```bash +npm install --save-dev geoptimize@0.11.0 +npx --no-install geoptimize +``` + +When the CLI is run directly with no arguments, and both standard input and standard output are TTYs, it offers a short guided flow for scanning one target and writing an offline HTML report. To run it from a development checkout: ```bash npm run build @@ -13,4 +18,4 @@ The flow lets the operator choose a website URL, a local HTML or Markdown file, Enter `b` or `back` to return to the previous menu, or `c`, `cancel`, `q`, or `quit` to leave the flow. At any prompt, EOF or Ctrl-C leaves without creating a report. Before scanning starts, the prompt closes; Ctrl-C during the scan is then handled by the normal process interrupt. EOF after that point is no longer a prompt cancellation. A scan that returns no pages is reported as an error and cannot produce an empty success report. -Explicit commands and flags keep their existing Commander behaviour. The menu is not entered for `--help`, `--version`, or non-TTY invocation. After a release that includes this flow, all three package aliases, `geoptimize`, `geo`, and `geo-cli`, will support the same entry point. URL and directory results retain the scanner's evidence and coverage limits; the guided flow does not turn a bounded scan into a complete site audit. +Explicit commands and flags keep their existing Commander behaviour. The menu is not entered for `--help`, `--version`, or non-TTY invocation. All three package aliases, `geoptimize`, `geo`, and `geo-cli`, support the same entry point in the v0.11.0 release. URL and directory results retain the scanner's evidence and coverage limits; the guided flow does not turn a bounded scan into a complete site audit. diff --git a/docs/migrating-from-aeoptimize.md b/docs/migrating-from-aeoptimize.md index 30d1ad0..41be075 100644 --- a/docs/migrating-from-aeoptimize.md +++ b/docs/migrating-from-aeoptimize.md @@ -2,7 +2,7 @@ `geoptimize` continues the same project previously published as `aeoptimize`. Version 0.7.0 was released under the old npm name; version 0.8.0 is the first release under the new name. The GitHub repository retains the project history, issues, releases, and stars. -[geoptimize on npm](https://www.npmjs.com/package/geoptimize) · [aeoptimize on npm](https://www.npmjs.com/package/aeoptimize) · [v0.7.0 release](https://github.com/cucuwang/geoptimize/releases/tag/v0.7.0) · [current release](https://github.com/cucuwang/geoptimize/releases/tag/v0.10.0) +[geoptimize on npm](https://www.npmjs.com/package/geoptimize) · [aeoptimize on npm](https://www.npmjs.com/package/aeoptimize) · [v0.7.0 release](https://github.com/cucuwang/geoptimize/releases/tag/v0.7.0) · [current release](https://github.com/cucuwang/geoptimize/releases/tag/v0.11.0) ## Update an existing project @@ -10,7 +10,7 @@ If the old package installed a pre-commit hook, remove that hook before uninstal ```bash npm uninstall aeoptimize -npm install --save-dev geoptimize@0.10.0 +npm install --save-dev geoptimize@0.11.0 ``` | Integration | aeoptimize 0.7.0 | geoptimize 0.8.0 and later | @@ -19,7 +19,7 @@ npm install --save-dev geoptimize@0.10.0 | CLI commands | `aeoptimize`, `aeo`, `aeo-cli` | `geoptimize`, `geo`, `geo-cli` | | Vite import | `aeoPlugin` from `aeoptimize/vite` | `geoPlugin` from `geoptimize/vite` | | Next.js import | `withAeo` from `aeoptimize/next` | `withGeo` from `geoptimize/next` | -| GitHub Action | `cucuwang/aeoptimize@v0.7.0` | `cucuwang/geoptimize@v0.10.0` | +| GitHub Action | `cucuwang/aeoptimize@v0.7.0` | `cucuwang/geoptimize@v0.11.0` | | Bundled skills | `aeo-scan`, `aeo-generate`, `aeo-transform` | `geo-scan`, `geo-generate`, `geo-transform` | | Generated schema directory | `_aeo` | `_geo` | @@ -34,7 +34,7 @@ npx --no-install geoptimize --version npx --no-install geoptimize audit-build ./dist --json ``` -The installed version should be `0.10.0`. Build the consuming project and review its output after updating Vite or Next.js imports. Deterministic scoring and audit evidence contracts are preserved across the rename. +The installed version should be `0.11.0`. Build the consuming project and review its output after updating Vite or Next.js imports. Deterministic scoring and audit evidence contracts are preserved across the rename. ## Package history and download counts diff --git a/docs/readme/README.de.md b/docs/readme/README.de.md index 716cc12..1dda8d7 100644 --- a/docs/readme/README.de.md +++ b/docs/readme/README.de.md @@ -54,7 +54,7 @@ Die Daten liegen in `data/seo/queries.json`, `observations.json` und `experiment Die GitHub Action liefert standardmäßig Hinweise. Nachdem ein Team den Ausgangswert akzeptiert hat, kann es einen Mindestwert zum Blockieren von Regressionen setzen. ```yaml -- uses: cucuwang/geoptimize@v0.10.0 +- uses: cucuwang/geoptimize@v0.11.0 with: path: dist ``` diff --git a/docs/readme/README.es.md b/docs/readme/README.es.md index af65cc0..4de7933 100644 --- a/docs/readme/README.es.md +++ b/docs/readme/README.es.md @@ -54,7 +54,7 @@ Los datos se guardan en `data/seo/queries.json`, `observations.json` y `experime La GitHub Action es informativa de forma predeterminada. Después de aceptar una línea base, el equipo puede configurar una puntuación mínima para bloquear regresiones. ```yaml -- uses: cucuwang/geoptimize@v0.10.0 +- uses: cucuwang/geoptimize@v0.11.0 with: path: dist ``` diff --git a/docs/readme/README.fr.md b/docs/readme/README.fr.md index 0c187ff..c3814d6 100644 --- a/docs/readme/README.fr.md +++ b/docs/readme/README.fr.md @@ -54,7 +54,7 @@ Les données sont enregistrées dans `data/seo/queries.json`, `observations.json La GitHub Action fournit des résultats consultatifs par défaut. Après validation d'une référence, l'équipe peut définir un score minimal pour bloquer les régressions. ```yaml -- uses: cucuwang/geoptimize@v0.10.0 +- uses: cucuwang/geoptimize@v0.11.0 with: path: dist ``` diff --git a/docs/readme/README.ja.md b/docs/readme/README.ja.md index ef3d78a..5db0c94 100644 --- a/docs/readme/README.ja.md +++ b/docs/readme/README.ja.md @@ -54,7 +54,7 @@ geo seo status . GitHub Action は既定で助言のみを行います。チームが基準値を確認した後、最低スコアを設定して回帰をブロックできます。 ```yaml -- uses: cucuwang/geoptimize@v0.10.0 +- uses: cucuwang/geoptimize@v0.11.0 with: path: dist ``` diff --git a/docs/readme/README.ko.md b/docs/readme/README.ko.md index 34029d4..cb3a192 100644 --- a/docs/readme/README.ko.md +++ b/docs/readme/README.ko.md @@ -54,7 +54,7 @@ geo seo status . GitHub Action은 기본적으로 권고 결과만 제공합니다. 팀에서 기준값을 승인한 뒤 최소 점수로 회귀를 차단할 수 있습니다. ```yaml -- uses: cucuwang/geoptimize@v0.10.0 +- uses: cucuwang/geoptimize@v0.11.0 with: path: dist ``` diff --git a/docs/readme/README.pt-BR.md b/docs/readme/README.pt-BR.md index 7a01d4d..055e165 100644 --- a/docs/readme/README.pt-BR.md +++ b/docs/readme/README.pt-BR.md @@ -54,7 +54,7 @@ Os dados ficam em `data/seo/queries.json`, `observations.json` e `experiments.js A GitHub Action fornece resultados consultivos por padrão. Depois que a equipe aceitar uma linha de base, ela pode definir uma pontuação mínima para bloquear regressões. ```yaml -- uses: cucuwang/geoptimize@v0.10.0 +- uses: cucuwang/geoptimize@v0.11.0 with: path: dist ``` diff --git a/docs/readme/README.zh-CN.md b/docs/readme/README.zh-CN.md index 05dee19..04c7c0b 100644 --- a/docs/readme/README.zh-CN.md +++ b/docs/readme/README.zh-CN.md @@ -54,7 +54,7 @@ geo seo status . GitHub Action 默认提供建议性检查。团队接受基准后,可以设置最低分数来阻止回归。 ```yaml -- uses: cucuwang/geoptimize@v0.10.0 +- uses: cucuwang/geoptimize@v0.11.0 with: path: dist ``` diff --git a/docs/readme/README.zh-TW.md b/docs/readme/README.zh-TW.md index b6279db..5900094 100644 --- a/docs/readme/README.zh-TW.md +++ b/docs/readme/README.zh-TW.md @@ -54,7 +54,7 @@ geo seo status . GitHub Action 預設提供建議性檢查。團隊接受基準後,可設定最低分數來阻擋回歸。 ```yaml -- uses: cucuwang/geoptimize@v0.10.0 +- uses: cucuwang/geoptimize@v0.11.0 with: path: dist ``` diff --git a/docs/release-notes-v0.11.md b/docs/release-notes-v0.11.md new file mode 100644 index 0000000..d86d9a7 --- /dev/null +++ b/docs/release-notes-v0.11.md @@ -0,0 +1,31 @@ +# geoptimize 0.11.0 + +## Guided interactive CLI + +- Run `geoptimize`, `geo`, or `geo-cli` without arguments in a TTY to open a guided flow for scanning a website URL, local HTML or Markdown file, or local directory. +- The flow runs a detailed scan and writes the same self-contained offline HTML report used by `geoptimize report`. +- Existing output files are preserved. Cancel, EOF, Ctrl-C at a prompt, scan errors, and empty scans do not create a report. +- Explicit commands, JSON output, `--help`, `--version`, and non-TTY invocation keep their existing behavior. + +## Compatibility and maintenance + +- Supports Node.js 22.12 and newer, with Node 24 type definitions retained. +- Updates Puppeteer Core, Chalk, Commander, and Vitest within the supported runtime range. +- Adds bounded retry for temporary npm visibility delays and verifies packages against their exact release source. +- Keeps the deterministic readiness score, existing audit JSON contracts, and composite Action scoring contracts unchanged. +- Clarifies how bundled skills handle untrusted page content, repositories, and scan reports within the approved task scope. + +## Install + +```bash +npm install --save-dev geoptimize@0.11.0 +npx geoptimize +``` + +To use the Action in a workflow: + +```yaml +- uses: cucuwang/geoptimize@v0.11.0 + with: + path: dist +``` diff --git a/docs/release-v0.11.md b/docs/release-v0.11.md new file mode 100644 index 0000000..9ffa28e --- /dev/null +++ b/docs/release-v0.11.md @@ -0,0 +1,86 @@ +# v0.11 release runbook + +Version 0.11.0 adds guided terminal reports while preserving the readiness score, +existing JSON output, and composite Action scoring contracts. The previous stable +release is 0.10.0. Public-facing changes belong in [release notes](release-notes-v0.11.md). + +## Candidate acceptance + +Start from a committed, clean checkout. The release version must agree across the +package and lockfile, CLI, plugin metadata, both Action defaults, sample workflow, +and CI tarball paths. The reusable CI workflow runs on Node 22 and 24 and requires +byte-identical tarballs. It checks tests, TypeScript, Action behavior, npm audit, +package contents, clean consumer installation, all three CLI aliases, and report +and SEO ledger contracts. + +Local candidate export on either supported runtime: + +```bash +npm ci +release_dir=$(mktemp -d) +RELEASE_MANIFEST_OUT="$release_dir/candidate.json" \ +RELEASE_TARBALL_OUT="$release_dir/geoptimize-0.11.0.tgz" npm run release:check +node scripts/prepare-release-artifacts.mjs "$release_dir" +(cd "$release_dir" && shasum -a 256 --check SHA256SUMS) +npm pack "$release_dir/geoptimize-0.11.0.tgz" --dry-run --ignore-scripts --json +``` + +PR CI exercises the same non-publishing path and retains the exact verified tarball, +its checksum manifest, and an SPDX 2.3 production-dependency SBOM. Publication uses +that artifact without rebuilding it. The interactive flow also needs a real TTY +smoke check, including cancellation and protection of existing output files. + +## Publish v0.11.0 + +1. Confirm the [maintainer gates](maintainer-security-settings.md), the publication + authorization, an unused npm version and tag, and green PR checks. Merge the + release preparation and fetch the exact current `main` commit. +2. Create an annotated SSH-signed `v0.11.0` tag for that commit using the approved + signing identity. Push the tag and verify GitHub reports a valid signature and + the same target commit. Preserve existing tags and releases. +3. Dispatch `.github/workflows/release.yml` from `main` with `publish=true` and + `tag=v0.11.0`. The `npm-release` environment and `RELEASE_ENABLED` gate apply. +4. The workflow revalidates both Node candidates, checks the signed tag and exact + main SHA, rejects an existing npm version, and verifies artifact hashes. +5. It attests the tarball, stages a draft GitHub Release with all assets, publishes + the verified tarball through npm OIDC, then finalizes the immutable release. + +The default manual dispatch keeps `publish=false` for packaging checks. Tag pushes +alone do not publish. The workflow uses `npm publish --ignore-scripts` only for the +already-tested tarball; the candidate gates have executed explicitly. Never bypass the exact-main, signed-tag, or unused-version gates. + +## Publication verification + +Read back the release workflow, non-draft immutable GitHub Release, signed tag, +npm `latest`, and exact `geoptimize@0.11.0` package. Download the released tarball, +`SHA256SUMS`, and `geoptimize-0.11.0.spdx.json`, then check their actual bytes. +Verify the tarball attestation against this repository and the release source SHA. + +```bash +bash scripts/verify-release-public.sh +gh attestation verify geoptimize-0.11.0.tgz --repo cucuwang/geoptimize \ + --signer-workflow cucuwang/geoptimize/.github/workflows/release.yml +``` + +The public verifier archives the exact release source and uses its original lockfile. +It retries temporary registry visibility delays only. Identity, hash, tag, and CLI +mismatches fail immediately. Confirm the README renders on npm and run the installed +public package in a real TTY to create and inspect a new HTML report. + +## Rollback and recovery + +If npm publication fails, retain the staged draft and inspect the failure. If npm +succeeds but GitHub finalization or verification fails, verify the existing package +and draft assets before finishing that same release. Do not publish the version again. +An existing version, moved main, or mismatched source requires investigation. + +Published versions, finalized assets, and signed tags remain immutable. With explicit +rollback authorization, restore the previous stable default and deprecate 0.11.0 while +preparing a corrective release: + +```bash +npm dist-tag add geoptimize@0.10.0 latest +npm deprecate geoptimize@0.11.0 "Use 0.10.0 while a corrective release is prepared." +``` + +Preserve the failed release's evidence and fix forward; do not replace its artifacts. diff --git a/examples/github-action-sample/.github/workflows/geoptimize.yml b/examples/github-action-sample/.github/workflows/geoptimize.yml index f535c70..ed9d62f 100644 --- a/examples/github-action-sample/.github/workflows/geoptimize.yml +++ b/examples/github-action-sample/.github/workflows/geoptimize.yml @@ -14,7 +14,7 @@ jobs: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false - - uses: cucuwang/geoptimize@v0.10.0 + - uses: cucuwang/geoptimize@v0.11.0 with: path: site fail-on-low-score: 'false' diff --git a/examples/github-action-sample/README.md b/examples/github-action-sample/README.md index 0c774c1..cfd835e 100644 --- a/examples/github-action-sample/README.md +++ b/examples/github-action-sample/README.md @@ -6,5 +6,5 @@ This directory is a copyable end-to-end sample for the v0.6 Action contract. - `site/index.html` is a deterministic public input. - The Action is advisory by default. The sample does not block a pull request on an unreviewed score threshold. -The workflow pins the published `geoptimize@0.10.0` package through the immutable -`v0.10.0` Git tag. Both artifacts were verified against the same release commit. +The workflow pins `geoptimize@0.11.0` through the immutable `v0.11.0` Git tag. +Change this exact version only when deliberately adopting another release. diff --git a/package-lock.json b/package-lock.json index 93b2bfc..218cdff 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "geoptimize", - "version": "0.10.0", + "version": "0.11.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "geoptimize", - "version": "0.10.0", + "version": "0.11.0", "license": "MIT", "dependencies": { "chalk": "^6.0.0", diff --git a/package.json b/package.json index 9d09ba4..51c7a3d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "geoptimize", - "version": "0.10.0", + "version": "0.11.0", "description": "Deterministic content-readiness lint for static websites and documentation", "type": "module", "main": "./dist/core/index.js", @@ -46,7 +46,9 @@ "docs/openssf-best-practices.md", "docs/action-reproducibility.md", "docs/interactive-cli.md", - "scripts/verify-release-public.sh" + "scripts/verify-release-public.sh", + "docs/release-v0.11.md", + "docs/release-notes-v0.11.md" ], "scripts": { "build": "tsc", diff --git a/scripts/verify-release-candidate.sh b/scripts/verify-release-candidate.sh index 91d3c97..915ed3a 100755 --- a/scripts/verify-release-candidate.sh +++ b/scripts/verify-release-candidate.sh @@ -71,6 +71,10 @@ jq -e ' (.[0].files | map(.path) | index("dist/core/seo-experiments.js")) != null and (.[0].files | map(.path) | index("docs/release-v0.9.md")) != null and (.[0].files | map(.path) | index("docs/release-v0.10.md")) != null and + (.[0].files | map(.path) | index("docs/release-v0.11.md")) != null and + (.[0].files | map(.path) | index("docs/release-notes-v0.11.md")) != null and + (.[0].files | map(.path) | index("docs/interactive-cli.md")) != null and + (.[0].files | map(.path) | index("dist/cli/interactive.js")) != null and (.[0].files | map(.path) | index("docs/seo-experiment-ledger.md")) != null and (.[0].files | map(.path) | index("skills/seo-experiment-ledger/SKILL.md")) != null and (.[0].files | map(.path) | index("docs/readme/README.zh-TW.md")) != null and diff --git a/src/cli/index.ts b/src/cli/index.ts index db8a9d2..2ae4c20 100644 --- a/src/cli/index.ts +++ b/src/cli/index.ts @@ -37,7 +37,7 @@ const program = new Command(); program .name('geoptimize') .description('Deterministic content-readiness lint for websites and documentation') - .version('0.10.0'); + .version('0.11.0'); // ── scan command ─────────────────────────────────────────────────── diff --git a/src/core/__tests__/evidence-boundaries.test.ts b/src/core/__tests__/evidence-boundaries.test.ts index 4283143..8d4ca87 100644 --- a/src/core/__tests__/evidence-boundaries.test.ts +++ b/src/core/__tests__/evidence-boundaries.test.ts @@ -109,7 +109,7 @@ describe('public metadata', () => { const action = await readFile(join(root, 'action.yml'), 'utf8'); const compatibilityAction = await readFile(join(root, 'action/action.yml'), 'utf8'); - expect(packageJson.version).toBe('0.10.0'); + expect(packageJson.version).toBe('0.11.0'); expect(pluginJson.version).toBe(packageJson.version); expect(marketplaceJson.metadata.version).toBe(packageJson.version); expect(cli).toContain(`.version('${packageJson.version}')`); @@ -126,7 +126,7 @@ describe('public metadata', () => { expect(marketplaceJson.plugins[0].description).toContain('SEO experiments'); }); - it('keeps current user documentation aligned with the published version', async () => { + it('keeps release instructions aligned while preserving historical publication evidence', async () => { const packageJson = JSON.parse(await readFile(join(root, 'package.json'), 'utf8')); const version = packageJson.version as string; const [readme, roadmap, security, migration, sample, settings, openSsf] = await Promise.all([ @@ -139,17 +139,19 @@ describe('public metadata', () => { readFile(join(root, 'docs', 'openssf-best-practices.md'), 'utf8'), ]); - expect(readme).toContain(`Version ${version} is published`); - expect(roadmap).toContain(`Version ${version} is published`); + expect(readme).toContain(`Version ${version}`); + expect(readme).toContain(`releases/tag/v${version}`); + expect(roadmap).toContain(`Version ${version}`); expect(roadmap).not.toContain('Package version remains 0.9.0'); - expect(security).toContain(`Version ${version} is the first release`); + expect(security).toContain('Version 0.10.0 is the first release'); expect(migration).toContain(`geoptimize@${version}`); expect(migration).toContain(`installed version should be \`${version}\``); - expect(sample).toContain(`published \`geoptimize@${version}\` package`); + expect(sample).toContain(`geoptimize@${version}`); + expect(sample).toContain(`v${version}`); expect(sample).not.toContain('Until both artifacts exist'); expect(settings).toContain('Release immutability is enabled'); expect(settings).toContain('npm Trusted Publisher binds'); - expect(openSsf).toContain(`${version} is public with npm OIDC provenance`); + expect(openSsf).toContain('0.10.0 is public with npm OIDC provenance'); }); it('keeps npm publisher metadata normalized and exposes every CLI alias', async () => { diff --git a/src/core/__tests__/release-contract.test.ts b/src/core/__tests__/release-contract.test.ts index 9246bf2..3c3f6eb 100644 --- a/src/core/__tests__/release-contract.test.ts +++ b/src/core/__tests__/release-contract.test.ts @@ -197,7 +197,7 @@ describe('v0.6 JSON automation contract', () => { 'npm run release:check && bash scripts/verify-publish-source.sh', ); expect(releaseGuide).toContain('## Rollback'); - expect(releaseGuide).toContain('npm dist-tag add geoptimize@0.9.0 latest'); + expect(releaseGuide).toContain('npm dist-tag add geoptimize@0.10.0 latest'); expect(releaseGuide).toContain(''); expect(candidateVerifier).toContain('index("README.md")'); expect(candidateVerifier).toContain('tar -xOf "$PACKAGE_TARBALL" package/README.md'); @@ -210,15 +210,15 @@ describe('v0.6 JSON automation contract', () => { it('keeps public release notes separate from the maintainer runbook', async () => { const workflow = await readFile(join(repositoryRoot, '.github/workflows/release.yml'), 'utf8'); - const releaseNotes = await readFile(join(repositoryRoot, 'docs/release-notes-v0.10.md'), 'utf8'); - const runbook = await readFile(join(repositoryRoot, 'docs/release-v0.10.md'), 'utf8'); + const releaseNotes = await readFile(join(repositoryRoot, 'docs/release-notes-v0.11.md'), 'utf8'); + const runbook = await readFile(join(repositoryRoot, 'docs/release-v0.11.md'), 'utf8'); - expect(workflow).toContain('--notes-file docs/release-notes-v0.10.md'); - expect(workflow).not.toContain('--notes-file docs/release-v0.10.md'); - expect(releaseNotes).toContain('# geoptimize 0.10.0'); + expect(workflow).toContain('--notes-file docs/release-notes-v0.11.md'); + expect(workflow).not.toContain('--notes-file docs/release-v0.11.md'); + expect(releaseNotes).toContain('# geoptimize 0.11.0'); expect(releaseNotes).not.toContain('repository preparation'); - expect(runbook).toContain('Status: published and verified on 2026-09-11.'); - expect(runbook).toContain('## Publication receipt'); - expect(runbook).not.toContain('release candidate preparation'); + expect(runbook).toContain('## Publication verification'); + expect(runbook).toContain('v0.11.0'); + expect(runbook).toContain('scripts/verify-release-public.sh'); }); });