Skip to content

feat: multi-dimensional health scoring + source-level accessibility analysis#65

Merged
himerus merged 16 commits intomainfrom
staging
Mar 14, 2026
Merged

feat: multi-dimensional health scoring + source-level accessibility analysis#65
himerus merged 16 commits intomainfrom
staging

Conversation

@himerus
Copy link
Copy Markdown
Contributor

@himerus himerus commented Mar 14, 2026

Summary

This release transforms helixir from a single-score CEM documentation checker into a multi-dimensional component health scoring engine with source-level accessibility analysis. The scoring system now evaluates components across 6 independently-weighted dimensions with an enterprise grade algorithm, and can read actual component source code to measure real accessibility implementation — not just what the CEM metadata happens to capture.

What changed

Multi-dimensional scoring engine — Components are now scored across 6 CEM-native dimensions (with 5 external dimensions ready for future data sources):

Dimension Weight What it measures
CEM Completeness 15% Description, property/event/slot/CSS part documentation
Accessibility 10% ARIA patterns, keyboard handling, focus management (CEM + source)
Type Coverage 10% Property types, event payload types, method return types
API Surface Quality 10% Method docs, attribute reflection, defaults, property descriptions
CSS Architecture 5% Custom property descriptions, design token naming, CSS parts docs
Event Architecture 5% Kebab-case naming, typed payloads, event descriptions

Each dimension produces sub-metrics with individual scores, making it clear exactly where a component is strong or weak.

Enterprise grade algorithm — Grades (A–F) are not just a score threshold. Critical dimension gates prevent gaming:

  • 0% on any measured critical dimension → grade capped at C
  • <50% on any critical dimension → grade capped at D
  • Untested critical dimensions restrict grade ceiling
  • Weighted scoring excludes unmeasured dimensions from the denominator (no inflation)

