@atlassian/chippy 0.0.0-stage → 0.0.1-beta.1

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 (126) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +188 -2
  3. package/bin/chippy.mjs +134 -0
  4. package/bin/pack.mjs +184 -0
  5. package/lib/avalanche.js +2570 -0
  6. package/lib/avalanche.js.map +7 -0
  7. package/lib/bootstrap.d.ts +1 -0
  8. package/lib/bootstrap.js +51 -0
  9. package/lib/bootstrap.js.map +7 -0
  10. package/lib/browser.js +15 -0
  11. package/lib/browser.js.map +7 -0
  12. package/lib/extension/avalanche.es.js +5396 -0
  13. package/lib/extension/avalanche.es.js.map +1 -0
  14. package/lib/extension/chippy-page-bridge.js +1833 -0
  15. package/lib/extension/inspect-react.js +216 -0
  16. package/lib/extension/layout-lab.js +1453 -0
  17. package/lib/extension/panel-dom.js +90 -0
  18. package/lib/extension/resolve-probes.js +342 -0
  19. package/lib/mcp-skill/LICENSE +201 -0
  20. package/lib/mcp-skill/README.md +150 -0
  21. package/lib/mcp-skill/SKILL.md +330 -0
  22. package/lib/mcp-skill/browser-scripts/playwright-probes.js +368 -0
  23. package/lib/mcp-skill/browser-scripts/playwright-session.js +114 -0
  24. package/lib/mcp-skill/extension/avalanche.es.js +5396 -0
  25. package/lib/mcp-skill/extension/avalanche.es.js.map +1 -0
  26. package/lib/mcp-skill/extension/avalanche.iife.js +5397 -0
  27. package/lib/mcp-skill/extension/avalanche.iife.js.map +1 -0
  28. package/lib/mcp-skill/extension/background.js +323 -0
  29. package/lib/mcp-skill/extension/chippy-page-bridge.js +1833 -0
  30. package/lib/mcp-skill/extension/content-script.js +167 -0
  31. package/lib/mcp-skill/extension/devtools-hook-shim.js +68 -0
  32. package/lib/mcp-skill/extension/early-bootstrap.js +47 -0
  33. package/lib/mcp-skill/extension/icon-128.png +0 -0
  34. package/lib/mcp-skill/extension/icon-16.png +0 -0
  35. package/lib/mcp-skill/extension/icon-32.png +0 -0
  36. package/lib/mcp-skill/extension/icon-48.png +0 -0
  37. package/lib/mcp-skill/extension/inspect-react.js +216 -0
  38. package/lib/mcp-skill/extension/layout-lab.js +1453 -0
  39. package/lib/mcp-skill/extension/logo.svg +14 -0
  40. package/lib/mcp-skill/extension/manifest.json +69 -0
  41. package/lib/mcp-skill/extension/panel-dom.js +90 -0
  42. package/lib/mcp-skill/extension/panel-settings.js +191 -0
  43. package/lib/mcp-skill/extension/popup.html +41 -0
  44. package/lib/mcp-skill/extension/popup.js +80 -0
  45. package/lib/mcp-skill/extension/probe-descriptor.js +241 -0
  46. package/lib/mcp-skill/extension/resolve-probes.js +342 -0
  47. package/lib/mcp-skill/package.json +1 -0
  48. package/lib/mcp-skill/references/README.md +56 -0
  49. package/lib/mcp-skill/references/active-stimulus.md +85 -0
  50. package/lib/mcp-skill/references/avalanche-detector.md +731 -0
  51. package/lib/mcp-skill/references/bdd-router.md +310 -0
  52. package/lib/mcp-skill/references/browser-runtime-api.md +193 -0
  53. package/lib/mcp-skill/references/command-output-formats.md +1075 -0
  54. package/lib/mcp-skill/references/command-surface.md +183 -0
  55. package/lib/mcp-skill/references/cynefin.md +99 -0
  56. package/lib/mcp-skill/references/debug-hook.md +161 -0
  57. package/lib/mcp-skill/references/fixing-performance.md +490 -0
  58. package/lib/mcp-skill/references/hook-metrics.md +199 -0
  59. package/lib/mcp-skill/references/hooks-inspection.md +61 -0
  60. package/lib/mcp-skill/references/jira-taxonomy.md +81 -0
  61. package/lib/mcp-skill/references/mcp.md +122 -0
  62. package/lib/mcp-skill/references/mode-a-injection.md +68 -0
  63. package/lib/mcp-skill/references/operating-model.md +128 -0
  64. package/lib/mcp-skill/references/playwright-cli-setup.md +105 -0
  65. package/lib/mcp-skill/references/playwright-probes.md +205 -0
  66. package/lib/mcp-skill/references/procedures.md +545 -0
  67. package/lib/mcp-skill/references/recipes.txt +114 -0
  68. package/lib/mcp-skill/references/stability-render.md +428 -0
  69. package/lib/mcp-skill/references/test-mode-playbook.md +193 -0
  70. package/lib/mcp-skill/references/troubleshooting.md +54 -0
  71. package/lib/mcp-skill/scripts/avalanche-analyze.cjs +495 -0
  72. package/lib/mcp-skill/scripts/build-avalanche-command.js +34 -0
  73. package/lib/mcp-skill/scripts/build-fiber-state-command.js +19 -0
  74. package/lib/mcp-skill/scripts/chippy-helper-server.js +1710 -0
  75. package/lib/mcp-skill/scripts/chippy-mcp.cjs +273 -0
  76. package/lib/mcp-skill/scripts/chippy.sh +1218 -0
  77. package/lib/mcp-skill/scripts/format-probe-result.js +34 -0
  78. package/lib/mcp-skill/scripts/helper-access.js +144 -0
  79. package/lib/mcp-skill/scripts/probe-annotation-channel.js +116 -0
  80. package/lib/mcp-skill/scripts/search-recipes.js +248 -0
  81. package/lib/mcp-skill/snippets/README.md +89 -0
  82. package/lib/mcp-skill/snippets/count-context-consumers.js +40 -0
  83. package/lib/mcp-skill/snippets/find-context-providers.js +38 -0
  84. package/lib/mcp-skill/snippets/find-legacy-context.js +47 -0
  85. package/lib/mcp-skill/snippets/find-prop.js +83 -0
  86. package/lib/mcp-skill/snippets/hook-metrics-sample.js +69 -0
  87. package/lib/mcp-skill/snippets/hook-metrics.js +60 -0
  88. package/lib/mcp-skill/snippets/hook-tracker.js +198 -0
  89. package/lib/mcp-skill/snippets/stability-nudge.js +101 -0
  90. package/lib/package.json +1 -0
  91. package/lib/plugin.js +119 -0
  92. package/lib/plugin.js.map +7 -0
  93. package/lib/storybook/avalanche-panel-model.js +79 -0
  94. package/lib/storybook/brand.jsx +6 -0
  95. package/lib/storybook/connection-fallback.jsx +47 -0
  96. package/lib/storybook/constants.js +15 -0
  97. package/lib/storybook/context-card.jsx +171 -0
  98. package/lib/storybook/manager.jsx +403 -0
  99. package/lib/storybook/preset.js +7 -0
  100. package/lib/storybook/preview.js +263 -0
  101. package/lib/storybook/probe-annotation-editor.jsx +52 -0
  102. package/lib/storybook/probe-intent.js +23 -0
  103. package/lib/storybook/setup.js +93 -0
  104. package/lib/types/avalanche/commit-metrics-adapter.d.ts +76 -0
  105. package/lib/types/avalanche/commit-stats-indices.d.ts +41 -0
  106. package/lib/types/avalanche/commit-surface-ownership.d.ts +9 -0
  107. package/lib/types/avalanche/detector.d.ts +183 -0
  108. package/lib/types/avalanche/interaction-capture.d.ts +25 -0
  109. package/lib/types/avalanche/internals.d.ts +189 -0
  110. package/lib/types/avalanche/report-serializer.d.ts +283 -0
  111. package/lib/types/avalanche/reporter.d.ts +610 -0
  112. package/lib/types/chippy-bridge/fiber-source.d.ts +37 -0
  113. package/lib/types/chippy-bridge/react-renderer.d.ts +49 -0
  114. package/lib/types/chippy-bridge/source-map.d.ts +30 -0
  115. package/lib/types/debug-render/core.d.ts +72 -0
  116. package/lib/types/layout-lab/fiber-boundaries.d.ts +51 -0
  117. package/lib/types/layout-lab/fiber-walk.d.ts +131 -0
  118. package/lib/types/layout-lab/marker-context.d.ts +94 -0
  119. package/lib/types/package/avalanche.d.ts +6 -0
  120. package/lib/types/package/browser.d.ts +10 -0
  121. package/lib/types/package/plugin.d.ts +15 -0
  122. package/lib/types/plugins/atl/commit-metrics-adapter.d.ts +65 -0
  123. package/lib/types/plugins/atl/metrics-slot.d.ts +37 -0
  124. package/lib/types/plugins/index.d.ts +49 -0
  125. package/lib/types/plugins/jira/context-provider.d.ts +36 -0
  126. package/package.json +104 -4
