@molecule/api-ai-tools 1.9.18 → 1.9.19

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.
@@ -197,6 +197,11 @@ function messageOf(value) {
197
197
  return null
198
198
  }
199
199
 
200
+ // A fill/type/selectOption records what the test typed; the note compares it with the body the
201
+ // page submitted (m173: the Settings form sent bio:"" although the test had just typed a value).
202
+ // Only those actions keep it, so a click's selector does not ride every row.
203
+ const FILLING_ACTION = /\\.(?:fill|type|pressSequentially|selectOption)$/
204
+
200
205
  // The text a failing assertion waited for, named by its own error: a \`has-text(…)\` CSS
201
206
  // pseudo-class, a \`getByText(…)\` locator, or a \`toContainText(…)\` expectation. A strict-mode
202
207
  // violation is not this shape — two elements DID match the text — and neither is a wait on a
@@ -446,14 +451,19 @@ for (const one of found.slice(0, MAX_TRACES)) {
446
451
  if (!entry || entry.type !== 'before') continue
447
452
  if (typeof entry.class !== 'string' || typeof entry.method !== 'string') continue
448
453
  if (entry.class === 'Test' || typeof entry.startTime !== 'number') continue
454
+ const api = entry.class + '.' + entry.method
455
+ const params = entry.params && typeof entry.params === 'object' ? entry.params : {}
456
+ const filling = FILLING_ACTION.test(api)
449
457
  const action = {
450
- api: entry.class + '.' + entry.method,
458
+ api: api,
451
459
  start: entry.startTime,
452
460
  end: typeof ended[entry.callId] === 'number' ? ended[entry.callId] : null,
453
461
  context: ctx.id,
454
462
  pageId: typeof entry.callId === 'string' ? pageByCall[entry.callId] : undefined,
455
463
  frameId: undefined,
456
464
  stepId: typeof entry.stepId === 'string' ? entry.stepId : undefined,
465
+ ...(filling && typeof params.selector === 'string' ? { selector: params.selector } : {}),
466
+ ...(filling && typeof params.value === 'string' ? { value: params.value } : {}),
457
467
  }
458
468
  if (action.pageId !== undefined) {
459
469
  for (const frame of ctx.frames) {
@@ -1054,6 +1064,8 @@ export function parseTraceArtifacts(stdout) {
1054
1064
  ...(typeof a.context === 'string' ? { context: a.context } : {}),
1055
1065
  ...(typeof a.pageId === 'string' ? { pageId: a.pageId } : {}),
1056
1066
  ...(typeof a.frameId === 'string' ? { frameId: a.frameId } : {}),
1067
+ ...(typeof a.selector === 'string' && a.selector ? { selector: a.selector } : {}),
1068
+ ...(typeof a.value === 'string' ? { value: a.value } : {}),
1057
1069
  })),
1058
1070
  ...(otherContexts.length === 0 ? {} : { otherContexts }),
1059
1071
  ...(raw.unattributed === true ? { unattributed: true } : {}),
@@ -1589,6 +1601,33 @@ function credentialExchangeBody(sent) {
1589
1601
  return false;
1590
1602
  return (CREDENTIAL_IDENTITY.test(text) || /"(?:credentials|grant_type|refresh_token)"\s*:/i.test(text));
1591
1603
  }
1604
+ /**
1605
+ * Whether a request PATH asks the app to mint a credential — a login, a registration, a token
1606
+ * endpoint — as opposed to a protected resource that presents one.
1607
+ *
1608
+ * This is the path half of {@link isCredentialExchange}, exported so a caller holding only a
1609
+ * `METHOD path` reads the same classification: a Hurl failing entry says
1610
+ * `POST /api/users/login` and nothing about the body, and the whole-suite note must not explain
1611
+ * a wrong-password login that answered 200 as a cookie-jar effect (xr-molecule-flash-m176).
1612
+ *
1613
+ * @param path - The request path (`/api/users/login`); a query or fragment is ignored.
1614
+ * @param authEndpoints - The endpoints the app's auth config names (`/users/login`).
1615
+ * @returns True when the path names a credential exchange.
1616
+ */
1617
+ export function isCredentialExchangePath(path, authEndpoints = []) {
1618
+ const clean = (path.split(/[?#]/)[0] ?? '').replace(/\/+$/, '');
1619
+ if (clean === '')
1620
+ return false;
1621
+ // The app's own config names it: matched as a path suffix, because an auth config writes the
1622
+ // endpoint relative to its API base (`/users/login`) while the trace records the mounted path
1623
+ // (`/api/users/login`).
1624
+ if (authEndpoints.some((endpoint) => {
1625
+ const named = `/${String(endpoint).replace(/^\/+|\/+$/g, '')}`;
1626
+ return named.length > 1 && (clean === named || clean.endsWith(named));
1627
+ }))
1628
+ return true;
1629
+ return CREDENTIAL_EXCHANGE_PATH.test(clean);
1630
+ }
1592
1631
  /**
1593
1632
  * Whether a refused request is a CREDENTIAL EXCHANGE: the app was asked to mint a token (a login,
1594
1633
  * a registration, a token endpoint), so it never needed one attached.
@@ -1613,15 +1652,7 @@ function isCredentialExchange(request, authEndpoints) {
1613
1652
  const path = sameOriginPath(request);
1614
1653
  if (path === null)
1615
1654
  return false;
1616
- // The app's own config names it: matched as a path suffix, because an auth config writes the
1617
- // endpoint relative to its API base (`/users/login`) while the trace records the mounted path
1618
- // (`/api/users/login`).
1619
- if (authEndpoints.some((endpoint) => {
1620
- const named = `/${String(endpoint).replace(/^\/+|\/+$/g, '')}`;
1621
- return named.length > 1 && (path === named || path.endsWith(named));
1622
- }))
1623
- return true;
1624
- if (CREDENTIAL_EXCHANGE_PATH.test(path))
1655
+ if (isCredentialExchangePath(path, authEndpoints))
1625
1656
  return true;
1626
1657
  return credentialExchangeBody(request.sent);
1627
1658
  }
@@ -2003,6 +2034,131 @@ function missingTextSentence(missing) {
2003
2034
  `not render it — the page drops it before rendering (a slice/filter/limit in the component ` +
2004
2035
  `that renders that list); find where that response is mapped.`);
2005
2036
  }
2037
+ /**
2038
+ * The `name` attribute a locator's selector reads (`textarea[name="bio"]` → `bio`), or null when
2039
+ * the selector names no field.
2040
+ *
2041
+ * Matching the form field to the request body's key is the whole point: a body that carries
2042
+ * `"bio": ""` says nothing unless the trace also says the test typed a bio.
2043
+ *
2044
+ * @param selector - The selector a `fill`/`type`/`selectOption` action carried.
2045
+ * @returns The field name, or null.
2046
+ */
2047
+ function fieldNameOf(selector) {
2048
+ const quoted = /\[\s*name\s*=\s*(["'])((?:(?!\1).)*)\1\s*\]/.exec(selector);
2049
+ if (quoted !== null)
2050
+ return quoted[2] === '' ? null : quoted[2];
2051
+ const bare = /\[\s*name\s*=\s*([^\s\]]+)\s*\]/.exec(selector);
2052
+ return bare === null ? null : (bare[1] ?? null);
2053
+ }
2054
+ /**
2055
+ * Whether a JSON request body carries `key` with an EMPTY value (`""` or null), looking inside the
2056
+ * wrapper object an API nests its entity under (`user`, `data`, `props`).
2057
+ *
2058
+ * A body that does not parse, or carries the key with a real value, is not evidence: the note only
2059
+ * claims the page sent a field empty when it did.
2060
+ *
2061
+ * @param sent - The body the page sent, as the trace recorded it.
2062
+ * @param key - The field name from the filled input's `name` attribute.
2063
+ * @returns True when the body carries that key empty.
2064
+ */
2065
+ function bodyCarriesEmptyField(sent, key) {
2066
+ let parsed;
2067
+ try {
2068
+ parsed = JSON.parse(sent);
2069
+ }
2070
+ catch (_error) {
2071
+ // A truncated body (the trace read bounds what it keeps) names no field confidently.
2072
+ return false;
2073
+ }
2074
+ const read = (value, level) => {
2075
+ if (level > 4 || value === null || typeof value !== 'object')
2076
+ return null;
2077
+ if (Array.isArray(value)) {
2078
+ for (const item of value) {
2079
+ const found = read(item, level + 1);
2080
+ if (found !== null)
2081
+ return found;
2082
+ }
2083
+ return null;
2084
+ }
2085
+ const record = value;
2086
+ if (Object.prototype.hasOwnProperty.call(record, key)) {
2087
+ return record[key] === '' || record[key] === null;
2088
+ }
2089
+ for (const nested of Object.values(record)) {
2090
+ const found = read(nested, level + 1);
2091
+ if (found !== null)
2092
+ return found;
2093
+ }
2094
+ return null;
2095
+ };
2096
+ return read(parsed, 0) === true;
2097
+ }
2098
+ /**
2099
+ * The field a test typed into that the same page submitted empty, when the trace recorded both.
2100
+ *
2101
+ * This is the Settings race of xr-molecule-flash-m173: `page.fill('textarea[name="bio"]', newBio)`
2102
+ * then `button[type=submit]`, and the `PUT /api/user` carried `"bio": ""`. The form's seeding
2103
+ * effect re-ran between the fill and the submit — on the deployed URL the background session
2104
+ * verification lands later than it does locally, and it handed the form a new user object. The
2105
+ * reading only pairs facts the trace holds: the filled value (its `selector`/`value`), the field
2106
+ * name the selector names, and the next call to the app's API on that page whose body carries
2107
+ * that key empty.
2108
+ *
2109
+ * @param item - One traced failure.
2110
+ * @returns The evidence, or null when no filled field was submitted empty.
2111
+ */
2112
+ function formResetOf(item) {
2113
+ const requests = [...(item.lastAction?.requests ?? []), ...item.requests];
2114
+ // A trace read before `actions` existed (or a hand-built one) carries none: no claim.
2115
+ for (const action of item.actions ?? []) {
2116
+ if (action.selector === undefined || action.value === undefined || action.value === '')
2117
+ continue;
2118
+ const field = fieldNameOf(action.selector);
2119
+ if (field === null)
2120
+ continue;
2121
+ let next = null;
2122
+ for (const request of requests) {
2123
+ if (!/^(?:POST|PUT|PATCH)$/.test(request.method) || request.sent === undefined)
2124
+ continue;
2125
+ // The submit follows the typing; a request that started before it cannot have sent it.
2126
+ if (typeof request.startedAt === 'number' && request.startedAt < action.start)
2127
+ continue;
2128
+ // Same page only: another context's set-up call is not this form's submit.
2129
+ if (action.pageId !== undefined &&
2130
+ request.pageId !== undefined &&
2131
+ action.pageId !== request.pageId)
2132
+ continue;
2133
+ if (!bodyCarriesEmptyField(request.sent, field))
2134
+ continue;
2135
+ const earlier = next === null ||
2136
+ (typeof request.startedAt === 'number' &&
2137
+ (typeof next.startedAt !== 'number' || request.startedAt < next.startedAt));
2138
+ if (earlier)
2139
+ next = request;
2140
+ }
2141
+ if (next !== null)
2142
+ return { value: action.value, selector: action.selector, field, request: next };
2143
+ }
2144
+ return null;
2145
+ }
2146
+ /**
2147
+ * The sentence for a submitted form field the test had just typed into, sent empty.
2148
+ *
2149
+ * It states the two recorded facts and the one inference they support — the form re-seeded after
2150
+ * the typing — then the fix at the source: copy the loaded data into the form once, on its first
2151
+ * load, instead of on every change of the data it was seeded from.
2152
+ *
2153
+ * @param reset - The filled field and the submit that carried it empty.
2154
+ * @returns The sentence the note leads with.
2155
+ */
2156
+ function formResetSentence(reset) {
2157
+ return (`The test typed "${reset.value}" into ${reset.selector}, but ` +
2158
+ `${requestLabel(reset.request)} sent "${reset.field}": "" — the form's state was reset after ` +
2159
+ `typing (an effect re-seeding the form from data that changed identity ran again after the ` +
2160
+ `test typed). Seed the form once, not every time that data changes.`);
2161
+ }
2006
2162
  /**
2007
2163
  * The note a failed suite run's result carries: what each failing test's page actually sent, and
2008
2164
  * what came back.
@@ -2042,6 +2198,14 @@ function missingTextSentence(missing) {
2042
2198
  * context and the assertion's page cannot be identified, the note lists the requests and makes NO
2043
2199
  * causal claim — no "the test's last action", no "the page stayed at …" — instead of merging them.
2044
2200
  *
2201
+ * A field the test filled and the page submitted EMPTY ({@link formResetOf}) leads the note: the
2202
+ * trace holds both facts — the value typed into `textarea[name="bio"]` and the `PUT /api/user`
2203
+ * whose body carried `"bio": ""` — so the form's state was reset between the typing and the
2204
+ * submit. The note names the effect that re-seeds a form from data whose identity changed and the
2205
+ * fix at the source (seed the form once). xr-molecule-flash-m173 lost a deploy-and-walk cycle to
2206
+ * this on the deployed URL only, where the background session verification lands later than it
2207
+ * does locally.
2208
+ *
2045
2209
  * WHICH rows it spends is evidence, not artifact order (xr-molecule-flash-m112 +53:46): a row
2046
2210
  * needs a recorded response, a real failure or a console line ({@link traceRowEvidence}), rows are
2047
2211
  * deduplicated by the test's location, and they are ordered real failure → repeated from an
@@ -2402,7 +2566,19 @@ export function failureTraceNote(items, target, earlierFailures = [], apiPrefixe
2402
2566
  const missingTextLead = missingTexts.length === 0
2403
2567
  ? ''
2404
2568
  : `${missingTexts.slice(0, 2).map(missingTextSentence).join(' ')}\n\n`;
2405
- return (missingTextLead +
2569
+ // A field the test typed and the page submitted empty: the form re-seeded itself after the
2570
+ // typing (m173's Settings race — the deployed URL lands the background session verification
2571
+ // later than a local run, and its new user object re-ran the form's seeding effect between the
2572
+ // fill and the submit). It is a direct cause of the failing request, so it leads the note.
2573
+ const formResets = [
2574
+ ...new Map(traced
2575
+ .map(formResetOf)
2576
+ .filter((reset) => reset !== null)
2577
+ .map((reset) => [`${reset.request.method} ${reset.request.path}\u0000${reset.field}`, reset])).values(),
2578
+ ];
2579
+ const formResetLead = formResets.length === 0 ? '' : `${formResets.slice(0, 2).map(formResetSentence).join(' ')}\n\n`;
2580
+ return (formResetLead +
2581
+ missingTextLead +
2406
2582
  transportLead +
2407
2583
  setupOriginLead +
2408
2584
  stalledLead +
@@ -171,15 +171,19 @@ export declare const PLAYWRIGHT_FAILURES_INLINE_ENV = "PLAYWRIGHT_LIST_PRINT_FAI
171
171
  * is exactly when the executor reads the log, and without it a running log carries `✘` rows and
172
172
  * nothing else (xr-molecule-flash-m99 spent ~90 s on greps of one, then fixed what it guessed).
173
173
  *
174
- * Only the command's last step is touched, and only its reporter, and only when that step runs
175
- * something: `npx playwright test --list` takes two seconds and writes nothing per test, so
176
- * neither reporter nor `--retries=0` is added to it ({@link isPlaywrightRunCommand}).
174
+ * Only the step that runs the suite is touched, and only its reporter, and only when that step
175
+ * runs something: `npx playwright test --list` takes two seconds and writes nothing per test, so
176
+ * neither reporter nor `--retries=0` is added to it ({@link isPlaywrightRunCommand}). A trailing
177
+ * status step (`; echo EXIT $?`, `&& true`) is not the run and is skipped when the run step is
178
+ * found ({@link isStatusOnlyStep}); a run whose output is redirected to a file is still readable
179
+ * through that file, which the launch records as the task's own output.
177
180
  *
178
181
  * A command that starts the suite MORE THAN ONCE is not launched at all: every run it carries is
179
182
  * a whole walk of the same suite against the same app, and only the last step is rewritten, so the
180
183
  * earlier walks run unmeasured for nothing. X1 xr-molecule-flash-m157 (+14:02) chained two whole
181
184
  * walks of one 138-test suite with `;` — 4.5 minutes each — and the second measured nothing the
182
- * first had not. The platform already refuses a second CONCURRENT run against one app; this is the
185
+ * first had not. The platform refuses a second CONCURRENT run against one app and database by the
186
+ * ONE rule ({@link suiteRunInTheWay}) — for every pair, whatever uid a run mints — and this is the
183
187
  * same hazard inside one command ({@link suiteRunStatements}). `error` then carries the refusal,
184
188
  * naming each suite step and the ONE command to send instead (the last suite step, rewritten as
185
189
  * this function rewrites a run), and nothing is launched.
@@ -944,10 +948,21 @@ export interface UniversalCause {
944
948
  }
945
949
  /**
946
950
  * How many tests a run must have walked — with nothing passing since its first failure — before
947
- * "the page renders nothing" can be its one cause. A handful of failures is a handful of bugs;
948
- * a page that never painted fails every spec that reaches it, and m141's walk had 36 by +20:30.
949
- */
950
- export declare const EMPTY_PAGE_CAUSE_TESTS = 15;
951
+ * "the page renders nothing" can be its one cause.
952
+ *
953
+ * THREE, and the number is the cost of the alternative. The old floor of 15 was chosen when the
954
+ * reading was only offered at a completed run; once it STOPS the walk, every test waited for is
955
+ * a test whose result is thrown away, and a blank page costs its per-test budget each time
956
+ * (m177: 18 tests, ~4.2 minutes, on a page whose thrown error was visible in the first
957
+ * `pageerror`). Three is the smallest count that is not one page's own bug: the cause additionally
958
+ * needs three DISTINCT spec files (`UNIVERSAL_CAUSE_FILES`, or the files a narrowed run selected),
959
+ * each spec waiting for its OWN first element, and no test passing after the first failure. A page
960
+ * that renders misses elements, but three unrelated specs in three files failing at three
961
+ * different first locators with nothing passing in between is the page, not three bugs. At the
962
+ * suite's own 5 s action timeout that verdict lands ~20 s into the walk, so the early stop costs
963
+ * about one test's worth of time instead of fifteen.
964
+ */
965
+ export declare const EMPTY_PAGE_CAUSE_TESTS = 3;
951
966
  /**
952
967
  * How many tests a connection-class cause must cover before the run is stopped even when they
953
968
  * are all in one file — see {@link universalCause}.
@@ -1 +1 @@
1
- {"version":3,"file":"utilities.d.ts","sourceRoot":"","sources":["../src/utilities.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"utilities.d.ts","sourceRoot":"","sources":["../src/utilities.ts"],"names":[],"mappings":"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"}
package/dist/utilities.js CHANGED
@@ -350,6 +350,25 @@ const PRINTING_REPORTERS = new Set(['list', 'line', 'dot', 'basic', 'spec']);
350
350
  * edited `app/src` while the run was still walking — which voids the run.
351
351
  */
352
352
  export const PLAYWRIGHT_FAILURES_INLINE_ENV = 'PLAYWRIGHT_LIST_PRINT_FAILURES_INLINE';
353
+ /**
354
+ * Whether a command step only reports or discards the status of the steps before it: `echo EXIT
355
+ * $?`, `echo $?`, `printf …`, `true`, `exit 0`.
356
+ *
357
+ * The shape models and the platform's own re-run notes send routinely ends on one of these —
358
+ * `npx playwright test … > /tmp/pw.log 2>&1; echo EXIT $?` — and reading the split's last part as
359
+ * the run withheld the reporter, the inline-failure switch and `--retries=0` from every one of
360
+ * them: the log then carried `✘` rows and nothing else while the wait note promised each failure's
361
+ * error under them (xr-molecule-flash-m173 +17:07, +39:14). Whitespace and a group's closing
362
+ * punctuation are not part of the step; {@link streamingBackgroundCommand} strips those before
363
+ * asking, and strips them here too for the split it is given.
364
+ *
365
+ * @param step - One statement of the command, as the `&&`/`||`/`;` split left it.
366
+ * @returns True when the step runs nothing but a status report.
367
+ */
368
+ function isStatusOnlyStep(step) {
369
+ const text = step.replace(/[\s)}]+$/, '').trim();
370
+ return /^(?:echo|printf)\b/.test(text) || /^true$/.test(text) || /^exit(?:\s+\S+)?$/.test(text);
371
+ }
353
372
  /**
354
373
  * Rewrite a command about to run in the background so its log grows while it
355
374
  * runs. Two shapes left the log empty until exit, and an empty log is what
@@ -384,15 +403,19 @@ export const PLAYWRIGHT_FAILURES_INLINE_ENV = 'PLAYWRIGHT_LIST_PRINT_FAILURES_IN
384
403
  * is exactly when the executor reads the log, and without it a running log carries `✘` rows and
385
404
  * nothing else (xr-molecule-flash-m99 spent ~90 s on greps of one, then fixed what it guessed).
386
405
  *
387
- * Only the command's last step is touched, and only its reporter, and only when that step runs
388
- * something: `npx playwright test --list` takes two seconds and writes nothing per test, so
389
- * neither reporter nor `--retries=0` is added to it ({@link isPlaywrightRunCommand}).
406
+ * Only the step that runs the suite is touched, and only its reporter, and only when that step
407
+ * runs something: `npx playwright test --list` takes two seconds and writes nothing per test, so
408
+ * neither reporter nor `--retries=0` is added to it ({@link isPlaywrightRunCommand}). A trailing
409
+ * status step (`; echo EXIT $?`, `&& true`) is not the run and is skipped when the run step is
410
+ * found ({@link isStatusOnlyStep}); a run whose output is redirected to a file is still readable
411
+ * through that file, which the launch records as the task's own output.
390
412
  *
391
413
  * A command that starts the suite MORE THAN ONCE is not launched at all: every run it carries is
392
414
  * a whole walk of the same suite against the same app, and only the last step is rewritten, so the
393
415
  * earlier walks run unmeasured for nothing. X1 xr-molecule-flash-m157 (+14:02) chained two whole
394
416
  * walks of one 138-test suite with `;` — 4.5 minutes each — and the second measured nothing the
395
- * first had not. The platform already refuses a second CONCURRENT run against one app; this is the
417
+ * first had not. The platform refuses a second CONCURRENT run against one app and database by the
418
+ * ONE rule ({@link suiteRunInTheWay}) — for every pair, whatever uid a run mints — and this is the
396
419
  * same hazard inside one command ({@link suiteRunStatements}). `error` then carries the refusal,
397
420
  * naming each suite step and the ONE command to send instead (the last suite step, rewritten as
398
421
  * this function rewrites a run), and nothing is launched.
@@ -446,10 +469,15 @@ export function streamingBackgroundCommand(command, context) {
446
469
  }
447
470
  // The last step that RUNS something. A trailing group closer is punctuation, not a step: a
448
471
  // brace group writes it after a `;` (`{ …; }`), so reading the split's last part literally
449
- // made `}` the step and withheld every rewrite from a run inside a group.
472
+ // made `}` the step and withheld every rewrite from a run inside a group. A trailing status
473
+ // step is not the run either: `… > /tmp/pw.log 2>&1; echo EXIT $?` ends on the echo, and
474
+ // treating THAT as the run withheld the reporter, the inline-failure switch and `--retries=0`
475
+ // from the exact shape models and the platform's re-run notes send (xr-molecule-flash-m173
476
+ // +17:07, +39:14).
450
477
  const parts = out.split(/&&|\|\||;/);
451
478
  let stepIndex = parts.length - 1;
452
- while (stepIndex > 0 && /^[\s)}]*$/.test(parts[stepIndex] ?? ''))
479
+ while (stepIndex > 0 &&
480
+ (/^[\s)}]*$/.test(parts[stepIndex] ?? '') || isStatusOnlyStep(parts[stepIndex] ?? '')))
453
481
  stepIndex -= 1;
454
482
  const rawLastStep = parts[stepIndex] ?? '';
455
483
  // The step's own text, with the punctuation that closes the group it sits in taken off — the
@@ -459,8 +487,9 @@ export function streamingBackgroundCommand(command, context) {
459
487
  // A command that starts the suite more than once is not launched: each statement is a whole walk
460
488
  // of the same suite against the same app, only the last of them is rewritten, and the earlier
461
489
  // ones measure nothing the first did. X1 xr-molecule-flash-m157 (+14:02) chained two whole walks
462
- // of one 138-test suite with `;` (4.5 minutes each); the platform already refuses a second
463
- // CONCURRENT run against one app, and this is the same hazard inside one command. The reading is
490
+ // of one 138-test suite with `;` (4.5 minutes each); the platform refuses a second CONCURRENT
491
+ // run against one app and database by the ONE rule ({@link suiteRunInTheWay}) — for every pair,
492
+ // whatever uid a run mints — and this is the same hazard inside one command. The reading is
464
493
  // {@link repeatedSuiteRunError}'s, so a foreground `exec_command` refuses the same commands.
465
494
  const repeated = repeatedSuiteRunError(out);
466
495
  if (repeated)
@@ -469,9 +498,17 @@ export function streamingBackgroundCommand(command, context) {
469
498
  // "nothing is piped out of the last step" withheld the reporter, the inline-failure switch and
470
499
  // `--retries=0` from exactly the runs whose output was filtered (xr-molecule-flash-m101
471
500
  // +25:54); what the runner writes into its log does not depend on what reads the pipe. A
472
- // REDIRECT still sends the output somewhere this tool cannot read it (`> out.txt`); `2>&1` only
473
- // joins stderr to it.
474
- const finalPlaywrightRun = isPlaywrightRunCommand(lastStep) && !/>/.test(lastStep.replace(/\d?>&\d/g, ''));
501
+ // REDIRECT used to withhold them too (`> out.txt`), but a redirect to a FILE is readable: the
502
+ // launch records that file as the task's own output (`outputFileByTask`, resolved from this
503
+ // same reader) and every wait reads it back. `> /tmp/pw-full.log 2>&1; echo EXIT $?` is the
504
+ // shape models and the platform's re-run notes send, so a run whose own redirect target is the
505
+ // one the launch will read is a readable run (xr-molecule-flash-m173 +17:07, +39:14). A target
506
+ // that is not a file (`/dev/null`, `2>&1`) still leaves the output unreadable.
507
+ const runRedirect = outputRedirectTarget(lastStep);
508
+ const finalPlaywrightRun = isPlaywrightRunCommand(lastStep) &&
509
+ (runRedirect === null
510
+ ? !/>/.test(lastStep.replace(/\d?>&\d/g, ''))
511
+ : runRedirect === outputRedirectTarget(out));
475
512
  /**
476
513
  * Add a word to the suite runner's own arguments; false when the runner could not be placed.
477
514
  *
@@ -483,14 +520,17 @@ export function streamingBackgroundCommand(command, context) {
483
520
  * platform's runner shape (xr-molecule-flash-m129 +34:29); appending after a pipe hands the
484
521
  * word to the filter (m102's dangling `--trace` flag, in the same shape).
485
522
  *
486
- * A suite the parse could not place — one inside a nested `sh -c '<command>'` string, whose
487
- * offsets are positions in THAT string, or a runner that is not the command's last step — is
488
- * left exactly as written and the caller reports no rewrite. There is nowhere in this command
489
- * the word belongs, and guessing at the text is what produced both failures above.
523
+ * The suite's own segment is found wherever it sits ({@link lastSuiteRun}), because a trailing
524
+ * status step is not another command's output: in `… > /tmp/pw.log 2>&1; echo EXIT $?` the run
525
+ * is what the launcher measures, and the echo only repeats its status
526
+ * ({@link isStatusOnlyStep}). A suite the parse could not place — one inside a nested
527
+ * `sh -c '<command>'` string, whose offsets are positions in THAT string — is left exactly as
528
+ * written and the caller reports no rewrite. There is nowhere in this command the word
529
+ * belongs, and guessing at the text is what produced both failures above.
490
530
  */
491
531
  const addToRun = (flag) => {
492
- const pipeline = lastSuitePipeline(out);
493
- const runner = pipeline ? pipeline.located[pipeline.at] : undefined;
532
+ const run = lastSuiteRun(out);
533
+ const runner = run ? run.located[run.at] : undefined;
494
534
  if (!runner)
495
535
  return false;
496
536
  const at = statementArgumentEnd(out, runner.start, runner.end);
@@ -2344,10 +2384,21 @@ function failureBlockTests(text) {
2344
2384
  export const UNIVERSAL_CAUSE_FILES = 3;
2345
2385
  /**
2346
2386
  * How many tests a run must have walked — with nothing passing since its first failure — before
2347
- * "the page renders nothing" can be its one cause. A handful of failures is a handful of bugs;
2348
- * a page that never painted fails every spec that reaches it, and m141's walk had 36 by +20:30.
2349
- */
2350
- export const EMPTY_PAGE_CAUSE_TESTS = 15;
2387
+ * "the page renders nothing" can be its one cause.
2388
+ *
2389
+ * THREE, and the number is the cost of the alternative. The old floor of 15 was chosen when the
2390
+ * reading was only offered at a completed run; once it STOPS the walk, every test waited for is
2391
+ * a test whose result is thrown away, and a blank page costs its per-test budget each time
2392
+ * (m177: 18 tests, ~4.2 minutes, on a page whose thrown error was visible in the first
2393
+ * `pageerror`). Three is the smallest count that is not one page's own bug: the cause additionally
2394
+ * needs three DISTINCT spec files (`UNIVERSAL_CAUSE_FILES`, or the files a narrowed run selected),
2395
+ * each spec waiting for its OWN first element, and no test passing after the first failure. A page
2396
+ * that renders misses elements, but three unrelated specs in three files failing at three
2397
+ * different first locators with nothing passing in between is the page, not three bugs. At the
2398
+ * suite's own 5 s action timeout that verdict lands ~20 s into the walk, so the early stop costs
2399
+ * about one test's worth of time instead of fifteen.
2400
+ */
2401
+ export const EMPTY_PAGE_CAUSE_TESTS = 3;
2351
2402
  /**
2352
2403
  * A failure body whose whole complaint is a wait for an element the page never rendered:
2353
2404
  * Playwright's `waiting for locator(…)` call log, its `element(s) not found` line, or the
@@ -2371,22 +2422,32 @@ function pageErrorInLog(text) {
2371
2422
  return m?.[1]?.trim() || null;
2372
2423
  }
2373
2424
  /**
2374
- * The "nothing has passed and nothing renders" cause: every failure block the log has written is
2375
- * a locator wait, the run has walked at least {@link EMPTY_PAGE_CAUSE_TESTS} tests across the
2376
- * file threshold, and no test has passed since the first failure.
2425
+ * The "nothing has passed and nothing renders" cause: the run's FIRST consecutive failures — from
2426
+ * its first failed test, with no pass since — are all locator waits, at least
2427
+ * {@link EMPTY_PAGE_CAUSE_TESTS} of them across {@link UNIVERSAL_CAUSE_FILES} different spec
2428
+ * files, and each waits for its own spec's first element.
2429
+ *
2430
+ * The file span stays at {@link UNIVERSAL_CAUSE_FILES} whatever the run selected: "the page
2431
+ * renders nothing" is a claim about the APP, and one file's failures can be that file's own setup
2432
+ * (a broken login helper fails every test of one spec at its first locator). A run narrowed to one
2433
+ * or two files still has the signature and connection causes for a whole-run stop.
2434
+ *
2435
+ * Stops the walk as soon as that verdict is readable, not after a fixed floor of failures have
2436
+ * been burned: the page error arrives with the first test, so every further test only repeats it.
2377
2437
  *
2378
2438
  * This is ONE cause even though the signatures differ — each spec asks for its own first element
2379
2439
  * (`input[name="username"]`, `a.navbar-brand`, `h1`), so {@link repeatingFailure} cannot group
2380
2440
  * them and {@link universalCause}'s signature test cannot see the run is over. xr-molecule-flash-
2381
2441
  * m141 (+20:30) walked a built app that rendered nothing: 36 tests had failed, every one at its
2382
- * first locator, and the note told the run to keep walking for another ~9 minutes.
2442
+ * first locator, and the note told the run to keep walking for another ~9 minutes. xr-molecule-
2443
+ * flash-m177 (+08:38 → +12:52) repeated it: 18 tests, one whole walk, on a page whose
2444
+ * `PAGEERROR No 'auth-client' provider bonded` was in the log from the first one.
2383
2445
  *
2384
2446
  * @param text - The log (ANSI already stripped).
2385
- * @param threshold - The spec-file threshold this run is judged against ({@link universalCause}).
2386
2447
  * @param found - The repeating cause {@link repeatingFailure} found, when it found one.
2387
2448
  * @returns The cause, or null when the log is not this shape.
2388
2449
  */
2389
- function emptyPageCause(text, threshold, found) {
2450
+ function emptyPageCause(text, found) {
2390
2451
  const marks = resultMarks(text);
2391
2452
  const firstFailure = marks.indexOf('✘');
2392
2453
  if (firstFailure === -1 || marks.slice(firstFailure).includes('✓'))
@@ -2404,10 +2465,15 @@ function emptyPageCause(text, threshold, found) {
2404
2465
  // (which names the repeated error) says more than "the page renders nothing" would.
2405
2466
  if (found !== null && found.message !== null && found.count >= tests.length)
2406
2467
  return null;
2468
+ // The cause is the FIRST consecutive failures: `tests` starts at the first ✘ and no ✓ follows
2469
+ // it, so a page that has failed three tests in a row across three files has already said
2470
+ // everything the rest of the walk can say (m177 paid 4.2 minutes learning that).
2407
2471
  if (tests.length < EMPTY_PAGE_CAUSE_TESTS)
2408
2472
  return null;
2409
2473
  const files = [...new Set(tests.map((t) => specFile(t.where)).filter(Boolean))];
2410
- if (files.length < threshold)
2474
+ // The blank-page claim is cross-file by construction (see the doc): a selected-file count
2475
+ // below the span does not shrink it, it removes the claim.
2476
+ if (files.length < UNIVERSAL_CAUSE_FILES)
2411
2477
  return null;
2412
2478
  const pageError = pageErrorInLog(text);
2413
2479
  return {
@@ -2544,7 +2610,7 @@ export function universalCause(log, found, command) {
2544
2610
  const threshold = selected === null ? UNIVERSAL_CAUSE_FILES : Math.min(UNIVERSAL_CAUSE_FILES, selected);
2545
2611
  // Nothing has passed and nothing renders: EVERY spec so far is waiting for its own first
2546
2612
  // element, so the signatures differ while the cause does not (xr-molecule-flash-m141).
2547
- const emptyPage = emptyPageCause(text, threshold, found);
2613
+ const emptyPage = emptyPageCause(text, found);
2548
2614
  if (emptyPage)
2549
2615
  return emptyPage;
2550
2616
  if (!found)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@molecule/api-ai-tools",
3
- "version": "1.9.18",
3
+ "version": "1.9.19",
4
4
  "description": "Shared AI agent tools with backend abstraction for sandbox and local execution",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",