Source-level accessibility scanner — The CEM standard captures ~20% of real accessibility implementation. The other 80% lives in source code: ARIA template bindings, keyboard handlers, focus management, form internals, live regions. helixir now reads component source files (located via CEM module paths) and scans for 7 categories of accessibility patterns using framework-agnostic regexes:

  1. ARIA Template Bindings (25 pts) — aria-checked=${this.checked}, .ariaLabel, setAttribute('aria-...')
  2. Role Assignments (15 pts) — role="button", setAttribute('role', ...)
  3. Keyboard Handling (20 pts) — @keydown=, addEventListener('key...), key switch blocks
  4. Focus Management (15 pts) — .focus(), tabindex, aria-activedescendant, focus traps
  5. Form Internals (10 pts) — attachInternals(), static formAssociated, setFormValue
  6. Live Regions (10 pts) — aria-live, role="alert", aria-atomic
  7. Screen Reader Support (5 pts) — aria-hidden, .sr-only, aria-labelledby

When source is available, accessibility scoring blends 30% CEM + 70% source (source is ground truth). When source isn't available, CEM-only scoring still works — graceful degradation.

Deep mixin-aware scanning — Many component libraries implement accessibility in shared mixins and base classes, not in each component file. The deep scanner follows CEM superclass/mixin declarations and a11y-relevant import statements through the full inheritance chain (depth-limited to prevent infinite loops). It aggregates accessibility markers across all files in the chain and classifies component architecture as inline, mixin-heavy, controller-based, or hybrid.

Honest scoring for empty CEM data — Previously, components with no members/events/CSS properties in their CEM received perfect 100/100 scores (the analyzer defaulted to full points when dividing by zero). This inflated scores for libraries with poor CEM metadata. Now, analyzers return null when there's nothing to evaluate, and those dimensions are excluded from the weighted average entirely — same principle as not penalizing presentational components for lacking accessibility patterns.

CEM accessibility reweight — The CEM-based accessibility analyzer was reweighted to stop penalizing libraries for data the CEM standard doesn't capture. ARIA attributes and keyboard handling (which almost no CEM generator extracts) were moved to "bonus" points. The reweight reflects what CEM can actually measure vs. what requires source scanning.

New MCP tools

  • score_component_multi_dimensional — Full 11-dimension scoring for a single component
  • score_all_multi_dimensional — Score every component in the library
  • audit_library — JSONL audit report generation (one JSON line per component)

New files

File Purpose
handlers/dimensions.ts Dimension registry, grade algorithm, weighted scoring
handlers/analyzers/source-accessibility.ts Source-level a11y scanner (shallow + deep)
handlers/analyzers/mixin-resolver.ts Inheritance chain resolution for deep scanning
handlers/analyzers/type-coverage.ts Type annotation completeness analyzer
handlers/analyzers/api-surface.ts API quality analyzer
handlers/analyzers/css-architecture.ts CSS architecture analyzer
handlers/analyzers/event-architecture.ts Event architecture analyzer
handlers/audit-report.ts JSONL audit report generator

Test coverage

1640 tests, all passing. New test files:

  • tests/handlers/dimensions.test.ts — 363 lines, grade algorithm edge cases, weighted scoring, critical dimension gates
  • tests/handlers/multi-dimensional-health.test.ts — 374 lines, full scoring pipeline integration
  • tests/handlers/analyzers.test.ts — 301 lines, all 4 CEM-native analyzers
  • tests/handlers/source-accessibility.test.ts — 400 lines, regex pattern detection across frameworks
  • tests/handlers/deep-source-accessibility.test.ts — 490 lines, mixin chain resolution, deep vs shallow comparison across 14 real-world libraries
  • tests/handlers/source-accessibility-wc-libraries.test.ts — 425 lines, full source scanning against real library repos
  • tests/handlers/source-accessibility-real-libs.test.ts — 282 lines, integration tests against real CEMs
  • tests/handlers/audit-report.test.ts — 184 lines, JSONL generation and summary aggregation
  • tests/config-rename.test.ts — 115 lines, config file rename migration
  • Updated: tests/handlers/accessibility.test.ts — +179 lines for reweighted scoring

Config changes

  • Config file renamed from mcp-wc.json to helixir.mcp.json (with backward-compatible migration)
  • config.ts updated with new fields: healthHistoryDir, tsconfigPath, tokensPath, cdnBase, watch

Validated against 14 real-world component libraries

The source scanner and multi-dimensional scoring have been validated against full source repos of: Shoelace, PatternFly Elements, Lion, Vaadin, Spectrum (Adobe), Material Web (Google), Carbon (IBM), Fluent UI (Microsoft), Wired Elements, Ionic, Porsche Design System, Calcite (Esri), UI5 (SAP), and Elix. These cover Lit, FAST, Stencil, vanilla, and hybrid architectures — confirming the scanner works across all major web component frameworks.

Test plan

  • npx vitest run — 1640/1640 tests pass
  • npm run build — 0 TypeScript errors
  • prettier --check . — all files formatted
  • ESLint passes via pre-commit hooks
  • Source scanner validated against 14 real-world WC libraries
  • Deep scanner correctly follows mixin/superclass chains
  • Empty CEM data returns null (not inflated 100/100)
  • Backward-compatible config migration works
  • New MCP tools register and respond correctly
  • Helix team pulls latest and runs against their component library

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added /update-helixir slash command, a JSONL audit-report tool, multi-dimensional component health scoring (11 dimensions) and new analyzers; enhanced source-level accessibility scanning with deep inheritance-aware analysis.
  • Configuration

    • Primary config moved to helixir.mcp.json with backward-compatible fallback to mcpwc.config.json (deprecation warnings).
  • Documentation

    • Expanded architecture, security, performance, gotchas, and testing docs.
  • Version

    • Bumped package version to 0.3.0.

github-actions Bot and others added 10 commits March 13, 2026 16:32
…ssibility-analyzer-for

fix: reweight accessibility analyzer for CEM-realistic scoring
…ty scanner

Phase 2 of the helixir health system:
- Multi-dimensional scoring engine (11 dimensions, enterprise-grade algorithm)
- Source-level accessibility scanner: regex-based analysis of component source
  files detecting ARIA bindings, keyboard handlers, focus management, form
  internals, live regions, and screen reader support patterns
- CEM schema hardened for real-world manifests (Lion, Vaadin edge cases)
- Source file resolution with 5 strategies (direct .ts/.js, src/ prefix,
  .component.ts convention)
- Real-world validation against 5 official WC library source repos
  (Shoelace, Spectrum, PatternFly, Vaadin, Lion)
- 1538 tests, all passing

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds inheritance chain following to the source-level accessibility scanner.
The scanner now traces CEM superclass/mixin declarations and follows
a11y-relevant imports to scan the FULL inheritance chain — not just the
component's leaf file.

Key additions:
- mixin-resolver.ts: resolves CEM superclass/mixin module paths to files,
  follows a11y-relevant imports (FocusMixin, FormControlMixin, etc.),
  classifies architecture (inline/mixin-heavy/controller-based/hybrid)
- CEM schema: added superclass, mixins, inheritedFrom fields
- analyzeSourceAccessibilityDeep(): chain-aware scoring with per-source
  breakdown showing which file contributed which patterns

Results against real libraries (shallow → deep):
  Vaadin:     24 → 62/100  (+38 points, mixin-heavy architecture)
  Spectrum:   48 → 57/100  (+9 points, hybrid architecture)
  Lion:       23 → 28/100  (+5 points, needs deeper package resolution)
  Shoelace:   61 → 64/100  (+3 points, inline architecture)
  PatternFly: 44 → 45/100  (+1 point, inline architecture)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add Material Web (Google, 97), Carbon (IBM, 110), Fluent UI (Microsoft, 41),
Wired Elements (26), Ionic (97), and Porsche Design System (91) to the
source-level accessibility scanner test suite. Total: 812 components across
11 libraries covering Lit, FAST, Stencil, and vanilla architectures.

Also fix CEM member name schema to handle undefined names in generated CEMs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Calcite (Esri/Lumina), UI5 (SAP), and Elix (vanilla) bring the test
arsenal to 14 libraries and 1,162 components. Elix proves the deep
scanner's value: 0/100 shallow → 61/100 deep (+61 points) because
ALL a11y patterns live in mixins like KeyboardMixin, AriaListMixin,
and FormElementMixin — invisible to single-file scanning.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Analyzers (type-coverage, api-surface, event-architecture, css-architecture)
now return null when there's no data to score (0 members, 0 events, 0 CSS
properties). These dimensions are excluded from the weighted average instead
of getting free perfect scores. Also fixes 7 TypeScript build errors in
audit-report, benchmark, and compare handlers.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 14, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 89d52428-bda2-405b-82cf-0c105e391e44

