From ed38b4e9c64df17b7c8b09d7506e8aaf7b908f37 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 26 Sep 2026 06:52:03 +0000 Subject: [PATCH 1/2] docs(roadmap): the plan for 1.0.0 Replaces the one-line 1.0 outline with a full plan: stack detection that covers Next.js properly (build manifests as the page list, standalone and export output, basePath and i18n), the missing frameworks, monorepos and package managers; the contracts frozen with published JSON Schemas and surface locks; an acceptance matrix and a hostile-input suite; speed work measured against 0.9.0 with a new --against mode; release checks that would have caught 0.8.0; and a date-aware Swedish authority. Each item names its gate and exit condition, and the release itself runs as an rc loop that exits on a clean candidate plus seven clean nightly soaks. Four decisions are listed at the end for review before work starts. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_013BXnvSeRtgZoTXe4j753gM --- ROADMAP.md | 348 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 345 insertions(+), 3 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index 6550b07..6208e1e 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -21,15 +21,357 @@ having to learn the tool first. Three releases get there: result: `init` that sets up CI and a baseline as well as a config, errors that say what to type next, a German rendering for Belgium's third language community, and Sweden, Denmark, Finland and Czechia. -- **1.0.0 — the promise.** The JSON report, the review record, the baseline and the config - file frozen as documented contracts under semver, with a migration note for anything that - changed on the way. No new surface: 1.0 is 0.9 with the guarantees written down. +- **1.0.0 — the promise, kept.** The contracts frozen under semver, stack detection that + covers what people actually build with (Next.js first), and "everything works" shown by + tests that run the tool the way its users do, on every platform, against real projects + and hostile input. See [1.0.0](#100--the-promise-kept) for the plan. Known before 1.0: on 1 January 2027, supervision under the Swedish Act moves from Post- och telestyrelsen to Digitaliseringsmyndigheten (förordning 2026:1769, 21 §). The Swedish templates have to change on that date, not before, because until then PTS is right. See [docs/citations.md](docs/citations.md#sweden-se). +## 1.0.0 — the promise, kept + +1.0 is the release somebody can install without reading anything, point at whatever they +build their site with, and get a correct audit, a CI job and a statement they can publish. +It is also the release where "it works" stops being a claim and becomes a set of checks +anyone can re-run. + +The earlier outline said 1.0 would add no new surface: 0.9 with the guarantees written +down. That still holds everywhere except one place. Stack detection has to cover what +people actually use, Next.js above all, because a tool that cannot find the site cannot +audit it, and every other guarantee here depends on that first step. + +### How the work is done: loops with exit conditions + +Every item below runs as a loop, not a to-do list. The rule is that a change is not done +when it compiles. It is done when the check that describes it is green, and that check +exists before the change does. + +- **The inner loop, for every change.** Write the check that fails first: a test, a + fixture or a benchmark budget. Make the change, then run `pnpm lint`, `pnpm typecheck`, + `pnpm test` and the item's own gate. Repeat until everything is green. Never widen the + change to get green. +- **The middle loop, for each item.** Each item names its gate (the fixture set, matrix or + benchmark that proves it) and its exit condition. An item closes when its gate is green + on Linux, macOS and Windows, not when the code is written. +- **The outer loop, for the release.** A nightly soak workflow runs the heavy gates that + are too slow for a PR: real projects built from scratch, the hostile-input suite, the + large-site benchmarks. Release candidates (`1.0.0-rc.N` on the npm `next` tag) go + through the full gate. Every finding is fixed and ships as the next rc. **Exit:** one rc + passes the full gate on all three platforms, followed by seven consecutive nightly soaks + with no new finding. That rc, unchanged except for the version, becomes 1.0.0. +- **Who drives the loop.** The nightly results land as workflow artifacts and a summary + comment. A scheduled check-in reads them, triages every red result into a fix or an + issue, and re-arms. Nothing red is left unexplained for more than one cycle. + +### 1. Stack detection that covers what people build with + +Today the registry (`src/audit/frameworks.ts`) knows 21 frameworks by a package or a file, +and finds HTML in a fixed set of directories. That is enough for a single-app repository +using a mainstream static generator, and not much beyond it. + +**1a. Next.js, in depth.** It is the most common stack this tool will meet, and the one it +handles worst: only a static export (`out/`) is found directly. +- Read `output` from `next.config.*`: + - `'export'` means the output directory (`out/` or `distDir`) is audited as files; + - `'standalone'` means the server is started with `node .next/standalone/server.js`. +- A normal `next build` writes prerendered HTML into `.next/server/app` and + `.next/server/pages`. Those pages link to `/_next/static/…`, which does not exist at that + path on disk, so auditing the files directly would audit pages without their CSS and + report wrong contrast results. The plan is to **start `next start` and use the build + manifests as the page list**: `prerender-manifest.json` and `routes-manifest.json` + replace link discovery, so every prerendered route is audited even when nothing links to + it. Dynamic routes that were not prerendered are reported as not audited, with the + reason, rather than guessed at. +- Respect `basePath`, `trailingSlash` and `i18n` locales when crawling. +- Never audit `next dev`: the dev overlay and unoptimised output are not the site. +- Recognise Next-based documentation frameworks (Nextra, Fumadocs) as Next.js. +- Verify every manifest and path claim against real projects built with Next 14, 15 and + the current major before it is relied on. Manifest formats change between majors, so each + supported major gets its own fixture. + +**1b. The frameworks that are missing.** Each one is added with its detection signal, +output directory, dev/preview port and anything to skip: +- **App frameworks:** + - Angular 17+ writes to `dist//browser`, and `index.csr.html` must be skipped; + - Qwik, SolidStart, Analog and TanStack Start; + - Vue CLI, Parcel, Rsbuild and Rspack; + - Ember. +- **Documentation and static generators:** + - Hexo (`public/`), MkDocs (`site/`), Sphinx (`_build/html`), Zola (`public/`); + - Pelican (`output/`), mdBook (`book/`), Quarto (`_site/`); + - Docsify, which has no build step: its `index.html` is the site; + - Hugo configured through `config/_default/` or `hugo.toml`. +- **Server-rendered systems**, detected and never started uninvited, as today: Drupal, + Statamic, Ghost and Shopify themes. +- **Recognised in order to be excluded:** Storybook output (`storybook-static/`) is a + component catalogue, not the site, and today it would be audited as if it were. + +**1c. Monorepos.** Run from a repository root, the tool currently sees only the root +`package.json`. +- Detect pnpm, yarn and npm workspaces, Turborepo, Nx and Lerna. +- Enumerate the workspace packages that are sites: + - exactly one: audit it; + - several: list them with the command for each (`eaa-kit audit apps/web`), and have + `init` ask which one. +- The generated CI workflow already supports `working-directory` and uses it. + +**1d. Package managers.** +- The `packageManager` field (corepack) decides first, then lockfiles. +- Lockfiles include Bun's text `bun.lock` (Bun 1.2+) as well as `bun.lockb`, and Deno's + `deno.lock` with `deno.json` tasks. +- Yarn Plug'n'Play is recognised, so no `node_modules` is not taken to mean nothing is + installed. + +**1e. Starting servers reliably.** +- Per-framework default ports, adding the ones missing today: Angular 4200, Gatsby 8000, + Hugo 1313, Jekyll 4000, Django and Laravel 8000. +- Parse the URL the server announces through ANSI colour codes, `0.0.0.0`, `127.0.0.1`, + IPv6 and Vite's `Local:` line. +- Wait for a real `200` from the page, not just any response. +- Report a port already taken by something else, instead of auditing the wrong server. + +**1f. Single-page-app shells.** +- `200.html`, `index.csr.html` and Nuxt's SPA fallback are empty shells with one root + element. Today they are audited as pages and pass, which is a false clean result. +- Recognise them and list them in completeness as "not audited: SPA shell, audit with + `--url`". This follows the rule the tool is built on: say what was never looked at. + +**1g. `eaa-kit detect`.** +- Prints what was recognised and the evidence for it (which package, file or config + line), the output directory chosen, and what an audit would build or start. `--json` + prints the same as data. +- Detection becomes debuggable by users and testable by the suite. This is the one piece + of new surface in 1.0, and it is marked as a decision below. + +**Gate:** +- An offline fixture per framework and major version in `tests/fixtures/stacks/`: the file + layout and config of a real scaffolded project, without `node_modules`. It runs on every + PR and asserts what `detect` concludes. +- A nightly job that scaffolds each framework with its official `create-*` tool at a pinned + version, installs, builds, and runs a real audit. +- The framework table in the docs is generated from the registry, and a test fails if they + drift. + +**Exit:** every registry entry has an offline fixture and a green nightly real build, on +all three platforms. + +### 2. The contracts, frozen + +After 1.0 these change only with a major version: +- the CLI: commands, flags, exit codes and the machine-readable outputs; +- the config file schema; +- the JSON report (`schemaVersion` 2), the baseline (2) and the review record (1); +- SARIF 2.1.0 with this tool's properties; +- the GitHub Action's inputs; +- the library exports and the integration option types. + +The page cache is explicitly **not** a contract. +- **Published JSON Schemas** for the report, baseline, review record and config ship in the + package under `schemas/`. The tests validate every example, snapshot and fixture against + them, so the documentation and the code cannot disagree. +- **Surface locks:** + - a committed snapshot of the public `.d.ts` API; + - a committed snapshot of `--help` for every command. + CI fails when either changes without a CHANGELOG entry, so nothing breaks silently. +- **What counts as breaking**, written down in `docs/contracts.md`. The subtle case is + axe-core: a minor axe-core update can add a rule, which adds findings, which can fail + somebody's CI. The policy: new rules arrive in minor releases, and a baseline absorbs + them. Upgrades are pinned, and the changelog names the new rules. +- **A migration note from 0.x**, covering every flag or field that moved on the way. +- **The deprecated schemaVersion-1 field** in the JSON report stays until 2.0, documented as + deprecated. Removing it now would mean a schemaVersion 3 on day one of the freeze. + +**Exit:** schemas published and enforced, locks in CI, `docs/contracts.md` and the +migration note written. + +### 3. Everything works, shown the way users run it + +- **Acceptance matrix.** Every command (bare `eaa-kit`, `init`, `audit` on a directory, + a URL and auto-detect, `baseline`, `checklist`, `statement`, `diff`, `countries`, `watch` + and `detect`) is run against real fixture projects: + - through each install method: `npx`, `pnpm dlx`, `bunx`, a global install and a local + dev dependency; + - on Linux, macOS and Windows. + This extends `scripts/test-packaged.mjs`, which already runs the packed tarball. +- **Documentation that is executed.** Every shell command in the README and `docs/` is + extracted and run against a fixture. A documented command that stops working fails CI. +- **Every error has a next step.** A test walks every exit-2 path and asserts it carries a + `next` command. It also asserts that no path prints a stack trace, unless `--debug` asks + for one. +- **Every integration runs in a real project** at the current major version of its host: + Vite, Astro, Nuxt, Eleventy, webpack and the GitHub Action. +- **Every statement renders.** All fifteen countries in every language: + - produce valid HTML; + - leave no placeholder unfilled; + - render identically with and without an audit report attached, apart from the findings + section. + +**Exit:** the matrix is green on all three platforms, and every documented command runs. + +### 4. What could break it, tried on purpose + +A `tests/robustness/` suite. Every case asserts the same things: +- a defined exit code; +- a message that says what happened and what to do; +- no stack trace; +- no orphaned process; +- no half-written file. + +The cases: +- **Hostile files:** + - malformed HTML, a 10 MB page, 50,000 nodes, nesting 1,000 deep; + - pages in Shift-JIS or Latin-1, with and without a charset declaration, and with a BOM; + - empty files, and binary files named `.html`; + - symlink loops, and names with spaces, `#`, `%` and non-Latin characters; + - 10,000-page builds, Windows long paths, and names that collide on case-insensitive + filesystems. +- **Hostile networks:** + - redirect loops, and servers that send bytes slowly enough to hit every timeout; + - bursts of 5xx errors, connection resets, oversized responses and compression bombs; + - a sitemap with 50,000 URLs, and a sitemap index that loops; + - `429` with `Retry-After`, and credentials that expire mid-crawl; + - an IPv6-only localhost, `HTTPS_PROXY`, and self-signed TLS (refused, with the flag + that allows it named); + - a port already in use. +- **Damaged state:** + - truncated or corrupt cache, baseline, review record and config files; + - two runs sharing one cache at the same time (writes must be atomic); + - a read-only project (the cache is switched off with a notice); + - a disk that fills during the report write. +- **Interrupted processes:** + - Ctrl-C during the build, the server start and the audit. The test sends `SIGINT` and + asserts the port is free and no child survives. + - `watch` through 1,000 saves, with memory flat. +- **Environments:** + - no TTY, the `CI` variable, `NO_COLOR`, `FORCE_COLOR` and 40-column terminals; + - a non-English system locale, and a non-UTC time zone; + - the exact Node floor in `engines`; + - Playwright absent, or at the wrong version; + - Alpine and musl in Docker, no git, and offline. +- **Generated input.** Property-based tests (fast-check) for the schema parser, URL + normalisation and baseline matching. A longer fuzz run is part of the nightly soak. + +**Exit:** every case is green on all three platforms, and a fuzz run finds nothing new for +seven nights. + +### 5. Speed, measured the whole way through + +Where it stands, from `pnpm bench` on 26 September 2026. These were measured on one +machine (4 cores, Node 22), so compare checkouts, not machines: + +| | today | +| --- | --- | +| `eaa-kit --version` | 253 ms | +| audit, 1 page | 1,444 ms | +| audit, 20 pages | 3,854 ms | +| each further page | 127 ms | +| everything before the first page | 1,317 ms | +| 20 pages, nothing changed (cache) | 343 ms | + +- **Benchmark what is not measured yet:** + - crawl mode against a local 100-page server, and browser mode through Playwright; + - static builds of 1,000 and 10,000 pages; + - peak memory; + - watch-mode latency from a save to the report; + - `init`, `detect` and a first run from scratch. +- **`pnpm bench --against `.** It builds another checkout in a worktree and runs both, + interleaved, on the same machine, then prints the difference. That is the only + comparison that means anything, and it is how every speed claim in the changelog will be + made. +- **Targets, relative to 0.9.0 on the same machine:** + - no measurement slower by more than 10%; + - everything before the first page cut by a third, by loading jsdom and axe-core only + once a page is about to be audited, and loading only the report renderer that was + asked for; + - a 10,000-page audit that finishes, with peak memory flat rather than growing with the + page count (no DOM retained after its page is reported); + - nothing quadratic in de-duplication, baselines or reports. +- **The loop:** measure, profile with `--cpu-prof`, change one thing, re-measure, and keep + the change only if it is a win with the tests green. +- **Nightly**, the soak job benchmarks against the last release tag on the same runner and + posts the table. A slowdown of more than 20% is triaged. It is still not a PR gate, for + the reason `scripts/bench.mjs` gives: timing on a shared runner is noise. + +**Exit:** the targets are met, and the numbers in `docs/audit.md` are regenerated from +`--against v0.9.x`. + +### 6. Releasing without surprises + +- **`pnpm release:check`** verifies that: + - the version in `package.json` matches the tag; + - the CHANGELOG entry is dated; + - the action pins in the docs and workflows match the version; + - `examples/` is regenerated. + + It runs on release PRs and again in `release.yml` before publishing. This is the check + that would have caught 0.8.0. +- **Publishing:** npm provenance on every publish, a test of the tarball's contents and + size, and release candidates on the `next` tag. +- **Clean-up:** + - delete the stray `v0.8.0` tag; + - fix the `github-advanced-security` check, which fails on GitHub's side and needs the + repository's code-scanning settings changed; + - make `npm audit` clean; + - add a `SECURITY.md`. + +### 7. What must be right on release day + +- **0.9.1 first.** The corrected Danish, Czech and Portuguese templates ship now, not with + 1.0. +- **Sweden, independent of the release date.** The Swedish authority becomes date-aware: a + statement generated before 1 January 2027 names PTS, and one generated on or after it + names Digitaliseringsmyndigheten (förordning 2026:1769, 21 §). A test with a fixed clock + covers both sides. After that, it does not matter which side of New Year 1.0 lands on. +- **All fifteen countries in `docs/citations.md`.** The original seven (AT, CH, DE, ES, FR, + IT, NL) have never had their check recorded there. They get the same treatment, and all + fifteen are re-checked within 30 days of the tag. +- **Native-speaker review** of the Czech, Danish, Finnish, Swedish, Polish and Portuguese + texts. This needs people, not the tool, so it is marked as a decision below. + +### Not in 1.0 + +- **New countries.** Fifteen is the scope. The next ones come after 1.0, on a stable + contract. +- **Writing fixes into source files.** Closed in 0.7.0, and still closed. +- **A score, Level AAA, anything model-generated, a hosted dashboard.** As before, and not + later. + +### Order of work + +1. 0.9.1: the corrected templates. +2. The contract inventory and surface locks, so nothing after this can change a contract + without it showing. +3. The acceptance and robustness harnesses, which are the tests that guard everything after + them. +4. Stack detection, Next.js first, then monorepos, then the missing frameworks. +5. Speed work, measured against 0.9.x. +6. Content: Sweden's date switch, the citations for all fifteen countries, and the reviews. +7. The release-candidate loop and the soak, then 1.0.0. + +### Done means + +- Every gate in sections 1–6 is green on Linux, macOS and Windows. +- One release candidate passes the full gate, followed by seven clean nightly soaks. +- The contracts are documented and locked, with a migration note from 0.x. +- `docs/citations.md` covers all fifteen countries and was re-checked within 30 days of + the tag. +- The speed targets are met, and the published numbers were regenerated with `--against`. + +### Decisions needed before work starts + +1. **`eaa-kit detect` as a new command.** Recommended: yes. It is the only new surface in + 1.0, and it makes detection explainable and testable. +2. **Native-speaker review as a release blocker.** Recommended: blocking for Czech, Danish, + Finnish and Swedish, the texts written for 0.9.0, and advisory for the rest. +3. **A moving `v1` tag for the GitHub Action.** Until now the Action was pinned to exact + tags on purpose, because 0.x promised nothing. Under semver a `v1` tag is the + convention. Recommended: yes, from 1.0.0. +4. **The deprecated schemaVersion-1 field** in the JSON report: keep it until 2.0 + (recommended), or remove it now as schemaVersion 3. + ## 0.9.0 — the first ten minutes 0.8.0 made the first command do the useful thing. 0.9.0 is about the next few: the ones a From db053e1ce3bc9e40bb4b22c8f663b74f75ae52ab Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 26 Sep 2026 17:10:14 +0000 Subject: [PATCH 2/2] release: 0.9.1, with release:check The corrected Danish, Czech and Portuguese statement templates, and `pnpm release:check`: the tag matches package.json, the changelog has a dated heading and no Unreleased section, the Action pins and examples are at this version. CI runs it on PRs that change the version, and the release workflow runs it against the tag before publishing. ROADMAP: the 1.0 plan as a product, with the release steps 0.9.1, 0.10.0, 0.11.0 and the 1.0.0 release candidates. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_013BXnvSeRtgZoTXe4j753gM --- .github/workflows/accessibility.yml | 2 +- .github/workflows/ci.yml | 18 ++++ .github/workflows/release.yml | 13 +-- CHANGELOG.md | 11 ++- ROADMAP.md | 140 ++++++++++++++++++++++------ docs/integrations.md | 2 +- examples/report.html | 4 +- examples/report.json | 2 +- examples/report.sarif | 2 +- examples/statement.de.html | 2 +- package.json | 5 +- scripts/release-check.ts | 99 ++++++++++++++++++++ tests/release-check.test.ts | 87 +++++++++++++++++ tsconfig.json | 2 +- 14 files changed, 339 insertions(+), 50 deletions(-) create mode 100644 scripts/release-check.ts create mode 100644 tests/release-check.test.ts diff --git a/.github/workflows/accessibility.yml b/.github/workflows/accessibility.yml index 4838d92..159c5ff 100644 --- a/.github/workflows/accessibility.yml +++ b/.github/workflows/accessibility.yml @@ -28,7 +28,7 @@ jobs: node-version: 22 # In your own repository this becomes: - # uses: likeBloodMoon/eaa-kit@v0.9.0 + # uses: likeBloodMoon/eaa-kit@v0.9.1 # # An exact release tag. There is deliberately no moving v0 tag to follow: # this is a 0.x package, the flags and the JSON contract can still move diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3807e2d..d391d5c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -77,3 +77,21 @@ jobs: run: | pnpm examples git diff --exit-code examples/ + + # A release PR is one that changes the version. It gets the checks the + # tag will need, while they can still be fixed in the PR: v0.8.0 was + # tagged on a commit that still said 0.7.0, and the release workflow only + # noticed after the tag was public. + - name: Check a release PR is ready to tag + if: github.event_name == 'pull_request' && runner.os == 'Linux' && matrix.node-version == 24 + env: + BASE_REF: ${{ github.base_ref }} + run: | + git fetch --no-tags --depth=1 origin "$BASE_REF" + base="$(git show "origin/$BASE_REF:package.json" | node -p "JSON.parse(require('fs').readFileSync(0, 'utf8')).version")" + head="$(node -p "require('./package.json').version")" + if [ "$base" != "$head" ]; then + pnpm release:check + else + echo "Version unchanged at $head: not a release PR." + fi diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index dcf44ae..de24ff4 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -45,14 +45,11 @@ jobs: - run: pnpm build - run: pnpm smoke - - name: Check the tag matches package.json - run: | - tag="${GITHUB_REF_NAME#v}" - pkg="$(node -p "require('./package.json').version")" - if [ "$tag" != "$pkg" ]; then - echo "::error::tag v${tag} does not match package.json version ${pkg}" - exit 1 - fi + # The tag against package.json, the dated changelog, the Action pins + # and the examples. CI already ran this on the release PR; running it + # again here covers a tag pushed by hand onto some other commit. + - name: Check this commit is ready to publish as this tag + run: pnpm release:check "$GITHUB_REF_NAME" # access and provenance come from publishConfig in package.json, so a # manual publish behaves the same way. diff --git a/CHANGELOG.md b/CHANGELOG.md index a8c86ec..17acb0c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,7 @@ move: the JSON report's `schemaVersion` and the baseline file's. Both are bumped a field is removed, renamed, or changes meaning — new fields may appear without one, so consumers must ignore what they do not recognise. -## Unreleased +## 0.9.1 — 2026-09-26 ### Fixed @@ -32,6 +32,15 @@ consumers must ignore what they do not recognise. A statement generated with 0.9.0 for Denmark, Czechia or Portugal should be generated again. +### Added + +- **`pnpm release:check`**, for maintainers: what has to be true before a version is + tagged (the tag matches `package.json`, the changelog has a dated heading and no + "Unreleased" section, the Action is pinned to this version in the docs, and the examples + were generated by it). CI runs it on any PR that changes the version, and the release + workflow runs it against the tag before publishing, so a tag like v0.8.0, cut on a commit + that still said 0.7.0, is caught before it is pushed. + ## 0.9.0 — 2026-09-24 The first release since 0.7.0, and it carries 0.8.0 as well: 0.8.0 was tagged but never diff --git a/ROADMAP.md b/ROADMAP.md index 6208e1e..18ea47a 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -13,7 +13,7 @@ record shows what was planned as well as what shipped. 1.0 is the release where somebody who has never read this file can install the tool, answer a few questions, and end up with an audit in CI and a statement they can publish, without -having to learn the tool first. Three releases get there: +having to learn the tool first. These releases get there: - **0.8.0 — reach.** More of the EU single market, and the loop between editing and seeing a result made short enough to use while working rather than after. @@ -21,10 +21,19 @@ having to learn the tool first. Three releases get there: result: `init` that sets up CI and a baseline as well as a config, errors that say what to type next, a German rendering for Belgium's third language community, and Sweden, Denmark, Finland and Czechia. -- **1.0.0 — the promise, kept.** The contracts frozen under semver, stack detection that - covers what people actually build with (Next.js first), and "everything works" shown by - tests that run the tool the way its users do, on every platform, against real projects - and hostile input. See [1.0.0](#100--the-promise-kept) for the plan. +- **0.9.1 — the corrected statements.** The Danish, Czech and Portuguese fixes from the + citation check, and `pnpm release:check`, so a tag can no longer point at a commit with + the wrong version. +- **0.10.0 — it finds your site.** Stack detection for what people actually build with + (Next.js properly first), monorepos and package managers, and `eaa-kit detect` and + `eaa-kit doctor` to explain what it found. +- **0.11.0 — it fits your workflow.** GitLab and Bitbucket CI from `init`, a Markdown + summary for job summaries and PR comments, and an HTML report that prints, speaks the + site's language and shows what changed since last time. +- **1.0.0 — the promise, kept.** A public `audit()` API, the contracts frozen under semver, + and "everything works" shown by tests that run the tool the way its users do, on every + platform, against real projects and hostile input. See + [1.0.0](#100--the-promise-kept) for the plan. Known before 1.0: on 1 January 2027, supervision under the Swedish Act moves from Post- och telestyrelsen to Digitaliseringsmyndigheten (förordning 2026:1769, 21 §). The Swedish @@ -38,10 +47,64 @@ build their site with, and get a correct audit, a CI job and a statement they ca It is also the release where "it works" stops being a claim and becomes a set of checks anyone can re-run. -The earlier outline said 1.0 would add no new surface: 0.9 with the guarantees written -down. That still holds everywhere except one place. Stack detection has to cover what -people actually use, Next.js above all, because a tool that cannot find the site cannot -audit it, and every other guarantee here depends on that first step. +The earlier outline said 1.0 would add no new surface, only 0.9 with the guarantees +written down. That turned out to be too narrow for a finished product, and the plan below +adds surface where a user would otherwise hit a wall: +- stack detection that covers what people actually use, Next.js above all, because a tool + that cannot find the site cannot audit it; +- CI beyond GitHub; +- a report a client can read in their own language; +- an API to build on. + +It adds nothing else. Everything is in place before the contracts are frozen, so nothing +arrives after the freeze. + +### What 1.0 looks like to the person using it + +It is built for freelancers and small agencies in the EU, who have had to comply since 28 +June 2025 without an accessibility budget. It does five jobs for them: **find** the +barriers, **keep** them from coming back in CI, **prove** what a person checked by hand, +**publish** the statement their country's law asks for, and **show** a client the result in +a report a non-developer can read. + +- **The first five minutes.** + - `npx eaa-kit` with nothing set up detects the stack, builds or starts the site if it + needs to, audits it and writes `.eaa-kit/report.html`. It ends with three lines: what it + found, what it could not check, and the one command to run next. + - `npx eaa-kit init` asks at most five questions, each with a default read from the site. + It writes the config, a baseline, and a CI workflow for GitHub, GitLab or Bitbucket, + whichever the repository is on. After that, every push is checked. +- **A small, stable set of commands**, one per job: + + | Job | Commands | + | --- | --- | + | First run | `eaa-kit` | + | Set up | `init` | + | Find | `audit` | + | Explain | `detect`, new | + | Keep | `baseline`, `diff` | + | Prove | `checklist` | + | Publish | `statement`, `countries` | + | Diagnose | `doctor`, new: Node, Playwright, config, detection and CI file on one screen | + + Every command has examples in `--help`, and every failure ends with the command to type + next. The exit codes mean the same everywhere: 0 clean, 1 barriers found, 2 could not run. +- **What it hands back.** + - The HTML report is the product's face, the one file a freelancer sends a client. At 1.0 + it also: + - prints cleanly, and can be saved as a PDF; + - is written in the site's language, starting with de, fr, nl, es and it; + - has a "since last time" section when there is a baseline or an earlier report; + - is itself accessible, which CI checks by auditing it. + - For CI: SARIF, and a new Markdown summary for job summaries and PR comments that says + only what this change did. + - The statement for fifteen countries, with authorities that switch on the date the law + says. + - For anyone building on it: a JSON report with a published schema, and a typed + `audit()` and `detect()` library API. The build integrations become thin callers of + that API. + +The rest of this section is how that gets built and shown to work. ### How the work is done: loops with exit conditions @@ -143,8 +206,8 @@ output directory, dev/preview port and anything to skip: - Prints what was recognised and the evidence for it (which package, file or config line), the output directory chosen, and what an audit would build or start. `--json` prints the same as data. -- Detection becomes debuggable by users and testable by the suite. This is the one piece - of new surface in 1.0, and it is marked as a decision below. +- Detection becomes debuggable by users and testable by the suite. The `detect()` library + function returns the same result. **Gate:** - An offline fixture per framework and major version in `tests/fixtures/stacks/`: the file @@ -341,15 +404,26 @@ machine (4 cores, Node 22), so compare checkouts, not machines: ### Order of work -1. 0.9.1: the corrected templates. -2. The contract inventory and surface locks, so nothing after this can change a contract - without it showing. -3. The acceptance and robustness harnesses, which are the tests that guard everything after - them. -4. Stack detection, Next.js first, then monorepos, then the missing frameworks. -5. Speed work, measured against 0.9.x. -6. Content: Sweden's date switch, the citations for all fifteen countries, and the reviews. -7. The release-candidate loop and the soak, then 1.0.0. +Each step is its own release, usable on its own, never a half-done step. + +1. **0.9.1:** the corrected templates, and `release:check` from section 6. +2. **0.10.0:** + - stack detection from section 1, Next.js first, then monorepos and package managers, + then the missing frameworks; + - `detect` and `doctor`; + - the per-framework fixtures, and the nightly real-project job. +3. **0.11.0:** + - GitLab and Bitbucket workflows from `init`, and the `markdown` report format; + - the HTML report's print layout, languages and "since last time"; + - Sweden's date switch, and the citations for all fifteen countries. +4. **1.0.0-rc.N:** + - the `audit()` and `detect()` API, with the integrations moved onto it; + - the contract inventory and surface locks; + - the acceptance and robustness harnesses; + - the speed work measured against 0.9.x; + - the README rewritten around the five jobs; + - the reviews. +5. **1.0.0:** the release-candidate loop and the soak, until the exit condition holds. ### Done means @@ -360,17 +434,21 @@ machine (4 cores, Node 22), so compare checkouts, not machines: the tag. - The speed targets are met, and the published numbers were regenerated with `--against`. -### Decisions needed before work starts - -1. **`eaa-kit detect` as a new command.** Recommended: yes. It is the only new surface in - 1.0, and it makes detection explainable and testable. -2. **Native-speaker review as a release blocker.** Recommended: blocking for Czech, Danish, - Finnish and Swedish, the texts written for 0.9.0, and advisory for the rest. -3. **A moving `v1` tag for the GitHub Action.** Until now the Action was pinned to exact - tags on purpose, because 0.x promised nothing. Under semver a `v1` tag is the - convention. Recommended: yes, from 1.0.0. -4. **The deprecated schemaVersion-1 field** in the JSON report: keep it until 2.0 - (recommended), or remove it now as schemaVersion 3. +### Decisions, taken with the plan on 26 September 2026 + +1. **`detect` and `doctor` are the new commands.** They are the only new commands in 1.0: + `detect` makes detection explainable and testable, and `doctor` puts the environment on + one screen. +2. **GitLab and Bitbucket workflows come from `init`**, next to GitHub's. Many EU agencies + are not on GitHub. +3. **The HTML report speaks the site's language**, starting with de, fr, nl, es and it. +4. **A public `audit()` API ships in 1.0.** Adding it after the freeze would take a 2.0. +5. **Native-speaker review blocks the release** for Czech, Danish, Finnish and Swedish (the + texts written for 0.9.0). It is advisory for the rest. +6. **The GitHub Action gets a moving `v1` tag from 1.0.0.** Until now it was pinned to + exact tags on purpose, because 0.x promised nothing; under semver, a `v1` tag is the + convention. +7. **The deprecated schemaVersion-1 field** in the JSON report stays until 2.0. ## 0.9.0 — the first ten minutes diff --git a/docs/integrations.md b/docs/integrations.md index 4626880..2da4c48 100644 --- a/docs/integrations.md +++ b/docs/integrations.md @@ -250,7 +250,7 @@ jobs: - uses: actions/setup-node@v4 with: node-version: 22 - - uses: likeBloodMoon/eaa-kit@v0.9.0 + - uses: likeBloodMoon/eaa-kit@v0.9.1 with: install-command: npm ci build-command: npm run build diff --git a/examples/report.html b/examples/report.html index 28a6e25..70db090 100644 --- a/examples/report.html +++ b/examples/report.html @@ -3,7 +3,7 @@ - + Accessibility audit · tests/fixtures/site