Skip to content

Part of #1706: autumn a11y verify build-time pass for raw-html escape hatches#1845

Merged
madmax983 merged 17 commits into
trunk-devfrom
1706-a11y-verify-pass
Jul 13, 2026
Merged

Part of #1706: autumn a11y verify build-time pass for raw-html escape hatches#1845
madmax983 merged 17 commits into
trunk-devfrom
1706-a11y-verify-pass

Conversation

@madmax983

@madmax983 madmax983 commented Jul 13, 2026

Copy link
Copy Markdown
Owner

Part of #1706 (Acceptance Criterion 3 + 4). Non-scaffold follow-on to the typed accessible primitives — does not touch scaffold.rs.

Before / After

Before — an alt-less <img> or an unlabeled <input> written in raw html! markup compiles clean and ships silently; the type system only guards code that goes through the typed primitives.

Afterautumn a11y verify fails CI (exit 1) with a WCAG-keyed report:

src/view.rs:3:  [WCAG 1.1.1] Serious — raw <img> has no alt attribute
    hint: use autumn_web::a11y::Img::new(src, alt) / Img::decorative(src)

How

The typed autumn_web::a11y primitives (Img/Button/Link/MenuItem/TextField) already prove accessible-name obligations at compile time for code that uses them. This pass covers the escape hatch the type system can't see: raw markup in maud::html! { … } blocks. There is no walkable widget tree at runtime, so this is an honest best-effort static scan.

  • New module autumn-cli/src/a11y.rs, structured after autumn-cli/src/i18n.rs: it scans project .rs files and token-walks descending into html! macro bodies (the same descent autumn i18n check uses to find t! calls nested in html!), building a Report with an exit_code(strict) and text/JSON output.
  • Reuses the WCAG success-criterion numbers, axe-core rule ids, and Severity semantics from autumn-cli/src/check.rs (the runtime autumn check --a11y lint), applied to static source instead of rendered HTML.
  • --format json emits the "conformance manifest" AC3 asks for: an array of findings keyed to WCAG SCs plus a summary.
  • Exit code is non-zero when findings exist (Serious by default; --strict lowers the threshold to Moderate), mirroring i18n check's exit_code(strict). This is what fails CI.
  • Clap wiring in main.rs: an a11y subcommand group with a verify variant ([PATH] defaulting to ., --format, --strict), dispatched like I18nSubcommands.

Scope note (the honest guarantee)

Typed primitives = the compile-time proof; this pass = the escape-hatch net. A typed primitive spliced into markup as (Img::new(src, alt)) is a (expr) splice, not an img element, so it is never re-scanned or falsely flagged. Like autumn i18n check, the scanner reads tokens rather than a resolved AST and always errs toward not flagging what it cannot resolve, so it never breaks CI on a false positive: a spliced attribute/content value (alt=(caption), button { (label) }) is treated as present, and a <label for>/id association a splice makes unresolvable suppresses the label finding. This is a documented best-effort static scan with a dynamic-value limitation.

WCAG SC mapping

Rule id Element Condition WCAG SC Severity
image-alt <img> no alt attribute 1.1.1 Serious
label <input>/<select>/<textarea> no matching &lt;label for=…&gt;, aria-label, or aria-labelledby 1.3.1 / 3.3.2 / 4.1.2 Serious
button-name &lt;button&gt; no text content and no aria-label/aria-labelledby 4.1.2 Serious
link-name &lt;a href&gt; no link text and no aria-label/aria-labelledby 2.4.4 / 4.1.2 Serious

Tests

  • 28 in-module unit tests over html! snippets: RED cases (alt-less img, unlabeled input/select/textarea, empty button, textless anchor) flagged with the correct WCAG SC; GREEN cases (img with alt / empty alt / dynamic alt, input with matching label for/id, aria-label, wrapped label, button/anchor with text or aria-label, icon button with alt image) clean; a typed-primitive splice and a fully-dynamic splice are not flagged; an element inside a @if block is still scanned.
  • An end-to-end tempdir test: red project (exit 1) → fix → green project (exit 0).
  • 2 clap parse tests for the new subcommand.

Docs (AC4)

docs/guide/accessibility.md gains an autumn a11y verify section: what it checks, the WCAG SC mapping table, a --format json example, CI usage (exit code), and the explicit statement that typed primitives are the compile-time proof while verify catches raw-html! escape hatches.

