From 06b5de3b57aef905b5c17967b10b546fa1f86646 Mon Sep 17 00:00:00 2001 From: Te-Shu Wang Date: Mon, 24 Aug 2026 18:10:14 +0800 Subject: [PATCH] chore: prepare v0.6.1 release Signed-off-by: Te-Shu Wang --- .claude-plugin/marketplace.json | 2 +- .claude-plugin/plugin.json | 2 +- .github/workflows/ci.yml | 12 +++--- CHANGELOG.md | 2 +- README.md | 4 +- action.yml | 2 +- action/action.yml | 2 +- docs/release-v0.6.md | 40 ++++++++----------- .../.github/workflows/aeoptimize.yml | 2 +- examples/github-action-sample/README.md | 2 +- package-lock.json | 4 +- package.json | 2 +- scripts/verify-release-v0.6.sh | 14 +++++-- src/cli/index.ts | 2 +- .../__tests__/evidence-boundaries.test.ts | 2 +- src/core/__tests__/release-contract.test.ts | 8 ++-- src/core/__tests__/release-verifier.test.ts | 22 +++++----- 17 files changed, 62 insertions(+), 62 deletions(-) diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 6632b73..20f857a 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -5,7 +5,7 @@ }, "metadata": { "description": "Content-readiness lint with evidence-bounded AI discovery experiments", - "version": "0.6.0" + "version": "0.6.1" }, "plugins": [ { diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json index 5d630e5..d72e41d 100644 --- a/.claude-plugin/plugin.json +++ b/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "aeoptimize", "description": "Content-readiness lint and evidence-bounded discovery experiments", - "version": "0.6.0", + "version": "0.6.1", "author": { "name": "Te-Shu Wang" }, diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e44c71d..61c2c34 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -84,7 +84,7 @@ jobs: with: path: .github/fixtures/action-low min-score: '100' - package-spec: ./aeoptimize-0.6.0.tgz + package-spec: ./aeoptimize-0.6.1.tgz - name: Validate Action outputs env: @@ -101,7 +101,7 @@ jobs: uses: ./ with: path: examples/github-action-sample/site - package-spec: ./aeoptimize-0.6.0.tgz + package-spec: ./aeoptimize-0.6.1.tgz - name: Validate sample outputs env: @@ -120,7 +120,7 @@ jobs: path: .github/fixtures/action-low min-score: '0' fail-on-low-score: 'true' - package-spec: ./aeoptimize-0.6.0.tgz + package-spec: ./aeoptimize-0.6.1.tgz - name: Validate blocking outputs env: @@ -140,7 +140,7 @@ jobs: path: .github/fixtures/action-low min-score: '100' fail-on-low-score: 'true' - package-spec: ./aeoptimize-0.6.0.tgz + package-spec: ./aeoptimize-0.6.1.tgz - name: Invalid choice is rejected id: invalid-choice @@ -149,7 +149,7 @@ jobs: with: path: .github/fixtures/action-low fail-on-low-score: sometimes - package-spec: ./aeoptimize-0.6.0.tgz + package-spec: ./aeoptimize-0.6.1.tgz - name: Out-of-range threshold is rejected id: invalid-threshold @@ -158,7 +158,7 @@ jobs: with: path: .github/fixtures/action-low min-score: '101' - package-spec: ./aeoptimize-0.6.0.tgz + package-spec: ./aeoptimize-0.6.1.tgz - name: Assert expected failures env: diff --git a/CHANGELOG.md b/CHANGELOG.md index aff64af..54ce665 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.6.1 ### Fixed diff --git a/README.md b/README.md index 0d49afa..e48325a 100644 --- a/README.md +++ b/README.md @@ -64,7 +64,7 @@ node -e "const r=require('./aeoptimize-report.json'); process.exit(r.overall.tot The v0.6 GitHub Action is advisory by default. It reports findings without blocking the workflow: ```yaml -- uses: cucuwang/aeoptimize@v0.6.0 +- uses: cucuwang/aeoptimize@v0.6.1 with: path: dist ``` @@ -72,7 +72,7 @@ The v0.6 GitHub Action is advisory by default. It reports findings without block Projects can explicitly choose blocking mode after accepting a baseline: ```yaml -- uses: cucuwang/aeoptimize@v0.6.0 +- uses: cucuwang/aeoptimize@v0.6.1 with: path: dist fail-on-low-score: 'true' diff --git a/action.yml b/action.yml index 3180e8a..cb6b20b 100644 --- a/action.yml +++ b/action.yml @@ -20,7 +20,7 @@ inputs: package-spec: description: npm package spec to install; keep the default outside prerelease testing required: false - default: 'aeoptimize@0.6.0' + default: 'aeoptimize@0.6.1' outputs: score: diff --git a/action/action.yml b/action/action.yml index bb0c072..119c025 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: 'aeoptimize@0.6.0' + default: 'aeoptimize@0.6.1' outputs: score: diff --git a/docs/release-v0.6.md b/docs/release-v0.6.md index e92366b..f4560a3 100644 --- a/docs/release-v0.6.md +++ b/docs/release-v0.6.md @@ -1,6 +1,6 @@ # v0.6 release and rollback guide -Version 0.6.0 establishes the evidence-bounded scoring, packaging, and GitHub Action contracts. It is not released until npm, the Git tag, and the GitHub Release are each created and read back independently. +Version 0.6.1 hardens the v0.6 evidence-bounded scoring, packaging, and GitHub Action contracts. It is not released until npm, the Git tag, and the GitHub Release are each created and read back independently. ## Release acceptance @@ -19,23 +19,15 @@ Publishing, tagging, creating a GitHub Release, changing npm dist-tags, and depr ## Release notes -### Evidence-bounded readiness scoring +### Artifact-bound release verification -- Reframe the score as deterministic content readiness rather than a prediction of ranking or AI citation. -- Treat FAQ structure and `llms.txt` as optional, zero-point signals. -- Remove exact-one-H1 and fixed meta-description-length assumptions. -- Flag unsourced quantitative claims instead of rewarding more numbers. -- Publish a versioned fixture corpus with positive, negative, and false-positive boundaries for every scored rule. +- Build the candidate from a clean worktree and install all three CLI aliases from the exact tarball whose SHA-256 is recorded. +- Require byte-identical candidate manifests from Node.js 22 and 24 before the release can proceed. +- Bind the public verifier's CLI smoke checks to the downloaded, hash-verified npm tarball. +- Fail closed when a CLI alias, tag target, repository identity, or GitHub Release state does not match. +- Exercise every v0.6 rule fixture through the real HTML parser boundary. -### Reproducible automation - -- Support maintained Node.js 22 and 24 lines. -- Keep `aeoptimize`, `aeo`, and `aeo-cli` in the packed npm manifest. -- Add an advisory-by-default GitHub Action with explicit blocking mode and stable JSON outputs. -- Add a copyable end-to-end Action sample and release-time contract checks. -- Refresh dependencies and require zero high or critical audit findings at release time. - -No ranking, traffic, indexing, rich-result, AI Overview, or citation outcome is claimed by this release. +No scoring rule, rule weight, JSON field, Action input, or Action output changes in this patch. No ranking, traffic, indexing, rich-result, AI Overview, or citation outcome is claimed by this release. ## Publication readback @@ -43,16 +35,16 @@ After an authorized npm publication: ```bash npm view aeoptimize version dist-tags --json -npm view aeoptimize@0.6.0 version gitHead repository homepage bugs dist --json -consumer_root=$(mktemp -d "${TMPDIR:-/tmp}/aeoptimize-v0.6-consumer.XXXXXX") -npm install --prefix "$consumer_root" aeoptimize@0.6.0 +npm view aeoptimize@0.6.1 version gitHead repository homepage bugs dist --json +consumer_root=$(mktemp -d "${TMPDIR:-/tmp}/aeoptimize-v0.6.1-consumer.XXXXXX") +npm install --prefix "$consumer_root" aeoptimize@0.6.1 "$consumer_root/node_modules/.bin/aeoptimize" --version "$consumer_root/node_modules/.bin/aeo" --version "$consumer_root/node_modules/.bin/aeo-cli" --version rm -rf -- "$consumer_root" ``` -After separately authorized tag and GitHub Release creation, verify that `v0.6.0` points to the tested release commit and that the Release is published rather than draft or prerelease. +After separately authorized tag and GitHub Release creation, verify that `v0.6.1` points to the tested release commit and that the Release is published rather than draft or prerelease. The fail-closed public verifier checks npm `latest`, the exact version, public repository identity, the downloaded tarball SHA-256, all three installed CLI aliases, the tag target, and the published GitHub Release. The tarball hash is the required artifact-identity gate. If npm exposes `gitHead`, it must match the expected release commit; absence is reported as informational because npm's publish contract guarantees tarball integrity but does not guarantee that metadata field. @@ -64,11 +56,11 @@ bash scripts/verify-release-v0.6.sh /dev/null 2>&1; then + echo "missing required command: node" >&2 + exit 2 +fi + +EXPECTED_VERSION=$(node -e "const fs=require('node:fs');const packageJson=JSON.parse(fs.readFileSync(process.argv[1],'utf8'));process.stdout.write(packageJson.version)" "$PACKAGE_JSON") +EXPECTED_TAG="v$EXPECTED_VERSION" if [ -z "$EXPECTED_COMMIT" ] || [ -z "$EXPECTED_PACKAGE_SHA256" ]; then echo "usage: $0 " >&2 @@ -26,7 +34,7 @@ if ! [[ "$EXPECTED_PACKAGE_SHA256" =~ ^[0-9a-f]{64}$ ]]; then exit 2 fi -for command_name in awk curl jq npm git mktemp node; do +for command_name in awk curl jq npm git mktemp; do if ! command -v "$command_name" >/dev/null 2>&1; then echo "missing required command: $command_name" >&2 exit 2 diff --git a/src/cli/index.ts b/src/cli/index.ts index 2c873d4..7b28836 100644 --- a/src/cli/index.ts +++ b/src/cli/index.ts @@ -18,7 +18,7 @@ const program = new Command(); program .name('aeoptimize') .description('Deterministic content-readiness lint for websites and documentation') - .version('0.6.0'); + .version('0.6.1'); // ── scan command ─────────────────────────────────────────────────── diff --git a/src/core/__tests__/evidence-boundaries.test.ts b/src/core/__tests__/evidence-boundaries.test.ts index 6deabb3..fe47ce4 100644 --- a/src/core/__tests__/evidence-boundaries.test.ts +++ b/src/core/__tests__/evidence-boundaries.test.ts @@ -83,7 +83,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.6.0'); + expect(packageJson.version).toBe('0.6.1'); expect(pluginJson.version).toBe(packageJson.version); expect(marketplaceJson.metadata.version).toBe(packageJson.version); expect(cli).toContain(`.version('${packageJson.version}')`); diff --git a/src/core/__tests__/release-contract.test.ts b/src/core/__tests__/release-contract.test.ts index 87eba87..3401359 100644 --- a/src/core/__tests__/release-contract.test.ts +++ b/src/core/__tests__/release-contract.test.ts @@ -122,7 +122,7 @@ describe('v0.6 public rule fixture corpus', () => { }); } - it('keeps the corpus, package, methodology, and Action sample on the same release version', async () => { + it('keeps the v0.6 scoring contract and Action sample aligned with the package release line', async () => { const packageJson = JSON.parse(await readFile(join(repositoryRoot, 'package.json'), 'utf8')); const methodology = await readFile(join(repositoryRoot, 'docs/methodology.md'), 'utf8'); const sampleWorkflow = await readFile( @@ -130,8 +130,8 @@ describe('v0.6 public rule fixture corpus', () => { 'utf8', ); - expect(ruleFixtureCorpusVersion).toBe(packageJson.version); - expect(methodology).toContain(`v${packageJson.version} scoring contract`); + expect(packageJson.version.split('.').slice(0, 2)).toEqual(ruleFixtureCorpusVersion.split('.').slice(0, 2)); + expect(methodology).toContain(`v${ruleFixtureCorpusVersion} scoring contract`); expect(sampleWorkflow).toContain(`uses: cucuwang/aeoptimize@v${packageJson.version}`); expect(sampleWorkflow).toContain('permissions:\n contents: read'); expect(sampleWorkflow).toContain('path: site'); @@ -189,7 +189,7 @@ describe('v0.6 JSON automation contract', () => { expect(packageJson.scripts['release:check']).toBe('bash scripts/verify-release-candidate.sh'); expect(packageJson.scripts.prepublishOnly).toBe('npm run release:check'); expect(releaseGuide).toContain('## Rollback'); - expect(releaseGuide).toContain('npm dist-tag add aeoptimize@0.5.3 latest'); + expect(releaseGuide).toContain('npm dist-tag add aeoptimize@0.6.0 latest'); expect(releaseGuide).toContain(''); expect(publicVerifier).toContain('.gitHead'); expect(publicVerifier).toContain('EXPECTED_REPOSITORY_URL'); diff --git a/src/core/__tests__/release-verifier.test.ts b/src/core/__tests__/release-verifier.test.ts index 11fd249..b3aa0fc 100644 --- a/src/core/__tests__/release-verifier.test.ts +++ b/src/core/__tests__/release-verifier.test.ts @@ -10,7 +10,7 @@ const testDirectory = dirname(fileURLToPath(import.meta.url)); const repositoryRoot = join(testDirectory, '../../..'); const verifier = join(repositoryRoot, 'scripts/verify-release-v0.6.sh'); const expectedCommit = '0123456789abcdef0123456789abcdef01234567'; -const tarballContent = 'verified aeoptimize v0.6.0 candidate'; +const tarballContent = 'verified aeoptimize v0.6.1 candidate'; const expectedTarballHash = createHash('sha256').update(tarballContent).digest('hex'); interface CommandResult { @@ -29,7 +29,7 @@ function runVerifier( env: { ...process.env, PATH: `${mockBin}:${process.env.PATH}`, - MOCK_LATEST: '0.6.0', + MOCK_LATEST: '0.6.1', MOCK_NPM_GIT_HEAD: expectedCommit, MOCK_REPOSITORY_URL: 'git+https://github.com/cucuwang/aeoptimize.git', MOCK_TAG_COMMIT: expectedCommit, @@ -80,13 +80,13 @@ done case "$url" in https://registry.npmjs.org/aeoptimize) - printf '{"dist-tags":{"latest":"%s"},"versions":{"0.6.0":{"gitHead":"%s","repository":{"url":"%s"},"homepage":"https://github.com/cucuwang/aeoptimize","bugs":{"url":"https://github.com/cucuwang/aeoptimize/issues"},"dist":{"tarball":"https://registry.npmjs.org/aeoptimize/-/aeoptimize-0.6.0.tgz"}}}}' "$MOCK_LATEST" "$MOCK_NPM_GIT_HEAD" "$MOCK_REPOSITORY_URL" + printf '{"dist-tags":{"latest":"%s"},"versions":{"0.6.1":{"gitHead":"%s","repository":{"url":"%s"},"homepage":"https://github.com/cucuwang/aeoptimize","bugs":{"url":"https://github.com/cucuwang/aeoptimize/issues"},"dist":{"tarball":"https://registry.npmjs.org/aeoptimize/-/aeoptimize-0.6.1.tgz"}}}}' "$MOCK_LATEST" "$MOCK_NPM_GIT_HEAD" "$MOCK_REPOSITORY_URL" ;; - https://registry.npmjs.org/aeoptimize/-/aeoptimize-0.6.0.tgz) + https://registry.npmjs.org/aeoptimize/-/aeoptimize-0.6.1.tgz) printf '%s' "$MOCK_TARBALL_CONTENT" > "$output_file" ;; - https://api.github.com/repos/cucuwang/aeoptimize/releases/tags/v0.6.0) - printf '{"tag_name":"v0.6.0","draft":%s,"prerelease":%s}' "$MOCK_RELEASE_DRAFT" "$MOCK_RELEASE_PRERELEASE" > "$output_file" + https://api.github.com/repos/cucuwang/aeoptimize/releases/tags/v0.6.1) + printf '{"tag_name":"v0.6.1","draft":%s,"prerelease":%s}' "$MOCK_RELEASE_DRAFT" "$MOCK_RELEASE_PRERELEASE" > "$output_file" printf '200' ;; *) @@ -98,7 +98,7 @@ esac await writeExecutable(join(mockBin, 'git'), `#!/usr/bin/env bash set -euo pipefail -printf '%s\trefs/tags/v0.6.0\n' "$MOCK_TAG_COMMIT" +printf '%s\trefs/tags/v0.6.1\n' "$MOCK_TAG_COMMIT" `); await writeExecutable(join(mockBin, 'npm'), `#!/usr/bin/env bash @@ -116,7 +116,7 @@ for binary in aeoptimize aeo aeo-cli; do if [ "$binary" = "$MOCK_MISSING_BINARY" ]; then continue fi - printf '#!/usr/bin/env bash\nprintf "0.6.0\\n"\n' > "$prefix/node_modules/.bin/$binary" + printf '#!/usr/bin/env bash\nprintf "0.6.1\\n"\n' > "$prefix/node_modules/.bin/$binary" chmod +x "$prefix/node_modules/.bin/$binary" done `); @@ -135,8 +135,8 @@ done expect(result.stdout).toContain('PASS: npm gitHead matches'); expect(result.stdout).toContain('PASS: npm tarball SHA-256 matches the verified candidate'); expect(result.stdout).toContain('All public release checks passed.'); - expect(npmArgs).toMatch(/aeoptimize-0\.6\.0\.tgz/); - expect(npmArgs).not.toContain('aeoptimize@0.6.0'); + expect(npmArgs).toMatch(/aeoptimize-0\.6\.1\.tgz/); + expect(npmArgs).not.toContain('aeoptimize@0.6.1'); }); it('fails closed when npm serves a different tarball', async () => { @@ -177,7 +177,7 @@ done }); expect(result.code).toBe(1); - expect(result.stderr).toContain('FAIL: v0.6.0 points to'); + expect(result.stderr).toContain('FAIL: v0.6.1 points to'); }); it('fails closed when the GitHub Release is a draft', async () => {