@validate.qa/runner 1.0.18 → 1.0.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -62040,7 +62040,7 @@ var require_mobile_explorer = __commonJS({
62040
62040
  }
62041
62041
  sections.push("");
62042
62042
  if (mode === "survey") {
62043
- sections.push("**Mission:** Map every reachable screen. For each new screen: mobile_snapshot -> capture_screen -> record_transition. Do NOT submit forms or mutate data. Call finish_exploration when no new screens remain.");
62043
+ sections.push(`**Mission:** Map every reachable screen. For each new screen: mobile_snapshot -> capture_screen -> record_transition. Get PAST the entry gate into the app's real main content \u2014 the login/landing screens are the ENTRANCE, not the app. If test credentials are provided (see the Test Credentials section), SIGN IN with them FIRST and map the authenticated app; that is the real product surface. Use a guest/demo/skip entry (e.g. "See Demo Profile", "Continue as guest") ONLY as a fallback when no credentials are available or login cannot be completed \u2014 demo mode is a limited sandbox, not the authenticated app. Do NOT submit forms with junk data or mutate real data. Call finish_exploration ONLY when every reachable screen \u2014 including the authenticated content \u2014 has been captured and no unvisited frontier screens remain.`);
62044
62044
  } else {
62045
62045
  sections.push("**Mission:** Use the focus features like a real user. Tap, type, submit, and observe outcomes. After a meaningful flow, call record_journey. Call finish_exploration when the flows are covered.");
62046
62046
  }
@@ -62098,7 +62098,14 @@ var require_mobile_explorer = __commonJS({
62098
62098
  This app has stored login credentials under these keys:
62099
62099
  ${keyList}
62100
62100
 
62101
- When you reach a login / sign-in screen, LOG IN so you can map and test the authenticated app \u2014 this OVERRIDES the "do not submit forms" rule for the login form ONLY. Fill each credential field with \`mobile_fill_credential\`: pass the field ref and the KEY (e.g. \`{ ref: "e5", credentialKey: "TEST_USER_EMAIL" }\`). The runner substitutes the real value on the device; you never see, log, or echo it.
62101
+ LOG IN FIRST \u2014 before broad exploration. The authenticated app is the real product surface; a survey that only maps the logged-out/demo screens has missed most of the app. This OVERRIDES the "do not submit forms" rule for the login form ONLY. The login sequence is:
62102
+ 1. Reach the email/password sign-in form (tap "Sign in with Email" / "Login" from the landing screen if needed).
62103
+ 2. Fill the email field: \`mobile_fill_credential({ ref, credentialKey: "TEST_USER_EMAIL" })\`. Fill the password field: \`mobile_fill_credential({ ref, credentialKey: "TEST_USER_PASSWORD" })\`. The runner substitutes the real value on the device; you never see, log, or echo it.
62104
+ 3. TAP THE SUBMIT BUTTON (e.g. "Sign In", "Log In", "Continue"). Filling the fields does NOT log you in \u2014 you MUST tap submit.
62105
+ 4. VERIFY you are actually signed in: re-snapshot and confirm an authenticated signal appeared (a home/feed/dashboard with real content, an account/profile tab, a "Sign out" option, or your user identity). If you are still on the login form, the login failed \u2014 check for an error, re-enter, and submit again (up to 2 attempts).
62106
+ 5. Only AFTER you have confirmed you are signed in, map the authenticated app.
62107
+
62108
+ PREFER real login over any "demo"/"guest"/"skip" entry: those give a limited sandbox, NOT the authenticated app. Use them only if login is impossible.
62102
62109
 
62103
62110
  SECURITY RULES:
62104
62111
  - NEVER call \`mobile_type\` with an email, password, or token value \u2014 the runner will REJECT the call and you lose an iteration. Use \`mobile_fill_credential\` for every credential field.
@@ -62405,6 +62412,8 @@ ${existingScreens.slice(0, 100).map((s) => `- ${s.screenId}${s.name ? ` "${s.nam
62405
62412
  let summary = "";
62406
62413
  let truncated = false;
62407
62414
  let truncatedReason;
62415
+ let finishRedirects = 0;
62416
+ const MAX_FINISH_REDIRECTS = 2;
62408
62417
  try {
62409
62418
  try {
62410
62419
  const seed = await driver.snapshot();
@@ -62534,6 +62543,20 @@ ${statePacket}` }
62534
62543
  continue;
62535
62544
  }
62536
62545
  if (toolName === "finish_exploration") {
62546
+ const frontier = mode === "survey" ? state2.getFrontier() : [];
62547
+ const budgetRemainingPct = (maxIterations - iteration) / maxIterations;
62548
+ if (frontier.length > 0 && budgetRemainingPct >= 0.2 && finishRedirects < MAX_FINISH_REDIRECTS) {
62549
+ finishRedirects++;
62550
+ const targets = frontier.slice(0, 6).join(", ");
62551
+ log2(`
62552
+ finish_exploration bounced (${finishRedirects}/${MAX_FINISH_REDIRECTS}): ${frontier.length} frontier screen(s) still unvisited, ${Math.round(budgetRemainingPct * 100)}% budget left.`);
62553
+ pushResult({
62554
+ acknowledged: false,
62555
+ keepExploring: true,
62556
+ reason: `Not done yet \u2014 ${frontier.length} screen(s) were seen via transitions but never visited, and ${Math.round(budgetRemainingPct * 100)}% of the iteration budget remains. A survey must map EVERY reachable screen. Navigate into the unvisited screens (e.g. ${targets}), snapshot + capture_screen each, then call finish_exploration only once no unvisited screens remain. If a screen is genuinely unreachable (needs credentials you don't have, or leaves the app), note that and move to the next one.`
62557
+ });
62558
+ continue;
62559
+ }
62537
62560
  explorationComplete = true;
62538
62561
  summary = String(toolArgs.summary ?? "");
62539
62562
  log2(`
@@ -62752,6 +62775,14 @@ Exploration complete: ${summary}`);
62752
62775
  ...actionResult.error ? { error: actionResult.error } : {},
62753
62776
  // Report only the KEY that was filled — never the value.
62754
62777
  filledCredentialKey: key,
62778
+ // Code-level reinforcement of the login sequence: filling a field does
62779
+ // NOT submit the form. The observed failure was fill-without-submit —
62780
+ // the model filled email+password then wandered off (into demo content)
62781
+ // without ever tapping Sign In, so it never reached the authenticated
62782
+ // app. This nudge fires on every credential fill so the model is
62783
+ // reminded to complete + verify the login rather than treating the fill
62784
+ // as "logged in".
62785
+ nextStep: "Credential filled \u2014 this does NOT log you in. Once all credential fields are filled, tap the submit button (Sign In / Log In / Continue), then re-snapshot and confirm an authenticated screen (home/feed/account/Sign out) appeared before exploring further.",
62755
62786
  screenId,
62756
62787
  observation,
62757
62788
  ...absorbed.externalBlocked ? { blockedExternalApp: true, externalApp: absorbed.externalOwner } : {},
@@ -328429,7 +328460,7 @@ var require_package4 = __commonJS({
328429
328460
  "package.json"(exports2, module2) {
328430
328461
  module2.exports = {
328431
328462
  name: "@validate.qa/runner",
328432
- version: "1.0.18",
328463
+ version: "1.0.19",
328433
328464
  description: "validate local test runner - execute Playwright tests on your machine, connected to validate.qa cloud.",
328434
328465
  bin: {
328435
328466
  "validate-runner": "dist/cli.js"
package/dist/cli.mjs CHANGED
@@ -62045,7 +62045,7 @@ var require_mobile_explorer = __commonJS({
62045
62045
  }
62046
62046
  sections.push("");
62047
62047
  if (mode === "survey") {
62048
- sections.push("**Mission:** Map every reachable screen. For each new screen: mobile_snapshot -> capture_screen -> record_transition. Do NOT submit forms or mutate data. Call finish_exploration when no new screens remain.");
62048
+ sections.push(`**Mission:** Map every reachable screen. For each new screen: mobile_snapshot -> capture_screen -> record_transition. Get PAST the entry gate into the app's real main content \u2014 the login/landing screens are the ENTRANCE, not the app. If test credentials are provided (see the Test Credentials section), SIGN IN with them FIRST and map the authenticated app; that is the real product surface. Use a guest/demo/skip entry (e.g. "See Demo Profile", "Continue as guest") ONLY as a fallback when no credentials are available or login cannot be completed \u2014 demo mode is a limited sandbox, not the authenticated app. Do NOT submit forms with junk data or mutate real data. Call finish_exploration ONLY when every reachable screen \u2014 including the authenticated content \u2014 has been captured and no unvisited frontier screens remain.`);
62049
62049
  } else {
62050
62050
  sections.push("**Mission:** Use the focus features like a real user. Tap, type, submit, and observe outcomes. After a meaningful flow, call record_journey. Call finish_exploration when the flows are covered.");
62051
62051
  }
@@ -62103,7 +62103,14 @@ var require_mobile_explorer = __commonJS({
62103
62103
  This app has stored login credentials under these keys:
62104
62104
  ${keyList}
62105
62105
 
62106
- When you reach a login / sign-in screen, LOG IN so you can map and test the authenticated app \u2014 this OVERRIDES the "do not submit forms" rule for the login form ONLY. Fill each credential field with \`mobile_fill_credential\`: pass the field ref and the KEY (e.g. \`{ ref: "e5", credentialKey: "TEST_USER_EMAIL" }\`). The runner substitutes the real value on the device; you never see, log, or echo it.
62106
+ LOG IN FIRST \u2014 before broad exploration. The authenticated app is the real product surface; a survey that only maps the logged-out/demo screens has missed most of the app. This OVERRIDES the "do not submit forms" rule for the login form ONLY. The login sequence is:
62107
+ 1. Reach the email/password sign-in form (tap "Sign in with Email" / "Login" from the landing screen if needed).
62108
+ 2. Fill the email field: \`mobile_fill_credential({ ref, credentialKey: "TEST_USER_EMAIL" })\`. Fill the password field: \`mobile_fill_credential({ ref, credentialKey: "TEST_USER_PASSWORD" })\`. The runner substitutes the real value on the device; you never see, log, or echo it.
62109
+ 3. TAP THE SUBMIT BUTTON (e.g. "Sign In", "Log In", "Continue"). Filling the fields does NOT log you in \u2014 you MUST tap submit.
62110
+ 4. VERIFY you are actually signed in: re-snapshot and confirm an authenticated signal appeared (a home/feed/dashboard with real content, an account/profile tab, a "Sign out" option, or your user identity). If you are still on the login form, the login failed \u2014 check for an error, re-enter, and submit again (up to 2 attempts).
62111
+ 5. Only AFTER you have confirmed you are signed in, map the authenticated app.
62112
+
62113
+ PREFER real login over any "demo"/"guest"/"skip" entry: those give a limited sandbox, NOT the authenticated app. Use them only if login is impossible.
62107
62114
 
62108
62115
  SECURITY RULES:
62109
62116
  - NEVER call \`mobile_type\` with an email, password, or token value \u2014 the runner will REJECT the call and you lose an iteration. Use \`mobile_fill_credential\` for every credential field.
@@ -62410,6 +62417,8 @@ ${existingScreens.slice(0, 100).map((s) => `- ${s.screenId}${s.name ? ` "${s.nam
62410
62417
  let summary = "";
62411
62418
  let truncated = false;
62412
62419
  let truncatedReason;
62420
+ let finishRedirects = 0;
62421
+ const MAX_FINISH_REDIRECTS = 2;
62413
62422
  try {
62414
62423
  try {
62415
62424
  const seed = await driver.snapshot();
@@ -62539,6 +62548,20 @@ ${statePacket}` }
62539
62548
  continue;
62540
62549
  }
62541
62550
  if (toolName === "finish_exploration") {
62551
+ const frontier = mode === "survey" ? state2.getFrontier() : [];
62552
+ const budgetRemainingPct = (maxIterations - iteration) / maxIterations;
62553
+ if (frontier.length > 0 && budgetRemainingPct >= 0.2 && finishRedirects < MAX_FINISH_REDIRECTS) {
62554
+ finishRedirects++;
62555
+ const targets = frontier.slice(0, 6).join(", ");
62556
+ log2(`
62557
+ finish_exploration bounced (${finishRedirects}/${MAX_FINISH_REDIRECTS}): ${frontier.length} frontier screen(s) still unvisited, ${Math.round(budgetRemainingPct * 100)}% budget left.`);
62558
+ pushResult({
62559
+ acknowledged: false,
62560
+ keepExploring: true,
62561
+ reason: `Not done yet \u2014 ${frontier.length} screen(s) were seen via transitions but never visited, and ${Math.round(budgetRemainingPct * 100)}% of the iteration budget remains. A survey must map EVERY reachable screen. Navigate into the unvisited screens (e.g. ${targets}), snapshot + capture_screen each, then call finish_exploration only once no unvisited screens remain. If a screen is genuinely unreachable (needs credentials you don't have, or leaves the app), note that and move to the next one.`
62562
+ });
62563
+ continue;
62564
+ }
62542
62565
  explorationComplete = true;
62543
62566
  summary = String(toolArgs.summary ?? "");
62544
62567
  log2(`
@@ -62757,6 +62780,14 @@ Exploration complete: ${summary}`);
62757
62780
  ...actionResult.error ? { error: actionResult.error } : {},
62758
62781
  // Report only the KEY that was filled — never the value.
62759
62782
  filledCredentialKey: key,
62783
+ // Code-level reinforcement of the login sequence: filling a field does
62784
+ // NOT submit the form. The observed failure was fill-without-submit —
62785
+ // the model filled email+password then wandered off (into demo content)
62786
+ // without ever tapping Sign In, so it never reached the authenticated
62787
+ // app. This nudge fires on every credential fill so the model is
62788
+ // reminded to complete + verify the login rather than treating the fill
62789
+ // as "logged in".
62790
+ nextStep: "Credential filled \u2014 this does NOT log you in. Once all credential fields are filled, tap the submit button (Sign In / Log In / Continue), then re-snapshot and confirm an authenticated screen (home/feed/account/Sign out) appeared before exploring further.",
62760
62791
  screenId,
62761
62792
  observation,
62762
62793
  ...absorbed.externalBlocked ? { blockedExternalApp: true, externalApp: absorbed.externalOwner } : {},
@@ -328434,7 +328465,7 @@ var require_package4 = __commonJS({
328434
328465
  "package.json"(exports, module) {
328435
328466
  module.exports = {
328436
328467
  name: "@validate.qa/runner",
328437
- version: "1.0.18",
328468
+ version: "1.0.19",
328438
328469
  description: "validate local test runner - execute Playwright tests on your machine, connected to validate.qa cloud.",
328439
328470
  bin: {
328440
328471
  "validate-runner": "dist/cli.js"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@validate.qa/runner",
3
- "version": "1.0.18",
3
+ "version": "1.0.19",
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"