@ia-qa/pal 0.1.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
@@ -2,12 +2,14 @@
2
2
 
3
3
  **A QA pal next to your team — not instead of it.**
4
4
 
5
- One command walks your web app, maps every page, checks it, and compares it with the last tour. Then it tells you four things, in the order you act on them: what is **broken**, what **needs a decision**, what is **ready to repair**, and what it **could not see**.
5
+ One command walks your web app, maps every page, checks it, and compares it with the last tour — and, when you declare your end-to-end suite, reads it too. Then it tells you four things, in the order you act on them: what is **broken**, what **needs a decision**, what is **ready to repair**, and what it **could not see**.
6
6
 
7
7
  - **Local.** A headless browser on your machine. Nothing is uploaded, no account, no LLM.
8
8
  - **Deterministic.** Verdicts come from [`@ia-qa/self-healing`](https://www.npmjs.com/package/@ia-qa/self-healing) — the same engine as `ia-qa-heal diff` and `ia-qa-heal check`, so the two can never disagree.
9
9
  - **Honest about coverage.** A tour that measured part of your app says which part. A first tour establishes a baseline; it is never reported as a pass.
10
10
 
11
+ > **New here?** The [step-by-step tutorial](https://www.ia-qa.com/devtools/pal/tutorial) walks a first tour, reading the report, logins and CI.
12
+
11
13
  ## Install
12
14
 
13
15
  ```bash
@@ -15,26 +17,36 @@ npm i -D @ia-qa/pal
15
17
  npx playwright install chromium
16
18
  ```
17
19
 
18
- `ia-qa-pal` needs a `.ia-qa/config.json` with your `baseUrl` and pages. The setup wizard comes with the dependency:
20
+ ## Use
19
21
 
20
22
  ```bash
21
- npx ia-qa-heal init
23
+ npx ia-qa-pal tour
22
24
  ```
23
25
 
24
- Behind a login? Either declare it in `init`, point at a Playwright `storageState` your suite already writes (`--session`), or log in once by hand with `npx ia-qa-heal login`.
26
+ **Not set up yet?** In a terminal, the first `tour` asks where the app lives and how it logs in — and, when it finds a test suite in the project, whether to read it — then reads its pages from `sitemap.xml` (or, without one, follows its links: same host, GET only, at most 50 pages), shows you exactly what it will write, and writes it only when you say yes. Nothing it asks takes a password.
25
27
 
26
- ## Use
28
+ From CI or an agent, the same setup with flags:
27
29
 
28
30
  ```bash
29
- npx ia-qa-pal tour
31
+ npx ia-qa-pal setup --url https://your-app.example --login none --yes
30
32
  ```
31
33
 
34
+ | `--login` | |
35
+ |---|---|
36
+ | `none` | public pages |
37
+ | `browser` | you log in by hand once — SSO, MFA, anything: `npx -p @ia-qa/self-healing ia-qa-heal login` |
38
+ | `session --session <file>` | your test suite already saves a Playwright `storageState`; only its path is written |
39
+
40
+ A login form filled from environment variables (`auth` in the config) is set up with `npx -p @ia-qa/self-healing ia-qa-heal init`.
41
+
32
42
  **First tour** — every page on the surface (no clicks), the first 10 pages that have closed menus, tabs or dialogs explored in depth, the checks, and a baseline.
33
43
 
34
44
  **Every tour after** — each page re-captured the way its baseline was captured, compared with it, checked.
35
45
 
36
46
  **`--more`** — explores the next batch in depth and adds it to the baseline. It refuses while the last tour ended on BLOCK: promoting those pages would accept drift nobody looked at.
37
47
 
48
+ Illustrative report:
49
+
38
50
  ```
39
51
  ia-qa-pal tour — https://app.example · level 1 (with a login)
40
52
  ✅ PASS · 7937 ok · 1 renamed · 0 lost · 0 ambiguous · 0 rebound
@@ -48,11 +60,42 @@ ia-qa-pal tour — https://app.example · level 1 (with a login)
48
60
 
49
61
  The time estimate only appears once a batch has been explored on your app: it is the pace measured there, never a constant.
50
62
 
63
+ ## With your test suite
64
+
65
+ Declare it at setup (`--tests tests/`, or answer yes when the tour finds it) and every tour also reads it:
66
+
67
+ - **🔧 Ready to repair** — when a selector your tests write stops reaching its element while the element is still there, the rewrite is listed with `file:line` and the command that applies it after you review it. pal never edits your tests.
68
+ - **⛔ To decide** — locator names your tests use that nothing on the mapped pages carries, and renamed labels your tests locate by name.
69
+ - **🔍 Not seen** — `ia-qa-pal tour --suite` runs the `testCommand` from your config once, with the capture hook, and names the pages your suite **never visits**. The capture is kept apart from the tour's contracts. Your specs need the hook for this — one import:
70
+
71
+ ```js
72
+ import { test, expect } from '@ia-qa/self-healing/capture';
73
+ ```
74
+
75
+ Without it, the report says the suite ran but recorded no page — never that it visits nothing.
76
+
77
+ ## In the background, and for agents
78
+
79
+ ```bash
80
+ npx ia-qa-pal tour --background # returns at once
81
+ npx ia-qa-pal status # phase and progress, then the report
82
+ ```
83
+
84
+ One tour runs per project; a second is refused while the first is alive, and a tour whose process died is reported as interrupted, never as running.
85
+
86
+ `ia-qa-pal-mcp` is the same thing as a local stdio MCP server — `pal_project`, `pal_setup`, `pal_tour` (always in the background, so no client times out) and `pal_status`. No tool takes a command, and there is no login tool.
87
+
88
+ ```json
89
+ { "mcpServers": { "ia-qa-pal": { "command": "npx", "args": ["-y", "-p", "@ia-qa/pal", "ia-qa-pal-mcp"] } } }
90
+ ```
91
+
51
92
  ### Options
52
93
 
53
94
  | flag | |
54
95
  |---|---|
55
96
  | `--more` | explore the next batch in depth instead of a regression tour |
97
+ | `--suite` | also run your test command once, with the capture hook |
98
+ | `--background` | start detached and return at once |
56
99
  | `--batch <n>` | pages per depth batch (default 10) |
57
100
  | `--json` | the whole report as one JSON document on stdout; progress stays on stderr |
58
101
  | `--session <file>` | a Playwright `storageState` to reuse |
@@ -62,9 +105,9 @@ The time estimate only appears once a batch has been explored on your app: it is
62
105
 
63
106
  | code | meaning |
64
107
  |---|---|
65
- | `0` | nothing needs a decision (warnings never fail a tour) |
66
- | `1` | a dead link, or drift that blocks (an element lost, ambiguous, or a selector now pointing at another element) |
67
- | `2` | could not answer: no config, nothing could be mapped, or the tour refused to run |
108
+ | `0` | nothing needs a decision (warnings and proposed repairs never fail a tour) |
109
+ | `1` | a dead link, drift that blocks (an element lost, ambiguous, or a selector now pointing at another element), or your suite failed when run with `--suite` |
110
+ | `2` | could not answer: not set up, nothing could be mapped, the tour refused to run, or one is already running |
68
111
 
69
112
  Read `2` as "no answer", never as "the app is broken".
70
113
 
@@ -73,8 +116,5 @@ Read `2` as "no answer", never as "the app is broken".
73
116
  - **Only your app.** Its pages load whatever they load in any browser.
74
117
  - **Exploration is read-only.** While menus, tabs and dialogs are opened, every non-GET request is blocked, and controls named like actions (log out, delete, pay…) are never clicked.
75
118
  - **The link check** requests your app's own links with GET, skipping any URL that acts (`/logout`, `/delete`…).
76
- - **Files** live in `.ia-qa/`: contracts, baseline, and `pal/state.json` (pace and already-reported findings). A saved session there holds live cookies — it is gitignored and never leaves your machine.
77
-
78
- ## Not yet
79
-
80
- Reading your test suite (coverage of what it does not test, repairs proposed as a patch), a setup inside `ia-qa-pal` itself, a local MCP server for agents, and background exploration are planned next.
119
+ - **Your test command** runs only with `--suite` (or `suite: true` from an agent), and it is always the one in your config — never a string passed on the call.
120
+ - **Files** live in `.ia-qa/`: contracts, baseline, `usage.json` (your suite's locators), and `pal/` (the measured pace, findings already reported, the current run and its log). A saved session there holds live cookies — it is gitignored and never leaves your machine.
package/TUTORIAL.md ADDED
@@ -0,0 +1,375 @@
1
+ # ia-qa-pal — tutorial
2
+
3
+ `@ia-qa/pal` is a QA pal **next to** your team. It does the routine rounds nobody has time for — walk the whole app, map every page, check it, compare it with the last round — and hands a person only what needs a person.
4
+
5
+ It is not a QA engineer. It does not know what your app *should* do, so it never judges business behaviour. It knows what your app *did* yesterday, what is broken in a way any app can be broken (a dead link, a control nobody can name), and — the part most tools leave out — **what it could not see**.
6
+
7
+ Everything runs on your machine, in a headless browser. Nothing is uploaded. No LLM decides anything.
8
+
9
+ ---
10
+
11
+ ## 1. Install
12
+
13
+ Node 18 or newer.
14
+
15
+ ```bash
16
+ npm i -D @ia-qa/pal
17
+ npx playwright install chromium
18
+ ```
19
+
20
+ Check it answers:
21
+
22
+ ```bash
23
+ npx ia-qa-pal --help
24
+ ```
25
+
26
+ ---
27
+
28
+ ## 2. The first tour
29
+
30
+ In your project folder:
31
+
32
+ ```bash
33
+ npx ia-qa-pal tour
34
+ ```
35
+
36
+ The project is not set up yet, so the tour asks first: where the app lives, how it logs in, and — only when it finds a test suite in the folder — whether to read it (section 7).
37
+
38
+ ```
39
+ This project is not set up yet — a few questions first.
40
+
41
+ Where does the app live? (https://…) https://www.ia-qa.com
42
+ Does the app ask you to log in?
43
+ 1 no
44
+ 2 yes — I log in by hand in a browser (SSO, MFA, anything)
45
+ 3 yes — my test suite already saves a Playwright storageState file
46
+ Choice [1-3]: 1
47
+ 🗺 Reading www.ia-qa.com/sitemap.xml (and robots.txt) — a plain fetch, nothing else.
48
+ Found 146 pages.
49
+
50
+ 📄 This writes /home/me/shop/.ia-qa/config.json
51
+ app https://www.ia-qa.com
52
+ pages 146 from the sitemap: home, all-tools, method, resources, articles, veille, mcp-server, mcp-registry, +138 more
53
+ login none
54
+ Nothing else is written. No field holds a secret.
55
+ Write it? [y/N] y
56
+ ```
57
+
58
+ - **The pages come from your `sitemap.xml`.** No sitemap? It follows the links from your home page instead — same host, GET only, at most 50 pages, never a link that acts (`/logout`, `/delete`…).
59
+ - **It shows the file before writing it**, and what it shows is exactly what it writes. It never overwrites an existing config.
60
+ - **No question takes a password.**
61
+
62
+ Then the tour runs:
63
+
64
+ 1. **Surface** — every page, loaded, no clicks. On a real site this is about 1.7 s a page.
65
+ 2. **Depth** — the first 10 pages that have closed menus, tabs, accordions or dialogs are explored: each is opened, and what it reveals goes into the page's contract. About 20 s a page, and it grows with the number of controls.
66
+ 3. **Checks** — dead links, controls without an accessible name, names shared by several controls, pages nothing links to.
67
+ 4. **Baseline** — what the app is today becomes the reference for tomorrow.
68
+
69
+ ---
70
+
71
+ ## 3. Reading the first report
72
+
73
+ A real first tour, on a 9-page app behind a login:
74
+
75
+ ```
76
+ ia-qa-pal tour — https://www.nodemented.com · level 1 (with a login)
77
+ 📌 Baseline established — nothing to compare yet. The next tour measures drift against it.
78
+ 9 of 9 pages under contract · 8 explored in depth of 8 pages with closed controls
79
+
80
+ ⛔ To decide
81
+ new 14 elements without an accessible name — e.g. alert #\31 on billing
82
+ new 7 names shared by several elements — e.g. button "🎥" ×10 on feature-manager
83
+ new 8 pages nothing links to — admin-dashboard, billing, cookies, …
84
+ Full list: ia-qa-heal check. Warnings never fail the tour.
85
+ ```
86
+
87
+ Every page fit in the first batch, so nothing was left unexplored. On a larger app the report ends with what the tour did not reach — illustrative numbers:
88
+
89
+ ```
90
+ 🔍 Not seen
91
+ 136 pages with closed controls not explored yet — about 47 min (3000 controls × 0.94 s, pace measured on 142 clicks)
92
+ ia-qa-pal tour --more explores the next batch
93
+ ```
94
+
95
+ The report has at most four sections, and each one appears only when it holds something:
96
+
97
+ | section | what it holds | what you do |
98
+ |---|---|---|
99
+ | 🔴 **Broken in the app** | links your app itself answers with an error | fix the link |
100
+ | ⛔ **To decide** | drift that blocks, and findings seen for the first time | a person looks |
101
+ | 🔧 **Ready to repair** | *(coming with test-suite support)* | |
102
+ | 🔍 **Not seen** | pages not explored, not mapped, only partly explored, links it could not verify | decide whether it matters |
103
+
104
+ Three things are worth knowing about this first report:
105
+
106
+ - **It is not a pass.** Nothing was compared — there was nothing to compare with. The headline says so.
107
+ - **The denominator is always there.** `10 explored in depth of 146` is the honest number; `10 pages explored` would not be.
108
+ - **The time estimate is measured, not assumed.** It only appears once a batch has run on *your* app, and it prints what it rests on.
109
+
110
+ ---
111
+
112
+ ## 4. The next tours
113
+
114
+ Change nothing, or deploy something, and run it again:
115
+
116
+ ```bash
117
+ npx ia-qa-pal tour
118
+ ```
119
+
120
+ The same app, the next tour:
121
+
122
+ ```
123
+ ia-qa-pal tour — https://www.nodemented.com · level 1 (with a login)
124
+ ✅ PASS · 358 ok · 0 renamed · 0 lost · 0 ambiguous · 0 rebound
125
+ 9 of 9 pages under contract · 8 explored in depth of 8 pages with closed controls
126
+ 29 warnings already reported — not listed again.
127
+ ```
128
+
129
+ Each page is captured again **the way its baseline was captured** — on the surface, or opened in depth — and compared with it. A finding already reported is counted, not listed again: a list that never shrinks stops being read by the third tour.
130
+
131
+ When something moved (illustrative):
132
+
133
+ ```
134
+ ⛔ BLOCK · 1937 ok · 0 renamed · 1 lost · 0 ambiguous · 0 rebound
135
+
136
+ ⛔ To decide
137
+ drift settings: 1 lost · 0 ambiguous · 0 rebound
138
+ ```
139
+
140
+ What the words mean:
141
+
142
+ | word | meaning |
143
+ |---|---|
144
+ | `renamed` | the same control, relabelled. Reported, never blocking. |
145
+ | `lost` | a control that is gone. |
146
+ | `ambiguous` | several controls now answer to the same description — choosing would be guessing. |
147
+ | `rebound` | a selector that used to reach one control now reaches **another**. A test using it would pass while clicking the wrong thing. |
148
+
149
+ A label that changes on its own every run — a counter, a date, a generated value — comes back as `renamed` every time. Tell it apart once in `.ia-qa/config.json`:
150
+
151
+ ```json
152
+ "nameMask": ["Cart (*)"]
153
+ ```
154
+
155
+ The control stays under contract; only its label is no longer compared.
156
+
157
+ ### Exit codes
158
+
159
+ | code | meaning |
160
+ |---|---|
161
+ | `0` | nothing needs a decision — warnings never fail a tour |
162
+ | `1` | a dead link, or drift that blocks |
163
+ | `2` | no answer: not set up, nothing could be mapped, or the tour refused to run |
164
+
165
+ Read `2` as "could not answer", never as "the app is broken".
166
+
167
+ ---
168
+
169
+ ## 5. Exploring the rest
170
+
171
+ ```bash
172
+ npx ia-qa-pal tour --more
173
+ ```
174
+
175
+ ```
176
+ # illustrative
177
+ 🔍 10 pages explored in depth and promoted to the baseline: resources, articles, …
178
+ ```
179
+
180
+ `--more` explores the next batch and adds those pages to the baseline. Run it when you have the time — the estimate told you how much. `--batch <n>` changes the batch size.
181
+
182
+ It **refuses** when the last tour ended on BLOCK:
183
+
184
+ ```
185
+ ⏸ Did not run — The last tour ended on BLOCK. Exploring now would promote those pages as they are today and accept that drift unseen — resolve it, then run `ia-qa-pal tour` again.
186
+ ```
187
+
188
+ Promoting a page to the baseline says "this is how it should be". Doing that while something unexplained changed would accept the change without anyone looking at it.
189
+
190
+ ---
191
+
192
+ ## 6. Behind a login
193
+
194
+ The second setup question has three answers.
195
+
196
+ **By hand in a browser** — for SSO, MFA, a consent screen, a magic link, anything:
197
+
198
+ ```bash
199
+ npx -p @ia-qa/self-healing ia-qa-heal login
200
+ ```
201
+
202
+ A visible browser opens, you log in, and the session is saved in `.ia-qa/session.json`. That file holds live cookies: it is gitignored and never leaves your machine. When it expires, the pages behind the login show up in **Not seen** — never as a pass.
203
+
204
+ Pages found during setup were found without logging in. Once logged in, list the ones behind the login:
205
+
206
+ ```bash
207
+ npx -p @ia-qa/self-healing ia-qa-heal discover --crawl --apply
208
+ ```
209
+
210
+ **Your test suite already saves a session** — most authenticated Playwright suites write a `storageState` in `globalSetup`. Give its path; only the path is written:
211
+
212
+ ```bash
213
+ npx ia-qa-pal setup --url https://staging.shop.example --login session --session playwright/.auth/user.json --yes
214
+ ```
215
+
216
+ **A login form filled from environment variables** is set up with `npx -p @ia-qa/self-healing ia-qa-heal init`, which writes the variable *names*, never their values.
217
+
218
+ ---
219
+
220
+ ## 7. With your test suite
221
+
222
+ A tour already tells you what changed in the app. With your end-to-end suite declared, it also tells you what that change does to **your tests**.
223
+
224
+ Declare it once — the setup offers it when it finds a `tests/`, `e2e/` or `cypress/e2e/` folder with specs, or with flags:
225
+
226
+ ```bash
227
+ npx ia-qa-pal setup --url https://staging.shop.example --login none --tests tests --yes
228
+ ```
229
+
230
+ The command that runs the suite is detected from `package.json` (`test:e2e`, `e2e`…) or a `playwright.config`; set it yourself with `--test-command "npm run test:e2e"`.
231
+
232
+ From then on, every tour reads the suite's locators before capturing, and the report gains three things.
233
+
234
+ **🔧 Ready to repair.** A selector your tests write stopped reaching its element — the class changed, a `data-testid` was added — while the element itself is still on the page (illustrative):
235
+
236
+ ```
237
+ 🔧 Ready to repair (1 replacement in 1 file)
238
+ tests/settings.spec.js:17 .btn-primary → #prefs > button:nth-of-type(1)
239
+ Apply after review: npx -p @ia-qa/self-healing ia-qa-heal fix (pal never edits your tests)
240
+ ```
241
+
242
+ pal only lists it. `ia-qa-heal fix` computes the same rewrite and applies it — review it with `git diff` before committing. A rewrite that could break a passing test (two pages wanting the same string to become two different things, an XPath inside `By.xpath`) is left out and named, never guessed.
243
+
244
+ **⛔ To decide.** Locator names your tests use that nothing on the mapped pages carries — `getByRole('button', { name: 'Save' })` when no button is called Save anymore — with `file:line`. It is advisory: the name may live on a page or in a state the tour did not map. And when a label your tests locate by name was renamed, the tour says so.
245
+
246
+ **🔍 Which pages your suite never visits.** This one needs the suite to run:
247
+
248
+ ```bash
249
+ npx ia-qa-pal tour --suite
250
+ ```
251
+
252
+ It runs the `testCommand` from your config once, with the capture hook armed, and keeps only the list of pages the suite really opened — its capture never mixes with the tour's contracts. The answer stays in the report until the next `--suite` (illustrative):
253
+
254
+ ```
255
+ 🔍 Not seen
256
+ your suite never visits 14 of 17 pages (run of 2026-09-15): faq, jeu-galaxie, jeu-classement, …
257
+ ```
258
+
259
+ Your specs need the capture hook — one import, a drop-in for Playwright's own:
260
+
261
+ ```js
262
+ import { test, expect } from '@ia-qa/self-healing/capture';
263
+ ```
264
+
265
+ Without it, the report says the suite ran but recorded no page, and names the import. It never says your suite visits nothing. If the suite fails during `--suite`, the tour reports it under **Broken** and exits `1`.
266
+
267
+ ---
268
+
269
+ ## 8. In the background
270
+
271
+ A tour on a large app takes a while. Start it and get your terminal back:
272
+
273
+ ```bash
274
+ npx ia-qa-pal tour --background
275
+ npx ia-qa-pal status
276
+ ```
277
+
278
+ ```
279
+ ⏳ A tour is running (pid 34136, since 2026-09-15T14:04:32Z) — depth 4/10 · jeu-planete
280
+ ```
281
+
282
+ When it is done, `status` prints the report. Only one tour runs per project: a second is refused while the first is alive, because two tours would write the same contracts. A tour whose process died before finishing is reported as **interrupted** — never as still running, never as a result. Its output is in `.ia-qa/pal/run.log`.
283
+
284
+ ---
285
+
286
+ ## 9. In CI
287
+
288
+ Build the baseline on your machine, commit it, and let CI compare.
289
+
290
+ ```bash
291
+ git add .ia-qa/config.json .ia-qa/baseline .ia-qa/pal/state.json
292
+ git commit -m "ia-qa-pal baseline"
293
+ ```
294
+
295
+ Never commit `.ia-qa/session.json`.
296
+
297
+ ```yaml
298
+ - run: npm ci
299
+ - run: npx playwright install chromium
300
+ - run: npx ia-qa-pal tour --json > pal-report.json
301
+ ```
302
+
303
+ - With the baseline committed, a tour in CI is a regression tour: it never grows the baseline. (Without one, it would run a first tour and write a baseline nobody reviewed — commit it first.) A green run over 10 pages and a green run over 20 do not say the same thing, so the reference changes only when a person runs `--more` or promotes it.
304
+ - `--json` puts the whole report on stdout; progress stays on stderr.
305
+ - Gate on the exit code: `1` fails the build, `2` means the job could not answer — report it as a broken job, not as a broken app.
306
+ - Setting up from CI takes flags and never asks: `ia-qa-pal setup --url … --login none --yes`.
307
+
308
+ ---
309
+
310
+ ## 10. With an AI agent
311
+
312
+ An agent can drive `ia-qa-pal` from a shell, or through its local MCP server:
313
+
314
+ ```json
315
+ { "mcpServers": { "ia-qa-pal": { "command": "npx", "args": ["-y", "-p", "@ia-qa/pal", "ia-qa-pal-mcp"] } } }
316
+ ```
317
+
318
+ | tool | what it does |
319
+ |---|---|
320
+ | `pal_project` | is the project set up, its level, its baseline, a tour running? |
321
+ | `pal_setup` | writes the config from **your** answers — never overwrites one |
322
+ | `pal_tour` | starts a tour in the background and returns at once, so no client times out |
323
+ | `pal_status` | progress, then the full report |
324
+
325
+ No tool takes a command — your test command comes from your config, which you wrote — and there is no login tool.
326
+
327
+ The rules the agent must follow are also in `ia-qa-pal --help`:
328
+
329
+ - **Read "Not seen".** A clean tour over part of an app is not a clean app, and the agent must say which part was not seen.
330
+ - **A first tour is not a pass.** It established the baseline.
331
+ - **Never answer a setup question for you, and never run `ia-qa-heal login`.** That command waits for a person at a browser; the agent gives it to you instead.
332
+ - **Never apply a proposed repair without your review, and never add `--suite` without asking** — it runs your suite on your machine.
333
+
334
+ Asked to tour a project that is not set up, `ia-qa-pal tour --json` answers with what is missing rather than guessing:
335
+
336
+ ```json
337
+ {
338
+ "refused": "This project is not set up yet — there is no .ia-qa/config.json.",
339
+ "setupRequired": {
340
+ "missing": ["url", "login"],
341
+ "command": "ia-qa-pal setup --url https://your-app.example --login none --yes"
342
+ },
343
+ "exitCode": 2
344
+ }
345
+ ```
346
+
347
+ ---
348
+
349
+ ## 11. What it touches
350
+
351
+ - **Only your app.** Its pages load whatever they load in any browser (fonts, analytics…).
352
+ - **Exploration is read-only.** While menus, tabs and dialogs are opened, every non-GET request is blocked, and controls named like actions (log out, delete, pay, send…) are never clicked.
353
+ - **The link check** requests your app's own links with GET and skips any URL that acts.
354
+ - **Your test files are read, never written.** Your test command runs only with `--suite`.
355
+ - **Files** live in `.ia-qa/`: `config.json`, `mapping/` (today), `baseline/` (the reference), `usage.json` (your suite's locators), `pal/state.json` (the measured pace, the findings already reported, the last `--suite` run), `pal/run.json` and `pal/run.log` (the current or last tour).
356
+
357
+ ---
358
+
359
+ ## 12. When something looks wrong
360
+
361
+ **A page is "not mapped" with a timeout.** One slow page costs that page, not the tour. It stays in **Not seen**; if its drift is shown, the report marks it as an older capture.
362
+
363
+ **Every page behind the login is "not mapped".** The session expired, or never worked. Log in again with `ia-qa-heal login`, then run the tour.
364
+
365
+ **`renamed` on a label you did not touch.** A counter, a date or generated content. Add a `nameMask` for it (section 4).
366
+
367
+ **"only partly explored (click budget reached)".** The page has more closed controls than one exploration opens (150 clicks). Its contract covers part of the page, and the report says so.
368
+
369
+ **"A tour is already running" but nothing is.** Run `ia-qa-pal status`: a tour whose process died shows as interrupted, and the next tour starts normally.
370
+
371
+ **"your suite ran but recorded no page".** Your specs do not import the capture hook (section 7).
372
+
373
+ ---
374
+
375
+ `ia-qa-pal` is built on [`@ia-qa/self-healing`](https://www.npmjs.com/package/@ia-qa/self-healing): the verdicts it prints are the ones `ia-qa-heal diff` and `ia-qa-heal check` compute, so the two never disagree.