📥 Commits

Reviewing files that changed from the base of the PR and between ed023d9 and b0555ad.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (3)
  • .coderabbit.yaml
  • package.json
  • pnpm-workspace.yaml

Walkthrough

This PR adds a multi-dimensional component health scoring system (11 dimensions), source-level accessibility scanning with inheritance/mixin resolution, four new analyzers, config migration to helixir.mcp.json with legacy fallback, audit JSONL reporting, CLI/tool integration, many tests, and bumps version to 0.3.0.

Changes

Cohort / File(s) Summary
Memory & Documentation
.automaker/memory/api.md, .automaker/memory/architecture.md, .automaker/memory/gotchas.md, .automaker/memory/performance.md, .automaker/memory/security.md, .automaker/memory/testing.md, .automaker/memory/validation.md
Updated usage statistics and added/expanded documentation covering async I/O patterns, error handling, security practices, DoS defenses, CI granularity, multi-library readiness, and expanded gotchas.
Version & Release
package.json, CHANGELOG.md, .changeset/add-update-helixir-command.md
Bumped package version 0.2.0 → 0.3.0, updated pnpm overrides, added changelog entry for /update-helixir, and removed the referenced changeset file.
Config Migration & Tests
packages/core/src/config.ts, tests/config-rename.test.ts
Adds primary config path helixir.mcp.json with fallback to legacy mcpwc.config.json (deprecation/malformed warnings); tests validate rename/fallback/malformed behaviors.
Core analyzers (new)
packages/core/src/handlers/analyzers/type-coverage.ts, packages/core/src/handlers/analyzers/api-surface.ts, packages/core/src/handlers/analyzers/css-architecture.ts, packages/core/src/handlers/analyzers/event-architecture.ts, packages/core/src/handlers/analyzers/index.ts
Adds four analyzer modules and a barrel export. Each analyzer computes sub-metrics, score (0–100), and confidence; exported interfaces and analyze* functions added.
Source-level accessibility & resolver
packages/core/src/handlers/analyzers/source-accessibility.ts, packages/core/src/handlers/analyzers/mixin-resolver.ts
Introduces source scanners (PATTERNS, markers, scoring), resolveComponentSourceFilePath, deep analyzeSourceAccessibilityDeep with inheritance/mixin resolution, aggregation of per-source markers, and architecture classification.
Health, dimensions & audit
packages/core/src/handlers/dimensions.ts, packages/core/src/handlers/health.ts, packages/core/src/handlers/audit-report.ts
Implements DIMENSION_REGISTRY (11 dims), weighting/grade algorithm, computeWeightedScore/calculateGrade, multi-dimensional scoring APIs (scoreComponentMultiDimensional, scoreAllComponentsMultiDimensional), history blending for external dims, and JSONL audit report generation (generateAuditReport + AuditSummary).
Accessibility handler updates
packages/core/src/handlers/accessibility.ts, tests/handlers/accessibility.test.ts
Broadened ARIA role inference (tag-name), expanded keyboard/focus/form signals, adjusted weighting and scoring; tests updated/expanded to reflect new signals and scoring expectations.
CEM inheritance modeling
packages/core/src/handlers/cem.ts
Adds schemas/types for superclass/mixin/inheritedFrom, optional fields on members/declarations, InheritanceEntry, getDeclarationSourcePath and getInheritanceChain helpers; new exported types for inheritance.
Tooling & CLI integration
packages/core/src/handlers/index.ts, packages/core/src/tools/health.ts, tests/tools/health.test.ts, tests/integration/server.test.ts
Barrel exports added for analyzers/audit/dimensions; health tools extended with multiDimensional flags and new audit_library tool; test expectations updated for tool counts and definitions.
Type assertions / minor typing fixes
packages/core/src/handlers/benchmark.ts, packages/core/src/handlers/compare.ts
Added Cem type assertions when loading JSON to tighten typing without runtime behavior changes.
Testing: analyzers, accessibility, source scans, dimensions, health, audit
tests/handlers/analyzers.test.ts, tests/handlers/audit-report.test.ts, tests/handlers/source-accessibility*.test.ts, tests/handlers/deep-source-accessibility.test.ts, tests/handlers/dimensions.test.ts, tests/handlers/multi-dimensional-health.test.ts
Large set of new and expanded tests covering analyzers, shallow/deep source scanners, multi-library integrations, audit report generation, DIMENSION_REGISTRY and grading logic, and multi-dimensional health outputs.
Workspace & CI
pnpm-workspace.yaml, .coderabbit.yaml
Adds pnpm-workspace manifest and broadens auto_review.path_filters to exclude additional directories/files.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Config
    participant Analyzer
    participant Scorer
    participant AuditGen

    Client->>Config: loadConfig()
    Config->>Config: check helixir.mcp.json
    alt primary exists
        Config->>Config: parse primary
    else fallback
        Config->>Config: check mcpwc.config.json
        Config->>Config: emit deprecation warning
        Config->>Config: parse legacy
    end
    Config-->>Client: return config

    Client->>Analyzer: analyzeSourceAccessibility(config, decl)
    Analyzer->>Analyzer: resolveComponentSourceFilePath(decl)
    Analyzer->>Analyzer: scanSourceForA11yPatterns(source)
    Analyzer->>Analyzer: scoreSourceMarkers(markers)
    Analyzer-->>Client: SourceAccessibilityResult

    Client->>Scorer: scoreComponentMultiDimensional(config, decl)
    Scorer->>Scorer: compute CEM-native dimensions (analyzers)
    Scorer->>Scorer: read history for external dimensions
    Scorer->>Scorer: computeWeightedScore & calculateGrade
    Scorer-->>Client: MultiDimensionalHealth

    Client->>AuditGen: generateAuditReport(config, decls)
    AuditGen->>Scorer: scoreComponentMultiDimensional (per decl)
    AuditGen->>AuditGen: aggregate summary & write JSONL
    AuditGen-->>Client: lines[], summary
