@rryando/arcs 4.0.0 → 4.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -20
- package/dist/cli/arcs-flash.d.ts +1 -1
- package/dist/cli/arcs-flash.d.ts.map +1 -1
- package/dist/cli/arcs-flash.js +9 -50
- package/dist/cli/arcs-flash.js.map +1 -1
- package/dist/cli/arcs-orchestrate-caveman.d.ts +2 -2
- package/dist/cli/arcs-orchestrate-caveman.d.ts.map +1 -1
- package/dist/cli/arcs-orchestrate-caveman.js +2 -8
- package/dist/cli/arcs-orchestrate-caveman.js.map +1 -1
- package/dist/cli/arcs-orchestrate.d.ts +1 -1
- package/dist/cli/arcs-orchestrate.d.ts.map +1 -1
- package/dist/cli/arcs-orchestrate.js +4 -54
- package/dist/cli/arcs-orchestrate.js.map +1 -1
- package/dist/cli/orchestrator-shared-blocks.d.ts +10 -30
- package/dist/cli/orchestrator-shared-blocks.d.ts.map +1 -1
- package/dist/cli/orchestrator-shared-blocks.js +46 -128
- package/dist/cli/orchestrator-shared-blocks.js.map +1 -1
- package/dist/utils/claude-code-hook-install.d.ts.map +1 -1
- package/dist/utils/claude-code-hook-install.js +3 -2
- package/dist/utils/claude-code-hook-install.js.map +1 -1
- package/dist/utils/diagram-generator.d.ts.map +1 -1
- package/dist/utils/diagram-generator.js +11 -6
- package/dist/utils/diagram-generator.js.map +1 -1
- package/dist/utils/hook-token-store.d.ts +5 -3
- package/dist/utils/hook-token-store.d.ts.map +1 -1
- package/dist/utils/hook-token-store.js +5 -3
- package/dist/utils/hook-token-store.js.map +1 -1
- package/dist/utils/session-store.d.ts +9 -57
- package/dist/utils/session-store.d.ts.map +1 -1
- package/dist/utils/session-store.js +19 -92
- package/dist/utils/session-store.js.map +1 -1
- package/dist/utils/storage-utils.d.ts +1 -1
- package/dist/utils/storage-utils.d.ts.map +1 -1
- package/dist/utils/storage-utils.js +1 -1
- package/dist/utils/storage-utils.js.map +1 -1
- package/dist/web-client/assets/{GraphCanvas-CTyf_XXQ.js → GraphCanvas-BPDgvsyT.js} +1 -1
- package/dist/web-client/assets/{MarkdownEditor-af2vwQOX.js → MarkdownEditor-D7TLp78z.js} +1 -1
- package/dist/web-client/assets/{abnfDiagram-VRR7QNED-CdxcKX9t.js → abnfDiagram-VRR7QNED-CyuP2N9t.js} +1 -1
- package/dist/web-client/assets/architecture-TIHT7OUA-Bdo2Yvm9.js +1 -0
- package/dist/web-client/assets/{architectureDiagram-ZJ3FMSHR-DOISDv6o.js → architectureDiagram-ZJ3FMSHR-DZ0ul9QX.js} +1 -1
- package/dist/web-client/assets/{blockDiagram-677ZJIJ3-DKwtbttM.js → blockDiagram-677ZJIJ3-LLGzlc9l.js} +1 -1
- package/dist/web-client/assets/{c4Diagram-LMCZKHZV-CilqK-Mm.js → c4Diagram-LMCZKHZV-CViu3CTc.js} +1 -1
- package/dist/web-client/assets/channel-DBNmizpo.js +1 -0
- package/dist/web-client/assets/{chunk-32BRIVSS-C79m1mkG.js → chunk-32BRIVSS-Bw_IuJCM.js} +1 -1
- package/dist/web-client/assets/{chunk-52WLFC77-C6WelGWJ.js → chunk-52WLFC77-C29h440W.js} +1 -1
- package/dist/web-client/assets/{chunk-C7G6YPKG-DLg7ryWI.js → chunk-C7G6YPKG-hhOrvw5w.js} +1 -1
- package/dist/web-client/assets/{chunk-EX3LRPZG-DjWgo4gL.js → chunk-EX3LRPZG-COMzol-M.js} +1 -1
- package/dist/web-client/assets/{chunk-FWX5IMBZ-BgS9p_zy.js → chunk-FWX5IMBZ-6vdX9EUn.js} +2 -2
- package/dist/web-client/assets/{chunk-HOUHSVGY-DuVR7dZO.js → chunk-HOUHSVGY-DWDW6sxp.js} +1 -1
- package/dist/web-client/assets/{chunk-ICXQ74PX-Y8DlnIJM.js → chunk-ICXQ74PX-BdMYglo2.js} +1 -1
- package/dist/web-client/assets/{chunk-MOJQB5TN-BEM3QgeD.js → chunk-MOJQB5TN-C0LAX_dC.js} +1 -1
- package/dist/web-client/assets/{chunk-OGEWGWER-DlM8LxGr.js → chunk-OGEWGWER-CBx8MB7f.js} +1 -1
- package/dist/web-client/assets/{chunk-PUDLZKDR-c6cqNVTx.js → chunk-PUDLZKDR-DKssR1nf.js} +1 -1
- package/dist/web-client/assets/{chunk-Q4XR5HBZ-C5lNmcka.js → chunk-Q4XR5HBZ-B3kcxFE-.js} +1 -1
- package/dist/web-client/assets/{chunk-V7JOEXUC-nSswxvSG.js → chunk-V7JOEXUC-CAlymndy.js} +1 -1
- package/dist/web-client/assets/{chunk-VAUOI2AC-CqJkCkT0.js → chunk-VAUOI2AC-BowfsmTW.js} +1 -1
- package/dist/web-client/assets/{chunk-VR4S4FIN-D3pFchin.js → chunk-VR4S4FIN-BBOydgvt.js} +1 -1
- package/dist/web-client/assets/{chunk-WYO6CB5R-BI9c-NzI.js → chunk-WYO6CB5R-DcymFbES.js} +1 -1
- package/dist/web-client/assets/{chunk-ZGVPDNZ5-CKTF2kLR.js → chunk-ZGVPDNZ5--uKFP-Lr.js} +1 -1
- package/dist/web-client/assets/classDiagram-OUVF2IWQ-CB3HiA1_.js +1 -0
- package/dist/web-client/assets/classDiagram-v2-EOCWNBFH-CB3HiA1_.js +1 -0
- package/dist/web-client/assets/{cynefin-VYW2F7L2-BrJrnfh1.js → cynefin-VYW2F7L2-CjboUOMA.js} +1 -1
- package/dist/web-client/assets/{cynefinDiagram-TSTJHNR4-9jYzPWJZ.js → cynefinDiagram-TSTJHNR4-BcxygBP7.js} +1 -1
- package/dist/web-client/assets/{dagre-VKFMJZFB-B705Djpu.js → dagre-VKFMJZFB-D-tiERQE.js} +1 -1
- package/dist/web-client/assets/{diagram-FQU43EPY-BfQAlUlJ.js → diagram-FQU43EPY-ChPXczaS.js} +1 -1
- package/dist/web-client/assets/{diagram-G47NLZAW-s1YDe06A.js → diagram-G47NLZAW-CVL3Y91h.js} +1 -1
- package/dist/web-client/assets/{diagram-NH7WQ7WH-Dy3z11Hc.js → diagram-NH7WQ7WH-DsaNA9Lh.js} +1 -1
- package/dist/web-client/assets/{diagram-OA4YK3LP-Bius2xUN.js → diagram-OA4YK3LP-CXhrhdhU.js} +1 -1
- package/dist/web-client/assets/{diagram-WEI45ONY-D7x4VcHM.js → diagram-WEI45ONY-BTVPnk4E.js} +1 -1
- package/dist/web-client/assets/{ebnfDiagram-CCIWWBDH-CBg1xrmD.js → ebnfDiagram-CCIWWBDH-BAyrRBtM.js} +1 -1
- package/dist/web-client/assets/{erDiagram-Q63AITRT-CJRvTFvd.js → erDiagram-Q63AITRT-Qm24Wepm.js} +1 -1
- package/dist/web-client/assets/eventmodeling-45OFAUF4-DoTBIvl5.js +1 -0
- package/dist/web-client/assets/flowDiagram-23GEKE2U-BEH23L1A.js +1 -0
- package/dist/web-client/assets/{ganttDiagram-NO4QXBWP-C_LsypZ4.js → ganttDiagram-NO4QXBWP-D8h7l3XJ.js} +1 -1
- package/dist/web-client/assets/{gitGraph-TEB2WS4Q-Dx2XxdGk.js → gitGraph-TEB2WS4Q-DIBml1SB.js} +1 -1
- package/dist/web-client/assets/{gitGraphDiagram-IHSO6WYX-DiKWkGWQ.js → gitGraphDiagram-IHSO6WYX-CtkYoXjn.js} +1 -1
- package/dist/web-client/assets/{index-CYwhkPtc.js → index-DOSH4Q9H.js} +38 -38
- package/dist/web-client/assets/{info-DKCQHKI2-DORwHenK.js → info-DKCQHKI2-DLEUtV5Q.js} +1 -1
- package/dist/web-client/assets/{infoDiagram-FWYZ7A6U-CQecXS1E.js → infoDiagram-FWYZ7A6U-BJQ7aQux.js} +1 -1
- package/dist/web-client/assets/{ishikawaDiagram-FXEZZL3T-CWhj60Zp.js → ishikawaDiagram-FXEZZL3T-BPM11FvG.js} +1 -1
- package/dist/web-client/assets/{journeyDiagram-5HDEW3XC-Cj3z2U8u.js → journeyDiagram-5HDEW3XC-C0aX2z3c.js} +1 -1
- package/dist/web-client/assets/{kanban-definition-HUTT4EX6-DFmBRenP.js → kanban-definition-HUTT4EX6-C56F29Ib.js} +1 -1
- package/dist/web-client/assets/{line-C_Hxz9xb.js → line-BLFHLF2N.js} +1 -1
- package/dist/web-client/assets/{mermaid-parser.core-E3xRdzPn.js → mermaid-parser.core-BLC8FhgU.js} +3 -3
- package/dist/web-client/assets/{mermaid.core-C2_CcotH.js → mermaid.core-BBqkKuXt.js} +3 -3
- package/dist/web-client/assets/{mindmap-definition-LN4V7U3C-Bs7VxPid.js → mindmap-definition-LN4V7U3C-aVZbsoPc.js} +1 -1
- package/dist/web-client/assets/{packet-7NZHBO7P-D2nqso7i.js → packet-7NZHBO7P-D4aqSQfB.js} +1 -1
- package/dist/web-client/assets/{pegDiagram-2B236MQR-Cepo1sIu.js → pegDiagram-2B236MQR-DjfyNI0U.js} +1 -1
- package/dist/web-client/assets/{pie-RZYD4A2V-Sx0IGbXt.js → pie-RZYD4A2V-ChCwYsYj.js} +1 -1
- package/dist/web-client/assets/{pieDiagram-ENE6RG2P-D-PMDNhk.js → pieDiagram-ENE6RG2P-BeHLKkXC.js} +1 -1
- package/dist/web-client/assets/{quadrantDiagram-ABIIQ3AL-BNGC7Fms.js → quadrantDiagram-ABIIQ3AL-stga3gvq.js} +1 -1
- package/dist/web-client/assets/{radar-I7S5WNFK-CFf_-2OC.js → radar-I7S5WNFK-DOGheiwT.js} +1 -1
- package/dist/web-client/assets/{railroad-3IZDKUUU-BvZeVRGh.js → railroad-3IZDKUUU-_JnU7M6L.js} +1 -1
- package/dist/web-client/assets/railroad-abnf-AHOZXSZD-nhNub7LE.js +1 -0
- package/dist/web-client/assets/railroad-ebnf-EBAXGLYW-BlQYe7Yf.js +1 -0
- package/dist/web-client/assets/railroad-peg-LSFZ7HO6-B3E8pRVN.js +1 -0
- package/dist/web-client/assets/{railroadDiagram-RFXS5EU6-D0iK_k84.js → railroadDiagram-RFXS5EU6-C0CkMsOd.js} +1 -1
- package/dist/web-client/assets/{requirementDiagram-TGXJPOKE-BPdsw9tz.js → requirementDiagram-TGXJPOKE-DuImwoRD.js} +1 -1
- package/dist/web-client/assets/{sankeyDiagram-HTMAVEWB-maA6ukOJ.js → sankeyDiagram-HTMAVEWB-kprq0XF9.js} +1 -1
- package/dist/web-client/assets/{sequenceDiagram-DBY2YBRQ-DKmAjmgr.js → sequenceDiagram-DBY2YBRQ-DiXKJMF6.js} +1 -1
- package/dist/web-client/assets/{stateDiagram-2N3HPSRC-esxmzk3w.js → stateDiagram-2N3HPSRC-D5qbVStE.js} +1 -1
- package/dist/web-client/assets/stateDiagram-v2-6OUMAXLB-DWwTAG1r.js +1 -0
- package/dist/web-client/assets/{swimlanes-5IMT3BWC-DFd-wGBv.js → swimlanes-5IMT3BWC-DCbw389c.js} +1 -1
- package/dist/web-client/assets/swimlanesDiagram-G3AALYLV-DabrCsjZ.js +8 -0
- package/dist/web-client/assets/{timeline-definition-FHXFAJF6-C7SG8MQH.js → timeline-definition-FHXFAJF6-CQeaYN_9.js} +1 -1
- package/dist/web-client/assets/{treeView-QDETBFTQ-M0rhxbs2.js → treeView-QDETBFTQ-Cf7Sq3qo.js} +1 -1
- package/dist/web-client/assets/{treemap-6X3UGDF4-BQfkQxSh.js → treemap-6X3UGDF4-BovzvoTU.js} +1 -1
- package/dist/web-client/assets/{vennDiagram-L72KCM5P-CyIlb8ju.js → vennDiagram-L72KCM5P-CZsJy139.js} +1 -1
- package/dist/web-client/assets/{wardley-OPB4EBWU-EE-7q8M1.js → wardley-OPB4EBWU-DJ7MS6XZ.js} +1 -1
- package/dist/web-client/assets/{wardleyDiagram-EHGQE667-bY8XdYYS.js → wardleyDiagram-EHGQE667-rqhcmsbM.js} +1 -1
- package/dist/web-client/assets/{xychartDiagram-FW5EYKEG-AhuXJ3de.js → xychartDiagram-FW5EYKEG-HuK4Seps.js} +1 -1
- package/dist/web-client/index.html +1 -1
- package/dist/web-server/app.d.ts +2 -2
- package/dist/web-server/app.d.ts.map +1 -1
- package/dist/web-server/app.js +0 -3
- package/dist/web-server/app.js.map +1 -1
- package/dist/web-server/routes/hook-events.d.ts +6 -7
- package/dist/web-server/routes/hook-events.d.ts.map +1 -1
- package/dist/web-server/routes/hook-events.js +18 -22
- package/dist/web-server/routes/hook-events.js.map +1 -1
- package/dist/web-server/routes/sessions.d.ts +6 -8
- package/dist/web-server/routes/sessions.d.ts.map +1 -1
- package/dist/web-server/routes/sessions.js +27 -137
- package/dist/web-server/routes/sessions.js.map +1 -1
- package/opencode/arcs/bundle-runtime.json +0 -3
- package/opencode/arcs/manifest.json +8 -25
- package/opencode/arcs/prompts/arcs-docs.txt +19 -157
- package/opencode/arcs/prompts/arcs-flash.txt +49 -152
- package/opencode/arcs/prompts/arcs-orchestrate-caveman.txt +47 -165
- package/opencode/arcs/prompts/arcs-orchestrate.txt +46 -158
- package/opencode/arcs/prompts/code-reviewer.txt +20 -60
- package/opencode/arcs/prompts/graph-explorer.txt +19 -49
- package/opencode/arcs/prompts/software-engineer.txt +21 -67
- package/opencode/arcs/prompts/tech-architect.txt +20 -130
- package/opencode/arcs/skills/brainstorming/SKILL.md +20 -100
- package/opencode/arcs/skills/brainstorming/visual-companion.md +6 -264
- package/opencode/arcs/skills/caveman-commit/SKILL.md +6 -43
- package/opencode/arcs/skills/deep-pr-review/SKILL.md +18 -200
- package/opencode/arcs/skills/deep-pr-review/codegraph-diff.md +7 -93
- package/opencode/arcs/skills/deep-pr-review/review-template.md +13 -60
- package/opencode/arcs/skills/enriching-codegraph-proposals/SKILL.md +16 -156
- package/opencode/arcs/skills/implementation/SKILL.md +20 -46
- package/opencode/arcs/skills/init-project/SKILL.md +12 -150
- package/opencode/arcs/skills/install-claude-code-hook/SKILL.md +13 -133
- package/opencode/arcs/skills/systematic-debugging/SKILL.md +13 -152
- package/opencode/arcs/skills/systematic-debugging/condition-based-waiting.md +7 -110
- package/opencode/arcs/skills/systematic-debugging/defense-in-depth.md +7 -119
- package/opencode/arcs/skills/systematic-debugging/phases-reference.md +9 -166
- package/opencode/arcs/skills/systematic-debugging/root-cause-tracing.md +8 -165
- package/opencode/arcs/skills/test-driven-development/SKILL.md +10 -61
- package/opencode/arcs/skills/test-driven-development/tdd-rationalizations-and-examples.md +7 -154
- package/opencode/arcs/skills/test-driven-development/testing-anti-patterns.md +8 -295
- package/opencode/arcs/skills/to-diagram/SKILL.md +18 -206
- package/opencode/arcs/skills/writing-knowledge/SKILL.md +11 -63
- package/opencode/arcs/skills/writing-plans/SKILL.md +25 -118
- package/opencode/arcs/skills/writing-plans/plan-document-reviewer-prompt.md +10 -61
- package/package.json +1 -1
- package/scripts/claude-code-session-hook.mjs +16 -41
- package/skills/explore-dag.md +9 -52
- package/skills/init-project.md +9 -98
- package/skills/orchestrate.md +15 -109
- package/skills/update-docs.md +9 -60
- package/dist/web-client/assets/architecture-TIHT7OUA-Bt2-DmfV.js +0 -1
- package/dist/web-client/assets/channel-C2mb9np_.js +0 -1
- package/dist/web-client/assets/classDiagram-OUVF2IWQ-CPd_w3Zr.js +0 -1
- package/dist/web-client/assets/classDiagram-v2-EOCWNBFH-CPd_w3Zr.js +0 -1
- package/dist/web-client/assets/eventmodeling-45OFAUF4-CTKRC2Yj.js +0 -1
- package/dist/web-client/assets/flowDiagram-23GEKE2U-CaZjFyU1.js +0 -1
- package/dist/web-client/assets/railroad-abnf-AHOZXSZD-DnGh6x2O.js +0 -1
- package/dist/web-client/assets/railroad-ebnf-EBAXGLYW-CGfgCoaE.js +0 -1
- package/dist/web-client/assets/railroad-peg-LSFZ7HO6-BzQxYdqp.js +0 -1
- package/dist/web-client/assets/stateDiagram-v2-6OUMAXLB-hcBqlOLc.js +0 -1
- package/dist/web-client/assets/swimlanesDiagram-G3AALYLV-DbSrPBYr.js +0 -8
- package/dist/web-server/opencode-client.d.ts +0 -123
- package/dist/web-server/opencode-client.d.ts.map +0 -1
- package/dist/web-server/opencode-client.js +0 -514
- package/dist/web-server/opencode-client.js.map +0 -1
- package/opencode/arcs/prompts/devil-advocate.txt +0 -79
- package/opencode/arcs/skills/executing-plans/SKILL.md +0 -49
|
@@ -1,143 +1,23 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: install-claude-code-hook
|
|
3
|
-
description:
|
|
3
|
+
description: Install the ARCS session-bridge hook into an existing Claude Code workspace
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
#
|
|
6
|
+
# Install Claude Code Hook
|
|
7
7
|
|
|
8
|
-
##
|
|
8
|
+
## Boundary
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
Claude Code only. If the current harness is not Claude Code, stop. The hook changes `.claude/settings.local.json`, so obtain explicit confirmation before using `--write`.
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
## Method
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
1. Run `arcs hooks status <slug> --json`.
|
|
15
|
+
2. If already installed for this slug, report a no-op.
|
|
16
|
+
3. Explain the file written, registered events, local token, and that a new Claude Code session is required.
|
|
17
|
+
4. If the hook points at another slug, warn that installation will repoint it and confirm that effect.
|
|
18
|
+
5. After explicit confirmation, run `arcs hooks install-claude-code <slug> --write --json` once.
|
|
19
|
+
6. Report `settingsPath`, events, and next-session requirement.
|
|
15
20
|
|
|
16
|
-
|
|
21
|
+
Do not hand-edit Claude settings. A malformed settings file is a stop condition: surface the CLI error and do not repair, reformat, or delete it. Do not rerun installation for reassurance because it may rotate the token.
|
|
17
22
|
|
|
18
|
-
|
|
19
|
-
flowchart TD
|
|
20
|
-
classDef decision fill:#f59e0b,color:#fff
|
|
21
|
-
classDef terminal fill:#22c55e,color:#fff
|
|
22
|
-
|
|
23
|
-
A{Running as Claude Code?}:::decision -->|no| Stop[State Claude-Code-only, stop]:::terminal
|
|
24
|
-
A -->|yes| B[arcs hooks status slug --json]
|
|
25
|
-
B --> C{installed?}:::decision
|
|
26
|
-
C -->|false| D[Explain the bridge, ask to install]
|
|
27
|
-
C -->|true| E{matchesCurrentSlug?}:::decision
|
|
28
|
-
E -->|true| F[Report found, no-op]:::terminal
|
|
29
|
-
E -->|false| G[Warn: installing repoints matchedSlugs, re-confirm]
|
|
30
|
-
D -->|declines| H[Print manual fallback, no mutation]:::terminal
|
|
31
|
-
G -->|declines| H
|
|
32
|
-
D -->|explicit yes| I[arcs hooks install-claude-code slug --write]
|
|
33
|
-
G -->|explicit yes| I
|
|
34
|
-
I --> J{ok?}:::decision
|
|
35
|
-
J -->|true| K[Report settingsPath + events + new-session note]:::terminal
|
|
36
|
-
J -->|false| L[Surface the CLI error verbatim, no repair]:::terminal
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
## CLI Primer
|
|
40
|
-
|
|
41
|
-
```bash
|
|
42
|
-
arcs hooks status <slug> --json
|
|
43
|
-
arcs hooks install-claude-code <slug> --write --json
|
|
44
|
-
```
|
|
45
|
-
Discovery: `arcs --commands --json`. Mutating commands run directly — no token.
|
|
46
|
-
|
|
47
|
-
`hooks status` is read-only and rotates nothing, so it is safe to call as many times as you like. Its envelope:
|
|
48
|
-
|
|
49
|
-
| Field | Meaning |
|
|
50
|
-
|---|---|
|
|
51
|
-
| `installed` | `true` only when ALL THREE events (`SessionStart`, `UserPromptSubmit`, `SessionEnd`) are registered. A partial registration is a broken bridge and reports `false`. |
|
|
52
|
-
| `matchesCurrentSlug` | The registered hook carries `ARCS_HOOK_SLUG=<slug>` for the project you asked about. |
|
|
53
|
-
| `matchedSlugs` | Every slug found on a matching hook command — how you see a hook wired to a *different* project. |
|
|
54
|
-
| `hookScriptPath` | Absolute path of the script the hook entry runs; the key both status and install match on. |
|
|
55
|
-
|
|
56
|
-
`hooks install-claude-code <slug> --write` performs the write via the same consent-gated merge `arcs project init` uses, and returns `settingsPath` and `events` alongside the pre-existing `token` / `hookScriptPath` / `serverUrl` / `settingsSnippet` fields. Omitting `--write` keeps the old snippet-only behavior — no file is touched — which is the manual fallback.
|
|
57
|
-
|
|
58
|
-
## Constraints
|
|
59
|
-
|
|
60
|
-
- Step 0 first: not Claude Code → state that this skill is Claude-Code-only and stop. No install, no status call.
|
|
61
|
-
- Never write without EXPLICIT user confirmation. Default posture is do nothing; silence, ambiguity, or "sure, whatever you think" is not consent.
|
|
62
|
-
- `matchesCurrentSlug: false` with a non-empty `matchedSlugs` demands a SECOND, explicit re-confirmation — the merge is keyed on `hookScriptPath`, so one workspace holds one hook and installing silently repoints it away from the other slug.
|
|
63
|
-
- Never edit `.claude/settings.local.json`, `.claude/settings.json`, or `~/.claude/settings.json` yourself. `--write` is the only sanctioned mutation path.
|
|
64
|
-
- Install failure (malformed existing settings file) → surface the CLI's own error message verbatim. Do NOT repair, reformat, or delete the settings file from this skill; the CLI aborted precisely so a hand-edited file is not clobbered.
|
|
65
|
-
- Do not rerun `--write` "to be safe" — every run rotates the token and invalidates the previously installed entry.
|
|
66
|
-
- Pass `--url` only when the user runs `arcs web` on a non-default port; the hook posts to `http://127.0.0.1:4173` otherwise.
|
|
67
|
-
|
|
68
|
-
## Opt-In Copy (what the user must be told before confirming)
|
|
69
|
-
|
|
70
|
-
State all four, plainly, before asking:
|
|
71
|
-
|
|
72
|
-
1. **What it buys them** — the ARCS web UI can see this Claude Code session, and messages queued from the UI are delivered to the next prompt.
|
|
73
|
-
2. **What is written** — `<workspacePath>/.claude/settings.local.json` and nothing else. Never the global config, never a committed file; `settings.local.json` is the git-ignored variant and the token in it is a secret.
|
|
74
|
-
3. **What is registered** — one script under three events: `SessionStart`, `UserPromptSubmit`, `SessionEnd`.
|
|
75
|
-
4. **When it takes effect** — a NEW Claude Code session. The session asking for the install will not pick it up.
|
|
76
|
-
|
|
77
|
-
## Worked Example
|
|
78
|
-
|
|
79
|
-
```bash
|
|
80
|
-
# 0. Self-check: you are Claude Code. If not → "This skill is Claude-Code-only." Stop here.
|
|
81
|
-
|
|
82
|
-
# 1. Read-only detection (rotates nothing; safe to repeat)
|
|
83
|
-
arcs hooks status arcs --json
|
|
84
|
-
# → {"installed":false,"matchesCurrentSlug":false,"matchedSlugs":[],
|
|
85
|
-
# "hookScriptPath":"/…/scripts/claude-code-session-hook.mjs"}
|
|
86
|
-
|
|
87
|
-
# 2. Not installed → present the opt-in copy above, then ask:
|
|
88
|
-
# "Install the Claude Code session-bridge hook for `arcs` now?"
|
|
89
|
-
# Wait for an explicit yes. Anything else → step 4.
|
|
90
|
-
|
|
91
|
-
# 3. Explicit yes → install and report
|
|
92
|
-
arcs hooks install-claude-code arcs --write --json
|
|
93
|
-
# → {"settingsPath":"/home/u/Work/arcs/.claude/settings.local.json",
|
|
94
|
-
# "events":["SessionStart","UserPromptSubmit","SessionEnd"], …}
|
|
95
|
-
# Report: settingsPath, the three events, and "start a NEW Claude Code session to pick it up".
|
|
96
|
-
|
|
97
|
-
# 4. Declined → no mutation. Print the manual fallback (snippet only, writes nothing):
|
|
98
|
-
arcs hooks install-claude-code arcs --json
|
|
99
|
-
# Paste `settingsSnippet` into .claude/settings.local.json by hand.
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
Already-installed branch:
|
|
103
|
-
|
|
104
|
-
```bash
|
|
105
|
-
arcs hooks status arcs --json
|
|
106
|
-
# → {"installed":true,"matchesCurrentSlug":true,"matchedSlugs":["arcs"], …}
|
|
107
|
-
# Report "session-bridge hook already installed for `arcs`". No-op. Done.
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
Different-slug branch:
|
|
111
|
-
|
|
112
|
-
```bash
|
|
113
|
-
arcs hooks status arcs --json
|
|
114
|
-
# → {"installed":true,"matchesCurrentSlug":false,"matchedSlugs":["legacy-app"], …}
|
|
115
|
-
# Warn: "This workspace's hook is registered for `legacy-app`. One workspace holds
|
|
116
|
-
# one hook by design — installing for `arcs` will silently repoint it and
|
|
117
|
-
# `legacy-app` will stop reporting sessions."
|
|
118
|
-
# Require a SECOND explicit confirmation, then:
|
|
119
|
-
arcs hooks install-claude-code arcs --write --json
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
Failure branch:
|
|
123
|
-
|
|
124
|
-
```bash
|
|
125
|
-
arcs hooks install-claude-code arcs --write --json
|
|
126
|
-
# → {"ok":false,"code":"hook_install_error","message":"/…/.claude/settings.local.json exists
|
|
127
|
-
# but is not valid JSON — fix it manually or delete it, then re-run
|
|
128
|
-
# `arcs hooks install-claude-code arcs`. Nothing was written."}
|
|
129
|
-
# Relay that message verbatim. Do not touch the file.
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
## Exit Conditions
|
|
133
|
-
|
|
134
|
-
| Condition | Action |
|
|
135
|
-
|-----------|--------|
|
|
136
|
-
| Not running as Claude Code | Stop. State the skill is Claude-Code-only; run nothing |
|
|
137
|
-
| `installed: true` and `matchesCurrentSlug: true` | Stop. Report already installed; no-op |
|
|
138
|
-
| `installed: true` and `matchesCurrentSlug: false` | Warn that installing repoints the hook away from `matchedSlugs`; require a second explicit confirmation before `--write` |
|
|
139
|
-
| `installed: false` | Present the opt-in copy; install only on explicit confirmation |
|
|
140
|
-
| User declines at any confirmation | Stop. No mutation. Print the manual fallback: `arcs hooks install-claude-code <slug> --json` (snippet only, no `--write`) |
|
|
141
|
-
| `--write` succeeds | Report `settingsPath` and `events`; tell the user a NEW Claude Code session is required |
|
|
142
|
-
| `--write` fails (e.g. malformed settings file) | Surface the CLI's error message verbatim. Attempt no repair; nothing was written |
|
|
143
|
-
| Project has no workspace path (`no_workspace_paths`) | Stop. Relay the error and offer the snippet-only fallback |
|
|
23
|
+
Without confirmation, offer the snippet-only command without `--write`.
|
|
@@ -1,162 +1,23 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: systematic-debugging
|
|
3
|
-
description:
|
|
3
|
+
description: Diagnose bugs and failing tests from evidence before changing code
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
#
|
|
6
|
+
# Systematic Debugging
|
|
7
7
|
|
|
8
|
-
##
|
|
8
|
+
## Method
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
Observe → reproduce → isolate → regression test → fix → verify.
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
1. **Observe:** read the full error, logs, inputs, and recent relevant changes.
|
|
13
|
+
2. **Reproduce:** find the smallest reliable reproduction. Add instrumentation when needed.
|
|
14
|
+
3. **Isolate:** trace backward, compare a working path, and test one hypothesis at a time.
|
|
15
|
+
4. **Regression test:** encode the failure when practical.
|
|
16
|
+
5. **Fix:** change the root cause with the smallest targeted patch.
|
|
17
|
+
6. **Verify:** show the reproduction and relevant checks pass.
|
|
13
18
|
|
|
14
|
-
|
|
19
|
+
If three failed fixes do not improve the evidence, stop and question the architecture or assumptions instead of stacking another guess.
|
|
15
20
|
|
|
16
|
-
|
|
17
|
-
flowchart TD
|
|
18
|
-
classDef decision fill:#f59e0b,color:#fff
|
|
19
|
-
classDef stop fill:#ef4444,color:#fff
|
|
21
|
+
Use ARCS knowledge only when a prior gotcha may save time. Capturing a durable discovery is optional, not part of the success condition.
|
|
20
22
|
|
|
21
|
-
|
|
22
|
-
ARCS --> Found{Match found?}
|
|
23
|
-
Found -->|Yes| Verify[Verify it applies]
|
|
24
|
-
Found -->|No| Observe
|
|
25
|
-
|
|
26
|
-
Verify -->|Applies| Isolate
|
|
27
|
-
Verify -->|Doesn't apply| Observe
|
|
28
|
-
|
|
29
|
-
Observe[Phase 1: Observe] --> Repro{Reproducible?}
|
|
30
|
-
Repro -->|No| Instrument[Add logging/tracing]
|
|
31
|
-
Instrument --> Observe
|
|
32
|
-
Repro -->|Yes| Hypothesize[Phase 2: Hypothesize]
|
|
33
|
-
|
|
34
|
-
Hypothesize --> Compare[Find working example, list differences]
|
|
35
|
-
Compare --> Theory[Form single specific hypothesis]
|
|
36
|
-
|
|
37
|
-
Theory --> Isolate[Phase 3: Isolate]
|
|
38
|
-
Isolate --> Test{Root cause isolated?}
|
|
39
|
-
Test -->|Yes| WriteFail[Write failing regression test]
|
|
40
|
-
Test -->|No| FailCount{3+ failures?}
|
|
41
|
-
FailCount -->|No| Theory
|
|
42
|
-
FailCount -->|Yes| Arch[Question architecture]
|
|
43
|
-
|
|
44
|
-
WriteFail --> Implement[Single targeted fix]
|
|
45
|
-
Implement --> Green{Scoped verification passes?}
|
|
46
|
-
Green -->|Yes| Capture[Propose resolution as ARCS knowledge]
|
|
47
|
-
Green -->|No| FailCount
|
|
48
|
-
|
|
49
|
-
class Found,Repro,Test,FailCount,Green decision
|
|
50
|
-
class Arch stop
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
## Phase 1: Observe (Root Cause Investigation)
|
|
54
|
-
|
|
55
|
-
- Read the actual error message completely
|
|
56
|
-
- Reproduce consistently before proceeding
|
|
57
|
-
- Check recent changes (`git log`, `git diff`)
|
|
58
|
-
- Trace data flow backward from failure point
|
|
59
|
-
- Instrument component boundaries if cause unclear
|
|
60
|
-
- **Pre-step:** `arcs knowledge search <slug> "<error>" --json` for gotcha/lesson/pattern entries
|
|
61
|
-
|
|
62
|
-
## Phase 2: Hypothesize (Pattern Analysis)
|
|
63
|
-
|
|
64
|
-
- Find a working example in the same codebase
|
|
65
|
-
- Compare working vs broken — list every difference
|
|
66
|
-
- Understand the dependency chain
|
|
67
|
-
- Form ONE specific hypothesis (not multiple)
|
|
68
|
-
|
|
69
|
-
## Phase 3: Root Cause Isolation
|
|
70
|
-
|
|
71
|
-
- Test the hypothesis with the smallest possible diagnostic change
|
|
72
|
-
- One variable at a time — never stack fixes
|
|
73
|
-
- If hypothesis fails, form a new one from evidence
|
|
74
|
-
- Do not proceed until the evidence isolates the root cause
|
|
75
|
-
- **Escalation:** 3+ failed fixes → question the architecture, not the symptom
|
|
76
|
-
|
|
77
|
-
## Phase 4: Fix
|
|
78
|
-
|
|
79
|
-
- Write a failing regression test FIRST (proves the bug exists and prevents a fix-before-test path)
|
|
80
|
-
- Implement a single targeted fix
|
|
81
|
-
- Run scoped verification for the files you changed (your dispatch VERIFY command — never the full suite; the devil-advocate completion gate owns that)
|
|
82
|
-
- Prepare the resolution as an ARCS knowledge proposal after verification passes; do not execute `arcs knowledge upsert`
|
|
83
|
-
- If your fix introduces new failures in YOUR scoped tests, revert and return to Phase 2. Failures in files outside your scope are report-only (BLOCKED_BY) — likely a sibling agent's in-flight work; never fix or revert it
|
|
84
|
-
|
|
85
|
-
## Log Triage Protocol
|
|
86
|
-
|
|
87
|
-
**Scan order:** failure point → errors → warnings → timing anomalies
|
|
88
|
-
|
|
89
|
-
```bash
|
|
90
|
-
rg -n "ERROR|FATAL|panic|exception" <logfile> # Error grep
|
|
91
|
-
jq 'select(.level == "error")' <json-log> # Structured logs
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
**Output:** Timeline of events leading to failure (T-5m, T-3m, T-0).
|
|
95
|
-
|
|
96
|
-
## Git Bisect (Regressions)
|
|
97
|
-
|
|
98
|
-
```bash
|
|
99
|
-
git bisect start
|
|
100
|
-
git bisect bad HEAD
|
|
101
|
-
git bisect good <last-known-good>
|
|
102
|
-
git bisect run <test-command>
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
After finding the commit: read the diff, isolate specific lines, feed into Phase 2.
|
|
106
|
-
|
|
107
|
-
## Dependency Conflict Diagnosis
|
|
108
|
-
|
|
109
|
-
| Symptom | Likely Cause |
|
|
110
|
-
|---------|-------------|
|
|
111
|
-
| `instanceof` fails across modules | Duplicate package copies |
|
|
112
|
-
| Type mismatch on same interface | Different versions loaded |
|
|
113
|
-
| "Cannot find module" intermittent | Hoisting conflict |
|
|
114
|
-
| Works with `--legacy-peer-deps` | Peer dep unsatisfied |
|
|
115
|
-
|
|
116
|
-
Diagnose: `npm ls <pkg>`, `npm explain <pkg>`, check for multiple copies.
|
|
117
|
-
|
|
118
|
-
## ARCS Knowledge Capture
|
|
119
|
-
|
|
120
|
-
After root cause identification, propose durable knowledge for orchestrator fan-in persistence:
|
|
121
|
-
- **gotcha** — environmental/config traps
|
|
122
|
-
- **lesson** — architectural insights from this session
|
|
123
|
-
- **pattern** — reusable solution to recurring problem
|
|
124
|
-
|
|
125
|
-
Include: root cause summary, evidence, affected files, fix approach.
|
|
126
|
-
|
|
127
|
-
### Propose Resolution as Knowledge
|
|
128
|
-
|
|
129
|
-
After resolving the issue, choose the kind and obtain its required anatomy before authoring a complete entry:
|
|
130
|
-
|
|
131
|
-
```bash
|
|
132
|
-
arcs knowledge template --kind=gotcha --json
|
|
133
|
-
# Fill every returned section with observed evidence, affected files, and the fix approach.
|
|
134
|
-
arcs knowledge upsert <slug> "<specific debugging discovery>" \
|
|
135
|
-
--kind=gotcha --summary="<durable takeaway>" --body-file=<complete-body.md> \
|
|
136
|
-
--keywords="<error,component,root-cause>" --source-files=<affected-paths> --json
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
Return that command as a ready-to-run proposal. Do not execute `arcs knowledge upsert`; the orchestrator owns fan-in persistence. Use the same template-first flow for `lesson` and `pattern`; do not copy a body-shaped example that omits the selected kind's required sections.
|
|
140
|
-
|
|
141
|
-
**Kind selection guide:**
|
|
142
|
-
- `gotcha` — surprising behavior, trap, or non-obvious failure mode
|
|
143
|
-
- `lesson` — learned technique, debugging approach, resolution method
|
|
144
|
-
- `pattern` — reusable solution that should be applied going forward
|
|
145
|
-
|
|
146
|
-
## Constraints
|
|
147
|
-
|
|
148
|
-
- **NO FIXES WITHOUT ROOT CAUSE INVESTIGATION.** If Phase 1 incomplete, you cannot propose fixes.
|
|
149
|
-
- **One variable at a time.** Never apply multiple changes simultaneously.
|
|
150
|
-
- **3+ failures = architectural problem.** Stop fixing symptoms, question the pattern.
|
|
151
|
-
- **Test before fix.** Failing test proves the bug; green test proves the fix.
|
|
152
|
-
- **Defense in depth:** After fixing root cause, add validation at multiple layers to prevent recurrence.
|
|
153
|
-
- **Systematic is faster than thrashing.** 15-30min systematic vs 2-3h random fixes.
|
|
154
|
-
|
|
155
|
-
## Red Flags (Return to Phase 1)
|
|
156
|
-
|
|
157
|
-
- "Quick fix for now, investigate later"
|
|
158
|
-
- "Just try changing X and see"
|
|
159
|
-
- Proposing solutions before tracing data flow
|
|
160
|
-
- Each fix reveals a new problem in a different place
|
|
161
|
-
- "I don't fully understand but this might work"
|
|
162
|
-
- Human says "stop guessing" or "is that not happening?"
|
|
23
|
+
Optional references provide concise techniques for tracing, waiting, and defense in depth. Do not run destructive Git operations unless the user requests them.
|
|
@@ -1,115 +1,12 @@
|
|
|
1
1
|
# Condition-Based Waiting
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Wait for an observable condition, not an arbitrary duration.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Use a bounded poll or event with:
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
- a clear success condition;
|
|
8
|
+
- a timeout;
|
|
9
|
+
- useful timeout evidence;
|
|
10
|
+
- cleanup for listeners or timers.
|
|
8
11
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
```dot
|
|
12
|
-
digraph when_to_use {
|
|
13
|
-
"Test uses setTimeout/sleep?" [shape=diamond];
|
|
14
|
-
"Testing timing behavior?" [shape=diamond];
|
|
15
|
-
"Document WHY timeout needed" [shape=box];
|
|
16
|
-
"Use condition-based waiting" [shape=box];
|
|
17
|
-
|
|
18
|
-
"Test uses setTimeout/sleep?" -> "Testing timing behavior?" [label="yes"];
|
|
19
|
-
"Testing timing behavior?" -> "Document WHY timeout needed" [label="yes"];
|
|
20
|
-
"Testing timing behavior?" -> "Use condition-based waiting" [label="no"];
|
|
21
|
-
}
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
**Use when:**
|
|
25
|
-
- Tests have arbitrary delays (`setTimeout`, `sleep`, `time.sleep()`)
|
|
26
|
-
- Tests are flaky (pass sometimes, fail under load)
|
|
27
|
-
- Tests timeout when run in parallel
|
|
28
|
-
- Waiting for async operations to complete
|
|
29
|
-
|
|
30
|
-
**Don't use when:**
|
|
31
|
-
- Testing actual timing behavior (debounce, throttle intervals)
|
|
32
|
-
- Always document WHY if using arbitrary timeout
|
|
33
|
-
|
|
34
|
-
## Core Pattern
|
|
35
|
-
|
|
36
|
-
```typescript
|
|
37
|
-
// ❌ BEFORE: Guessing at timing
|
|
38
|
-
await new Promise(r => setTimeout(r, 50));
|
|
39
|
-
const result = getResult();
|
|
40
|
-
expect(result).toBeDefined();
|
|
41
|
-
|
|
42
|
-
// ✅ AFTER: Waiting for condition
|
|
43
|
-
await waitFor(() => getResult() !== undefined);
|
|
44
|
-
const result = getResult();
|
|
45
|
-
expect(result).toBeDefined();
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
## Quick Patterns
|
|
49
|
-
|
|
50
|
-
| Scenario | Pattern |
|
|
51
|
-
|----------|---------|
|
|
52
|
-
| Wait for event | `waitFor(() => events.find(e => e.type === 'DONE'))` |
|
|
53
|
-
| Wait for state | `waitFor(() => machine.state === 'ready')` |
|
|
54
|
-
| Wait for count | `waitFor(() => items.length >= 5)` |
|
|
55
|
-
| Wait for file | `waitFor(() => fs.existsSync(path))` |
|
|
56
|
-
| Complex condition | `waitFor(() => obj.ready && obj.value > 10)` |
|
|
57
|
-
|
|
58
|
-
## Implementation
|
|
59
|
-
|
|
60
|
-
Generic polling function:
|
|
61
|
-
```typescript
|
|
62
|
-
async function waitFor<T>(
|
|
63
|
-
condition: () => T | undefined | null | false,
|
|
64
|
-
description: string,
|
|
65
|
-
timeoutMs = 5000
|
|
66
|
-
): Promise<T> {
|
|
67
|
-
const startTime = Date.now();
|
|
68
|
-
|
|
69
|
-
while (true) {
|
|
70
|
-
const result = condition();
|
|
71
|
-
if (result) return result;
|
|
72
|
-
|
|
73
|
-
if (Date.now() - startTime > timeoutMs) {
|
|
74
|
-
throw new Error(`Timeout waiting for ${description} after ${timeoutMs}ms`);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
await new Promise(r => setTimeout(r, 10)); // Poll every 10ms
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
See `condition-based-waiting-example.ts` in this directory for complete implementation with domain-specific helpers (`waitForEvent`, `waitForEventCount`, `waitForEventMatch`) from actual debugging session.
|
|
83
|
-
|
|
84
|
-
## Common Mistakes
|
|
85
|
-
|
|
86
|
-
**❌ Polling too fast:** `setTimeout(check, 1)` - wastes CPU
|
|
87
|
-
**✅ Fix:** Poll every 10ms
|
|
88
|
-
|
|
89
|
-
**❌ No timeout:** Loop forever if condition never met
|
|
90
|
-
**✅ Fix:** Always include timeout with clear error
|
|
91
|
-
|
|
92
|
-
**❌ Stale data:** Cache state before loop
|
|
93
|
-
**✅ Fix:** Call getter inside loop for fresh data
|
|
94
|
-
|
|
95
|
-
## When Arbitrary Timeout IS Correct
|
|
96
|
-
|
|
97
|
-
```typescript
|
|
98
|
-
// Tool ticks every 100ms - need 2 ticks to verify partial output
|
|
99
|
-
await waitForEvent(manager, 'TOOL_STARTED'); // First: wait for condition
|
|
100
|
-
await new Promise(r => setTimeout(r, 200)); // Then: wait for timed behavior
|
|
101
|
-
// 200ms = 2 ticks at 100ms intervals - documented and justified
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
**Requirements:**
|
|
105
|
-
1. First wait for triggering condition
|
|
106
|
-
2. Based on known timing (not guessing)
|
|
107
|
-
3. Comment explaining WHY
|
|
108
|
-
|
|
109
|
-
## Real-World Impact
|
|
110
|
-
|
|
111
|
-
From debugging session (2025-10-03):
|
|
112
|
-
- Fixed 15 flaky tests across 3 files
|
|
113
|
-
- Pass rate: 60% → 100%
|
|
114
|
-
- Execution time: 40% faster
|
|
115
|
-
- No more race conditions
|
|
12
|
+
Fixed sleeps are acceptable only when time itself is the behavior under test.
|
|
@@ -1,122 +1,10 @@
|
|
|
1
|
-
# Defense
|
|
1
|
+
# Defense in Depth
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
After fixing the root cause, add another guard only when it prevents a distinct realistic failure:
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
- validate at an input boundary;
|
|
6
|
+
- preserve an invariant in the domain layer;
|
|
7
|
+
- make an unsafe state unrepresentable;
|
|
8
|
+
- monitor a failure that cannot be prevented.
|
|
6
9
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
## Why Multiple Layers
|
|
10
|
-
|
|
11
|
-
Single validation: "We fixed the bug"
|
|
12
|
-
Multiple layers: "We made the bug impossible"
|
|
13
|
-
|
|
14
|
-
Different layers catch different cases:
|
|
15
|
-
- Entry validation catches most bugs
|
|
16
|
-
- Business logic catches edge cases
|
|
17
|
-
- Environment guards prevent context-specific dangers
|
|
18
|
-
- Debug logging helps when other layers fail
|
|
19
|
-
|
|
20
|
-
## The Four Layers
|
|
21
|
-
|
|
22
|
-
### Layer 1: Entry Point Validation
|
|
23
|
-
**Purpose:** Reject obviously invalid input at API boundary
|
|
24
|
-
|
|
25
|
-
```typescript
|
|
26
|
-
function createProject(name: string, workingDirectory: string) {
|
|
27
|
-
if (!workingDirectory || workingDirectory.trim() === '') {
|
|
28
|
-
throw new Error('workingDirectory cannot be empty');
|
|
29
|
-
}
|
|
30
|
-
if (!existsSync(workingDirectory)) {
|
|
31
|
-
throw new Error(`workingDirectory does not exist: ${workingDirectory}`);
|
|
32
|
-
}
|
|
33
|
-
if (!statSync(workingDirectory).isDirectory()) {
|
|
34
|
-
throw new Error(`workingDirectory is not a directory: ${workingDirectory}`);
|
|
35
|
-
}
|
|
36
|
-
// ... proceed
|
|
37
|
-
}
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
### Layer 2: Business Logic Validation
|
|
41
|
-
**Purpose:** Ensure data makes sense for this operation
|
|
42
|
-
|
|
43
|
-
```typescript
|
|
44
|
-
function initializeWorkspace(projectDir: string, sessionId: string) {
|
|
45
|
-
if (!projectDir) {
|
|
46
|
-
throw new Error('projectDir required for workspace initialization');
|
|
47
|
-
}
|
|
48
|
-
// ... proceed
|
|
49
|
-
}
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
### Layer 3: Environment Guards
|
|
53
|
-
**Purpose:** Prevent dangerous operations in specific contexts
|
|
54
|
-
|
|
55
|
-
```typescript
|
|
56
|
-
async function gitInit(directory: string) {
|
|
57
|
-
// In tests, refuse git init outside temp directories
|
|
58
|
-
if (process.env.NODE_ENV === 'test') {
|
|
59
|
-
const normalized = normalize(resolve(directory));
|
|
60
|
-
const tmpDir = normalize(resolve(tmpdir()));
|
|
61
|
-
|
|
62
|
-
if (!normalized.startsWith(tmpDir)) {
|
|
63
|
-
throw new Error(
|
|
64
|
-
`Refusing git init outside temp dir during tests: ${directory}`
|
|
65
|
-
);
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
// ... proceed
|
|
69
|
-
}
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
### Layer 4: Debug Instrumentation
|
|
73
|
-
**Purpose:** Capture context for forensics
|
|
74
|
-
|
|
75
|
-
```typescript
|
|
76
|
-
async function gitInit(directory: string) {
|
|
77
|
-
const stack = new Error().stack;
|
|
78
|
-
logger.debug('About to git init', {
|
|
79
|
-
directory,
|
|
80
|
-
cwd: process.cwd(),
|
|
81
|
-
stack,
|
|
82
|
-
});
|
|
83
|
-
// ... proceed
|
|
84
|
-
}
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
## Applying the Pattern
|
|
88
|
-
|
|
89
|
-
When you find a bug:
|
|
90
|
-
|
|
91
|
-
1. **Trace the data flow** - Where does bad value originate? Where used?
|
|
92
|
-
2. **Map all checkpoints** - List every point data passes through
|
|
93
|
-
3. **Add validation at each layer** - Entry, business, environment, debug
|
|
94
|
-
4. **Test each layer** - Try to bypass layer 1, verify layer 2 catches it
|
|
95
|
-
|
|
96
|
-
## Example from Session
|
|
97
|
-
|
|
98
|
-
Bug: Empty `projectDir` caused `git init` in source code
|
|
99
|
-
|
|
100
|
-
**Data flow:**
|
|
101
|
-
1. Test setup → empty string
|
|
102
|
-
2. `Project.create(name, '')`
|
|
103
|
-
3. `WorkspaceManager.createWorkspace('')`
|
|
104
|
-
4. `git init` runs in `process.cwd()`
|
|
105
|
-
|
|
106
|
-
**Four layers added:**
|
|
107
|
-
- Layer 1: `Project.create()` validates not empty/exists/writable
|
|
108
|
-
- Layer 2: `WorkspaceManager` validates projectDir not empty
|
|
109
|
-
- Layer 3: `WorktreeManager` refuses git init outside tmpdir in tests
|
|
110
|
-
- Layer 4: Stack trace logging before git init
|
|
111
|
-
|
|
112
|
-
**Result:** All 1847 tests passed, bug impossible to reproduce
|
|
113
|
-
|
|
114
|
-
## Key Insight
|
|
115
|
-
|
|
116
|
-
All four layers were necessary. During testing, each layer caught bugs the others missed:
|
|
117
|
-
- Different code paths bypassed entry validation
|
|
118
|
-
- Mocks bypassed business logic checks
|
|
119
|
-
- Edge cases on different platforms needed environment guards
|
|
120
|
-
- Debug logging identified structural misuse
|
|
121
|
-
|
|
122
|
-
**Don't stop at one validation point.** Add checks at every layer.
|
|
10
|
+
Do not duplicate the same check across layers without a concrete failure mode.
|