Skip to content

feat(atomic-a11y): add OpenACR converter modules#7124

Open
y-lakhdar wants to merge 31 commits intofeat/a11y-merge-shardsfrom
feat/a11y-openacr
Open

feat(atomic-a11y): add OpenACR converter modules#7124
y-lakhdar wants to merge 31 commits intofeat/a11y-merge-shardsfrom
feat/a11y-openacr

Conversation

@y-lakhdar
Copy link
Contributor

@y-lakhdar y-lakhdar commented Feb 16, 2026

TL;DR

Converts the a11y-report.json (from the Vitest reporter) into OpenACR-compliant YAML — the machine-readable format behind VPAT 2.5 accessibility conformance reports.

What it does

After the reporter (#7123) captures axe-core results and the shard merger (#7137) consolidates parallel runs, we need to translate that data into an industry-standard format. OpenACR is the format the U.S. GSA uses for machine-readable VPATs.

a11y-report.json  +  manual-audit-*.json  +  a11y-overrides.json
      │                    │                        │
      └────────────────────┴────────────────────────┘
                           │
                 transformJsonToOpenAcr()
                           │
                           ▼
                  reports/openacr.yaml

Conformance priority: override → manual audit → existing report → automated (axe-core)

Design decisions

Schema-aligned output types

The OpenAcrReport and OpenAcrCriterion types match the official GSA OpenACR 0.1.0 JSON Schema exactly. No custom extensions are added to the YAML output — the @openacr/openacr CLI only reads official schema fields (num, components[].adherence.level, components[].adherence.notes), so anything extra would be dead data.

Runtime validation of the generated YAML against the official schema is handled in #7164.

Options objects for conformance functions

resolveConformance() and buildRemarks() use typed context objects (ConformanceContext, RemarksContext) instead of positional parameters. Both share the same base context (criterion, aggregate, manual aggregates, override), and buildRemarks extends it with the resolved conformance and component lists.

File organization

  • types.ts — Only type definitions and mapping constants. No functions.
  • manual-audit.ts — Parsing, loading, and counting logic for manual audit baselines.
  • conformance.ts — Conformance resolution priority chain and remarks generation.
  • report-builder.ts — Assembles the full OpenACR structure.
  • json-to-openacr.ts — Entry point that wires I/O together.

How to review

Order File What to look for
1 json-to-openacr.ts Entry point — reads inputs, writes YAML
2 conformance.ts resolveConformance() priority chain + buildRemarks()
3 report-builder.ts Assembles full OpenACR structure (chapters, criteria)
4 manual-audit.ts Parses manual-audit-*.json baselines, worst-wins resolution
5 overrides.ts Loads a11y-overrides.json per-criterion exceptions
6 types.ts OpenACR interfaces (schema-aligned) + conformance mapping constants

Try it

Minimal run (automated data only)

If reports/a11y-report.json exists (from the Vitest reporter), you can generate the OpenACR YAML immediately:

node scripts/json-to-openacr.mjs
# → writes reports/openacr.yaml

If the input report doesn't exist yet, the converter still runs — it produces a placeholder YAML with all 55 criteria set to not-evaluated.

Full loop (with manual audits + overrides)

1. Create a manual audit baseline in a11y/reports/:

mkdir -p a11y/reports
// a11y/reports/manual-audit-search.json
[
  {
    "name": "atomic-search-box",
    "category": "search",
    "manual": {
      "status": "complete",
      "wcag22Criteria": {
        "1.1.1-non-text-content": "pass",
        "2.1.1-keyboard": "pass",
        "2.4.7-focus-visible": "partial",
        "4.1.2-name-role-value": "fail"
      }
    }
  }
]

Files must match manual-audit-*.json (no -violations in the name). Only entries with "status": "complete" are processed. Status values: pass, fail, partial, not-applicable.

See docs/manual-audit-guide.md for the full QA reference on manual baselines.

2. (Optional) Add a conformance override in a11y/:

// a11y/a11y-overrides.json
{
  "overrides": [
    {
      "criterion": "1.4.2",
      "conformance": "not-applicable",
      "reason": "Atomic components do not produce audio output."
    }
  ]
}

3. Run the converter:

node scripts/json-to-openacr.mjs

You'll see output like:

[json-to-openacr] Loaded 1 conformance override(s) from a11y/a11y-overrides.json.
[json-to-openacr] Loaded {x} manual audit entries across {x} criteria from x baseline file(s): {filename}.

Tests

Extracted to #7163 to keep this PR focused on implementation.

PR Chain (5 of 8)

# PR Description
1 #7111 Package scaffolding
2 #7122 Shared types, constants, utilities
3 #7123 VitestA11yReporter + wiring
4 #7137 Shard merging
5 #7124 OpenACR generator ← this PR
6 #7163 OpenACR tests
7 #7164 Schema validation
8 #7125 CLI scripts
9 #7117 CI workflow

KIT-5470

- Add VitestA11yReporter class for collecting axe-core results during vitest runs
- Add reporter-utils.ts with shard resolution, component extraction, error processing
- Add axe-integration.ts with axe-core type guards and WCAG tag parsing
- Add merge-shards.ts for combining sharded a11y reports
- Add unit tests for reporter (9 tests) and merge-shards (3 tests)
- Update index.ts with reporter exports
- Add test and a11y:merge-shards scripts to package.json
- Add src/openacr/types.ts with OpenACR interfaces and conformance mappings
- Add src/openacr/overrides.ts for loading override configuration
- Add src/openacr/manual-audit.ts for manual audit baseline parsing and resolution
- Add src/openacr/conformance.ts for multi-source conformance calculation
- Add src/openacr/report-builder.ts for building OpenACR report structure
- Add src/openacr/yaml-serializer.ts with hand-rolled YAML serializer (no deps)
- Add src/reporter/json-to-openacr.ts as slim CLI orchestrator (137 lines)
- Add unit tests for json-to-openacr (7 tests)
- Update index.ts with OpenACR exports
- Add a11y:vpat script to package.json
Copy link

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

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: 94a34f0b09

ℹ️ 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".

@y-lakhdar y-lakhdar marked this pull request as ready for review February 26, 2026 16:06
Copy link

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

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: d26e8a39e0

ℹ️ 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".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant