waygraph 0.15.2 → 0.15.4

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 (41) hide show
  1. package/dist/auto-session-ipc.d.ts +14 -0
  2. package/dist/auto-session-ipc.js +4 -0
  3. package/dist/auto-session.d.ts +15 -0
  4. package/dist/auto-session.js +34 -1
  5. package/dist/cli.js +43 -2
  6. package/dist/engine.d.ts +124 -12
  7. package/dist/engine.js +170 -13
  8. package/dist/highlights.d.ts +8 -0
  9. package/dist/highlights.js +2 -0
  10. package/dist/index.d.ts +2 -2
  11. package/dist/index.js +1 -1
  12. package/dist/pilot-overlay.d.ts +42 -0
  13. package/dist/pilot-overlay.js +148 -0
  14. package/dist/types.d.ts +17 -0
  15. package/examples/saucedemo/.waygraph-auto/1d266123.log +0 -0
  16. package/examples/saucedemo/.waygraph-auto/2c7e8edd.log +0 -0
  17. package/examples/saucedemo/.waygraph-auto/49edc885.log +4 -0
  18. package/examples/saucedemo/.waygraph-auto/79600ead.log +0 -0
  19. package/examples/saucedemo/.waygraph-auto/d2c6ed66.log +0 -0
  20. package/examples/saucedemo/.waygraph-auto/ddcb4212.log +0 -0
  21. package/examples/saucedemo/.waygraph-auto/ebc2ebdb.log +0 -0
  22. package/examples/saucedemo/src/blocks/saucedemo-web/checkout-step-two/methods/finish-order.method.block.ts +8 -7
  23. package/examples/saucedemo/src/blocks/saucedemo-web/methods/fill-password.method.block.ts +8 -10
  24. package/examples/saucedemo/src/blocks/saucedemo-web/methods/fill-username.method.block.ts +11 -10
  25. package/examples/saucedemo/src/blocks/saucedemo-web/methods/submit-login-for-flow.ts +5 -4
  26. package/examples/saucedemo/src/flows/checkout.flow.ts +61 -97
  27. package/examples/saucedemo/src/flows/login.flow.ts +11 -2
  28. package/examples/saucedemo/src/flows/shop.flow.ts +13 -13
  29. package/examples/saucedemo/src/flows/viewer-blocked.flow.ts +9 -2
  30. package/package.json +1 -1
  31. package/templates/quickstart/src/blocks/saucedemo-web/checkout-step-two/methods/finish-order.method.block.ts +8 -7
  32. package/templates/quickstart/src/blocks/saucedemo-web/methods/fill-password.method.block.ts +8 -10
  33. package/templates/quickstart/src/blocks/saucedemo-web/methods/fill-username.method.block.ts +11 -10
  34. package/templates/quickstart/src/blocks/saucedemo-web/methods/submit-login-for-flow.ts +5 -4
  35. package/templates/quickstart/src/flows/checkout.flow.ts +61 -97
  36. package/templates/quickstart/src/flows/login.flow.ts +11 -2
  37. package/templates/quickstart/src/flows/shop.flow.ts +13 -13
  38. package/templates/quickstart/src/flows/viewer-blocked.flow.ts +9 -2
  39. package/templates/skills/waygraph-blind-pilot.skill.md +2 -1
  40. package/templates/skills/waygraph-pilot.skill.md +17 -0
  41. package/examples/saucedemo/.waygraph-auto/0b1f5b26.json +0 -8
@@ -1,4 +1,6 @@
1
1
  import { AutoSession, type AutoSessionInit, type SessionSnapshot, type InspectDomOptions, type DomSnapshot, type TraceStep, type ApplyPathResult, type ConsoleLogEntry, type StorageSnapshot, type StubFileKind } from "./auto-session.js";
