Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,23 @@ jobs:
esac
node -e "const r=JSON.parse(process.env.REPORT);if(r.overall.total!==Number(process.env.SCORE))process.exit(1)"

- name: Run the copyable end-to-end sample
id: sample
uses: ./
with:
path: examples/github-action-sample/site
package-spec: ./aeoptimize-0.6.0.tgz

- name: Validate sample outputs
env:
SCORE: ${{ steps.sample.outputs.score }}
REPORT: ${{ steps.sample.outputs.report }}
run: |
case "$SCORE" in
''|*[!0-9]*) echo "Invalid sample score: $SCORE"; exit 1 ;;
esac
node -e "const r=JSON.parse(process.env.REPORT);if(r.pages.length!==1||r.overall.total!==Number(process.env.SCORE))process.exit(1)"

- name: Blocking mode passes at an accepted threshold
id: blocking-passes
uses: ./
Expand Down
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

## 0.6.0 — 2026-08-16
## 0.6.0

### Changed

Expand All @@ -14,6 +14,8 @@ All notable user-visible changes will be documented here. The project follows Se
- Limited CI support to maintained Node.js LTS lines and refreshed dependencies.
- Added methodology, contribution, security, roadmap, and root GitHub Action files.
- Made the GitHub Action advisory by default, with explicit blocking mode, version-matched package installation, stable outputs, and contract fixtures.
- Added a public positive, negative, and false-positive boundary corpus for every scored rule.
- Added a copyable end-to-end GitHub Action sample plus release and rollback instructions.

### Security

Expand Down
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ Two often-promoted AEO signals are deliberately excluded from the score:
- FAQ content and `FAQPage` schema are optional. The generator does not infer FAQ schema from question headings.
- `llms.txt` is an experimental proposal. Generating or publishing it does not add points.

Every rule, its evidence class, and known false-positive boundary is documented in [docs/methodology.md](docs/methodology.md).
Every rule, its evidence class, and known false-positive boundary is documented in [docs/methodology.md](docs/methodology.md) and exercised by the [versioned public fixture corpus](fixtures/v0.6/rule-corpus.ts).

## CI contract

Expand Down Expand Up @@ -81,6 +81,8 @@ Projects can explicitly choose blocking mode after accepting a baseline:

The Action exposes `score` and `report` outputs in both modes. Its release is reproducible only when the Action tag and matching npm package version both exist. Before pinning a version, verify both artifacts; if either is missing, use the CLI directly.

A copyable advisory workflow and controlled input are available in the [end-to-end Action sample](examples/github-action-sample/README.md).

## Optional generators

