@validate.qa/runner 1.0.58 → 1.0.60

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.
Files changed (3) hide show
  1. package/dist/cli.js +219 -34
  2. package/dist/cli.mjs +219 -34
  3. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -72841,18 +72841,15 @@ var require_verification_inbox = __commonJS({
72841
72841
  return { code: cleaned, confidence: "keyword" };
72842
72842
  }
72843
72843
  }
72844
- const distinct = /* @__PURE__ */ new Set();
72845
72844
  for (const body of bodies) {
72846
72845
  if (!body)
72847
72846
  continue;
72848
72847
  for (const n of body.match(/\b[0-9]{4,8}\b/g) ?? []) {
72849
- if (!looksLikeYearOrDate(n))
72850
- distinct.add(n);
72848
+ if (looksLikeYearOrDate(n))
72849
+ continue;
72850
+ return { code: n, confidence: "fallback" };
72851
72851
  }
72852
72852
  }
72853
- if (distinct.size === 1) {
72854
- return { code: distinct.values().next().value ?? null, confidence: "fallback" };
72855
- }
72856
72853
  return { code: null, confidence: null };
72857
72854
  }
72858
72855
  function matchBestCode(line) {
@@ -73150,9 +73147,10 @@ var require_verification_inbox = __commonJS({
73150
73147
  const satisfies = (m) => {
73151
73148
  if (opts.require === "code")
73152
73149
  return m.code !== null && m.codeConfidence !== "fallback";
73150
+ const linkOk = (l) => l !== null && (!opts.linkAcceptable || opts.linkAcceptable(l));
73153
73151
  if (opts.require === "link")
73154
- return m.link !== null;
73155
- return m.hasVerificationSignal;
73152
+ return linkOk(m.link);
73153
+ return m.code !== null && m.codeConfidence !== "fallback" || linkOk(m.link);
73156
73154
  };
73157
73155
  let weakest = null;
73158
73156
  const check2 = async () => {
@@ -73199,7 +73197,7 @@ var require_verification_inbox = __commonJS({
73199
73197
  const since = new Date(Math.max(0, opts.sinceMs));
73200
73198
  const lock = await client.getMailboxLock(mailbox);
73201
73199
  const results = [];
73202
- const taggedRecipient = isPlusTagged(opts.toAddress);
73200
+ const demoteMismatch = isPlusTagged(opts.toAddress) && Boolean(opts.demoteFilterMismatch);
73203
73201
  try {
73204
73202
  try {
73205
73203
  await client.noop();
@@ -73245,7 +73243,7 @@ var require_verification_inbox = __commonJS({
73245
73243
  continue;
73246
73244
  const filterActive = Boolean(opts.fromMatch || opts.subjectMatch);
73247
73245
  const filterMatched = (!opts.fromMatch || matchField(parsed.from?.text, opts.fromMatch)) && (!opts.subjectMatch || matchField(parsed.subject, opts.subjectMatch));
73248
- if (filterActive && !filterMatched && !taggedRecipient) {
73246
+ if (filterActive && !filterMatched && !demoteMismatch) {
73249
73247
  if (opts.stats)
73250
73248
  opts.stats.filteredOut += 1;
73251
73249
  continue;
@@ -73344,6 +73342,58 @@ var require_verification_inbox = __commonJS({
73344
73342
  }
73345
73343
  });
73346
73344
 
73345
+ // ../runner-core/dist/services/brokered-inbox-reader.js
73346
+ var require_brokered_inbox_reader = __commonJS({
73347
+ "../runner-core/dist/services/brokered-inbox-reader.js"(exports2) {
73348
+ "use strict";
73349
+ Object.defineProperty(exports2, "__esModule", { value: true });
73350
+ exports2.BrokeredInboxReader = void 0;
73351
+ var BROKERED_WAIT_CHUNK_MS = 55e3;
73352
+ var BrokeredInboxReader = class {
73353
+ transport;
73354
+ constructor(transport) {
73355
+ this.transport = transport;
73356
+ }
73357
+ async getUidWatermark() {
73358
+ const value = await this.transport("getUidWatermark", {});
73359
+ const record = value ?? {};
73360
+ return {
73361
+ uid: typeof record.uid === "number" ? record.uid : 0,
73362
+ uidValidity: typeof record.uidValidity === "number" ? record.uidValidity : 0
73363
+ };
73364
+ }
73365
+ async search(opts) {
73366
+ const value = await this.transport("search", { opts });
73367
+ return Array.isArray(value) ? value : [];
73368
+ }
73369
+ async getLatest(opts) {
73370
+ const value = await this.transport("getLatest", { opts });
73371
+ return value ?? null;
73372
+ }
73373
+ async getById(uid, address, altAddress, freshness) {
73374
+ const value = await this.transport("getById", { uid, address, altAddress, freshness });
73375
+ return value ?? null;
73376
+ }
73377
+ async waitForMessage(opts) {
73378
+ const totalBudgetMs = Math.max(opts.maxWaitMs ?? 9e4, 1e3);
73379
+ const deadline = Date.now() + totalBudgetMs;
73380
+ for (; ; ) {
73381
+ const remaining = deadline - Date.now();
73382
+ if (remaining <= 0)
73383
+ return null;
73384
+ const chunkMs = Math.min(remaining, BROKERED_WAIT_CHUNK_MS);
73385
+ const value = await this.transport("waitForMessage", {
73386
+ opts: { ...opts, maxWaitMs: chunkMs }
73387
+ });
73388
+ if (value)
73389
+ return value;
73390
+ }
73391
+ }
73392
+ };
73393
+ exports2.BrokeredInboxReader = BrokeredInboxReader;
73394
+ }
73395
+ });
73396
+
73347
73397
  // ../runner-core/dist/services/inbox-tools.js
73348
73398
  var require_inbox_tools = __commonJS({
73349
73399
  "../runner-core/dist/services/inbox-tools.js"(exports2) {
@@ -73383,7 +73433,8 @@ var require_inbox_tools = __commonJS({
73383
73433
  // Captured at provision (needs a live reader); 0 = use the sinceMs floor.
73384
73434
  sinceUid: 0,
73385
73435
  sinceUidValidity: 0,
73386
- knownLinks: /* @__PURE__ */ new Set()
73436
+ knownLinks: /* @__PURE__ */ new Set(),
73437
+ demoteFilterMismatch: opts.demoteFilterMismatch ?? false
73387
73438
  };
73388
73439
  }
73389
73440
  exports2.PROVISION_IDENTITY_TOOL = {
@@ -73571,6 +73622,7 @@ var require_inbox_tools = __commonJS({
73571
73622
  sinceUidValidity: ctx.state.sinceUidValidity,
73572
73623
  fromMatch: asStr(args.senderMatch),
73573
73624
  subjectMatch: asStr(args.subjectMatch),
73625
+ demoteFilterMismatch: ctx.state.demoteFilterMismatch,
73574
73626
  limit: 10
73575
73627
  });
73576
73628
  return ok({
@@ -73595,6 +73647,7 @@ var require_inbox_tools = __commonJS({
73595
73647
  sinceUidValidity: ctx.state.sinceUidValidity,
73596
73648
  fromMatch: asStr(args.senderMatch),
73597
73649
  subjectMatch: asStr(args.subjectMatch),
73650
+ demoteFilterMismatch: ctx.state.demoteFilterMismatch,
73598
73651
  maxWaitMs: maxWaitSeconds * 1e3,
73599
73652
  stats
73600
73653
  });
@@ -73741,7 +73794,7 @@ var require_inbox_tools = __commonJS({
73741
73794
  const u = new URL(raw);
73742
73795
  if (u.protocol !== "http:" && u.protocol !== "https:")
73743
73796
  return false;
73744
- host = u.hostname.toLowerCase().replace(/^\[|\]$/g, "");
73797
+ host = u.hostname.toLowerCase().replace(/^\[|\]$/g, "").replace(/\.+$/, "");
73745
73798
  } catch {
73746
73799
  return false;
73747
73800
  }
@@ -73757,7 +73810,7 @@ var require_inbox_tools = __commonJS({
73757
73810
  const dotted = host.match(/(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/);
73758
73811
  if (dotted && !ipv4IsPublic(dotted[1]))
73759
73812
  return false;
73760
- const mapped = host.match(/^::ffff:([0-9a-f]{1,4}):([0-9a-f]{1,4})$/);
73813
+ const mapped = host.match(/^::(?:ffff:)?([0-9a-f]{1,4}):([0-9a-f]{1,4})$/);
73761
73814
  if (mapped) {
73762
73815
  const hi = parseInt(mapped[1], 16);
73763
73816
  const lo = parseInt(mapped[2], 16);
@@ -74050,6 +74103,7 @@ var require_mobile_explorer = __commonJS({
74050
74103
  var mobile_auth_coverage_js_1 = require_mobile_auth_coverage();
74051
74104
  var mobile_driver_errors_js_1 = require_mobile_driver_errors();
74052
74105
  var verification_inbox_js_1 = require_verification_inbox();
74106
+ var brokered_inbox_reader_js_1 = require_brokered_inbox_reader();
74053
74107
  var inbox_tools_js_1 = require_inbox_tools();
74054
74108
  var mobile_discovery_auth_js_1 = require_mobile_discovery_auth();
74055
74109
  var MAX_MOBILE_ITERATIONS_SURVEY = 40;
@@ -75371,6 +75425,23 @@ ${existingScreens.slice(0, 100).map((s) => `- ${s.screenId}${s.name ? ` "${s.nam
75371
75425
  log: (line) => log2(line)
75372
75426
  });
75373
75427
  log2("Verification inbox ENABLED for registration \u2014 monitored identity provisioned.");
75428
+ } else if (registerRequested && ctx.inboxBroker?.address && ctx.inboxBrokerRead) {
75429
+ inboxState = (0, inbox_tools_js_1.createInboxRunState)({ address: ctx.inboxBroker.address }, {
75430
+ tagSeed: targetAppId ?? ctx.projectId,
75431
+ projectScope: ctx.projectId
75432
+ });
75433
+ inboxReader = new brokered_inbox_reader_js_1.BrokeredInboxReader(ctx.inboxBrokerRead);
75434
+ await (0, inbox_tools_js_1.applyAndPersistInboxIdentity)({
75435
+ variableContext: ctx.variableContext,
75436
+ registration: {
75437
+ email: inboxState.email,
75438
+ legacyEmail: inboxState.legacyEmail,
75439
+ passwordKey: inboxState.passwordKey ?? "TEST_USER_PASSWORD"
75440
+ },
75441
+ persist: ctx.onCredentialUpdate,
75442
+ log: (line) => log2(line)
75443
+ });
75444
+ log2("Verification inbox ENABLED via server broker \u2014 monitored identity provisioned (IMAP credentials stay server-side).");
75374
75445
  } else if (registerRequested) {
75375
75446
  log2("Registration requested without a verification inbox \u2014 preserving the seeded credential identity and reporting any verification wall as unauthenticated.");
75376
75447
  }
@@ -84285,12 +84356,14 @@ ${args.directive}`);
84285
84356
  { role: "user", content: userContent }
84286
84357
  ];
84287
84358
  let content;
84359
+ let finishReason;
84288
84360
  try {
84289
84361
  const response = await (0, ai_retry_js_1.resilientAICall)((signal, arm) => (0, ai_queue_js_1.queuedAICall)(() => {
84290
84362
  arm();
84291
84363
  return aiClient.chat.completions.create({ model, messages, max_tokens: 8e3, temperature: 0.1 }, { signal });
84292
84364
  }), { label: `mobile-heal-attempt-${attempt}`, deferTimeoutUntilArmed: true });
84293
84365
  content = response?.choices?.[0]?.message?.content ?? "";
84366
+ finishReason = response?.choices?.[0]?.finish_reason ?? void 0;
84294
84367
  } catch {
84295
84368
  options.onProgress?.(`Phase 1 attempt ${attempt}: model call failed in transport \u2014 granting a recovery turn`);
84296
84369
  markRecoverableTurn();
@@ -84300,7 +84373,7 @@ ${args.directive}`);
84300
84373
  aiResponseCount += 1;
84301
84374
  const parsed = parseHealVerdict(content);
84302
84375
  if (!parsed) {
84303
- options.onProgress?.(`Phase 1 attempt ${attempt}: response was not a valid verdict \u2014 granting a recovery turn`);
84376
+ options.onProgress?.(`Phase 1 attempt ${attempt}: response was not a valid verdict (${content.length} chars, finish=${finishReason ?? "unknown"}) \u2014 granting a recovery turn`);
84304
84377
  markRecoverableTurn();
84305
84378
  pendingDirective = "Your last response was not valid JSON matching the verdict schema. Return exactly one JSON verdict object.";
84306
84379
  continue;
@@ -86418,6 +86491,8 @@ var require_inbox_stamp = __commonJS({
86418
86491
  exports2.INBOX_HELPER_TOKEN_RE = exports2.INBOX_HELPER_NAME = exports2.INBOX_REGION_RE = exports2.INBOX_MARKER_VERSION = void 0;
86419
86492
  exports2.codeUsesInboxHelper = codeUsesInboxHelper;
86420
86493
  exports2.stripInboxRegions = stripInboxRegions;
86494
+ exports2.codeUsesTestInboxIdentity = codeUsesTestInboxIdentity;
86495
+ exports2.codeSelfProvisionsRegistration = codeSelfProvisionsRegistration2;
86421
86496
  exports2.renderInboxFn = renderInboxFn;
86422
86497
  exports2.upsertInboxBlock = upsertInboxBlock;
86423
86498
  var auth_recipe_js_1 = require_auth_recipe();
@@ -86432,12 +86507,54 @@ var require_inbox_stamp = __commonJS({
86432
86507
  return false;
86433
86508
  return exports2.INBOX_HELPER_TOKEN_RE.test(code) || /VALIDATE_QA_INBOX/.test(code);
86434
86509
  }
86510
+ var INBOX_REGION_START = "// >>> VALIDATE_QA_INBOX";
86511
+ var INBOX_REGION_END = "// <<< VALIDATE_QA_INBOX";
86435
86512
  function stripInboxRegions(code) {
86436
- return code.replace(exports2.INBOX_REGION_RE, "");
86513
+ if (!code || code.indexOf(INBOX_REGION_START) === -1)
86514
+ return code;
86515
+ let out = "";
86516
+ let i = 0;
86517
+ while (i < code.length) {
86518
+ const start = code.indexOf(INBOX_REGION_START, i);
86519
+ if (start === -1) {
86520
+ out += code.slice(i);
86521
+ break;
86522
+ }
86523
+ const end = code.indexOf(INBOX_REGION_END, start + INBOX_REGION_START.length);
86524
+ if (end === -1) {
86525
+ out += code.slice(i);
86526
+ break;
86527
+ }
86528
+ let lineEnd = code.indexOf("\n", end);
86529
+ lineEnd = lineEnd === -1 ? code.length : lineEnd + 1;
86530
+ out += code.slice(i, start);
86531
+ i = lineEnd;
86532
+ }
86533
+ return out;
86534
+ }
86535
+ var TEST_INBOX_IDENTITY_RE = /VQA_TEST_INBOX_EMAIL|VQA_TEST_ACCOUNT_PASSWORD/;
86536
+ function codeUsesTestInboxIdentity(code) {
86537
+ if (!code)
86538
+ return false;
86539
+ return TEST_INBOX_IDENTITY_RE.test(stripInboxRegions(code));
86540
+ }
86541
+ function codeSelfProvisionsRegistration2(code) {
86542
+ return codeUsesTestInboxIdentity(code);
86437
86543
  }
86438
86544
  function countInboxRegions(code) {
86439
- const m = code.match(exports2.INBOX_REGION_RE);
86440
- return m ? m.length : 0;
86545
+ let count = 0;
86546
+ let i = 0;
86547
+ while (i < code.length) {
86548
+ const start = code.indexOf(INBOX_REGION_START, i);
86549
+ if (start === -1)
86550
+ break;
86551
+ const end = code.indexOf(INBOX_REGION_END, start + INBOX_REGION_START.length);
86552
+ if (end === -1)
86553
+ break;
86554
+ count++;
86555
+ i = end + INBOX_REGION_END.length;
86556
+ }
86557
+ return count;
86441
86558
  }
86442
86559
  function renderInboxFn() {
86443
86560
  const lines = [
@@ -86531,7 +86648,12 @@ var require_test_inbox_broker = __commonJS({
86531
86648
  return { found: true, code, link, subject: msg.subject, from: msg.from };
86532
86649
  }
86533
86650
  async function startTestInboxBroker(opts) {
86534
- const identity = mintTestRunInboxIdentity(opts.config, opts);
86651
+ const executionNonce = (0, node_crypto_1.randomBytes)(4).toString("hex");
86652
+ const identity = mintTestRunInboxIdentity(opts.config, {
86653
+ baseUrl: opts.baseUrl,
86654
+ projectId: opts.projectId,
86655
+ runId: `${opts.runId}#${executionNonce}`
86656
+ });
86535
86657
  const reader = new verification_inbox_js_1.VerificationInboxReader(opts.config);
86536
86658
  const sinceMs = Date.now();
86537
86659
  let sinceUid = 0;
@@ -86571,6 +86693,12 @@ var require_test_inbox_broker = __commonJS({
86571
86693
  sinceUidValidity,
86572
86694
  maxWaitMs: timeoutMs,
86573
86695
  require: require2,
86696
+ // The plus-tag recipient is unique to this run, so an unexpected ESP
86697
+ // sender is still this run's mail — demote, don't drop.
86698
+ demoteFilterMismatch: true,
86699
+ // Don't let a private/internal link end a `require:'link'` wait early —
86700
+ // keep polling for a public one (SSRF parity with the post-wait check).
86701
+ linkAcceptable: inbox_tools_js_1.isPublicHttpUrl,
86574
86702
  stats
86575
86703
  });
86576
86704
  const publicLink = msg && msg.link && (0, inbox_tools_js_1.isPublicHttpUrl)(msg.link) ? msg.link : null;
@@ -86705,7 +86833,8 @@ var require_playwright_native = __commonJS({
86705
86833
  runDir = (0, path_1.join)(RUNS_DIR, (0, crypto_1.randomUUID)());
86706
86834
  await (0, promises_1.mkdir)(runDir, { recursive: true });
86707
86835
  const isApiTest2 = playwrightCode.includes("@api") || playwrightCode.includes("{ request }") && !playwrightCode.includes("{ page");
86708
- const usesInboxHelper = !isApiTest2 && (0, inbox_stamp_js_1.codeUsesInboxHelper)(playwrightCode);
86836
+ const usesRealInboxWait = !isApiTest2 && (0, inbox_stamp_js_1.codeUsesInboxHelper)(playwrightCode);
86837
+ const selfProvisionsRegistration = !isApiTest2 && (0, inbox_stamp_js_1.codeSelfProvisionsRegistration)(playwrightCode);
86709
86838
  const effectiveStandingMode = isApiTest2 ? authStandingMode ?? "legacy-if-configured" : "none";
86710
86839
  const resolvedExtraHeaders = (0, api_auth_headers_js_1.resolveApiAuthHeaders)({
86711
86840
  explicit: extraHttpHeaders,
@@ -86952,7 +87081,7 @@ test.afterEach(async ({ page }, testInfo) => {
86952
87081
  module.exports = {
86953
87082
  testDir: ${JSON.stringify(absTestDir)},
86954
87083
  outputDir: ${JSON.stringify(absOutputDir)},
86955
- timeout: ${usesInboxHelper ? 24e4 : 6e4},
87084
+ timeout: ${usesRealInboxWait ? 24e4 : 6e4},
86956
87085
  retries: 0,
86957
87086
  use: {
86958
87087
  baseURL: ${JSON.stringify(baseUrl)},
@@ -86978,7 +87107,7 @@ module.exports = {
86978
87107
  const isolation = await (0, chromium_isolation_js_1.createChromiumIsolation)(runDir);
86979
87108
  const processClaimEpoch = Number(process.env.CLAIM_EPOCH);
86980
87109
  const callbackClaimEpoch = Number.isSafeInteger(validateContext?.claimEpoch) ? validateContext?.claimEpoch : Number.isSafeInteger(processClaimEpoch) && processClaimEpoch >= 0 ? processClaimEpoch : void 0;
86981
- if (usesInboxHelper && validateContext?.runId) {
87110
+ if (selfProvisionsRegistration && validateContext?.runId) {
86982
87111
  const inboxConfig = (0, verification_inbox_js_1.loadVerificationInboxConfig)();
86983
87112
  if (!inboxConfig) {
86984
87113
  logs2.push("\u{1F4EA} Test uses __vqaWaitForEmail but this runner has no verification inbox configured \u2014 the helper will fail as CONFIG_ISSUE");
@@ -86996,8 +87125,8 @@ module.exports = {
86996
87125
  logs2.push(`\u26A0 Inbox broker failed to start: ${error3 instanceof Error ? error3.message : String(error3)}`);
86997
87126
  }
86998
87127
  }
86999
- } else if (usesInboxHelper) {
87000
- logs2.push("\u{1F4EA} Test uses __vqaWaitForEmail but no run callback context is available \u2014 the helper will fail as CONFIG_ISSUE");
87128
+ } else if (selfProvisionsRegistration) {
87129
+ logs2.push("\u{1F4EA} Test self-provisions a registration identity (VQA_TEST_* / __vqaWaitForEmail) but no run callback context is available \u2014 the broker cannot start, so those values will be undefined at runtime");
87001
87130
  }
87002
87131
  if (validateContext?.runId && validateContext.serverUrl && validateContext.authHeader) {
87003
87132
  try {
@@ -87038,16 +87167,20 @@ module.exports = {
87038
87167
  ...process.env.SHARED_AUTH_INJECT ? { SHARED_AUTH_INJECT: process.env.SHARED_AUTH_INJECT } : {},
87039
87168
  // Register-and-verify tests: the run's minted registration identity. An
87040
87169
  // address + a DERIVED throwaway-app password — never the IMAP secret,
87041
- // which stays in this parent (test-inbox-broker.ts). Useless without the
87042
- // loopback proxy the helper reads mail through, hence the guard.
87043
- ...inboxBroker && callbackProxy ? inboxBroker.childEnv() : {}
87170
+ // which stays in this parent (test-inbox-broker.ts). Injected whenever the
87171
+ // broker started, NOT gated on the callback proxy: a signup that registers
87172
+ // with this identity but needs no email verification uses the env yet never
87173
+ // touches the proxy — gating on the proxy left it with undefined creds. A
87174
+ // helper test still needs the proxy, and simply fails as CONFIG_ISSUE
87175
+ // without it; leaking the throwaway address/password to that child is inert.
87176
+ ...inboxBroker ? inboxBroker.childEnv() : {}
87044
87177
  };
87045
87178
  delete childTestVariables.API_AUTH_HEADERS;
87046
87179
  logs2.push("\u{1F680} Spawning playwright test...");
87047
87180
  const stopLiveBrowserPolling = liveBrowserStatePath && liveBrowserHandle ? startLiveBrowserStatePolling(liveBrowserStatePath, liveBrowserHandle, onLiveBrowserSnapshot) : null;
87048
87181
  let playResult;
87049
87182
  try {
87050
- playResult = await runPlaywright(configPath, childTestVariables, trustedRuntimeEnv, usesInboxHelper ? 3e5 : void 0);
87183
+ playResult = await runPlaywright(configPath, childTestVariables, trustedRuntimeEnv, usesRealInboxWait ? 3e5 : void 0);
87051
87184
  } finally {
87052
87185
  await stopLiveBrowserPolling?.();
87053
87186
  }
@@ -94799,7 +94932,7 @@ var require_discover_generator = __commonJS({
94799
94932
  var test_inbox_broker_js_1 = require_test_inbox_broker();
94800
94933
  var REGISTER_SCENARIO_RE = /\b(register|registration|sign[\s-]?up|create[\s-]?(a[n]?[\s-]?)?(new[\s-]?)?account|verify[\s-]?(your[\s-]?)?email|email[\s-]?verification|confirm[\s-]?(your[\s-]?)?(email|account)|activate[\s-]?(your[\s-]?)?account|new[\s-]?account)\b/i;
94801
94934
  function scenarioLooksLikeRegistration(scenario) {
94802
- const hay = `${scenario.name ?? ""} ${scenario.description ?? ""} ${scenario.entryRoute ?? ""} ${(scenario.targetPages ?? []).join(" ")}`;
94935
+ const hay = `${scenario.name ?? ""} ${scenario.goal ?? ""} ${scenario.description ?? ""} ${scenario.entryRoute ?? ""} ${(scenario.targetPages ?? []).join(" ")}`;
94803
94936
  return REGISTER_SCENARIO_RE.test(hay);
94804
94937
  }
94805
94938
  function buildEmailVerifyGenBlock(genEmail, genPassword) {
@@ -97752,7 +97885,7 @@ ${tailBlock}`;
97752
97885
  const genEmail = (0, verification_inbox_js_1.applyPlusTag)(inboxGenConfig.address, genTag);
97753
97886
  const genPassword = (0, verification_inbox_js_1.deriveRegistrationPassword)(genEmail);
97754
97887
  genInboxReader = new verification_inbox_js_1.VerificationInboxReader(inboxGenConfig);
97755
- genInboxState = (0, inbox_tools_js_1.createInboxRunState)(inboxGenConfig, { tag: genTag, passwordKey: test_inbox_broker_js_1.TEST_INBOX_PASSWORD_ENV });
97888
+ genInboxState = (0, inbox_tools_js_1.createInboxRunState)(inboxGenConfig, { tag: genTag, passwordKey: test_inbox_broker_js_1.TEST_INBOX_PASSWORD_ENV, demoteFilterMismatch: true });
97756
97889
  genInboxCredentials = { ...credentials, [test_inbox_broker_js_1.TEST_INBOX_EMAIL_ENV]: genEmail, [test_inbox_broker_js_1.TEST_INBOX_PASSWORD_ENV]: genPassword };
97757
97890
  genInboxSecret = genPassword;
97758
97891
  openaiTools.push(...inbox_tools_js_1.INBOX_TOOLS);
@@ -98314,6 +98447,13 @@ Do NOT assert that the button/tab/heading you interacted with is merely visible
98314
98447
  logs2.push(` Strength gate: block persists after revision \u2014 tagged @needs-review (proves no outcome)`);
98315
98448
  }
98316
98449
  }
98450
+ const finalSelfProvisions = (0, inbox_stamp_js_1.codeSelfProvisionsRegistration)(result.playwrightCode);
98451
+ if (finalSelfProvisions) {
98452
+ if (!result.tags.includes("@email-verify"))
98453
+ result.tags.push("@email-verify");
98454
+ } else if (inboxGenConfig) {
98455
+ logs2.push(` \u26A0 Email-verify generation was armed but the emitted test neither calls __vqaWaitForEmail nor uses the VQA_TEST_* runtime identity \u2014 it may have hardcoded values (stale on re-run).`);
98456
+ }
98317
98457
  const elapsed = Date.now() - startTime;
98318
98458
  logs2.push(` Scenario test generated in ${iteration} iterations (${elapsed}ms, ${verifyCallCount} verify calls)`);
98319
98459
  } else {
@@ -349882,9 +350022,9 @@ var require_dist2 = __commonJS({
349882
350022
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p)) __createBinding(exports3, m, p);
349883
350023
  };
349884
350024
  Object.defineProperty(exports2, "__esModule", { value: true });
349885
- exports2.acquireRepoForImport = exports2.runFrameworkImportOnRunner = exports2.getAgenticEngine = exports2.resolveRefFromSnapshot = exports2.replayAuthRecipeIntoBrowser = exports2.runRegisterCaptureRun = exports2.runLoginCaptureRun = exports2.filterLoginCaptureCredentials = exports2.buildLoginCaptureCredentials = exports2.isReservedRunnerEnvVar = exports2.RESERVED_RUNNER_ENV_VARS = exports2.AUTH_MARKER_VERSION = exports2.buildHealAuthStamp = exports2.extractAuthRegion = exports2.upsertAuthBlock = exports2.buildAuthRecipe = exports2.commandToReplayStep = exports2.buildReplayPlan = exports2.absoluteRoute = exports2.renderReplaySettleArrow = exports2.renderReplayClickArrow = exports2.renderAuthFn = exports2.filterFeatureGroupsToPathScope = exports2.isAuthFlowRoute = exports2.deriveSurveyPathScope = exports2.canonicalizeRoute = exports2.executeGrokPerBatchHeal = exports2.executeGrokPerTestHeal = exports2.headerVal = exports2.classifyAuthType = exports2.isTextExcerptable = exports2.isStaticAssetByExt = exports2.isApiCall = exports2.buildApiCallSummary = exports2.computeMobileHealOutcome = exports2.detectMobileStepSecretLeak = exports2.redactMobileSecretsFromText = exports2.MOBILE_LIVE_HEAL_SYSTEM_PROMPT = exports2.MOBILE_SCRIPT_HEAL_SYSTEM_PROMPT = exports2.executeMobileLiveHeal = exports2.executeMobileTestWithHealing = exports2.executeMobileScriptDrivenHeal = exports2.prepareMobileScenarioAppState = exports2.runMobileGeneratePhase = exports2.runMobileAIPlanner = exports2.buildMobileSiteMap = exports2.formatMobileEvidenceForPlanner = exports2.MOBILE_SCENARIO_SYSTEM_PROMPT = exports2.MOBILE_SURVEY_SYSTEM_PROMPT = exports2.runMobileExplorePhase = void 0;
349886
- exports2.gracefulCloseWithTreeKill = exports2.liveBrowserRegistry = exports2.REPO_SWITCH_REMOVED_FRACTION = exports2.MAX_MANIFEST_FILES = exports2.toDiffSummary = exports2.isLikelyTestFile = exports2.sanitizeRepoRelPath = exports2.sha256Hex = exports2.hashFiles = exports2.enumerateTestFiles = exports2.buildNextManifest = exports2.detectRepoSwitch = exports2.classifyImportDiff = exports2.parseImportManifest = exports2.validateAuthoredMobileTest = exports2.buildMobileRepoAuthorSystemRules = exports2.buildMobileRepoAuthorKickoff = exports2.buildMobileRepoAuthorContractMd = exports2.REPO_ANALYSIS_SCHEMA_VERSION = exports2.validateSourceEndpoints = exports2.validateAuthoredTest = exports2.validateRepoMapFile = exports2.validateRepoMemoryFile = exports2.buildTestingStandardsSection = exports2.buildRepoAuthorSystemRules = exports2.buildRepoAuthorKickoff = exports2.buildRepoAuthorContractMd = exports2.buildRepoMapSystemRules = exports2.buildRepoMapKickoff = exports2.buildRepoMapContractMd = exports2.buildRepoMemorySystemRules = exports2.buildRepoMemoryKickoff = exports2.buildRepoMemoryContractMd = exports2.runRepoAnalysisOnRunner = exports2.MOBILE_IMPORT_SCHEMA_VERSION = exports2.validateImportedMobileTest = exports2.buildMobileImportSystemRules = exports2.buildMobileImportKickoff = exports2.buildMobileImportContractMd = exports2.IMPORT_SCHEMA_VERSION = exports2.validateImportResultFile = exports2.validateImportedTest = exports2.buildImportSystemRules = exports2.buildImportKickoff = exports2.buildImportContractMd = exports2.MAX_ARCHIVE_BYTES = exports2.isUnsafeEntryName = exports2.extractZipSafely = exports2.downloadArchiveCapped = exports2.detectArchiveKind = void 0;
349887
- exports2.UNSUPPORTED_RENDERER_PREFIX = exports2.UnsupportedRendererError = exports2.buildCanvasModeAuthoringAddendum = exports2.buildUnsupportedRendererMessage = exports2.modelSupportsVision = exports2.decideCanvasStrategy = exports2.decideAppRenderType = exports2.detectCanvasApp = exports2.detectRateLimitBlock = exports2.isSafeCanonicalRedirect = exports2.resolveBaseUrlPreflight = exports2.checkBaseUrlRedirect = exports2.stripJsonFences = exports2.scrubCredentials = exports2.withAIRetry = exports2.snapshotMatchingChildren = exports2.findNewChromiumChildPid = exports2.killProcessTree = void 0;
350025
+ exports2.resolveRefFromSnapshot = exports2.replayAuthRecipeIntoBrowser = exports2.runRegisterCaptureRun = exports2.runLoginCaptureRun = exports2.filterLoginCaptureCredentials = exports2.buildLoginCaptureCredentials = exports2.isReservedRunnerEnvVar = exports2.RESERVED_RUNNER_ENV_VARS = exports2.AUTH_MARKER_VERSION = exports2.buildHealAuthStamp = exports2.extractAuthRegion = exports2.upsertAuthBlock = exports2.buildAuthRecipe = exports2.commandToReplayStep = exports2.buildReplayPlan = exports2.absoluteRoute = exports2.renderReplaySettleArrow = exports2.renderReplayClickArrow = exports2.renderAuthFn = exports2.filterFeatureGroupsToPathScope = exports2.isAuthFlowRoute = exports2.deriveSurveyPathScope = exports2.canonicalizeRoute = exports2.codeUsesInboxHelper = exports2.codeUsesTestInboxIdentity = exports2.codeSelfProvisionsRegistration = exports2.executeGrokPerBatchHeal = exports2.executeGrokPerTestHeal = exports2.headerVal = exports2.classifyAuthType = exports2.isTextExcerptable = exports2.isStaticAssetByExt = exports2.isApiCall = exports2.buildApiCallSummary = exports2.computeMobileHealOutcome = exports2.detectMobileStepSecretLeak = exports2.redactMobileSecretsFromText = exports2.MOBILE_LIVE_HEAL_SYSTEM_PROMPT = exports2.MOBILE_SCRIPT_HEAL_SYSTEM_PROMPT = exports2.executeMobileLiveHeal = exports2.executeMobileTestWithHealing = exports2.executeMobileScriptDrivenHeal = exports2.prepareMobileScenarioAppState = exports2.runMobileGeneratePhase = exports2.runMobileAIPlanner = exports2.buildMobileSiteMap = exports2.formatMobileEvidenceForPlanner = exports2.MOBILE_SCENARIO_SYSTEM_PROMPT = exports2.MOBILE_SURVEY_SYSTEM_PROMPT = exports2.runMobileExplorePhase = void 0;
350026
+ exports2.MAX_MANIFEST_FILES = exports2.toDiffSummary = exports2.isLikelyTestFile = exports2.sanitizeRepoRelPath = exports2.sha256Hex = exports2.hashFiles = exports2.enumerateTestFiles = exports2.buildNextManifest = exports2.detectRepoSwitch = exports2.classifyImportDiff = exports2.parseImportManifest = exports2.validateAuthoredMobileTest = exports2.buildMobileRepoAuthorSystemRules = exports2.buildMobileRepoAuthorKickoff = exports2.buildMobileRepoAuthorContractMd = exports2.REPO_ANALYSIS_SCHEMA_VERSION = exports2.validateSourceEndpoints = exports2.validateAuthoredTest = exports2.validateRepoMapFile = exports2.validateRepoMemoryFile = exports2.buildTestingStandardsSection = exports2.buildRepoAuthorSystemRules = exports2.buildRepoAuthorKickoff = exports2.buildRepoAuthorContractMd = exports2.buildRepoMapSystemRules = exports2.buildRepoMapKickoff = exports2.buildRepoMapContractMd = exports2.buildRepoMemorySystemRules = exports2.buildRepoMemoryKickoff = exports2.buildRepoMemoryContractMd = exports2.runRepoAnalysisOnRunner = exports2.MOBILE_IMPORT_SCHEMA_VERSION = exports2.validateImportedMobileTest = exports2.buildMobileImportSystemRules = exports2.buildMobileImportKickoff = exports2.buildMobileImportContractMd = exports2.IMPORT_SCHEMA_VERSION = exports2.validateImportResultFile = exports2.validateImportedTest = exports2.buildImportSystemRules = exports2.buildImportKickoff = exports2.buildImportContractMd = exports2.MAX_ARCHIVE_BYTES = exports2.isUnsafeEntryName = exports2.extractZipSafely = exports2.downloadArchiveCapped = exports2.detectArchiveKind = exports2.acquireRepoForImport = exports2.runFrameworkImportOnRunner = exports2.getAgenticEngine = void 0;
350027
+ exports2.BrokeredInboxReader = exports2.applyPlusTag = exports2.deriveProjectInboxTag = exports2.deriveInboxTag = exports2.loadVerificationInboxConfig = exports2.VerificationInboxReader = exports2.UNSUPPORTED_RENDERER_PREFIX = exports2.UnsupportedRendererError = exports2.buildCanvasModeAuthoringAddendum = exports2.buildUnsupportedRendererMessage = exports2.modelSupportsVision = exports2.decideCanvasStrategy = exports2.decideAppRenderType = exports2.detectCanvasApp = exports2.detectRateLimitBlock = exports2.isSafeCanonicalRedirect = exports2.resolveBaseUrlPreflight = exports2.checkBaseUrlRedirect = exports2.stripJsonFences = exports2.scrubCredentials = exports2.withAIRetry = exports2.snapshotMatchingChildren = exports2.findNewChromiumChildPid = exports2.killProcessTree = exports2.gracefulCloseWithTreeKill = exports2.liveBrowserRegistry = exports2.REPO_SWITCH_REMOVED_FRACTION = void 0;
349888
350028
  __exportStar(require_ai_provider(), exports2);
349889
350029
  __exportStar(require_mobile_types(), exports2);
349890
350030
  __exportStar(require_mobile_source_parser(), exports2);
@@ -349975,6 +350115,16 @@ var require_dist2 = __commonJS({
349975
350115
  return grok_batch_healer_js_1.executeGrokPerBatchHeal;
349976
350116
  } });
349977
350117
  __exportStar(require_playwright_code(), exports2);
350118
+ var inbox_stamp_js_1 = require_inbox_stamp();
350119
+ Object.defineProperty(exports2, "codeSelfProvisionsRegistration", { enumerable: true, get: function() {
350120
+ return inbox_stamp_js_1.codeSelfProvisionsRegistration;
350121
+ } });
350122
+ Object.defineProperty(exports2, "codeUsesTestInboxIdentity", { enumerable: true, get: function() {
350123
+ return inbox_stamp_js_1.codeUsesTestInboxIdentity;
350124
+ } });
350125
+ Object.defineProperty(exports2, "codeUsesInboxHelper", { enumerable: true, get: function() {
350126
+ return inbox_stamp_js_1.codeUsesInboxHelper;
350127
+ } });
349978
350128
  __exportStar(require_playwright_native(), exports2);
349979
350129
  __exportStar(require_regression_runner(), exports2);
349980
350130
  __exportStar(require_snapshot_parser(), exports2);
@@ -350296,6 +350446,26 @@ var require_dist2 = __commonJS({
350296
350446
  Object.defineProperty(exports2, "UNSUPPORTED_RENDERER_PREFIX", { enumerable: true, get: function() {
350297
350447
  return canvas_detector_js_1.UNSUPPORTED_RENDERER_PREFIX;
350298
350448
  } });
350449
+ var verification_inbox_js_1 = require_verification_inbox();
350450
+ Object.defineProperty(exports2, "VerificationInboxReader", { enumerable: true, get: function() {
350451
+ return verification_inbox_js_1.VerificationInboxReader;
350452
+ } });
350453
+ Object.defineProperty(exports2, "loadVerificationInboxConfig", { enumerable: true, get: function() {
350454
+ return verification_inbox_js_1.loadVerificationInboxConfig;
350455
+ } });
350456
+ Object.defineProperty(exports2, "deriveInboxTag", { enumerable: true, get: function() {
350457
+ return verification_inbox_js_1.deriveInboxTag;
350458
+ } });
350459
+ Object.defineProperty(exports2, "deriveProjectInboxTag", { enumerable: true, get: function() {
350460
+ return verification_inbox_js_1.deriveProjectInboxTag;
350461
+ } });
350462
+ Object.defineProperty(exports2, "applyPlusTag", { enumerable: true, get: function() {
350463
+ return verification_inbox_js_1.applyPlusTag;
350464
+ } });
350465
+ var brokered_inbox_reader_js_1 = require_brokered_inbox_reader();
350466
+ Object.defineProperty(exports2, "BrokeredInboxReader", { enumerable: true, get: function() {
350467
+ return brokered_inbox_reader_js_1.BrokeredInboxReader;
350468
+ } });
350299
350469
  }
350300
350470
  });
350301
350471
 
@@ -350304,7 +350474,7 @@ var require_package4 = __commonJS({
350304
350474
  "package.json"(exports2, module2) {
350305
350475
  module2.exports = {
350306
350476
  name: "@validate.qa/runner",
350307
- version: "1.0.58",
350477
+ version: "1.0.60",
350308
350478
  description: "validate local test runner - execute Playwright tests on your machine, connected to validate.qa cloud.",
350309
350479
  bin: {
350310
350480
  "validate-runner": "dist/cli.js"
@@ -357933,7 +358103,8 @@ async function executeRun(run2, opts, headers, requestLiveBrowserHeartbeat = ()
357933
358103
  const codeUsesCreds = codeProvided && /TEST_USER_EMAIL|TEST_USER_PASSWORD|__vqaLogin/.test(code);
357934
358104
  const tags = Array.isArray(run2.tags) ? run2.tags : [];
357935
358105
  const isHallucinationShape = codeProvided && !codeUsesCreds && tags.includes("@inline-login") && !tags.includes("@api");
357936
- const requireCreds = authPlan.needsLoginCreds && !legacyHeaderBypass && !isHallucinationShape;
358106
+ const selfProvisioningRegisterTest = codeProvided && !codeUsesCreds && tags.includes("@email-verify") && (0, import_runner_core13.codeSelfProvisionsRegistration)(code);
358107
+ const requireCreds = authPlan.needsLoginCreds && !legacyHeaderBypass && !isHallucinationShape && !selfProvisioningRegisterTest;
357937
358108
  if (requireCreds && !run2.testVariables?.["TEST_USER_EMAIL"]?.trim()) {
357938
358109
  preflightError = "Pre-flight failed: Missing TEST_USER_EMAIL. Tests that log in (tagged @auth, @needs-auth, @api, @auth-cookie-state, @auth-login-cookie, or @auth-login-bearer) require login credentials.";
357939
358110
  } else if (requireCreds && !run2.testVariables?.["TEST_USER_PASSWORD"]?.trim()) {
@@ -358836,6 +359007,20 @@ ${finalVerifyResult.logs ?? ""}`;
358836
359007
  { ...input, actor: "ai-explorer" },
358837
359008
  run2.claimEpoch
358838
359009
  );
359010
+ if (ctx.inboxBroker?.address) {
359011
+ ctx.inboxBrokerRead = async (op, payload) => {
359012
+ const res = await fetch(`${opts.serverUrl}/api/runner/inbox/read`, {
359013
+ method: "POST",
359014
+ headers: { ...headers, "Content-Type": "application/json" },
359015
+ body: JSON.stringify({ runId: run2.runId, op, payload })
359016
+ });
359017
+ if (!res.ok) {
359018
+ const detail = await res.text().catch(() => "");
359019
+ throw new Error(`inbox broker ${op} failed: HTTP ${res.status}${detail ? ` \u2014 ${detail.slice(0, 200)}` : ""}`);
359020
+ }
359021
+ return (await res.json()).value ?? null;
359022
+ };
359023
+ }
358839
359024
  log.info(`Discovery (${ctx.mode}) on ${ctx.baseUrl}`);
358840
359025
  const { push: pushAudit, drain: drainAudit } = createAuditFlusher(
358841
359026
  `${opts.serverUrl}/api/runner/runs/${run2.runId}/ai-audit-batch`,
package/dist/cli.mjs CHANGED
@@ -72846,18 +72846,15 @@ var require_verification_inbox = __commonJS({
72846
72846
  return { code: cleaned, confidence: "keyword" };
72847
72847
  }
72848
72848
  }
72849
- const distinct = /* @__PURE__ */ new Set();
72850
72849
  for (const body of bodies) {
72851
72850
  if (!body)
72852
72851
  continue;
72853
72852
  for (const n of body.match(/\b[0-9]{4,8}\b/g) ?? []) {
72854
- if (!looksLikeYearOrDate(n))
72855
- distinct.add(n);
72853
+ if (looksLikeYearOrDate(n))
72854
+ continue;
72855
+ return { code: n, confidence: "fallback" };
72856
72856
  }
72857
72857
  }
72858
- if (distinct.size === 1) {
72859
- return { code: distinct.values().next().value ?? null, confidence: "fallback" };
72860
- }
72861
72858
  return { code: null, confidence: null };
72862
72859
  }
72863
72860
  function matchBestCode(line) {
@@ -73155,9 +73152,10 @@ var require_verification_inbox = __commonJS({
73155
73152
  const satisfies = (m) => {
73156
73153
  if (opts.require === "code")
73157
73154
  return m.code !== null && m.codeConfidence !== "fallback";
73155
+ const linkOk = (l) => l !== null && (!opts.linkAcceptable || opts.linkAcceptable(l));
73158
73156
  if (opts.require === "link")
73159
- return m.link !== null;
73160
- return m.hasVerificationSignal;
73157
+ return linkOk(m.link);
73158
+ return m.code !== null && m.codeConfidence !== "fallback" || linkOk(m.link);
73161
73159
  };
73162
73160
  let weakest = null;
73163
73161
  const check2 = async () => {
@@ -73204,7 +73202,7 @@ var require_verification_inbox = __commonJS({
73204
73202
  const since = new Date(Math.max(0, opts.sinceMs));
73205
73203
  const lock = await client.getMailboxLock(mailbox);
73206
73204
  const results = [];
73207
- const taggedRecipient = isPlusTagged(opts.toAddress);
73205
+ const demoteMismatch = isPlusTagged(opts.toAddress) && Boolean(opts.demoteFilterMismatch);
73208
73206
  try {
73209
73207
  try {
73210
73208
  await client.noop();
@@ -73250,7 +73248,7 @@ var require_verification_inbox = __commonJS({
73250
73248
  continue;
73251
73249
  const filterActive = Boolean(opts.fromMatch || opts.subjectMatch);
73252
73250
  const filterMatched = (!opts.fromMatch || matchField(parsed.from?.text, opts.fromMatch)) && (!opts.subjectMatch || matchField(parsed.subject, opts.subjectMatch));
73253
- if (filterActive && !filterMatched && !taggedRecipient) {
73251
+ if (filterActive && !filterMatched && !demoteMismatch) {
73254
73252
  if (opts.stats)
73255
73253
  opts.stats.filteredOut += 1;
73256
73254
  continue;
@@ -73349,6 +73347,58 @@ var require_verification_inbox = __commonJS({
73349
73347
  }
73350
73348
  });
73351
73349
 
73350
+ // ../runner-core/dist/services/brokered-inbox-reader.js
73351
+ var require_brokered_inbox_reader = __commonJS({
73352
+ "../runner-core/dist/services/brokered-inbox-reader.js"(exports) {
73353
+ "use strict";
73354
+ Object.defineProperty(exports, "__esModule", { value: true });
73355
+ exports.BrokeredInboxReader = void 0;
73356
+ var BROKERED_WAIT_CHUNK_MS = 55e3;
73357
+ var BrokeredInboxReader = class {
73358
+ transport;
73359
+ constructor(transport) {
73360
+ this.transport = transport;
73361
+ }
73362
+ async getUidWatermark() {
73363
+ const value = await this.transport("getUidWatermark", {});
73364
+ const record = value ?? {};
73365
+ return {
73366
+ uid: typeof record.uid === "number" ? record.uid : 0,
73367
+ uidValidity: typeof record.uidValidity === "number" ? record.uidValidity : 0
73368
+ };
73369
+ }
73370
+ async search(opts) {
73371
+ const value = await this.transport("search", { opts });
73372
+ return Array.isArray(value) ? value : [];
73373
+ }
73374
+ async getLatest(opts) {
73375
+ const value = await this.transport("getLatest", { opts });
73376
+ return value ?? null;
73377
+ }
73378
+ async getById(uid, address, altAddress, freshness) {
73379
+ const value = await this.transport("getById", { uid, address, altAddress, freshness });
73380
+ return value ?? null;
73381
+ }
73382
+ async waitForMessage(opts) {
73383
+ const totalBudgetMs = Math.max(opts.maxWaitMs ?? 9e4, 1e3);
73384
+ const deadline = Date.now() + totalBudgetMs;
73385
+ for (; ; ) {
73386
+ const remaining = deadline - Date.now();
73387
+ if (remaining <= 0)
73388
+ return null;
73389
+ const chunkMs = Math.min(remaining, BROKERED_WAIT_CHUNK_MS);
73390
+ const value = await this.transport("waitForMessage", {
73391
+ opts: { ...opts, maxWaitMs: chunkMs }
73392
+ });
73393
+ if (value)
73394
+ return value;
73395
+ }
73396
+ }
73397
+ };
73398
+ exports.BrokeredInboxReader = BrokeredInboxReader;
73399
+ }
73400
+ });
73401
+
73352
73402
  // ../runner-core/dist/services/inbox-tools.js
73353
73403
  var require_inbox_tools = __commonJS({
73354
73404
  "../runner-core/dist/services/inbox-tools.js"(exports) {
@@ -73388,7 +73438,8 @@ var require_inbox_tools = __commonJS({
73388
73438
  // Captured at provision (needs a live reader); 0 = use the sinceMs floor.
73389
73439
  sinceUid: 0,
73390
73440
  sinceUidValidity: 0,
73391
- knownLinks: /* @__PURE__ */ new Set()
73441
+ knownLinks: /* @__PURE__ */ new Set(),
73442
+ demoteFilterMismatch: opts.demoteFilterMismatch ?? false
73392
73443
  };
73393
73444
  }
73394
73445
  exports.PROVISION_IDENTITY_TOOL = {
@@ -73576,6 +73627,7 @@ var require_inbox_tools = __commonJS({
73576
73627
  sinceUidValidity: ctx.state.sinceUidValidity,
73577
73628
  fromMatch: asStr(args.senderMatch),
73578
73629
  subjectMatch: asStr(args.subjectMatch),
73630
+ demoteFilterMismatch: ctx.state.demoteFilterMismatch,
73579
73631
  limit: 10
73580
73632
  });
73581
73633
  return ok({
@@ -73600,6 +73652,7 @@ var require_inbox_tools = __commonJS({
73600
73652
  sinceUidValidity: ctx.state.sinceUidValidity,
73601
73653
  fromMatch: asStr(args.senderMatch),
73602
73654
  subjectMatch: asStr(args.subjectMatch),
73655
+ demoteFilterMismatch: ctx.state.demoteFilterMismatch,
73603
73656
  maxWaitMs: maxWaitSeconds * 1e3,
73604
73657
  stats
73605
73658
  });
@@ -73746,7 +73799,7 @@ var require_inbox_tools = __commonJS({
73746
73799
  const u = new URL(raw);
73747
73800
  if (u.protocol !== "http:" && u.protocol !== "https:")
73748
73801
  return false;
73749
- host = u.hostname.toLowerCase().replace(/^\[|\]$/g, "");
73802
+ host = u.hostname.toLowerCase().replace(/^\[|\]$/g, "").replace(/\.+$/, "");
73750
73803
  } catch {
73751
73804
  return false;
73752
73805
  }
@@ -73762,7 +73815,7 @@ var require_inbox_tools = __commonJS({
73762
73815
  const dotted = host.match(/(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/);
73763
73816
  if (dotted && !ipv4IsPublic(dotted[1]))
73764
73817
  return false;
73765
- const mapped = host.match(/^::ffff:([0-9a-f]{1,4}):([0-9a-f]{1,4})$/);
73818
+ const mapped = host.match(/^::(?:ffff:)?([0-9a-f]{1,4}):([0-9a-f]{1,4})$/);
73766
73819
  if (mapped) {
73767
73820
  const hi = parseInt(mapped[1], 16);
73768
73821
  const lo = parseInt(mapped[2], 16);
@@ -74055,6 +74108,7 @@ var require_mobile_explorer = __commonJS({
74055
74108
  var mobile_auth_coverage_js_1 = require_mobile_auth_coverage();
74056
74109
  var mobile_driver_errors_js_1 = require_mobile_driver_errors();
74057
74110
  var verification_inbox_js_1 = require_verification_inbox();
74111
+ var brokered_inbox_reader_js_1 = require_brokered_inbox_reader();
74058
74112
  var inbox_tools_js_1 = require_inbox_tools();
74059
74113
  var mobile_discovery_auth_js_1 = require_mobile_discovery_auth();
74060
74114
  var MAX_MOBILE_ITERATIONS_SURVEY = 40;
@@ -75376,6 +75430,23 @@ ${existingScreens.slice(0, 100).map((s) => `- ${s.screenId}${s.name ? ` "${s.nam
75376
75430
  log: (line) => log2(line)
75377
75431
  });
75378
75432
  log2("Verification inbox ENABLED for registration \u2014 monitored identity provisioned.");
75433
+ } else if (registerRequested && ctx.inboxBroker?.address && ctx.inboxBrokerRead) {
75434
+ inboxState = (0, inbox_tools_js_1.createInboxRunState)({ address: ctx.inboxBroker.address }, {
75435
+ tagSeed: targetAppId ?? ctx.projectId,
75436
+ projectScope: ctx.projectId
75437
+ });
75438
+ inboxReader = new brokered_inbox_reader_js_1.BrokeredInboxReader(ctx.inboxBrokerRead);
75439
+ await (0, inbox_tools_js_1.applyAndPersistInboxIdentity)({
75440
+ variableContext: ctx.variableContext,
75441
+ registration: {
75442
+ email: inboxState.email,
75443
+ legacyEmail: inboxState.legacyEmail,
75444
+ passwordKey: inboxState.passwordKey ?? "TEST_USER_PASSWORD"
75445
+ },
75446
+ persist: ctx.onCredentialUpdate,
75447
+ log: (line) => log2(line)
75448
+ });
75449
+ log2("Verification inbox ENABLED via server broker \u2014 monitored identity provisioned (IMAP credentials stay server-side).");
75379
75450
  } else if (registerRequested) {
75380
75451
  log2("Registration requested without a verification inbox \u2014 preserving the seeded credential identity and reporting any verification wall as unauthenticated.");
75381
75452
  }
@@ -84290,12 +84361,14 @@ ${args.directive}`);
84290
84361
  { role: "user", content: userContent }
84291
84362
  ];
84292
84363
  let content;
84364
+ let finishReason;
84293
84365
  try {
84294
84366
  const response = await (0, ai_retry_js_1.resilientAICall)((signal, arm) => (0, ai_queue_js_1.queuedAICall)(() => {
84295
84367
  arm();
84296
84368
  return aiClient.chat.completions.create({ model, messages, max_tokens: 8e3, temperature: 0.1 }, { signal });
84297
84369
  }), { label: `mobile-heal-attempt-${attempt}`, deferTimeoutUntilArmed: true });
84298
84370
  content = response?.choices?.[0]?.message?.content ?? "";
84371
+ finishReason = response?.choices?.[0]?.finish_reason ?? void 0;
84299
84372
  } catch {
84300
84373
  options.onProgress?.(`Phase 1 attempt ${attempt}: model call failed in transport \u2014 granting a recovery turn`);
84301
84374
  markRecoverableTurn();
@@ -84305,7 +84378,7 @@ ${args.directive}`);
84305
84378
  aiResponseCount += 1;
84306
84379
  const parsed = parseHealVerdict(content);
84307
84380
  if (!parsed) {
84308
- options.onProgress?.(`Phase 1 attempt ${attempt}: response was not a valid verdict \u2014 granting a recovery turn`);
84381
+ options.onProgress?.(`Phase 1 attempt ${attempt}: response was not a valid verdict (${content.length} chars, finish=${finishReason ?? "unknown"}) \u2014 granting a recovery turn`);
84309
84382
  markRecoverableTurn();
84310
84383
  pendingDirective = "Your last response was not valid JSON matching the verdict schema. Return exactly one JSON verdict object.";
84311
84384
  continue;
@@ -86423,6 +86496,8 @@ var require_inbox_stamp = __commonJS({
86423
86496
  exports.INBOX_HELPER_TOKEN_RE = exports.INBOX_HELPER_NAME = exports.INBOX_REGION_RE = exports.INBOX_MARKER_VERSION = void 0;
86424
86497
  exports.codeUsesInboxHelper = codeUsesInboxHelper;
86425
86498
  exports.stripInboxRegions = stripInboxRegions;
86499
+ exports.codeUsesTestInboxIdentity = codeUsesTestInboxIdentity;
86500
+ exports.codeSelfProvisionsRegistration = codeSelfProvisionsRegistration2;
86426
86501
  exports.renderInboxFn = renderInboxFn;
86427
86502
  exports.upsertInboxBlock = upsertInboxBlock;
86428
86503
  var auth_recipe_js_1 = require_auth_recipe();
@@ -86437,12 +86512,54 @@ var require_inbox_stamp = __commonJS({
86437
86512
  return false;
86438
86513
  return exports.INBOX_HELPER_TOKEN_RE.test(code) || /VALIDATE_QA_INBOX/.test(code);
86439
86514
  }
86515
+ var INBOX_REGION_START = "// >>> VALIDATE_QA_INBOX";
86516
+ var INBOX_REGION_END = "// <<< VALIDATE_QA_INBOX";
86440
86517
  function stripInboxRegions(code) {
86441
- return code.replace(exports.INBOX_REGION_RE, "");
86518
+ if (!code || code.indexOf(INBOX_REGION_START) === -1)
86519
+ return code;
86520
+ let out = "";
86521
+ let i = 0;
86522
+ while (i < code.length) {
86523
+ const start = code.indexOf(INBOX_REGION_START, i);
86524
+ if (start === -1) {
86525
+ out += code.slice(i);
86526
+ break;
86527
+ }
86528
+ const end = code.indexOf(INBOX_REGION_END, start + INBOX_REGION_START.length);
86529
+ if (end === -1) {
86530
+ out += code.slice(i);
86531
+ break;
86532
+ }
86533
+ let lineEnd = code.indexOf("\n", end);
86534
+ lineEnd = lineEnd === -1 ? code.length : lineEnd + 1;
86535
+ out += code.slice(i, start);
86536
+ i = lineEnd;
86537
+ }
86538
+ return out;
86539
+ }
86540
+ var TEST_INBOX_IDENTITY_RE = /VQA_TEST_INBOX_EMAIL|VQA_TEST_ACCOUNT_PASSWORD/;
86541
+ function codeUsesTestInboxIdentity(code) {
86542
+ if (!code)
86543
+ return false;
86544
+ return TEST_INBOX_IDENTITY_RE.test(stripInboxRegions(code));
86545
+ }
86546
+ function codeSelfProvisionsRegistration2(code) {
86547
+ return codeUsesTestInboxIdentity(code);
86442
86548
  }
86443
86549
  function countInboxRegions(code) {
86444
- const m = code.match(exports.INBOX_REGION_RE);
86445
- return m ? m.length : 0;
86550
+ let count = 0;
86551
+ let i = 0;
86552
+ while (i < code.length) {
86553
+ const start = code.indexOf(INBOX_REGION_START, i);
86554
+ if (start === -1)
86555
+ break;
86556
+ const end = code.indexOf(INBOX_REGION_END, start + INBOX_REGION_START.length);
86557
+ if (end === -1)
86558
+ break;
86559
+ count++;
86560
+ i = end + INBOX_REGION_END.length;
86561
+ }
86562
+ return count;
86446
86563
  }
86447
86564
  function renderInboxFn() {
86448
86565
  const lines = [
@@ -86536,7 +86653,12 @@ var require_test_inbox_broker = __commonJS({
86536
86653
  return { found: true, code, link, subject: msg.subject, from: msg.from };
86537
86654
  }
86538
86655
  async function startTestInboxBroker(opts) {
86539
- const identity = mintTestRunInboxIdentity(opts.config, opts);
86656
+ const executionNonce = (0, node_crypto_1.randomBytes)(4).toString("hex");
86657
+ const identity = mintTestRunInboxIdentity(opts.config, {
86658
+ baseUrl: opts.baseUrl,
86659
+ projectId: opts.projectId,
86660
+ runId: `${opts.runId}#${executionNonce}`
86661
+ });
86540
86662
  const reader = new verification_inbox_js_1.VerificationInboxReader(opts.config);
86541
86663
  const sinceMs = Date.now();
86542
86664
  let sinceUid = 0;
@@ -86576,6 +86698,12 @@ var require_test_inbox_broker = __commonJS({
86576
86698
  sinceUidValidity,
86577
86699
  maxWaitMs: timeoutMs,
86578
86700
  require: require2,
86701
+ // The plus-tag recipient is unique to this run, so an unexpected ESP
86702
+ // sender is still this run's mail — demote, don't drop.
86703
+ demoteFilterMismatch: true,
86704
+ // Don't let a private/internal link end a `require:'link'` wait early —
86705
+ // keep polling for a public one (SSRF parity with the post-wait check).
86706
+ linkAcceptable: inbox_tools_js_1.isPublicHttpUrl,
86579
86707
  stats
86580
86708
  });
86581
86709
  const publicLink = msg && msg.link && (0, inbox_tools_js_1.isPublicHttpUrl)(msg.link) ? msg.link : null;
@@ -86710,7 +86838,8 @@ var require_playwright_native = __commonJS({
86710
86838
  runDir = (0, path_1.join)(RUNS_DIR, (0, crypto_1.randomUUID)());
86711
86839
  await (0, promises_1.mkdir)(runDir, { recursive: true });
86712
86840
  const isApiTest2 = playwrightCode.includes("@api") || playwrightCode.includes("{ request }") && !playwrightCode.includes("{ page");
86713
- const usesInboxHelper = !isApiTest2 && (0, inbox_stamp_js_1.codeUsesInboxHelper)(playwrightCode);
86841
+ const usesRealInboxWait = !isApiTest2 && (0, inbox_stamp_js_1.codeUsesInboxHelper)(playwrightCode);
86842
+ const selfProvisionsRegistration = !isApiTest2 && (0, inbox_stamp_js_1.codeSelfProvisionsRegistration)(playwrightCode);
86714
86843
  const effectiveStandingMode = isApiTest2 ? authStandingMode ?? "legacy-if-configured" : "none";
86715
86844
  const resolvedExtraHeaders = (0, api_auth_headers_js_1.resolveApiAuthHeaders)({
86716
86845
  explicit: extraHttpHeaders,
@@ -86957,7 +87086,7 @@ test.afterEach(async ({ page }, testInfo) => {
86957
87086
  module.exports = {
86958
87087
  testDir: ${JSON.stringify(absTestDir)},
86959
87088
  outputDir: ${JSON.stringify(absOutputDir)},
86960
- timeout: ${usesInboxHelper ? 24e4 : 6e4},
87089
+ timeout: ${usesRealInboxWait ? 24e4 : 6e4},
86961
87090
  retries: 0,
86962
87091
  use: {
86963
87092
  baseURL: ${JSON.stringify(baseUrl)},
@@ -86983,7 +87112,7 @@ module.exports = {
86983
87112
  const isolation = await (0, chromium_isolation_js_1.createChromiumIsolation)(runDir);
86984
87113
  const processClaimEpoch = Number(process.env.CLAIM_EPOCH);
86985
87114
  const callbackClaimEpoch = Number.isSafeInteger(validateContext?.claimEpoch) ? validateContext?.claimEpoch : Number.isSafeInteger(processClaimEpoch) && processClaimEpoch >= 0 ? processClaimEpoch : void 0;
86986
- if (usesInboxHelper && validateContext?.runId) {
87115
+ if (selfProvisionsRegistration && validateContext?.runId) {
86987
87116
  const inboxConfig = (0, verification_inbox_js_1.loadVerificationInboxConfig)();
86988
87117
  if (!inboxConfig) {
86989
87118
  logs2.push("\u{1F4EA} Test uses __vqaWaitForEmail but this runner has no verification inbox configured \u2014 the helper will fail as CONFIG_ISSUE");
@@ -87001,8 +87130,8 @@ module.exports = {
87001
87130
  logs2.push(`\u26A0 Inbox broker failed to start: ${error3 instanceof Error ? error3.message : String(error3)}`);
87002
87131
  }
87003
87132
  }
87004
- } else if (usesInboxHelper) {
87005
- logs2.push("\u{1F4EA} Test uses __vqaWaitForEmail but no run callback context is available \u2014 the helper will fail as CONFIG_ISSUE");
87133
+ } else if (selfProvisionsRegistration) {
87134
+ logs2.push("\u{1F4EA} Test self-provisions a registration identity (VQA_TEST_* / __vqaWaitForEmail) but no run callback context is available \u2014 the broker cannot start, so those values will be undefined at runtime");
87006
87135
  }
87007
87136
  if (validateContext?.runId && validateContext.serverUrl && validateContext.authHeader) {
87008
87137
  try {
@@ -87043,16 +87172,20 @@ module.exports = {
87043
87172
  ...process.env.SHARED_AUTH_INJECT ? { SHARED_AUTH_INJECT: process.env.SHARED_AUTH_INJECT } : {},
87044
87173
  // Register-and-verify tests: the run's minted registration identity. An
87045
87174
  // address + a DERIVED throwaway-app password — never the IMAP secret,
87046
- // which stays in this parent (test-inbox-broker.ts). Useless without the
87047
- // loopback proxy the helper reads mail through, hence the guard.
87048
- ...inboxBroker && callbackProxy ? inboxBroker.childEnv() : {}
87175
+ // which stays in this parent (test-inbox-broker.ts). Injected whenever the
87176
+ // broker started, NOT gated on the callback proxy: a signup that registers
87177
+ // with this identity but needs no email verification uses the env yet never
87178
+ // touches the proxy — gating on the proxy left it with undefined creds. A
87179
+ // helper test still needs the proxy, and simply fails as CONFIG_ISSUE
87180
+ // without it; leaking the throwaway address/password to that child is inert.
87181
+ ...inboxBroker ? inboxBroker.childEnv() : {}
87049
87182
  };
87050
87183
  delete childTestVariables.API_AUTH_HEADERS;
87051
87184
  logs2.push("\u{1F680} Spawning playwright test...");
87052
87185
  const stopLiveBrowserPolling = liveBrowserStatePath && liveBrowserHandle ? startLiveBrowserStatePolling(liveBrowserStatePath, liveBrowserHandle, onLiveBrowserSnapshot) : null;
87053
87186
  let playResult;
87054
87187
  try {
87055
- playResult = await runPlaywright(configPath, childTestVariables, trustedRuntimeEnv, usesInboxHelper ? 3e5 : void 0);
87188
+ playResult = await runPlaywright(configPath, childTestVariables, trustedRuntimeEnv, usesRealInboxWait ? 3e5 : void 0);
87056
87189
  } finally {
87057
87190
  await stopLiveBrowserPolling?.();
87058
87191
  }
@@ -94804,7 +94937,7 @@ var require_discover_generator = __commonJS({
94804
94937
  var test_inbox_broker_js_1 = require_test_inbox_broker();
94805
94938
  var REGISTER_SCENARIO_RE = /\b(register|registration|sign[\s-]?up|create[\s-]?(a[n]?[\s-]?)?(new[\s-]?)?account|verify[\s-]?(your[\s-]?)?email|email[\s-]?verification|confirm[\s-]?(your[\s-]?)?(email|account)|activate[\s-]?(your[\s-]?)?account|new[\s-]?account)\b/i;
94806
94939
  function scenarioLooksLikeRegistration(scenario) {
94807
- const hay = `${scenario.name ?? ""} ${scenario.description ?? ""} ${scenario.entryRoute ?? ""} ${(scenario.targetPages ?? []).join(" ")}`;
94940
+ const hay = `${scenario.name ?? ""} ${scenario.goal ?? ""} ${scenario.description ?? ""} ${scenario.entryRoute ?? ""} ${(scenario.targetPages ?? []).join(" ")}`;
94808
94941
  return REGISTER_SCENARIO_RE.test(hay);
94809
94942
  }
94810
94943
  function buildEmailVerifyGenBlock(genEmail, genPassword) {
@@ -97757,7 +97890,7 @@ ${tailBlock}`;
97757
97890
  const genEmail = (0, verification_inbox_js_1.applyPlusTag)(inboxGenConfig.address, genTag);
97758
97891
  const genPassword = (0, verification_inbox_js_1.deriveRegistrationPassword)(genEmail);
97759
97892
  genInboxReader = new verification_inbox_js_1.VerificationInboxReader(inboxGenConfig);
97760
- genInboxState = (0, inbox_tools_js_1.createInboxRunState)(inboxGenConfig, { tag: genTag, passwordKey: test_inbox_broker_js_1.TEST_INBOX_PASSWORD_ENV });
97893
+ genInboxState = (0, inbox_tools_js_1.createInboxRunState)(inboxGenConfig, { tag: genTag, passwordKey: test_inbox_broker_js_1.TEST_INBOX_PASSWORD_ENV, demoteFilterMismatch: true });
97761
97894
  genInboxCredentials = { ...credentials, [test_inbox_broker_js_1.TEST_INBOX_EMAIL_ENV]: genEmail, [test_inbox_broker_js_1.TEST_INBOX_PASSWORD_ENV]: genPassword };
97762
97895
  genInboxSecret = genPassword;
97763
97896
  openaiTools.push(...inbox_tools_js_1.INBOX_TOOLS);
@@ -98319,6 +98452,13 @@ Do NOT assert that the button/tab/heading you interacted with is merely visible
98319
98452
  logs2.push(` Strength gate: block persists after revision \u2014 tagged @needs-review (proves no outcome)`);
98320
98453
  }
98321
98454
  }
98455
+ const finalSelfProvisions = (0, inbox_stamp_js_1.codeSelfProvisionsRegistration)(result.playwrightCode);
98456
+ if (finalSelfProvisions) {
98457
+ if (!result.tags.includes("@email-verify"))
98458
+ result.tags.push("@email-verify");
98459
+ } else if (inboxGenConfig) {
98460
+ logs2.push(` \u26A0 Email-verify generation was armed but the emitted test neither calls __vqaWaitForEmail nor uses the VQA_TEST_* runtime identity \u2014 it may have hardcoded values (stale on re-run).`);
98461
+ }
98322
98462
  const elapsed = Date.now() - startTime;
98323
98463
  logs2.push(` Scenario test generated in ${iteration} iterations (${elapsed}ms, ${verifyCallCount} verify calls)`);
98324
98464
  } else {
@@ -349887,9 +350027,9 @@ var require_dist2 = __commonJS({
349887
350027
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports2, p)) __createBinding(exports2, m, p);
349888
350028
  };
349889
350029
  Object.defineProperty(exports, "__esModule", { value: true });
349890
- exports.acquireRepoForImport = exports.runFrameworkImportOnRunner = exports.getAgenticEngine = exports.resolveRefFromSnapshot = exports.replayAuthRecipeIntoBrowser = exports.runRegisterCaptureRun = exports.runLoginCaptureRun = exports.filterLoginCaptureCredentials = exports.buildLoginCaptureCredentials = exports.isReservedRunnerEnvVar = exports.RESERVED_RUNNER_ENV_VARS = exports.AUTH_MARKER_VERSION = exports.buildHealAuthStamp = exports.extractAuthRegion = exports.upsertAuthBlock = exports.buildAuthRecipe = exports.commandToReplayStep = exports.buildReplayPlan = exports.absoluteRoute = exports.renderReplaySettleArrow = exports.renderReplayClickArrow = exports.renderAuthFn = exports.filterFeatureGroupsToPathScope = exports.isAuthFlowRoute = exports.deriveSurveyPathScope = exports.canonicalizeRoute = exports.executeGrokPerBatchHeal = exports.executeGrokPerTestHeal = exports.headerVal = exports.classifyAuthType = exports.isTextExcerptable = exports.isStaticAssetByExt = exports.isApiCall = exports.buildApiCallSummary = exports.computeMobileHealOutcome = exports.detectMobileStepSecretLeak = exports.redactMobileSecretsFromText = exports.MOBILE_LIVE_HEAL_SYSTEM_PROMPT = exports.MOBILE_SCRIPT_HEAL_SYSTEM_PROMPT = exports.executeMobileLiveHeal = exports.executeMobileTestWithHealing = exports.executeMobileScriptDrivenHeal = exports.prepareMobileScenarioAppState = exports.runMobileGeneratePhase = exports.runMobileAIPlanner = exports.buildMobileSiteMap = exports.formatMobileEvidenceForPlanner = exports.MOBILE_SCENARIO_SYSTEM_PROMPT = exports.MOBILE_SURVEY_SYSTEM_PROMPT = exports.runMobileExplorePhase = void 0;
349891
- exports.gracefulCloseWithTreeKill = exports.liveBrowserRegistry = exports.REPO_SWITCH_REMOVED_FRACTION = exports.MAX_MANIFEST_FILES = exports.toDiffSummary = exports.isLikelyTestFile = exports.sanitizeRepoRelPath = exports.sha256Hex = exports.hashFiles = exports.enumerateTestFiles = exports.buildNextManifest = exports.detectRepoSwitch = exports.classifyImportDiff = exports.parseImportManifest = exports.validateAuthoredMobileTest = exports.buildMobileRepoAuthorSystemRules = exports.buildMobileRepoAuthorKickoff = exports.buildMobileRepoAuthorContractMd = exports.REPO_ANALYSIS_SCHEMA_VERSION = exports.validateSourceEndpoints = exports.validateAuthoredTest = exports.validateRepoMapFile = exports.validateRepoMemoryFile = exports.buildTestingStandardsSection = exports.buildRepoAuthorSystemRules = exports.buildRepoAuthorKickoff = exports.buildRepoAuthorContractMd = exports.buildRepoMapSystemRules = exports.buildRepoMapKickoff = exports.buildRepoMapContractMd = exports.buildRepoMemorySystemRules = exports.buildRepoMemoryKickoff = exports.buildRepoMemoryContractMd = exports.runRepoAnalysisOnRunner = exports.MOBILE_IMPORT_SCHEMA_VERSION = exports.validateImportedMobileTest = exports.buildMobileImportSystemRules = exports.buildMobileImportKickoff = exports.buildMobileImportContractMd = exports.IMPORT_SCHEMA_VERSION = exports.validateImportResultFile = exports.validateImportedTest = exports.buildImportSystemRules = exports.buildImportKickoff = exports.buildImportContractMd = exports.MAX_ARCHIVE_BYTES = exports.isUnsafeEntryName = exports.extractZipSafely = exports.downloadArchiveCapped = exports.detectArchiveKind = void 0;
349892
- exports.UNSUPPORTED_RENDERER_PREFIX = exports.UnsupportedRendererError = exports.buildCanvasModeAuthoringAddendum = exports.buildUnsupportedRendererMessage = exports.modelSupportsVision = exports.decideCanvasStrategy = exports.decideAppRenderType = exports.detectCanvasApp = exports.detectRateLimitBlock = exports.isSafeCanonicalRedirect = exports.resolveBaseUrlPreflight = exports.checkBaseUrlRedirect = exports.stripJsonFences = exports.scrubCredentials = exports.withAIRetry = exports.snapshotMatchingChildren = exports.findNewChromiumChildPid = exports.killProcessTree = void 0;
350030
+ exports.resolveRefFromSnapshot = exports.replayAuthRecipeIntoBrowser = exports.runRegisterCaptureRun = exports.runLoginCaptureRun = exports.filterLoginCaptureCredentials = exports.buildLoginCaptureCredentials = exports.isReservedRunnerEnvVar = exports.RESERVED_RUNNER_ENV_VARS = exports.AUTH_MARKER_VERSION = exports.buildHealAuthStamp = exports.extractAuthRegion = exports.upsertAuthBlock = exports.buildAuthRecipe = exports.commandToReplayStep = exports.buildReplayPlan = exports.absoluteRoute = exports.renderReplaySettleArrow = exports.renderReplayClickArrow = exports.renderAuthFn = exports.filterFeatureGroupsToPathScope = exports.isAuthFlowRoute = exports.deriveSurveyPathScope = exports.canonicalizeRoute = exports.codeUsesInboxHelper = exports.codeUsesTestInboxIdentity = exports.codeSelfProvisionsRegistration = exports.executeGrokPerBatchHeal = exports.executeGrokPerTestHeal = exports.headerVal = exports.classifyAuthType = exports.isTextExcerptable = exports.isStaticAssetByExt = exports.isApiCall = exports.buildApiCallSummary = exports.computeMobileHealOutcome = exports.detectMobileStepSecretLeak = exports.redactMobileSecretsFromText = exports.MOBILE_LIVE_HEAL_SYSTEM_PROMPT = exports.MOBILE_SCRIPT_HEAL_SYSTEM_PROMPT = exports.executeMobileLiveHeal = exports.executeMobileTestWithHealing = exports.executeMobileScriptDrivenHeal = exports.prepareMobileScenarioAppState = exports.runMobileGeneratePhase = exports.runMobileAIPlanner = exports.buildMobileSiteMap = exports.formatMobileEvidenceForPlanner = exports.MOBILE_SCENARIO_SYSTEM_PROMPT = exports.MOBILE_SURVEY_SYSTEM_PROMPT = exports.runMobileExplorePhase = void 0;
350031
+ exports.MAX_MANIFEST_FILES = exports.toDiffSummary = exports.isLikelyTestFile = exports.sanitizeRepoRelPath = exports.sha256Hex = exports.hashFiles = exports.enumerateTestFiles = exports.buildNextManifest = exports.detectRepoSwitch = exports.classifyImportDiff = exports.parseImportManifest = exports.validateAuthoredMobileTest = exports.buildMobileRepoAuthorSystemRules = exports.buildMobileRepoAuthorKickoff = exports.buildMobileRepoAuthorContractMd = exports.REPO_ANALYSIS_SCHEMA_VERSION = exports.validateSourceEndpoints = exports.validateAuthoredTest = exports.validateRepoMapFile = exports.validateRepoMemoryFile = exports.buildTestingStandardsSection = exports.buildRepoAuthorSystemRules = exports.buildRepoAuthorKickoff = exports.buildRepoAuthorContractMd = exports.buildRepoMapSystemRules = exports.buildRepoMapKickoff = exports.buildRepoMapContractMd = exports.buildRepoMemorySystemRules = exports.buildRepoMemoryKickoff = exports.buildRepoMemoryContractMd = exports.runRepoAnalysisOnRunner = exports.MOBILE_IMPORT_SCHEMA_VERSION = exports.validateImportedMobileTest = exports.buildMobileImportSystemRules = exports.buildMobileImportKickoff = exports.buildMobileImportContractMd = exports.IMPORT_SCHEMA_VERSION = exports.validateImportResultFile = exports.validateImportedTest = exports.buildImportSystemRules = exports.buildImportKickoff = exports.buildImportContractMd = exports.MAX_ARCHIVE_BYTES = exports.isUnsafeEntryName = exports.extractZipSafely = exports.downloadArchiveCapped = exports.detectArchiveKind = exports.acquireRepoForImport = exports.runFrameworkImportOnRunner = exports.getAgenticEngine = void 0;
350032
+ exports.BrokeredInboxReader = exports.applyPlusTag = exports.deriveProjectInboxTag = exports.deriveInboxTag = exports.loadVerificationInboxConfig = exports.VerificationInboxReader = exports.UNSUPPORTED_RENDERER_PREFIX = exports.UnsupportedRendererError = exports.buildCanvasModeAuthoringAddendum = exports.buildUnsupportedRendererMessage = exports.modelSupportsVision = exports.decideCanvasStrategy = exports.decideAppRenderType = exports.detectCanvasApp = exports.detectRateLimitBlock = exports.isSafeCanonicalRedirect = exports.resolveBaseUrlPreflight = exports.checkBaseUrlRedirect = exports.stripJsonFences = exports.scrubCredentials = exports.withAIRetry = exports.snapshotMatchingChildren = exports.findNewChromiumChildPid = exports.killProcessTree = exports.gracefulCloseWithTreeKill = exports.liveBrowserRegistry = exports.REPO_SWITCH_REMOVED_FRACTION = void 0;
349893
350033
  __exportStar(require_ai_provider(), exports);
349894
350034
  __exportStar(require_mobile_types(), exports);
349895
350035
  __exportStar(require_mobile_source_parser(), exports);
@@ -349980,6 +350120,16 @@ var require_dist2 = __commonJS({
349980
350120
  return grok_batch_healer_js_1.executeGrokPerBatchHeal;
349981
350121
  } });
349982
350122
  __exportStar(require_playwright_code(), exports);
350123
+ var inbox_stamp_js_1 = require_inbox_stamp();
350124
+ Object.defineProperty(exports, "codeSelfProvisionsRegistration", { enumerable: true, get: function() {
350125
+ return inbox_stamp_js_1.codeSelfProvisionsRegistration;
350126
+ } });
350127
+ Object.defineProperty(exports, "codeUsesTestInboxIdentity", { enumerable: true, get: function() {
350128
+ return inbox_stamp_js_1.codeUsesTestInboxIdentity;
350129
+ } });
350130
+ Object.defineProperty(exports, "codeUsesInboxHelper", { enumerable: true, get: function() {
350131
+ return inbox_stamp_js_1.codeUsesInboxHelper;
350132
+ } });
349983
350133
  __exportStar(require_playwright_native(), exports);
349984
350134
  __exportStar(require_regression_runner(), exports);
349985
350135
  __exportStar(require_snapshot_parser(), exports);
@@ -350301,6 +350451,26 @@ var require_dist2 = __commonJS({
350301
350451
  Object.defineProperty(exports, "UNSUPPORTED_RENDERER_PREFIX", { enumerable: true, get: function() {
350302
350452
  return canvas_detector_js_1.UNSUPPORTED_RENDERER_PREFIX;
350303
350453
  } });
350454
+ var verification_inbox_js_1 = require_verification_inbox();
350455
+ Object.defineProperty(exports, "VerificationInboxReader", { enumerable: true, get: function() {
350456
+ return verification_inbox_js_1.VerificationInboxReader;
350457
+ } });
350458
+ Object.defineProperty(exports, "loadVerificationInboxConfig", { enumerable: true, get: function() {
350459
+ return verification_inbox_js_1.loadVerificationInboxConfig;
350460
+ } });
350461
+ Object.defineProperty(exports, "deriveInboxTag", { enumerable: true, get: function() {
350462
+ return verification_inbox_js_1.deriveInboxTag;
350463
+ } });
350464
+ Object.defineProperty(exports, "deriveProjectInboxTag", { enumerable: true, get: function() {
350465
+ return verification_inbox_js_1.deriveProjectInboxTag;
350466
+ } });
350467
+ Object.defineProperty(exports, "applyPlusTag", { enumerable: true, get: function() {
350468
+ return verification_inbox_js_1.applyPlusTag;
350469
+ } });
350470
+ var brokered_inbox_reader_js_1 = require_brokered_inbox_reader();
350471
+ Object.defineProperty(exports, "BrokeredInboxReader", { enumerable: true, get: function() {
350472
+ return brokered_inbox_reader_js_1.BrokeredInboxReader;
350473
+ } });
350304
350474
  }
350305
350475
  });
350306
350476
 
@@ -350309,7 +350479,7 @@ var require_package4 = __commonJS({
350309
350479
  "package.json"(exports, module) {
350310
350480
  module.exports = {
350311
350481
  name: "@validate.qa/runner",
350312
- version: "1.0.58",
350482
+ version: "1.0.60",
350313
350483
  description: "validate local test runner - execute Playwright tests on your machine, connected to validate.qa cloud.",
350314
350484
  bin: {
350315
350485
  "validate-runner": "dist/cli.js"
@@ -357941,7 +358111,8 @@ async function executeRun(run2, opts, headers, requestLiveBrowserHeartbeat = ()
357941
358111
  const codeUsesCreds = codeProvided && /TEST_USER_EMAIL|TEST_USER_PASSWORD|__vqaLogin/.test(code);
357942
358112
  const tags = Array.isArray(run2.tags) ? run2.tags : [];
357943
358113
  const isHallucinationShape = codeProvided && !codeUsesCreds && tags.includes("@inline-login") && !tags.includes("@api");
357944
- const requireCreds = authPlan.needsLoginCreds && !legacyHeaderBypass && !isHallucinationShape;
358114
+ const selfProvisioningRegisterTest = codeProvided && !codeUsesCreds && tags.includes("@email-verify") && (0, import_runner_core13.codeSelfProvisionsRegistration)(code);
358115
+ const requireCreds = authPlan.needsLoginCreds && !legacyHeaderBypass && !isHallucinationShape && !selfProvisioningRegisterTest;
357945
358116
  if (requireCreds && !run2.testVariables?.["TEST_USER_EMAIL"]?.trim()) {
357946
358117
  preflightError = "Pre-flight failed: Missing TEST_USER_EMAIL. Tests that log in (tagged @auth, @needs-auth, @api, @auth-cookie-state, @auth-login-cookie, or @auth-login-bearer) require login credentials.";
357947
358118
  } else if (requireCreds && !run2.testVariables?.["TEST_USER_PASSWORD"]?.trim()) {
@@ -358844,6 +359015,20 @@ ${finalVerifyResult.logs ?? ""}`;
358844
359015
  { ...input, actor: "ai-explorer" },
358845
359016
  run2.claimEpoch
358846
359017
  );
359018
+ if (ctx.inboxBroker?.address) {
359019
+ ctx.inboxBrokerRead = async (op, payload) => {
359020
+ const res = await fetch(`${opts.serverUrl}/api/runner/inbox/read`, {
359021
+ method: "POST",
359022
+ headers: { ...headers, "Content-Type": "application/json" },
359023
+ body: JSON.stringify({ runId: run2.runId, op, payload })
359024
+ });
359025
+ if (!res.ok) {
359026
+ const detail = await res.text().catch(() => "");
359027
+ throw new Error(`inbox broker ${op} failed: HTTP ${res.status}${detail ? ` \u2014 ${detail.slice(0, 200)}` : ""}`);
359028
+ }
359029
+ return (await res.json()).value ?? null;
359030
+ };
359031
+ }
358847
359032
  log.info(`Discovery (${ctx.mode}) on ${ctx.baseUrl}`);
358848
359033
  const { push: pushAudit, drain: drainAudit } = createAuditFlusher(
358849
359034
  `${opts.serverUrl}/api/runner/runs/${run2.runId}/ai-audit-batch`,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@validate.qa/runner",
3
- "version": "1.0.58",
3
+ "version": "1.0.60",
4
4
  "description": "validate local test runner - execute Playwright tests on your machine, connected to validate.qa cloud.",
5
5
  "bin": {
6
6
  "validate-runner": "dist/cli.js"