2
+ import type { PilotHighlightFixtures } from "./pilot-overlay.js";
3
+ export type { PilotHighlightFixtures, PilotFixtureRing } from "./pilot-overlay.js";
2
4
  export interface SessionMeta {
3
5
  sessionId: string;
4
6
  socketPath: string;
@@ -43,6 +45,15 @@ export type StorageResponse = ({
43
45
  error: string;
44
46
  };
45
47
  export type ReachResponse = ApplyPathResult;
48
+ export type HighlightResponse = {
49
+ ok: true;
50
+ painted: number;
51
+ missing: string[];
52
+ snapshot: SessionSnapshot;
53
+ } | {
54
+ ok: false;
55
+ error: string;
56
+ };
46
57
  /**
47
58
  * Client-side: sends one request to a running session and returns its
48
59
  * response. Reports a stale/unreachable session as an error within
@@ -94,6 +105,9 @@ export declare function requestSession(projectDir: string, sessionId: string, re
94
105
  op: "reach";
95
106
  checkpoint: string;
96
107
  }, timeoutMs?: number): Promise<ReachResponse>;
108
+ export declare function requestSession(projectDir: string, sessionId: string, request: {
109
+ op: "highlight";
110
+ } & PilotHighlightFixtures, timeoutMs?: number): Promise<HighlightResponse>;
97
111
  /**
98
112
  * Server-side: runs `session` behind a unix socket at
99
113
  * `.waygraph-auto/<sessionId>.sock`, writing session metadata only once the
@@ -235,6 +235,10 @@ export async function serveSession(session, projectDir, sessionId, headless = tr
235
235
  else if (request.op === "resync") {
236
236
  response = await session.resync();
237
237
  }
238
+ else if (request.op === "highlight") {
239
+ const { op: _op, ...fixtures } = request;
240
+ response = await session.applyHighlight(fixtures);
241
+ }
238
242
  else {
239
243
  response = { ok: false, error: `unknown op "${request.op}"` };
240
244
  }
@@ -1,6 +1,7 @@
1
1
  import { type BlockEntry, type ExploreMenu } from "./auto-explore.js";
2
2
  import { type PickResult } from "./auto-explore-run.js";
3
3
  import { type StubPhaseResult } from "./highlights.js";
4
+ import type { PilotHighlightFixtures } from "./pilot-overlay.js";
4
5
  export interface SessionSnapshotEdge {
5
6
  /** 1-based, matching the numbers a human/agent picks by (same as printCliMenu). */
6
7
  index: number;
@@ -299,6 +300,20 @@ export declare class AutoSession {
299
300
  rawUpload(selector: string, stub: StubFileKind | {
300
301
  filePath: string;
301
302
  }): Promise<ApplyPickResult>;
303
+ /**
304
+ * Agent-sent highlight fixtures (rings + optional todos) on the live page -
305
+ * the Pilot equivalent of Block `stubBefore` narration in `waygraph demo`.
306
+ * Does not run a Block; paint-only. Missing selectors are reported, not fatal.
307
+ */
308
+ applyHighlight(fixtures: PilotHighlightFixtures): Promise<{
309
+ ok: true;
310
+ painted: number;
311
+ missing: string[];
312
+ snapshot: SessionSnapshot;
313
+ } | {
314
+ ok: false;
315
+ error: string;
316
+ }>;
302
317
  /**
303
318
  * Runs a whole multi-step route to `targetCheckpoint` in one call, instead
304
319
  * of an agent hand-picking one index at a time across many separate
@@ -5,7 +5,7 @@ import { buildExploreContext, buildExploreMenu, } from "./auto-explore.js";
5
5
  import { ensureLivePage, detectHere, seedDefaultMem, ensureMem, runOneBlock, resolveBaseUrl, } from "./auto-explore-run.js";
6
6
  import { runStubPhase } from "./highlights.js";
7
7
  import { findBlockPathDetailed } from "./graph.js";
8
- import { updatePilotOverlay, showPilotActivity, showPilotVision } from "./pilot-overlay.js";
8
+ import { updatePilotOverlay, showPilotActivity, showPilotVision, showPilotFixtures } from "./pilot-overlay.js";
9
9
  /** True when a stub-phase result actually carries authored content worth keeping. */
10
10
  function stubPhaseHasContent(r) {
11
11
  return (Object.keys(r.highlights).length > 0 ||
@@ -670,6 +670,39 @@ export class AutoSession {
670
670
  quit: false,
671
671
  };
672
672
  }
673
+ /**
674
+ * Agent-sent highlight fixtures (rings + optional todos) on the live page -
675
+ * the Pilot equivalent of Block `stubBefore` narration in `waygraph demo`.
676
+ * Does not run a Block; paint-only. Missing selectors are reported, not fatal.
677
+ */
678
+ async applyHighlight(fixtures) {
679
+ this.page = await ensureLivePage(this.context, this.page, this.startUrl);
680
+ const label = fixtures.clear === true
681
+ ? "clear fixtures"
682
+ : `${fixtures.rings?.length ?? 0} ring(s)` +
683
+ (fixtures.todos?.length ? `, ${fixtures.todos.length} todo(s)` : "");
684
+ await showPilotActivity(this.page, `Highlight: ${label}`);
685
+ try {
686
+ const { painted, missing } = await showPilotFixtures(this.page, fixtures);
687
+ const menu = await this.currentMenu();
688
+ this.lastRunNote = fixtures.clear
689
+ ? "highlight cleared"
690
+ : `highlight painted ${painted}` +
691
+ (missing.length ? ` (missing: ${missing.join(", ")})` : "");
692
+ return {
693
+ ok: true,
694
+ painted,
695
+ missing,
696
+ snapshot: buildSessionSnapshot(menu, this.library.byName, this.here, this.lastRunNote),
697
+ };
698
+ }
699
+ catch (err) {
700
+ return {
701
+ ok: false,
702
+ error: `highlight failed - ${err instanceof Error ? err.message : String(err)}`,
703
+ };
704
+ }
705
+ }
673
706
  /**
674
707
  * Runs a whole multi-step route to `targetCheckpoint` in one call, instead
675
708
  * of an agent hand-picking one index at a time across many separate
package/dist/cli.js CHANGED
@@ -2381,6 +2381,7 @@ async function presentFailPanel(page, opts) {
2381
2381
  gatesFast,
2382
2382
  demoPace,
2383
2383
  gate,
2384
+ mem,
2384
2385
  } = opts;
2385
2386
  if (hasAuthoredStubOnError(block, fixtures)) {
2386
2387
  await page
@@ -2396,6 +2397,7 @@ async function presentFailPanel(page, opts) {
2396
2397
  fixtures,
2397
2398
  error,
2398
2399
  out: opts.out,
2400
+ mem,
2399
2401
  });
2400
2402
  const errHighlights = errPhase.highlights.map((h) => {
2401
2403
  const styled = applyHighlightStyleDefaults(h, opts.highlightStyle);
@@ -5101,7 +5103,7 @@ async function runStepMode(engine, start, end, context, page, mem, resolved, slo
5101
5103
  !!r.wasFastForward;
5102
5104
  const fixtures = r.highlightFixtures;
5103
5105
  const flowStyle = r.highlightStyle;
5104
- const stubBeforePhase = await runStubPhase(r.block, "stubBefore", { fixtures });
5106
+ const stubBeforePhase = await runStubPhase(r.block, "stubBefore", { fixtures, mem });
5105
5107
  stubBeforeRef.current = stubBeforePhase.highlights.map((h) =>
5106
5108
  applyHighlightStyleDefaults(h, flowStyle),
5107
5109
  );
@@ -5317,6 +5319,7 @@ async function runStepMode(engine, start, end, context, page, mem, resolved, slo
5317
5319
  gatesFast: pacing.gatesFast,
5318
5320
  demoPace: pacing.demoPace,
5319
5321
  gate,
5322
+ mem,
5320
5323
  });
5321
5324
  if (errEdits && errEdits.__wgRetry) {
5322
5325
  await resetPageState(context, page, baseURL);
@@ -5376,6 +5379,7 @@ async function runStepMode(engine, start, end, context, page, mem, resolved, slo
5376
5379
  gatesFast: pacing.gatesFast,
5377
5380
  demoPace: pacing.demoPace,
5378
5381
  gate,
5382
+ mem,
5379
5383
  });
5380
5384
  if (errEdits && errEdits.__wgRetry) {
5381
5385
  await resetPageState(context, page, baseURL);
@@ -5416,6 +5420,7 @@ async function runStepMode(engine, start, end, context, page, mem, resolved, slo
5416
5420
  const afterPhase = await runStubPhase(r.block, "stubAfter", {
5417
5421
  out: result,
5418
5422
  fixtures: fixturesAfter,
5423
+ mem,
5419
5424
  });
5420
5425
  logStubPhaseFixtures("after", {
5421
5426
  ...afterPhase,
@@ -7001,6 +7006,13 @@ Primary (less is more):
7001
7006
  --non-headless session someone is co-driving);
7002
7007
  send/reach never do this on their own, since they
7003
7008
  only re-detect when the position is already unknown
7009
+ waygraph auto highlight <sessionId> '<json>'
7010
+ Paint agent highlight fixtures on the live page
7011
+ (rings + optional todos). Same visual language as
7012
+ Block stubBefore in demo. JSON: rings[{selector,
7013
+ label,tone?,size?,weight?}], todos[], todoIndex?,
7014
+ todoTitle?, holdMs? (0=until next), clear:true.
7015
+ Missing selectors listed in response, not fatal.
7004
7016
  waygraph pilot start Bootstrap for an agent: starts a --detach session
7005
7017
  (same as auto --cli --detach) AND reads back the
7006
7018
  whole project's Block graph (same as waygraph
@@ -7463,7 +7475,8 @@ Agents shipped: waygraph-planner, waygraph-author, waygraph-healer.
7463
7475
  args[1] === "goto" ||
7464
7476
  args[1] === "reload" ||
7465
7477
  args[1] === "reach" ||
7466
- args[1] === "resync")) {
7478
+ args[1] === "resync" ||
7479
+ args[1] === "highlight")) {
7467
7480
  const sub = args[1];
7468
7481
  const sessionId = args[2];
7469
7482
  if (!sessionId) {
@@ -7665,6 +7678,34 @@ Agents shipped: waygraph-planner, waygraph-author, waygraph-healer.
7665
7678
  process.exitCode = 1;
7666
7679
  break;
7667
7680
  }
7681
+ if (sub === "highlight") {
7682
+ const raw = args[3];
7683
+ if (raw === undefined) {
7684
+ console.error('waygraph auto highlight: usage: waygraph auto highlight <sessionId> \'{"rings":[{"selector":"#x","label":"X"}]}\'');
7685
+ process.exit(1);
7686
+ }
7687
+ let fixtures;
7688
+ try {
7689
+ fixtures = JSON.parse(raw);
7690
+ }
7691
+ catch {
7692
+ console.error("waygraph auto highlight: body must be valid JSON");
7693
+ process.exit(1);
7694
+ }
7695
+ if (fixtures.op !== undefined && fixtures.op !== "highlight") {
7696
+ console.error('waygraph auto highlight: do not set "op" (or set it to "highlight")');
7697
+ process.exit(1);
7698
+ }
7699
+ const { op: _ignore, ...rest } = fixtures;
7700
+ const res = await requestSession(proj, sessionId, {
7701
+ op: "highlight",
7702
+ ...rest,
7703
+ });
7704
+ console.log(JSON.stringify(res));
7705
+ if (!res.ok)
7706
+ process.exitCode = 1;
7707
+ break;
7708
+ }
7668
7709
  const res = await requestSession(proj, sessionId, { op: "status" });
7669
7710
  console.log(JSON.stringify(res));
7670
7711
  if (!res.ok)
package/dist/engine.d.ts CHANGED
@@ -707,37 +707,58 @@ export declare class MapBuilder<Out extends Checkpoint<string>> {
707
707
  private readonly engine;
708
708
  private readonly steps;
709
709
  private readonly homeOrigin;
710
+ private readonly ff;
710
711
  private constructor();
711
712
  /** @internal - use `engine.map()` or the standalone `map()` export. */
712
713
  static begin(engine: Engine, homeOrigin: string | undefined): MapBuilder<S>;
713
714
  /** Readable chain-opener - mirrors `defineFlow`'s leading `start` sentinel. Returns `this` unchanged; entirely optional. */
714
715
  start(): MapBuilder<Out>;
716
+ /**
717
+ * Open a fast-forward window - steps until {@link ffEnd} collapse into one
718
+ * opaque `fastForwardComposeBlock` (blitz theater). Kind/salt checks still
719
+ * run on each inner step as it is added.
720
+ */
721
+ ffStart(name?: string): MapBuilder<Out>;
722
+ /**
723
+ * Close the current fast-forward window and append one FFCompose step.
724
+ * Throws if empty or if {@link ffStart} was never opened.
725
+ */
726
+ ffEnd(): MapBuilder<Out>;
727
+ private appendStep;
715
728
  /**
716
729
  * Appends an internal navigation/page-arrival step - requires a Block from
717
730
  * `defineNavBlock`/`defineMemNavBlock`/`definePageBlock`. Throws if given
718
731
  * anything else, including a `homeOrigin`-mismatched static `url`.
732
+ * Compile-time: {@link NavBlock} or {@link PageBlock} only (not Assert/Method).
719
733
  */
720
- gotoPage<NextOut extends Checkpoint<string>>(block: Block<Out, NextOut> & {
734
+ gotoPage<NextOut extends Checkpoint<string>>(block: (NavBlock<NextOut> | PageBlock<NextOut>) & {
721
735
  name: string;
722
736
  }): MapBuilder<NextOut>;
723
737
  /**
724
738
  * Appends a genuinely cross-origin navigation step (e.g. `(external)/`
725
739
  * Blocks in the Waygraph Map convention: mailpit, maildrop.cc) - same
726
740
  * kind requirement as {@link gotoPage}, plus the inverse `homeOrigin` check.
741
+ * Compile-time: {@link NavBlock} or {@link PageBlock} only.
727
742
  */
728
- gotoExternal<NextOut extends Checkpoint<string>>(block: Block<Out, NextOut> & {
743
+ gotoExternal<NextOut extends Checkpoint<string>>(block: (NavBlock<NextOut> | PageBlock<NextOut>) & {
729
744
  name: string;
730
745
  }): MapBuilder<NextOut>;
731
- /** Appends a self-loop verification step - requires a Block from `defineAssertBlock`. */
732
- assert<NextOut extends Checkpoint<string>>(block: Block<Out, NextOut> & {
746
+ /**
747
+ * Appends a self-loop verification step - requires a Block from
748
+ * `defineAssertBlock`. Compile-time: {@link AssertBlock} only (not `.method()`).
749
+ */
750
+ assert(block: AssertBlock<Out> & {
733
751
  name: string;
734
- }): MapBuilder<NextOut>;
752
+ }): MapBuilder<Out>;
735
753
  /**
736
754
  * Appends a non-navigating page action (submit, upload, add/remove an
737
755
  * instance) - requires a Block from `defineMethodBlock`/`defineActionBlock`/
738
756
  * `defineEffectBlock`/`defineMemEffectBlock`.
757
+ * Compile-time: {@link MethodBlock} or {@link EffectBlock} only - Assert
758
+ * Blocks must use `.assert()`. Runtime also rejects `__waygraphKind =
759
+ * "assert"` (those still carry method salt from the factory internals).
739
760
  */
740
- method<NextOut extends Checkpoint<string>>(block: Block<Out, NextOut> & {
761
+ method<NextOut extends Checkpoint<string>>(block: (MethodBlock<Out, NextOut> | EffectBlock<Out, NextOut>) & {
741
762
  name: string;
742
763
  }): MapBuilder<NextOut>;
743
764
  /**
@@ -799,8 +820,27 @@ export declare function defineBlock<In extends Checkpoint<string>, Out extends C
799
820
  * `defineFlow([...])`, `connect()`, `composeBlock()` exactly like any other
800
821
  * Block - no special-casing needed anywhere that only expects a `Block`.
801
822
  * See `openspec/specs/nav-block-and-check/spec.md` for why this exists.
823
+ *
824
+ * `__wgFactory` is a TypeScript-only brand so {@link MapBuilder.gotoPage} /
825
+ * {@link MapBuilder.gotoExternal} can reject Assert/Method Blocks at compile
826
+ * time (runtime still checks `__waygraphKind`). Decorate methods are re-stated
827
+ * (via Omit) so `.stubBefore()` / `.withVerify()` keep the brand.
802
828
  */
803
- export type NavBlock<Out extends Checkpoint<string>> = DefinedBlock<Checkpoint<string>, Out>;
829
+ export type NavBlock<Out extends Checkpoint<string>> = Omit<DefinedBlock<Checkpoint<string>, Out>, "withVerify" | "modVerify" | "modVerifyAll" | "stubBefore" | "stubAfter" | "stubOnError"> & {
830
+ readonly __wgFactory?: "nav";
831
+ withVerify(verify: Trait[] | ((out: Out) => Trait[])): NavBlock<Out>;
832
+ modVerify(nameOrIndex: string | number, newCheck: Trait["check"] | Trait): NavBlock<Out>;
833
+ modVerifyAll(patches: Record<string, Trait["check"] | Trait>): NavBlock<Out>;
834
+ stubBefore(stub: import("./highlights.js").HighlightStubPhase): NavBlock<Out>;
835
+ stubBefore(stub: import("./highlights.js").StubLifecycleFn<Out>): NavBlock<Out>;
836
+ stubBefore(stub: (out: Out) => import("./highlights.js").HighlightStubPhase): NavBlock<Out>;
837
+ stubAfter(stub: import("./highlights.js").HighlightStubPhase): NavBlock<Out>;
838
+ stubAfter(stub: import("./highlights.js").StubLifecycleFn<Out>): NavBlock<Out>;
839
+ stubAfter(stub: (out: Out) => import("./highlights.js").HighlightStubPhase): NavBlock<Out>;
840
+ stubOnError(stub: import("./highlights.js").HighlightStubPhase): NavBlock<Out>;
841
+ stubOnError(stub: import("./highlights.js").StubLifecycleFn<Out>): NavBlock<Out>;
842
+ stubOnError(stub: (out: Out) => import("./highlights.js").HighlightStubPhase): NavBlock<Out>;
843
+ };
804
844
  /**
805
845
  * `defineNavBlock`'s own options - exactly one of `url`/`click` required,
806
846
  * enforced at compile time (giving both, or neither, is a type error - see
@@ -897,7 +937,21 @@ export declare function defineNavClickBlock<Out extends Checkpoint<string>>(opti
897
937
  * {@link defineEffectBlock} when the auto menu should spawn one row per live
898
938
  * DOM instance. Prefer hanging methods off a {@link definePageBlock} hub.
899
939
  */
900
- export type MethodBlock<In extends Checkpoint<string>, Out extends Checkpoint<string>> = DefinedBlock<In, Out>;
940
+ export type MethodBlock<In extends Checkpoint<string>, Out extends Checkpoint<string>> = Omit<DefinedBlock<In, Out>, "withVerify" | "modVerify" | "modVerifyAll" | "stubBefore" | "stubAfter" | "stubOnError"> & {
941
+ readonly __wgFactory?: "method";
942
+ withVerify(verify: Trait[] | ((out: Out) => Trait[])): MethodBlock<In, Out>;
943
+ modVerify(nameOrIndex: string | number, newCheck: Trait["check"] | Trait): MethodBlock<In, Out>;
944
+ modVerifyAll(patches: Record<string, Trait["check"] | Trait>): MethodBlock<In, Out>;
945
+ stubBefore(stub: import("./highlights.js").HighlightStubPhase): MethodBlock<In, Out>;
946
+ stubBefore(stub: import("./highlights.js").StubLifecycleFn<Out>): MethodBlock<In, Out>;
947
+ stubBefore(stub: (out: Out) => import("./highlights.js").HighlightStubPhase): MethodBlock<In, Out>;
948
+ stubAfter(stub: import("./highlights.js").HighlightStubPhase): MethodBlock<In, Out>;
949
+ stubAfter(stub: import("./highlights.js").StubLifecycleFn<Out>): MethodBlock<In, Out>;
950
+ stubAfter(stub: (out: Out) => import("./highlights.js").HighlightStubPhase): MethodBlock<In, Out>;
951
+ stubOnError(stub: import("./highlights.js").HighlightStubPhase): MethodBlock<In, Out>;
952
+ stubOnError(stub: import("./highlights.js").StubLifecycleFn<Out>): MethodBlock<In, Out>;
953
+ stubOnError(stub: (out: Out) => import("./highlights.js").HighlightStubPhase): MethodBlock<In, Out>;
954
+ };
901
955
  /** @deprecated Prefer {@link MethodBlock} - same type; Action was the 0.7 name. */
902
956
  export type ActionBlock<In extends Checkpoint<string>, Out extends Checkpoint<string>> = MethodBlock<In, Out>;
903
957
  export declare function defineMethodBlock<In extends Checkpoint<string>, Out extends Checkpoint<string>>(base: Parameters<typeof defineBlock<In, Out>>[0]): MethodBlock<In, Out>;
@@ -941,7 +995,26 @@ export interface AssertBlockOptions<Out extends Checkpoint<string> = Checkpoint<
941
995
  * verify: [Trait.visible(RawMaterialsSel.reorderBadge)],
942
996
  * });
943
997
  */
944
- export declare function defineAssertBlock<Out extends Checkpoint<string> = Checkpoint<string>>(options: AssertBlockOptions<Out>): MethodBlock<Out, Out>;
998
+ export declare function defineAssertBlock<Out extends Checkpoint<string> = Checkpoint<string>>(options: AssertBlockOptions<Out>): AssertBlock<Out>;
999
+ /**
1000
+ * Self-loop verify Block from {@link defineAssertBlock}. Branded for
1001
+ * {@link MapBuilder.assert} (not accepted by `.method()`).
1002
+ */
1003
+ export type AssertBlock<Out extends Checkpoint<string>> = Omit<DefinedBlock<Out, Out>, "withVerify" | "modVerify" | "modVerifyAll" | "stubBefore" | "stubAfter" | "stubOnError"> & {
1004
+ readonly __wgFactory?: "assert";
1005
+ withVerify(verify: Trait[] | ((out: Out) => Trait[])): AssertBlock<Out>;
1006
+ modVerify(nameOrIndex: string | number, newCheck: Trait["check"] | Trait): AssertBlock<Out>;
1007
+ modVerifyAll(patches: Record<string, Trait["check"] | Trait>): AssertBlock<Out>;
1008
+ stubBefore(stub: import("./highlights.js").HighlightStubPhase): AssertBlock<Out>;
1009
+ stubBefore(stub: import("./highlights.js").StubLifecycleFn<Out>): AssertBlock<Out>;
1010
+ stubBefore(stub: (out: Out) => import("./highlights.js").HighlightStubPhase): AssertBlock<Out>;
1011
+ stubAfter(stub: import("./highlights.js").HighlightStubPhase): AssertBlock<Out>;
1012
+ stubAfter(stub: import("./highlights.js").StubLifecycleFn<Out>): AssertBlock<Out>;
1013
+ stubAfter(stub: (out: Out) => import("./highlights.js").HighlightStubPhase): AssertBlock<Out>;
1014
+ stubOnError(stub: import("./highlights.js").HighlightStubPhase): AssertBlock<Out>;
1015
+ stubOnError(stub: import("./highlights.js").StubLifecycleFn<Out>): AssertBlock<Out>;
1016
+ stubOnError(stub: (out: Out) => import("./highlights.js").HighlightStubPhase): AssertBlock<Out>;
1017
+ };
945
1018
  /** One Block (or lazy factory) registered on a {@link PageBlock}. */
946
1019
  export type PageMethodEntry = DefinedBlock<any, any> | (() => DefinedBlock<any, any>);
947
1020
  export type PageBlockOptions<Out extends Checkpoint<string>> = {
@@ -975,10 +1048,25 @@ export type PageBlockOptions<Out extends Checkpoint<string>> = {
975
1048
  * readability / auto grouping. Runtime is still a Block (`__waygraphKind = "page"`).
976
1049
  * `act` is goto/click when `url`/`click` is set, otherwise a no-op (already here).
977
1050
  * Child methods stay ordinary Blocks for graph edges - the page only registers them.
1051
+ * Branded `__wgFactory: "page"` (not `"nav"`) - both are accepted by
1052
+ * {@link MapBuilder.gotoPage} / {@link MapBuilder.gotoExternal}.
978
1053
  */
979
- export type PageBlock<Out extends Checkpoint<string>> = NavBlock<Out> & {
1054
+ export type PageBlock<Out extends Checkpoint<string>> = Omit<DefinedBlock<Checkpoint<string>, Out>, "withVerify" | "modVerify" | "modVerifyAll" | "stubBefore" | "stubAfter" | "stubOnError"> & {
1055
+ readonly __wgFactory?: "page";
980
1056
  /** Resolved method Blocks registered at define time. */
981
1057
  readonly methods: readonly DefinedBlock<any, any>[];
1058
+ withVerify(verify: Trait[] | ((out: Out) => Trait[])): PageBlock<Out>;
1059
+ modVerify(nameOrIndex: string | number, newCheck: Trait["check"] | Trait): PageBlock<Out>;
1060
+ modVerifyAll(patches: Record<string, Trait["check"] | Trait>): PageBlock<Out>;
1061
+ stubBefore(stub: import("./highlights.js").HighlightStubPhase): PageBlock<Out>;
1062
+ stubBefore(stub: import("./highlights.js").StubLifecycleFn<Out>): PageBlock<Out>;
1063
+ stubBefore(stub: (out: Out) => import("./highlights.js").HighlightStubPhase): PageBlock<Out>;
1064
+ stubAfter(stub: import("./highlights.js").HighlightStubPhase): PageBlock<Out>;
1065
+ stubAfter(stub: import("./highlights.js").StubLifecycleFn<Out>): PageBlock<Out>;
1066
+ stubAfter(stub: (out: Out) => import("./highlights.js").HighlightStubPhase): PageBlock<Out>;
1067
+ stubOnError(stub: import("./highlights.js").HighlightStubPhase): PageBlock<Out>;
1068
+ stubOnError(stub: import("./highlights.js").StubLifecycleFn<Out>): PageBlock<Out>;
1069
+ stubOnError(stub: (out: Out) => import("./highlights.js").HighlightStubPhase): PageBlock<Out>;
982
1070
  };
983
1071
  /** @see {@link PageBlockOptions} */
984
1072
  export declare function definePageBlock<Out extends Checkpoint<string>>(options: PageBlockOptions<Out>): PageBlock<Out>;
@@ -988,9 +1076,22 @@ export declare function definePageBlock<Out extends Checkpoint<string>>(options:
988
1076
  * row per live instance (add/remove/toggle). Not a separate engine concept -
989
1077
  * everything is still a Block.
990
1078
  */
991
- export type EffectBlock<In extends Checkpoint<string>, Out extends Checkpoint<string>> = DefinedBlock<In, Out> & {
1079
+ export type EffectBlock<In extends Checkpoint<string>, Out extends Checkpoint<string>> = Omit<DefinedBlock<In, Out>, "withVerify" | "modVerify" | "modVerifyAll" | "stubBefore" | "stubAfter" | "stubOnError"> & {
1080
+ readonly __wgFactory?: "effect";
992
1081
  requires: readonly MemKey<any>[];
993
1082
  instanceOptions: NonNullable<Block<In, Out>["instanceOptions"]>;
1083
+ withVerify(verify: Trait[] | ((out: Out) => Trait[])): EffectBlock<In, Out>;
1084
+ modVerify(nameOrIndex: string | number, newCheck: Trait["check"] | Trait): EffectBlock<In, Out>;
1085
+ modVerifyAll(patches: Record<string, Trait["check"] | Trait>): EffectBlock<In, Out>;
1086
+ stubBefore(stub: import("./highlights.js").HighlightStubPhase): EffectBlock<In, Out>;
1087
+ stubBefore(stub: import("./highlights.js").StubLifecycleFn<Out>): EffectBlock<In, Out>;
1088
+ stubBefore(stub: (out: Out) => import("./highlights.js").HighlightStubPhase): EffectBlock<In, Out>;
1089
+ stubAfter(stub: import("./highlights.js").HighlightStubPhase): EffectBlock<In, Out>;
1090
+ stubAfter(stub: import("./highlights.js").StubLifecycleFn<Out>): EffectBlock<In, Out>;
1091
+ stubAfter(stub: (out: Out) => import("./highlights.js").HighlightStubPhase): EffectBlock<In, Out>;
1092
+ stubOnError(stub: import("./highlights.js").HighlightStubPhase): EffectBlock<In, Out>;
1093
+ stubOnError(stub: import("./highlights.js").StubLifecycleFn<Out>): EffectBlock<In, Out>;
1094
+ stubOnError(stub: (out: Out) => import("./highlights.js").HighlightStubPhase): EffectBlock<In, Out>;
994
1095
  };
995
1096
  /** @deprecated Prefer {@link EffectBlock} - same type; Mem* was an early name. */
996
1097
  export type MemEffectBlock<In extends Checkpoint<string>, Out extends Checkpoint<string>> = EffectBlock<In, Out>;
@@ -1064,7 +1165,18 @@ export declare function locate(page: Page, library: readonly NavBlock<any>[], op
1064
1165
  * argument at all, only whatever `verify` each Block's own `instruction` (or
1065
1166
  * a `withVerify(...)` wrapping it) carries with it.
1066
1167
  */
1067
- export declare function withVerify<In extends Checkpoint<string>, Out extends Checkpoint<string>>(block: Block<In, Out>, verify: Trait[] | ((out: Out) => Trait[])): DefinedBlock<In, Out>;
1168
+ export declare function withVerify<B extends Block<any, any>>(block: B, verify: Trait[] | ((out: any) => Trait[])): B;
1169
+ type StubPhaseFn<Out extends Checkpoint<string>> = import("./highlights.js").HighlightStubPhaseOrFn<Out>;
1170
+ /**
1171
+ * Attach / chain a stubBefore lifecycle on a Block. Prefer
1172
+ * `(ctx) => { ctx.ring(...); const x = ctx.mem?.get(Key); }`.
1173
+ * @example FillUsernameBlock.stubBefore((ctx) => { ctx.ring("username", { ... }) })
1174
+ */
1175
+ export declare function withStubBefore<B extends Block<any, any>>(block: B, stub: StubPhaseFn<any>): B;
1176
+ /** @see {@link withStubBefore} */
1177
+ export declare function withStubAfter<B extends Block<any, any>>(block: B, stub: StubPhaseFn<any>): B;
1178
+ /** @see {@link withStubBefore} */
1179
+ export declare function withStubOnError<B extends Block<any, any>>(block: B, stub: StubPhaseFn<any>): B;
1068
1180
  /**
1069
1181
  * Replaces one Trait inside `block`'s verify list, leaving every other check
1070
1182
  * untouched - the v1/v2/legacy-variant case, where one check needs a different