```bash
Expand Down Expand Up @@ -149,7 +151,7 @@ claude plugin marketplace add cucuwang/aeoptimize

## Project status

The next evidence release focuses on methodology, reproducible fixtures, CI compatibility, packaging, and external adoption—not more scoring rules. See [ROADMAP.md](ROADMAP.md).
The v0.6 evidence baseline focuses on methodology, reproducible fixtures, CI compatibility, packaging, and external adoption—not more scoring rules. Release acceptance and rollback are documented in [docs/release-v0.6.md](docs/release-v0.6.md); longer-term adoption work remains in [ROADMAP.md](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).

Expand Down
2 changes: 2 additions & 0 deletions ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ Release gates:
- root GitHub Action metadata and an end-to-end sample repository;
- stable JSON output, changelog, release notes, and rollback instructions.

The release gates are enforced by `src/core/__tests__/release-contract.test.ts`, the versioned corpus in `fixtures/v0.6/`, the copyable sample in `examples/github-action-sample/`, and the release runbook in `docs/release-v0.6.md`.

## Product validation after v0.6

- Validate one core workflow: static site or documentation CI content-readiness lint.
Expand Down
7 changes: 6 additions & 1 deletion action/test-contract.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ set -euo pipefail
REPO_ROOT=$(cd "$(dirname "$0")/.." && pwd)
RUNNER="$REPO_ROOT/action/run.sh"
FIXTURE="$REPO_ROOT/.github/fixtures/action-low"
SAMPLE_FIXTURE="$REPO_ROOT/examples/github-action-sample/site"
CLI="$REPO_ROOT/dist/cli/index.js"
TEST_ROOT=$(mktemp -d "${TMPDIR:-/tmp}/aeoptimize-action-contract.XXXXXX")
trap 'rm -rf "$TEST_ROOT"' EXIT
Expand All @@ -13,10 +14,11 @@ run_case() {
local fail_on_low_score=$2
local min_score=$3
local expected_status=$4
local input_path=${5:-$FIXTURE}
local output_file="$TEST_ROOT/$name.output"
local status=0

INPUT_PATH="$FIXTURE" \
INPUT_PATH="$input_path" \
MIN_SCORE="$min_score" \
FAIL_ON_LOW_SCORE="$fail_on_low_score" \
GITHUB_OUTPUT="$output_file" \
Expand All @@ -36,11 +38,14 @@ run_case blocking-passes true 0 0
run_case invalid-threshold false invalid 2
run_case invalid-threshold-high false 101 2
run_case invalid-choice sometimes 60 2
run_case sample-advisory false 100 0 "$SAMPLE_FIXTURE"

grep -Eq '^score=[0-9]+$' "$TEST_ROOT/advisory.output"
grep -q '^report<<AEOPTIMIZE_REPORT$' "$TEST_ROOT/advisory.output"
grep -Eq '^score=[0-9]+$' "$TEST_ROOT/blocking-passes.output"
grep -q '^report<<AEOPTIMIZE_REPORT$' "$TEST_ROOT/blocking-passes.output"
grep -Eq '^score=[0-9]+$' "$TEST_ROOT/sample-advisory.output"
grep -q '^report<<AEOPTIMIZE_REPORT$' "$TEST_ROOT/sample-advisory.output"
grep -q 'aeoptimize advisory mode' "$TEST_ROOT/advisory.log"
grep -q 'aeoptimize blocking mode' "$TEST_ROOT/blocking-fails.log"

Expand Down
6 changes: 3 additions & 3 deletions docs/methodology.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Methodology and limitations

This document describes the v0.6 draft scoring contract. `aeoptimize` is a deterministic content-readiness linter. Its score is not a forecast of ranking, indexing, rich-result eligibility, AI visibility, or citation.
This document describes the v0.6.0 scoring contract. `aeoptimize` is a deterministic content-readiness linter. Its score is not a forecast of ranking, indexing, rich-result eligibility, AI visibility, or citation.

## Evidence classes

Expand Down Expand Up @@ -64,7 +64,7 @@ A scoring-rule change must include:
3. the expected JSON change and migration impact;
4. no claim that the rule improves ranking or citation without a preregistered outcome study and public data.

The v0.6 evidence release will version a public fixture corpus and publish rule-level change notes. Outcome research, if added later, will be reported separately from the readiness score.
The v0.6 fixture corpus is published in [`fixtures/v0.6/rule-corpus.ts`](../fixtures/v0.6/rule-corpus.ts) and is enforced by the release-contract tests. Outcome research, if added later, will be reported separately from the readiness score.

## Primary sources

Expand All @@ -75,4 +75,4 @@ The v0.6 evidence release will version a public fixture corpus and publish rule-
- [Google Search: robots meta tag](https://developers.google.com/search/docs/crawling-indexing/robots-meta-tag)
- [llms.txt proposal](https://llmstxt.org/)

Last reviewed: 2026-08-15.
Last reviewed: 2026-08-22.
72 changes: 72 additions & 0 deletions docs/release-v0.6.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# 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.

## Release acceptance

Before publication, verify all of the following from the intended release commit:

1. `npm ci`, `npm run check`, `npm audit --audit-level=high`, and `bash action/test-contract.sh` pass.
2. The public v0.6 rule corpus covers the positive, negative, and false-positive boundary for every scored rule.
3. `npm pack` is reproducible, its SHA-256 is recorded, and a clean consumer can invoke `aeoptimize`, `aeo`, and `aeo-cli`.
4. CI succeeds on Node.js 22 and 24 for the release commit.
5. The JSON automation contract and Action sample tests pass.
6. The npm account is verified immediately before publishing.

Publishing, tagging, creating a GitHub Release, changing npm dist-tags, and deprecating a version are separate external mutations and require separate maintainer authorization.

## Release notes

### Evidence-bounded readiness scoring

- 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.

### 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.

## Publication readback

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
"$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.

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.

```bash
bash scripts/verify-release-v0.6.sh <verified-release-commit> <verified-package-sha256>
```

## Rollback

An npm dist-tag rollback changes what `npm install aeoptimize` selects; it does not remove exact-version installs. Never silently move an existing Git tag to different code.

If npm 0.6.0 is unsuitable before a corrective release is available, request separate authorization for each mutation, then:

```bash
npm dist-tag add aeoptimize@0.5.3 latest
npm deprecate aeoptimize@0.6.0 "Use 0.5.3 until the corrective release is available."
```

Mark the GitHub Release with the same warning. Preserve the `v0.6.0` tag as evidence of what was published, fix forward in 0.6.1, rerun the complete release acceptance suite, and only then move npm `latest` to the corrective version.
18 changes: 18 additions & 0 deletions examples/github-action-sample/.github/workflows/aeoptimize.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
name: Content readiness

on:
pull_request:
workflow_dispatch:

permissions:
contents: read

jobs:
readiness:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: cucuwang/aeoptimize@v0.6.0
with:
path: site
fail-on-low-score: 'false'
9 changes: 9 additions & 0 deletions examples/github-action-sample/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# aeoptimize GitHub Action sample

This directory is a copyable end-to-end sample for the v0.6 Action contract.

- `.github/workflows/aeoptimize.yml` checks the static site on pull requests and manual runs.
- `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 becomes reproducible only after both `aeoptimize@0.6.0` exists on npm and the immutable `v0.6.0` Git tag points to the matching release commit. Until both artifacts exist, use the local CLI or the release-candidate package during controlled verification.
38 changes: 38 additions & 0 deletions examples/github-action-sample/site/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="description" content="A deterministic sample site for verifying the aeoptimize v0.6 GitHub Action contract.">
<meta name="author" content="aeoptimize maintainers">
<meta name="date" content="2026-08-22">
<meta name="robots" content="index,follow">
<title>aeoptimize Action sample</title>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "TechArticle",
"headline": "aeoptimize Action sample",
"author": { "@type": "Organization", "name": "aeoptimize maintainers" },
"datePublished": "2026-08-22"
}
</script>
</head>
<body>
<main>
<article>
<h1>aeoptimize Action sample</h1>
<p>The aeoptimize Action sample is a controlled input for the public v0.6 automation contract.</p>
<h2>What the workflow verifies</h2>
<p>The workflow installs the version-matched package, scans this directory, and exposes a numeric score plus a JSON report.</p>
<ul>
<li>Advisory mode reports findings without blocking a pull request.</li>
<li>Blocking mode requires a project owner to accept a baseline first.</li>
<li>The score remains a content-readiness heuristic rather than an outcome prediction.</li>
</ul>
<h2>How to interpret results</h2>
<p>According to the versioned methodology, teams should compare reports only within the same project, package version, configuration, and fixture set.</p>
<pre><code>npx aeoptimize scan ./site --dir --json</code></pre>
</article>
</main>
</body>
</html>
Loading
Loading