Loading
sequenceDiagram
    participant Source as Source File
    participant Resolver as MixinResolver
    participant Scanner as Scanner
    participant Aggregator as Aggregator

    Resolver->>Resolver: resolveInheritanceChain(componentSource)
    Resolver->>Source: read component source
    Resolver->>Scanner: scanSourceForA11yPatterns(source)
    Scanner-->>Resolver: SourceA11yMarkers

    loop each superclass/mixin
        Resolver->>Resolver: resolveModulePath(import)
        Resolver->>Source: read inherited source
        Resolver->>Scanner: scanSourceForA11yPatterns(source)
        Scanner-->>Resolver: SourceA11yMarkers
    end

    Resolver->>Aggregator: aggregateMarkers(all sources)
    Aggregator->>Aggregator: merge markers & classify architecture
    Aggregator-->>Resolver: InheritanceChainResult
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 57.38% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the two primary changes: multi-dimensional health scoring and source-level accessibility analysis. It accurately reflects the main scope of the changeset.
Description check ✅ Passed The PR description is comprehensive and well-structured. It includes all required sections: type of change (checked), related issue reference, detailed description with tables and organized information, test coverage confirmation, and checklist items verified.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch staging
📝 Coding Plan
  • Generate coding plan for human review comments

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 20

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
tests/tools/health.test.ts (1)

