@validate.qa/runner 1.0.64 → 1.0.66

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 +193 -12
  2. package/dist/cli.mjs +193 -12
  3. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -3485,6 +3485,135 @@ var init_audit_pricing = __esm({
3485
3485
  }
3486
3486
  });
3487
3487
 
3488
+ // ../shared/dist/audit-grouping.js
3489
+ var GROUPABLE_CALL_TYPES, GROUP_LABELS, FLOW_PHASE_TYPES, FLOW_SERVER_TYPES, FLOW_PHASE_LABELS;
3490
+ var init_audit_grouping = __esm({
3491
+ "../shared/dist/audit-grouping.js"() {
3492
+ "use strict";
3493
+ GROUPABLE_CALL_TYPES = /* @__PURE__ */ new Set([
3494
+ "healIteration",
3495
+ "healOrchestrator",
3496
+ "generateRegressionSuite",
3497
+ "discoveryExplore",
3498
+ "surveyExplore",
3499
+ "featureExplore",
3500
+ "discoveryGenerate",
3501
+ "discoveryPlan",
3502
+ "discoveryGenerateSkeleton",
3503
+ "discoveryGenerateElementContext",
3504
+ "liveGenerate",
3505
+ "scenarioGenerate",
3506
+ "liveSuiteHeal",
3507
+ "captureIteration",
3508
+ "healAPITest",
3509
+ "generateAPITests",
3510
+ // Auth-prologue login-capture run (runLoginCaptureRun) — per-turn rows share a
3511
+ // groupId so they collapse into one "Login Capture" phase card on /audit.
3512
+ "authCapture",
3513
+ // Assistant chat — rounds of one conversation collapse into one card.
3514
+ "assistantChat"
3515
+ ]);
3516
+ GROUP_LABELS = {
3517
+ healIteration: "healSession",
3518
+ healOrchestrator: "healSession",
3519
+ healAPITest: "apiHealSession",
3520
+ generateRegressionSuite: "regressionSession",
3521
+ generateAPITests: "apiTestGenSession",
3522
+ discoveryExplore: "discoveryExploreSession",
3523
+ surveyExplore: "surveyExploreSession",
3524
+ featureExplore: "featureExploreSession",
3525
+ discoveryGenerate: "discoveryGenerateSession",
3526
+ discoveryGenerateSkeleton: "discoveryGenerateSession",
3527
+ discoveryGenerateElementContext: "discoveryGenerateSession",
3528
+ liveGenerate: "liveGenerateSession",
3529
+ scenarioGenerate: "scenarioGenerateSession",
3530
+ discoveryPlan: "discoveryPlanSession",
3531
+ liveSuiteHeal: "liveSuiteHealSession",
3532
+ captureIteration: "captureIterationSession",
3533
+ authCapture: "authCaptureSession",
3534
+ assistantChat: "assistantChatSession"
3535
+ };
3536
+ FLOW_PHASE_TYPES = /* @__PURE__ */ new Set([
3537
+ "surveyExploreSession",
3538
+ "featureExploreSession",
3539
+ "discoveryAIPlanner",
3540
+ "discoveryPlanSession",
3541
+ "scenarioGenerateSession",
3542
+ "liveGenerateSession",
3543
+ "discoveryGenerateSession",
3544
+ // Raw callTypes (for ungrouped single-turn entries like planner)
3545
+ "surveyExplore",
3546
+ "featureExplore",
3547
+ "discoveryPlan",
3548
+ "scenarioGenerate",
3549
+ "liveGenerate",
3550
+ "discoveryGenerate",
3551
+ // Planner repair / retry / strengthen-gate — the one-shot extra planner call
3552
+ // shares the base planner's discoveryFlowId, so it nests as its own phase
3553
+ // instead of dangling as a raw camelCase row.
3554
+ "discoveryAIPlannerRepair",
3555
+ "discoveryAIPlannerRetry",
3556
+ "discoveryAIPlannerStrengthenGate",
3557
+ // Deep-run feature analyst insight (one call per feature discovery).
3558
+ "featureInsight",
3559
+ // Discovery v2 Call-1-authoring pivot — per-test Call 2 spawns. Each session
3560
+ // has its OWN sessionId but shares the parent discoveryFlowId, so grouping by
3561
+ // flowId pulls them under the same Discovery Flow card. `Cleanup` is the
3562
+ // teardown sibling of Fix/Author and nests the same way.
3563
+ "discoveryCall2Fix",
3564
+ "discoveryCall2Author",
3565
+ "discoveryCall2Cleanup",
3566
+ // Auth-prologue login-capture run — grouped label + raw callType.
3567
+ "authCaptureSession",
3568
+ "authCapture"
3569
+ ]);
3570
+ FLOW_SERVER_TYPES = /* @__PURE__ */ new Set([
3571
+ "healthAnalysis",
3572
+ "apiSecurityAudit",
3573
+ "apiSecurityAuditVerify",
3574
+ "generateAPITests",
3575
+ "apiTestGenSession",
3576
+ "healAPITest",
3577
+ "apiHealSession",
3578
+ "healSession",
3579
+ "healIteration"
3580
+ ]);
3581
+ FLOW_PHASE_LABELS = {
3582
+ surveyExploreSession: "Survey Explore",
3583
+ featureExploreSession: "Feature Explore",
3584
+ discoveryAIPlanner: "Feature Analyst",
3585
+ discoveryAIPlannerRepair: "Planner Repair",
3586
+ discoveryAIPlannerRetry: "Planner Retry",
3587
+ discoveryAIPlannerStrengthenGate: "Planner Strengthen Gate",
3588
+ discoveryPlanSession: "Survey Planner",
3589
+ scenarioGenerateSession: "Scenario Gen",
3590
+ liveGenerateSession: "Live Browser Gen",
3591
+ discoveryGenerateSession: "Test Generation",
3592
+ surveyExplore: "Survey Explore",
3593
+ featureExplore: "Feature Explore",
3594
+ discoveryPlan: "Planner",
3595
+ scenarioGenerate: "Scenario Gen",
3596
+ liveGenerate: "Live Browser Gen",
3597
+ discoveryGenerate: "Test Generation",
3598
+ discoveryCall2Fix: "Call 2 Fix",
3599
+ discoveryCall2Author: "Call 2 Author",
3600
+ discoveryCall2Cleanup: "Call 2 Cleanup",
3601
+ featureInsight: "Feature Insight",
3602
+ healthAnalysis: "Health Analysis",
3603
+ apiSecurityAudit: "Security Audit",
3604
+ apiSecurityAuditVerify: "Security Verify",
3605
+ generateAPITests: "API Test Gen",
3606
+ apiTestGenSession: "API Test Gen",
3607
+ healAPITest: "API Test Heal",
3608
+ apiHealSession: "API Test Heal",
3609
+ healSession: "Heal Session",
3610
+ healIteration: "Heal",
3611
+ authCapture: "Login Capture",
3612
+ authCaptureSession: "Login Capture"
3613
+ };
3614
+ }
3615
+ });
3616
+
3488
3617
  // ../shared/dist/discovery-har-decision.js
