nfunc-mcp 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -22,6 +22,8 @@ A local MCP server that gives Claude (or any MCP client) a full non-functional Q
22
22
  - [HTML report](#html-report)
23
23
  - [Output shape](#output-shape)
24
24
  7. [Individual tools](#individual-tools)
25
+ - [Mobile vs desktop](#mobile-vs-desktop)
26
+ - [Choosing an accessibility engine](#choosing-an-accessibility-engine)
25
27
  8. [Priority system](#priority-system)
26
28
  9. [Project layout](#project-layout)
27
29
  10. [How to prompt](#how-to-prompt)
@@ -128,10 +130,10 @@ claude mcp add nfunc-mcp -- node /absolute/path/to/NFunc_MCP/dist/index.js
128
130
  | Tool | Description | Inputs |
129
131
  |---|---|---|
130
132
  | `ping` | Health check — confirms the server is up | — |
131
- | `run_lighthouse` | Full Lighthouse audit for a URL | `url` |
132
- | `run_accessibility_check` | pa11y WCAG audit for a URL | `url`, `standard` (optional), `ignore` (optional) |
133
+ | `run_lighthouse` | Full Lighthouse audit for a URL | `url`, `form_factor` (optional), `categories` (optional), `thresholds` (optional) |
134
+ | `run_accessibility_check` | pa11y WCAG audit for a URL | `url`, `runner` (optional), `standard` (optional), `ignore` (optional) |
133
135
  | `run_static_analysis` | ESLint + Semgrep scan for a local codebase | `path` |
134
- | `run_qa_gate` | All tools in parallel + correlation + HTML report | `url` and/or `path` |
136
+ | `run_qa_gate` | All tools in parallel + correlation + HTML report | `url` and/or `path`, `form_factor` (optional), `a11y_runner` (optional) |
135
137
 
136
138
  ---
137
139
 
@@ -148,6 +150,8 @@ Both inputs are **optional** — provide whichever you have. At least one is req
148
150
  | `url` | string (URL) | You have a running page — production, staging, preview URL, or localhost. Enables Lighthouse and pa11y. |
149
151
  | `path` | string (path) | You have a local codebase. Enables ESLint and Semgrep. |
150
152
  | `context` | string | Optional. Free-text description of the project (e.g. `"React e-commerce checkout"`). Helps Claude interpret results. |
153
+ | `form_factor` | `mobile` \| `desktop` \| `both` | Optional, default `mobile`. Lighthouse device profile — see [Mobile vs desktop](#mobile-vs-desktop). |
154
+ | `a11y_runner` | `htmlcs` \| `axe` \| `both` | Optional, default `htmlcs`. pa11y engine — see [Choosing an accessibility engine](#choosing-an-accessibility-engine). |
151
155
 
152
156
  **URL only** — browser-based checks, static analysis skipped:
153
157
  ```
@@ -300,9 +304,28 @@ Runs a full Lighthouse audit against a URL.
300
304
 
301
305
  ```
302
306
  Run Lighthouse on https://myapp.com
307
+ Run Lighthouse on https://myapp.com for mobile and desktop
303
308
  ```
304
309
 
305
- Returns: `url`, `scores` (per category), `ttfb_ms`, `findings` (priority-ordered).
310
+ Returns: `url`, `form_factor`, `scores` (per category), `ttfb_ms`, `findings` (priority-ordered).
311
+
312
+ #### Mobile vs desktop
313
+
314
+ `form_factor` accepts `desktop` (default), `mobile`, or `both`.
315
+
316
+ **This default deliberately differs from the Lighthouse CLI's**, which is mobile: a 412×823 screen, a mid-range Android user agent, simulated slow 4G, and a **4× CPU slowdown**. That profile is much harsher and reports substantially lower performance scores for the same page, so passing `mobile` here is not a like-for-like comparison with a default run — check `form_factor` in the response before comparing two reports.
317
+
318
+ **The two are not interchangeable.** They render different DOM, so they find different defects — not just different performance numbers. Measured against one commerce category page:
319
+
320
+ | | Mobile | Desktop |
321
+ |---|---|---|
322
+ | performance | 54 | 62 |
323
+ | accessibility | **87** | **73** |
324
+ | seo | 77 | 69 |
325
+
326
+ Five accessibility audits failed on desktop that mobile never reported — `image-alt`, `aria-required-children`, `aria-required-parent`, `aria-allowed-attr`, `aria-valid-attr-value` — while three others failed only on mobile. Neither profile is a superset of the other.
327
+
328
+ With `form_factor: "both"`, the two run concurrently (so it costs little more wall time than one), `scores` is keyed by form factor, and each finding carries `affects_form_factors` and `form_factor_specific` so device-only regressions are obvious at a glance.
306
329
 
307
330
  ### run_accessibility_check
308
331
 
@@ -311,9 +334,28 @@ Runs pa11y against a URL at WCAG 2 AA by default. Returns only violations (error
311
334
  ```
312
335
  Run an accessibility check on https://myapp.com
313
336
  Run accessibility check at AAA standard on https://myapp.com
337
+ Run an accessibility check on https://myapp.com using the axe runner
314
338
  ```
315
339
 
316
- Returns: `url`, `standard`, `violation_count`, `findings`.
340
+ Returns: `url`, `standard`, `runners`, `violation_count`, `raw_violation_count`, `findings`.
341
+
342
+ #### Choosing an accessibility engine
343
+
344
+ `runner` accepts `htmlcs` (default), `axe`, or `both`.
345
+
346
+ | Engine | Strongest at | Severity source |
347
+ |---|---|---|
348
+ | `htmlcs` | WCAG techniques, document structure, form labelling, duplicate ids | WCAG technique class |
349
+ | `axe` | **ARIA** — invalid roles, missing required parent/child relationships, prohibited and unsupported attributes — and computed colour contrast | axe's own `impact` rating |
350
+
351
+ **Reach for `axe` whenever the work under test involves ARIA, a component library, or a design system.** The overlap between the engines is smaller than you would expect. On the same page:
352
+
353
+ - htmlcs found unlabelled inputs, forms with no submit mechanism, and ten duplicate ids that axe did not report.
354
+ - axe found `aria-allowed-attr`, `aria-prohibited-attr`, `aria-required-parent`, `aria-required-children` and `image-alt` failures that htmlcs missed entirely.
355
+
356
+ `both` runs them concurrently and merges the results. Note that an element flagged by both engines appears twice, because they emit different rule codes for the same defect — that is deliberate, since two independent engines agreeing is corroboration worth seeing.
357
+
358
+ Findings from axe carry `axe_impact` in evidence, and `needs_manual_review: true` where axe wants a human to confirm (those are demoted one priority tier — a maybe should not gate a release as hard as a certainty).
317
359
 
318
360
  ### run_static_analysis
319
361
 
package/dist/index.js CHANGED
@@ -1,14 +1,33 @@
1
1
  #!/usr/bin/env node
2
+ import { readFileSync } from "fs";
3
+ import { fileURLToPath } from "url";
2
4
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
5
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
6
  import { registerLighthouseTool } from "./tools/lighthouse.js";
5
7
  import { registerAccessibilityTool } from "./tools/accessibility.js";
6
8
  import { registerStaticAnalysisTool } from "./tools/staticAnalysis.js";
7
9
  import { registerQaGateTool } from "./tools/qaGate.js";
8
- const server = new McpServer({
9
- name: "qa-mcp",
10
- version: "0.1.0",
11
- });
10
+ /**
11
+ * Identity comes from package.json rather than being written out here, so the
12
+ * two cannot drift — they already had, declaring qa-mcp/0.1.0 against
13
+ * nfunc-mcp/0.2.0 after the npm rename, and `npm version` would reintroduce
14
+ * the gap on every release if these were hardcoded.
15
+ *
16
+ * "../package.json" resolves to the repo root from both src/index.ts and
17
+ * dist/index.js, and npm always ships package.json, so the same path works in
18
+ * dev, in a local build, and in an installed package. Falls back rather than
19
+ * failing to boot if it is ever unreadable.
20
+ */
21
+ function readIdentity() {
22
+ try {
23
+ const pkg = JSON.parse(readFileSync(fileURLToPath(new URL("../package.json", import.meta.url)), "utf8"));
24
+ return { name: pkg.name ?? "nfunc-mcp", version: pkg.version ?? "0.0.0" };
25
+ }
26
+ catch {
27
+ return { name: "nfunc-mcp", version: "0.0.0" };
28
+ }
29
+ }
30
+ const server = new McpServer(readIdentity());
12
31
  server.registerTool("ping", {
13
32
  description: "Health-check tool. Returns ok status and current ISO timestamp.",
14
33
  inputSchema: {},
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;AACrE,OAAO,EAAE,0BAA0B,EAAE,MAAM,2BAA2B,CAAC;AACvE,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAEvD,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;IAC3B,IAAI,EAAE,QAAQ;IACd,OAAO,EAAE,OAAO;CACjB,CAAC,CAAC;AAEH,MAAM,CAAC,YAAY,CACjB,MAAM,EACN;IACE,WAAW,EAAE,iEAAiE;IAC9E,WAAW,EAAE,EAAE;CAChB,EACD,KAAK,IAAI,EAAE;IACT,MAAM,OAAO,GAAG;QACd,MAAM,EAAE,IAAI;QACZ,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACpC,CAAC;IACF,OAAO;QACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC;KAC3D,CAAC;AACJ,CAAC,CACF,CAAC;AAEF,sBAAsB,CAAC,MAAM,CAAC,CAAC;AAC/B,yBAAyB,CAAC,MAAM,CAAC,CAAC;AAClC,0BAA0B,CAAC,MAAM,CAAC,CAAC;AACnC,kBAAkB,CAAC,MAAM,CAAC,CAAC;AAE3B,KAAK,UAAU,IAAI;IACjB,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;AAClC,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACnB,OAAO,CAAC,KAAK,CAAC,qBAAqB,EAAE,GAAG,CAAC,CAAC;IAC1C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AACpC,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;AACrE,OAAO,EAAE,0BAA0B,EAAE,MAAM,2BAA2B,CAAC;AACvE,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAEvD;;;;;;;;;;GAUG;AACH,SAAS,YAAY;IACnB,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CACpB,YAAY,CAAC,aAAa,CAAC,IAAI,GAAG,CAAC,iBAAiB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,CAC1C,CAAC;QACzC,OAAO,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,IAAI,WAAW,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,IAAI,OAAO,EAAE,CAAC;IAC5E,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;IACjD,CAAC;AACH,CAAC;AAED,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC,YAAY,EAAE,CAAC,CAAC;AAE7C,MAAM,CAAC,YAAY,CACjB,MAAM,EACN;IACE,WAAW,EAAE,iEAAiE;IAC9E,WAAW,EAAE,EAAE;CAChB,EACD,KAAK,IAAI,EAAE;IACT,MAAM,OAAO,GAAG;QACd,MAAM,EAAE,IAAI;QACZ,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACpC,CAAC;IACF,OAAO;QACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC;KAC3D,CAAC;AACJ,CAAC,CACF,CAAC;AAEF,sBAAsB,CAAC,MAAM,CAAC,CAAC;AAC/B,yBAAyB,CAAC,MAAM,CAAC,CAAC;AAClC,0BAA0B,CAAC,MAAM,CAAC,CAAC;AACnC,kBAAkB,CAAC,MAAM,CAAC,CAAC;AAE3B,KAAK,UAAU,IAAI;IACjB,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;AAClC,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACnB,OAAO,CAAC,KAAK,CAAC,qBAAqB,EAAE,GAAG,CAAC,CAAC;IAC1C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,25 @@
1
+ import type { Finding } from "../types.js";
2
+ export interface A11yDedupeResult {
3
+ findings: Finding[];
4
+ rawCount: number;
5
+ }
6
+ /**
7
+ * Collapses the two ways pa11y over-reports a single defect.
8
+ *
9
+ * Pass 1 — exact repeats. pa11y emits one violation per occurrence, and for
10
+ * page-wide rules (F77, duplicate id, above all) every occurrence resolves
11
+ * back to the same selector. A real commerce page produced 70 of 85 findings
12
+ * from two defects repeated 35 times each, burying the genuine issues and
13
+ * flooring the qa_gate composite score. Collapsing on (rule_code, selector)
14
+ * removes those while keeping two different elements failing the same rule
15
+ * separate, since they are separate fixes.
16
+ *
17
+ * Pass 2 — systemic defects. One rule failing across many *different*
18
+ * elements, which (rule_code, selector) cannot catch. The axe runner produces
19
+ * these routinely: one mis-authored component reused across a page gave 41
20
+ * distinct aria-allowed-attr findings. See SYSTEMIC_THRESHOLD.
21
+ *
22
+ * Counts survive as evidence.occurrences (written only when > 1), so the
23
+ * volume signal is preserved without N copies of the finding.
24
+ */
25
+ export declare function dedupeA11yFindings(findings: Finding[]): A11yDedupeResult;
@@ -0,0 +1,95 @@
1
+ const PRIORITY_ORDER = { P1: 0, P2: 1, P3: 2 };
2
+ /**
3
+ * Above this many distinct elements failing one rule, the individual findings
4
+ * stop being separately actionable and start being one systemic defect — a
5
+ * component used everywhere, not N unrelated bugs. At or below it, each
6
+ * element keeps its own line.
7
+ *
8
+ * Set at 10 rather than lower because distinct elements failing the same rule
9
+ * are often still separate fixes: ten duplicate ids on a page are ten ids to
10
+ * rename, and collapsing them hides the list a developer needs. It takes a
11
+ * genuine flood — axe reported 41 aria-allowed-attr failures from one reused
12
+ * component — before the group is more useful than its members.
13
+ */
14
+ const SYSTEMIC_THRESHOLD = 10;
15
+ /**
16
+ * Collapses the two ways pa11y over-reports a single defect.
17
+ *
18
+ * Pass 1 — exact repeats. pa11y emits one violation per occurrence, and for
19
+ * page-wide rules (F77, duplicate id, above all) every occurrence resolves
20
+ * back to the same selector. A real commerce page produced 70 of 85 findings
21
+ * from two defects repeated 35 times each, burying the genuine issues and
22
+ * flooring the qa_gate composite score. Collapsing on (rule_code, selector)
23
+ * removes those while keeping two different elements failing the same rule
24
+ * separate, since they are separate fixes.
25
+ *
26
+ * Pass 2 — systemic defects. One rule failing across many *different*
27
+ * elements, which (rule_code, selector) cannot catch. The axe runner produces
28
+ * these routinely: one mis-authored component reused across a page gave 41
29
+ * distinct aria-allowed-attr findings. See SYSTEMIC_THRESHOLD.
30
+ *
31
+ * Counts survive as evidence.occurrences (written only when > 1), so the
32
+ * volume signal is preserved without N copies of the finding.
33
+ */
34
+ export function dedupeA11yFindings(findings) {
35
+ // Pass 1 — exact repeats: same rule on the same selector.
36
+ const byKey = new Map();
37
+ for (const f of findings) {
38
+ const key = `${String(f.evidence["rule_code"] ?? "")}|` +
39
+ `${String(f.evidence["selector"] ?? "")}`;
40
+ const existing = byKey.get(key);
41
+ if (!existing) {
42
+ byKey.set(key, { finding: f, count: 1 });
43
+ continue;
44
+ }
45
+ existing.count += 1;
46
+ // pa11y can grade occurrences of one rule differently (error vs warning);
47
+ // keep the most severe so dedup never downgrades a defect.
48
+ if (PRIORITY_ORDER[f.priority] < PRIORITY_ORDER[existing.finding.priority]) {
49
+ existing.finding = f;
50
+ }
51
+ }
52
+ const exact = Array.from(byKey.values()).map(({ finding, count }) => count > 1
53
+ ? { ...finding, evidence: { ...finding.evidence, occurrences: count } }
54
+ : finding);
55
+ // Pass 2 — systemic defects: one rule failing across many *different*
56
+ // elements. htmlcs rarely does this (its repeats share a selector, which
57
+ // pass 1 already caught) but axe routinely does: a single mis-authored
58
+ // component reused across a page produced 41 separate aria-allowed-attr
59
+ // findings, which drowned everything else and inflated the P1 count.
60
+ const byRule = new Map();
61
+ for (const f of exact) {
62
+ const rule = String(f.evidence["rule_code"] ?? "");
63
+ const group = byRule.get(rule);
64
+ if (group)
65
+ group.push(f);
66
+ else
67
+ byRule.set(rule, [f]);
68
+ }
69
+ const out = [];
70
+ for (const [, group] of byRule) {
71
+ if (group.length <= SYSTEMIC_THRESHOLD) {
72
+ out.push(...group);
73
+ continue;
74
+ }
75
+ const worst = group.reduce((a, b) => PRIORITY_ORDER[a.priority] <= PRIORITY_ORDER[b.priority] ? a : b);
76
+ const elements = group.reduce((n, f) => n + Number(f.evidence["occurrences"] ?? 1), 0);
77
+ out.push({
78
+ ...worst,
79
+ description: `${worst.description} This rule fails on ${elements} elements across the page, ` +
80
+ `which usually means one shared component rather than ${elements} separate defects — ` +
81
+ `fix the component and all of them clear.`,
82
+ evidence: {
83
+ ...worst.evidence,
84
+ occurrences: elements,
85
+ distinct_elements: group.length,
86
+ systemic: true,
87
+ sample_selectors: group
88
+ .slice(0, 10)
89
+ .map((f) => String(f.evidence["selector"] ?? "")),
90
+ },
91
+ });
92
+ }
93
+ return { findings: out, rawCount: findings.length };
94
+ }
95
+ //# sourceMappingURL=a11yDedupe.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"a11yDedupe.js","sourceRoot":"","sources":["../../src/mappers/a11yDedupe.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ import type { Finding } from "../types.js";
2
+ /**
3
+ * Lighthouse's own category scores ARE a calibrated 0–100 health signal, with
4
+ * per-audit weighting Google already tuned. Re-deriving one by counting
5
+ * findings throws that away and double-counts besides: total-blocking-time,
6
+ * bootup-time, mainthread-work-breakdown, interactive and max-potential-fid are
7
+ * five findings describing one overloaded main thread, and the old formula
8
+ * charged 75 points for it. So use the category scores directly.
9
+ */
10
+ export declare function lighthouseSubScore(categoryScores: Record<string, number>): number | null;
11
+ export declare function a11ySubScore(findings: Finding[]): number;
12
+ export declare function staticSubScore(findings: Finding[]): number;
13
+ export interface SubScores {
14
+ lighthouse: number | null;
15
+ pa11y: number | null;
16
+ static: number | null;
17
+ }
18
+ /**
19
+ * Weighted mean over the tools that produced a score. Weights are renormalised
20
+ * across whatever ran, so a url-only run and a url+path run are on the same
21
+ * scale. Returns null when nothing scored.
22
+ */
23
+ export declare function compositeScore(sub: SubScores): number | null;
@@ -0,0 +1,107 @@
1
+ /**
2
+ * Composite health score.
3
+ *
4
+ * The previous formula was a single global subtraction — 100 minus 15 per P1,
5
+ * 7 per P2, 3 per P3 — which had two structural faults:
6
+ *
7
+ * 1. No resolution. Seven P1 findings floored it at 0, so a mediocre page and
8
+ * a catastrophic one were indistinguishable. Real pages routinely exceed
9
+ * that within a single tool.
10
+ * 2. Running more tools lowered the score, because every tool fed the same
11
+ * running subtraction. A url-only run was not comparable to a url+path run,
12
+ * which is exactly backwards: broader checking should not look like worse
13
+ * health.
14
+ *
15
+ * Both are fixed by scoring each tool to its own 0–100 sub-score and taking a
16
+ * weighted mean over only the tools that actually ran.
17
+ */
18
+ const SEVERITY_DAMAGE = { P1: 10, P2: 3, P3: 1 };
19
+ /**
20
+ * Saturating decay. Never reaches 0, always preserves ordering, and each
21
+ * additional finding costs less than the one before — which matches how the
22
+ * information actually behaves: the twentieth P1 tells you far less about the
23
+ * page than the first did.
24
+ *
25
+ * K sets where the curve has resolution. At K = 90 a single P1 scores 89, five
26
+ * P1s score 57, and fifteen P1s score 19 — spread across the range real pages
27
+ * occupy instead of collapsing onto the floor.
28
+ */
29
+ function decay(damage, k) {
30
+ return Math.round(100 * Math.exp(-damage / k));
31
+ }
32
+ function damageOf(findings) {
33
+ return findings.reduce((sum, f) => sum + SEVERITY_DAMAGE[f.priority], 0);
34
+ }
35
+ // Tuned so a page's sub-score lands where a human triager would put it. Static
36
+ // analysis decays faster because code defects are fewer and more directly
37
+ // actionable than page-level accessibility violations.
38
+ const A11Y_K = 90;
39
+ const STATIC_K = 60;
40
+ /**
41
+ * Relative weights of the Lighthouse categories inside the Lighthouse
42
+ * sub-score. Lighthouse publishes per-audit weights but no cross-category
43
+ * weighting, so this is our judgement: performance and accessibility carry the
44
+ * most user impact, SEO and best-practices matter but less directly.
45
+ *
46
+ * Categories not listed here — currently the experimental "agentic-browsing" —
47
+ * get UNKNOWN_CATEGORY_WEIGHT so a new or volatile category cannot dominate the
48
+ * score, while still being visible in the breakdown.
49
+ */
50
+ const CATEGORY_WEIGHTS = {
51
+ performance: 0.3,
52
+ accessibility: 0.3,
53
+ "best-practices": 0.2,
54
+ seo: 0.2,
55
+ };
56
+ const UNKNOWN_CATEGORY_WEIGHT = 0.05;
57
+ /**
58
+ * Lighthouse's own category scores ARE a calibrated 0–100 health signal, with
59
+ * per-audit weighting Google already tuned. Re-deriving one by counting
60
+ * findings throws that away and double-counts besides: total-blocking-time,
61
+ * bootup-time, mainthread-work-breakdown, interactive and max-potential-fid are
62
+ * five findings describing one overloaded main thread, and the old formula
63
+ * charged 75 points for it. So use the category scores directly.
64
+ */
65
+ export function lighthouseSubScore(categoryScores) {
66
+ const entries = Object.entries(categoryScores);
67
+ if (entries.length === 0)
68
+ return null;
69
+ let weighted = 0;
70
+ let totalWeight = 0;
71
+ for (const [name, score] of entries) {
72
+ const w = CATEGORY_WEIGHTS[name] ?? UNKNOWN_CATEGORY_WEIGHT;
73
+ weighted += w * score;
74
+ totalWeight += w;
75
+ }
76
+ return totalWeight > 0 ? Math.round(weighted / totalWeight) : null;
77
+ }
78
+ export function a11ySubScore(findings) {
79
+ return decay(damageOf(findings), A11Y_K);
80
+ }
81
+ export function staticSubScore(findings) {
82
+ return decay(damageOf(findings), STATIC_K);
83
+ }
84
+ // How much each tool contributes to the composite. Static analysis is weighted
85
+ // lowest because a clean scan of a small directory returns 100 and would
86
+ // otherwise flatter a run whose real problems are all in the browser.
87
+ const TOOL_WEIGHTS = { lighthouse: 0.4, pa11y: 0.4, static: 0.2 };
88
+ /**
89
+ * Weighted mean over the tools that produced a score. Weights are renormalised
90
+ * across whatever ran, so a url-only run and a url+path run are on the same
91
+ * scale. Returns null when nothing scored.
92
+ */
93
+ export function compositeScore(sub) {
94
+ const parts = [];
95
+ if (sub.lighthouse !== null)
96
+ parts.push([sub.lighthouse, TOOL_WEIGHTS.lighthouse]);
97
+ if (sub.pa11y !== null)
98
+ parts.push([sub.pa11y, TOOL_WEIGHTS.pa11y]);
99
+ if (sub.static !== null)
100
+ parts.push([sub.static, TOOL_WEIGHTS.static]);
101
+ if (parts.length === 0)
102
+ return null;
103
+ const totalWeight = parts.reduce((s, [, w]) => s + w, 0);
104
+ const weighted = parts.reduce((s, [v, w]) => s + v * w, 0);
105
+ return Math.round(weighted / totalWeight);
106
+ }
107
+ //# sourceMappingURL=compositeScore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compositeScore.js","sourceRoot":"","sources":["../../src/mappers/compositeScore.ts"],"names":[],"mappings":"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"}
@@ -9,17 +9,49 @@ function promotePriority(p) {
9
9
  // Maps Lighthouse accessibility audit IDs to substrings that appear inside the
10
10
  // pa11y rule_code for the same class of issue. A leading "." prevents matching
11
11
  // partial segment names (e.g. ".H44" won't accidentally match ".1H44").
12
+ //
13
+ // Keep this keyed on defects the two tools genuinely detect in common. A wrong
14
+ // entry is worse than a missing one: a bogus match promotes a finding a whole
15
+ // priority tier and stamps it "confirmed by two tools". Where Lighthouse and
16
+ // pa11y test adjacent-but-different criteria (e.g. label-content-name-mismatch
17
+ // under WCAG 2.5.3 vs F68 under 1.3.1) they are deliberately left unmapped.
12
18
  const LH_TO_PA11Y_SUBSTRINGS = {
19
+ // Colour / contrast
13
20
  "color-contrast": [".G18", ".G145", ".G174"],
21
+ // Images
14
22
  "image-alt": [".H37", ".H67", ".F65"],
23
+ "input-image-alt": [".H36"],
24
+ "object-alt": [".H53"],
25
+ // Accessible names on controls
15
26
  label: [".H44", ".F68", ".H91.Input", ".H91.Select", ".H91.Textarea"],
27
+ "form-field-multiple-labels": [".H44", ".F68"],
28
+ "button-name": [".H91.Button"],
29
+ "select-name": [".H91.Select"],
30
+ "aria-input-field-name": [".ARIA6", ".ARIA9", ".H91"],
31
+ "aria-toggle-field-name": [".ARIA6", ".ARIA9", ".H91"],
32
+ "aria-command-name": [".ARIA6", ".ARIA9", ".H91"],
33
+ "aria-dialog-name": [".ARIA6", ".ARIA9"],
34
+ // ARIA misuse
35
+ "aria-prohibited-attr": [".ARIA6", ".ARIA4"],
36
+ "aria-valid-attr-value": [".ARIA9"],
37
+ // Links
16
38
  "link-name": [".H30", ".H91.A."],
39
+ "link-text": [".H30", ".H91.A."],
40
+ "crawlable-anchors": [".G1,G123,G124", ".H30"],
41
+ // Document / language
17
42
  "document-title": [".H25", ".F89"],
18
43
  "html-has-lang": [".H57"],
44
+ "html-lang-valid": [".H57"],
45
+ "valid-lang": [".H58"],
46
+ // Structure
47
+ "heading-order": [".G141", ".H42"],
19
48
  "frame-title": [".H64"],
20
- "button-name": [".H91.Button"],
21
- "select-name": [".H91.Select"],
49
+ // Duplicate identifiers. Lighthouse 12 removed duplicate-id-aria altogether,
50
+ // which is why a page throwing 35 pa11y F77 violations correlated with
51
+ // nothing under Lighthouse 13. Both ids are kept so older Lighthouse output
52
+ // still matches; there is currently no LH 13 equivalent to pair F77 with.
22
53
  "duplicate-id-aria": [".H93", ".F77"],
54
+ "duplicate-id-active": [".H93", ".F77"],
23
55
  };
24
56
  // Lighthouse performance audit IDs where Rule 2 (code linkage) is relevant.
25
57
  const PERFORMANCE_AUDIT_IDS = new Set([
@@ -30,14 +62,27 @@ const PERFORMANCE_AUDIT_IDS = new Set([
30
62
  "mainthread-work-breakdown",
31
63
  "total-blocking-time",
32
64
  ]);
65
+ // Deterministic non-crypto string hash (djb2), base36-encoded.
66
+ // Selectors are long and routinely share long prefixes — e.g.
67
+ // "#accordion-panel-:rn: > div > div > input:nth-child(1)" and the same
68
+ // selector ending ":nth-child(3)" are identical for their first 40 characters.
69
+ // The previous id truncated the selector to 16 chars, so those two distinct
70
+ // findings collapsed to one id and consumedA11yIds claimed the wrong entry
71
+ // during correlation. Hashing the whole selector keeps ids short and unique.
72
+ function shortHash(input) {
73
+ let h = 5381;
74
+ for (let i = 0; i < input.length; i++) {
75
+ h = ((h << 5) + h + input.charCodeAt(i)) | 0;
76
+ }
77
+ return (h >>> 0).toString(36);
78
+ }
33
79
  function makeId(tool, f) {
34
80
  const e = f.evidence;
35
81
  if (tool === "lighthouse")
36
82
  return `lh:${String(e["audit_id"] ?? f.title)}`;
37
83
  if (tool === "a11y") {
38
84
  const code = String(e["rule_code"] ?? "").split(".").slice(-2).join(".");
39
- const sel = String(e["selector"] ?? "").slice(0, 16);
40
- return `a11y:${code}:${sel}`;
85
+ return `a11y:${code}:${shortHash(String(e["selector"] ?? ""))}`;
41
86
  }
42
87
  const basename = String(e["file"] ?? "").split("/").pop() ?? "";
43
88
  return `static:${String(e["source"] ?? "")}:${basename}:${String(e["line"] ?? "")}`;
@@ -58,37 +103,53 @@ function applyRule1(lhFindings, a11yFindings) {
58
103
  const substrings = LH_TO_PA11Y_SUBSTRINGS[auditId];
59
104
  if (!substrings)
60
105
  continue;
61
- for (const a11yF of a11yFindings) {
106
+ // Claim every unconsumed pa11y finding covering the same technique, not
107
+ // just the first. One Lighthouse audit routinely corresponds to several
108
+ // pa11y violations — one per offending element — and stopping at the first
109
+ // left the rest to reappear as uncorroborated copies of the same defect.
110
+ const matches = a11yFindings.filter((a11yF) => {
62
111
  if (consumedA11yIds.has(a11yF.id))
63
- continue;
112
+ return false;
64
113
  const ruleCode = String(a11yF.evidence["rule_code"] ?? "");
65
- if (!substrings.some((s) => ruleCode.includes(s)))
66
- continue;
67
- // Use the better (lower index = higher priority) of the two raw priorities
68
- // as the base, then promote it one tier.
69
- const basePriority = PRIORITY_ORDER[lhF.priority] <= PRIORITY_ORDER[a11yF.priority]
70
- ? lhF.priority
71
- : a11yF.priority;
72
- correlated.push({
73
- id: `corr:lh+a11y:${auditId}`,
74
- source_tool: "lighthouse+pa11y",
75
- priority: promotePriority(basePriority),
76
- title: lhF.title,
77
- description: `[Lighthouse] ${lhF.description} ` +
78
- `[pa11y] ${a11yF.description} ` +
79
- `Two independent tools flagged the same accessibility gap — ` +
80
- `this cross-tool confirmation increases confidence that the issue is real and affects real users.`,
81
- evidence: {
82
- ...lhF.evidence,
83
- pa11y_rule_code: ruleCode,
84
- pa11y_selector: a11yF.evidence["selector"] ?? "",
85
- },
86
- confirmed_by: ["lighthouse", "pa11y"],
87
- });
88
- consumedLhIds.add(lhF.id);
89
- consumedA11yIds.add(a11yF.id);
90
- break; // one correlation per Lighthouse finding
91
- }
114
+ return substrings.some((s) => ruleCode.includes(s));
115
+ });
116
+ if (matches.length === 0)
117
+ continue;
118
+ // Use the most severe of the matched pa11y findings, then take the better
119
+ // (lower index = higher priority) of that and the Lighthouse finding as the
120
+ // base, and promote it one tier.
121
+ const worstA11y = matches.reduce((a, b) => PRIORITY_ORDER[a.priority] <= PRIORITY_ORDER[b.priority] ? a : b);
122
+ const basePriority = PRIORITY_ORDER[lhF.priority] <= PRIORITY_ORDER[worstA11y.priority]
123
+ ? lhF.priority
124
+ : worstA11y.priority;
125
+ // Findings arrive here already deduplicated, so fold the collapsed
126
+ // occurrence counts back in to report how many elements are affected.
127
+ const elementCount = matches.reduce((n, m) => n + Number(m.evidence["occurrences"] ?? 1), 0);
128
+ correlated.push({
129
+ id: `corr:lh+a11y:${auditId}`,
130
+ source_tool: "lighthouse+pa11y",
131
+ priority: promotePriority(basePriority),
132
+ title: lhF.title,
133
+ description: `[Lighthouse] ${lhF.description} ` +
134
+ `[pa11y] ${worstA11y.description} ` +
135
+ `Two independent tools flagged the same accessibility gap across ` +
136
+ `${elementCount} element${elementCount !== 1 ? "s" : ""} — ` +
137
+ `this cross-tool confirmation increases confidence that the issue is real and affects real users.`,
138
+ evidence: {
139
+ ...lhF.evidence,
140
+ pa11y_rule_codes: [
141
+ ...new Set(matches.map((m) => String(m.evidence["rule_code"] ?? ""))),
142
+ ],
143
+ pa11y_selectors: matches
144
+ .slice(0, 5)
145
+ .map((m) => String(m.evidence["selector"] ?? "")),
146
+ pa11y_elements_affected: elementCount,
147
+ },
148
+ confirmed_by: ["lighthouse", "pa11y"],
149
+ });
150
+ consumedLhIds.add(lhF.id);
151
+ for (const m of matches)
152
+ consumedA11yIds.add(m.id);
92
153
  }
93
154
  return { correlated, consumedLhIds, consumedA11yIds };
94
155
  }
@@ -1 +1 @@
1
- {"version":3,"file":"correlator.js","sourceRoot":"","sources":["../../src/mappers/correlator.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"correlator.js","sourceRoot":"","sources":["../../src/mappers/correlator.ts"],"names":[],"mappings":"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"}