waygraph 0.15.11 → 0.15.15
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/README.md +67 -26
- package/dist/auto-explore.d.ts +7 -6
- package/dist/auto-explore.js +43 -32
- package/dist/auto-session-ipc.d.ts +13 -0
- package/dist/auto-session-ipc.js +119 -7
- package/dist/auto-session.d.ts +16 -13
- package/dist/auto-session.js +72 -53
- package/dist/block-inject.d.ts +15 -0
- package/dist/block-inject.js +91 -0
- package/dist/browser.d.ts +15 -0
- package/dist/browser.js +29 -0
- package/dist/cli.js +335 -47
- package/dist/coverage-gap.d.ts +11 -0
- package/dist/coverage-gap.js +119 -0
- package/dist/graph.d.ts +1 -0
- package/dist/graph.js +99 -91
- package/dist/pilot-overlay.d.ts +7 -1
- package/dist/pilot-overlay.js +59 -41
- package/dist/pilot.d.ts +7 -2
- package/dist/pilot.js +34 -7
- package/dist/practices-check.d.ts +14 -0
- package/dist/practices-check.js +115 -0
- package/examples/saucedemo/.waygraph-auto/0b937f26.log +4 -0
- package/examples/saucedemo/.waygraph-auto/2b608ed3.log +0 -0
- package/examples/saucedemo/.waygraph-auto/2c13567b.log +0 -0
- package/examples/saucedemo/.waygraph-auto/2d9622a5.log +4 -0
- package/examples/saucedemo/.waygraph-auto/305f6e5b.log +4 -0
- package/examples/saucedemo/.waygraph-auto/418befbf.log +4 -0
- package/examples/saucedemo/.waygraph-auto/483bd763.log +4 -0
- package/examples/saucedemo/.waygraph-auto/48e3596a.log +0 -0
- package/examples/saucedemo/.waygraph-auto/4adfbe91.json +8 -0
- package/examples/saucedemo/.waygraph-auto/4adfbe91.log +0 -0
- package/examples/saucedemo/.waygraph-auto/4f0e33e7.log +4 -0
- package/examples/saucedemo/.waygraph-auto/5bd8fedf.log +4 -0
- package/examples/saucedemo/.waygraph-auto/5dde8331.log +4 -0
- package/examples/saucedemo/.waygraph-auto/68903903.log +0 -0
- package/examples/saucedemo/.waygraph-auto/78bbf43c.log +0 -0
- package/examples/saucedemo/.waygraph-auto/7efa646f.log +4 -0
- package/examples/saucedemo/.waygraph-auto/9cecb0c8.log +4 -0
- package/examples/saucedemo/.waygraph-auto/aae57d51.log +0 -0
- package/examples/saucedemo/.waygraph-auto/b61a08d8.log +0 -0
- package/examples/saucedemo/.waygraph-auto/c946f66c.log +0 -0
- package/examples/saucedemo/.waygraph-auto/cd0d5b50.log +4 -0
- package/examples/saucedemo/.waygraph-auto/cd5b203c.log +0 -0
- package/examples/saucedemo/.waygraph-auto/ea2df316.log +4 -0
- package/examples/saucedemo/.waygraph-auto/ee60ed24.log +0 -0
- package/examples/saucedemo/.waygraph-auto/f2b6cb1b.log +0 -0
- package/examples/saucedemo/.waygraph-auto/f392cdc8.log +0 -0
- package/package.json +2 -2
- package/templates/scaffold/package.json +1 -1
- package/templates/skills/waygraph-blind-pilot.skill.md +30 -15
- package/templates/skills/waygraph-convention.skill.md +11 -1
- package/templates/skills/waygraph-pilot.skill.md +71 -4
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
(node:1438409) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
|
|
2
|
+
(Use `node --trace-warnings ...` to show where the warning was created)
|
|
3
|
+
(node:1438409) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
|
|
4
|
+
(Use `node --trace-warnings ...` to show where the warning was created)
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
(node:1424575) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
|
|
2
|
+
(Use `node --trace-warnings ...` to show where the warning was created)
|
|
3
|
+
(node:1424575) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
|
|
4
|
+
(Use `node --trace-warnings ...` to show where the warning was created)
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
(node:1424626) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
|
|
2
|
+
(Use `node --trace-warnings ...` to show where the warning was created)
|
|
3
|
+
(node:1424626) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
|
|
4
|
+
(Use `node --trace-warnings ...` to show where the warning was created)
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
(node:1434346) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
|
|
2
|
+
(Use `node --trace-warnings ...` to show where the warning was created)
|
|
3
|
+
(node:1434346) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
|
|
4
|
+
(Use `node --trace-warnings ...` to show where the warning was created)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
(node:1434366) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
|
|
2
|
+
(Use `node --trace-warnings ...` to show where the warning was created)
|
|
3
|
+
(node:1434366) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
|
|
4
|
+
(Use `node --trace-warnings ...` to show where the warning was created)
|
|
File without changes
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
(node:1429810) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
|
|
2
|
+
(Use `node --trace-warnings ...` to show where the warning was created)
|
|
3
|
+
(node:1429810) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
|
|
4
|
+
(Use `node --trace-warnings ...` to show where the warning was created)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "waygraph",
|
|
3
|
-
"version": "0.15.
|
|
3
|
+
"version": "0.15.15",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "A typed graph of reusable Blocks for driving a browser through E2E flows.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
},
|
|
36
36
|
"scripts": {
|
|
37
37
|
"build": "tsc -p tsconfig.build.json",
|
|
38
|
-
"typecheck": "
|
|
38
|
+
"typecheck": "node bin/waygraph typecheck .",
|
|
39
39
|
"test": "playwright test",
|
|
40
40
|
"docs:preview": "python3 -m http.server 4173 --directory docs",
|
|
41
41
|
"example:saucedemo:install": "npm --prefix examples/saucedemo install",
|
|
@@ -4,16 +4,29 @@ description: Cold-start a waygraph project against a real site with zero existin
|
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
Blind Pilot is the same session mechanism as `waygraph-pilot`, minus the requirement of any
|
|
7
|
-
pre-existing Blocks.
|
|
8
|
-
`
|
|
7
|
+
pre-existing Blocks. A project with zero `.block.ts` files still gets a live session —
|
|
8
|
+
`browser click/type/goto/press/upload` act on the real page before any Block exists to cover it.
|
|
9
9
|
This package generates **no Block content for you** - you write real `.block.ts`/`*Sel`/
|
|
10
10
|
mem-key files by hand as you go. That's the whole point: turn one-off exploration into
|
|
11
11
|
permanent, reusable, typed coverage instead of leaving nothing behind.
|
|
12
12
|
|
|
13
|
+
## Session lifecycle (list first)
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
waygraph browser # show browser subcommands
|
|
17
|
+
waygraph browser sessions # list live sessions (cwd)
|
|
18
|
+
waygraph browser start [--goto <url>] # new headful session (about:blank by default)
|
|
19
|
+
waygraph browser attach <sessionId> # terminal picker on existing session
|
|
20
|
+
waygraph browser stop <sessionId|--all> # shut down when done
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
`browser start` always opens a **new** session. Check `browser sessions` before starting another.
|
|
24
|
+
Session control works as `browser …` or `auto …` with the same `<sessionId>`.
|
|
25
|
+
|
|
13
26
|
## The real loop
|
|
14
27
|
|
|
15
|
-
1. `
|
|
16
|
-
2. `
|
|
28
|
+
1. `browser goto <sessionId> <url>` / `browser click` / `browser type` to explore the real page.
|
|
29
|
+
2. `browser dom <sessionId> --mode full --selector <sel>` to read real structure before writing
|
|
17
30
|
a selector - never guess a selector, confirm it against the real DOM first. `--mode aria`
|
|
18
31
|
is faster for a first pass but can show stale/hidden responsive-duplicate content in some
|
|
19
32
|
real apps (confirmed live: a hidden `lg:hidden` panel's heading text showed up in an aria
|
|
@@ -24,19 +37,20 @@ permanent, reusable, typed coverage instead of leaving nothing behind.
|
|
|
24
37
|
then `Nav`/`Page`/`Method` Blocks, following `templates/scaffold`'s own folder convention
|
|
25
38
|
(`(group)/<page-slug>/page.block.ts` + `nav.block.ts` + `methods/*.block.ts` + one `*.sel.ts`)
|
|
26
39
|
so the result becomes part of the Waygraph Map, not a scattered one-off file.
|
|
27
|
-
4. `
|
|
28
|
-
5. Optionally narrate for a headful watcher: `
|
|
29
|
-
|
|
40
|
+
4. `browser reload <sessionId>` to pick up the newly-written Block(s) without restarting.
|
|
41
|
+
5. Optionally narrate for a headful watcher: `browser highlight <sessionId> '{"rings":[...],"todos":[...]}'`
|
|
42
|
+
Raw ops show **`Running (no Block): …`** in the bottom-left toast; Block runs show **`Running (Block): …`**.
|
|
43
|
+
6. Run the new Block for real via `browser send` - prove it works before moving to the next
|
|
30
44
|
pattern, exactly like any other real Block.
|
|
31
|
-
|
|
45
|
+
7. Ask the user a clarifying question only when something genuinely can't be resolved from
|
|
32
46
|
the DOM alone (is this instance local or published? does a downstream integration exist?)
|
|
33
|
-
- don't ask about things `
|
|
47
|
+
- don't ask about things `browser dom` can just answer.
|
|
34
48
|
|
|
35
49
|
## Real gotchas specific to cold-start authoring
|
|
36
50
|
|
|
37
51
|
- **`discoverGraph`'s per-file import errors are mostly silent.** A malformed newly-written
|
|
38
52
|
Block file can simply vanish from the graph with no error printed anywhere obvious - if a
|
|
39
|
-
Block you just wrote doesn't show up after `
|
|
53
|
+
Block you just wrote doesn't show up after `browser reload`, check `waygraph graph`'s own
|
|
40
54
|
`skipped` list and the file's syntax directly, don't assume it just needs more time.
|
|
41
55
|
- **`defineAssertBlock` needs no `<In, Out>` generic to type-check** (`checkpoint: "X"` alone
|
|
42
56
|
is enough for TypeScript to infer it) - but older/naive static-graph discovery logic may
|
|
@@ -47,9 +61,9 @@ permanent, reusable, typed coverage instead of leaving nothing behind.
|
|
|
47
61
|
- **A `<p>`/text-based selector often needs scoping**, not just a class name - a sibling
|
|
48
62
|
"chat list item" and "message preview" frequently share the exact same CSS classes in real
|
|
49
63
|
apps, distinguished only by DOM position (first vs second child of a specific wrapper).
|
|
50
|
-
Confirm via `
|
|
64
|
+
Confirm via `browser dom --mode full` before assuming a class alone is unique enough.
|
|
51
65
|
- **Confirm a selector count, not just its first match**, when building anything the menu
|
|
52
|
-
will expand into multiple live rows (an `instanceOptions`-driven Block) - `
|
|
66
|
+
will expand into multiple live rows (an `instanceOptions`-driven Block) - `browser dom`'s
|
|
53
67
|
default read can silently show only one match even when several exist; check the real
|
|
54
68
|
page count (e.g. via a scoped debug script) before assuming a plain `.first()` is safe
|
|
55
69
|
long-term. A `.first()`-shaped Block is a legitimate STARTING point for a page that only
|
|
@@ -57,6 +71,7 @@ permanent, reusable, typed coverage instead of leaving nothing behind.
|
|
|
57
71
|
`defineEffectBlock` (see the `waygraph-pilot` skill and
|
|
58
72
|
`examples/saucedemo/.../nav-item-detail.block.ts` for the real pattern) once a second real
|
|
59
73
|
row genuinely exists to pick between, not before.
|
|
60
|
-
- **Prefer the real Pilot overlay over ad hoc status output** when driving a
|
|
61
|
-
|
|
62
|
-
|
|
74
|
+
- **Prefer the real Pilot overlay over ad hoc status output** when driving a headful session
|
|
75
|
+
someone might be watching - badge/panel on `about:blank` and after every navigation; raw
|
|
76
|
+
ops toast **`Running (no Block): …`**. Point a human at the badge instead of re-inventing
|
|
77
|
+
status reporting.
|
|
@@ -24,6 +24,14 @@ against a live site, use `--skill-pilot-blind`.
|
|
|
24
24
|
an explicit type argument when it sits between two specifically-typed Blocks in a Flow.
|
|
25
25
|
5. **`requires` = externally supplied.** A key an earlier Block in the same chain produces
|
|
26
26
|
is never listed under `requires` - preflight checks the whole chain up front.
|
|
27
|
+
6. **Keep Checkpoints typed — never `Checkpoint<string>`.** Block helpers take concrete
|
|
28
|
+
Checkpoint types from `src/states/` (e.g. `defineMethodBlock<LoginPage, LoginPage>`).
|
|
29
|
+
Wildcard `Checkpoint<string>` compiles but kills graph honesty; `waygraph check` / `waygraph typecheck` warn.
|
|
30
|
+
Same for `defineAssertBlock({…})` without an explicit type arg — use
|
|
31
|
+
`defineAssertBlock<YourCheckpoint>({…})`.
|
|
32
|
+
7. **One input/action per Method Block.** No block that `.fill()`s two fields or `.fill()` + `.click()` in one
|
|
33
|
+
`act()` — split like saucedemo login (`fill-username`, `fill-password`, `submit-login`). Opt out per file:
|
|
34
|
+
`// waygraph-ignore: multi-input` or `// waygraph-ignore-practices`.
|
|
27
35
|
|
|
28
36
|
## Block kinds (file convention)
|
|
29
37
|
|
|
@@ -84,7 +92,9 @@ the site's `*-web/` tree. Browser-driven (DOM / iframe Traits), not the catcher'
|
|
|
84
92
|
## Verify before you call it done
|
|
85
93
|
|
|
86
94
|
```bash
|
|
87
|
-
npx waygraph check . # orphans + nav-escape + inline-selector warnings
|
|
95
|
+
npx waygraph check . # orphans + nav-escape + inline-selector + bad-practice warnings
|
|
96
|
+
npx waygraph typecheck . # tsc --noEmit + bad-practice warnings (npm run typecheck)
|
|
97
|
+
npx waygraph check --no-practices . # skip bad-practice scan only
|
|
88
98
|
npx waygraph map . # exit 1 if src/map/ folder path != real static url
|
|
89
99
|
npx waygraph validate . # every .flow.ts loads
|
|
90
100
|
npx waygraph graph . # nodes/edges/skipped/orphans - counts should make sense
|
|
@@ -9,10 +9,37 @@ the reasoning agent. Every multi-step decision (which Block to run next, when a
|
|
|
9
9
|
`reach` vs `send`, when to fall back to raw primitives) is yours to make, turn by turn, by
|
|
10
10
|
reading each `auto status`/`auto send` response.
|
|
11
11
|
|
|
12
|
+
## auto vs browser vs pilot (do not conflate them)
|
|
13
|
+
|
|
14
|
+
| Layer | Command | What it is |
|
|
15
|
+
|-------|---------|------------|
|
|
16
|
+
| **auto** | `waygraph auto` | Interactive explore (picker / `--cli` menu). **Not** a persistent agent browser. |
|
|
17
|
+
| **browser** | `waygraph browser start` | New persistent Playwright session — **headful by default**, **about:blank by default**. `waygraph browser` prints subcommands; `browser sessions` lists live ones. |
|
|
18
|
+
| **pilot** | `waygraph pilot start` | Bootstrap only: `browser start` + whole-project `graph` + starting `snapshot` in one JSON payload. Does not plan or act. |
|
|
19
|
+
|
|
20
|
+
Session control (`send`, `status`, `highlight`, `dom`, …) works on **`auto`**, **`browser`**, and **`pilot`** — same socket, same session id:
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
waygraph browser send <sessionId> "<pick>" # same as auto send / pilot send
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
**Session lifecycle — list first, then attach or start:**
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
waygraph browser sessions [project] # what's live right now
|
|
30
|
+
waygraph browser attach <sessionId> # terminal picker on an existing session
|
|
31
|
+
waygraph browser stop <sessionId|--all> # shut one down when done
|
|
32
|
+
waygraph pilot attach <sessionId> # graph + snapshot for an existing session
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
`browser start` / `pilot start` always open a **new** session. Check `browser sessions` before starting another.
|
|
36
|
+
|
|
12
37
|
## Starting a session
|
|
13
38
|
|
|
14
39
|
```
|
|
15
40
|
waygraph pilot start # bootstraps: {sessionId, socketPath, headless, graph, snapshot}
|
|
41
|
+
waygraph browser start [--inject path] [--goto <url>] [--cli] # new browser session; --cli opens terminal picker
|
|
42
|
+
waygraph pilot start [--cli] # --cli opens terminal picker after bootstrap JSON
|
|
16
43
|
waygraph auto status <sessionId> # re-read the live menu, no side effects
|
|
17
44
|
waygraph auto send <sessionId> "<pick>" # run exactly one Block (by menu index or name)
|
|
18
45
|
waygraph auto reach <sessionId> <Checkpoint> # path-find + run a whole route in one call
|
|
@@ -23,6 +50,47 @@ waygraph auto highlight <sessionId> '<json>' # paint rings/todos on the live pa
|
|
|
23
50
|
just what's reachable from here - use it to plan several steps ahead before you start
|
|
24
51
|
sending picks.
|
|
25
52
|
|
|
53
|
+
## Bad practices (`waygraph check` / `waygraph typecheck`)
|
|
54
|
+
|
|
55
|
+
Run `waygraph typecheck .` (or `npm run typecheck`) — runs `tsc --noEmit` then bad-practice warnings.
|
|
56
|
+
`waygraph check` includes the same practice scan plus nav/orphan/selector hygiene.
|
|
57
|
+
Use `--no-practices` on either command to skip the practice scan.
|
|
58
|
+
|
|
59
|
+
Patterns warned (does not fail `check`; fails `typecheck` only when `tsc` fails):
|
|
60
|
+
|
|
61
|
+
- **`Checkpoint<string>` in Block generics** — e.g. `defineMethodBlock<Checkpoint<string>, …>` instead of a project Checkpoint type from `src/states/`.
|
|
62
|
+
- **`defineAssertBlock({…})` without an explicit type arg** — use `defineAssertBlock<YourCheckpoint>({…})` so `defineFlow` typing stays honest.
|
|
63
|
+
- **Multiple `.fill()` in one Method** — split into one Block per input (fill-username, fill-password, …).
|
|
64
|
+
- **`.fill()` + `.click()` in one Method** — split fill and submit into separate Blocks.
|
|
65
|
+
|
|
66
|
+
Opt out per file: `// waygraph-ignore-practices` or `// waygraph-ignore: multi-input, combined-action`.
|
|
67
|
+
|
|
68
|
+
Fix these before adding more Blocks; wildcard Checkpoints hide real graph edges from the type checker.
|
|
69
|
+
|
|
70
|
+
## Coverage gaps on the live page (`auto console`)
|
|
71
|
+
|
|
72
|
+
After `auto status` / `auto send`, read `waygraph auto console <sessionId>` — the session warns once per page load about:
|
|
73
|
+
|
|
74
|
+
- **Unmapped hrefs** — same-origin `<a href>` paths with no `defineNavBlock` URL.
|
|
75
|
+
- **Unmapped buttons** — visible `button` / `[role=button]` / submit inputs with no Method or NavClick selector in the Block library.
|
|
76
|
+
|
|
77
|
+
Example warnings:
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
[waygraph] unmapped nav link on this page: /settings - no NavBlock covers this URL; add defineNavBlock
|
|
81
|
+
[waygraph] unmapped button on this page: #save-draft - no Method/NavClick Block selector matches; consider defineMethodBlock or defineNavClickBlock
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
When you see these, author the missing Block — do not keep clicking raw primitives.
|
|
85
|
+
|
|
86
|
+
## Session reachability (multi-pane / wrong cwd)
|
|
87
|
+
|
|
88
|
+
Session ids are registered globally under `/tmp/waygraph-auto/` as well as `<project>/.waygraph-auto/`. If `auto status` says unreachable:
|
|
89
|
+
|
|
90
|
+
1. Run `waygraph pilot sessions` from the project that started the browser — reuse the id, do not spawn again.
|
|
91
|
+
2. Or `waygraph pilot attach <sessionId>` for graph + snapshot without a new browser.
|
|
92
|
+
3. Stale metadata (crashed pid) is pruned automatically — start fresh only when the pid is actually gone.
|
|
93
|
+
|
|
26
94
|
## Highlight fixtures (Pilot supports them — use `auto highlight`)
|
|
27
95
|
|
|
28
96
|
**Yes, Pilot paints rings/todos/zoom/device on the live page.** That is what
|
|
@@ -73,7 +141,7 @@ Supported fields (demo parity):
|
|
|
73
141
|
- `clear`: true drops rings/todos/focus/zoom badge
|
|
74
142
|
|
|
75
143
|
- `tone`: all demo tones - `planned` | `auto` | `info` | `warning` | `danger` | `success` | `orange` (aliases like `error`/`blue`/`green` work too)
|
|
76
|
-
- Bottom-left toast shows `Highlighting: …` (same strip as `Running (
|
|
144
|
+
- Bottom-left toast shows `Highlighting: …` (same strip as `Running (no Block): …` for raw ops)
|
|
77
145
|
- Missing selectors are listed in the JSON response (`missing`) - not a hard failure
|
|
78
146
|
- Does not replace `auto send` - paint, then run the real Block
|
|
79
147
|
|
|
@@ -100,9 +168,8 @@ only ever be as good as the project's own Block coverage: if two Checkpoints sha
|
|
|
100
168
|
and nothing in their `verify` arrays tells them apart, `resync` will confidently report the
|
|
101
169
|
wrong one. This is a coverage gap in the project's Blocks, not a `resync` bug - if you hit
|
|
102
170
|
one, fix the ambiguity (add a second, concrete `Trait.visible` condition that's only true in
|
|
103
|
-
one of the two states
|
|
104
|
-
|
|
105
|
-
"Leave pool" button).
|
|
171
|
+
one of the two states — e.g. the same route with different visible buttons that distinguish
|
|
172
|
+
pool membership vs home).
|
|
106
173
|
|
|
107
174
|
## Rule 3: mem is intent, Checkpoint is reality - never blur them
|
|
108
175
|
|