Skip to content

fix: six bugs found by using 0.4.0 on real builds - #21

Merged
likeBloodMoon merged 1 commit into
masterfrom
claude/release-0.4.0-testing-qe8mnu
Sep 1, 2026
Merged

fix: six bugs found by using 0.4.0 on real builds#21
likeBloodMoon merged 1 commit into
masterfrom
claude/release-0.4.0-testing-qe8mnu

Conversation

@likeBloodMoon

Copy link
Copy Markdown
Owner

Each of these was reached by running 0.4.0 against real builds — a static site, an auto-detected project, a crawled server, both engines — rather than by reading the code. Every one is a case where a report stated something that was not true.

The two that matter most

audit --browser audited nothing unless it was handed a directory.

The browser runner takes the build directory so it can serve the pages over loopback; passing nothing is how a caller says these pages came off a running site and already have somewhere to be fetched from. The audit command passed the directory the user typed — which under auto-detection is nothing, because auto-detection is the thing that works it out. So eaa-kit audit --browser, the form the README leads with, skipped the loopback server and navigated Chromium to /home/you/site/dist/index.html: a filesystem path, not a URL.

$ eaa-kit audit --browser
Summary
  No violations across the 2 pages that were audited.
  2 pages could not be audited
error 2 of 2 pages could not be audited

Every page came back Cannot navigate to invalid URL. --browser ./dist was never affected, which is why the suite never saw it: every browser test named a directory. The collection stage now reports the directory it settled on, and both audit and baseline pass that along. A real crawl still passes nothing — serving a crawled page back out of a copy on disk would audit the markup with the server that produced it cut out of the picture.

A baseline stopped suppressing a barrier when anything else on the page changed, and diff called that same untouched barrier fixed.

The identity of a violating element hashed the element's whole outer markup. For the document-level rules — html-has-lang, document-title, everything that fails against <html> — the element's outer markup is the entire page. Adding one paragraph gave them a new identity, and all three consumers believed it:

$ # added one <p> to kontakt.html; changed nothing else
$ eaa-kit diff before.json after.json
Fixed (2)
  document-title (serious) — Documents must have <title> element to aid in navigation
    kontakt.html html

The page still had no <title>. Alongside that, the baseline went red on barriers a team had already accepted (5 accepted → 3 accepted and 3 "new" from one added <img>), and SARIF churned its fingerprints so code scanning closed an alert and opened an identical one on every edit.

The hash now covers the element's opening tag and not its descendants. Where two elements share an opening tag, axe-core's selector already tells them apart — it qualifies an ambiguous match with :nth-child(…) — so nothing that could be distinguished before stops being distinguishable, and a barrier that is genuinely fixed still changes identity. Verified both directions: an unrelated edit now yields 0 new · 0 fixed · 5 unchanged, while adding lang and a <title> still yields 0 new · 2 fixed.

The other four

  • A run where every page failed reported "No violations". The count in that sentence was of pages attempted, not pages audited, so a run that could read none of them opened its summary with a clean result in green — the exact fail-open the rest of the tool is built to refuse. It now says nothing was audited, and where only some pages failed the counts are over the pages actually read.

  • A browser run reported criteria as unevaluable and then advised --browser. The coverage view consulted the table of rules jsdom is structurally blind to without asking which engine had run, so a report produced in real Chromium said 2.1.1 Keyboard — this engine could not evaluate it (--browser would answer this). It now believes a browser run's own results.

  • A filter that excluded every page was reported as an empty build directory, together with framework advice naming another directory to audit — a fix for a path that was never wrong. --include/--exclude matching nothing now says so and echoes the patterns.

  • One unreachable page was counted in the singular and conjugated in the plural: "1 page could not be reached, and were not audited".

Contract versions

The fingerprint change moves both file contracts, by the project's own rule that a field changing meaning bumps the version:

was now
baseline schemaVersion 1 2
JSON report schemaVersion 1 2
SARIF partial fingerprint key eaaKit/v1 eaaKit/v2

Neither is read across the boundary, and that is deliberate rather than incidental: matching 0.4.0 baseline entries against the new rule would suppress nothing while looking as though it had, and diffing a 0.4.0 report against a newer one is precisely the comparison that reports every document-level barrier as both new and fixed. Both refusals name the command that resolves them. Checked-in examples and the docs are regenerated.

Validation

  • pnpm test — 49 files, 1061 passing, 2 skipped, including the browser suite against real Chromium
  • pnpm lint, pnpm typecheck, pnpm smoke, pnpm test:packaged all clean
  • New: tests/audit/fingerprint.test.ts, tests/cli/pages.test.ts, plus cases in the coverage, console-report, CLI-audit, CLI-baseline and Playwright suites
  • The end-to-end --browser regression test was confirmed to fail against the old code before the fix, not just to pass after it

🤖 Generated with Claude Code

https://claude.ai/code/session_012xCGmHyxdTMCF2GFwr4CAm


Generated by Claude Code

Each of these was reached by running the tool rather than reading it, and
each is a case where a report said something that was not true.

audit --browser audited nothing unless it was given a directory. The runner
takes the build directory so it can serve the pages over loopback; passing
nothing is how a caller says these pages came off a running site. The audit
command passed the directory the user typed, which under auto-detection is
nothing — so `eaa-kit audit --browser`, the form the README leads with,
navigated Chromium to a filesystem path and failed every page. The
collection stage now reports the directory it settled on.

A baseline stopped suppressing a barrier when anything else on the page
changed, and diff reported that same untouched barrier as fixed. The
element fingerprint hashed the whole outerHTML, and for the document-level
rules the failing element is <html>, whose outerHTML is the entire page. It
now covers the opening tag only; axe-core's selector already separates
elements that share one. This moves the baseline and JSON report schema
versions to 2 and the SARIF fingerprint key to eaaKit/v2, because reading
either across the boundary produces exactly the falsehood being fixed.

A run where every page failed opened its summary with "No violations" in
green. The count was of pages attempted rather than pages audited.

A browser run reported criteria as unevaluable and then advised --browser,
because the coverage view consulted jsdom's blind-spot table without asking
which engine had run.

A filter that excluded every page was reported as an empty build directory,
with framework advice naming another directory to audit.

One unreachable page was counted in the singular and conjugated in the
plural.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012xCGmHyxdTMCF2GFwr4CAm
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@likeBloodMoon
likeBloodMoon merged commit 4673574 into master Sep 1, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants