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

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 (133) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +276 -2
  3. package/bin/chippy.mjs +92 -0
  4. package/bin/pack.mjs +204 -0
  5. package/bin/skill-dir.mjs +15 -0
  6. package/lib/avalanche.js +2601 -0
  7. package/lib/avalanche.js.map +7 -0
  8. package/lib/bootstrap.d.ts +1 -0
  9. package/lib/bootstrap.js +70 -0
  10. package/lib/bootstrap.js.map +7 -0
  11. package/lib/browser.js +15 -0
  12. package/lib/browser.js.map +7 -0
  13. package/lib/extension/avalanche.es.js +5535 -0
  14. package/lib/extension/avalanche.es.js.map +1 -0
  15. package/lib/extension/chippy-page-bridge.js +1953 -0
  16. package/lib/extension/inspect-react.js +216 -0
  17. package/lib/extension/layout-lab.js +1453 -0
  18. package/lib/extension/panel-dom.js +90 -0
  19. package/lib/extension/resolve-probes.js +342 -0
  20. package/lib/mcp-skill/LICENSE +201 -0
  21. package/lib/mcp-skill/README.md +148 -0
  22. package/lib/mcp-skill/SKILL.md +335 -0
  23. package/lib/mcp-skill/browser-scripts/playwright-probes.js +368 -0
  24. package/lib/mcp-skill/browser-scripts/playwright-session.js +114 -0
  25. package/lib/mcp-skill/extension/armed-reload-startup.js +83 -0
  26. package/lib/mcp-skill/extension/avalanche.es.js +5535 -0
  27. package/lib/mcp-skill/extension/avalanche.es.js.map +1 -0
  28. package/lib/mcp-skill/extension/avalanche.iife.js +5536 -0
  29. package/lib/mcp-skill/extension/avalanche.iife.js.map +1 -0
  30. package/lib/mcp-skill/extension/background.js +325 -0
  31. package/lib/mcp-skill/extension/chippy-page-bridge.js +1953 -0
  32. package/lib/mcp-skill/extension/content-script.js +190 -0
  33. package/lib/mcp-skill/extension/devtools-hook-shim.js +85 -0
  34. package/lib/mcp-skill/extension/early-bootstrap.js +49 -0
  35. package/lib/mcp-skill/extension/icon-128.png +0 -0
  36. package/lib/mcp-skill/extension/icon-16.png +0 -0
  37. package/lib/mcp-skill/extension/icon-32.png +0 -0
  38. package/lib/mcp-skill/extension/icon-48.png +0 -0
  39. package/lib/mcp-skill/extension/inspect-react.js +216 -0
  40. package/lib/mcp-skill/extension/layout-lab.js +1453 -0
  41. package/lib/mcp-skill/extension/logo.svg +14 -0
  42. package/lib/mcp-skill/extension/manifest.json +69 -0
  43. package/lib/mcp-skill/extension/panel-dom.js +90 -0
  44. package/lib/mcp-skill/extension/panel-settings.js +173 -0
  45. package/lib/mcp-skill/extension/popup.html +41 -0
  46. package/lib/mcp-skill/extension/popup.js +80 -0
  47. package/lib/mcp-skill/extension/probe-descriptor.js +241 -0
  48. package/lib/mcp-skill/extension/resolve-probes.js +342 -0
  49. package/lib/mcp-skill/extension/startup-handoff.js +30 -0
  50. package/lib/mcp-skill/package.json +1 -0
  51. package/lib/mcp-skill/references/README.md +56 -0
  52. package/lib/mcp-skill/references/active-stimulus.md +85 -0
  53. package/lib/mcp-skill/references/avalanche-detector.md +731 -0
  54. package/lib/mcp-skill/references/bdd-router.md +310 -0
  55. package/lib/mcp-skill/references/browser-runtime-api.md +193 -0
  56. package/lib/mcp-skill/references/command-output-formats.md +1085 -0
  57. package/lib/mcp-skill/references/command-surface.md +183 -0
  58. package/lib/mcp-skill/references/cynefin.md +99 -0
  59. package/lib/mcp-skill/references/debug-hook.md +161 -0
  60. package/lib/mcp-skill/references/fixing-performance.md +490 -0
  61. package/lib/mcp-skill/references/hook-metrics.md +199 -0
  62. package/lib/mcp-skill/references/hooks-inspection.md +61 -0
  63. package/lib/mcp-skill/references/jira-taxonomy.md +81 -0
  64. package/lib/mcp-skill/references/mcp.md +122 -0
  65. package/lib/mcp-skill/references/mode-a-injection.md +102 -0
  66. package/lib/mcp-skill/references/operating-model.md +128 -0
  67. package/lib/mcp-skill/references/playwright-cli-setup.md +105 -0
  68. package/lib/mcp-skill/references/playwright-probes.md +205 -0
  69. package/lib/mcp-skill/references/procedures.md +545 -0
  70. package/lib/mcp-skill/references/recipes.txt +114 -0
  71. package/lib/mcp-skill/references/stability-render.md +428 -0
  72. package/lib/mcp-skill/references/test-mode-playbook.md +194 -0
  73. package/lib/mcp-skill/references/troubleshooting.md +59 -0
  74. package/lib/mcp-skill/scripts/avalanche-analyze.cjs +495 -0
  75. package/lib/mcp-skill/scripts/build-avalanche-command.js +34 -0
  76. package/lib/mcp-skill/scripts/build-fiber-state-command.js +19 -0
  77. package/lib/mcp-skill/scripts/chippy-helper-server.js +1768 -0
  78. package/lib/mcp-skill/scripts/chippy-mcp.cjs +273 -0
  79. package/lib/mcp-skill/scripts/chippy.sh +1252 -0
  80. package/lib/mcp-skill/scripts/format-probe-result.js +34 -0
  81. package/lib/mcp-skill/scripts/helper-access.js +158 -0
  82. package/lib/mcp-skill/scripts/helper-proxy.js +87 -0
  83. package/lib/mcp-skill/scripts/page-socket-trust.js +81 -0
  84. package/lib/mcp-skill/scripts/probe-annotation-channel.js +116 -0
  85. package/lib/mcp-skill/scripts/search-recipes.js +248 -0
  86. package/lib/mcp-skill/snippets/README.md +89 -0
  87. package/lib/mcp-skill/snippets/count-context-consumers.js +40 -0
  88. package/lib/mcp-skill/snippets/find-context-providers.js +38 -0
  89. package/lib/mcp-skill/snippets/find-legacy-context.js +47 -0
  90. package/lib/mcp-skill/snippets/find-prop.js +83 -0
  91. package/lib/mcp-skill/snippets/hook-metrics-sample.js +69 -0
  92. package/lib/mcp-skill/snippets/hook-metrics.js +60 -0
  93. package/lib/mcp-skill/snippets/hook-tracker.js +198 -0
  94. package/lib/mcp-skill/snippets/stability-nudge.js +101 -0
  95. package/lib/package.json +1 -0
  96. package/lib/plugin.js +119 -0
  97. package/lib/plugin.js.map +7 -0
  98. package/lib/storybook/avalanche-panel-model.js +79 -0
  99. package/lib/storybook/brand.jsx +6 -0
  100. package/lib/storybook/connection-fallback.jsx +47 -0
  101. package/lib/storybook/constants.js +15 -0
  102. package/lib/storybook/context-card.jsx +171 -0
  103. package/lib/storybook/manager-owner.js +42 -0
  104. package/lib/storybook/manager.jsx +425 -0
  105. package/lib/storybook/preset.js +7 -0
  106. package/lib/storybook/preview.js +298 -0
  107. package/lib/storybook/probe-annotation-editor.jsx +52 -0
  108. package/lib/storybook/probe-intent.js +23 -0
  109. package/lib/storybook/setup.js +104 -0
  110. package/lib/types/avalanche/commit-metrics-adapter.d.ts +76 -0
  111. package/lib/types/avalanche/commit-stats-indices.d.ts +41 -0
  112. package/lib/types/avalanche/commit-surface-ownership.d.ts +9 -0
  113. package/lib/types/avalanche/detector.d.ts +183 -0
  114. package/lib/types/avalanche/interaction-capture.d.ts +25 -0
  115. package/lib/types/avalanche/internals.d.ts +189 -0
  116. package/lib/types/avalanche/report-serializer.d.ts +283 -0
  117. package/lib/types/avalanche/reporter.d.ts +610 -0
  118. package/lib/types/chippy-bridge/fiber-source.d.ts +48 -0
  119. package/lib/types/chippy-bridge/react-renderer.d.ts +74 -0
  120. package/lib/types/chippy-bridge/recorded-source.d.ts +44 -0
  121. package/lib/types/chippy-bridge/source-map.d.ts +30 -0
  122. package/lib/types/debug-render/core.d.ts +78 -0
  123. package/lib/types/layout-lab/fiber-boundaries.d.ts +51 -0
  124. package/lib/types/layout-lab/fiber-walk.d.ts +131 -0
  125. package/lib/types/layout-lab/marker-context.d.ts +94 -0
  126. package/lib/types/package/avalanche.d.ts +6 -0
  127. package/lib/types/package/browser.d.ts +10 -0
  128. package/lib/types/package/plugin.d.ts +15 -0
  129. package/lib/types/plugins/atl/commit-metrics-adapter.d.ts +65 -0
  130. package/lib/types/plugins/atl/metrics-slot.d.ts +37 -0
  131. package/lib/types/plugins/index.d.ts +49 -0
  132. package/lib/types/plugins/jira/context-provider.d.ts +36 -0
  133. package/package.json +106 -4
@@ -0,0 +1,310 @@
1
+ # Chippy BDD Router — Situation Matrix & Iteration Cycles
2
+
3
+ The router maps an observed Chippy situation to one capability, procedure, command chain, and verification signal.
4
+
5
+ Canonical contracts:
6
+ - Phase model, proof packet, and apply gate: [operating-model](operating-model.md)
7
+ - Domain positioning and OODA evidence iteration: [cynefin](cynefin.md)
8
+ - P-01..P-20 procedure steps: [procedures](procedures.md)
9
+ - Command contract: main [SKILL.md](../SKILL.md#command-surface)
10
+
11
+ ## Domain tags by router section
12
+
13
+ The router picks the procedure once the domain is named. Each section below operates predominantly in one Cynefin domain. Within the selected procedure, use OODA to choose the next bounded evidence move. If evidence no longer fits the section's domain, reposition before routing again.
14
+
15
+ | Section | Predominant domain | Sensor or experiment? |
16
+ |---|---|---|
17
+ | 3.1 Identification & Tracing | 🔍 Complicated | Sensors (probes, find-fibers, source read). Move to 🌀 only when forwarding chain breaks. |
18
+ | 3.2 Performance — Runtime | 🌀 Complex | Safe-to-fail experiments (avalanche-arm, stability-nudge). `confirmed` rare; `likely`/`partial` is normal. |
19
+ | 3.3 Performance — Load | 🌀 Complex | Experiment (reload-with-avalanche). Load capture is a perturbation; cause is read from emergent wave. |
20
+ | 3.4 Context & Store | 🔍 Complicated → 🌀 Complex | Sensors locate provider; stability-render is the experiment when identity is suspected. |
21
+ | 3.5 Automated / Browser Harness | 🔍 Complicated | Sensors over Playwright. Failures here are often 🔥 (injection order, helper down) — stabilize first. |
22
+ | 3.6 Production and Jira Pages | 🔍 Complicated | Sensors against minified source. Owner-chain analysis with taxonomy filter. |
23
+ | 3.7 Tool Boundaries & Gaps | 🔥 Chaotic → ❓ Disorder | Runtime is broken or capability is missing. Stabilize or report; do not analyze. |
24
+
25
+ Read the GIVEN column first. Pick the row that best matches the situation. Follow THEN exactly.
26
+
27
+ ## Table of contents
28
+
29
+ - [Router](#router)
30
+ - [Identification & Tracing](#31-identification--tracing)
31
+ - [Performance — Runtime](#32-performance--runtime)
32
+ - [Performance — Load](#33-performance--load)
33
+ - [Context & Store](#34-context--store)
34
+ - [Automated / Browser Harness](#35-automated--browser-harness)
35
+ - [Production and Jira Pages](#36-production-and-jira-pages)
36
+ - [Tool Boundaries & Gaps](#37-tool-boundaries--gaps)
37
+ - [Iteration Patterns & Cycles](#iteration-patterns--cycles)
38
+
39
+ ## Router
40
+
41
+
42
+ **Format:** `GIVEN <situation> WHEN <intent> THEN <procedure> + <commands> + <verification>`
43
+
44
+ Read the GIVEN column first. Pick the row that best matches the situation. Follow THEN exactly.
45
+
46
+ ---
47
+
48
+ ### 3.1 Identification & Tracing
49
+
50
+ | ID | GIVEN | WHEN | THEN: Procedure | THEN: Key Commands | THEN: Verified By |
51
+ |---|---|---|---|---|---|
52
+ | R-01 | User points at visible text/element | "What is this?" / "Where does X come from?" | P-14 → P-01 → P-02 → P-15 | `probe-dom` → `probe-owners` → `probe-prop-value` → open file | Proof packet: component + file + line + value source |
53
+ | R-02 | Probe resolved, component has `hookCount > 50` | "What is this component doing?" | P-14 → P-01 → P-03 → P-15 | replay preflight → `explain-component` → `describe-component` → `inspect-fiber-structure` | Essence of component stated before cause/fix |
54
+ | R-03 | No probe placed, component name known | "Find X in the live tree" | P-14 → P-10 → P-15 | `find-fibers --name X` → replay preflight → `describe-component` → open file | fiberId resolved, file:line confirmed |
55
+ | R-03A | Same feature exists in Storybook/local fixture and living app | "Where should Chippy investigate first?" | P-14 → P-13/P-20 → P-15 | prefer direct story or local harness before living app | Better-named tree chosen first; same branch signal easier to isolate |
56
+ | R-04 | Probe placed, style mismatch | "Why does this look wrong?" | P-14 → P-02 then `get-computed-style` → P-15 | `probe-dom` → `get-computed-style` → matchedStyles | Style rule source identified; renderer vs data source separated |
57
+ | R-05 | No connected page | Any probe/fiber task | Define runtime gap, then branch on helper health | `health`; unavailable → install Chippy if absent, then agent starts/verifies helper; healthy + `pages` empty → follow the integration's reconnect/reload action | `health` succeeds and page appears in `chippy.sh pages` |
58
+ | R-06 | Production page (minified) | Trace source | P-14 → P-11 → P-15 | `probe-owners`, `nearestTestId`, `componentStack` (plus `jira-taxonomy` on Jira pages) | Owner chain walked; source named with caveat |
59
+ | R-07 | Two pages match target | Any | Ask user which page | `pages` output shown, user picks by URL/title | clientId confirmed by user |
60
+ | R-08 | User asks "why" but target/invariant unclear | Deep grasp first | P-14 only | Ask/derive anchor + invariant; no specialized tool until case defined | Case definition exists |
61
+ | R-09 | Evidence identifies only a forwarding wrapper | Continue proof, do not conclude | P-02 → P-15 | `probe-owners` deeper → `probe-prop-value` at next owner → open caller | Creator named, not just forwarder |
62
+ | R-09A | User asks for fix while trace is partial | Separate Apply from Prove | P-15 → P-16 gate fails → continue proof | Next missing evidence command selected | No edit until proof packet is confirmed |
63
+
64
+ ---
65
+
66
+ ### 3.2 Performance — Runtime
67
+
68
+ | ID | GIVEN | WHEN | THEN: Procedure | THEN: Key Commands | THEN: Verified By |
69
+ |---|---|---|---|---|---|
70
+ | R-10 | Open page, user reports lag on interaction | "Why is clicking X slow?" | P-14 → P-04 → P-15 | `avalanche-arm` → interact → `avalanche-status` → `hot-sources` → `commit-list` → `commit-peek` | Proof packet: trigger + role + file:line |
71
+ | R-11 | Open page, jank during scroll/animation | "Why is scrolling janky?" | P-14 → P-04 → P-15 | Same as R-10 | Hot source identified; blast radius measured; cause not inferred from hotspot alone |
72
+ | R-12 | Capture has >100 commits | Analyse without losing context | P-09 → P-15 | `avalanche-save` → `avalanche-offline` → subagent per wave | Crime scene rebuilt: setup → wave → noise |
73
+ | R-13 | Suspected unstable memo or context | "Does this re-render when it shouldn't?" | P-14 → P-06 → P-15 | `avalanche-recapture full` → schedule one target render → settle → status → commit-list → commit-peek `stats,sources,rendered` → classify | `commitCount`, `collateral`, `trasherCounts`, verdict, render invariant |
74
+ | R-14 | Stability-render shows leak, hook role unclear | "Which hook causes this?" | P-07 → P-15 | `avalanche-recapture` → reproduce trigger → `avalanche-debug-hook` | `target.primitive` confirmed; remediation branch chosen |
75
+ | R-15 | Context updates high in commit list | "Why is context re-rendering everything?" | P-14 → P-08 → P-15 | `commit-list contextUpdates` → `commit-peek` → provider sample → unique `find-fibers` match → direct schedule-update | Provider value identity confirmed stable/unstable |
76
+ | R-15A | Unmounts appear during interaction | "What branch is being torn down?" | P-14 → P-18 → P-15 | `commit-list unmountedSubtrees` → `commit-peek stats,sources,atl` → owner/key/type trace | Branch start named; legitimate teardown vs accidental remount separated; Chippy states where unmount starts |
77
+ | R-15B | Suspense boundary likely entered or left fallback | "Did Suspense cause this wave?" | P-14 → P-04 → P-15 | `commit-peek stats,sources,atl` → read `suspenseByCommit` + source trace below boundary | Boundary transition named as enter/leave; Chippy says whether to look at boundary or below it; placeholder separated from business source |
78
+ | R-15C | One sibling/cousin/descendant branch is noisy enough to hide target signal in the same tree | "Can we isolate this branch in place?" | P-14 → P-15 → P-16 → P-20 → P-12 | prove mixed branches → authorize temporary prune/shallow edit → same capture → revert plan | Same target signal becomes smaller/clearer without unrelated branch work; ancestors untouched; maneuver declared temporary |
79
+ | R-15D | Only available noise is in an ancestor (cannot be pruned in place) | "Can we move the target to a cleaner harness?" | P-14 → R-03A → P-13 → P-12 | move target into Storybook/local fixture; re-measure same signal there | Target rendered without ancestor noise; same measurement repeated in new harness |
80
+ | R-16 | After fix applied | "Did the fix work?" | P-12 | Same capture as before fix; compare `collateral`, `commitCount`, hot-source rank | Same signals reduced; no new signals added |
81
+ | R-17 | User asks "optimize this" but trigger is unknown | Observe before defining optimization target | P-14 → choose P-04/P-05/P-06 | Anchor the target in visible element / interaction / load window first | Measurement route chosen from observed anchor + case definition |
82
+ | R-18 | Avalanche shows hot component but no source proof (not yet known if self-updater) | Avoid hotspot fallacy | P-04 → P-02/P-10 → P-15 | `avalanche-recapture full` → repeat identical interaction → `commit-list` → `commit-peek stats,sources,rendered` → check `isSelfSource` + `propChanges` → owners/source | Hotspot classified as self-source / amplifier-driven / cascade collateral per `renderedByCommit` table |
83
+ | R-18A | Avalanche source has `isSelfSource: true` in `renderedByCommit` (confirmed self-updater) | "Why does this component re-render itself?" | P-04 full-mode branch → P-07 → P-15 | confirm full-mode capture → `commit-peek rendered` → confirm `isSelfSource` → `avalanche-debug-hook <sourceId> <hookIndex>` | Self-source confirmed; trigger hook + primitive named |
84
+ | R-19 | Effect/callback/memo churn appears (suspected, not yet quantified) | Trace dependency chain | P-17 → P-15 | `avalanche-debug-hook` or hook structure → source dep arrays | Semantic dependency named before fix |
85
+ | R-19C | `commit-peek include=rendered` shows non-zero `trasherCounts` on a component | "Which hook is the amplifier?" | P-06 → P-07 → P-15 | `commit-peek include=rendered` → identify `trasherCounts.{effects,callbacks,memos}` → `avalanche-debug-hook` on that hook | Trasher verdict supported by `trasherCounts > 0` across ≥2 commits; offending hook + primitive named |
86
+ | R-19D | `propChanges` shows `ref-changed` callback or object prop on a re-rendered child | "Who passed the unstable identity?" | P-04 full-mode branch → re-resolve child → walk current owners → P-06 on parent | `avalanche-recapture full` → repeat interaction → `commit-peek rendered` → read `ref-changed` prop → re-resolve child → owners → same-anchor parent nudge | Parent identity churn confirmed; amplifier hook in parent named |
87
+ | R-19A | Mount work high during interaction | Prove remount essence | P-18 → P-15 | `commit-peek stats,sources,atl` → owner/key/type trace | Unstable key/type/conditional boundary named or mount declared legitimate |
88
+ | R-19B | User asks to apply perf fix after proof | Fix as separate capability | P-16 → P-12 | Apply gate → edit → same capture | Edit allowed only after proof packet + verification plan |
89
+
90
+ ---
91
+
92
+ ### 3.3 Performance — Load
93
+
94
+ | ID | GIVEN | WHEN | THEN: Procedure | THEN: Key Commands | THEN: Verified By |
95
+ |---|---|---|---|---|---|
96
+ | R-20 | Page is slow to first paint | "Why is initial load slow?" | P-14 → P-05 → P-15 | `reload-with-avalanche` → `avalanche-status` → `hot-sources` → `commit-list` → `commit-peek` | Load invariant + integration mode + top sources ranked |
97
+ | R-21 | Load capture has low commit count | "Did capture miss early commits?" | Prove capture quality before cause | `reload-with-avalanche` with higher `settleMs` (5000+) | commitCount increases or gap is reported as capture limitation |
98
+ | R-22 | After load perf fix | "Did the fix improve load?" | P-05 again + P-12 | Re-run `reload-with-avalanche`, compare hot-sources | Same sources lower rank or absent |
99
+ | R-23 | Load wave looks large | Decide necessary vs avoidable work | P-05 → before/during/after read → P-15 | `commit-peek` on N-2/N-1/N/N+1 | Setup/main/noise roles separated |
100
+ | R-24 | Initial load includes Suspense/lazy boundaries | Avoid blaming transport | P-11 + P-05 → P-15 | `commit-peek` + taxonomy/source trace below placeholder | Business source separated from placeholder/wrapper |
101
+ | R-25 | User asks to fix load before cause known | Apply gate blocks edit | P-15 → P-16 fails | Choose next proof command | No edit until source/boundary role proven |
102
+
103
+ ---
104
+
105
+ ### 3.4 Context & Store
106
+
107
+ | ID | GIVEN | WHEN | THEN: Procedure | THEN: Key Commands | THEN: Verified By |
108
+ |---|---|---|---|---|---|
109
+ | R-30 | Too many re-renders, context suspected | "Find what context is thrashing" | P-14 → P-08 → P-15 | `find-context-providers` → `count-context-consumers` → resolve provider with `find-fibers` → `fiber-schedule-update` | Provider identity and consumer blast radius measured |
110
+ | R-31 | Legacy context suspected | "Are there legacy context users?" | P-14 → eval-page snippet → P-15 | `eval-page find-legacy-context` | Producer/consumer pairs listed |
111
+ | R-32 | `debug-hook` returns `Context` primitive | Investigate provider side | P-08 + stability-render → P-15 | provider sample → unique `find-fibers` match → `fiber-schedule-update` → classify | Provider value stable/unstable confirmed |
112
+ | R-33 | SyncExternalStore hook, over-broad selector | Prove subscription width first | P-19 → P-15 → maybe P-16 | `avalanche-debug-hook` → existing debugValues/source selector read → consumed/subscribed comparison | Consumed fields and subscribed fields both named |
113
+ | R-34 | Selector returns object/array each render | Prove identity churn | P-19 | `debug-hook` value/debugValues + source selector read | Equal-data/new-identity condition proven |
114
+ | R-35 | Store updates frequently but consumer reads one field | Prove broad store mutation | P-19 → P-15 | compare `target.value` changes to rendered fields | Store mutation rate vs consumer need separated |
115
+ | R-36 | Context provider value is inline object/function | Prove value identity, not just source shape | P-08 → P-06 → source read | unique provider fiber → direct schedule-update → open provider file | Runtime wave + source inline value both present |
116
+ | R-37 | User asks to split context/store immediately | Apply gate | P-15 → P-16 | proof packet must name provider/store, consumers, consumed fields | Split/narrow only after blast radius proven |
117
+
118
+ ---
119
+
120
+ ### 3.5 Automated / Browser Harness
121
+
122
+ | ID | GIVEN | WHEN | THEN: Procedure | THEN: Key Commands | THEN: Verified By |
123
+ |---|---|---|---|---|---|
124
+ | R-40 | Running against a page without the extension | Automated Chippy loop | P-13 | shim before navigation → packaged init loader or ad-hoc runtime load → `pages` → `avalanche-install` → `avalanche-clear` → interact → read | Client appears in `pages`; detector reports installed; structured output returned |
125
+ | R-41 | Bridge commands return `bridge module not loaded` | Inject missing bundle | Check injection order | Inject `avalanche.iife.js` AFTER `inject.js` | Bridge commands return real data, not fallback |
126
+ | R-42 | devtools-hook shim not installed before nav | React hook state missing | Fix install order | `addInitScript` BEFORE `page.goto` | `replayComponentHooks` returns hook data, not fiber-only fallback |
127
+ | R-43 | Need repeatable regression check | CI/pre-merge verification | P-06 (stability-render) + P-13 | Same `--testId` + same React tree → same nudge → compare output | commitCount and collateral match expected baseline |
128
+ | R-44 | Automation reads once and fails intermittently | Race condition | Poll instead of single read | Poll at 100–250ms intervals; budget 5–15s per state type | State stable for 2+ consecutive reads before proceeding |
129
+
130
+ ---
131
+
132
+ ### 3.6 Production and Jira Pages
133
+
134
+ | ID | GIVEN | WHEN | THEN: Procedure | THEN: Key Commands | THEN: Verified By |
135
+ |---|---|---|---|---|---|
136
+ | R-50 | Jira page, avalanche source is `Connect(X)` | Classify ownership | Apply jira-taxonomy | Promote `X` or nearest Jira-owned child; filter Connect wrapper | Business component named as source, not wrapper |
137
+ | R-51 | `ComponentWithCondition[]` in source list | Classify | Apply jira-taxonomy | Treat as path metadata; promote nearest self-updater with `whatChanged` | Real source named; gate treated as branch metadata |
138
+ | R-52 | `SuspensePlaceholder` is largest hot source | Classify | Apply jira-taxonomy | Inspect nearest Jira-owned child/self-updater below | Actual update origin named below placeholder |
139
+ | R-53 | `Container(X)` in source list | Classify | Apply jira-taxonomy | Keep as candidate (SweetState boundary); inspect for concrete field changes | Real data boundary confirmed or ruled out |
140
+
141
+ ---
142
+
143
+ ### 3.7 Tool Boundaries & Gaps
144
+
145
+ | ID | GIVEN | WHEN | THEN |
146
+ |---|---|---|---|
147
+ | R-60 | Requested operation not in command surface | Any | Report capability gap. Do not invent. Do not grep Chippy source. |
148
+ | R-61 | Global present (`window.__avalanche`) but not in contract | Validate integration | Read `avalanche-status`; confirm `integrationMode`. Presence ≠ integration. |
149
+ | R-62 | `debug-hook` returns `ok: false`, `source fiber unavailable` | Re-arm with fibers | `avalanche-recapture <clientId>` → reproduce trigger → re-run `debug-hook` |
150
+ | R-63 | `debug-hook` returns `partial` on Context/DebugValue/MemoCache | Re-pick hookIndex | Switch to provider-side analysis; context has no indexable memoizedState slot |
151
+ | R-64 | Capture `commitCount: 0` with detector installed | Verify integration mode | Check `hasMetricsGlobal`, `integrationMode`, `metricsAdapter`; reload page if needed |
152
+ | R-65 | Duplicate `__AVALANCHE__ already defined` | Fix startup order | Injected twice. Fix order before trusting output. |
153
+ | R-66 | Subagent needed for large data | Delegate | State **one concrete pre-stated question**. No raw exports. No "analyze this" prompts. |
154
+
155
+ ---
156
+
157
+ ## Iteration Patterns & Cycles
158
+
159
+ ### Cycle A — Observe/Position → Define → Prove with OODA → Maybe Apply (Core Loop)
160
+
161
+ ```
162
+ [Observe / Position] read-only orientation → anchor first signal → name Cynefin domain
163
+ ↓
164
+ [Define] case + invariant + scope from the first signal
165
+ ↓
166
+ [OODA Observe] read the smallest current signal
167
+ ↓
168
+ [OODA Orient] compare domain + invariant + evidence + next gap
169
+ ↓
170
+ [OODA Decide] choose one permitted sensor / experiment / stabilizer
171
+ ↓
172
+ [OODA Act] execute that evidence move — this is not source Apply
173
+ ↓
174
+ [Evidence] classify source / forwarder / boundary / collateral / provider / store / mount / unknown
175
+ ↓
176
+ [Enough?] no → OODA Observe | domain changed → Position | yes → Proof packet
177
+ ↓
178
+ [Proof packet] confidence + next gap
179
+ ↓
180
+ [Apply gate] user intent + fix layer + verification command
181
+ ↓
182
+ [Maybe edit] source code only if gate passes
183
+ ↓
184
+ [Verify] same measurement, compare signals
185
+ ↓
186
+ [Stable?] yes → done | no → back to [Define or Proof plan]
187
+ ```
188
+
189
+ Fixing is optional and late. The loop can end after **Proof packet** when the user asked for understanding only. OODA Act never bypasses the Apply gate. If evidence changes the apparent case, redefine it; if it changes the cause/effect posture, reposition before proving deeper.
190
+
191
+ ---
192
+
193
+ ### Cycle B — Performance Triage Ladder
194
+
195
+ ```
196
+ 1. User reports slow [interaction | load]
197
+ 2. Capture (arm for runtime, reload-with-avalanche for load)
198
+ 3. hot-sources → quick triage (shape + scale)
199
+ 4. commit-list → pick suspicious commit
200
+ 5. commit-peek → join evidence (stats + sources + atl)
201
+ 6. Probe/fiber → why this component? (owners, props, hooks)
202
+ 7. Code → implementation cause (deps, selector, provider value, keys)
203
+ 8. If user intent permits and P-15/P-16 pass, edit source
204
+ 9. Repeat capture → same window, same signals, compare
205
+ ```
206
+
207
+ Rules:
208
+ - Never jump from step 3 to step 7.
209
+ - Never call a cause "confirmed" without step 6 + 7 evidence.
210
+ - Never mark hotspot as trigger without causal chain.
211
+
212
+ ---
213
+
214
+ ### Cycle C — Stability Verification Loop
215
+
216
+ ```
217
+ 1. Recapture avalanche in full mode
218
+ 2. Schedule one target render (`stability-nudge` or direct fiber command)
219
+ 3. Settle 1s
220
+ 4. Read (status + commit-list + commit-peek `stats,sources,rendered` for every commit + hot-sources)
221
+ 5. Classify (clean / leak / leak+cascade / trasher)
222
+ 6. If dirty: locate offender (commit-list → debug-hook)
223
+ 7. If the user requested a change and the Apply gate passes, fix the proven layer
224
+ 8. Go to 1 — same target and scheduling command, compare
225
+ ```
226
+
227
+ Use this loop as a regression check after any performance edit. Keep the same `--testId` and `--ownerIndex`; compare `commitCount`, `componentRenders`, and `collateral`.
228
+
229
+ ---
230
+
231
+ ### Cycle D — Read Hierarchy (Avalanche Signal Order)
232
+
233
+ ```
234
+ Population metrics → shape and scale
235
+ Commit stats → shape of one commit
236
+ Commit details → sources / providers / restarts
237
+ Fiber / probe → why specific component participated
238
+ Code → implementation cause
239
+ Before/after diff → fix confirmed
240
+ ```
241
+
242
+ Never skip levels. Never claim single-component causality from population metrics alone.
243
+
244
+ ---
245
+
246
+ ### Cycle E — Large Capture Analysis
247
+
248
+ ```
249
+ 1. Save export once
250
+ 2. Build global timeline (summary + commit-list by multiple sort keys)
251
+ 3. Identify waves by question, not by equal commit count
252
+ 4. Reduce each wave to commit-peek slices
253
+ 5. Delegate one concrete question per subagent
254
+ 6. Collect compact findings
255
+ 7. Join: setup → main wave → noise
256
+ 8. Ask: do multiple slices share one upstream root cause?
257
+ 9. If yes: one upstream fix > many local patches
258
+ ```
259
+
260
+ ---
261
+
262
+ ## Part 5 — Verification Checklist
263
+
264
+ Before marking any Chippy task complete:
265
+
266
+ ### Tracing task
267
+ - [ ] Observation anchor recorded (probe/fiber/testId/text/page state)
268
+ - [ ] Case defined from observed anchor
269
+ - [ ] Component named (not "a wrapper")
270
+ - [ ] File named (`source.fileName`)
271
+ - [ ] Line named (`lineNumber`) or render block
272
+ - [ ] Prop forwarding hops named (or "none")
273
+ - [ ] Confidence level stated: `confirmed | likely | partial`
274
+ - [ ] Next gap stated ("none" if done)
275
+
276
+ ### Performance task
277
+ - [ ] First observation recorded (interaction/load/subtree + initial signal)
278
+ - [ ] Case and invariant defined from observation
279
+ - [ ] Trigger identified (interaction or load)
280
+ - [ ] Source classified (source / hotspot / collateral / mount / context / store)
281
+ - [ ] Causal chain stated: source → why → propagation → blast radius
282
+ - [ ] Fix layer decided: above source | boundary | below source
283
+ - [ ] Before/after measurement compared (same signals, same window)
284
+ - [ ] Hot source rank changed (or explained why not)
285
+
286
+ ### Stability-render task
287
+ - [ ] Target observed first (probe/testId/fiber exists in current runtime)
288
+ - [ ] Stability invariant defined from target observation
289
+ - [ ] Nudge target confirmed (testId or probeId)
290
+ - [ ] Verdict stated: clean / leak / leak+cascade / trasher
291
+ - [ ] Render factor stated (`commits / 1`)
292
+ - [ ] Offender named if dirty (component + file + line)
293
+ - [ ] Re-run after fix compared
294
+
295
+ ### Debug-hook task
296
+ - [ ] `target.primitive` read first
297
+ - [ ] Remediation branch chosen from table (not guessed)
298
+ - [ ] `confidence` stated: confirmed | partial
299
+ - [ ] If partial: re-pick hookIndex or switch to provider analysis
300
+
301
+ ### Automated task
302
+ - [ ] Bundle injection order verified (devtools-hook shim before nav)
303
+ - [ ] `avalanche.iife.js` injected if bridge commands used
304
+ - [ ] Connection confirmed via `chippy.sh pages` (not `__chippyPageBridge`)
305
+ - [ ] Polling used (not single read)
306
+ - [ ] Structured output compared (not just screenshot)
307
+
308
+ ---
309
+
310
+ *End of Chippy BDD Router reference.*
@@ -0,0 +1,193 @@
1
+ # Browser runtime API
2
+
3
+ The injected bundle exposes `window.__CHIPPY` in the page. The APIs below are
4
+ nested capabilities on that public root.
5
+
6
+ ## `window.__CHIPPY.inspectReact`
7
+
8
+ Fiber inspection helpers for React pages.
9
+
10
+ - `inspectNode(domNode)`
11
+ - `findByText(text)`
12
+ - `findBySelector(selector)`
13
+ - `inspectAtPoint(x, y)`
14
+ - `getNearestComponent(domNode)`
15
+ - `getOwnerChain(fiber)`
16
+ - `getReturnChain(fiber)`
17
+
18
+ ## `window.__CHIPPY.layoutLab`
19
+
20
+ Probe overlay and state.
21
+
22
+ - `exposeDefaultMarkers()`
23
+ - `getMarkerProbe(id)`
24
+ - `getMarkerState(id)`
25
+ - `getAllMarkerStates()`
26
+ - `setMarkerAnnotation(id, { intent, comment })`
27
+ - `probePoint(x, y)`
28
+ - `clearAll()`
29
+ - `snapToDock(id)`
30
+ - `markerColors`
31
+
32
+ Important behavior:
33
+ - P1 is red, P2 is green
34
+ - extension-owned pages initially render one small bottom-corner Chippy launcher; expanding it reveals compact `P1 — drag to source` / `P2 — drag to source` rows that serve as each probe's dock and detail surface
35
+ - dragging a probe does not collapse the panel; an undocked probe uses document coordinates and stays anchored to its target while the page scrolls
36
+ - the extension toolbar popup contains only Enable and Disable for the current origin; helper and proxy configuration stay in the in-page panel
37
+ - extension-owned panels expose the helper URL and plugin settings behind the gear; the isolated content script mounts the form in a closed shadow root, with no iframe and no page access to extension storage
38
+ - Storybook host-panel mode keeps a standalone dock in the preview frame because probe details live in the manager frame
39
+ - docked probes are inactive
40
+ - while dragging:
41
+ - ← / → walks DOM element levels (up/down the DOM tree)
42
+ - ↑ / ↓ walks fiber parent chain (up/down React component tree)
43
+ - clicking an owner name in the panel jumps the probe to that owner's fiber
44
+ - active P1/P2 cards accept an intent (`explain`, `investigate`, or `change`) and a free-text comment; changing the intent stores both fields immediately, while Enter in the comment stores them and Shift+Enter inserts a newline
45
+ - probe/connection refreshes patch keyed panel nodes in place instead of replacing the panel subtree; existing probe rows, controls, focus, unsubmitted drafts, the settings slot, and its content-script-owned shadow host survive ordinary refreshes
46
+ - Context-provider cards (for example Jira ownership and error-boundary fields) are visible by default when recognized markers exist; `context-ui <clientId> on|off` changes that presentation for the current connected page
47
+ - probe highlights and parent borders are overlay-only, never DOM mutations
48
+
49
+ `getMarkerState(id)` and `getMarkerProbe(id)` always include `intent` (`"explain" | "investigate" | "change" | null`) and `comment` (`string`). `setMarkerAnnotation` patch-merges omitted fields, normalizes unsupported intents to `null`, caps comments at 2,000 characters, and emits `layout-lab:update` with reason `marker-annotation-change`.
50
+
51
+ ## `window.__CHIPPY.pageBridge`
52
+
53
+ Bridge between the page and the helper.
54
+
55
+ The helper must be a real local process reachable by the user's browser. The agent — not the user — owns starting it: invoke `./scripts/chippy.sh start` using outside-sandbox / escalated execution. Do not start the helper inside the sandbox and assume the extension can see it; sandboxed Node servers and ports may be private to the sandbox. Every helper-contacting command must also run outside the sandbox, because they connect to the real `127.0.0.1:7823`. If connectivity is unclear, the agent runs `./scripts/chippy.sh start` (outside-sandbox) and verifies with `./scripts/chippy.sh pages`. Asking the user to open a terminal and run `chippy.sh` is a last-resort fallback only.
56
+
57
+ - `activate()`
58
+ - `deactivate()`
59
+ - `publishSnapshot(reason)`
60
+ - `setProbeAnnotation(probeId, { intent, comment })`
61
+ - `ensureProbes()`
62
+ - `clearProbes()`
63
+ - `showStatus(text)` / `hideStatus()`
64
+ - `getState()` — includes `integration: { kind, who, source, reinjectsOnReload, reloadAction }`
65
+ - `applyConfig({ helperBaseUrl, activated, integration?, contextUiEnabled? })`
66
+
67
+ `contextUiEnabled` defaults to `true`. It controls only context-provider cards in the active probe UI, including Storybook marker cards; generic probe resolution and snapshots continue when it is false.
68
+
69
+ Source reads are cross-version. React <=18 locations come from `_debugSource`; when the module the page loaded for that file carries a source map, its recorded literal is mapped back to correct lines shifted by an earlier transform. React 19 locations start at `_debugStack`, skip dependency frames, and resolve the served module through its inline or external Source Map v3 payload. Snapshot publication is immediate and may be followed by a `<reason>-source-resolved` snapshot when the authored position differs; `find-fibers`, `describe-component`, and `explain-component` await the mapped position.
70
+
71
+ `integration.kind` is `extension`, `import`, or `storybook`. `who` names the host that established Chippy and `source` points to its real setup source file. Import integrations report `reinjectsOnReload: false`; a full reload/navigation requires the user or automation to run the import again.
72
+
73
+ ## Storybook addon panels
74
+
75
+ The Chippy panel presents probe targets rather than transport counters. While a probe is held in the preview, left/right walk DOM targets and up/down walk the React component chain.
76
+
77
+ For an active P1/P2 marker, the panel renders the same intent selector and comment field as the in-page panel. Changing the intent or pressing Enter in the comment sends one `set-probe-annotation` command into the preview; Shift+Enter inserts a newline. The resulting marker snapshot carries both fields through the helper in every slice mode. The helper also queues the resulting `marker-annotation-change` for an explicit `chippy.sh wait`; it does not wake an idle task or modify host lifecycle hooks.
78
+
79
+ When a placed probe resolves context from a registered provider (for example the Jira plugin's ownership and `JSErrorBoundary` fields), its marker card shows the available fields. Markers without such context render no context section and no empty placeholder. The bridge exposes this as `markers[id].context`; the field is `null` when no recognized context exists or `contextUiEnabled` is off.
80
+
81
+ The Avalanche panel installs and refreshes capture state while selected. It groups equivalent commit shapes, shows hot sources first, and keeps individual commits and connection diagnostics behind disclosures.
82
+
83
+ When either panel is `failed` or `reconnecting`, it may offer:
84
+
85
+ ```bash
86
+ npx skills add atlassian-labs/chippy --skill chippy -g
87
+ ```
88
+
89
+ That command installs the Chippy skill with the skills CLI when it is absent. It does not start or verify the helper; the agent still follows [troubleshooting](troubleshooting.md) and runs the helper checks.
90
+
91
+ ## `window.__CHIPPY.resolveProbes` / `window.__CHIPPY.resolveProbesCompact`
92
+
93
+ Resolve one or more probes into DOM + React + source summaries.
94
+
95
+ - `__resolveProbes('1', '2')`
96
+ - `__resolveProbesCompact('1', '2')`
97
+
98
+ Compact results include:
99
+ - `confidence`
100
+ - `dom`
101
+ - `component`
102
+ - `note`
103
+ - `__crossSourceHints`
104
+
105
+ `component` includes:
106
+ - `propNames` — all prop keys (excluding `children`) on the probe component
107
+ - `hookCount` / `hookCountTruncated` / `hookCountMax` — hook-count complexity signal on the probe component
108
+ - `owners[N].propNames` — prop keys on each owner in the chain
109
+ - `owners[N].hookCount` / `hookCountTruncated` / `hookCountMax` — same complexity signal for each owner
110
+
111
+ Always surface `key` when present.
112
+
113
+ ## Page-bridge request examples (sent from helper → page bridge)
114
+
115
+ These common probe, inspection, and stimulus requests run in-page and return results asynchronously via WebSocket. The [command surface](command-surface.md) is the complete public shell-command catalog.
116
+
117
+ ### `eval-probe-dom`
118
+ ```js
119
+ { type: 'eval-probe-dom', requestId, probeId, parentLevel? }
120
+ ```
121
+ Returns the selected DOM target's structure, attributes, text, source, styles, and nearest test-id boundary.
122
+
123
+ ### `eval-probe-props`
124
+ ```js
125
+ { type: 'eval-probe-props', requestId, probeId, ownerIndex? }
126
+ ```
127
+ Returns `{ name, ownerIndex, pod, nonPod, children }`. See `probe-props` in command-output-formats.md.
128
+
129
+ ### `eval-probe-boundaries`
130
+ ```js
131
+ { type: 'eval-probe-boundaries', requestId, probeId, max? }
132
+ ```
133
+ Returns every Error/Suspense boundary on the probe fiber's rendered parent path, ordered inner → outer. This is read-only and does not use debug replay.
134
+
135
+ ### `page-boundaries`
136
+ ```js
137
+ { type: 'page-boundaries', requestId, max? }
138
+ ```
139
+ Returns the current page's React roots pruned to a nested Error/Suspense-only forest. Each surviving node has a reusable `fiberId`, source and DOM summaries, boundary nesting distance, and Suspense status.
140
+
141
+ ### `eval-prop-value`
142
+ ```js
143
+ { type: 'eval-prop-value', requestId, probeId, prop, ownerIndex? }
144
+ ```
145
+ Returns `{ name, ownerIndex, prop, type, value }`.
146
+
147
+ ### `eval-probe-hooks`
148
+ ```js
149
+ { type: 'eval-probe-hooks', requestId, probeId }
150
+ ```
151
+ Returns `{ name, hookCount, truncated, maxHooks, hooks[] }`. See `probe-hooks` in command-output-formats.md.
152
+
153
+ ### `eval-probe-hooks-summary`
154
+ ```js
155
+ { type: 'eval-probe-hooks-summary', requestId, probeId }
156
+ ```
157
+ Returns the prepared compact hook summary documented under `probe-hooks-summary` in command-output-formats.md.
158
+
159
+ ### `page-click`
160
+ ```js
161
+ { type: 'page-click', requestId, target: { selector? , probeId? , fiberId? } }
162
+ ```
163
+ Active stimulus. Resolves exactly one target kind: CSS selector, probe DOM target, or remembered fiber DOM node. Selector clicks require a single match; ambiguous selectors refuse. Returns `{ ok, mode, target, selector, probeId, fiberId }`.
164
+
165
+ ### `fiber-prop-contract`
166
+ ```js
167
+ { type: 'fiber-prop-contract', requestId, fiberId, propName }
168
+ ```
169
+ Read-only inspection. Reads `memoizedProps[propName]` from the remembered fiber and returns callable-shape evidence: `fiberName`, `source`, `propNames`, `propType`, `isFunction`, `fnLength`, `fnName`, and `fnSourcePreview`. This command does not invoke the prop.
170
+
171
+ ### `fiber-invoke`
172
+ ```js
173
+ { type: 'fiber-invoke', requestId, fiberId, propName, args? }
174
+ ```
175
+ Active stimulus. Reads `memoizedProps[propName]` from the remembered fiber and invokes it if it is a function. Use only after `fiber-prop-contract` and source inspection prove the callback argument contract. Returns `{ ok, fiberId, fiberName, propName, propType, fnLength, invoked, args, async, returnValue }` or a refusal/throw/rejection payload.
176
+
177
+ ### `fiber-schedule-update`
178
+
179
+ ```
180
+ { type: 'fiber-schedule-update', requestId, fiberId, ownerIndex? }
181
+ ```
182
+
183
+ Forces one re-render on the resolved fiber via the DevTools renderer's `scheduleUpdate`. Response is an `eval-probe-result` carrying `{ ok, scheduled, fiberName, source, ownerIndex }` or `{ ok:false, reason }`.
184
+
185
+ Each request shown above responds with `{ type: 'eval-probe-result', clientId, requestId, result }` back to the helper.
186
+
187
+ ## Runtime source maps
188
+
189
+ The helper serves `/__chippy/avalanche.iife.js.map` and
190
+ `/__chippy/avalanche.es.js.map` as source-map JSON for the corresponding runtime
191
+ bundles. These include authored sources and source content for browser developer
192
+ tools. They describe Chippy's runtime; they do not supply an inspected app's
193
+ source maps.