110-131: 🧹 Nitpick | 🔵 Trivial

Consider adding handler test for audit_library.

The existing tests cover definition presence but there's no handleHealthCall test for the audit_library tool. If handler behavior is tested elsewhere (e.g., audit-report.test.ts), this is fine. Otherwise, consider adding coverage for the handler dispatch path.

Would you like me to generate a test case for handleHealthCall('audit_library', ...) or open an issue to track this?

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/tools/health.test.ts` around lines 110 - 131, Add a unit test that
verifies the handler dispatch for the "audit_library" tool by calling
handleHealthCall('audit_library', ...) with a representative input and asserting
the expected outcome (or that the correct handler was invoked); locate the
handler by the handleHealthCall function and the "audit_library" entry in
HEALTH_TOOL_DEFINITIONS, mock any external dependencies or the audit library
handler as done for other tools in tests (e.g., mirror existing patterns used
for score_component or analyze_accessibility), and place the test alongside the
other HEALTH_TOOL_DEFINITIONS tests so the tool definition presence and dispatch
behavior are both covered.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.automaker/memory/architecture.md:
- Around line 477-489: Clarify the adjacent, seemingly contradictory notes by
explicitly stating their contexts: update the entry that mentions replacing
existsSync with async access() to reference the async refactor of parseTokens
(e.g., "use fs/promises.access() when converting parseTokens or other
already-async functions to avoid blocking"), and update the entry that defends
retaining existsSync to note it's for simple synchronous guard checks (e.g.,
"retain existsSync for trivial boolean guards where introducing async try/catch
would harm readability"); reference the symbols existsSync, access(),
fs/promises, and parseTokens so readers can see when each approach applies.

In @.automaker/memory/gotchas.md:
- Around line 114-152: Several new "#### [Gotcha]" headings in the
.automaker/memory/gotchas.md block are missing a blank line above them (MD022);
insert a single blank line immediately before each "#### [Gotcha]" heading
occurrence (the headings starting with "#### [Gotcha] A feature branch..." and
the subsequent seven gotcha entries) so every "####" heading is preceded by an
empty line, preserving existing text and spacing around the surrounding
paragraphs.

In @.automaker/memory/security.md:
- Around line 289-311: The file violates MD022 and MD047: add a blank line
before each top-level heading (insert a newline immediately above "Response SLA
tiered as 48h acknowledgment + 7-day status update rather than a single flat SLA
(2026-03-12)", above "Response SLA..."'s subsequent headings like "Gotcha]
Supported versions table...", and above the "[Pattern] pnpm audit is run with
--audit-level=high..." heading) so all headings are surrounded by a blank line,
and ensure the file ends with exactly one trailing newline character (terminate
after the final line rather than leaving it without a newline or with extra
blank lines).

In `@CHANGELOG.md`:
- Around line 3-7: The changelog for v0.3.0 only documents the /update-helixir
slash command but omits major features; update CHANGELOG.md to include concise
entries under v0.3.0 for multi-dimensional health scoring, source-level
accessibility analysis, the new MCP tools (score_component_multi_dimensional,
score_all_multi_dimensional, audit_library), and the config migration
utility/notes, ensuring each bullet references the corresponding feature name or
command and briefly summarizes its purpose and impact.

In `@packages/core/src/handlers/accessibility.ts`:
- Around line 103-107: The current logic treats any CSS custom property whose
name contains "role" as evidence of ARIA role support (ariaRoleInCss), which
wrongly awards accessibility points for purely styling tokens; remove the
cssProperties-based detection by deleting the ariaRoleInCss variable and update
the hasAriaRole computation to rely only on ariaRoleInDesc and
ariaRoleFromTagName (i.e., set hasAriaRole = ariaRoleInDesc ||
ariaRoleFromTagName), ensuring no CSS token names are used to infer ARIA
behavior (adjust or remove any related references to ariaRoleInCss in the
surrounding code).

In `@packages/core/src/handlers/analyzers/api-surface.ts`:
- Around line 41-47: The current reflectedCount uses
Math.max(fieldsWithAttribute.length, fieldsReflecting.length) which undercounts
when different fields have attribute and reflects; change the calculation to
count the union of fields that have either a non-empty attribute or reflects ===
true by deriving a single collection (e.g., filter fields by (m) => (typeof
m.attribute === 'string' && m.attribute.length > 0) || m.reflects === true or
build a Set of unique field identifiers) and use its length for reflectedCount
before computing attrScore; update references to
fieldsWithAttribute/fieldsReflecting as needed so attrScore uses that union
length.

In `@packages/core/src/handlers/analyzers/css-architecture.ts`:
- Around line 39-51: The token naming regex used in tokenPattern is too strict
(currently /^--[a-z]+-[a-z]/) and rejects valid custom properties with digits or
uppercase letters; update tokenPattern to a more permissive pattern such as
/^--[A-Za-z][A-Za-z0-9]*-/ so prefixes can include letters (any case) and digits
while still enforcing the required hyphenated namespace; update the occurrence
in the css-architecture analyzer (variables tokenPattern, wellNamedProps,
tokenScore) and any related tests or documentation to reflect the relaxed
pattern.

In `@packages/core/src/handlers/analyzers/source-accessibility.ts`:
- Around line 170-177: The existence check in tryReadFile causes a TOCTOU race
and is redundant; simplify tryReadFile by removing the existsSync(filePath)
branch and just attempt to await readFile(filePath, 'utf-8') inside the
try/catch, returning the file contents on success and null on any thrown error
so the function behavior and signature (tryReadFile) remain the same.

In `@packages/core/src/handlers/audit-report.ts`:
- Around line 92-96: The file write using writeFile when options?.outputPath is
set can throw and currently bubbles up; wrap the write in a try-catch so the
handler returns the computed lines and summary even if writing fails.
Concretely, around the block that resolves outputFile
(resolve(config.projectRoot, options.outputPath)) and calls await
writeFile(outputFile, lines.join('\n') + '\n', 'utf-8'), catch any error, attach
or include the error message in the handler's response (e.g., return or include
an exportError field alongside lines and summary) and ensure the function still
returns the computed data (lines and summary) when a write error occurs. Ensure
you reference options?.outputPath, outputFile, writeFile, lines and summary when
implementing the catch handling so callers can access both the computed report
and the write failure details.

In `@packages/core/src/handlers/dimensions.ts`:
- Around line 173-181: The logic in the lowCritical block allows a less
restrictive cap to overwrite a stricter one: change the comparison that sets
gradeCap so we only replace gradeCap with newCap when newCap is strictly more
restrictive (i.e., a better/stricter cap) than the existing gradeCap;
specifically, in the block referencing lowCritical, measuredCritical, gradeCap,
and gradeOrdinal, invert the comparison (or otherwise compare ordinals
correctly) so newCap is applied only if gradeOrdinal(newCap) indicates a
stricter cap than gradeOrdinal(gradeCap), keeping the strictest cap across
checks and leaving notes.push as-is.

In `@packages/core/src/handlers/health.ts`:
- Around line 776-795: When populating dimensions from historyEntry, validate
historyEntry.confidence before casting: read const conf =
historyEntry.confidence and set confidence to conf if conf === 'verified' ||
conf === 'heuristic', otherwise fall back to a safe default (e.g., 'verified');
update the object pushed into dimensions to use that validated value so
unexpected or misspelled confidence strings from historyBreakdown cannot produce
an invalid state.

In `@packages/core/src/tools/health.ts`:
- Around line 248-260: The call to scoreAllComponentsMultiDimensional is missing
the cem argument causing source-level accessibility analysis to fail; update the
call in the score_all_components branch to pass the previously loaded cem (from
const cemData = await loadCemData(config, cem))—i.e., change
scoreAllComponentsMultiDimensional(config, declarations) to include cem as the
third parameter so it matches the other call pattern (and keeps
analyzeSourceAccessibility working), ensuring any related uses of
ScoreAllComponentsArgsSchema.parse and createSuccessResponse remain unchanged.
- Around line 287-292: The call to scoreAllComponentsMultiDimensional inside
handleHealthCall is passing the original cem parameter (which may be undefined)
instead of the loaded CEM data variable cemData, causing source-level
accessibility analysis to be skipped when cem was not provided; change the
argument from cem to cemData so the function receives the loaded CEM data, and
scan for any other places in handleHealthCall that still reference cem where
cemData should be used (e.g., the call site of
scoreAllComponentsMultiDimensional and any subsequent uses of CEM data).

In `@tests/config-rename.test.ts`:
- Around line 10-18: Remove the redundant vi.unstubAllEnvs() call from the
beforeEach block and keep the single cleanup call in afterEach; update the
tests/config-rename.test.ts beforeEach so it only initializes tmpDir with
mkdtempSync(join(tmpdir(), 'helixir-rename-test-')) and leaves
vi.unstubAllEnvs() in afterEach to perform environment cleanup between tests.

In `@tests/handlers/deep-source-accessibility.test.ts`:
- Around line 366-383: The forEach callbacks for logging top and bottom scorers
use concise arrow bodies that implicitly return the result of console.log,
triggering the lint rule; update the two forEach calls on the sorted and bottom
arrays to use block arrow functions with an explicit statement body (e.g., (s)
=> { console.log(...); }) so they do not implicitly return a value, referencing
the sorted variable and bottom variable used in those callbacks.

In `@tests/handlers/multi-dimensional-health.test.ts`:
- Around line 109-123: Replace the weak LOW_TYPE_COVERAGE_DECL test fixture with
a variant derived from PERFECT_DECL that only strips type metadata (keep all
other fields identical) so the test actually isolates Type Coverage loss; update
the test to run the handler/validator with this new fixture, assert that the
returned score is capped to the expected Type Coverage cap value, and explicitly
assert that result.gradingNotes contains the expected note about the cap
(reference symbols: create NEW_LOW_TYPE_FROM_PERFECT or reuse PERFECT_DECL to
build the fixture, check result.gradingNotes and the returned grade value).

In `@tests/handlers/source-accessibility-real-libs.test.ts`:
- Around line 244-254: The test only validates the first five declarations
because it uses allDecls.slice(0, 5); update the test to iterate over the full
allDecls array instead of the sliced sample so every declaration is verified;
change the loop that calls analyzeSourceAccessibility(fakeConfig, cem, decl) to
run for each decl in allDecls (or use a direct array iteration/assertion) and
assert expect(result).toBeNull() for each to prevent regressions after the first
five entries.
- Around line 23-25: This ESM test file uses __dirname when computing
HELIX_ROOT, HELIX_CEM_PATH, and HELIX_HAS_SOURCE but never defines it; add an
ESM-compatible __dirname initialization at the top of the module by importing
fileURLToPath (from 'url') and dirname (from 'path') and setting const __dirname
= dirname(fileURLToPath(import.meta.url)); then the existing resolve(...) calls
that produce HELIX_ROOT, HELIX_CEM_PATH and HELIX_HAS_SOURCE will work without
throwing a ReferenceError.
- Around line 186-189: The forEach callback on tiers.excellent is using an
expression-bodied arrow that implicitly returns console.log (forEach callbacks
must not return values); change the expression-bodied arrow to a block-bodied
arrow for the .forEach call so the callback becomes { console.log(...) } instead
of the implicit-return form—do the same for the other .forEach at the later
block to satisfy the useIterableCallbackReturn rule while keeping the same
logging behavior.

In `@tests/handlers/source-accessibility-wc-libraries.test.ts`:
- Around line 149-167: The forEach callbacks that currently use concise arrow
bodies and implicitly return the result of console.log (in the tiers.excellent
.forEach and tiers.low .forEach blocks) should be converted to block arrow
functions to avoid implicit returns: replace .forEach((s) => console.log(...))
with .forEach((s) => { console.log(...); }) for both the top scorers
(tiers.excellent) and lowest interactive scorers (tiers.low) iterations so they
no longer return a value and satisfy the useIterableCallbackReturn lint rule.

---

Outside diff comments:
In `@tests/tools/health.test.ts`:
- Around line 110-131: Add a unit test that verifies the handler dispatch for
the "audit_library" tool by calling handleHealthCall('audit_library', ...) with
a representative input and asserting the expected outcome (or that the correct
handler was invoked); locate the handler by the handleHealthCall function and
the "audit_library" entry in HEALTH_TOOL_DEFINITIONS, mock any external
dependencies or the audit library handler as done for other tools in tests
(e.g., mirror existing patterns used for score_component or
analyze_accessibility), and place the test alongside the other
HEALTH_TOOL_DEFINITIONS tests so the tool definition presence and dispatch
behavior are both covered.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 677c992b-3d35-4a03-92c4-609facf024a1

📥 Commits

Reviewing files that changed from the base of the PR and between ba51def and 0607cf3.

📒 Files selected for processing (39)
  • .automaker/memory/api.md
  • .automaker/memory/architecture.md
  • .automaker/memory/gotchas.md
  • .automaker/memory/performance.md
  • .automaker/memory/security.md
  • .automaker/memory/testing.md
  • .automaker/memory/validation.md
  • .changeset/add-update-helixir-command.md
  • CHANGELOG.md
  • package.json
  • packages/core/src/config.ts
  • packages/core/src/handlers/accessibility.ts
  • packages/core/src/handlers/analyzers/api-surface.ts
  • packages/core/src/handlers/analyzers/css-architecture.ts
  • packages/core/src/handlers/analyzers/event-architecture.ts
  • packages/core/src/handlers/analyzers/index.ts
  • packages/core/src/handlers/analyzers/mixin-resolver.ts
  • packages/core/src/handlers/analyzers/source-accessibility.ts
  • packages/core/src/handlers/analyzers/type-coverage.ts
  • packages/core/src/handlers/audit-report.ts
  • packages/core/src/handlers/benchmark.ts
  • packages/core/src/handlers/cem.ts
  • packages/core/src/handlers/compare.ts
  • packages/core/src/handlers/dimensions.ts
  • packages/core/src/handlers/health.ts
  • packages/core/src/handlers/index.ts
  • packages/core/src/tools/health.ts
  • tests/config-rename.test.ts
  • tests/handlers/accessibility.test.ts
  • tests/handlers/analyzers.test.ts
  • tests/handlers/audit-report.test.ts
  • tests/handlers/deep-source-accessibility.test.ts
  • tests/handlers/dimensions.test.ts
  • tests/handlers/multi-dimensional-health.test.ts
  • tests/handlers/source-accessibility-real-libs.test.ts
  • tests/handlers/source-accessibility-wc-libraries.test.ts
  • tests/handlers/source-accessibility.test.ts
  • tests/integration/server.test.ts
  • tests/tools/health.test.ts
💤 Files with no reviewable changes (1)
  • .changeset/add-update-helixir-command.md

Comment thread .automaker/memory/architecture.md
Comment thread .automaker/memory/gotchas.md
Comment thread .automaker/memory/security.md
Comment thread CHANGELOG.md
Comment thread packages/core/src/handlers/accessibility.ts
Comment thread tests/handlers/multi-dimensional-health.test.ts
Comment thread tests/handlers/source-accessibility-real-libs.test.ts
Comment thread tests/handlers/source-accessibility-real-libs.test.ts
Comment thread tests/handlers/source-accessibility-real-libs.test.ts
Comment thread tests/handlers/source-accessibility-wc-libraries.test.ts
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.changeset/multi-dimensional-health-scoring.md:
- Line 5: Add a top-level H1 as the first line of the file so markdownlint MD041
is satisfied: insert a heading such as "# Multi-dimensional health scoring
engine" (or similar descriptive H1) at the very top of
.changeset/multi-dimensional-health-scoring.md before the body text "Add
multi-dimensional health scoring engine with source-level accessibility
analysis".

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 7d0f636c-6bde-44b7-8e81-57e028438896

📥 Commits

Reviewing files that changed from the base of the PR and between 0607cf3 and ed023d9.

📒 Files selected for processing (1)
  • .changeset/multi-dimensional-health-scoring.md

Comment thread .changeset/multi-dimensional-health-scoring.md
himerus and others added 4 commits March 13, 2026 20:51
Update pnpm overrides to patch flatted (>=3.4.0), hono (>=4.12.7), and
undici (>=7.24.0). Restore pnpm-workspace.yaml so overrides apply to the
github-action sub-package. Regenerated lockfile — 0 vulnerabilities.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…tories

Excludes .automaker/, build/, pnpm-lock.yaml, .changeset/, .worktrees/,
.husky/, coverage/, node_modules/, and source maps from code review.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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.

1 participant