Gate

cargo fmt --all -- --check, cargo clippy -p autumn-cli --all-targets -- -D warnings, and the new autumn-cli a11y tests all pass.

Follow-ons

  • Extend the ruleset (e.g. redundant/empty alt heuristics, role/tabindex misuse, duplicate id) as further slices.
  • Cross-html!-block &lt;label for&gt;/id resolution (associations currently scoped per block).
  • Optionally surface verify through the /actuator/a11y actuator or a dedicated CI workflow step.

Scope and limitations

  • This PR adds autumn a11y verify, a build-time static scanner over raw maud html! bodies (WCAG rules: image-alt 1.1.1, label 1.3.1 / 3.3.2, button-name / link-name 4.1.2), emitting a WCAG-keyed report and failing CI on findings.
  • It is explicitly best-effort / advisory-grade. It parses maud markup heuristically at the token level and deliberately errs toward not failing on ambiguous, dynamic, or non-maud constructs (unresolved splices, complex Rust expressions, foreign html! macros) to avoid false CI failures. It may therefore miss a defect in exotic raw markup — acceptable by design — but should not fail valid markup.
  • The actual compile-time accessibility guarantee is the typed primitives in autumn_web::a11y (Img/Button/TextField/Link/MenuItem — accessible name is a type-level obligation proven by trybuild), landed in Part of #1706: typed accessible UI primitives (compile-time accessible-name obligation) #1840 and Part of #1706: typed accessible Link and MenuItem primitives #1842. Findings from a11y verify over raw html! are advisory signal, not the proof — consistent with Prove UI accessibility conformance at build time by construction #1706 scoping raw hand-written HTML as the "unverifiable, not proven" escape hatch.
  • The scanner was hardened over many review rounds against maud grammar corners (struct literals, match arms, control heads, class/id shorthands, colon-qualified names, foreign JSX html!). Any remaining niche parser corners are a documented limitation of the best-effort net rather than blockers.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Pf5JUv54F6Bxo8KzErU9sz


Generated by Claude Code

The typed autumn_web::a11y primitives prove accessible-name obligations at
compile time for code that uses them. This adds a build-time pass that covers
the escape hatch the type system cannot see: raw `html!` markup that bypasses
the typed primitives.

