staysfixed 0.11.1 → 0.13.0

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 (57) hide show
  1. package/CHANGELOG.md +108 -2
  2. package/README.md +77 -19
  3. package/docs/design-v2.md +8 -7
  4. package/docs/getting-started.md +5 -3
  5. package/docs/guards.md +18 -0
  6. package/docs/how-v2-works.md +43 -10
  7. package/docs/mcp.md +6 -4
  8. package/docs/settings.md +11 -2
  9. package/package.json +1 -1
  10. package/src/cli/approve.js +4 -1
  11. package/src/cli/flake.js +4 -1
  12. package/src/cli/mark.js +5 -1
  13. package/src/cli/status.js +53 -1
  14. package/src/cli/trace.js +27 -2
  15. package/src/core/config.js +136 -25
  16. package/src/core/stop-tree.js +109 -0
  17. package/src/drive/browser.js +20 -31
  18. package/src/drive/page.js +74 -2
  19. package/src/guard/api.js +14 -9
  20. package/src/types.js +1 -1
  21. package/src/v2/adapters/android.js +220 -11
  22. package/src/v2/adapters/child.js +15 -17
  23. package/src/v2/adapters/contract.js +122 -1
  24. package/src/v2/adapters/extension.js +1988 -0
  25. package/src/v2/adapters/http.js +152 -30
  26. package/src/v2/adapters/ios-driver.js +95 -12
  27. package/src/v2/adapters/ios.js +220 -10
  28. package/src/v2/adapters/isolate.js +169 -14
  29. package/src/v2/adapters/linux-driver.js +1028 -0
  30. package/src/v2/adapters/linux.js +1324 -0
  31. package/src/v2/adapters/macos-driver.js +913 -0
  32. package/src/v2/adapters/macos.js +1374 -0
  33. package/src/v2/adapters/process.js +72 -8
  34. package/src/v2/adapters/source.js +254 -7
  35. package/src/v2/adapters/web.js +69 -19
  36. package/src/v2/browsers.js +145 -25
  37. package/src/v2/cause.js +46 -5
  38. package/src/v2/check.js +465 -47
  39. package/src/v2/cli.js +21 -1
  40. package/src/v2/coverage.js +556 -19
  41. package/src/v2/detect.js +742 -42
  42. package/src/v2/doctor.js +125 -18
  43. package/src/v2/escalate.js +57 -11
  44. package/src/v2/init.js +574 -23
  45. package/src/v2/journeys/answers-probe.js +376 -0
  46. package/src/v2/journeys/from-exports.js +456 -0
  47. package/src/v2/journeys/from-suite.js +9 -1
  48. package/src/v2/journeys/index.js +3 -3
  49. package/src/v2/journeys/record-session.js +839 -0
  50. package/src/v2/journeys/record.js +12 -0
  51. package/src/v2/mcp/tools.js +193 -27
  52. package/src/v2/observation.js +145 -0
  53. package/src/v2/run.js +133 -9
  54. package/src/v2/selfcheck.js +297 -11
  55. package/src/v2/store.js +16 -1
  56. package/src/v2/types.js +1 -1
  57. package/src/v2/watch/events.js +6 -0
package/src/v2/cli.js CHANGED
@@ -39,6 +39,7 @@ import { escalationBlock, escalationsFor, productFor, writeEscalations } from '.
39
39
  // module is still being evaluated.
40
40
  import { watchFlags } from '../cli/watch-flags.js';
41
41
  import { INIT_COMMANDS } from './init.js';
42
+ import { RECORD_COMMANDS } from './journeys/record-session.js';
42
43
  import { whatWasNotChecked } from './check.js';
43
44
 
44
45
  /**
@@ -143,6 +144,7 @@ export const V2_COMMANDS = {
143
144
  // the new one actually does.
144
145
  ...INIT_COMMANDS,
145
146
  ...SHIP_COMMANDS,
147
+ ...RECORD_COMMANDS,
146
148
 
147
149
  check: {
148
150
  summary: 'Prove nothing that already worked has changed. This is the one you run.',
@@ -257,7 +259,7 @@ export const V2_COMMANDS = {
257
259
  summary: 'Test whether your own edit really caused a finding, by undoing it.',
258
260
  usage: 'staysfixed prove <finding> --revert <file> [--revert <file>]',
259
261
  describe:
260
- 'You believe your change to a particular file caused a difference. This puts that file\nback to the reference build, runs again, and says whether the difference went away.\nIf it survives, your edit did not cause it and you were about to fix the wrong thing.\n\nNothing is left reverted: the working tree is put back exactly as it was.\n\nIt answers 0 when it could test the claim and 2 when it could not. The answer itself —\ncaused it, or did not — is in the words, not the exit code, because "your edit was\ninnocent" is not a failure and must not be read as one.',
262
+ 'You believe your change to a particular file caused a difference. This puts that file\nback to the reference build, runs again, and says whether the difference went away.\n\nIt gives you one of THREE answers, and only two of them are answers:\n PROVEN CAUSED undoing your change made the difference go away.\n PROVEN NOT CAUSED it was re-run without your change and the difference is still there,\n so you were about to fix the wrong file.\n NOT TESTED nothing was measured — the file you named was not among your changes,\n the old build would not build, or nothing was re-run at all. This\n never means your edit is innocent. It means nobody looked.\n\nIt is a real re-run, not a lookup: expect it to take about as long as a check.\nNothing is left reverted: the working tree is put back exactly as it was.\n\nIt answers 0 when it could test the claim and 2 when it could not. Which way it came out —\ncaused it, or did not — is in the words, not the exit code, because "your edit was\ninnocent" is not a failure and must not be read as one.',
261
263
  options: [
262
264
  ['--revert <file>', 'A file to put back to the reference for one run. Repeat it for several.'],
263
265
  ],
@@ -473,8 +475,26 @@ export async function proveRun(ctx) {
473
475
  });
474
476
  }
475
477
 
478
+ // The price, said before it is charged rather than after.
479
+ //
480
+ // Proving a cause is not a lookup. It checks out the old build into a scratch copy, undoes
481
+ // the one change, and WALKS THE JOURNEYS AGAIN - on a real website that is eleven to
482
+ // twenty minutes, and somebody who thinks they typed a query sits watching a blank screen
483
+ // and kills it. On 2026-08-31 the opposite also happened and is worse: an answer came back
484
+ // in five seconds, having started no build and walked nothing, and read exactly like a
485
+ // measurement. Saying what this is about to cost is half of what stops a fast reply being
486
+ // mistaken for a cheap one - the reply itself now says what it actually ran.
487
+ say(paint.grey(`Undoing ${revert.join(', ')} in a scratch copy and walking this product again. That is a full re-run of the journeys this finding came from, so it costs about what a check costs. Nothing of yours is touched and nothing is left reverted.`));
488
+ blank();
489
+
476
490
  const reply = await askTheToolSet(ctx, 'staysfixed_prove', { finding, revert });
477
491
  sayReply(reply);
492
+ // Non-zero means "could not test", never "your edit was innocent". `staysfixed_prove`
493
+ // marks exactly one of its three answers as an error - the one that is not an answer -
494
+ // which is the promise this command's own help has always made: 0 when it could test the
495
+ // claim, 2 when it could not. Until 2026-08-31 it exited 0 on all three, so a CI step or
496
+ // an agent reading the code alone was told a question nobody had answered had come back
497
+ // clean.
478
498
  return reply.isError ? EXIT.error : EXIT.ok;
479
499
  }
480
500