@ia-qa/self-healing 1.5.0 → 1.5.2

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
@@ -383,6 +383,8 @@ Everything above is deterministic and **refuses to guess**: a rename Dice can't
383
383
 
384
384
  `ia-qa-heal-ai` is an **optional, opt-in** third binary that hands **only** those `lost`/`ambiguous` rows to **your own** LLM (bring your own key) and proposes a match. It is a **suggestion you confirm** — never a CI auto-fix. The deterministic `ia-qa-heal` works fully without it; configure no key and nothing changes.
385
385
 
386
+ > **There is no `--ai` flag on `ia-qa-heal`** — and there never will be: the loop and its CI verdict stay AI-free. The AI layer is always this separate binary. (`ia-qa-heal run --ai` errors and points you here.)
387
+
386
388
  **Why it stays safe** — the same reason the deterministic engine is trusted:
387
389
  - The model **picks a live candidate by index** — it cannot invent a selector, so the worst case is pointing at the wrong *existing* element, which you veto.
388
390
  - A **confidence floor** drops weak guesses; below it the row stays `lost`.
@@ -446,7 +448,7 @@ await aiClick(page, 'button#login', {
446
448
  ```
447
449
  A low-confidence, malformed, or failed call returns `null` and falls through to the deterministic heuristic — the AI never breaks a run.
448
450
 
449
- See **[ROADMAP.md](ROADMAP.md)** for what phase 2 (vision) and beyond add on top of this.
451
+ See **[ROADMAP.md](ROADMAP.md)** for what comes next — and for why the vision/VLM phase was measured and dropped: no image ever leaves your machine, because none is ever sent anywhere.
450
452
 
451
453
  ## Page Object Models — one file to keep in sync
452
454
 
package/ROADMAP.md CHANGED
@@ -16,6 +16,7 @@ The guardrails that make this safe (kept across all phases):
16
16
  4. **Suggestion, not auto-fix** — `--apply` needs a TTY and refuses in CI.
17
17
  5. **Zero bundled dependency** — provider calls are a raw `fetch`; keys via `SecretRef`, never on disk.
18
18
  6. `src/browser/match.js` stays dependency-free and byte-shared with the web tool — AI lives in a separate module that imports *from* it, never the reverse.
19
+ 7. **Framework parity** — every phase ships for all three adapters (Playwright, Cypress, Selenium) or degrades *identically* for all three; nothing lands Playwright-only. The AI layer earns this for free (it works on contracts, downstream of any browser); the one capability that would touch the framework layer is screenshot capture, now handled outside this roadmap in [SPEC-visual-evidence.md](./SPEC-visual-evidence.md).
19
20
 
20
21
  ---
21
22
 
@@ -28,32 +29,42 @@ shortlist of same-role candidates to the user's own LLM, which picks the match.
28
29
 
29
30
  - **Module** — `src/ai/resolver.ts` (`aiResolve`): same-role top-N pre-filter (reuses `diceSimilarity`/`normalize`), CoT-ordered JSON output `{rationale, confidence, candidateIndex}`, defensive parse, hardened `fetch` (AbortController timeout, 429/5xx/network → `null`).
30
31
  - **Three façades, one brain:**
31
- - CLI — third binary `ia-qa-heal-ai suggest [--apply] [--json] [--dir]`.
32
+ - CLI — third binary `ia-qa-heal-ai suggest [--apply] [--json] [--dir] [--report [file.html]] [--open]`.
32
33
  - Runtime — `createAiResolver(opts)` behind the existing `aiClick`/`aiFill` `llmResolver` seam.
33
34
  - MCP — `suggest_heal` tool (key from the server's env, never passed in the call; writes nothing).
34
35
  - **Config** — optional `ai` block in `.ia-qa/config.json` (`provider`, `model`, `apiKey: SecretRef`, `minConfidence`), written by an interactive `ia-qa-heal-ai init` picker (`ia-qa-heal-ai models` lists the catalogue).
35
36
  - **Providers** — `openai`, `anthropic`, `google` (Gemini). Curated model list + free-form custom ids; temperature sent at 0 with an automatic no-temperature retry on a 400, so models that reject sampling params (newest Claude/GPT reasoning models) still work.
36
37
 
37
- **Status:** implemented, 17 unit tests (mocked `fetchFn`, no network), full suite green (deterministic non-regression verified). Pending real-key dogfood on a live app before release.
38
+ **Status:** released — on npm since `1.1.0` (2026-07-19), current `1.5.1`. 17 unit tests (mocked `fetchFn`, no network), full suite green (deterministic non-regression verified). Real-key dogfood of `suggest`: **done** (2026-07-23, external Playwright repo, OpenAI). First attempt never reached the resolver — the tester ran `ia-qa-heal --ai`, a silent no-op, because the main help never mentioned `ia-qa-heal-ai`; fixed in `1.5.1` (help points to the add-on; unknown flags error loudly, `--ai` answers with the `ia-qa-heal-ai` pointer — `src/cli/args.ts`, pinned by `tests/cliArgs.test.js`). Second attempt exercised the full binary against a live key: a cross-language semantic rename (`"Envoyer le formulaire"` → `"Submit form"`, different selectors) came back with a correct suggestion (`confidence` 0.76), and the no-drift case returned empty arrays; both are now pinned as key-gated e2e tests in the dogfood repo. Caveat: the renames were synthetic (hand-edited baseline). Still to collect from *organic* drift: whether `confidence` behaves at the floor (the phase-3 trigger). The other open question — how often the icon-only/no-name tranche shows up — was answered by measurement on 2026-07-25 and closed phase 2 (below).
38
39
 
39
40
  ---
40
41
 
41
- ## Phase 2 — Vision (VLM), *conditional*
42
+ ## Phase 2 — Vision (VLM) — ❌ **dropped, 2026-07-25**
42
43
 
43
- The one tranche text cannot reach: an element that **lost its accessible name AND
44
- moved** — an icon-only button with `name: ""`, where Dice has nothing to rank on
45
- and even the LLM has only role + context to go by. A screenshot supplies the signal
46
- the contract deliberately doesn't store (visual layout).
44
+ This phase targeted the one tranche text cannot reach: an element that **lost its
45
+ accessible name AND moved** — an icon-only button with `name: ""` to be resolved
46
+ by sending a screenshot to a VLM. Its gate was *"dogfooding shows the icon-only
47
+ tranche is a real, recurring miss"*.
47
48
 
48
- Prerequisites (all additive, none touch the deterministic verdict):
49
+ **The gate was measured, and it fails.** 4 706 real elements (40 pages of a
50
+ dogfood corpus + 12 third-party sites mapped live):
49
51
 
50
- - **Persist geometry**`src/browser/extract.js` already computes `getBoundingClientRect()` for a visibility gate, then discards it. Keep it: add `rect?: {x,y,w,h}` to `MappedElement`.
51
- - **Capture a screenshot** `page.screenshot()` in `mapUrl.ts` / `map.ts` / `capture.ts`, stored beside the contract. Uses the browser the package *already* launches **no Playwright MCP, no new install.**
52
- - **Multimodal `aiResolve`** a variant that sends the image + candidate crops to a VLM. Same invariant 2: the model still picks **by index**.
52
+ - The blind tranche no accessible name, no `hint`, **and** a positional selector, the only one a VLM could reach — is **0 elements in the wild**. Every anonymous element found there carries an identity selector (`a[href=…]`, `[data-testid=…]`), so it cannot drift positionally.
53
+ - The 25 blind rows in the dogfood corpus are **unlabelled range sliders and colour pickersnot a single icon-only button**.
54
+ - **100 % of them (52/52) are recoverable by a plain DOM read** (`title` on a descendant, or the nearest ancestor's own text) — including the canonical case, Excalidraw's `data-testid="main-menu-trigger"` hamburger, whose neighbouring text already says *"Exportation, préférences, langues…"*. The screenshot would be a lossy, paid re-derivation of a string the extractor already had in hand.
53
55
 
54
- **Gate to start it:** phase-1 dogfooding shows the icon-only tranche is a real, recurring miss worth the added weight (screenshots on disk, geometry in the contract, VLM latency/cost). Text-only already covers semantic renames without any schema change, so phase 2 earns its place only if the data says so.
56
+ And a reason that does not depend on any measurement: **a crop of a customer's
57
+ authenticated app is not a contract.** The AI add-on sends *structure* today —
58
+ role, name, selector, context. An image sends whatever was on screen: customer
59
+ names, amounts, records. That is a different consent, not an extra option.
55
60
 
56
- **Non-goal even here:** vision output is still a suggestion for `lost`/`ambiguous`, still outside CI.
61
+ **What survives, and where it went:** the useful half of this phase persisting
62
+ `rect`, capturing a screenshot, cropping it — is real, but it serves a *human
63
+ triage* need the roadmap never identified: the `ambiguous` population (role + name
64
+ + context collisions) is **10,2 % of elements on the dogfood corpus and 20,3 % in
65
+ the wild** — 6 to 20× the anonymous one. It is specified, fully local, with no
66
+ model call at all, in **[SPEC-visual-evidence.md](./SPEC-visual-evidence.md)**
67
+ (not shipped in the npm tarball). Measurements are reproducible from `studies/`.
57
68
 
58
69
  ---
59
70
 
@@ -76,5 +87,5 @@ speculative building.
76
87
  - **AI inside the CI gate / `fix`.** The gate stays deterministic. This is the whole point.
77
88
  - **A runtime computer-use agent** (clicking through unpredictable modals, CAPTCHAs). That is a different product — autonomous test *execution*, not selector self-healing — and would dilute the "deterministic codemod of test source" identity. The `llmResolver` seam is for a lightweight per-action resolver, not an agent loop.
78
89
  - **A bundled embedding/vision model.** Everything ships as raw `fetch` (BYOK). No multi-MB model in the package.
79
- - **A dependency on the Playwright MCP.** The package launches its own headless Chromium; screenshots (phase 2) are taken with it.
90
+ - **A dependency on the Playwright MCP.** The package launches its own headless Chromium; any screenshot it ever takes is taken with that.
80
91
  - **A separate npm package for the AI layer.** It consumes the healing package's contract + diff, so it cannot be functionally standalone; a third `bin` in the same package gives the "distinct, optional add-on" feel without a second release pipeline or a PATH collision.
package/TUTORIAL.md CHANGED
@@ -480,6 +480,8 @@ Steps 1–8 are **100% deterministic** and **refuse to guess**. That is delibera
480
480
 
481
481
  If you'd rather get a *suggestion* for those, there's an **optional** add-on: `ia-qa-heal-ai`. It sends **only** the `lost`/`ambiguous` elements to **your own** AI model (you bring your own API key) and proposes a match — which you then confirm. It never runs in CI, never auto-edits, and the normal tool works completely without it.
482
482
 
483
+ > Note it is a **separate command**, not a flag: there is no `--ai` on `ia-qa-heal` (trying it errors and points you here). Putting an API key in `.env` activates nothing by itself — the AI only ever runs when *you* run `ia-qa-heal-ai suggest`.
484
+
483
485
  **1. Pick your model** — one command, choose from a list, it writes the config for you:
484
486
  ```bash
485
487
  npx ia-qa-heal-ai init
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Flag validation for the hand-rolled CLI parser.
3
+ *
4
+ * Every subcommand parses its own args and used to swallow flags it did not
5
+ * know — `ia-qa-heal run --ai` ran the deterministic loop and said nothing,
6
+ * a reassuring no-op that made a field tester conclude the AI layer did not
7
+ * exist. Unknown flags now fail loudly, and `--ai` specifically points to the
8
+ * separate `ia-qa-heal-ai` binary (the gate stays AI-free by design).
9
+ *
10
+ * Flag *values* never start with `-` here (URLs, paths, numbers, words), so a
11
+ * leading dash is enough to tell a flag from a positional.
12
+ */
13
+ export declare const KNOWN_FLAGS: Record<string, readonly string[]>;
14
+ export declare function rejectUnknownFlags(command: string, args: string[]): void;
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.KNOWN_FLAGS = void 0;
4
+ exports.rejectUnknownFlags = rejectUnknownFlags;
5
+ /**
6
+ * Flag validation for the hand-rolled CLI parser.
7
+ *
8
+ * Every subcommand parses its own args and used to swallow flags it did not
9
+ * know — `ia-qa-heal run --ai` ran the deterministic loop and said nothing,
10
+ * a reassuring no-op that made a field tester conclude the AI layer did not
11
+ * exist. Unknown flags now fail loudly, and `--ai` specifically points to the
12
+ * separate `ia-qa-heal-ai` binary (the gate stays AI-free by design).
13
+ *
14
+ * Flag *values* never start with `-` here (URLs, paths, numbers, words), so a
15
+ * leading dash is enough to tell a flag from a positional.
16
+ */
17
+ exports.KNOWN_FLAGS = {
18
+ init: [],
19
+ discover: ['--sitemap', '--crawl', '--no-reveal', '--strict-host', '--apply', '--max', '--depth'],
20
+ map: [],
21
+ baseline: [],
22
+ diff: ['--strict', '--json', '--dir', '--report', '--open'],
23
+ fix: ['--dry-run', '--locators', '--dir'],
24
+ ingest: [],
25
+ graph: ['--format', '--kind', '--out', '--open'],
26
+ run: ['--yes', '--no-verify', '--locators', '--report', '--open'],
27
+ };
28
+ function rejectUnknownFlags(command, args) {
29
+ const known = exports.KNOWN_FLAGS[command];
30
+ if (known === undefined)
31
+ return;
32
+ for (const a of args) {
33
+ if (!a.startsWith('-'))
34
+ continue;
35
+ if (known.includes(a))
36
+ continue;
37
+ if (a === '--ai' || a.startsWith('--ai=')) {
38
+ throw new Error(`"ia-qa-heal ${command}" has no --ai flag — the deterministic loop and its CI verdict stay AI-free by design.\n` +
39
+ `The AI layer is a separate binary shipped in this same package: ia-qa-heal-ai (init / models / suggest).\n` +
40
+ `It suggests matches for the lost/ambiguous rows a diff leaves behind: ia-qa-heal-ai suggest`);
41
+ }
42
+ throw new Error(`Unknown flag "${a}" for "ia-qa-heal ${command}". Run \`ia-qa-heal help\` to see its flags.`);
43
+ }
44
+ }
45
+ //# sourceMappingURL=args.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"args.js","sourceRoot":"","sources":["../../src/cli/args.ts"],"names":[],"mappings":";;;AAwBA,gDAeC;AAvCD;;;;;;;;;;;GAWG;AACU,QAAA,WAAW,GAAsC;IAC5D,IAAI,EAAE,EAAE;IACR,QAAQ,EAAE,CAAC,WAAW,EAAE,SAAS,EAAE,aAAa,EAAE,eAAe,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,CAAC;IACjG,GAAG,EAAE,EAAE;IACP,QAAQ,EAAE,EAAE;IACZ,IAAI,EAAE,CAAC,UAAU,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU,EAAE,QAAQ,CAAC;IAC3D,GAAG,EAAE,CAAC,WAAW,EAAE,YAAY,EAAE,OAAO,CAAC;IACzC,MAAM,EAAE,EAAE;IACV,KAAK,EAAE,CAAC,UAAU,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,CAAC;IAChD,GAAG,EAAE,CAAC,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,UAAU,EAAE,QAAQ,CAAC;CAClE,CAAC;AAEF,SAAgB,kBAAkB,CAAC,OAAe,EAAE,IAAc;IAChE,MAAM,KAAK,GAAG,mBAAW,CAAC,OAAO,CAAC,CAAC;IACnC,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO;IAChC,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;QACrB,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,SAAS;QACjC,IAAI,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC;YAAE,SAAS;QAChC,IAAI,CAAC,KAAK,MAAM,IAAI,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;YAC1C,MAAM,IAAI,KAAK,CACb,eAAe,OAAO,0FAA0F;gBAC9G,4GAA4G;gBAC5G,8FAA8F,CACjG,CAAC;QACJ,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,qBAAqB,OAAO,8CAA8C,CAAC,CAAC;IAChH,CAAC;AACH,CAAC"}
package/dist/cli/index.js CHANGED
@@ -2,6 +2,7 @@
2
2
  "use strict";
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
4
  const config_1 = require("../config");
5
+ const args_1 = require("./args");
5
6
  const init_1 = require("./init");
6
7
  const map_1 = require("./map");
7
8
  const baseline_1 = require("./baseline");
@@ -21,7 +22,9 @@ One verb: ia-qa-heal run (capture during your suite → diff → confirm → f
21
22
  [FOR AI AGENTS] You are driving this for a human. Explain the loop and the
22
23
  PASS/FIX/BLOCK verdict; propose running it when their E2E selectors may have
23
24
  drifted. In non-interactive shells, write .ia-qa/config.json directly instead
24
- of \`init\` (see the wizard's non-TTY guidance).
25
+ of \`init\` (see the wizard's non-TTY guidance). The AI layer is the separate
26
+ \`ia-qa-heal-ai\` binary (BYOK suggestions for lost/ambiguous rows) — this
27
+ binary has no --ai flag: the loop and its CI verdict stay deterministic.
25
28
 
26
29
  Usage:
27
30
  ia-qa-heal init Interactive setup wizard (writes .ia-qa/config.json)
@@ -96,6 +99,12 @@ Global:
96
99
  --config <dir> Resolve .ia-qa/ under <dir> instead of the current directory
97
100
  (monorepos: one config per portal). Also IAQA_CONFIG_DIR=<dir>,
98
101
  the only lever that reaches capture (it runs in your test process).
102
+
103
+ AI add-on (separate binary, same package — optional, BYOK):
104
+ ia-qa-heal-ai init | models | suggest Suggests matches for the lost/ambiguous rows a diff leaves
105
+ behind, using your own LLM key (OpenAI / Anthropic / Gemini).
106
+ A suggestion you confirm — never part of the CI gate, which
107
+ is why there is no --ai flag on ia-qa-heal itself.
99
108
  `;
100
109
  /**
101
110
  * Pull the global `--config <dir>` / `--config=<dir>` out of argv wherever it
@@ -134,6 +143,12 @@ async function main() {
134
143
  (0, config_1.setBaseDir)(configDir);
135
144
  }
136
145
  const [command, ...rest] = argv;
146
+ if (rest.includes('--help') || rest.includes('-h')) {
147
+ console.log(HELP);
148
+ return;
149
+ }
150
+ if (command !== undefined)
151
+ (0, args_1.rejectUnknownFlags)(command, rest);
137
152
  const arg = rest[0];
138
153
  switch (command) {
139
154
  case 'init':
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ia-qa/self-healing",
3
- "version": "1.5.0",
3
+ "version": "1.5.2",
4
4
  "description": "Local-first self-healing for UI tests: a local MCP server + CLI that map your app's pages to a role/name/selector contract, diff selector drift (PASS/FIX/BLOCK), and apply deterministic fixes to Cypress/Playwright/Selenium tests. Runs on your machine — nothing leaves it.",
5
5
  "keywords": [
6
6
  "self-healing",