`autumn a11y verify` token-scans the `html!` blocks in a project's `.rs` files
(mirroring `autumn i18n check`'s descent into macro bodies) and reports raw
elements missing an accessible name, reusing the WCAG success criteria, rule
ids, and Severity semantics of `autumn check --a11y`:

- image-alt   (WCAG 1.1.1)                 — <img> with no alt
- label       (WCAG 1.3.1 / 3.3.2 / 4.1.2) — form control with no label/aria
- button-name (WCAG 4.1.2)                  — <button> with no name
- link-name   (WCAG 2.4.4 / 4.1.2)         — <a href> with no name

Text and `--format json` (a WCAG-keyed conformance manifest) output, a non-zero
CI exit code (Serious by default, --strict lowers to Moderate), and a best-effort
static scan that skips spliced/dynamic values so a typed-primitive splice like
`(Img::new(src, alt))` is never falsely flagged. Adds the docs section and unit
plus end-to-end tests.

Part of #1706

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pf5JUv54F6Bxo8KzErU9sz
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

@madmax983 madmax983 marked this pull request as ready for review July 13, 2026 06:50
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 22ea4bc799

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread autumn-cli/src/a11y.rs
An unreadable/misspelled/nonexistent PATH made the top-level read_dir
error get swallowed into an empty file list, so `run_in` built a
zero-findings report and exited 0 — printing PASS and silently disabling
the whole audit on a CI path typo.

Make the initial scan-root read fatal (mirroring `autumn i18n check`):
`scan_project` now returns `io::Result<Scan>` and probes the root with
`read_dir`, which surfaces path-absent, not-a-directory, and unreadable
alike. `run_in` reports the io error on stderr and exits non-zero. A
genuinely empty-but-readable directory still reads fine and passes;
nested subdir read errors during recursion stay best-effort as before.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pf5JUv54F6Bxo8KzErU9sz

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 746dc85152

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread autumn-cli/src/a11y.rs Outdated
Comment thread autumn-cli/src/a11y.rs Outdated
…se-positive

An empty <label for=..> was recorded as a valid label association even
though it provides no accessible name, causing check_field to suppress
the label finding for an unlabeled control. Gate the for/id association
on label_provides_name, matching the wrapped-label logic (dynamic bodies
still count).

An input with a spliced type=(kind) fell through the literal-only exempt
branch and was flagged as an unlabeled control. Treat an unresolved
type splice as non-failing, consistent with other splice handling.

Adds focused unit tests for both fixes plus regression guards.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pf5JUv54F6Bxo8KzErU9sz

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 72c8874e29

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread autumn-cli/src/a11y.rs
The static a11y scanner treated a @match block's arm-list brace group as
raw markup, so each arm's Rust pattern (e.g. `input => { .. }`) was parsed
as an element and produced a false `label` WCAG finding on valid views.

Special-case @match: skip the scrutinee, and for each arm skip the pattern
(and any `if <guard>`) up to and including `=>`, then scan only the arm
body as markup. Real elements in arm bodies are still flagged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pf5JUv54F6Bxo8KzErU9sz

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 34ac8b4ec8

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread autumn-cli/src/a11y.rs Outdated
Comment thread autumn-cli/src/a11y.rs
Two false-report fixes in the raw-html! a11y scanner:

- Dynamic `for` labels (`label for=(id) { }`) set the block-wide
  dynamic-for marker without the `label_provides_name` guard the
  literal-`for` path already had, so an empty spliced-`for` label made
  every static-id control pass as labeled (false negative). Apply the
  same guard so only a name-providing label registers the association.

- `skip_control` parsed an `@let` initializer's brace group as markup,
  so `@let props = Field { input: true };` misread the Rust field
  `input` as an unlabeled `<input>` (false positive). Route `@let`
  through a new `skip_let` that consumes the binding to its top-level
  `;` without descending into any brace; `@if`/`@for`/`@match` are
  unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pf5JUv54F6Bxo8KzErU9sz

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1f2b284633

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread autumn-cli/src/a11y.rs Outdated
…verify

An icon-only button/link whose only content is an aria-hidden="true"
glyph is effectively nameless, but named_content still counted that
hidden text, wrongly suppressing the button-name/link-name finding. Skip
literal aria-hidden="true" subtrees when deriving the accessible name;
a dynamic aria-hidden=(expr) stays conservatively not-hidden.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pf5JUv54F6Bxo8KzErU9sz

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 806c6c8bb3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread autumn-cli/src/a11y.rs Outdated
Comment thread autumn-cli/src/a11y.rs Outdated
…n a11y verify

BUG 1 (false positive): collect_labels dropped top-level (expr) splice
siblings, so a fragment-composed label spliced beside a raw control
(html! { (field_label) input id="email"; }) was treated as absent and
the control wrongly flagged. Node::Dynamic now records whether it is a
genuine splice vs an @-control head; a spliced fragment marks the block
as possibly-labeled, mirroring the dynamic-for convention. @-control
heads do not set the marker, so unrelated static controls stay flagged.

BUG 2 (false negative + false positive): the label validity check used a
naive text-any/dynamic walk that accepted aria-hidden text and ignored
child <img alt>. label_provides_name now reuses content_provides_name --
the same aria-hidden-excluding, img-alt-including, dynamic-counting walk
used for buttons/links -- so a hidden-only label is flagged and an
img-alt label is clean. Removes the now-dead subtree_has_text/dynamic.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pf5JUv54F6Bxo8KzErU9sz

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 43326c19ba

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread autumn-cli/src/a11y.rs Outdated
Comment thread autumn-cli/src/a11y.rs Outdated
…verify

Two follow-ons to the Node::Dynamic { splice } parser change:

- BUG (false negative): the accessible-name walk counted every Node::Dynamic
  as a name, so a control that contains only an @-control HEAD (splice: false,
  its branch bodies already parsed out) — e.g. `button { @if disabled { } }` or
  an empty `label { @if show { } }` — wrongly passed. content_provides_name now
  counts only a genuine (expr)/[..] splice (splice: true), matching the
  distinction already used by collect_labels.

- BUG (false positive): after a parsed control block, skip_control treated ANY
  following @ token as an @else continuation, so a sibling @let never reached
  skip_let and its `Field { input: true }` struct literal was misparsed as
  markup, reporting a bogus unlabeled <input>. The continuation is now gated on
  @else only; any other @-control is returned to parse_nodes for its proper
  handler. Genuine @if@else … / @else if chains still parse.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pf5JUv54F6Bxo8KzErU9sz

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4820c93f52

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread autumn-cli/src/a11y.rs Outdated
Comment thread autumn-cli/src/a11y.rs
claude added 2 commits July 13, 2026 09:14
… remaining edge cases

Address two reviewer findings plus proactively-found genuine defects in the
best-effort maud token-walker and ARIA accessible-name logic — every change
either removes a false positive on valid markup or restores a missed real
defect, never the reverse.

Parser (false positives on valid markup):
- skip_control: handle `@if`/`@while` block-expression conditions
  (`@if { cond } { body }`, condition parsed with parse_without_eager_brace)
  and `let`/`for` struct-pattern braces (`@for Foo { x } in xs`,
  `@if let Foo { x } = e`); the body is the final brace of the clause. Also
  covers `@while`, `@else if` chains, and block-expr conditions across `@else`.
- skip_match: skip a leading block-expression scrutinee (`@match { x } { arms }`).
- parse_shorthand: consume dynamic (`.(expr)`/`#(expr)`) and toggled
  (`.class[cond]`) shorthand values so the element does not end early and
  orphan its `{ … }` body; record `#(expr)` as a dynamic id.

Accessible-name / rules:
- collect_labels + walk: scope splice-fragment label suppression to a control's
  DIRECT sibling list instead of the whole block, so an unrelated nested splice
  (`p { (user.name) }`) no longer disables the unlabeled-control rule.
- aria-hidden on the control itself (and its subtree) exempts it from the rules.
- `title` counts as a last-resort accessible name for button/link/form controls.
- `<img>` is named by aria-label/aria-labelledby/title or a presentational
  role, not only by `alt`.
- a descendant's own aria-label/aria-labelledby/title contributes to the
  name-from-content walk.

Adds focused unit tests for each fix (false-positive gone AND a real defect in
the same construct still caught).

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 38b191c766

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread autumn-cli/src/a11y.rs
Comment thread autumn-cli/src/a11y.rs
Fix two false positives in `autumn a11y verify`'s maud shorthand parsing:

- A leading `.`/`#` shorthand with no explicit tag (`.input { }`,
  `#button { }`) is maud's implicit `<div>`; the scanner dropped the
  punctuation and read the class/id token as a phantom `<input>`/`<button>`.
  It is now parsed as a `div` element (no rule), while its body is still
  scanned for real controls.

- A markup-valued class shorthand (`button.@if c { "x" } { "Save" }`) ended
  the element before its real `{ … }` body, so the control was analyzed as
  empty and falsely flagged. The `@`-control (and braced markup group) class
  value is now fully consumed before the element's real body is parsed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pf5JUv54F6Bxo8KzErU9sz

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2548277fb4

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread autumn-cli/src/a11y.rs
Comment thread autumn-cli/src/a11y.rs Outdated
Comment thread autumn-cli/src/a11y.rs
… subtrees

Fix three false-result bugs in the raw-html! accessibility scanner:

- BUG 1 (false positive): only analyze maud html! bodies. A different html!
  macro (e.g. a Yew/JSX island using <tag>...</tag>) was fed to the maud
  parser, which stripped the angle brackets and misread <button></button> as
  an empty maud button -> false button-name. Detect JSX angle-bracket tag
  syntax (`<` followed by an ident or `/`) and skip such bodies entirely.

- BUG 2 (false positive): maud names accept `:` as well as `-`. read_name now
  consumes colon-qualified names (x-on:click, svg:path, data:foo) as one name,
  so the element's real { ... } body is still parsed instead of being orphaned
  at the leftover `:`.

- BUG 3 (false negative): collect_labels now stops descending into
  aria-hidden="true" subtrees, consistent with walk. A <label for=..> that
  only exists inside a hidden container no longer counts, so the visible input
  is correctly flagged.

Adds 8 focused unit tests (113 -> 121 a11y tests).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pf5JUv54F6Bxo8KzErU9sz

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0ba5abcaf3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread autumn-cli/src/a11y.rs Outdated
Comment thread autumn-cli/src/a11y.rs Outdated
Comment thread autumn-cli/src/a11y.rs
Clarify that `autumn a11y verify` is a build-time static scanner over raw
maud html! bodies that is best-effort and advisory: it errs toward not
failing on ambiguous/dynamic/non-maud constructs, so it can miss a defect
in exotic markup and its raw-html! findings are advisory-grade, not proof.
The complete compile-time accessibility guarantee lives in the typed
primitives in autumn_web::a11y. Docs only; no scanner behavior changes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pf5JUv54F6Bxo8KzErU9sz

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7de84206e7

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread autumn-cli/src/a11y.rs
…me edge cases

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pf5JUv54F6Bxo8KzErU9sz

Copy link
Copy Markdown
Owner Author

autumn a11y verify — review disposition

The static scanner has been hardened across ~20 review rounds against maud grammar corners, and the latest commit (c6f6be1) fixes the qualifying items:

  • JSX-vs-Rust comparison false-negative — a </> comparison in a control head (e.g. @if count < limit { … }) no longer causes the surrounding html! block to be skipped.
  • @if match { … } { … } control-head false-positive — the match-condition arm list is no longer parsed as markup, so a pattern name like input no longer produces a bogus label finding.
  • Whitespace-only static name attributesaria-label / title / alt values that are only whitespace now correctly count as an empty accessible name.

Per the newly documented Scope and limitations (see the PR "Scope and limitations" section, the a11y.rs module docs, and docs/guide/accessibility.md): this scanner is explicitly best-effort / advisory-grade over raw html!. The compile-time accessibility guarantee is the typed primitives in autumn_web::a11y (landed in #1840 / #1842), where accessible name is a type-level obligation proven by trybuild — a11y verify is advisory signal for the raw-markup escape hatch, not the proof.

Remaining suggestions that are missed-check coverage gaps on raw markup (e.g. requiring a name on input type="button" / input type="image") are acknowledged as candidate follow-ons within that best-effort scope — advisory net improvements rather than correctness blockers for this PR. Deliberately erring toward not flagging ambiguous, dynamic, or non-maud constructs is by design, to avoid false CI failures.

Thanks for the thorough pass — the corner-case coverage is meaningfully better for it.


Generated by Claude Code

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c6f6be1513

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread autumn-cli/src/a11y.rs
Comment thread autumn-cli/src/a11y.rs
…rify

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pf5JUv54F6Bxo8KzErU9sz

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4db18643b3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread autumn-cli/src/a11y.rs Outdated
Comment thread autumn-cli/src/a11y.rs
Fix two false positives that made the a11y verify scanner fail valid
maud markup:

- Element tag names are a full maud HtmlName
  (Punctuated<HtmlNameFragment, '-' | ':'>), so read the whole name via
  read_name instead of only the first ident. Custom/namespaced tags like
  x-input, x-button, and svg:rect are now one tag (matching no rule)
  rather than a phantom input/button suffix.
- A Rust macro call in an @if/@while/@for condition head
  (ready! { input }) owns its !-delimited group as macro input, part of
  the condition. Detect ident-followed-by-! and skip the group so it is
  not misparsed as markup, leaving the final brace as the body.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pf5JUv54F6Bxo8KzErU9sz

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4110eb02ee

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread autumn-cli/src/a11y.rs Outdated
Comment thread autumn-cli/src/a11y.rs Outdated
maud HtmlName fragments may be integers, so a name reader that stopped at
a numeric fragment (e.g. .col-12, data-1) orphaned the element body and
falsely flagged named buttons/links as empty. Read integer fragments as
part of the name.

Elements with the native boolean hidden attribute are removed from the
accessibility tree, so extend the hidden predicate (used by walk,
collect_labels, and content_provides_name) to treat a present static
hidden as hidden alongside aria-hidden="true". A dynamic hidden=(expr)
stays non-hidden (conservative).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pf5JUv54F6Bxo8KzErU9sz

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3a5a15e7b3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread autumn-cli/src/a11y.rs
@madmax983 madmax983 merged commit b363b8f into trunk-dev Jul 13, 2026
39 of 40 checks passed
@madmax983 madmax983 deleted the 1706-a11y-verify-pass branch July 13, 2026 16:47
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