@@ -0,0 +1,128 @@
1
+ # Chippy Operating Model
2
+
3
+ Chippy works in four separated phases: **Observe → Define → Prove → Apply**. This is the enforcement layer for evidence-first work. Do not collapse these phases.
4
+
5
+ Cynefin positions the work; OODA drives repeated evidence steps inside Prove. See [cynefin](cynefin.md) for the full positioning and iteration rules.
6
+
7
+ | Phase | Position or iteration role |
8
+ |---|---|
9
+ | Observe | Use read-only orientation to exit ❓ Disorder and name the domain. If it is 🔥, stabilize before further analysis. |
10
+ | Define | Frame the case in the language of the named domain — sensor question for 🔍, experiment hypothesis for 🌀. |
11
+ | Prove | Repeat OODA inside the named domain. Run sensors in 🔍; run safe-to-fail experiments through an observable SUT in 🌀. Never demand 🔍 certainty from a 🌀 system. |
12
+ | Apply | Separate from OODA Act. Allowed only when the proof packet meets the per-domain confidence rule, identifies a fix layer, and supplies repeatable verification. |
13
+
14
+ | Phase | Purpose | Question | Output | May edit? |
15
+ |---|---|---|---|---|
16
+ | **Observe** | Anchor the symptom in runtime or source reality | What is actually there? | Observation anchor: page/client, probe/fiber/testId/interaction/load window, first signal | No |
17
+ | **Define** | Name the observed thing and the invariant under test | What case did observation reveal? | Case definition: target, scope, invariant, suspected dimensions | No |
18
+ | **Prove** | Gather evidence until the case is confirmed, falsified, or bounded | What does runtime/source evidence prove? | Proof packet: runtime + structure + source + signal facts, confidence, next gap | No |
19
+ | **Apply** | Change source only after proof identifies a fix layer | What is the smallest source change that preserves the invariant? | Edit + same-signal verification | Yes, only after explicit proof |
20
+
21
+ ## OODA inside Prove
22
+
23
+ The Prove phase repeats a bounded loop:
24
+
25
+ 1. **Observe** the smallest current signal.
26
+ 2. **Orient** it against the domain, invariant, accumulated facts, and next gap.
27
+ 3. **Decide** the next move permitted by the domain and documented command surface.
28
+ 4. **Act** by executing that evidence move, then update the proof packet.
29
+
30
+ OODA Act can be read-only. It can also be a bounded stimulus or stabilizer when the domain permits one. It is never implicit authorization to edit source: only the Apply phase can do that. If new evidence changes the cause/effect posture, return to Observe, reposition, and continue with the new domain.
31
+
32
+ ## Observation contract
33
+
34
+ Before defining the case, anchor it in observed data:
35
+
36
+ ```text
37
+ Observation: <probe/fiber/interaction/load window/page state> shows <first concrete signal>.
38
+ ```
39
+
40
+ Examples:
41
+
42
+ ```text
43
+ Observation: probe 1 resolves to a status label with text "Done" under IssueHeader.
44
+ ```
45
+
46
+ ```text
47
+ Observation: after arming Avalanche and clicking Save, commit 42 has high collateral under the Save panel.
48
+ ```
49
+
50
+ ## Case definition contract
51
+
52
+ After observation, define the case in one sentence:
53
+
54
+ ```text
55
+ Case: <visible/runtime symptom> violates <expected invariant> at <scope>.
56
+ Need to prove: <prop | hook | provider | store | boundary | source | load/runtime wave>.
57
+ ```
58
+
59
+ Examples:
60
+
61
+ ```text
62
+ Case: clicking Save causes the whole panel to lag; invariant is one bounded update under the Save branch.
63
+ Need to prove: whether the trigger is local state, context propagation, store restart, or missing memo boundary.
64
+ ```
65
+
66
+ ```text
67
+ Case: this status label says Done; invariant is that displayed text comes from issue status data, not presentation fallback.
68
+ Need to prove: which owner passes the label prop and where the value is derived.
69
+ ```
70
+
71
+ ## Proof packet contract
72
+
73
+ A claim is not ready for Apply until it has a proof packet.
74
+
75
+ ```text
76
+ Definition:
77
+ target: <probe/fiber/story/page/interaction>
78
+ invariant: <what should stay true>
79
+ scope: <component/subtree/page/load/interaction>
80
+
81
+ Evidence:
82
+ runtime: <probe-dom/pages/snapshot/avalanche status/logged transition>
83
+ structure: <owners/parents/fiber/hook tree>
84
+ source: <file:line and render block>
85
+ signal: <prop value/hook primitive/context wave/commit stats>
86
+ fact split: <source fact | runtime fact | unknown bridge>
87
+
88
+ Decision:
89
+ role: <source | boundary | collateral | provider | store | mount | unknown>
90
+ confidence: confirmed | likely | partial
91
+ next gap: <none or exact missing fact>
92
+ ```
93
+
94
+ ## Apply gate
95
+
96
+ Apply is allowed when the proof packet answers four questions:
97
+
98
+ 1. **Case + evidence** — what invariant is in scope, and which runtime/source facts support it?
99
+ 2. **Signal movement** — for no-rush or emergent work, did the last tapped contract or safe-to-fail experiment move, reproduce, or falsify the observed failure?
100
+ 3. **Fix layer** — is the change above source, at a boundary, or below source?
101
+ 4. **Verification** — can the same measurement be repeated after edit, with confidence appropriate to the domain?
102
+
103
+ If any gate fails, Chippy continues proving or reports the gap. Chippy does not patch while still discovering the essence.
104
+
105
+ ### Per-domain confidence rule
106
+
107
+ Confidence is not a free-floating field. It is bounded by the Cynefin domain Observe declared. See [cynefin](cynefin.md).
108
+
109
+ | Domain | Minimum confidence to Apply | Why |
110
+ |---|---|---|
111
+ | ✅ Clear | `confirmed` | Sense → categorize → respond. The answer is deterministic; anything less than `confirmed` means the situation was misclassified. Reposition first. |
112
+ | 🔍 Complicated | `confirmed` | Sense → analyze → respond. The chain is knowable; `likely`/`partial` means analysis is incomplete — keep proving, do not apply. |
113
+ | 🌀 Complex | `likely` is sufficient **iff** the experiment is repeatable | Probe → sense → respond. Emergent systems rarely produce `confirmed`. Apply is allowed when (a) the same safe-to-fail experiment yields the same outcome on rerun, and (b) the verification command in gate 4 *is* that repeatable experiment. Never apply on `partial` in 🌀. |
114
+ | 🔥 Chaotic | — | Apply is forbidden. Stabilize first, then re-classify. |
115
+ | ❓ Disorder | — | Apply is forbidden. Use read-only orientation to position first. |
116
+
117
+ Rule of thumb: if the proof packet reports `confidence: partial`, Apply is never allowed. If it reports `confidence: likely` in 🌀, the verification command must be the *same* experiment that produced the `likely` reading.
118
+
119
+ ## Fixing is a separate capability
120
+
121
+ Fixing is not a natural continuation of tracing. It is invoked only after Observe, Define, and Prove.
122
+
123
+ ```text
124
+ Understand path: Observe → Define → Prove → Report essence
125
+ Fix path: Observe → Define → Prove → Apply → Verify
126
+ ```
127
+
128
+ A user may ask for understanding only. In that case, stop after Prove and report the proof packet. Do not apply.
@@ -0,0 +1,105 @@
1
+ # Chippy with `playwright-cli`
2
+
3
+ Use this when there is no Chippy browser extension on the page (`playwright-cli` opens a vanilla Chromium).
4
+
5
+ ## What is Chippy on the page
6
+
7
+ Chippy assets are served by the local Chippy helper:
8
+
9
+ - `http://127.0.0.1:7823/__chippy/inject.mjs` — **preferred ESM bootstrap**. Import side-effect installs `window.__CHIPPY`, registers the page with the helper, auto-loads `window.__AVALANCHE__` from the ESM-safe `avalanche.es.js` asset, activates probes immediately, and installs a small in-page control panel. The module default export is `window.__CHIPPY`; named export `ready` resolves to `{ chippy, avalanche, connState, integration, activated, probesActive }` immediately after bootstrap.
10
+ - `http://127.0.0.1:7823/__chippy/inject.js` — **classic-script bootstrap**. Installs `window.__CHIPPY` only.
11
+ - `http://127.0.0.1:7823/__chippy/avalanche.iife.js` — **Chippy runtime for bridge / Avalanche-backed commands**. Installs `window.__AVALANCHE__` when the classic bootstrap is used.
12
+
13
+ Both paths are Chippy. `playwright-cli` is only the transport that loads them into the page.
14
+
15
+ The same ESM bootstrap is also valid for a real user-controlled browser tab when the page allows helper-served module import:
16
+
17
+ ```js
18
+ import('http://127.0.0.1:7823/__chippy/inject.mjs')
19
+ ```
20
+
21
+ In that mode the import is intended to be extension-equivalent for the current page: it activates probes immediately and installs the in-page Chippy controls.
22
+
23
+ The equivalence lasts only for the current document. A full reload or navigation removes the imported runtime because no extension or Storybook host remains to inject it. The in-page import controls display this warning. The user—or Playwright—must run the import command again after every reload/navigation.
24
+
25
+ ## Steps
26
+
27
+ 1. Start the helper:
28
+
29
+ ```bash
30
+ ./scripts/chippy.sh start
31
+ ./scripts/chippy.sh health
32
+ ```
33
+
34
+ 2. Open or reuse one `playwright-cli` Chromium session on the target URL.
35
+
36
+ 3. Prefer the ESM bootstrap when module loading is available:
37
+
38
+ ```bash
39
+ yarn exec playwright-cli -s=<session> run-code "async page => {
40
+ await page.addScriptTag({
41
+ content: `
42
+ const script = document.createElement('script');
43
+ script.type = 'module';
44
+ script.textContent = \"import 'http://127.0.0.1:7823/__chippy/inject.mjs';\";
45
+ document.head.appendChild(script);
46
+ `,
47
+ });
48
+ await page.waitForTimeout(700);
49
+ return await page.evaluate(() => ({
50
+ hasChippy: !!window.__CHIPPY,
51
+ hasAvalanche: !!window.__AVALANCHE__,
52
+ href: location.href,
53
+ }));
54
+ }"
55
+ ```
56
+
57
+ Fallback: classic script injection when ESM import is not available:
58
+
59
+ ```bash
60
+ yarn exec playwright-cli -s=<session> run-code "async page => {
61
+ await page.addScriptTag({ url: 'http://127.0.0.1:7823/__chippy/inject.js' });
62
+ await page.waitForTimeout(500);
63
+ await page.addScriptTag({ url: 'http://127.0.0.1:7823/__chippy/avalanche.iife.js' });
64
+ await page.waitForTimeout(200);
65
+ return await page.evaluate(() => ({
66
+ hasChippy: !!window.__CHIPPY,
67
+ hasAvalanche: !!window.__AVALANCHE__,
68
+ href: location.href,
69
+ }));
70
+ }"
71
+ ```
72
+
73
+ 4. Confirm the page is connected:
74
+
75
+ ```bash
76
+ ./scripts/chippy.sh pages
77
+ ```
78
+
79
+ The connected page is the one whose URL matches the opened tab.
80
+
81
+ 5. Before the first Avalanche capture or analysis command, install the detector explicitly:
82
+
83
+ ```bash
84
+ ./scripts/chippy.sh avalanche-install <clientId>
85
+ ```
86
+
87
+ Both bootstraps load the Avalanche runtime; neither auto-installs its detector in this extension-free mode. Probe, fiber, and describe commands need only the loaded runtime and connection. Avalanche commands additionally need this install step.
88
+
89
+ ## Re-injection after reload
90
+
91
+ A full reload wipes both globals and the `import` integration does not return by itself. Re-run steps 3–5 with the same bootstrap path (`inject.mjs` preferred; `inject.js` + `avalanche.iife.js` fallback). In a user-controlled tab, ask the user to run the console import again, then install Avalanche through Chippy. Verify connection with `chippy.sh pages`, not by checking `window.__chippyPageBridge`.
92
+
93
+ ## Common bridge failure
94
+
95
+ If a bridge / Avalanche command returns:
96
+
97
+ ```text
98
+ bridge module not loaded
99
+ ```
100
+
101
+ The cause is missing `avalanche.iife.js`. Inject it (step 3 second `addScriptTag`) and retry.
102
+
103
+ ## Dispatcher replay ancestry (only when explicitly needed)
104
+
105
+ Dispatcher-based component-structure paths (`explain-component`, `describe-component`, and `inspect-fiber-structure`) need the devtools-hook shim installed **before React evaluates**. With `playwright-cli` that means `addInitScript` before navigation, using the helper-served shim at `http://127.0.0.1:7823/__chippy/devtools-hook-shim.js`. Run the debug replay preflight before those commands. `avalanche-debug-hook` is different: it reads hook events passively captured during real renders and does not execute component bodies. Ordinary bridge work does not need dispatcher replay.
@@ -0,0 +1,205 @@
1
+ # Playwright probes
2
+
3
+ How Chippy operates inside a Playwright-driven browser. Same shared runtime as
4
+ the extension, different transport. No drag UI. AI-driven targets, not pixels.
5
+
6
+ ## What a probe is
7
+
8
+ A probe is **a focus descriptor + a resolved target**. It is not a marker.
9
+
10
+ ```
11
+ Probe {
12
+ id string // "p1", "p2", ...
13
+ intent string|null // optional human note
14
+ descriptor { // portable identity
15
+ dom: { tag, attrs, text, nearestTestId, siblingIndex }
16
+ component: { name, source, ownerNames }
17
+ }
18
+ resolved { // per-session, recomputed
19
+ confidence: "strict"|"high"|"medium"|"low"|"none"
20
+ candidateKind: "fiber"|"dom"
21
+ score: number
22
+ matches: { ...field flags }
23
+ component, dom, alternates[]
24
+ resolvedAt: iso
25
+ } | null
26
+ history[] // confidence/score timeline
27
+ createdAt iso
28
+ }
29
+ ```
30
+
31
+ Identity rules:
32
+
33
+ - Descriptor is portable across windows, runs, browsers.
34
+ - Resolved is per-session and re-derived on demand.
35
+ - **Coordinates are never identity.**
36
+
37
+ ## Lifecycle
38
+
39
+ 1. **Acquire** — derive a descriptor (AI, prior browser, selector hint).
40
+ 2. **Resolve** — fiber-first candidates, DOM fallback, ranked.
41
+ 3. **Inspect** — DOM, fiber props, hooks, owners, styles.
42
+ 4. **Measure** — avalanche around an interaction.
43
+ 5. **Maybe Apply** — when user intent and the P-15/P-16 gate permit, edit source and reload/HMR.
44
+ 6. **Re-resolve** — confirm the probe still lands; compare.
45
+ 7. **Handoff** — extension client → Playwright client via helper.
46
+
47
+ ## Operations
48
+
49
+ All operations live in:
50
+
51
+ ```
52
+ ./browser-scripts/playwright-probes.js
53
+ ```
54
+
55
+ ### Session
56
+ - `launch({ browser, url, headless })`
57
+ - `close(session)`
58
+ - `goto(session, url, options?)`
59
+ - `reload(session, options?)`
60
+
61
+ ### Probes
62
+ - `defineProbe({ id, intent, descriptor })`
63
+ - `registerProbe(session, probe)`
64
+ - `captureFromNode(session, locator)`
65
+ - `captureFromSelector(session, selector)`
66
+ - `resolveProbe(session, probe, options?)`
67
+ - `refreshProbe(session, probeId, options?)`
68
+ - `listProbes(session)`
69
+ - `removeProbe(session, probeId)`
70
+
71
+ ### Inspect
72
+ - `probeDom(session, probe, parentLevel?)`
73
+ - `probeOwners(session, probe)`
74
+ - `probeOwner(session, probe, ownerIndex)`
75
+ - `probeProps(session, probe, ownerIndex?)`
76
+ - `probePropValue(session, probe, propName, ownerIndex?)`
77
+ - `probeHooks(session, probe)`
78
+ - `getComputedStyle(session, probe, parentLevel?)`
79
+
80
+ ### Measure (avalanche)
81
+
82
+ The Playwright session connects to the helper as a normal client. All
83
+ avalanche calls go through the helper HTTP API; the helper drives
84
+ `__AVALANCHE__` on the page over the existing WS bridge. Playwright never
85
+ calls `__AVALANCHE__` directly.
86
+
87
+ Why route through the helper:
88
+ - one transport and explicit detector-install path
89
+ - one result format across extension and Playwright
90
+ - one place to reason about cross-session capture state
91
+ - helper is the context manager for everything Chippy does
92
+
93
+ Read flow (each call):
94
+ ```
95
+ Playwright → helper HTTP /api/pages/:clientId/avalanche
96
+ → WS to client → __CHIPPY.pageBridge.evalAvalanche
97
+ → __AVALANCHE__.<action>
98
+ → result back through WS → helper HTTP body → Playwright
99
+ ```
100
+
101
+ How Playwright reads data:
102
+ - `clientId` is read once via `__CHIPPY.pageBridge.getState().clientId`
103
+ and cached on the session
104
+ - each avalanche call returns `{ ok, status, payload }` from the helper
105
+ - `payload` is the standard helper avalanche response (`action`, `available`,
106
+ `status`, `payload`, etc.)
107
+ - the actual data lives on the page in `__AVALANCHE__`; we only ever read it
108
+ through the helper
109
+
110
+ Operations:
111
+ - `avalanche(session, action, payload?)` — generic dispatcher
112
+ - `avalancheStatus(session)`
113
+ - `avalancheHotSources(session, limit?)`
114
+ - `avalancheExport(session, lastN?)`
115
+ - `reloadWithAvalanche(session, { settleMs?, hotLimit? })`
116
+
117
+ Supported generic actions are `install`, `uninstall`, `reset`/`clear`, `status`, `export`, `export-last`, `debug-hook`, `hot-sources`, `commit-list`, `commit-peek`, and `describe-action`. The module still exports legacy `avalancheStart`, `avalancheStop`, and `avalancheMetrics` wrappers for compatibility; do not use them in new workflows. `avalancheStart` is only an alias for `install`, while `stop` and `metrics` are not actions on the current bridge contract.
118
+
119
+ Helper base URL is `http://127.0.0.1:7823/__chippy` by default and can be
120
+ overridden with `CHIPPY_HELPER_BASE`.
121
+
122
+ ### reloadWithAvalanche
123
+
124
+ The packaged `launchSession(...)` path installs the Chippy bridge and Avalanche runtime via `addInitScript`, so both runtimes exist before page scripts on every reload. The detector still starts uninstalled in each new page realm. `reloadWithAvalanche` therefore reloads, waits for the new client, calls the Avalanche `install` action explicitly, then settles and reads evidence. It does not use helper origin-arming.
125
+
126
+ Commits that occur before that post-reload install are not captured. Use this helper for post-install triggers and settled-state checks, not to claim complete initial-load coverage.
127
+
128
+ Flow:
129
+ 1. `page.reload()` via Playwright
130
+ 2. wait for the reinjected runtime and a fresh `clientId`
131
+ 3. install the detector through the helper
132
+ 4. settle for `settleMs` (default 3000)
133
+ 5. read `status` and `hot-sources` through the helper
134
+
135
+ Returns:
136
+ ```js
137
+ {
138
+ previousClientId,
139
+ clientId, // new clientId after reload
140
+ install, // explicit detector-install response
141
+ status, // helper avalanche-status response
142
+ hot, // helper hot-sources response
143
+ }
144
+ ```
145
+
146
+ Notes:
147
+ - requires the session to have been started with `launch(...)`, which uses
148
+ `installHelpers({ init: true })` under the hood
149
+ - bump `settleMs` to 5000+ for heavy app loads
150
+ - this packaged init-script loader and the ad-hoc `addScriptTag` flow are two Mode A bootstrap variants; both require detector installation and both miss commits before that install
151
+
152
+ ### Compare
153
+ - `snapshotProbe(session, probe)`
154
+ - `diffProbeSnapshots(a, b)`
155
+
156
+ ## Operating rules
157
+
158
+ - **Probes are descriptors first.** Resolution is recomputed, not cached identity.
159
+ - **Fiber beats DOM** when scoring matches.
160
+ - **Strict identity wins** over fuzzy when both available.
161
+ - **No coordinates as identity.** Pixels never cross window boundaries.
162
+ - **Confidence is reported.** Low-confidence ops must be acknowledged.
163
+ - **Re-resolve after** any reload, navigation, code edit, HMR, route change.
164
+ - **Avalanche is per-session.** Probes interpret hot sources, not gate them.
165
+ - **Browser is Chromium or WebKit.** Never user's Chrome.
166
+ - **DRY:** the same shared runtime files power extension and Playwright.
167
+
168
+ ## Handoff from extension to Playwright
169
+
170
+ Helper command:
171
+ ```
172
+ ./scripts/chippy.sh handoff-to-playwright <clientId> [url] [probeIdsCsv] [browserName] [headless]
173
+ ```
174
+
175
+ What it does:
176
+ 1. Captures live probe descriptors from the source extension client.
177
+ 2. Launches Playwright Chromium and navigates to URL.
178
+ 3. Injects shared __CHIPPY runtime via `playwright-session.js`.
179
+ 4. Registers the new page as another helper client.
180
+ 5. Returns descriptors so Playwright probe code can resolve them.
181
+
182
+ The Playwright session is then operated like any other helper client.
183
+
184
+ ## When to use Playwright vs extension
185
+
186
+ Use the **extension**:
187
+ - user is exploring
188
+ - target is unclear
189
+ - live page already has the right state
190
+ - user needs to point at things
191
+
192
+ Use **Playwright**:
193
+ - iteration loop is repetitive (reload + interact + measure)
194
+ - target is already known via descriptor
195
+ - need a clean, controlled environment
196
+ - need reproducibility across runs
197
+ - user is not in front of the page
198
+
199
+ Both share:
200
+ - inspect-react.js
201
+ - layout-lab.js
202
+ - resolve-probes.js
203
+ - probe-descriptor.js
204
+ - avalanche.iife.js
205
+ - chippy-page-bridge.js