@validate.qa/runner 1.0.58 → 1.0.59

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 +112 -33
  2. package/dist/cli.mjs +112 -33
  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;
@@ -73383,7 +73381,8 @@ var require_inbox_tools = __commonJS({
73383
73381
  // Captured at provision (needs a live reader); 0 = use the sinceMs floor.
73384
73382
  sinceUid: 0,
73385
73383
  sinceUidValidity: 0,
73386
- knownLinks: /* @__PURE__ */ new Set()
73384
+ knownLinks: /* @__PURE__ */ new Set(),
73385
+ demoteFilterMismatch: opts.demoteFilterMismatch ?? false
73387
73386
  };
73388
73387
  }
73389
73388
  exports2.PROVISION_IDENTITY_TOOL = {
@@ -73571,6 +73570,7 @@ var require_inbox_tools = __commonJS({
73571
73570
  sinceUidValidity: ctx.state.sinceUidValidity,
73572
73571
  fromMatch: asStr(args.senderMatch),
73573
73572
  subjectMatch: asStr(args.subjectMatch),
73573
+ demoteFilterMismatch: ctx.state.demoteFilterMismatch,
73574
73574
  limit: 10
73575
73575
  });
73576
73576
  return ok({
@@ -73595,6 +73595,7 @@ var require_inbox_tools = __commonJS({
73595
73595
  sinceUidValidity: ctx.state.sinceUidValidity,
73596
73596
  fromMatch: asStr(args.senderMatch),
73597
73597
  subjectMatch: asStr(args.subjectMatch),
73598
+ demoteFilterMismatch: ctx.state.demoteFilterMismatch,
73598
73599
  maxWaitMs: maxWaitSeconds * 1e3,
73599
73600
  stats
73600
73601
  });
@@ -73741,7 +73742,7 @@ var require_inbox_tools = __commonJS({
73741
73742
  const u = new URL(raw);
73742
73743
  if (u.protocol !== "http:" && u.protocol !== "https:")
73743
73744
  return false;
73744
- host = u.hostname.toLowerCase().replace(/^\[|\]$/g, "");
73745
+ host = u.hostname.toLowerCase().replace(/^\[|\]$/g, "").replace(/\.+$/, "");
73745
73746
  } catch {
73746
73747
  return false;
73747
73748
  }
@@ -73757,7 +73758,7 @@ var require_inbox_tools = __commonJS({
73757
73758
  const dotted = host.match(/(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/);
73758
73759
  if (dotted && !ipv4IsPublic(dotted[1]))
73759
73760
  return false;
73760
- const mapped = host.match(/^::ffff:([0-9a-f]{1,4}):([0-9a-f]{1,4})$/);
73761
+ const mapped = host.match(/^::(?:ffff:)?([0-9a-f]{1,4}):([0-9a-f]{1,4})$/);
73761
73762
  if (mapped) {
73762
73763
  const hi = parseInt(mapped[1], 16);
73763
73764
  const lo = parseInt(mapped[2], 16);
@@ -86418,6 +86419,8 @@ var require_inbox_stamp = __commonJS({
86418
86419
  exports2.INBOX_HELPER_TOKEN_RE = exports2.INBOX_HELPER_NAME = exports2.INBOX_REGION_RE = exports2.INBOX_MARKER_VERSION = void 0;
86419
86420
  exports2.codeUsesInboxHelper = codeUsesInboxHelper;
86420
86421
  exports2.stripInboxRegions = stripInboxRegions;
86422
+ exports2.codeUsesTestInboxIdentity = codeUsesTestInboxIdentity;
86423
+ exports2.codeSelfProvisionsRegistration = codeSelfProvisionsRegistration2;
86421
86424
  exports2.renderInboxFn = renderInboxFn;
86422
86425
  exports2.upsertInboxBlock = upsertInboxBlock;
86423
86426
  var auth_recipe_js_1 = require_auth_recipe();
@@ -86432,12 +86435,54 @@ var require_inbox_stamp = __commonJS({
86432
86435
  return false;
86433
86436
  return exports2.INBOX_HELPER_TOKEN_RE.test(code) || /VALIDATE_QA_INBOX/.test(code);
86434
86437
  }
86438
+ var INBOX_REGION_START = "// >>> VALIDATE_QA_INBOX";
86439
+ var INBOX_REGION_END = "// <<< VALIDATE_QA_INBOX";
86435
86440
  function stripInboxRegions(code) {
86436
- return code.replace(exports2.INBOX_REGION_RE, "");
86441
+ if (!code || code.indexOf(INBOX_REGION_START) === -1)
86442
+ return code;
86443
+ let out = "";
86444
+ let i = 0;
86445
+ while (i < code.length) {
86446
+ const start = code.indexOf(INBOX_REGION_START, i);
86447
+ if (start === -1) {
86448
+ out += code.slice(i);
86449
+ break;
86450
+ }
86451
+ const end = code.indexOf(INBOX_REGION_END, start + INBOX_REGION_START.length);
86452
+ if (end === -1) {
86453
+ out += code.slice(i);
86454
+ break;
86455
+ }
86456
+ let lineEnd = code.indexOf("\n", end);
86457
+ lineEnd = lineEnd === -1 ? code.length : lineEnd + 1;
86458
+ out += code.slice(i, start);
86459
+ i = lineEnd;
86460
+ }
86461
+ return out;
86462
+ }
86463
+ var TEST_INBOX_IDENTITY_RE = /VQA_TEST_INBOX_EMAIL|VQA_TEST_ACCOUNT_PASSWORD/;
86464
+ function codeUsesTestInboxIdentity(code) {
86465
+ if (!code)
86466
+ return false;
86467
+ return TEST_INBOX_IDENTITY_RE.test(stripInboxRegions(code));
86468
+ }
86469
+ function codeSelfProvisionsRegistration2(code) {
86470
+ return codeUsesTestInboxIdentity(code);
86437
86471
  }
86438
86472
  function countInboxRegions(code) {
86439
- const m = code.match(exports2.INBOX_REGION_RE);
86440
- return m ? m.length : 0;
86473
+ let count = 0;
86474
+ let i = 0;
86475
+ while (i < code.length) {
86476
+ const start = code.indexOf(INBOX_REGION_START, i);
86477
+ if (start === -1)
86478
+ break;
86479
+ const end = code.indexOf(INBOX_REGION_END, start + INBOX_REGION_START.length);
86480
+ if (end === -1)
86481
+ break;
86482
+ count++;
86483
+ i = end + INBOX_REGION_END.length;
86484
+ }
86485
+ return count;
86441
86486
  }
86442
86487
  function renderInboxFn() {
86443
86488
  const lines = [
@@ -86531,7 +86576,12 @@ var require_test_inbox_broker = __commonJS({
86531
86576
  return { found: true, code, link, subject: msg.subject, from: msg.from };
86532
86577
  }
86533
86578
  async function startTestInboxBroker(opts) {
86534
- const identity = mintTestRunInboxIdentity(opts.config, opts);
86579
+ const executionNonce = (0, node_crypto_1.randomBytes)(4).toString("hex");
86580
+ const identity = mintTestRunInboxIdentity(opts.config, {
86581
+ baseUrl: opts.baseUrl,
86582
+ projectId: opts.projectId,
86583
+ runId: `${opts.runId}#${executionNonce}`
86584
+ });
86535
86585
  const reader = new verification_inbox_js_1.VerificationInboxReader(opts.config);
86536
86586
  const sinceMs = Date.now();
86537
86587
  let sinceUid = 0;
@@ -86571,6 +86621,12 @@ var require_test_inbox_broker = __commonJS({
86571
86621
  sinceUidValidity,
86572
86622
  maxWaitMs: timeoutMs,
86573
86623
  require: require2,
86624
+ // The plus-tag recipient is unique to this run, so an unexpected ESP
86625
+ // sender is still this run's mail — demote, don't drop.
86626
+ demoteFilterMismatch: true,
86627
+ // Don't let a private/internal link end a `require:'link'` wait early —
86628
+ // keep polling for a public one (SSRF parity with the post-wait check).
86629
+ linkAcceptable: inbox_tools_js_1.isPublicHttpUrl,
86574
86630
  stats
86575
86631
  });
86576
86632
  const publicLink = msg && msg.link && (0, inbox_tools_js_1.isPublicHttpUrl)(msg.link) ? msg.link : null;
@@ -86705,7 +86761,8 @@ var require_playwright_native = __commonJS({
86705
86761
  runDir = (0, path_1.join)(RUNS_DIR, (0, crypto_1.randomUUID)());
86706
86762
  await (0, promises_1.mkdir)(runDir, { recursive: true });
86707
86763
  const isApiTest2 = playwrightCode.includes("@api") || playwrightCode.includes("{ request }") && !playwrightCode.includes("{ page");
86708
- const usesInboxHelper = !isApiTest2 && (0, inbox_stamp_js_1.codeUsesInboxHelper)(playwrightCode);
86764
+ const usesRealInboxWait = !isApiTest2 && (0, inbox_stamp_js_1.codeUsesInboxHelper)(playwrightCode);
86765
+ const selfProvisionsRegistration = !isApiTest2 && (0, inbox_stamp_js_1.codeSelfProvisionsRegistration)(playwrightCode);
86709
86766
  const effectiveStandingMode = isApiTest2 ? authStandingMode ?? "legacy-if-configured" : "none";
86710
86767
  const resolvedExtraHeaders = (0, api_auth_headers_js_1.resolveApiAuthHeaders)({
86711
86768
  explicit: extraHttpHeaders,
@@ -86952,7 +87009,7 @@ test.afterEach(async ({ page }, testInfo) => {
86952
87009
  module.exports = {
86953
87010
  testDir: ${JSON.stringify(absTestDir)},
86954
87011
  outputDir: ${JSON.stringify(absOutputDir)},
86955
- timeout: ${usesInboxHelper ? 24e4 : 6e4},
87012
+ timeout: ${usesRealInboxWait ? 24e4 : 6e4},
86956
87013
  retries: 0,
86957
87014
  use: {
86958
87015
  baseURL: ${JSON.stringify(baseUrl)},
@@ -86978,7 +87035,7 @@ module.exports = {
86978
87035
  const isolation = await (0, chromium_isolation_js_1.createChromiumIsolation)(runDir);
86979
87036
  const processClaimEpoch = Number(process.env.CLAIM_EPOCH);
86980
87037
  const callbackClaimEpoch = Number.isSafeInteger(validateContext?.claimEpoch) ? validateContext?.claimEpoch : Number.isSafeInteger(processClaimEpoch) && processClaimEpoch >= 0 ? processClaimEpoch : void 0;
86981
- if (usesInboxHelper && validateContext?.runId) {
87038
+ if (selfProvisionsRegistration && validateContext?.runId) {
86982
87039
  const inboxConfig = (0, verification_inbox_js_1.loadVerificationInboxConfig)();
86983
87040
  if (!inboxConfig) {
86984
87041
  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 +87053,8 @@ module.exports = {
86996
87053
  logs2.push(`\u26A0 Inbox broker failed to start: ${error3 instanceof Error ? error3.message : String(error3)}`);
86997
87054
  }
86998
87055
  }
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");
87056
+ } else if (selfProvisionsRegistration) {
87057
+ 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
87058
  }
87002
87059
  if (validateContext?.runId && validateContext.serverUrl && validateContext.authHeader) {
87003
87060
  try {
@@ -87038,16 +87095,20 @@ module.exports = {
87038
87095
  ...process.env.SHARED_AUTH_INJECT ? { SHARED_AUTH_INJECT: process.env.SHARED_AUTH_INJECT } : {},
87039
87096
  // Register-and-verify tests: the run's minted registration identity. An
87040
87097
  // 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() : {}
87098
+ // which stays in this parent (test-inbox-broker.ts). Injected whenever the
87099
+ // broker started, NOT gated on the callback proxy: a signup that registers
87100
+ // with this identity but needs no email verification uses the env yet never
87101
+ // touches the proxy — gating on the proxy left it with undefined creds. A
87102
+ // helper test still needs the proxy, and simply fails as CONFIG_ISSUE
87103
+ // without it; leaking the throwaway address/password to that child is inert.
87104
+ ...inboxBroker ? inboxBroker.childEnv() : {}
87044
87105
  };
87045
87106
  delete childTestVariables.API_AUTH_HEADERS;
87046
87107
  logs2.push("\u{1F680} Spawning playwright test...");
87047
87108
  const stopLiveBrowserPolling = liveBrowserStatePath && liveBrowserHandle ? startLiveBrowserStatePolling(liveBrowserStatePath, liveBrowserHandle, onLiveBrowserSnapshot) : null;
87048
87109
  let playResult;
87049
87110
  try {
87050
- playResult = await runPlaywright(configPath, childTestVariables, trustedRuntimeEnv, usesInboxHelper ? 3e5 : void 0);
87111
+ playResult = await runPlaywright(configPath, childTestVariables, trustedRuntimeEnv, usesRealInboxWait ? 3e5 : void 0);
87051
87112
  } finally {
87052
87113
  await stopLiveBrowserPolling?.();
87053
87114
  }
@@ -94799,7 +94860,7 @@ var require_discover_generator = __commonJS({
94799
94860
  var test_inbox_broker_js_1 = require_test_inbox_broker();
94800
94861
  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
94862
  function scenarioLooksLikeRegistration(scenario) {
94802
- const hay = `${scenario.name ?? ""} ${scenario.description ?? ""} ${scenario.entryRoute ?? ""} ${(scenario.targetPages ?? []).join(" ")}`;
94863
+ const hay = `${scenario.name ?? ""} ${scenario.goal ?? ""} ${scenario.description ?? ""} ${scenario.entryRoute ?? ""} ${(scenario.targetPages ?? []).join(" ")}`;
94803
94864
  return REGISTER_SCENARIO_RE.test(hay);
94804
94865
  }
94805
94866
  function buildEmailVerifyGenBlock(genEmail, genPassword) {
@@ -97752,7 +97813,7 @@ ${tailBlock}`;
97752
97813
  const genEmail = (0, verification_inbox_js_1.applyPlusTag)(inboxGenConfig.address, genTag);
97753
97814
  const genPassword = (0, verification_inbox_js_1.deriveRegistrationPassword)(genEmail);
97754
97815
  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 });
97816
+ genInboxState = (0, inbox_tools_js_1.createInboxRunState)(inboxGenConfig, { tag: genTag, passwordKey: test_inbox_broker_js_1.TEST_INBOX_PASSWORD_ENV, demoteFilterMismatch: true });
97756
97817
  genInboxCredentials = { ...credentials, [test_inbox_broker_js_1.TEST_INBOX_EMAIL_ENV]: genEmail, [test_inbox_broker_js_1.TEST_INBOX_PASSWORD_ENV]: genPassword };
97757
97818
  genInboxSecret = genPassword;
97758
97819
  openaiTools.push(...inbox_tools_js_1.INBOX_TOOLS);
@@ -98314,6 +98375,13 @@ Do NOT assert that the button/tab/heading you interacted with is merely visible
98314
98375
  logs2.push(` Strength gate: block persists after revision \u2014 tagged @needs-review (proves no outcome)`);
98315
98376
  }
98316
98377
  }
98378
+ const finalSelfProvisions = (0, inbox_stamp_js_1.codeSelfProvisionsRegistration)(result.playwrightCode);
98379
+ if (finalSelfProvisions) {
98380
+ if (!result.tags.includes("@email-verify"))
98381
+ result.tags.push("@email-verify");
98382
+ } else if (inboxGenConfig) {
98383
+ 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).`);
98384
+ }
98317
98385
  const elapsed = Date.now() - startTime;
98318
98386
  logs2.push(` Scenario test generated in ${iteration} iterations (${elapsed}ms, ${verifyCallCount} verify calls)`);
98319
98387
  } else {
@@ -349882,9 +349950,9 @@ var require_dist2 = __commonJS({
349882
349950
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p)) __createBinding(exports3, m, p);
349883
349951
  };
349884
349952
  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;
349953
+ 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;
349954
+ 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;
349955
+ 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
349956
  __exportStar(require_ai_provider(), exports2);
349889
349957
  __exportStar(require_mobile_types(), exports2);
349890
349958
  __exportStar(require_mobile_source_parser(), exports2);
@@ -349975,6 +350043,16 @@ var require_dist2 = __commonJS({
349975
350043
  return grok_batch_healer_js_1.executeGrokPerBatchHeal;
349976
350044
  } });
349977
350045
  __exportStar(require_playwright_code(), exports2);
350046
+ var inbox_stamp_js_1 = require_inbox_stamp();
350047
+ Object.defineProperty(exports2, "codeSelfProvisionsRegistration", { enumerable: true, get: function() {
350048
+ return inbox_stamp_js_1.codeSelfProvisionsRegistration;
350049
+ } });
350050
+ Object.defineProperty(exports2, "codeUsesTestInboxIdentity", { enumerable: true, get: function() {
350051
+ return inbox_stamp_js_1.codeUsesTestInboxIdentity;
350052
+ } });
350053
+ Object.defineProperty(exports2, "codeUsesInboxHelper", { enumerable: true, get: function() {
350054
+ return inbox_stamp_js_1.codeUsesInboxHelper;
350055
+ } });
349978
350056
  __exportStar(require_playwright_native(), exports2);
349979
350057
  __exportStar(require_regression_runner(), exports2);
349980
350058
  __exportStar(require_snapshot_parser(), exports2);
@@ -350304,7 +350382,7 @@ var require_package4 = __commonJS({
350304
350382
  "package.json"(exports2, module2) {
350305
350383
  module2.exports = {
350306
350384
  name: "@validate.qa/runner",
350307
- version: "1.0.58",
350385
+ version: "1.0.59",
350308
350386
  description: "validate local test runner - execute Playwright tests on your machine, connected to validate.qa cloud.",
350309
350387
  bin: {
350310
350388
  "validate-runner": "dist/cli.js"
@@ -357933,7 +358011,8 @@ async function executeRun(run2, opts, headers, requestLiveBrowserHeartbeat = ()
357933
358011
  const codeUsesCreds = codeProvided && /TEST_USER_EMAIL|TEST_USER_PASSWORD|__vqaLogin/.test(code);
357934
358012
  const tags = Array.isArray(run2.tags) ? run2.tags : [];
357935
358013
  const isHallucinationShape = codeProvided && !codeUsesCreds && tags.includes("@inline-login") && !tags.includes("@api");
357936
- const requireCreds = authPlan.needsLoginCreds && !legacyHeaderBypass && !isHallucinationShape;
358014
+ const selfProvisioningRegisterTest = codeProvided && !codeUsesCreds && tags.includes("@email-verify") && (0, import_runner_core13.codeSelfProvisionsRegistration)(code);
358015
+ const requireCreds = authPlan.needsLoginCreds && !legacyHeaderBypass && !isHallucinationShape && !selfProvisioningRegisterTest;
357937
358016
  if (requireCreds && !run2.testVariables?.["TEST_USER_EMAIL"]?.trim()) {
357938
358017
  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
358018
  } else if (requireCreds && !run2.testVariables?.["TEST_USER_PASSWORD"]?.trim()) {
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;
@@ -73388,7 +73386,8 @@ var require_inbox_tools = __commonJS({
73388
73386
  // Captured at provision (needs a live reader); 0 = use the sinceMs floor.
73389
73387
  sinceUid: 0,
73390
73388
  sinceUidValidity: 0,
73391
- knownLinks: /* @__PURE__ */ new Set()
73389
+ knownLinks: /* @__PURE__ */ new Set(),
73390
+ demoteFilterMismatch: opts.demoteFilterMismatch ?? false
73392
73391
  };
73393
73392
  }
73394
73393
  exports.PROVISION_IDENTITY_TOOL = {
@@ -73576,6 +73575,7 @@ var require_inbox_tools = __commonJS({
73576
73575
  sinceUidValidity: ctx.state.sinceUidValidity,
73577
73576
  fromMatch: asStr(args.senderMatch),
73578
73577
  subjectMatch: asStr(args.subjectMatch),
73578
+ demoteFilterMismatch: ctx.state.demoteFilterMismatch,
73579
73579
  limit: 10
73580
73580
  });
73581
73581
  return ok({
@@ -73600,6 +73600,7 @@ var require_inbox_tools = __commonJS({
73600
73600
  sinceUidValidity: ctx.state.sinceUidValidity,
73601
73601
  fromMatch: asStr(args.senderMatch),
73602
73602
  subjectMatch: asStr(args.subjectMatch),
73603
+ demoteFilterMismatch: ctx.state.demoteFilterMismatch,
73603
73604
  maxWaitMs: maxWaitSeconds * 1e3,
73604
73605
  stats
73605
73606
  });
@@ -73746,7 +73747,7 @@ var require_inbox_tools = __commonJS({
73746
73747
  const u = new URL(raw);
73747
73748
  if (u.protocol !== "http:" && u.protocol !== "https:")
73748
73749
  return false;
73749
- host = u.hostname.toLowerCase().replace(/^\[|\]$/g, "");
73750
+ host = u.hostname.toLowerCase().replace(/^\[|\]$/g, "").replace(/\.+$/, "");
73750
73751
  } catch {
73751
73752
  return false;
73752
73753
  }
@@ -73762,7 +73763,7 @@ var require_inbox_tools = __commonJS({
73762
73763
  const dotted = host.match(/(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/);
73763
73764
  if (dotted && !ipv4IsPublic(dotted[1]))
73764
73765
  return false;
73765
- const mapped = host.match(/^::ffff:([0-9a-f]{1,4}):([0-9a-f]{1,4})$/);
73766
+ const mapped = host.match(/^::(?:ffff:)?([0-9a-f]{1,4}):([0-9a-f]{1,4})$/);
73766
73767
  if (mapped) {
73767
73768
  const hi = parseInt(mapped[1], 16);
73768
73769
  const lo = parseInt(mapped[2], 16);
@@ -86423,6 +86424,8 @@ var require_inbox_stamp = __commonJS({
86423
86424
  exports.INBOX_HELPER_TOKEN_RE = exports.INBOX_HELPER_NAME = exports.INBOX_REGION_RE = exports.INBOX_MARKER_VERSION = void 0;
86424
86425
  exports.codeUsesInboxHelper = codeUsesInboxHelper;
86425
86426
  exports.stripInboxRegions = stripInboxRegions;
86427
+ exports.codeUsesTestInboxIdentity = codeUsesTestInboxIdentity;
86428
+ exports.codeSelfProvisionsRegistration = codeSelfProvisionsRegistration2;
86426
86429
  exports.renderInboxFn = renderInboxFn;
86427
86430
  exports.upsertInboxBlock = upsertInboxBlock;
86428
86431
  var auth_recipe_js_1 = require_auth_recipe();
@@ -86437,12 +86440,54 @@ var require_inbox_stamp = __commonJS({
86437
86440
  return false;
86438
86441
  return exports.INBOX_HELPER_TOKEN_RE.test(code) || /VALIDATE_QA_INBOX/.test(code);
86439
86442
  }
86443
+ var INBOX_REGION_START = "// >>> VALIDATE_QA_INBOX";
86444
+ var INBOX_REGION_END = "// <<< VALIDATE_QA_INBOX";
86440
86445
  function stripInboxRegions(code) {
86441
- return code.replace(exports.INBOX_REGION_RE, "");
86446
+ if (!code || code.indexOf(INBOX_REGION_START) === -1)
86447
+ return code;
86448
+ let out = "";
86449
+ let i = 0;
86450
+ while (i < code.length) {
86451
+ const start = code.indexOf(INBOX_REGION_START, i);
86452
+ if (start === -1) {
86453
+ out += code.slice(i);
86454
+ break;
86455
+ }
86456
+ const end = code.indexOf(INBOX_REGION_END, start + INBOX_REGION_START.length);
86457
+ if (end === -1) {
86458
+ out += code.slice(i);
86459
+ break;
86460
+ }
86461
+ let lineEnd = code.indexOf("\n", end);
86462
+ lineEnd = lineEnd === -1 ? code.length : lineEnd + 1;
86463
+ out += code.slice(i, start);
86464
+ i = lineEnd;
86465
+ }
86466
+ return out;
86467
+ }
86468
+ var TEST_INBOX_IDENTITY_RE = /VQA_TEST_INBOX_EMAIL|VQA_TEST_ACCOUNT_PASSWORD/;
86469
+ function codeUsesTestInboxIdentity(code) {
86470
+ if (!code)
86471
+ return false;
86472
+ return TEST_INBOX_IDENTITY_RE.test(stripInboxRegions(code));
86473
+ }
86474
+ function codeSelfProvisionsRegistration2(code) {
86475
+ return codeUsesTestInboxIdentity(code);
86442
86476
  }
86443
86477
  function countInboxRegions(code) {
86444
- const m = code.match(exports.INBOX_REGION_RE);
86445
- return m ? m.length : 0;
86478
+ let count = 0;
86479
+ let i = 0;
86480
+ while (i < code.length) {
86481
+ const start = code.indexOf(INBOX_REGION_START, i);
86482
+ if (start === -1)
86483
+ break;
86484
+ const end = code.indexOf(INBOX_REGION_END, start + INBOX_REGION_START.length);
86485
+ if (end === -1)
86486
+ break;
86487
+ count++;
86488
+ i = end + INBOX_REGION_END.length;
86489
+ }
86490
+ return count;
86446
86491
  }
86447
86492
  function renderInboxFn() {
86448
86493
  const lines = [
@@ -86536,7 +86581,12 @@ var require_test_inbox_broker = __commonJS({
86536
86581
  return { found: true, code, link, subject: msg.subject, from: msg.from };
86537
86582
  }
86538
86583
  async function startTestInboxBroker(opts) {
86539
- const identity = mintTestRunInboxIdentity(opts.config, opts);
86584
+ const executionNonce = (0, node_crypto_1.randomBytes)(4).toString("hex");
86585
+ const identity = mintTestRunInboxIdentity(opts.config, {
86586
+ baseUrl: opts.baseUrl,
86587
+ projectId: opts.projectId,
86588
+ runId: `${opts.runId}#${executionNonce}`
86589
+ });
86540
86590
  const reader = new verification_inbox_js_1.VerificationInboxReader(opts.config);
86541
86591
  const sinceMs = Date.now();
86542
86592
  let sinceUid = 0;
@@ -86576,6 +86626,12 @@ var require_test_inbox_broker = __commonJS({
86576
86626
  sinceUidValidity,
86577
86627
  maxWaitMs: timeoutMs,
86578
86628
  require: require2,
86629
+ // The plus-tag recipient is unique to this run, so an unexpected ESP
86630
+ // sender is still this run's mail — demote, don't drop.
86631
+ demoteFilterMismatch: true,
86632
+ // Don't let a private/internal link end a `require:'link'` wait early —
86633
+ // keep polling for a public one (SSRF parity with the post-wait check).
86634
+ linkAcceptable: inbox_tools_js_1.isPublicHttpUrl,
86579
86635
  stats
86580
86636
  });
86581
86637
  const publicLink = msg && msg.link && (0, inbox_tools_js_1.isPublicHttpUrl)(msg.link) ? msg.link : null;
@@ -86710,7 +86766,8 @@ var require_playwright_native = __commonJS({
86710
86766
  runDir = (0, path_1.join)(RUNS_DIR, (0, crypto_1.randomUUID)());
86711
86767
  await (0, promises_1.mkdir)(runDir, { recursive: true });
86712
86768
  const isApiTest2 = playwrightCode.includes("@api") || playwrightCode.includes("{ request }") && !playwrightCode.includes("{ page");
86713
- const usesInboxHelper = !isApiTest2 && (0, inbox_stamp_js_1.codeUsesInboxHelper)(playwrightCode);
86769
+ const usesRealInboxWait = !isApiTest2 && (0, inbox_stamp_js_1.codeUsesInboxHelper)(playwrightCode);
86770
+ const selfProvisionsRegistration = !isApiTest2 && (0, inbox_stamp_js_1.codeSelfProvisionsRegistration)(playwrightCode);
86714
86771
  const effectiveStandingMode = isApiTest2 ? authStandingMode ?? "legacy-if-configured" : "none";
86715
86772
  const resolvedExtraHeaders = (0, api_auth_headers_js_1.resolveApiAuthHeaders)({
86716
86773
  explicit: extraHttpHeaders,
@@ -86957,7 +87014,7 @@ test.afterEach(async ({ page }, testInfo) => {
86957
87014
  module.exports = {
86958
87015
  testDir: ${JSON.stringify(absTestDir)},
86959
87016
  outputDir: ${JSON.stringify(absOutputDir)},
86960
- timeout: ${usesInboxHelper ? 24e4 : 6e4},
87017
+ timeout: ${usesRealInboxWait ? 24e4 : 6e4},
86961
87018
  retries: 0,
86962
87019
  use: {
86963
87020
  baseURL: ${JSON.stringify(baseUrl)},
@@ -86983,7 +87040,7 @@ module.exports = {
86983
87040
  const isolation = await (0, chromium_isolation_js_1.createChromiumIsolation)(runDir);
86984
87041
  const processClaimEpoch = Number(process.env.CLAIM_EPOCH);
86985
87042
  const callbackClaimEpoch = Number.isSafeInteger(validateContext?.claimEpoch) ? validateContext?.claimEpoch : Number.isSafeInteger(processClaimEpoch) && processClaimEpoch >= 0 ? processClaimEpoch : void 0;
86986
- if (usesInboxHelper && validateContext?.runId) {
87043
+ if (selfProvisionsRegistration && validateContext?.runId) {
86987
87044
  const inboxConfig = (0, verification_inbox_js_1.loadVerificationInboxConfig)();
86988
87045
  if (!inboxConfig) {
86989
87046
  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 +87058,8 @@ module.exports = {
87001
87058
  logs2.push(`\u26A0 Inbox broker failed to start: ${error3 instanceof Error ? error3.message : String(error3)}`);
87002
87059
  }
87003
87060
  }
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");
87061
+ } else if (selfProvisionsRegistration) {
87062
+ 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
87063
  }
87007
87064
  if (validateContext?.runId && validateContext.serverUrl && validateContext.authHeader) {
87008
87065
  try {
@@ -87043,16 +87100,20 @@ module.exports = {
87043
87100
  ...process.env.SHARED_AUTH_INJECT ? { SHARED_AUTH_INJECT: process.env.SHARED_AUTH_INJECT } : {},
87044
87101
  // Register-and-verify tests: the run's minted registration identity. An
87045
87102
  // 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() : {}
87103
+ // which stays in this parent (test-inbox-broker.ts). Injected whenever the
87104
+ // broker started, NOT gated on the callback proxy: a signup that registers
87105
+ // with this identity but needs no email verification uses the env yet never
87106
+ // touches the proxy — gating on the proxy left it with undefined creds. A
87107
+ // helper test still needs the proxy, and simply fails as CONFIG_ISSUE
87108
+ // without it; leaking the throwaway address/password to that child is inert.
87109
+ ...inboxBroker ? inboxBroker.childEnv() : {}
87049
87110
  };
87050
87111
  delete childTestVariables.API_AUTH_HEADERS;
87051
87112
  logs2.push("\u{1F680} Spawning playwright test...");
87052
87113
  const stopLiveBrowserPolling = liveBrowserStatePath && liveBrowserHandle ? startLiveBrowserStatePolling(liveBrowserStatePath, liveBrowserHandle, onLiveBrowserSnapshot) : null;
87053
87114
  let playResult;
87054
87115
  try {
87055
- playResult = await runPlaywright(configPath, childTestVariables, trustedRuntimeEnv, usesInboxHelper ? 3e5 : void 0);
87116
+ playResult = await runPlaywright(configPath, childTestVariables, trustedRuntimeEnv, usesRealInboxWait ? 3e5 : void 0);
87056
87117
  } finally {
87057
87118
  await stopLiveBrowserPolling?.();
87058
87119
  }
@@ -94804,7 +94865,7 @@ var require_discover_generator = __commonJS({
94804
94865
  var test_inbox_broker_js_1 = require_test_inbox_broker();
94805
94866
  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
94867
  function scenarioLooksLikeRegistration(scenario) {
94807
- const hay = `${scenario.name ?? ""} ${scenario.description ?? ""} ${scenario.entryRoute ?? ""} ${(scenario.targetPages ?? []).join(" ")}`;
94868
+ const hay = `${scenario.name ?? ""} ${scenario.goal ?? ""} ${scenario.description ?? ""} ${scenario.entryRoute ?? ""} ${(scenario.targetPages ?? []).join(" ")}`;
94808
94869
  return REGISTER_SCENARIO_RE.test(hay);
94809
94870
  }
94810
94871
  function buildEmailVerifyGenBlock(genEmail, genPassword) {
@@ -97757,7 +97818,7 @@ ${tailBlock}`;
97757
97818
  const genEmail = (0, verification_inbox_js_1.applyPlusTag)(inboxGenConfig.address, genTag);
97758
97819
  const genPassword = (0, verification_inbox_js_1.deriveRegistrationPassword)(genEmail);
97759
97820
  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 });
97821
+ genInboxState = (0, inbox_tools_js_1.createInboxRunState)(inboxGenConfig, { tag: genTag, passwordKey: test_inbox_broker_js_1.TEST_INBOX_PASSWORD_ENV, demoteFilterMismatch: true });
97761
97822
  genInboxCredentials = { ...credentials, [test_inbox_broker_js_1.TEST_INBOX_EMAIL_ENV]: genEmail, [test_inbox_broker_js_1.TEST_INBOX_PASSWORD_ENV]: genPassword };
97762
97823
  genInboxSecret = genPassword;
97763
97824
  openaiTools.push(...inbox_tools_js_1.INBOX_TOOLS);
@@ -98319,6 +98380,13 @@ Do NOT assert that the button/tab/heading you interacted with is merely visible
98319
98380
  logs2.push(` Strength gate: block persists after revision \u2014 tagged @needs-review (proves no outcome)`);
98320
98381
  }
98321
98382
  }
98383
+ const finalSelfProvisions = (0, inbox_stamp_js_1.codeSelfProvisionsRegistration)(result.playwrightCode);
98384
+ if (finalSelfProvisions) {
98385
+ if (!result.tags.includes("@email-verify"))
98386
+ result.tags.push("@email-verify");
98387
+ } else if (inboxGenConfig) {
98388
+ 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).`);
98389
+ }
98322
98390
  const elapsed = Date.now() - startTime;
98323
98391
  logs2.push(` Scenario test generated in ${iteration} iterations (${elapsed}ms, ${verifyCallCount} verify calls)`);
98324
98392
  } else {
@@ -349887,9 +349955,9 @@ var require_dist2 = __commonJS({
349887
349955
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports2, p)) __createBinding(exports2, m, p);
349888
349956
  };
349889
349957
  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;
349958
+ 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;
349959
+ 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;
349960
+ 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
349961
  __exportStar(require_ai_provider(), exports);
349894
349962
  __exportStar(require_mobile_types(), exports);
349895
349963
  __exportStar(require_mobile_source_parser(), exports);
@@ -349980,6 +350048,16 @@ var require_dist2 = __commonJS({
349980
350048
  return grok_batch_healer_js_1.executeGrokPerBatchHeal;
349981
350049
  } });
349982
350050
  __exportStar(require_playwright_code(), exports);
350051
+ var inbox_stamp_js_1 = require_inbox_stamp();
350052
+ Object.defineProperty(exports, "codeSelfProvisionsRegistration", { enumerable: true, get: function() {
350053
+ return inbox_stamp_js_1.codeSelfProvisionsRegistration;
350054
+ } });
350055
+ Object.defineProperty(exports, "codeUsesTestInboxIdentity", { enumerable: true, get: function() {
350056
+ return inbox_stamp_js_1.codeUsesTestInboxIdentity;
350057
+ } });
350058
+ Object.defineProperty(exports, "codeUsesInboxHelper", { enumerable: true, get: function() {
350059
+ return inbox_stamp_js_1.codeUsesInboxHelper;
350060
+ } });
349983
350061
  __exportStar(require_playwright_native(), exports);
349984
350062
  __exportStar(require_regression_runner(), exports);
349985
350063
  __exportStar(require_snapshot_parser(), exports);
@@ -350309,7 +350387,7 @@ var require_package4 = __commonJS({
350309
350387
  "package.json"(exports, module) {
350310
350388
  module.exports = {
350311
350389
  name: "@validate.qa/runner",
350312
- version: "1.0.58",
350390
+ version: "1.0.59",
350313
350391
  description: "validate local test runner - execute Playwright tests on your machine, connected to validate.qa cloud.",
350314
350392
  bin: {
350315
350393
  "validate-runner": "dist/cli.js"
@@ -357941,7 +358019,8 @@ async function executeRun(run2, opts, headers, requestLiveBrowserHeartbeat = ()
357941
358019
  const codeUsesCreds = codeProvided && /TEST_USER_EMAIL|TEST_USER_PASSWORD|__vqaLogin/.test(code);
357942
358020
  const tags = Array.isArray(run2.tags) ? run2.tags : [];
357943
358021
  const isHallucinationShape = codeProvided && !codeUsesCreds && tags.includes("@inline-login") && !tags.includes("@api");
357944
- const requireCreds = authPlan.needsLoginCreds && !legacyHeaderBypass && !isHallucinationShape;
358022
+ const selfProvisioningRegisterTest = codeProvided && !codeUsesCreds && tags.includes("@email-verify") && (0, import_runner_core13.codeSelfProvisionsRegistration)(code);
358023
+ const requireCreds = authPlan.needsLoginCreds && !legacyHeaderBypass && !isHallucinationShape && !selfProvisioningRegisterTest;
357945
358024
  if (requireCreds && !run2.testVariables?.["TEST_USER_EMAIL"]?.trim()) {
357946
358025
  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
358026
  } else if (requireCreds && !run2.testVariables?.["TEST_USER_PASSWORD"]?.trim()) {
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.59",
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"