3489
3618
  function decideHarPosted(response) {
3490
3619
  if (!response)
@@ -5850,6 +5979,11 @@ __export(dist_exports, {
5850
5979
  DEFAULT_UI_VARIANT: () => DEFAULT_UI_VARIANT,
5851
5980
  EMAIL_FROM_IDENTITIES: () => EMAIL_FROM_IDENTITIES,
5852
5981
  ENVIRONMENTAL_ERROR_PREFIXES: () => ENVIRONMENTAL_ERROR_PREFIXES,
5982
+ FLOW_PHASE_LABELS: () => FLOW_PHASE_LABELS,
5983
+ FLOW_PHASE_TYPES: () => FLOW_PHASE_TYPES,
5984
+ FLOW_SERVER_TYPES: () => FLOW_SERVER_TYPES,
5985
+ GROUPABLE_CALL_TYPES: () => GROUPABLE_CALL_TYPES,
5986
+ GROUP_LABELS: () => GROUP_LABELS,
5853
5987
  LEGACY_TTS_VOICE_ID_MAP: () => LEGACY_TTS_VOICE_ID_MAP,
5854
5988
  MAX_CREDIT_TOPUP_CENTS: () => MAX_CREDIT_TOPUP_CENTS,
5855
5989
  MAX_DEEPLINK_LENGTH: () => MAX_DEEPLINK_LENGTH,
@@ -6033,6 +6167,7 @@ var init_dist = __esm({
6033
6167
  init_mobile_deeplink();
6034
6168
  init_plans();
6035
6169
  init_audit_pricing();
6170
+ init_audit_grouping();
6036
6171
  init_discovery_har_decision();
6037
6172
  init_assertion_classifier();
6038
6173
  init_assertion_strength();
@@ -73489,6 +73624,7 @@ var require_inbox_tools = __commonJS({
73489
73624
  exports2.buildInboxPromptBlock = buildInboxPromptBlock;
73490
73625
  exports2.guardVerificationCodeFabrication = guardVerificationCodeFabrication;
73491
73626
  exports2.hasRegisterIntent = hasRegisterIntent;
73627
+ exports2.hasSignupTestIntent = hasSignupTestIntent;
73492
73628
  exports2.resolveInboxRegistration = resolveInboxRegistration;
73493
73629
  exports2.applyInboxRegistrationIdentity = applyInboxRegistrationIdentity;
73494
73630
  exports2.isThrowawayRegisterSeedEmail = isThrowawayRegisterSeedEmail;
@@ -74032,6 +74168,9 @@ This project asked to REGISTER a new account, but this runner CANNOT receive ema
74032
74168
  const v = variableContext.allTestVariables?.DISCOVERY_SHOULD_REGISTER ?? variableContext.publicTestVariables?.DISCOVERY_SHOULD_REGISTER ?? "";
74033
74169
  return String(v).trim().toLowerCase() === "true";
74034
74170
  }
74171
+ function hasSignupTestIntent(variableContext) {
74172
+ return variableContext?.allTestVariables?.DISCOVERY_ALLOW_SIGNUP_TESTS !== "false";
74173
+ }
74035
74174
  function resolveInboxRegistration(opts) {
74036
74175
  const config = (0, verification_inbox_js_1.loadVerificationInboxConfig)(opts.env ?? process.env);
74037
74176
  if (!config)
@@ -94980,6 +95119,8 @@ var require_discover_generator = __commonJS({
94980
95119
  Object.defineProperty(exports2, "__esModule", { value: true });
94981
95120
  exports2.MIN_BUG_DESCRIPTION_LENGTH = exports2.VALID_PLAYWRIGHT_GETBY_METHODS = exports2.BLOCKED_MCP_TOOLS_SCENARIO_GEN = void 0;
94982
95121
  exports2.scenarioLooksLikeRegistration = scenarioLooksLikeRegistration;
95122
+ exports2.signupFeatureTestingAllowed = signupFeatureTestingAllowed;
95123
+ exports2.scenarioTouchesSignupAuthSurface = scenarioTouchesSignupAuthSurface;
94983
95124
  exports2.filterMcpToolsForScenarioGen = filterMcpToolsForScenarioGen;
94984
95125
  exports2.detectScenarioSignals = detectScenarioSignals;
94985
95126
  exports2.scenarioStepsCoverAuth = scenarioStepsCoverAuth;
@@ -95067,6 +95208,19 @@ EMIT (the code you put in finish_generate) \u2014 do NOT hardcode the throwaway
95067
95208
  - Tag the test \`@email-verify\`. Emit EXACTLY ONE test() in this file (one registration per run).
95068
95209
  - End with a DURABLE assertion of the post-verification signed-in state (e.g. a Logout control, an account/dashboard landmark) in your OWN test body \u2014 the helper call is not itself a proof.`;
95069
95210
  }
95211
+ function signupFeatureTestingAllowed(credentials) {
95212
+ if (!(0, discovery_lint_flags_js_1.isTestgenEmailVerifyEnabled)() || !(0, verification_inbox_js_1.loadVerificationInboxConfig)())
95213
+ return false;
95214
+ return credentials?.DISCOVERY_ALLOW_SIGNUP_TESTS !== "false";
95215
+ }
95216
+ var SIGNUP_AUTH_ROUTE_RE = /\/(sign-?up|verify-?email|email-?verification|create-?account|confirm-?email)\b/i;
95217
+ function scenarioTouchesSignupAuthSurface(scenario, pages) {
95218
+ const routes = [scenario.entryRoute, ...scenario.targetPages ?? []].filter((r) => !!r);
95219
+ if (routes.some((r) => SIGNUP_AUTH_ROUTE_RE.test(r)))
95220
+ return true;
95221
+ const authRoutes = new Set(pages.filter((p) => (p.pageType ?? "").toUpperCase() === "AUTH").map((p) => p.route));
95222
+ return routes.some((r) => authRoutes.has(r));
95223
+ }
95070
95224
  exports2.BLOCKED_MCP_TOOLS_SCENARIO_GEN = /* @__PURE__ */ new Set([
95071
95225
  "browser_install",
95072
95226
  "browser_close",
@@ -98178,9 +98332,16 @@ ${tailBlock}`;
98178
98332
  extraAuthEvidence: !!opts?.recipe || hasConfiguredLoginCredentials(credentials)
98179
98333
  });
98180
98334
  const baseSkeletonHadRegression = tags.includes("@regression");
98335
+ const selfProvisioningSignupScenario = signupFeatureTestingAllowed(credentials) && scenarioLooksLikeRegistration(scenario) && scenarioTouchesSignupAuthSurface(scenario, siteMap.pages);
98336
+ if (selfProvisioningSignupScenario) {
98337
+ for (const prereqTag of ["@needs-auth", "@inline-login", "@auth-guarded"]) {
98338
+ const idx = tags.indexOf(prereqTag);
98339
+ if (idx !== -1)
98340
+ tags.splice(idx, 1);
98341
+ }
98342
+ }
98181
98343
  const hasVerifiedRecipe = !!opts?.recipe && tags.includes("@needs-auth");
98182
- const projectHasRegisterIntent = credentials?.DISCOVERY_SHOULD_REGISTER === "true";
98183
- const inboxGenConfig = (0, discovery_lint_flags_js_1.isTestgenEmailVerifyEnabled)() && projectHasRegisterIntent && !hasVerifiedRecipe && scenarioLooksLikeRegistration(scenario) ? (0, verification_inbox_js_1.loadVerificationInboxConfig)() : null;
98344
+ const inboxGenConfig = selfProvisioningSignupScenario ? (0, verification_inbox_js_1.loadVerificationInboxConfig)() : null;
98184
98345
  let genInboxState = null;
98185
98346
  let genInboxCredentials = credentials;
98186
98347
  let genInboxSecret = null;
@@ -99127,7 +99288,8 @@ Scenario: "${scenario.name}" (${scenario.type})`);
99127
99288
  } catch {
99128
99289
  }
99129
99290
  const recipe = authRecipe;
99130
- const replayLogin = shouldReplayAuthRecipe(scenario.targetPages, siteMap.pages, recipe);
99291
+ const selfProvisioningSignupScenario = signupFeatureTestingAllowed(credentials) && scenarioLooksLikeRegistration(scenario) && scenarioTouchesSignupAuthSurface(scenario, siteMap.pages);
99292
+ const replayLogin = !selfProvisioningSignupScenario && shouldReplayAuthRecipe(scenario.targetPages, siteMap.pages, recipe);
99131
99293
  let effectiveRecipe = null;
99132
99294
  if (replayLogin && recipe) {
99133
99295
  const planLeaks = findSensitiveLiteralLeaks(JSON.stringify(recipe.replayPlan ?? []), credentials);
@@ -99234,7 +99396,8 @@ Scenario: "${scenario.name}" (${scenario.type})`);
99234
99396
  return;
99235
99397
  }
99236
99398
  let effectiveRecipe = null;
99237
- if (shouldReplayAuthRecipe(scenario.targetPages, siteMap.pages, authRecipe) && authRecipe) {
99399
+ const selfProvisioningSignupScenario = signupFeatureTestingAllowed(credentials) && scenarioLooksLikeRegistration(scenario) && scenarioTouchesSignupAuthSurface(scenario, siteMap.pages);
99400
+ if (!selfProvisioningSignupScenario && shouldReplayAuthRecipe(scenario.targetPages, siteMap.pages, authRecipe) && authRecipe) {
99238
99401
  const planLeaks = findSensitiveLiteralLeaks(JSON.stringify(authRecipe.replayPlan ?? []), credentials);
99239
99402
  if (planLeaks.length > 0) {
99240
99403
  scenarioLogs.push(` Warning: login replay plan contains literal credential value(s) for ${planLeaks.join(", ")} \u2014 falling back to model-authored login for "${scenario.name}"`);
@@ -335035,6 +335198,7 @@ var require_discover_agent = __commonJS({
335035
335198
  var discover_ai_planner_js_1 = require_discover_ai_planner();
335036
335199
  var discovery_lint_flags_js_1 = require_discovery_lint_flags();
335037
335200
  var verification_inbox_js_1 = require_verification_inbox();
335201
+ var inbox_tools_js_1 = require_inbox_tools();
335038
335202
  var sitemap_builder_js_1 = require_sitemap_builder();
335039
335203
  Object.defineProperty(exports2, "buildInMemorySiteMap", { enumerable: true, get: function() {
335040
335204
  return sitemap_builder_js_1.buildInMemorySiteMap;
@@ -335048,11 +335212,16 @@ var require_discover_agent = __commonJS({
335048
335212
  var canvas_detector_js_1 = require_canvas_detector();
335049
335213
  var auth_recipe_js_1 = require_auth_recipe();
335050
335214
  function plannerEmailVerifyArmed(ctx) {
335051
- if (!(0, discovery_lint_flags_js_1.isTestgenEmailVerifyEnabled)())
335052
- return false;
335053
- if (ctx.variableContext?.allTestVariables?.DISCOVERY_SHOULD_REGISTER !== "true")
335215
+ if (!(0, discovery_lint_flags_js_1.isTestgenEmailVerifyEnabled)() || !(0, verification_inbox_js_1.loadVerificationInboxConfig)())
335054
335216
  return false;
335055
- return (0, verification_inbox_js_1.isVerificationInboxConfigured)();
335217
+ return (0, inbox_tools_js_1.hasSignupTestIntent)(ctx.variableContext);
335218
+ }
335219
+ var PLANNER_AUTH_NAME_RE = /\b(auth|authentication|log[\s-]?in|sign[\s-]?in|sign[\s-]?up|signup|account|password|verify[\s-]?email)\b/i;
335220
+ var PLANNER_AUTH_ROUTE_RE = /\/(auth|login|sign-?in|sign-?up|signup|verify-?email|create-?account)\b/i;
335221
+ function featureLooksLikeAuth(featureName, focusRoutes) {
335222
+ if (featureName && PLANNER_AUTH_NAME_RE.test(featureName))
335223
+ return true;
335224
+ return (focusRoutes ?? []).some((r) => PLANNER_AUTH_ROUTE_RE.test(r));
335056
335225
  }
335057
335226
  async function runCanvasPreflight(ctx, sharedBrowser, log2) {
335058
335227
  const cached = ctx.appRenderType ?? null;
@@ -335704,6 +335873,11 @@ Explore complete: ${exploreResult.pagesDiscovered} pages, ${exploreResult.elemen
335704
335873
  authRedirectRoute: (0, shared_1.parseBoolFlag)(process.env.AUTH_RECIPE_STAMP) ? ctx.authRecipe?.redirectRoute ?? void 0 : void 0,
335705
335874
  // Email-verify capability — only for scenario-producing modes; a survey emits
335706
335875
  // featureGroups (no scenarios), so keep its prompt free of the round-trip block.
335876
+ // This site serves survey + FULL mode. Full mode is app-wide (no single feature
335877
+ // identity here), so we deliberately do NOT apply the auth-feature scope: the
335878
+ // per-scenario generator gates (scenarioLooksLikeRegistration +
335879
+ // scenarioTouchesSignupAuthSurface) still isolate non-auth scenarios. The
335880
+ // auth-feature scope IS applied at the DEEP call site where ctx.featureName is known.
335707
335881
  emailVerifyArmed: mode !== "survey" && plannerEmailVerifyArmed(ctx),
335708
335882
  testBudget
335709
335883
  }, {
@@ -336292,9 +336466,10 @@ Plan (reused): ${resumeSavedScenarios.length} scenarios from the paused run.`);
336292
336466
  // Email-verify capability: when armed, let the planner plan the full
336293
336467
  // register→verify and forgot-password→reset round trips to completion
336294
336468
  // (see the planner's "## Verification Inbox Available" block). Armed on the
336295
- // SAME project-level predicate the generator uses (flag + register intent +
336469
+ // SAME project-level predicate the generator uses (flag + consent +
336296
336470
  // configured inbox), so the planner never promises what generation can't do.
336297
- emailVerifyArmed: plannerEmailVerifyArmed(ctx),
336471
+ // Scoped to AUTH features: a non-auth feature has no signup surface to test.
336472
+ emailVerifyArmed: plannerEmailVerifyArmed(ctx) && featureLooksLikeAuth(ctx.featureName, augmentedFeatureFocusAreas),
336298
336473
  testBudget: featureTestBudget
336299
336474
  }, {
336300
336475
  modelOverride: ctx.planModel ?? ctx.generateModel,
@@ -350920,7 +351095,7 @@ var require_package4 = __commonJS({
350920
351095
  "package.json"(exports2, module2) {
350921
351096
  module2.exports = {
350922
351097
  name: "@validate.qa/runner",
350923
- version: "1.0.64",
351098
+ version: "1.0.66",
350924
351099
  description: "validate local test runner - execute Playwright tests on your machine, connected to validate.qa cloud.",
350925
351100
  bin: {
350926
351101
  "validate-runner": "dist/cli.js"
@@ -359516,13 +359691,14 @@ ${finalVerifyResult.logs ?? ""}`;
359516
359691
  }
359517
359692
  }
359518
359693
  }
359694
+ const auditStatus = info.exitReason === "abort" || info.exitReason === "timeout" ? "ERROR" : "SUCCESS";
359519
359695
  pushAudit({
359520
359696
  projectId: ctx.projectId,
359521
359697
  sessionId: ctx.sessionId,
359522
359698
  callType: info.callType,
359523
359699
  model: info.model,
359524
359700
  provider: info.provider,
359525
- status: "SUCCESS",
359701
+ status: auditStatus,
359526
359702
  durationMs: info.durationMs,
359527
359703
  promptTokens: info.promptTokens,
359528
359704
  completionTokens: info.completionTokens,
@@ -359539,6 +359715,11 @@ ${finalVerifyResult.logs ?? ""}`;
359539
359715
  discoveryFlowId: run2.runId,
359540
359716
  ...info.callType === "authCapture" ? { featureName: "Login" } : ctx.featureName ? { featureName: ctx.featureName } : {},
359541
359717
  ...ctx.mode ? { discoveryMode: ctx.mode } : {},
359718
+ // Per-session identity for Call-2 rows (parity with execute-run.ts) so
359719
+ // Fix/Author/Cleanup phases are distinguishable in the flow card.
359720
+ ...info.scenarioName ? { scenarioName: info.scenarioName } : {},
359721
+ ...info.sessionKind ? { sessionKind: info.sessionKind } : {},
359722
+ ...info.exitReason ? { exitReason: info.exitReason } : {},
359542
359723
  ...cliCostUsd !== void 0 ? { cliCostUsd } : {},
359543
359724
  ...ledgerAudit ? {
359544
359725
  ledger: ledgerAudit.entries,
package/dist/cli.mjs CHANGED
@@ -3490,6 +3490,135 @@ var init_audit_pricing = __esm({
3490
3490
  }
3491
3491
  });
3492
3492
 
3493
+ // ../shared/dist/audit-grouping.js
3494
+ var GROUPABLE_CALL_TYPES, GROUP_LABELS, FLOW_PHASE_TYPES, FLOW_SERVER_TYPES, FLOW_PHASE_LABELS;
3495
+ var init_audit_grouping = __esm({
3496
+ "../shared/dist/audit-grouping.js"() {
3497
+ "use strict";
3498
+ GROUPABLE_CALL_TYPES = /* @__PURE__ */ new Set([
3499
+ "healIteration",
3500
+ "healOrchestrator",
3501
+ "generateRegressionSuite",
3502
+ "discoveryExplore",
3503
+ "surveyExplore",
3504
+ "featureExplore",
3505
+ "discoveryGenerate",
3506
+ "discoveryPlan",
3507
+ "discoveryGenerateSkeleton",
3508
+ "discoveryGenerateElementContext",
3509
+ "liveGenerate",
3510
+ "scenarioGenerate",
3511
+ "liveSuiteHeal",
3512
+ "captureIteration",
3513
+ "healAPITest",
3514
+ "generateAPITests",
3515
+ // Auth-prologue login-capture run (runLoginCaptureRun) — per-turn rows share a
3516
+ // groupId so they collapse into one "Login Capture" phase card on /audit.
3517
+ "authCapture",
3518
+ // Assistant chat — rounds of one conversation collapse into one card.
3519
+ "assistantChat"
3520
+ ]);
3521
+ GROUP_LABELS = {
3522
+ healIteration: "healSession",
3523
+ healOrchestrator: "healSession",
3524
+ healAPITest: "apiHealSession",
3525
+ generateRegressionSuite: "regressionSession",
3526
+ generateAPITests: "apiTestGenSession",
3527
+ discoveryExplore: "discoveryExploreSession",
3528
+ surveyExplore: "surveyExploreSession",
3529
+ featureExplore: "featureExploreSession",
3530
+ discoveryGenerate: "discoveryGenerateSession",
3531
+ discoveryGenerateSkeleton: "discoveryGenerateSession",
3532
+ discoveryGenerateElementContext: "discoveryGenerateSession",
3533
+ liveGenerate: "liveGenerateSession",
3534
+ scenarioGenerate: "scenarioGenerateSession",
3535
+ discoveryPlan: "discoveryPlanSession",
3536
+ liveSuiteHeal: "liveSuiteHealSession",
3537
+ captureIteration: "captureIterationSession",
3538
+ authCapture: "authCaptureSession",
3539
+ assistantChat: "assistantChatSession"
3540
+ };
3541
+ FLOW_PHASE_TYPES = /* @__PURE__ */ new Set([
3542
+ "surveyExploreSession",
3543
+ "featureExploreSession",
3544
+ "discoveryAIPlanner",
3545
+ "discoveryPlanSession",
3546
+ "scenarioGenerateSession",
3547
+ "liveGenerateSession",
3548
+ "discoveryGenerateSession",
3549
+ // Raw callTypes (for ungrouped single-turn entries like planner)
3550
+ "surveyExplore",
3551
+ "featureExplore",
3552
+ "discoveryPlan",
3553
+ "scenarioGenerate",
3554
+ "liveGenerate",
3555
+ "discoveryGenerate",
3556
+ // Planner repair / retry / strengthen-gate — the one-shot extra planner call
3557
+ // shares the base planner's discoveryFlowId, so it nests as its own phase
3558
+ // instead of dangling as a raw camelCase row.
3559
+ "discoveryAIPlannerRepair",
3560
+ "discoveryAIPlannerRetry",
3561
+ "discoveryAIPlannerStrengthenGate",
3562
+ // Deep-run feature analyst insight (one call per feature discovery).
3563
+ "featureInsight",
3564
+ // Discovery v2 Call-1-authoring pivot — per-test Call 2 spawns. Each session
3565
+ // has its OWN sessionId but shares the parent discoveryFlowId, so grouping by
3566
+ // flowId pulls them under the same Discovery Flow card. `Cleanup` is the
3567
+ // teardown sibling of Fix/Author and nests the same way.
3568
+ "discoveryCall2Fix",
3569
+ "discoveryCall2Author",
3570
+ "discoveryCall2Cleanup",
3571
+ // Auth-prologue login-capture run — grouped label + raw callType.
3572
+ "authCaptureSession",
3573
+ "authCapture"
3574
+ ]);
3575
+ FLOW_SERVER_TYPES = /* @__PURE__ */ new Set([
3576
+ "healthAnalysis",
3577
+ "apiSecurityAudit",
3578
+ "apiSecurityAuditVerify",
3579
+ "generateAPITests",
3580
+ "apiTestGenSession",
3581
+ "healAPITest",
3582
+ "apiHealSession",
3583
+ "healSession",
3584
+ "healIteration"
3585
+ ]);
3586
+ FLOW_PHASE_LABELS = {
3587
+ surveyExploreSession: "Survey Explore",
3588
+ featureExploreSession: "Feature Explore",
3589
+ discoveryAIPlanner: "Feature Analyst",
3590
+ discoveryAIPlannerRepair: "Planner Repair",
3591
+ discoveryAIPlannerRetry: "Planner Retry",
3592
+ discoveryAIPlannerStrengthenGate: "Planner Strengthen Gate",
3593
+ discoveryPlanSession: "Survey Planner",
3594
+ scenarioGenerateSession: "Scenario Gen",
3595
+ liveGenerateSession: "Live Browser Gen",
3596
+ discoveryGenerateSession: "Test Generation",
3597
+ surveyExplore: "Survey Explore",
3598
+ featureExplore: "Feature Explore",
3599
+ discoveryPlan: "Planner",
3600
+ scenarioGenerate: "Scenario Gen",
3601
+ liveGenerate: "Live Browser Gen",
3602
+ discoveryGenerate: "Test Generation",
3603
+ discoveryCall2Fix: "Call 2 Fix",
3604
+ discoveryCall2Author: "Call 2 Author",
3605
+ discoveryCall2Cleanup: "Call 2 Cleanup",
3606
+ featureInsight: "Feature Insight",
3607
+ healthAnalysis: "Health Analysis",
3608
+ apiSecurityAudit: "Security Audit",
3609
+ apiSecurityAuditVerify: "Security Verify",
3610
+ generateAPITests: "API Test Gen",
3611
+ apiTestGenSession: "API Test Gen",
3612
+ healAPITest: "API Test Heal",
3613
+ apiHealSession: "API Test Heal",
3614
+ healSession: "Heal Session",
3615
+ healIteration: "Heal",
3616
+ authCapture: "Login Capture",
3617
+ authCaptureSession: "Login Capture"
3618
+ };
3619
+ }
3620
+ });
3621
+
3493
3622
  // ../shared/dist/discovery-har-decision.js
3494
3623
  function decideHarPosted(response) {
3495
3624
  if (!response)
@@ -5855,6 +5984,11 @@ __export(dist_exports, {
5855
5984
  DEFAULT_UI_VARIANT: () => DEFAULT_UI_VARIANT,
5856
5985
  EMAIL_FROM_IDENTITIES: () => EMAIL_FROM_IDENTITIES,
5857
5986
  ENVIRONMENTAL_ERROR_PREFIXES: () => ENVIRONMENTAL_ERROR_PREFIXES,
5987
+ FLOW_PHASE_LABELS: () => FLOW_PHASE_LABELS,
5988
+ FLOW_PHASE_TYPES: () => FLOW_PHASE_TYPES,
5989
+ FLOW_SERVER_TYPES: () => FLOW_SERVER_TYPES,
5990
+ GROUPABLE_CALL_TYPES: () => GROUPABLE_CALL_TYPES,
5991
+ GROUP_LABELS: () => GROUP_LABELS,
5858
5992
  LEGACY_TTS_VOICE_ID_MAP: () => LEGACY_TTS_VOICE_ID_MAP,
5859
5993
  MAX_CREDIT_TOPUP_CENTS: () => MAX_CREDIT_TOPUP_CENTS,
5860
5994
  MAX_DEEPLINK_LENGTH: () => MAX_DEEPLINK_LENGTH,
@@ -6038,6 +6172,7 @@ var init_dist = __esm({
6038
6172
  init_mobile_deeplink();
6039
6173
  init_plans();
6040
6174
  init_audit_pricing();
6175
+ init_audit_grouping();
6041
6176
  init_discovery_har_decision();
6042
6177
  init_assertion_classifier();
6043
6178
  init_assertion_strength();
@@ -73494,6 +73629,7 @@ var require_inbox_tools = __commonJS({
73494
73629
  exports.buildInboxPromptBlock = buildInboxPromptBlock;
73495
73630
  exports.guardVerificationCodeFabrication = guardVerificationCodeFabrication;
73496
73631
  exports.hasRegisterIntent = hasRegisterIntent;
73632
+ exports.hasSignupTestIntent = hasSignupTestIntent;
73497
73633
  exports.resolveInboxRegistration = resolveInboxRegistration;
73498
73634
  exports.applyInboxRegistrationIdentity = applyInboxRegistrationIdentity;
73499
73635
  exports.isThrowawayRegisterSeedEmail = isThrowawayRegisterSeedEmail;
@@ -74037,6 +74173,9 @@ This project asked to REGISTER a new account, but this runner CANNOT receive ema
74037
74173
  const v = variableContext.allTestVariables?.DISCOVERY_SHOULD_REGISTER ?? variableContext.publicTestVariables?.DISCOVERY_SHOULD_REGISTER ?? "";
74038
74174
  return String(v).trim().toLowerCase() === "true";
74039
74175
  }
74176
+ function hasSignupTestIntent(variableContext) {
74177
+ return variableContext?.allTestVariables?.DISCOVERY_ALLOW_SIGNUP_TESTS !== "false";
74178
+ }
74040
74179
  function resolveInboxRegistration(opts) {
74041
74180
  const config = (0, verification_inbox_js_1.loadVerificationInboxConfig)(opts.env ?? process.env);
74042
74181
  if (!config)
@@ -94985,6 +95124,8 @@ var require_discover_generator = __commonJS({
94985
95124
  Object.defineProperty(exports, "__esModule", { value: true });
94986
95125
  exports.MIN_BUG_DESCRIPTION_LENGTH = exports.VALID_PLAYWRIGHT_GETBY_METHODS = exports.BLOCKED_MCP_TOOLS_SCENARIO_GEN = void 0;
94987
95126
  exports.scenarioLooksLikeRegistration = scenarioLooksLikeRegistration;
95127
+ exports.signupFeatureTestingAllowed = signupFeatureTestingAllowed;
95128
+ exports.scenarioTouchesSignupAuthSurface = scenarioTouchesSignupAuthSurface;
94988
95129
  exports.filterMcpToolsForScenarioGen = filterMcpToolsForScenarioGen;
94989
95130
  exports.detectScenarioSignals = detectScenarioSignals;
94990
95131
  exports.scenarioStepsCoverAuth = scenarioStepsCoverAuth;
@@ -95072,6 +95213,19 @@ EMIT (the code you put in finish_generate) \u2014 do NOT hardcode the throwaway
95072
95213
  - Tag the test \`@email-verify\`. Emit EXACTLY ONE test() in this file (one registration per run).
95073
95214
  - End with a DURABLE assertion of the post-verification signed-in state (e.g. a Logout control, an account/dashboard landmark) in your OWN test body \u2014 the helper call is not itself a proof.`;
95074
95215
  }
95216
+ function signupFeatureTestingAllowed(credentials) {
95217
+ if (!(0, discovery_lint_flags_js_1.isTestgenEmailVerifyEnabled)() || !(0, verification_inbox_js_1.loadVerificationInboxConfig)())
95218
+ return false;
95219
+ return credentials?.DISCOVERY_ALLOW_SIGNUP_TESTS !== "false";
95220
+ }
95221
+ var SIGNUP_AUTH_ROUTE_RE = /\/(sign-?up|verify-?email|email-?verification|create-?account|confirm-?email)\b/i;
95222
+ function scenarioTouchesSignupAuthSurface(scenario, pages) {
95223
+ const routes = [scenario.entryRoute, ...scenario.targetPages ?? []].filter((r) => !!r);
95224
+ if (routes.some((r) => SIGNUP_AUTH_ROUTE_RE.test(r)))
95225
+ return true;
95226
+ const authRoutes = new Set(pages.filter((p) => (p.pageType ?? "").toUpperCase() === "AUTH").map((p) => p.route));
95227
+ return routes.some((r) => authRoutes.has(r));
95228
+ }
95075
95229
  exports.BLOCKED_MCP_TOOLS_SCENARIO_GEN = /* @__PURE__ */ new Set([
95076
95230
  "browser_install",
95077
95231
  "browser_close",
@@ -98183,9 +98337,16 @@ ${tailBlock}`;
98183
98337
  extraAuthEvidence: !!opts?.recipe || hasConfiguredLoginCredentials(credentials)
98184
98338
  });
98185
98339
  const baseSkeletonHadRegression = tags.includes("@regression");
98340
+ const selfProvisioningSignupScenario = signupFeatureTestingAllowed(credentials) && scenarioLooksLikeRegistration(scenario) && scenarioTouchesSignupAuthSurface(scenario, siteMap.pages);
98341
+ if (selfProvisioningSignupScenario) {
98342
+ for (const prereqTag of ["@needs-auth", "@inline-login", "@auth-guarded"]) {
98343
+ const idx = tags.indexOf(prereqTag);
98344
+ if (idx !== -1)
98345
+ tags.splice(idx, 1);
98346
+ }
98347
+ }
98186
98348
  const hasVerifiedRecipe = !!opts?.recipe && tags.includes("@needs-auth");
98187
- const projectHasRegisterIntent = credentials?.DISCOVERY_SHOULD_REGISTER === "true";
98188
- const inboxGenConfig = (0, discovery_lint_flags_js_1.isTestgenEmailVerifyEnabled)() && projectHasRegisterIntent && !hasVerifiedRecipe && scenarioLooksLikeRegistration(scenario) ? (0, verification_inbox_js_1.loadVerificationInboxConfig)() : null;
98349
+ const inboxGenConfig = selfProvisioningSignupScenario ? (0, verification_inbox_js_1.loadVerificationInboxConfig)() : null;
98189
98350
  let genInboxState = null;
98190
98351
  let genInboxCredentials = credentials;
98191
98352
  let genInboxSecret = null;
@@ -99132,7 +99293,8 @@ Scenario: "${scenario.name}" (${scenario.type})`);
99132
99293
  } catch {
99133
99294
  }
99134
99295
  const recipe = authRecipe;
99135
- const replayLogin = shouldReplayAuthRecipe(scenario.targetPages, siteMap.pages, recipe);
99296
+ const selfProvisioningSignupScenario = signupFeatureTestingAllowed(credentials) && scenarioLooksLikeRegistration(scenario) && scenarioTouchesSignupAuthSurface(scenario, siteMap.pages);
99297
+ const replayLogin = !selfProvisioningSignupScenario && shouldReplayAuthRecipe(scenario.targetPages, siteMap.pages, recipe);
99136
99298
  let effectiveRecipe = null;
99137
99299
  if (replayLogin && recipe) {
99138
99300
  const planLeaks = findSensitiveLiteralLeaks(JSON.stringify(recipe.replayPlan ?? []), credentials);
@@ -99239,7 +99401,8 @@ Scenario: "${scenario.name}" (${scenario.type})`);
99239
99401
  return;
99240
99402
  }
99241
99403
  let effectiveRecipe = null;
99242
- if (shouldReplayAuthRecipe(scenario.targetPages, siteMap.pages, authRecipe) && authRecipe) {
99404
+ const selfProvisioningSignupScenario = signupFeatureTestingAllowed(credentials) && scenarioLooksLikeRegistration(scenario) && scenarioTouchesSignupAuthSurface(scenario, siteMap.pages);
99405
+ if (!selfProvisioningSignupScenario && shouldReplayAuthRecipe(scenario.targetPages, siteMap.pages, authRecipe) && authRecipe) {
99243
99406
  const planLeaks = findSensitiveLiteralLeaks(JSON.stringify(authRecipe.replayPlan ?? []), credentials);
99244
99407
  if (planLeaks.length > 0) {
99245
99408
  scenarioLogs.push(` Warning: login replay plan contains literal credential value(s) for ${planLeaks.join(", ")} \u2014 falling back to model-authored login for "${scenario.name}"`);
@@ -335040,6 +335203,7 @@ var require_discover_agent = __commonJS({
335040
335203
  var discover_ai_planner_js_1 = require_discover_ai_planner();
335041
335204
  var discovery_lint_flags_js_1 = require_discovery_lint_flags();
335042
335205
  var verification_inbox_js_1 = require_verification_inbox();
335206
+ var inbox_tools_js_1 = require_inbox_tools();
335043
335207
  var sitemap_builder_js_1 = require_sitemap_builder();
335044
335208
  Object.defineProperty(exports, "buildInMemorySiteMap", { enumerable: true, get: function() {
335045
335209
  return sitemap_builder_js_1.buildInMemorySiteMap;
@@ -335053,11 +335217,16 @@ var require_discover_agent = __commonJS({
335053
335217
  var canvas_detector_js_1 = require_canvas_detector();
335054
335218
  var auth_recipe_js_1 = require_auth_recipe();
335055
335219
  function plannerEmailVerifyArmed(ctx) {
335056
- if (!(0, discovery_lint_flags_js_1.isTestgenEmailVerifyEnabled)())
335057
- return false;
335058
- if (ctx.variableContext?.allTestVariables?.DISCOVERY_SHOULD_REGISTER !== "true")
335220
+ if (!(0, discovery_lint_flags_js_1.isTestgenEmailVerifyEnabled)() || !(0, verification_inbox_js_1.loadVerificationInboxConfig)())
335059
335221
  return false;
335060
- return (0, verification_inbox_js_1.isVerificationInboxConfigured)();
335222
+ return (0, inbox_tools_js_1.hasSignupTestIntent)(ctx.variableContext);
335223
+ }
335224
+ var PLANNER_AUTH_NAME_RE = /\b(auth|authentication|log[\s-]?in|sign[\s-]?in|sign[\s-]?up|signup|account|password|verify[\s-]?email)\b/i;
335225
+ var PLANNER_AUTH_ROUTE_RE = /\/(auth|login|sign-?in|sign-?up|signup|verify-?email|create-?account)\b/i;
335226
+ function featureLooksLikeAuth(featureName, focusRoutes) {
335227
+ if (featureName && PLANNER_AUTH_NAME_RE.test(featureName))
335228
+ return true;
335229
+ return (focusRoutes ?? []).some((r) => PLANNER_AUTH_ROUTE_RE.test(r));
335061
335230
  }
335062
335231
  async function runCanvasPreflight(ctx, sharedBrowser, log2) {
335063
335232
  const cached = ctx.appRenderType ?? null;
@@ -335709,6 +335878,11 @@ Explore complete: ${exploreResult.pagesDiscovered} pages, ${exploreResult.elemen
335709
335878
  authRedirectRoute: (0, shared_1.parseBoolFlag)(process.env.AUTH_RECIPE_STAMP) ? ctx.authRecipe?.redirectRoute ?? void 0 : void 0,
335710
335879
  // Email-verify capability — only for scenario-producing modes; a survey emits
335711
335880
  // featureGroups (no scenarios), so keep its prompt free of the round-trip block.
335881
+ // This site serves survey + FULL mode. Full mode is app-wide (no single feature
335882
+ // identity here), so we deliberately do NOT apply the auth-feature scope: the
335883
+ // per-scenario generator gates (scenarioLooksLikeRegistration +
335884
+ // scenarioTouchesSignupAuthSurface) still isolate non-auth scenarios. The
335885
+ // auth-feature scope IS applied at the DEEP call site where ctx.featureName is known.
335712
335886
  emailVerifyArmed: mode !== "survey" && plannerEmailVerifyArmed(ctx),
335713
335887
  testBudget
335714
335888
  }, {
@@ -336297,9 +336471,10 @@ Plan (reused): ${resumeSavedScenarios.length} scenarios from the paused run.`);
336297
336471
  // Email-verify capability: when armed, let the planner plan the full
336298
336472
  // register→verify and forgot-password→reset round trips to completion
336299
336473
  // (see the planner's "## Verification Inbox Available" block). Armed on the
336300
- // SAME project-level predicate the generator uses (flag + register intent +
336474
+ // SAME project-level predicate the generator uses (flag + consent +
336301
336475
  // configured inbox), so the planner never promises what generation can't do.
336302
- emailVerifyArmed: plannerEmailVerifyArmed(ctx),
336476
+ // Scoped to AUTH features: a non-auth feature has no signup surface to test.
336477
+ emailVerifyArmed: plannerEmailVerifyArmed(ctx) && featureLooksLikeAuth(ctx.featureName, augmentedFeatureFocusAreas),
336303
336478
  testBudget: featureTestBudget
336304
336479
  }, {
336305
336480
  modelOverride: ctx.planModel ?? ctx.generateModel,
@@ -350925,7 +351100,7 @@ var require_package4 = __commonJS({
350925
351100
  "package.json"(exports, module) {
350926
351101
  module.exports = {
350927
351102
  name: "@validate.qa/runner",
350928
- version: "1.0.64",
351103
+ version: "1.0.66",
350929
351104
  description: "validate local test runner - execute Playwright tests on your machine, connected to validate.qa cloud.",
350930
351105
  bin: {
350931
351106
  "validate-runner": "dist/cli.js"
@@ -359524,13 +359699,14 @@ ${finalVerifyResult.logs ?? ""}`;
359524
359699
  }
359525
359700
  }
359526
359701
  }
359702
+ const auditStatus = info.exitReason === "abort" || info.exitReason === "timeout" ? "ERROR" : "SUCCESS";
359527
359703
  pushAudit({
359528
359704
  projectId: ctx.projectId,
359529
359705
  sessionId: ctx.sessionId,
359530
359706
  callType: info.callType,
359531
359707
  model: info.model,
359532
359708
  provider: info.provider,
359533
- status: "SUCCESS",
359709
+ status: auditStatus,
359534
359710
  durationMs: info.durationMs,
359535
359711
  promptTokens: info.promptTokens,
359536
359712
  completionTokens: info.completionTokens,
@@ -359547,6 +359723,11 @@ ${finalVerifyResult.logs ?? ""}`;
359547
359723
  discoveryFlowId: run2.runId,
359548
359724
  ...info.callType === "authCapture" ? { featureName: "Login" } : ctx.featureName ? { featureName: ctx.featureName } : {},
359549
359725
  ...ctx.mode ? { discoveryMode: ctx.mode } : {},
359726
+ // Per-session identity for Call-2 rows (parity with execute-run.ts) so
359727
+ // Fix/Author/Cleanup phases are distinguishable in the flow card.
359728
+ ...info.scenarioName ? { scenarioName: info.scenarioName } : {},
359729
+ ...info.sessionKind ? { sessionKind: info.sessionKind } : {},
359730
+ ...info.exitReason ? { exitReason: info.exitReason } : {},
359550
359731
  ...cliCostUsd !== void 0 ? { cliCostUsd } : {},
359551
359732
  ...ledgerAudit ? {
359552
359733
  ledger: ledgerAudit.entries,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@validate.qa/runner",
3
- "version": "1.0.64",
3
+ "version": "1.0.66",
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"