@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,183 @@
1
+ # Chippy command surface
2
+
3
+ For typed tools with automatic helper startup, use the [MCP adapter](mcp.md).
4
+ This page owns the CLI contract; MCP keeps that implementation available as an
5
+ alternative transport for the main inspection loop.
6
+
7
+ Map each task to the public shell command that owns it. Run `./scripts/chippy.sh help` from the skill directory for mechanical signatures and [command-output-formats](command-output-formats.md) for exact response shapes.
8
+
9
+ Every command that contacts the helper must run outside the agent sandbox. The agent runs the command; the user only controls visible browser actions when required.
10
+
11
+ ## Recipe lookup
12
+
13
+ | Command | Purpose |
14
+ |---|---|
15
+ | `recipes <query...> [--limit N]` | Search the local grep-friendly task corpus without contacting the helper. It defaults to five results and accepts limits from 1 through 20. Each result includes an answer, completion signal, guardrail, and canonical deeper references. |
16
+
17
+ Use recipe search when the operation or recovery route is not already obvious. It streams `recipes.txt` rather than loading the corpus into memory and ranks exact, prefix, and one-edit typo matches with a small BM25-style scorer. Plain `rg '^id=.*term' references/recipes.txt` or `rg 'term' references/recipes.txt` remains available when deterministic textual matching is preferable.
18
+
19
+ ## Runtime and connection
20
+
21
+ | Command | Purpose |
22
+ |---|---|
23
+ | `start`, `stop`, `health` | Own the local helper lifecycle and readiness check. `start` backgrounds itself and binds `127.0.0.1`; `start --host 0.0.0.0` binds wide only when the user asks for network access. |
24
+ | `inject-url` | Print the classic `inject.js` URL to stdout and the document-scoped reload warning to stderr. Prefer the ESM import recipe for new injection workflows. |
25
+ | `pages [slice]` | List currently connected pages. This is connection truth. |
26
+ | `recent-pages` | List recently disconnected page summaries for reload/navigation diagnosis. |
27
+ | `page <clientId> [slice]` | Read one connected page with `minimal`, `standard`, or `full` detail. |
28
+ | `snapshot <clientId> [slice]` | Read the helper's latest stored snapshot for a page. Probe `intent` and `comment` survive `minimal`, `standard`, and `full` slices. |
29
+ | `request-snapshot <clientId>` | Ask the connected page to emit a fresh snapshot. |
30
+ | `wait <clientId> [timeoutSeconds]` | Consume the oldest queued user-attached probe annotation, or wait for the next one. Default 300 seconds; valid range 1–1800. This is one cancellable long poll and never changes host hooks or configuration. |
31
+ | `activate`, `deactivate` | Change Chippy activation state for one connected page. |
32
+ | `context-ui <clientId> <on\|off>` | Show or hide context-provider enrichment (for example Jira ownership and error-boundary fields) in the active probe UI, including Storybook marker cards. It defaults to `on`; this command changes the current connected page at runtime. |
33
+ | `ensure-probes`, `clear-probes` | Install or remove probe markers. Preserve probes while they remain evidence. |
34
+ | `show-status`, `hide-status` | Control the page-visible Chippy status message. |
35
+ | `command <type> [clientId]` | Generic command escape hatch. Prefer explicit subcommands. |
36
+
37
+ ## Probe inspection
38
+
39
+ | Command | Purpose |
40
+ |---|---|
41
+ | `get-computed-style` | Read computed style for a resolved probe target or bounded parent/selector. |
42
+ | `probe-dom` | Read the exact DOM target, text, attributes, source, styles, and test-id boundary. |
43
+ | `probe-parents` | Read the `fiber.return` parent chain from a probe target. This is the production-safe fiber-walk command. |
44
+ | `probe-boundaries` | Read every Error/Suspense boundary from the probe target to the root, ordered inner → outer. |
45
+ | `probe-owners`, `probe-owner` | Read the React debug-build `_debugOwner` chain or one owner by positional index. This is not a production-build parent-chain route. |
46
+ | `probe-props`, `probe-prop-value` | Read serializable props, reference identities, or one named prop at a chosen owner. |
47
+ | `probe-hooks`, `probe-hooks-summary` | Read the hook tree or its prepared compact summary. |
48
+
49
+ Start value traces with `probe-dom`, then owners, then props. Open the reported source location before searching the repository.
50
+
51
+ ## Fiber inspection and active stimulus
52
+
53
+ | Command | Purpose |
54
+ |---|---|
55
+ | `find-fibers` | Find current fibers by component name, source file, prop, test-id, or text. |
56
+ | `fiber-state-capture`, `fiber-state-list`, `fiber-state-compare` | Retain compact fiber/prop fingerprints for two rendered states—even on different pages—and return only their bounded structural diff. |
57
+ | `page-boundaries` | Read the whole page as a nested Error/Suspense-only forest. Ordinary component fibers are removed while declarative-boundary containment is preserved. |
58
+ | `explain-component` | Return compact semantic text by default; use `--complexity` for the bounded complexity section or `--json` for the full transport payload. May use dispatcher replay, with status and warnings in the result. |
59
+ | `describe-component` | Return the detailed hook tree as plain text by default; use `--json` for the full transport payload. May use dispatcher replay and degrades to fiber-only evidence when replay is unavailable. |
60
+ | `inspect-fiber-hooks`, `inspect-fiber-hooks-summary` | Read detailed or compact hook data for one fiber. |
61
+ | `inspect-fiber-props`, `inspect-fiber-owners`, `inspect-fiber-parents`, `inspect-fiber-boundaries` | Read props, `_debugOwner`, `fiber.return` parent context, or the complete declarative-boundary chain for one remembered fiber after `explain-component` or `find-fibers` yields a `fiberId`. |
62
+ | `inspect-fiber-structure` | Return one hook and its neighboring folder structure; may use dispatcher replay and reports replay warnings. |
63
+ | `page-click` | Click exactly one resolved DOM target. Active stimulus; requires an anchor contract. |
64
+ | `fiber-prop-contract` | Inspect a function prop before invocation. Read-only. |
65
+ | `fiber-invoke` | Invoke one proven function prop, optionally with JSON arguments. Active stimulus. |
66
+ | `fiber-schedule-update` | Schedule one DevTools renderer update on a current composite fiber. Active stimulus; does not mutate a hook or prop. |
67
+
68
+ Run the [debug replay preflight](active-stimulus.md#debug-replay-preflight) before `explain-component`, `describe-component`, or `inspect-fiber-structure`.
69
+
70
+ Load [active-stimulus](active-stimulus.md) before an active command. A `fiber:*` token lives in the current page realm, but React may replace the current fiber after any commit. Re-run `find-fibers` after state changes, interactions, HMR, navigation, or reload instead of assuming a remembered token still points at the current alternate.
71
+
72
+ ## Avalanche capture and analysis
73
+
74
+ | Command | Purpose |
75
+ |---|---|
76
+ | `avalanche-clear` | Clear capture history before a new bounded measurement. |
77
+ | `avalanche-status` | Read installation, capture, and commit-count state. |
78
+ | `avalanche-install`, `avalanche-recapture` | Install with fiber capture or reinstall and clear in one sequence. |
79
+ | `avalanche-arm`, `avalanche-disarm` | Control live interaction capture without reloading the page. |
80
+ | `reload-with-avalanche` | Arm, reload, wait, settle, and print initial-load evidence. |
81
+ | `avalanche-hot-sources` | Rank source families before opening commit detail. |
82
+ | `avalanche-commit-list` | Rank compact commits by a supported signal. |
83
+ | `avalanche-commit-peek` | Join bounded detail for one commit. |
84
+ | `avalanche-describe-action` | Expand one action breadcrumb and its owner/parent context. |
85
+ | `avalanche-debug-hook` | Interrogate one captured `sourceId + hookIndex`. |
86
+ | `avalanche-export` | Return the full export or last N commits. Do not open this first. |
87
+ | `avalanche-save` | Save a full or bounded export for repeated offline analysis. |
88
+ | `avalanche-offline` | Run `summary`, `commit-list`, `commit-peek`, `hot-sources`, `describe-action`, or `source-search --name` over a saved export; shapes match the live commands. |
89
+
90
+ ### Capture modes
91
+
92
+ | Mode | Use it for | Boundary |
93
+ |---|---|---|
94
+ | `sources` | Default source and commit attribution | No per-component `renderedByCommit` evidence |
95
+ | `full` | Per-component render, prop-change, and trasher evidence | Higher collection cost |
96
+ | `stats` | Aggregate capture statistics | No source or rendered detail needed |
97
+ | `amplifiers` | Amplifier-focused capture | Specialized analysis; load Avalanche reference first |
98
+
99
+ `avalanche-arm` and `reload-with-avalanche` also accept `captureFibers=true|false`. Keep it `true` when debug-hook or fiber-backed analysis may follow.
100
+
101
+ ### Commit selectors
102
+
103
+ `avalanche-commit-list` live `by` values are `collateral`, `sources`, `restarts`, `performedWork`, `effects`, `memos`, `callbacks`, `contextUpdates`, `unmountedComponents`, and `unmountedSubtrees`.
104
+
105
+ `avalanche-commit-peek` live `include` values are `stats`, `sources`, `timing`, `metrics`, `unmounts`, `actions`, and `rendered`; `atl` is a deprecated alias of `metrics`. `rendered` requires `detectionMode=full`.
106
+
107
+ Load [avalanche-detector](avalanche-detector.md) for schemas and evidence-reading rules.
108
+
109
+ ## Snippets, navigation, and automation
110
+
111
+ | Command | Purpose |
112
+ |---|---|
113
+ | `eval-snippets` | List packaged snippets. |
114
+ | `eval-page` | Execute one packaged or local snippet in the connected page realm with `--key value` arguments. |
115
+ | `page-reload`, `page-wait-reload` | Request a reload and wait for the helper's reconnect transition. For a Storybook integration, `page-reload` emits `FORCE_REMOUNT`, remounting only the current SUT without navigating the preview iframe. |
116
+ | `handoff-to-playwright` | Transfer a connected page URL and selected probes into a Playwright session configuration. |
117
+ | `proxy-state`, `proxy-start`, `proxy-stop` | Inspect or control the helper's local proxy. |
118
+
119
+ `eval-page` has a fixed five-second page-script timeout through the shell wrapper. The helper HTTP API accepts a timeout field, but `chippy.sh eval-page` does not expose a timeout option.
120
+
121
+ ## Full signatures
122
+
123
+ ```text
124
+ start | stop | health | inject-url
125
+ recipes <query...> [--limit N]
126
+ pages [slice] | recent-pages | page <clientId> [slice]
127
+ snapshot <clientId> [slice] | request-snapshot <clientId>
128
+ wait <clientId> [timeoutSeconds]
129
+ activate <clientId> | deactivate <clientId>
130
+ context-ui <clientId> <on|off>
131
+ ensure-probes <clientId> | clear-probes <clientId>
132
+ show-status <clientId> <text> | hide-status <clientId>
133
+ command <type> [clientId]
134
+ get-computed-style <clientId> <probeId> [parentLevel] [selector]
135
+ probe-dom <clientId> <probeId> [parentLevel]
136
+ probe-parents <clientId> <probeId> [max]
137
+ probe-boundaries <clientId> <probeId> [max]
138
+ probe-owners <clientId> <probeId>
139
+ probe-owner <clientId> <probeId> <ownerIndex>
140
+ probe-props <clientId> <probeId> [ownerIndex]
141
+ probe-prop-value <clientId> <probeId> <propName> [ownerIndex]
142
+ probe-hooks <clientId> <probeId>
143
+ probe-hooks-summary <clientId> <probeId>
144
+ page-click <clientId> <selector|probeId|fiberId>
145
+ fiber-prop-contract <clientId> <fiberId> <propName>
146
+ fiber-invoke <clientId> <fiberId> <propName> [--args JSON]
147
+ fiber-schedule-update <clientId> <fiberId> [--ownerIndex N]
148
+ find-fibers <clientId> [--name regex] [--file regex] [--prop name] [--testid regex] [--text regex] [--max N]
149
+ fiber-state-capture <clientId> [label] [maxFibers]
150
+ fiber-state-list
151
+ fiber-state-compare <beforeCaptureId> <afterCaptureId> [maxChanges]
152
+ page-boundaries <clientId> [max]
153
+ inspect-fiber-hooks <clientId> <fiberId>
154
+ inspect-fiber-hooks-summary <clientId> <fiberId>
155
+ inspect-fiber-props <clientId> <fiberId>
156
+ inspect-fiber-owners <clientId> <fiberId>
157
+ inspect-fiber-parents <clientId> <fiberId> [max]
158
+ inspect-fiber-boundaries <clientId> <fiberId> [max]
159
+ inspect-fiber-structure <clientId> <fiberId> <hookIndex> [windowSize]
160
+ describe-component <clientId> <fiberIdOrName> [--text|--json]
161
+ explain-component <clientId> <probeId|fiberId|name> [--text|--json|--complexity]
162
+ avalanche-clear <clientId>
163
+ avalanche-status <clientId>
164
+ avalanche-export <clientId> [lastN]
165
+ avalanche-hot-sources <clientId> [limit]
166
+ avalanche-commit-list <clientId> [top] [by]
167
+ avalanche-commit-peek <clientId> <commitId> [include] [depth] [maxItems]
168
+ avalanche-describe-action <clientId> <actionId>
169
+ avalanche-install <clientId> [detectionMode]
170
+ avalanche-recapture <clientId> [detectionMode]
171
+ avalanche-debug-hook <clientId> <sourceId> <hookIndex> [window]
172
+ avalanche-save <clientId> <file> [count]
173
+ avalanche-offline <file> <summary|commit-list|commit-peek|source-search> [args...]
174
+ eval-page <clientId> <snippet-file-or-name> [--key value ...]
175
+ eval-snippets
176
+ avalanche-arm <clientId> <origin> [maxCommits] [captureFibers=true|false] [detectionMode=sources|full|stats|amplifiers]
177
+ avalanche-disarm <clientId> <origin>
178
+ page-reload <clientId>
179
+ page-wait-reload <clientId> [timeoutMs]
180
+ reload-with-avalanche <clientId> <origin> [maxCommits] [timeoutMs] [settleMs] [captureFibers=true|false] [detectionMode=sources|full|stats|amplifiers]
181
+ handoff-to-playwright <clientId> [url] [probeIdsCsv] [browserName] [headless]
182
+ proxy-state | proxy-start <targetPort> [originalUrl] | proxy-stop
183
+ ```
@@ -0,0 +1,99 @@
1
+ # Cynefin positioning and OODA iteration for Chippy
2
+
3
+ Cynefin (Snowden) positions a situation by the relationship between cause and effect. OODA drives the evidence iterations after that position is known. Chippy uses them together:
4
+
5
+ > **Position with Cynefin; iterate with OODA; Apply only through the proof gate.**
6
+
7
+ Every task starts unpositioned in ❓ Disorder. Mise en Place may run the read-only orientation needed to obtain the first concrete signal: `health`, `pages`, `request-snapshot`, and reads of existing probe state. Use that signal to name the initial domain before investigative stimuli, diagnosis, or source edits. Position once for the current evidence state; reposition only when evidence changes the cause/effect posture or the runtime becomes unstable.
8
+
9
+ This is not theory. It is a guard against the two recurring Chippy failure modes:
10
+
11
+ 1. Treating a 🌀 Complex situation as ✅ Clear — confidently applying a one-line fix to an emergent cascade.
12
+ 2. Reading data from a 🔥 Chaotic surface — trusting a stale snapshot, a disconnected helper, or a mid-reload page.
13
+
14
+ ## The five domains
15
+
16
+ ### ✅ Clear (Obvious)
17
+
18
+ - **Cause/effect:** known, repeatable, visible to everyone.
19
+ - **Disposition:** sense → categorize → respond. Apply best practice. No deliberation.
20
+ - **Chippy signature:** `probe-dom` resolves to one fiber with `source.fileName` + `lineNumber`. `probe-prop-value` returns a scalar that matches the user's words. The owner chain has one obvious carrier.
21
+ - **Verb:** open file, read line, answer.
22
+ - **Failure mode:** over-deliberating a Clear case — describing the component, arming Avalanche, spinning subagents when the answer is one `probe-dom` away.
23
+
24
+ ### 🔍 Complicated
25
+
26
+ - **Cause/effect:** knowable, but requires expertise and analysis. Multiple defensible answers may exist.
27
+ - **Disposition:** sense → analyze → respond. Apply good practice.
28
+ - **Chippy signature:** prop forwarding crosses several hops. A hook tree has 50+ hooks. A commit list shows a clear hot source but the upstream trigger needs walking. The probe data is real and stable; the question is *which* documented chain to follow.
29
+ - **Verb:** investigate with documented commands — `probe-owners`, `describe-component`, `avalanche-commit-list` + `commit-peek`, `find-fibers`, source open at exact lines.
30
+ - **Failure mode:** treating Complicated as Complex — running speculative experiments when a careful read of existing data would answer the question.
31
+
32
+ ### 🌀 Complex
33
+
34
+ - **Cause/effect:** emergent. No right answer up front. The answer is only visible *after* the system has been perturbed.
35
+ - **Disposition:** probe → sense → respond. Run **safe-to-fail experiments** and watch what emerges.
36
+ - **Chippy signature:** re-render cascades, avalanche storms, store-wave propagation, hook-order surprises, timing-dependent stability, "this only happens after the third click." The system has too many interacting parts to predict from static reading.
37
+ - **Verb:** create the **observable SUT**. Build the smallest tapped white-box test or `eval-page` snippet that exposes the internals. Arm Avalanche, perform the stimulus under an anchor contract, read the emergent signal.
38
+ - **Tap contract, one step at a time.** For no-rush Complex/Complicated work, tap one stable contract seam, observe whether the target signal moves there, then choose the next step. Each step should move, reproduce, or falsify the observed failure before a permanent fix is chosen.
39
+ - **Safe-to-fail criteria:** the experiment is bounded (timeout, commit cap), reversible (no source mutation, or HMR-reverted), and instrumented (you can read the result without re-running). Active-stimulus commands (`page-click`, `fiber-invoke`, `stability-nudge`) declare an anchor contract — what they touch, what becomes opaque, what the caller must guarantee.
40
+ - **Confidence:** emergent systems usually return `likely` or `partial`. If certainty is required, run another bounded experiment and compare the same signal.
41
+
42
+ ### 🔥 Chaotic
43
+
44
+ - **Cause/effect:** none discernible. The surface is moving.
45
+ - **Disposition:** act → sense → respond. Stabilize first, analyze later.
46
+ - **Chippy signature:** helper disconnected, `clientId` stale, page mid-reload, avalanche unbounded and still capturing, snapshot older than the last interaction, HMR in flight.
47
+ - **Verb:** stabilize the runtime — reload, reconnect, `health` → `pages` → `request-snapshot`, get a clean baseline. **Only then** read a signal.
48
+ - **Failure mode:** reading any signal from a chaotic surface. Stale data from chaos is worse than no data — it produces confident-sounding but wrong conclusions.
49
+
50
+ ### ❓ Disorder / Confusion
51
+
52
+ - **Cause/effect:** not yet known. The domain itself is unclassified.
53
+ - **Disposition:** **orient read-only, then classify before investigating or mutating.** Every Chippy task starts here.
54
+ - **Chippy signature:** the user just said a thing. No probe yet. No snapshot. No domain.
55
+ - **Verb:** **Mise en Place** — stage the page, run the runtime ceremony (`health` → `pages` → `request-snapshot`), look at the first concrete signal, then declare which of the four real domains this task lives in.
56
+ - **Failure mode:** diagnosing, stimulating, or editing from Disorder. Read-only orientation is permitted; treating an unpositioned signal as proof is not.
57
+
58
+ ## OODA inside the named domain
59
+
60
+ Cynefin chooses the class of move. OODA chooses and evaluates the next concrete move:
61
+
62
+ | OODA step | Chippy contract |
63
+ |---|---|
64
+ | **Observe** | Read the smallest current runtime, structure, source, or signal fact. |
65
+ | **Orient** | Compare it with the named domain, case invariant, existing evidence, and exact proof gap. |
66
+ | **Decide** | Choose one move allowed by the domain: recognize, analyze with a sensor, run a bounded experiment, or stabilize. |
67
+ | **Act** | Execute exactly that move, record what changed or was falsified, then observe again. |
68
+
69
+ OODA **Act** is not Chippy **Apply**. An OODA action may be a read-only probe, source read, analysis command, bounded active stimulus, or runtime stabilizer. It grants no independent permission to mutate the page or edit source. Active stimuli still require an anchor contract; source edits still require the [operating-model](operating-model.md) Apply gate and user intent.
70
+
71
+ Use one OODA cycle for a Clear answer and as many bounded cycles as the proof gap requires for Complicated or Complex work. In Chaotic work, the domain's act-first stabilizer runs before the normal evidence loop. Reposition when a cycle proves that the current domain no longer fits; do not relabel the task after every command.
72
+
73
+ ## Mapping to Chippy primitives
74
+
75
+ | Chippy concept | Position or iteration role |
76
+ |---|---|
77
+ | Mise en Place | Read-only orientation that exits ❓ Disorder. |
78
+ | OODA | Repeat the next evidence move inside the named domain. |
79
+ | `probe-dom`, `probe-owners`, `probe-props` (read-only) | **Sensors** for ✅/🔍. |
80
+ | `describe-component`, `find-fibers`, `inspect-fiber-structure` | **Analysis tools** for 🔍. |
81
+ | `avalanche-arm`, `avalanche-commit-list`, `eval-page` snippets, tapped white-box tests | **Experiments** for 🌀. |
82
+ | `page-click`, `fiber-invoke`, `stability-nudge` | **Active-stimulus experiments** for 🌀 — require anchor contract. |
83
+ | `reload-with-avalanche`, `health` after disconnect | **Stabilizers** for 🔥. |
84
+ | Proof packet `confidence` field | Confidence reports the domain implicitly: `confirmed` = ✅/🔍, `likely`/`partial` = 🌀, missing = ❓. |
85
+ | Apply gate | Separates source editing from OODA Act. |
86
+
87
+ ## Cross-domain anti-patterns
88
+
89
+ - **Clear-in-Complex:** confident one-line edit against an emergent cascade. Symptom: "this is probably the cause" without an experiment.
90
+ - **Complicated-in-Chaotic:** carefully analyzing a snapshot that is already stale. Symptom: reading a `clientId` from a prior turn instead of re-snapshotting.
91
+ - **Complex-in-Complicated:** spinning up experiments and avalanche captures when a documented `probe-owners` chain would resolve the question. Symptom: token-budget burn with no new signal.
92
+ - **Investigating-from-Disorder:** diagnosing, stimulating, or editing before read-only orientation establishes a domain. Symptom: treating the first unpositioned signal as proof.
93
+
94
+ ## Cross-references
95
+
96
+ - [operating-model](operating-model.md) — phase contracts. Observe exits Disorder, Prove contains the OODA evidence loop, and Apply remains independently gated.
97
+ - [stability-render](stability-render.md) — canonical observable-SUT play for Complex stability questions.
98
+ - [bdd-router](bdd-router.md) — selects the procedure once the domain is named.
99
+ - [active-stimulus](active-stimulus.md) — anchor-contract rules for safe-to-fail experiments.
@@ -0,0 +1,161 @@
1
+ # Debug-hook
2
+
3
+ Fiber-to-source hook locator. Resolves a single hook on a single committed source: not just what primitive hook it is, but **how to find that hook in source** when React only gave you a flat primitive index like `230`.
4
+
5
+ Not a profiler. Not a source finder for the component itself. Not a wave analyzer. A focused **locator/interrogation tool** for a hook you already suspect.
6
+
7
+ Lifecycle stage: **hook localization after triage/experiment**. Enter only when a prior commit analysis or stability-render result already gives a `sourceId` and changed `hookIndex`.
8
+
9
+ Exit when you can walk from the known component source to the target hook using the output: primitive kind, custom-hook parent folders, relative order, and any `useDebugValue` landmarks. Then return to [fixing-performance](fixing-performance.md) for fix-layer choice, or to provider/context analysis if the result is `Context`/`partial`.
10
+
11
+ Purpose: React fibers store only the real primitive hook chain. They do not preserve the nested custom-hook structure developers read in source. `debug-hook` exists to bridge that gap. Given a known source component and a primitive hook index, it should reconstruct enough nested structure — component → custom hooks → primitive hooks, plus relative landmarks such as `useDebugValue` — that Chippy can say *which* `useMemo` / `useState` / `useSyncExternalStore` to inspect in code.
12
+
13
+ Capability boundary: debug-hook does **not** find the component source from scratch. It starts from a component/source location already known from prior Chippy/Avalanche evidence. Its job is to convert a flat fiber hook coordinate into a source-walkable path inside that known component.
14
+
15
+ ## When to use
16
+
17
+ Use after **another tool already pointed at a source and a changed hook index**:
18
+
19
+ - avalanche commit-peek surfaced a hot/source component with a changed hook index
20
+ - stability-render shows leak/cascade isolated to a single source
21
+
22
+ Do not use to:
23
+
24
+ - find sources (`avalanche-hot-sources`, `avalanche-commit-list`)
25
+ - find triggers / waves (`fixing-performance`)
26
+ - grade a subtree (`stability-render`)
27
+ - read all hooks on a fiber (this tool answers about **one** hook + its near neighbors)
28
+
29
+ ## Inputs
30
+
31
+ - `sourceId` — public id from a report (e.g. `StoreReader#1@6`)
32
+ - `hookIndex` — fiber `memoizedState` index of the changed hook
33
+ - `windowSize` — included neighborhood radius around the target index. Default `3`. Operationally: hook is included when `|hook.index - target| <= windowSize`.
34
+
35
+ ## Read order
36
+
37
+ Always read the output in this order. Stop at the first step that gives you the answer.
38
+
39
+ 1. `target.primitive` — chooses the remediation branch entirely. Read first.
40
+ 2. `target.value` — current committed hook value summary. This is now the primary evidence.
41
+ 3. `parents` — custom-hook owner chain if available. Can be empty in the working fiber-chain reconstruction.
42
+ 4. `target.debugValues` — semantic labels if available.
43
+ 5. `neighborhood[*].debugValues` — labels on adjacent hooks when available.
44
+ 6. `flat` — one-liner summary for log-scrolling humans, not for decisions.
45
+
46
+ ## Field semantics
47
+
48
+ - `target.primitive` — primitive React hook kind: `SyncExternalStore`, `State`, `Reducer`, `Memo`, `Callback`, `Effect`, `LayoutEffect`, `Ref`, `Context`, `DebugValue`, `Id`, `ImperativeHandle`, `InsertionEffect`, `DeferredValue`, `Transition`, `CacheRefresh`, `MemoCache`, `Unknown`.
49
+ - `parents` — custom-hook owner chain when available from hook metadata. **Empty parents does not mean failure**: it can mean the target hook is called directly inside the component, or that the current reconstruction only knows the component frame. Empty `parents` + non-empty `target` is still `confirmed`.
50
+ - `neighborhood` — primitive hooks within `windowSize` of the target.
51
+ - `confidence` — tri-state. See below.
52
+ - `reconstruction` — tells you which runtime strategy produced the answer. Current working path is `fiber-hook-chain + _debugHookTypes`.
53
+
54
+ ## Confidence
55
+
56
+ The API field `confidence` is binary: `confirmed | partial`. A third logical state — *unknown* — is not a `confidence` value; it is signaled by `ok: false` or a present `renderError`. Read all three together.
57
+
58
+ | state | how to detect | next |
59
+ |---|---|---|
60
+ | `confirmed` | `ok: true`, `confidence: 'confirmed'`, `target` resolved, no `renderError`. | act on remediation table. |
61
+ | `partial` | `ok: true`, `confidence: 'partial'`, no `target` (index out of range, `Context`, `DebugValue`, or `MemoCache` cell). | re-pick `hookIndex`, or switch to provider/context analysis. |
62
+ | *unknown* (logical) | `ok: false` or `renderError` present. | report `renderError`. Do not infer cause. Re-run once if it looks transient; otherwise raise it as a tool gap. |
63
+
64
+ ## What to do next, by primitive
65
+
66
+ - **SyncExternalStore** — external store fired. See *Root causes / remediations*.
67
+ - **State / Reducer** — in-component update. Trace the `setX` / `dispatch` caller. Two sub-cases:
68
+ - value churn — the new state is genuinely different.
69
+ - identity churn — `dispatch` / `setX` is treated as identity-stable, but the consumer received a new object (e.g. a closed-over reducer rebuilt every render). Check whether the dispatcher itself is recreated.
70
+ - **Memo / Callback** — identity churn. Inspect the deps array; an object/function/array rebuilt each render is the usual cause.
71
+ - **Effect / LayoutEffect / InsertionEffect** — side-effect ran. Inspect deps. Effect *running* is rarely the perf cause; the effect's body is. If body calls `setState`, jump to State cascade.
72
+ - **Ref** — mutation, not a render cause. Mark benign.
73
+ - **Context** — has no fiber `memoizedState` slot you can index. Switch to provider-side analysis (`stability-render` on the provider value).
74
+ - **DebugValue / Id / MemoCache** — diagnostic / structural slots. Not a cause. Re-pick `hookIndex`.
75
+ - **DeferredValue / Transition / CacheRefresh** — concurrent-mode primitives. Treat as advisory; cause is upstream.
76
+ - **ImperativeHandle** — handle re-creation; rare cause.
77
+ - **Unknown** — hook shape did not match any classifier. Report as a debug-hook gap; do not guess.
78
+
79
+ ## Root causes / remediations
80
+
81
+ Mutually exclusive rows. Pick by `target.primitive` and the **detection** column. Detection columns may mention `debugValues` fields such as `selector`; use them only when the source already emits those labels. When labels are absent, join the primitive and value with the known component's hook call order. If that still cannot distinguish the call site, report the localization gap rather than editing source during Prove.
82
+
83
+ | Primitive | Root cause | Detection (from debugHook output) | Remediation |
84
+ |---|---|---|---|
85
+ | SyncExternalStore | **over-broad subscription** | `target.value` differs each commit *and* differs by fields the consumer doesn't read; debugValues `selector` returns a wide slice (object/array of many keys). | Narrow the slice to only fields the consumer reads. Return primitives where possible. |
86
+ | SyncExternalStore | **selector returns wrong identity** | `target.value` deep-equals previous but identity differs each commit (new object/array literal); debugValues `selector` ends in `map`/`filter`/`{...}`/`[...]`. | Stable selector: memoize, return a primitive, or subscribe with shallow-equal. |
87
+ | SyncExternalStore | **store mutation rate too high** | identity *and* value change, debugValues store is shared, multiple unrelated sources hit the same store on the same commit. | Split store, debounce writes, or move the read closer to the consumer. |
88
+ | State / Reducer | **unconditional setState in render or layout effect** | repeated `confirmed` debugHook results on the same source per interaction; State value oscillates / monotonic-grows each commit. | Hoist or guard the update. Remove the avoidable setState. |
89
+ | State / Reducer | **dispatcher identity churn** | State *value* unchanged but consumers below re-render; reducer object recreated per render. | Stabilize reducer/dispatcher identity (module scope or `useRef`). |
90
+ | Memo / Callback | **deps contain a recreated reference** | `target.primitive` is Memo/Callback on a hot source; debugValues / context show a parent re-rendering with new object/function props. | Stabilize deps (lift constants, memoize source object, switch to primitive deps). |
91
+ | Effect / LayoutEffect | **deps churn** | Effect runs every commit; deps array contains a recreated reference. | Stabilize deps. Then verify the effect is needed at all. |
92
+ | Context | **provider value identity churn** | `target.primitive` is Context (or provider rendered directly above the source); value identity differs commit-over-commit. | Memoize provider value or split context. Use `stability-render` on the provider to verify. |
93
+ | Ref | none — benign | `target.primitive` is Ref. | No action. |
94
+ | Unknown | classifier gap | `target.primitive === 'Unknown'`. | Report as debug-hook gap. Do not invent a cause. |
95
+
96
+ ## Read existing `useDebugValue` landmarks
97
+
98
+ Use the existing output. No source edits.
99
+
100
+ **Stop (you have the answer) when all hold:**
101
+
102
+ - `target.primitive` is a single concrete kind (not `Unknown`, not `MemoCache`).
103
+ - `target.value` is a primitive, OR a stable reference already named in `debugValues`.
104
+ - `parents` either names the custom hook you expected, OR is empty *and* the source component itself is the owner you expected.
105
+ - you can name the store / state / memo this hook represents in one sentence using the data shown.
106
+
107
+ **The runtime result is insufficient if any hold:**
108
+
109
+ - `parents` is generic-only (`["useState"]`, `["useReducer"]`) and you cannot tell which logical hook it represents. (Empty `parents` + recognizable source name is *not* this case — that's a stop, see Phase A above.)
110
+ - `target.value` renders as `[object]`, `[function]`, `[array:N]` and the identity matters for the question.
111
+ - multiple sibling hooks in `neighborhood` have the same primitive and you cannot tell them apart.
112
+ - repeated triggers produce identical-looking output and existing labels do not distinguish the call sites.
113
+
114
+ When the runtime result is insufficient, open the already-known component source and align the primitive with hook call order, custom-hook calls, and the returned neighborhood. If more than one call site still fits, return `confidence: partial` with the exact ambiguous calls. Adding diagnostic source labels is a separate, user-authorized change and must pass the normal P-15/P-16 edit gate before it occurs.
115
+
116
+ ## Playwright verification path
117
+
118
+ Use this exact flow when verifying debug-hook under Playwright without the browser extension. Playwright is a contract here, not a specific runner. Runtime globals must match the names defined in the Chippy skill's **Runtime globals contract** — only `window.__CHIPPY` and `window.__AVALANCHE__` (with the trailing `__`) are valid.
119
+
120
+ Prerequisites (do not skip):
121
+
122
+ - Chippy helper is running (`chippy.sh start`, `chippy.sh health` ok).
123
+ - The target page is being served and can be opened by Playwright.
124
+
125
+ Steps:
126
+
127
+ 1. Install the helper-served devtools-hook shim with `addInitScript` before navigation, then open the exact target page in Playwright.
128
+ 2. Inject `inject.mjs` (preferred), or inject `inject.js` followed by `avalanche.iife.js`.
129
+ 3. Verify the connection with `chippy.sh pages` and pick the matching `dev` client for that page URL.
130
+ 4. Run `chippy.sh avalanche-install <clientId>`; loading `window.__AVALANCHE__` does not install the detector in Mode A.
131
+ 5. Run `chippy.sh avalanche-clear <clientId>`, then replay one trigger through Playwright.
132
+ 6. Read runtime source evidence from `avalanche-hot-sources` / `avalanche-commit-peek`.
133
+ 7. Run `chippy.sh avalanche-debug-hook <clientId> <sourceId> <hookIndex> 3`.
134
+
135
+ Do not treat missing top-level `__chippyPageBridge` as an injection failure. In this mode the reliable checks are `window.__CHIPPY` in the page, `window.__AVALANCHE__` after step 4, and the matching client appearing in `chippy.sh pages`. Any other global name (e.g. `window.__avalanche`) is wrong by contract.
136
+
137
+ ## Recovering from `source fiber unavailable`
138
+
139
+ debug-hook needs the detector to retain fibers. If the response is:
140
+
141
+ ```
142
+ { ok: false, error: "source fiber unavailable; install with captureFibers=true" }
143
+ ```
144
+
145
+ the current capture cannot answer debug-hook. No reload is required:
146
+
147
+ 1. Re-install the detector with fiber capture on the live page:
148
+ `chippy.sh avalanche-install <clientId>` (uses `captureFibers=true`, `detectionMode=sources`).
149
+ 2. Clear and reset history if needed: `chippy.sh avalanche-recapture <clientId>` does install + clear + status in one call.
150
+ 3. Reproduce the trigger:
151
+ - Interactive (extension): ask the user to redo the same interaction so the new detector observes it.
152
+ - Playwright: re-run the same Playwright step that produced the symptom.
153
+ 4. Re-run `avalanche-debug-hook` with the same `sourceId` + `hookIndex`.
154
+
155
+ Never preload-only. Fiber capture is a runtime setting and can be activated at any time; only the *next* capture window contains fiber data.
156
+
157
+ ## Limits
158
+
159
+ - Minified production: `parents` degrade — function names collapse to short aliases or empty strings. Primitive classification still works.
160
+ - Current working implementation reconstructs from the fiber hook chain plus `_debugHookTypes`. That makes primitive/value output reliable, but custom-hook ownership can be shallower than the ideal replay-based form.
161
+ - `Context`, `DebugValue`, `MemoCache` do not occupy indexable `memoizedState` slots in the way the other hooks do; expect `partial` confidence if `hookIndex` lands on them.