wicked-garden 12.27.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.
Files changed (640) hide show
  1. package/.claude-plugin/archetypes.json +166 -0
  2. package/.claude-plugin/components.json +75 -0
  3. package/.claude-plugin/marketplace.json +15 -0
  4. package/.claude-plugin/plugin.json +174 -0
  5. package/.claude-plugin/specialist.json +48 -0
  6. package/.claude-plugin/stack-registry.json +96 -0
  7. package/AGENTS.md +13 -0
  8. package/CHANGELOG.md +712 -0
  9. package/CONTRIBUTING.md +99 -0
  10. package/ETHOS.md +83 -0
  11. package/LICENSE +21 -0
  12. package/README.md +115 -0
  13. package/WICKED_GARDEN_BUS_EVENTS.md +149 -0
  14. package/agents/agentic/architect.md +449 -0
  15. package/agents/agentic/performance-analyst.md +702 -0
  16. package/agents/agentic/safety-reviewer.md +662 -0
  17. package/agents/crew/implementer.md +163 -0
  18. package/agents/crew/researcher.md +94 -0
  19. package/agents/crew/reviewer.md +184 -0
  20. package/agents/data/data-engineer.md +227 -0
  21. package/agents/engineering/api-documentarian.md +440 -0
  22. package/agents/engineering/migration-engineer.md +301 -0
  23. package/agents/engineering/solution-architect.md +208 -0
  24. package/agents/jam/brainstorm-facilitator.md +297 -0
  25. package/agents/jam/council.md +322 -0
  26. package/agents/jam/quick-facilitator.md +85 -0
  27. package/agents/persona/persona-agent.md +121 -0
  28. package/agents/platform/compliance-officer.md +266 -0
  29. package/agents/platform/privacy-expert.md +496 -0
  30. package/agents/platform/security-engineer.md +287 -0
  31. package/agents/product/a11y-expert.md +323 -0
  32. package/agents/product/requirements-analyst.md +238 -0
  33. package/agents/product/ui-reviewer.md +180 -0
  34. package/agents/product/ux-designer.md +199 -0
  35. package/agents/product/value-strategist.md +269 -0
  36. package/agents/qe/semantic-reviewer.md +78 -0
  37. package/commands/agentic/audit.md +24 -0
  38. package/commands/agentic/design.md +24 -0
  39. package/commands/agentic/frameworks.md +25 -0
  40. package/commands/agentic/review.md +27 -0
  41. package/commands/archetype/build.md +12 -0
  42. package/commands/archetype/decide.md +12 -0
  43. package/commands/archetype/explore.md +12 -0
  44. package/commands/archetype/incident.md +12 -0
  45. package/commands/archetype/migrate.md +12 -0
  46. package/commands/archetype/modernize.md +12 -0
  47. package/commands/archetype/review.md +14 -0
  48. package/commands/archetype/ship.md +12 -0
  49. package/commands/archetype/specify.md +12 -0
  50. package/commands/archetype/triage.md +12 -0
  51. package/commands/compile.md +37 -0
  52. package/commands/data/analyze.md +18 -0
  53. package/commands/data/data.md +21 -0
  54. package/commands/data/ml.md +18 -0
  55. package/commands/data/ontology.md +22 -0
  56. package/commands/data/pipeline.md +17 -0
  57. package/commands/deliberate.md +181 -0
  58. package/commands/engineering/add-field.md +77 -0
  59. package/commands/engineering/apply.md +58 -0
  60. package/commands/engineering/arch.md +26 -0
  61. package/commands/engineering/debug.md +27 -0
  62. package/commands/engineering/docs.md +27 -0
  63. package/commands/engineering/new-generator.md +257 -0
  64. package/commands/engineering/patch-plan.md +59 -0
  65. package/commands/engineering/plan.md +29 -0
  66. package/commands/engineering/remove.md +48 -0
  67. package/commands/engineering/rename.md +44 -0
  68. package/commands/engineering/review.md +32 -0
  69. package/commands/help.md +128 -0
  70. package/commands/install.md +118 -0
  71. package/commands/intent.md +54 -0
  72. package/commands/jam/brainstorm.md +37 -0
  73. package/commands/jam/council.md +49 -0
  74. package/commands/jam/quick.md +21 -0
  75. package/commands/jam/revisit.md +79 -0
  76. package/commands/persona/as.md +136 -0
  77. package/commands/persona/define.md +24 -0
  78. package/commands/persona/list.md +118 -0
  79. package/commands/platform/actions.md +20 -0
  80. package/commands/platform/assert.md +18 -0
  81. package/commands/platform/audit.md +23 -0
  82. package/commands/platform/compliance.md +20 -0
  83. package/commands/platform/gh.md +22 -0
  84. package/commands/platform/health.md +22 -0
  85. package/commands/platform/incident.md +23 -0
  86. package/commands/platform/infra.md +24 -0
  87. package/commands/platform/peer-health.md +103 -0
  88. package/commands/platform/plugin-health.md +58 -0
  89. package/commands/platform/security.md +38 -0
  90. package/commands/platform/toolchain.md +96 -0
  91. package/commands/platform/traces.md +20 -0
  92. package/commands/product/a11y.md +19 -0
  93. package/commands/product/acceptance.md +19 -0
  94. package/commands/product/align.md +20 -0
  95. package/commands/product/analyze.md +23 -0
  96. package/commands/product/elicit.md +19 -0
  97. package/commands/product/listen.md +24 -0
  98. package/commands/product/mockup.md +20 -0
  99. package/commands/product/screenshot.md +19 -0
  100. package/commands/product/strategy.md +40 -0
  101. package/commands/product/synthesize.md +23 -0
  102. package/commands/product/ux-review.md +42 -0
  103. package/commands/product/ux.md +20 -0
  104. package/commands/product/visual-direction.md +34 -0
  105. package/commands/prove.md +47 -0
  106. package/commands/report-issue.md +243 -0
  107. package/commands/reset.md +144 -0
  108. package/commands/search/blast-radius.md +58 -0
  109. package/commands/search/hotspots.md +55 -0
  110. package/commands/search/index.md +38 -0
  111. package/commands/search/lineage.md +47 -0
  112. package/commands/search/service-map.md +79 -0
  113. package/commands/setup.md +363 -0
  114. package/commands/smaht/briefing.md +200 -0
  115. package/commands/smaht/events-import.md +95 -0
  116. package/commands/smaht/state.md +19 -0
  117. package/commands/where-am-i.md +58 -0
  118. package/docs/README.md +32 -0
  119. package/docs/adr/0001-code-relationship-graph-engine.md +116 -0
  120. package/docs/adr/0002-major-cleanup-keep-cut.md +91 -0
  121. package/docs/adr/0003-peers-gate-required-layers-optin.md +41 -0
  122. package/docs/adr/0004-code-graph-moves-to-wicked-brain.md +47 -0
  123. package/docs/brain-chunk-format.md +135 -0
  124. package/docs/compiler.md +95 -0
  125. package/docs/daemon-api.md +70 -0
  126. package/docs/domains.md +197 -0
  127. package/docs/getting-started.md +208 -0
  128. package/docs/plans/2026-06-08-wicked-loom-conduct.md +1337 -0
  129. package/docs/plans/2026-06-08-wicked-loom-contract.md +638 -0
  130. package/docs/plans/2026-06-08-wicked-loom-cutover.md +1300 -0
  131. package/docs/plans/2026-06-08-wicked-loom-expand-compose.md +843 -0
  132. package/docs/plans/2026-06-08-wicked-loom-flow-cutover.md +403 -0
  133. package/docs/plans/2026-06-10-codegraph-to-brain-phase1a-graph-core.md +838 -0
  134. package/docs/plans/2026-06-10-codegraph-to-brain-phase1b-injected-edges.md +44 -0
  135. package/docs/required-peers.md +60 -0
  136. package/docs/specs/2026-06-08-wicked-loom-extraction.md +225 -0
  137. package/docs/specs/2026-06-10-codegraph-to-brain-migration.md +168 -0
  138. package/docs/v11/archetypes.md +231 -0
  139. package/hooks/hooks.json +275 -0
  140. package/hooks/scripts/bootstrap.py +1797 -0
  141. package/hooks/scripts/invoke.py +62 -0
  142. package/hooks/scripts/notification.py +166 -0
  143. package/hooks/scripts/permission_request.py +223 -0
  144. package/hooks/scripts/post_tool.py +1374 -0
  145. package/hooks/scripts/pre_compact.py +272 -0
  146. package/hooks/scripts/pre_tool.py +1278 -0
  147. package/hooks/scripts/prompt_submit.py +1109 -0
  148. package/hooks/scripts/session_end.py +95 -0
  149. package/hooks/scripts/stop.py +624 -0
  150. package/hooks/scripts/subagent_lifecycle.py +464 -0
  151. package/hooks/scripts/subscribers/on_gate_decided.py +84 -0
  152. package/hooks/scripts/task_completed.py +322 -0
  153. package/hooks/scripts/worktree_guard.py +148 -0
  154. package/hooks/subscriptions/on_gate_decided.json +9 -0
  155. package/install.mjs +128 -0
  156. package/package.json +41 -0
  157. package/pyproject.toml +59 -0
  158. package/schemas/README.md +32 -0
  159. package/schemas/assert_contracts.json +37 -0
  160. package/schemas/health_probe.json +46 -0
  161. package/schemas/plugin_status.json +37 -0
  162. package/scripts/_adapters/__init__.py +166 -0
  163. package/scripts/_adapters/jira_adapter.py +18 -0
  164. package/scripts/_adapters/linear_adapter.py +18 -0
  165. package/scripts/_adapters/miro_adapter.py +18 -0
  166. package/scripts/_adapters/notion_adapter.py +18 -0
  167. package/scripts/_agents.py +357 -0
  168. package/scripts/_brain_ingest/__init__.py +2 -0
  169. package/scripts/_brain_ingest/session_fact_extractor.py +341 -0
  170. package/scripts/_brain_port.py +163 -0
  171. package/scripts/_bus.py +1081 -0
  172. package/scripts/_bus_catalog_gen.py +93 -0
  173. package/scripts/_bus_consumers.json +46 -0
  174. package/scripts/_bus_emit.py +43 -0
  175. package/scripts/_capability_registry.py +334 -0
  176. package/scripts/_capability_resolver.py +322 -0
  177. package/scripts/_domain_store.py +559 -0
  178. package/scripts/_event_log_reader.py +154 -0
  179. package/scripts/_event_schema.py +305 -0
  180. package/scripts/_event_store.py +397 -0
  181. package/scripts/_heavy_cadence.py +324 -0
  182. package/scripts/_integration_resolver.py +321 -0
  183. package/scripts/_logger.py +151 -0
  184. package/scripts/_loom.py +482 -0
  185. package/scripts/_paths.py +133 -0
  186. package/scripts/_python.sh +22 -0
  187. package/scripts/_run.py +137 -0
  188. package/scripts/_session.py +502 -0
  189. package/scripts/_validate_registry.py +1042 -0
  190. package/scripts/_wicked_testing_probe.py +277 -0
  191. package/scripts/agentic/analyze_agents.py +391 -0
  192. package/scripts/agentic/detect_framework.py +420 -0
  193. package/scripts/agentic/issue_taxonomy.py +357 -0
  194. package/scripts/agentic/pattern_scorer.py +434 -0
  195. package/scripts/classify/persist.py +169 -0
  196. package/scripts/compiler/compile.py +552 -0
  197. package/scripts/compiler/phase0/VERDICT.md +60 -0
  198. package/scripts/compiler/phase0/detect.py +292 -0
  199. package/scripts/compiler/phase0/emit.py +228 -0
  200. package/scripts/compiler/phase0/evidence/Enterprise-AISDLC.bindings.json +30 -0
  201. package/scripts/compiler/phase0/evidence/Enterprise-AISDLC.lint-output.txt +17 -0
  202. package/scripts/compiler/phase0/evidence/Enterprise-AISDLC.stage/.wg/evidence/failing-tests.txt +4 -0
  203. package/scripts/compiler/phase0/evidence/Enterprise-AISDLC.stage/.wg/evidence/honest-tests.txt +2 -0
  204. package/scripts/compiler/phase0/evidence/Enterprise-AISDLC.stage/fab-fail.build.md +8 -0
  205. package/scripts/compiler/phase0/evidence/Enterprise-AISDLC.stage/fab-missing.build.md +8 -0
  206. package/scripts/compiler/phase0/evidence/Enterprise-AISDLC.stage/honest.build.md +8 -0
  207. package/scripts/compiler/phase0/evidence/Enterprise-AISDLC.stage/wg_check_claims.py +174 -0
  208. package/scripts/compiler/phase0/evidence/command_iq.bindings.json +45 -0
  209. package/scripts/compiler/phase0/evidence/command_iq.lint-output.txt +17 -0
  210. package/scripts/compiler/phase0/evidence/command_iq.stage/.projects/evidence-domain/phase-1-clarify/evidence/failing-tests.txt +4 -0
  211. package/scripts/compiler/phase0/evidence/command_iq.stage/.projects/evidence-domain/phase-1-clarify/evidence/honest-tests.txt +3 -0
  212. package/scripts/compiler/phase0/evidence/command_iq.stage/fab-fail.build.md +8 -0
  213. package/scripts/compiler/phase0/evidence/command_iq.stage/fab-missing.build.md +8 -0
  214. package/scripts/compiler/phase0/evidence/command_iq.stage/honest.build.md +8 -0
  215. package/scripts/compiler/phase0/evidence/command_iq.stage/wg_check_claims.py +174 -0
  216. package/scripts/compiler/phase0/evidence/memos.bindings.json +28 -0
  217. package/scripts/compiler/phase0/evidence/memos.lint-output.txt +17 -0
  218. package/scripts/compiler/phase0/evidence/memos.stage/.wg/evidence/failing-tests.txt +4 -0
  219. package/scripts/compiler/phase0/evidence/memos.stage/.wg/evidence/honest-tests.txt +2 -0
  220. package/scripts/compiler/phase0/evidence/memos.stage/fab-fail.build.md +8 -0
  221. package/scripts/compiler/phase0/evidence/memos.stage/fab-missing.build.md +8 -0
  222. package/scripts/compiler/phase0/evidence/memos.stage/honest.build.md +8 -0
  223. package/scripts/compiler/phase0/evidence/memos.stage/wg_check_claims.py +174 -0
  224. package/scripts/compiler/phase0/evidence/verdict.json +104 -0
  225. package/scripts/compiler/phase0/evidence/wicked-bus.bindings.json +29 -0
  226. package/scripts/compiler/phase0/evidence/wicked-bus.lint-output.txt +17 -0
  227. package/scripts/compiler/phase0/evidence/wicked-bus.stage/coverage/failing-tests.txt +4 -0
  228. package/scripts/compiler/phase0/evidence/wicked-bus.stage/coverage/honest-tests.txt +3 -0
  229. package/scripts/compiler/phase0/evidence/wicked-bus.stage/fab-fail.build.md +8 -0
  230. package/scripts/compiler/phase0/evidence/wicked-bus.stage/fab-missing.build.md +8 -0
  231. package/scripts/compiler/phase0/evidence/wicked-bus.stage/honest.build.md +8 -0
  232. package/scripts/compiler/phase0/evidence/wicked-bus.stage/wg_check_claims.py +174 -0
  233. package/scripts/compiler/phase0/evidence/wire-vault-transcript.txt +60 -0
  234. package/scripts/compiler/phase0/run_probe.py +234 -0
  235. package/scripts/compiler/phase0/wire_vault.py +310 -0
  236. package/scripts/crew/__init__.py +0 -0
  237. package/scripts/crew/_task_audit_writer.py +243 -0
  238. package/scripts/crew/_task_reader.py +389 -0
  239. package/scripts/crew/archetypes_v11.py +348 -0
  240. package/scripts/crew/detectors/__init__.py +12 -0
  241. package/scripts/crew/flow_compiler.py +121 -0
  242. package/scripts/crew/phase_manager.py +703 -0
  243. package/scripts/crew/scope_delta.py +264 -0
  244. package/scripts/crew/specialist_resolver.py +218 -0
  245. package/scripts/crew/stack_registry.py +189 -0
  246. package/scripts/data/data_profiler.py +271 -0
  247. package/scripts/data/ontology_recommender.py +231 -0
  248. package/scripts/data/schema_validator.py +267 -0
  249. package/scripts/delivery/drift.py +739 -0
  250. package/scripts/delivery/telemetry.py +614 -0
  251. package/scripts/engineering/patch/codegraph_db.py +125 -0
  252. package/scripts/engineering/patch/generators/__init__.py +56 -0
  253. package/scripts/engineering/patch/generators/base.py +373 -0
  254. package/scripts/engineering/patch/generators/csharp_generator.py +494 -0
  255. package/scripts/engineering/patch/generators/go_generator.py +430 -0
  256. package/scripts/engineering/patch/generators/java_generator.py +928 -0
  257. package/scripts/engineering/patch/generators/jsp_generator.py +454 -0
  258. package/scripts/engineering/patch/generators/kotlin_generator.py +561 -0
  259. package/scripts/engineering/patch/generators/perl_generator.py +510 -0
  260. package/scripts/engineering/patch/generators/php_generator.py +644 -0
  261. package/scripts/engineering/patch/generators/propagation_engine.py +929 -0
  262. package/scripts/engineering/patch/generators/python_generator.py +487 -0
  263. package/scripts/engineering/patch/generators/ruby_generator.py +463 -0
  264. package/scripts/engineering/patch/generators/rust_generator.py +400 -0
  265. package/scripts/engineering/patch/generators/sql_generator.py +594 -0
  266. package/scripts/engineering/patch/generators/typescript_generator.py +439 -0
  267. package/scripts/engineering/patch/patch.py +800 -0
  268. package/scripts/engineering/patch/safety.py +429 -0
  269. package/scripts/jam/__init__.py +0 -0
  270. package/scripts/jam/_bus_consumers.py +271 -0
  271. package/scripts/jam/agentic_cli_registry.py +703 -0
  272. package/scripts/jam/consensus.py +737 -0
  273. package/scripts/jam/detect_clis.py +409 -0
  274. package/scripts/jam/jam.py +283 -0
  275. package/scripts/jam/save_transcript.py +171 -0
  276. package/scripts/loom/__init__.py +22 -0
  277. package/scripts/loom/cli.py +170 -0
  278. package/scripts/loom/compose.py +180 -0
  279. package/scripts/loom/gate.py +120 -0
  280. package/scripts/loom/manifest.py +140 -0
  281. package/scripts/loom/resolve.py +59 -0
  282. package/scripts/persona/__init__.py +0 -0
  283. package/scripts/persona/registry.py +688 -0
  284. package/scripts/platform/guard_pipeline.py +1214 -0
  285. package/scripts/platform/guard_profiles.py +216 -0
  286. package/scripts/platform/observability/assert_contracts.py +434 -0
  287. package/scripts/platform/observability/health_probe.py +915 -0
  288. package/scripts/platform/observability/ops_log_viewer.py +209 -0
  289. package/scripts/platform/prereq_doctor.py +567 -0
  290. package/scripts/qe/conditions_manifest.py +260 -0
  291. package/scripts/qe/content_sanitizer.py +160 -0
  292. package/scripts/qe/coverage_tracker.py +535 -0
  293. package/scripts/qe/discover_scenarios.py +243 -0
  294. package/scripts/qe/evidence_tracker.py +232 -0
  295. package/scripts/qe/prove.py +196 -0
  296. package/scripts/qe/registry_lookup.py +80 -0
  297. package/scripts/qe/registry_store.py +176 -0
  298. package/scripts/qe/semantic_review.py +1005 -0
  299. package/scripts/qe/vault_gate.py +382 -0
  300. package/scripts/qe/verdict_audit.py +175 -0
  301. package/scripts/qe/verdict_schema.py +335 -0
  302. package/scripts/reset.py +220 -0
  303. package/scripts/resolve_path.py +22 -0
  304. package/scripts/sentinel/invariants.py +402 -0
  305. package/scripts/sentinel/pre_push.py +73 -0
  306. package/scripts/setup/__init__.py +1 -0
  307. package/scripts/setup/detect_state.py +114 -0
  308. package/scripts/setup/migrate_legacy.py +67 -0
  309. package/scripts/setup/migrate_v6_projects.py +232 -0
  310. package/scripts/setup/onboarding.py +114 -0
  311. package/scripts/smaht/_bus_consumers.py +98 -0
  312. package/scripts/smaht/adapters/__init__.py +83 -0
  313. package/scripts/smaht/adapters/brain_adapter.py +254 -0
  314. package/scripts/smaht/adapters/context7_adapter.py +438 -0
  315. package/scripts/smaht/adapters/delegation_adapter.py +104 -0
  316. package/scripts/smaht/adapters/domain_adapter.py +206 -0
  317. package/scripts/smaht/adapters/events_adapter.py +231 -0
  318. package/scripts/smaht/adapters/tools_adapter.py +49 -0
  319. package/scripts/smaht/cheatsheet_store.py +236 -0
  320. package/scripts/smaht/context_package.py +386 -0
  321. package/scripts/smaht/knowledge_graph.py +395 -0
  322. package/scripts/smaht/propose_skills.py +856 -0
  323. package/scripts/smaht/test_cheatsheet_store.py +428 -0
  324. package/scripts/statusline.py +151 -0
  325. package/scripts/where_am_i.py +236 -0
  326. package/skills/agentic/agentic-patterns/SKILL.md +91 -0
  327. package/skills/agentic/agentic-patterns/refs/anti-patterns-design.md +283 -0
  328. package/skills/agentic/agentic-patterns/refs/anti-patterns-operational.md +216 -0
  329. package/skills/agentic/agentic-patterns/refs/pattern-catalog.md +329 -0
  330. package/skills/agentic/context-engineering/SKILL.md +142 -0
  331. package/skills/agentic/context-engineering/refs/caching-and-optimization.md +251 -0
  332. package/skills/agentic/context-engineering/refs/compression-techniques.md +171 -0
  333. package/skills/agentic/context-engineering/refs/cost-calculation-budget.md +250 -0
  334. package/skills/agentic/context-engineering/refs/cost-optimization-reporting.md +300 -0
  335. package/skills/agentic/context-engineering/refs/selective-loading.md +179 -0
  336. package/skills/agentic/frameworks/SKILL.md +191 -0
  337. package/skills/agentic/frameworks/refs/framework-profiles-1.md +209 -0
  338. package/skills/agentic/frameworks/refs/framework-profiles-2.md +214 -0
  339. package/skills/agentic/frameworks/refs/migration-patterns-paths.md +267 -0
  340. package/skills/agentic/frameworks/refs/migration-patterns-testing.md +208 -0
  341. package/skills/agentic/refs/audit.md +134 -0
  342. package/skills/agentic/refs/design.md +137 -0
  343. package/skills/agentic/refs/frameworks.md +102 -0
  344. package/skills/agentic/refs/review.md +160 -0
  345. package/skills/agentic/review-methodology/SKILL.md +186 -0
  346. package/skills/agentic/review-methodology/refs/deliverable-templates.md +246 -0
  347. package/skills/agentic/review-methodology/refs/issue-taxonomy-quality-testing.md +277 -0
  348. package/skills/agentic/review-methodology/refs/issue-taxonomy-reliability-safety.md +253 -0
  349. package/skills/agentic/trust-and-safety/SKILL.md +177 -0
  350. package/skills/agentic/trust-and-safety/refs/guardrails-actions.md +246 -0
  351. package/skills/agentic/trust-and-safety/refs/guardrails-input-output.md +238 -0
  352. package/skills/agentic/trust-and-safety/refs/guardrails-resources.md +209 -0
  353. package/skills/agentic/trust-and-safety/refs/safety-checklist-advanced.md +209 -0
  354. package/skills/agentic/trust-and-safety/refs/safety-checklist-core.md +215 -0
  355. package/skills/archetype/SKILL.md +104 -0
  356. package/skills/archetype/refs/build.md +142 -0
  357. package/skills/archetype/refs/decide.md +117 -0
  358. package/skills/archetype/refs/explore.md +66 -0
  359. package/skills/archetype/refs/incident.md +149 -0
  360. package/skills/archetype/refs/migrate.md +170 -0
  361. package/skills/archetype/refs/modernize.md +187 -0
  362. package/skills/archetype/refs/review.md +145 -0
  363. package/skills/archetype/refs/ship.md +117 -0
  364. package/skills/archetype/refs/specify.md +108 -0
  365. package/skills/archetype/refs/triage.md +62 -0
  366. package/skills/classify/SKILL.md +157 -0
  367. package/skills/data/analysis/SKILL.md +125 -0
  368. package/skills/data/analysis/refs/templates.md +170 -0
  369. package/skills/data/data/SKILL.md +118 -0
  370. package/skills/data/data/refs/examples.md +235 -0
  371. package/skills/data/ml/SKILL.md +125 -0
  372. package/skills/data/ml/refs/templates.md +172 -0
  373. package/skills/data/pipeline/SKILL.md +136 -0
  374. package/skills/data/pipeline/refs/templates.md +175 -0
  375. package/skills/data/refs/analyze.md +123 -0
  376. package/skills/data/refs/data.md +95 -0
  377. package/skills/data/refs/ml.md +118 -0
  378. package/skills/data/refs/pipeline.md +92 -0
  379. package/skills/deliberate/SKILL.md +125 -0
  380. package/skills/deliberate/refs/architecture-lens.md +37 -0
  381. package/skills/deliberate/refs/assumptions-lens.md +43 -0
  382. package/skills/deliberate/refs/code-lens.md +38 -0
  383. package/skills/deliberate/refs/content-lens.md +37 -0
  384. package/skills/deliberate/refs/data-lens.md +43 -0
  385. package/skills/deliberate/refs/design-lens.md +37 -0
  386. package/skills/deliberate/refs/opportunity-patterns.md +107 -0
  387. package/skills/deliberate/refs/ops-lens.md +43 -0
  388. package/skills/deliberate/refs/product-lens.md +46 -0
  389. package/skills/deliberate/refs/rethink-framework.md +77 -0
  390. package/skills/deliberate/refs/security-lens.md +47 -0
  391. package/skills/deliberate/refs/testing-lens.md +45 -0
  392. package/skills/deliberate/refs/timing-lens.md +42 -0
  393. package/skills/engineering/architecture/SKILL.md +177 -0
  394. package/skills/engineering/architecture/refs/adr-template.md +268 -0
  395. package/skills/engineering/architecture/refs/architecture-template-deployment.md +176 -0
  396. package/skills/engineering/architecture/refs/architecture-template-design.md +300 -0
  397. package/skills/engineering/architecture/refs/examples-ecommerce-analytics.md +299 -0
  398. package/skills/engineering/architecture/refs/examples-saas-trading.md +291 -0
  399. package/skills/engineering/architecture/refs/patterns-advanced.md +238 -0
  400. package/skills/engineering/architecture/refs/patterns-structural.md +303 -0
  401. package/skills/engineering/backend/SKILL.md +102 -0
  402. package/skills/engineering/backend/refs/checklists.md +146 -0
  403. package/skills/engineering/backend/refs/patterns.md +181 -0
  404. package/skills/engineering/debugging/SKILL.md +99 -0
  405. package/skills/engineering/debugging/refs/patterns.md +248 -0
  406. package/skills/engineering/debugging/refs/process.md +203 -0
  407. package/skills/engineering/docs/SKILL.md +97 -0
  408. package/skills/engineering/engineering/SKILL.md +88 -0
  409. package/skills/engineering/engineering/refs/checklists.md +91 -0
  410. package/skills/engineering/engineering/refs/templates.md +71 -0
  411. package/skills/engineering/frontend/SKILL.md +92 -0
  412. package/skills/engineering/frontend/refs/checklists.md +96 -0
  413. package/skills/engineering/frontend/refs/patterns.md +167 -0
  414. package/skills/engineering/integration/SKILL.md +183 -0
  415. package/skills/engineering/integration/refs/error-handling-best-practices.md +139 -0
  416. package/skills/engineering/integration/refs/error-handling-error-classes-typescript.md +212 -0
  417. package/skills/engineering/integration/refs/error-handling-error-response-format.md +301 -0
  418. package/skills/engineering/integration/refs/error-handling-retry-strategies.md +190 -0
  419. package/skills/engineering/integration/refs/event-schemas-best-practices.md +225 -0
  420. package/skills/engineering/integration/refs/event-schemas-event-naming-conventions.md +303 -0
  421. package/skills/engineering/integration/refs/event-schemas-event-structure.md +288 -0
  422. package/skills/engineering/integration/refs/graphql-best-practices.md +138 -0
  423. package/skills/engineering/integration/refs/graphql-error-handling.md +198 -0
  424. package/skills/engineering/integration/refs/graphql-graphql-basics.md +197 -0
  425. package/skills/engineering/integration/refs/graphql-query-examples.md +226 -0
  426. package/skills/engineering/integration/refs/graphql-schema-design-patterns.md +280 -0
  427. package/skills/engineering/integration/refs/grpc-grpc-overview.md +246 -0
  428. package/skills/engineering/integration/refs/grpc-implementation-examples.md +269 -0
  429. package/skills/engineering/integration/refs/grpc-metadata-headers.md +304 -0
  430. package/skills/engineering/integration/refs/grpc-testing.md +49 -0
  431. package/skills/engineering/integration/refs/openapi-template.yaml +682 -0
  432. package/skills/engineering/integration/refs/resilience-best-practices.md +109 -0
  433. package/skills/engineering/integration/refs/resilience-circuit-breaker-pattern.md +302 -0
  434. package/skills/engineering/integration/refs/resilience-rate-limiting.md +245 -0
  435. package/skills/engineering/integration/refs/resilience-timeout-pattern.md +212 -0
  436. package/skills/engineering/integration/refs/rest-api-fundamentals.md +299 -0
  437. package/skills/engineering/integration/refs/rest-api-responses-security.md +302 -0
  438. package/skills/engineering/integration/refs/versioning-breaking-changes.md +237 -0
  439. package/skills/engineering/integration/refs/versioning-migration-strategies.md +257 -0
  440. package/skills/engineering/integration/refs/versioning-versioning-strategies.md +296 -0
  441. package/skills/engineering/large-scale-migration/SKILL.md +65 -0
  442. package/skills/engineering/patch/SKILL.md +184 -0
  443. package/skills/engineering/refs/arch.md +126 -0
  444. package/skills/engineering/refs/debug.md +142 -0
  445. package/skills/engineering/refs/docs.md +190 -0
  446. package/skills/engineering/refs/plan.md +109 -0
  447. package/skills/engineering/refs/review.md +138 -0
  448. package/skills/engineering/system-design/SKILL.md +154 -0
  449. package/skills/engineering/system-design/refs/anti-patterns-big-ball-of-mud.md +254 -0
  450. package/skills/engineering/system-design/refs/anti-patterns-circular-dependencies.md +241 -0
  451. package/skills/engineering/system-design/refs/anti-patterns-feature-envy.md +168 -0
  452. package/skills/engineering/system-design/refs/anti-patterns-god-object.md +247 -0
  453. package/skills/engineering/system-design/refs/component-template-lifecycle.md +210 -0
  454. package/skills/engineering/system-design/refs/component-template-maintenance.md +219 -0
  455. package/skills/engineering/system-design/refs/component-template-structure.md +276 -0
  456. package/skills/engineering/system-design/refs/dependencies-best-practices.md +260 -0
  457. package/skills/engineering/system-design/refs/dependencies-dependency-principles.md +295 -0
  458. package/skills/engineering/system-design/refs/dependencies-dependency-tracking.md +261 -0
  459. package/skills/engineering/system-design/refs/interface-template-lifecycle.md +211 -0
  460. package/skills/engineering/system-design/refs/interface-template-maintenance.md +212 -0
  461. package/skills/engineering/system-design/refs/interface-template-structure.md +269 -0
  462. package/skills/engineering/system-design/refs/patterns-dependency-injection.md +151 -0
  463. package/skills/engineering/system-design/refs/patterns-facade-pattern.md +257 -0
  464. package/skills/engineering/system-design/refs/patterns-layered-pattern.md +204 -0
  465. package/skills/engineering/system-design/refs/patterns-plugin-architecture.md +229 -0
  466. package/skills/engineering/unit-test-quality/SKILL.md +194 -0
  467. package/skills/ground/SKILL.md +130 -0
  468. package/skills/integration-discovery/SKILL.md +168 -0
  469. package/skills/integration-discovery/refs/capabilities.md +282 -0
  470. package/skills/integration-discovery/refs/cli-detection.md +295 -0
  471. package/skills/integration-discovery/refs/discovery-sources.md +233 -0
  472. package/skills/integration-discovery/refs/task-patterns.md +206 -0
  473. package/skills/jam/SKILL.md +45 -0
  474. package/skills/jam/refs/facilitation-patterns.md +125 -0
  475. package/skills/jam/refs/quick.md +64 -0
  476. package/skills/jam/refs/synthesis-patterns.md +114 -0
  477. package/skills/multi-model/SKILL.md +168 -0
  478. package/skills/multi-model/refs/aichat.md +119 -0
  479. package/skills/multi-model/refs/aider.md +100 -0
  480. package/skills/multi-model/refs/auditability.md +238 -0
  481. package/skills/multi-model/refs/codex.md +169 -0
  482. package/skills/multi-model/refs/context.md +306 -0
  483. package/skills/multi-model/refs/copilot.md +161 -0
  484. package/skills/multi-model/refs/examples.md +224 -0
  485. package/skills/multi-model/refs/gemini.md +185 -0
  486. package/skills/multi-model/refs/goose.md +112 -0
  487. package/skills/multi-model/refs/llm.md +124 -0
  488. package/skills/multi-model/refs/opencode.md +196 -0
  489. package/skills/multi-model/refs/orchestration.md +188 -0
  490. package/skills/multi-model/refs/pi.md +208 -0
  491. package/skills/persona/SKILL.md +144 -0
  492. package/skills/persona/refs/define.md +133 -0
  493. package/skills/platform/actions/refs/actions.md +114 -0
  494. package/skills/platform/audit/SKILL.md +174 -0
  495. package/skills/platform/audit/refs/audit.md +145 -0
  496. package/skills/platform/audit/refs/checklists-evidence-operations.md +144 -0
  497. package/skills/platform/audit/refs/checklists-gdpr-pci-evidence.md +213 -0
  498. package/skills/platform/audit/refs/checklists-soc2-hipaa.md +120 -0
  499. package/skills/platform/audit/refs/frameworks-gdpr-pci.md +225 -0
  500. package/skills/platform/audit/refs/frameworks-soc2-hipaa.md +228 -0
  501. package/skills/platform/compliance/SKILL.md +169 -0
  502. package/skills/platform/compliance/refs/checklists.md +303 -0
  503. package/skills/platform/compliance/refs/compliance.md +117 -0
  504. package/skills/platform/compliance/refs/frameworks.md +282 -0
  505. package/skills/platform/errors/SKILL.md +183 -0
  506. package/skills/platform/errors/refs/patterns.md +271 -0
  507. package/skills/platform/errors/refs/severity.md +264 -0
  508. package/skills/platform/gate-benchmark-rebaseline/SKILL.md +108 -0
  509. package/skills/platform/gh/refs/gh.md +105 -0
  510. package/skills/platform/gh-cli/SKILL.md +120 -0
  511. package/skills/platform/gh-cli/refs/automation.md +63 -0
  512. package/skills/platform/gh-cli/refs/gh-ops.md +103 -0
  513. package/skills/platform/gh-cli/refs/patterns.md +132 -0
  514. package/skills/platform/gh-cli/scripts/gh_ops.py +454 -0
  515. package/skills/platform/github-actions/SKILL.md +159 -0
  516. package/skills/platform/github-actions/refs/security.md +150 -0
  517. package/skills/platform/github-actions/refs/templates.md +230 -0
  518. package/skills/platform/github-actions/refs/troubleshooting.md +174 -0
  519. package/skills/platform/github-actions/scripts/workflow_gen.py +215 -0
  520. package/skills/platform/gitlab-ci/SKILL.md +140 -0
  521. package/skills/platform/gitlab-ci/refs/templates.md +223 -0
  522. package/skills/platform/gitlab-ci/refs/troubleshooting.md +213 -0
  523. package/skills/platform/glab-cli/SKILL.md +133 -0
  524. package/skills/platform/glab-cli/refs/ci-debugging.md +95 -0
  525. package/skills/platform/glab-cli/refs/glab-ops.md +78 -0
  526. package/skills/platform/glab-cli/refs/patterns.md +131 -0
  527. package/skills/platform/glab-cli/scripts/glab_ops.py +313 -0
  528. package/skills/platform/health/SKILL.md +177 -0
  529. package/skills/platform/health/refs/health.md +72 -0
  530. package/skills/platform/health/refs/sources.md +302 -0
  531. package/skills/platform/incident/refs/incident.md +136 -0
  532. package/skills/platform/infra/refs/infra.md +104 -0
  533. package/skills/platform/observability/SKILL.md +128 -0
  534. package/skills/platform/observability/refs/toolchain-discovery.md +243 -0
  535. package/skills/platform/prereq-doctor/SKILL.md +57 -0
  536. package/skills/platform/prereq-doctor/refs/tool-registry.md +58 -0
  537. package/skills/platform/traces/refs/traces.md +101 -0
  538. package/skills/product/acceptance-criteria/SKILL.md +193 -0
  539. package/skills/product/acceptance-criteria/refs/ac-anti-patterns.md +291 -0
  540. package/skills/product/acceptance-criteria/refs/ac-examples.md +277 -0
  541. package/skills/product/accessibility/SKILL.md +197 -0
  542. package/skills/product/accessibility/refs/aria-patterns-basics.md +250 -0
  543. package/skills/product/accessibility/refs/aria-patterns-dynamic.md +187 -0
  544. package/skills/product/accessibility/refs/aria-patterns-interactive.md +246 -0
  545. package/skills/product/accessibility/refs/audit-report-findings.md +248 -0
  546. package/skills/product/accessibility/refs/audit-report-results.md +276 -0
  547. package/skills/product/accessibility/refs/common-violations-html-css.md +270 -0
  548. package/skills/product/accessibility/refs/common-violations-interactive.md +303 -0
  549. package/skills/product/accessibility/refs/keyboard-testing-basics.md +222 -0
  550. package/skills/product/accessibility/refs/keyboard-testing-patterns.md +173 -0
  551. package/skills/product/accessibility/refs/screen-reader-testing-advanced.md +294 -0
  552. package/skills/product/accessibility/refs/screen-reader-testing-commands.md +255 -0
  553. package/skills/product/accessibility/refs/wcag-checklist.md +262 -0
  554. package/skills/product/analyze/SKILL.md +164 -0
  555. package/skills/product/analyze/refs/algorithms.md +238 -0
  556. package/skills/product/analyze/refs/sentiment-patterns.md +180 -0
  557. package/skills/product/imagery/SKILL.md +97 -0
  558. package/skills/product/imagery/alter/SKILL.md +105 -0
  559. package/skills/product/imagery/alter/refs/editing-reference.md +146 -0
  560. package/skills/product/imagery/create/SKILL.md +109 -0
  561. package/skills/product/imagery/create/refs/prompt-engineering.md +112 -0
  562. package/skills/product/imagery/create/refs/provider-reference.md +219 -0
  563. package/skills/product/imagery/review/SKILL.md +101 -0
  564. package/skills/product/imagery/review/refs/analysis-lenses.md +136 -0
  565. package/skills/product/imagery/review/refs/quality-gates.md +153 -0
  566. package/skills/product/imagery/scripts/analyze.sh +23 -0
  567. package/skills/product/imagery/scripts/edit.sh +14 -0
  568. package/skills/product/imagery/scripts/generate.sh +13 -0
  569. package/skills/product/imagery/scripts/provider.py +787 -0
  570. package/skills/product/listen/SKILL.md +175 -0
  571. package/skills/product/listen/refs/channels.md +220 -0
  572. package/skills/product/mockup/SKILL.md +106 -0
  573. package/skills/product/mockup/refs/templates.md +95 -0
  574. package/skills/product/refs/a11y.md +109 -0
  575. package/skills/product/refs/acceptance.md +79 -0
  576. package/skills/product/refs/align.md +67 -0
  577. package/skills/product/refs/analyze.md +77 -0
  578. package/skills/product/refs/elicit.md +67 -0
  579. package/skills/product/refs/listen.md +58 -0
  580. package/skills/product/refs/mockup.md +77 -0
  581. package/skills/product/refs/screenshot.md +59 -0
  582. package/skills/product/refs/strategy.md +77 -0
  583. package/skills/product/refs/synthesize.md +54 -0
  584. package/skills/product/refs/ux-review.md +68 -0
  585. package/skills/product/refs/ux.md +101 -0
  586. package/skills/product/requirements-analysis/SKILL.md +136 -0
  587. package/skills/product/requirements-analysis/refs/requirements-example-auth.md +264 -0
  588. package/skills/product/requirements-analysis/refs/requirements-example-export-integration.md +88 -0
  589. package/skills/product/requirements-analysis/refs/requirements-output-format-template.md +247 -0
  590. package/skills/product/requirements-analysis/refs/user-story-guide.md +296 -0
  591. package/skills/product/requirements-graph/SKILL.md +155 -0
  592. package/skills/product/requirements-graph/refs/examples.md +223 -0
  593. package/skills/product/requirements-graph/refs/schema.md +162 -0
  594. package/skills/product/requirements-migrate/SKILL.md +90 -0
  595. package/skills/product/requirements-navigate/SKILL.md +141 -0
  596. package/skills/product/requirements-navigate/refs/meta-templates.md +141 -0
  597. package/skills/product/screenshot/SKILL.md +147 -0
  598. package/skills/product/strategy/SKILL.md +198 -0
  599. package/skills/product/strategy/refs/frameworks.md +295 -0
  600. package/skills/product/strategy/refs/templates-competitive-market.md +299 -0
  601. package/skills/product/strategy/refs/templates-roi-value.md +207 -0
  602. package/skills/product/synthesize/SKILL.md +116 -0
  603. package/skills/product/synthesize/refs/journey-mapping.md +212 -0
  604. package/skills/product/synthesize/refs/prioritization.md +193 -0
  605. package/skills/product/ux-review/SKILL.md +164 -0
  606. package/skills/product/visual-direction/SKILL.md +137 -0
  607. package/skills/product/visual-review/SKILL.md +131 -0
  608. package/skills/runtime-exec/SKILL.md +138 -0
  609. package/skills/search/codebase-narrator/SKILL.md +131 -0
  610. package/skills/search/codebase-narrator/refs/output-template.md +100 -0
  611. package/skills/smaht/SKILL.md +72 -0
  612. package/skills/smaht/discovery/SKILL.md +65 -0
  613. package/skills/smaht/intent/SKILL.md +89 -0
  614. package/skills/smaht/propose-skills/SKILL.md +142 -0
  615. package/skills/smaht/refs/state.md +76 -0
  616. package/skills/swarm/SKILL.md +132 -0
  617. package/skills/swarm/refs/fan-out.md +104 -0
  618. package/skills/swarm/refs/independent-verification.md +86 -0
  619. package/skills/swarm/refs/receipts-and-evidence.md +69 -0
  620. package/skills/swarm/refs/recon-synthesis.md +87 -0
  621. package/skills/swarm/refs/ship-discipline.md +90 -0
  622. package/skills/wickedizer/SKILL.md +147 -0
  623. package/skills/wickedizer/refs/artifact-types.md +238 -0
  624. package/skills/wickedizer/refs/complexity.md +278 -0
  625. package/skills/wickedizer/refs/de-ai-pass.md +140 -0
  626. package/skills/wickedizer/refs/failure-modes.md +249 -0
  627. package/skills/wickedizer/refs/patterns.md +282 -0
  628. package/skills/wickedizer/refs/review.md +221 -0
  629. package/skills/wickedizer/refs/structure.md +282 -0
  630. package/skills/wickedizer/refs/voice-profile.md +125 -0
  631. package/skills/workflow/SKILL.md +132 -0
  632. package/skills/workflow/refs/archetype-adjustments.md +205 -0
  633. package/skills/workflow/refs/evidence.md +58 -0
  634. package/skills/workflow/refs/integration.md +130 -0
  635. package/skills/workflow/refs/risk-dimension-signals.md +260 -0
  636. package/skills/workflow/refs/scoring-rubric.md +49 -0
  637. package/skills/workflow/refs/signal-keywords.md +176 -0
  638. package/skills/workflow/refs/specialist-routing-rules.md +159 -0
  639. package/skills/worktrees/SKILL.md +87 -0
  640. package/skills/worktrees/refs/recipes.md +96 -0
@@ -0,0 +1,614 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ telemetry.py — cross-session quality telemetry capture for wicked-garden.
4
+
5
+ Closes Issue #443: quality trends invisible across sessions.
6
+
7
+ Responsibilities
8
+ ----------------
9
+ 1. Capture per-session quality metrics from crew + native-task state.
10
+ 2. Append one record per session-close to a per-project JSONL timeline.
11
+ 3. Expose read helpers for drift.py and status commands.
12
+
13
+ Storage
14
+ -------
15
+ Path (resolve via get_local_file from _paths):
16
+ ~/.something-wicked/wicked-garden/projects/{slug}/metrics/{project}/timeline.jsonl
17
+
18
+ One JSONL record per session-close. Append-only. Never rewrites.
19
+
20
+ Captured fields (timeline.jsonl record schema)
21
+ ----------------------------------------------
22
+ version: schema version (currently "1")
23
+ session_id: the session that closed (sanitized)
24
+ project: crew project name (or "_global" if none active)
25
+ recorded_at: UTC ISO8601 timestamp
26
+ sample_window: dict with first/last observation timestamps
27
+ metrics:
28
+ gate_pass_rate: float 0..1 — APPROVE / total verdicts this session
29
+ gate_avg_score: float — mean gate score (APPROVE/CONDITIONAL) or None
30
+ gate_verdict_count: int — total verdicts observed this session
31
+ gate_rework_count: int — REJECT verdicts this session
32
+ task_count: int — native tasks observed this session
33
+ task_completed: int — tasks completed this session
34
+ complexity_delta: int — complexity_score at close minus at session open
35
+ cycle_time_by_phase: {phase: seconds_to_approve} (float)
36
+ skip_reeval_count: int — --skip-reeval invocations this session
37
+ rework_events: int — alias for gate_rework_count for easy querying
38
+
39
+ Design rules
40
+ ------------
41
+ - Stdlib-only (importable from hook scripts).
42
+ - Fail-open: every public entry point has a top-level try/except that returns
43
+ None / False rather than raising. Hook callers must never break.
44
+ - Capture target: <100ms typical, <500ms worst (bounded by a single stat+read
45
+ pass over the session's tasks dir).
46
+ - No external dependencies and no wicked-bus coupling. drift.py handles bus.
47
+ """
48
+
49
+ from __future__ import annotations
50
+
51
+ import json
52
+ import os
53
+ import sys
54
+ import time
55
+ from datetime import datetime, timezone
56
+ from pathlib import Path
57
+ from typing import Any, Dict, List, Optional
58
+
59
+ # ---------------------------------------------------------------------------
60
+ # Path setup — inherit from wicked-garden local root layout
61
+ # ---------------------------------------------------------------------------
62
+
63
+ _SCRIPTS_ROOT = Path(__file__).resolve().parents[1]
64
+ if str(_SCRIPTS_ROOT) not in sys.path:
65
+ sys.path.insert(0, str(_SCRIPTS_ROOT))
66
+
67
+ # SCHEMA_VERSION intentionally remains at "1" through v8.3.x — see #667.
68
+ # PR #663 renamed sample_window.task_files_scanned -> tasks_observed, but the
69
+ # deprecated alias (also written into timeline.jsonl) preserves wire compat for
70
+ # any consumer reading the old field name. Because the change is non-breaking
71
+ # from a consumer's perspective, the schema version is held at "1" rather than
72
+ # bumped to "1.1". Drop the alias (and bump the version) only when the old
73
+ # field name is removed entirely.
74
+ SCHEMA_VERSION = "1"
75
+ # Per-session capture worst-case budget. We bail out rather than block session-end.
76
+ _CAPTURE_BUDGET_SECONDS = 0.5
77
+ _MAX_SCENARIO_SCAN = 500 # PR #730: bound DomainStore iteration in scenario extractor
78
+ # Max tasks to scan in one capture. Covers any realistic session.
79
+ _MAX_TASKS_SCAN = 500
80
+ # Minimum total verdicts before gate_pass_rate is considered meaningful.
81
+ _MIN_VERDICTS_FOR_RATE = 1
82
+
83
+
84
+ def _utc_now_iso() -> str:
85
+ return datetime.now(timezone.utc).isoformat().replace("+00:00", "Z")
86
+
87
+
88
+ def _sanitize(s: str) -> str:
89
+ return str(s).replace("/", "_").replace("\\", "_").replace("..", "_")
90
+
91
+
92
+ def _timeline_path(project: str) -> Path:
93
+ """Resolve the per-project timeline.jsonl path.
94
+
95
+ Uses get_local_file so the project-scoped root from _paths.py applies.
96
+ Falls back to a home-relative path if _paths is unavailable.
97
+ """
98
+ safe_project = _sanitize(project) if project else "_global"
99
+ try:
100
+ from _paths import get_local_file
101
+ return get_local_file("metrics", safe_project, "timeline.jsonl")
102
+ except Exception:
103
+ fallback = (
104
+ Path.home() / ".something-wicked" / "wicked-garden" / "local"
105
+ / "metrics" / safe_project / "timeline.jsonl"
106
+ )
107
+ fallback.parent.mkdir(parents=True, exist_ok=True)
108
+ return fallback
109
+
110
+
111
+ # ---------------------------------------------------------------------------
112
+ # Native task scanning — pure read, no mutations
113
+ # ---------------------------------------------------------------------------
114
+
115
+ def _native_tasks_dir(session_id: str) -> Path:
116
+ """Return the native-tasks dir for the given session. Never raises."""
117
+ config_dir = os.environ.get("CLAUDE_CONFIG_DIR")
118
+ if config_dir:
119
+ base = Path(config_dir)
120
+ else:
121
+ base = Path.home() / ".claude"
122
+ return base / "tasks" / _sanitize(session_id)
123
+
124
+
125
+ def _iter_task_files(session_id: str, deadline: float) -> List[Path]:
126
+ """List task JSON files for the session, bounded by _MAX_TASKS_SCAN + deadline."""
127
+ tdir = _native_tasks_dir(session_id)
128
+ if not tdir.exists():
129
+ return []
130
+ out: List[Path] = []
131
+ try:
132
+ for p in sorted(tdir.glob("*.json")):
133
+ if time.monotonic() > deadline:
134
+ break
135
+ out.append(p)
136
+ if len(out) >= _MAX_TASKS_SCAN:
137
+ break
138
+ except OSError:
139
+ return []
140
+ return out
141
+
142
+
143
+ def _read_task(path: Path) -> Optional[Dict[str, Any]]:
144
+ try:
145
+ return json.loads(path.read_text(encoding="utf-8"))
146
+ except (OSError, json.JSONDecodeError):
147
+ return None
148
+
149
+
150
+ def _parse_iso(ts: Any) -> Optional[float]:
151
+ if not isinstance(ts, str) or not ts:
152
+ return None
153
+ try:
154
+ s = ts.replace("Z", "+00:00")
155
+ return datetime.fromisoformat(s).timestamp()
156
+ except (ValueError, TypeError):
157
+ return None
158
+
159
+
160
+ # ---------------------------------------------------------------------------
161
+ # Metric extraction
162
+ # ---------------------------------------------------------------------------
163
+
164
+ def _extract_metrics_from_tasks(
165
+ tasks: List[Dict[str, Any]],
166
+ ) -> Dict[str, Any]:
167
+ """Extract quality metrics from the session's native task records.
168
+
169
+ Looks at metadata.event_type == 'gate-finding' for verdict + score,
170
+ and at task status for completion counts. Phase-transition events
171
+ contribute cycle-time samples.
172
+ """
173
+ approve = 0
174
+ conditional = 0
175
+ reject = 0
176
+ scores: List[float] = []
177
+ task_count = 0
178
+ task_completed = 0
179
+ phase_started: Dict[str, float] = {}
180
+ cycle_time_by_phase: Dict[str, float] = {}
181
+
182
+ # Per-(phase, tier) verdict + score breakdown — issue #719 ACs need
183
+ # `{phase}.{tier}.min_score` and verdict ratios per gate. Stored as a
184
+ # nested dict keyed by ``f"{phase}.{tier}"`` for stable JSON addressing.
185
+ gate_breakdown: Dict[str, Dict[str, Any]] = {}
186
+
187
+ for t in tasks:
188
+ if not isinstance(t, dict):
189
+ continue
190
+ task_count += 1
191
+ status = t.get("status")
192
+ if status == "completed":
193
+ task_completed += 1
194
+
195
+ meta = t.get("metadata") or {}
196
+ if not isinstance(meta, dict):
197
+ continue
198
+ et = meta.get("event_type")
199
+
200
+ if et == "gate-finding":
201
+ verdict = str(meta.get("verdict", "")).upper()
202
+ if verdict == "APPROVE":
203
+ approve += 1
204
+ elif verdict == "CONDITIONAL":
205
+ conditional += 1
206
+ elif verdict == "REJECT":
207
+ reject += 1
208
+ score = meta.get("score")
209
+ if isinstance(score, (int, float)):
210
+ scores.append(float(score))
211
+
212
+ # Per phase × tier rollup. Tier defaults to "standard" when the
213
+ # gate-finding event doesn't carry an explicit rigor tag — most
214
+ # phase events do, but legacy fallbacks may not.
215
+ phase_name = meta.get("phase") or "unknown"
216
+ tier = (meta.get("rigor_tier") or meta.get("tier") or "standard")
217
+ key = f"{phase_name}.{tier}"
218
+ slot = gate_breakdown.setdefault(key, {
219
+ "phase": phase_name,
220
+ "tier": tier,
221
+ "approve": 0,
222
+ "conditional": 0,
223
+ "reject": 0,
224
+ "scores": [],
225
+ "min_score": None,
226
+ })
227
+ if verdict == "APPROVE":
228
+ slot["approve"] += 1
229
+ elif verdict == "CONDITIONAL":
230
+ slot["conditional"] += 1
231
+ elif verdict == "REJECT":
232
+ slot["reject"] += 1
233
+ if isinstance(score, (int, float)):
234
+ slot["scores"].append(float(score))
235
+ cur_min = slot["min_score"]
236
+ slot["min_score"] = float(score) if cur_min is None else min(cur_min, float(score))
237
+
238
+ elif et == "phase-transition":
239
+ phase = meta.get("phase") or meta.get("from_phase")
240
+ ts_end = _parse_iso(t.get("updated_at") or t.get("created_at"))
241
+ if phase and ts_end is not None:
242
+ start = phase_started.get(phase)
243
+ if start is not None and ts_end >= start:
244
+ cycle_time_by_phase[phase] = round(ts_end - start, 3)
245
+ # Any transition on the phase resets its start anchor.
246
+ phase_started[phase] = ts_end
247
+
248
+ # Finalize per-gate avg scores (kept alongside min for SPC of mean lines).
249
+ for slot in gate_breakdown.values():
250
+ scores_list = slot.pop("scores", [])
251
+ slot["avg_score"] = round(sum(scores_list) / len(scores_list), 4) if scores_list else None
252
+ total = slot["approve"] + slot["conditional"] + slot["reject"]
253
+ slot["total"] = total
254
+ slot["reject_rate"] = round(slot["reject"] / total, 4) if total else None
255
+
256
+ total_verdicts = approve + conditional + reject
257
+ if total_verdicts >= _MIN_VERDICTS_FOR_RATE:
258
+ # CONDITIONAL counts as partial pass: weight 0.5 so CONDITIONAL-heavy
259
+ # sessions don't mask real degradation but also aren't full failures.
260
+ pass_rate = (approve + 0.5 * conditional) / total_verdicts
261
+ else:
262
+ pass_rate = None
263
+
264
+ avg_score = round(sum(scores) / len(scores), 4) if scores else None
265
+
266
+ return {
267
+ "gate_pass_rate": pass_rate,
268
+ "gate_avg_score": avg_score,
269
+ "gate_verdict_count": total_verdicts,
270
+ "gate_rework_count": reject,
271
+ "rework_events": reject,
272
+ "task_count": task_count,
273
+ "task_completed": task_completed,
274
+ "cycle_time_by_phase": cycle_time_by_phase,
275
+ # Issue #719: nested per-(phase, tier) rollups for SPC drift.
276
+ "gate_breakdown": gate_breakdown,
277
+ }
278
+
279
+
280
+ def _extract_convergence_metrics(
281
+ project: Optional[str],
282
+ deadline: Optional[float] = None,
283
+ ) -> Dict[str, Any]:
284
+ """Read crew convergence stalls for the active project.
285
+
286
+ Returns counts of stalled artifacts (sessions_in_state >= threshold) and
287
+ the count of recorded transitions in the most recent log scan. Fail-open:
288
+ any failure → all-zero metrics. Honors capture deadline (PR #730 review):
289
+ if budget already exhausted on entry, returns zeros without doing any work.
290
+ """
291
+ out = {"convergence_stalls": 0, "convergence_artifacts": 0}
292
+ if not project or project == "_global":
293
+ return out
294
+ if deadline is not None and time.monotonic() > deadline:
295
+ return out # over budget — skip rather than block the hook
296
+ try:
297
+ # `_SCRIPTS_ROOT` is already on sys.path at module-load (lines 63-65).
298
+ # No per-call insert needed — flagged in gemini's PR #730 review.
299
+ from crew import convergence # type: ignore
300
+ # convergence APIs take a project *directory*, not the slug. Resolve
301
+ # via the same helper its CLI uses so we honor _paths.
302
+ project_dir = convergence._resolve_project_dir(project)
303
+ stalls = convergence.detect_stalls(project_dir) or []
304
+ status = convergence.project_status(project_dir) or {}
305
+ out["convergence_stalls"] = len(stalls)
306
+ out["convergence_artifacts"] = int(status.get("total") or 0)
307
+ except Exception:
308
+ pass
309
+ return out
310
+
311
+
312
+ def _extract_scenario_metrics(
313
+ project: Optional[str],
314
+ deadline: Optional[float] = None,
315
+ since_iso: Optional[str] = None,
316
+ ) -> Dict[str, Any]:
317
+ """Read PER-SESSION scenario verdict counts for the active project.
318
+
319
+ Counts only verdicts whose recorded timestamp is later than ``since_iso``
320
+ (the previous session's recorded_at). This produces session-delta counts
321
+ suitable for ratio drift detection — Copilot flagged the prior cumulative
322
+ behavior in PR #730 as semantically wrong (lifetime cumulative counts can
323
+ only grow, so per-session ratios cannot drift).
324
+
325
+ Honors ``deadline``: if budget exhausted on entry, returns zeros. Caps the
326
+ iteration at _MAX_SCENARIO_SCAN to bound the worst-case scan even when no
327
+ deadline is provided.
328
+
329
+ Falls back to all-zero output when wicked-testing is not installed.
330
+ """
331
+ out = {"scenario_pass": 0, "scenario_partial": 0, "scenario_fail": 0}
332
+ if not project or project == "_global":
333
+ return out
334
+ if deadline is not None and time.monotonic() > deadline:
335
+ return out
336
+ try:
337
+ from _domain_store import DomainStore # type: ignore
338
+ ds = DomainStore("wicked-testing", hook_mode=True)
339
+ scanned = 0
340
+ for source in ("verdicts", "runs", "scenarios"):
341
+ if deadline is not None and time.monotonic() > deadline:
342
+ break
343
+ try:
344
+ rows = ds.list(source, project=project) or []
345
+ except Exception:
346
+ rows = []
347
+ for row in rows:
348
+ scanned += 1
349
+ if scanned > _MAX_SCENARIO_SCAN:
350
+ break
351
+ # Only count verdicts after the previous session's capture.
352
+ # Records older than `since_iso` (or all rows on the first ever
353
+ # capture, where since_iso is None) are excluded so each
354
+ # session emits its own delta, not the running total.
355
+ if since_iso:
356
+ rec_ts = str(row.get("recorded_at") or row.get("created_at") or "")
357
+ if rec_ts and rec_ts <= since_iso:
358
+ continue
359
+ v = str(row.get("verdict") or row.get("result") or "").upper()
360
+ if v == "PASS":
361
+ out["scenario_pass"] += 1
362
+ elif v in ("PARTIAL", "WARN"):
363
+ out["scenario_partial"] += 1
364
+ elif v in ("FAIL", "ERROR"):
365
+ out["scenario_fail"] += 1
366
+ if any(out.values()) and scanned <= _MAX_SCENARIO_SCAN:
367
+ break # first source that yielded data wins
368
+ except Exception:
369
+ pass
370
+ return out
371
+
372
+
373
+ def _extract_session_extras() -> Dict[str, Any]:
374
+ """Read session-level counters (skip_reeval, complexity delta)."""
375
+ skip_reeval_count = 0
376
+ complexity_open: Optional[int] = None
377
+ complexity_close: Optional[int] = None
378
+ active_project: Optional[str] = None
379
+ try:
380
+ from _session import SessionState
381
+ state = SessionState.load()
382
+ # These fields are optional — gracefully absent on older sessions.
383
+ raw_skip = getattr(state, "skip_reeval_count", None)
384
+ if isinstance(raw_skip, int):
385
+ skip_reeval_count = raw_skip
386
+ complexity_open = getattr(state, "complexity_at_session_open", None)
387
+ complexity_close = getattr(state, "complexity_score", None)
388
+ active_project = getattr(state, "active_project", None)
389
+ except Exception:
390
+ pass # fail open — session state unavailable is not fatal for telemetry
391
+
392
+ complexity_delta = 0
393
+ if isinstance(complexity_open, int) and isinstance(complexity_close, int):
394
+ complexity_delta = complexity_close - complexity_open
395
+
396
+ return {
397
+ "skip_reeval_count": skip_reeval_count,
398
+ "complexity_delta": complexity_delta,
399
+ "active_project": active_project,
400
+ }
401
+
402
+
403
+ # ---------------------------------------------------------------------------
404
+ # Public entry points
405
+ # ---------------------------------------------------------------------------
406
+
407
+ def capture_session(
408
+ session_id: str,
409
+ project: Optional[str] = None,
410
+ ) -> Optional[Dict[str, Any]]:
411
+ """Capture telemetry for a session-close and append to the timeline.
412
+
413
+ Returns the appended record dict on success, or None on any failure.
414
+ Never raises. Honors _CAPTURE_BUDGET_SECONDS so hook callers stay fast.
415
+ """
416
+ try:
417
+ t0 = time.monotonic()
418
+ deadline = t0 + _CAPTURE_BUDGET_SECONDS
419
+
420
+ extras = _extract_session_extras()
421
+ raw_project = project or extras.get("active_project") or "_global"
422
+ resolved_project = _sanitize(raw_project)
423
+
424
+ # Task reading routed via _task_reader (#596 v8-PR-2).
425
+ # WG_DAEMON_ENABLED=false → direct file scan (unchanged behaviour).
426
+ tasks: List[Dict[str, Any]] = []
427
+ # task_files: initialised before the try-block so the direct-scan fallback
428
+ # path populates it. The happy-path (daemon-routed read_session_tasks)
429
+ # leaves task_files empty but tasks populated; sample_window now uses
430
+ # len(tasks) (tasks_observed) rather than len(task_files) so the metric
431
+ # is accurate for both paths (issues #647, #660).
432
+ task_files: List[Path] = []
433
+ try:
434
+ _scripts_root = str(Path(__file__).resolve().parents[1])
435
+ import sys as _sys
436
+ if _scripts_root not in _sys.path:
437
+ _sys.path.insert(0, _scripts_root)
438
+ from crew._task_reader import read_session_tasks # type: ignore[import]
439
+ tasks = read_session_tasks(session_id, limit=_MAX_TASKS_SCAN)
440
+ except Exception:
441
+ # Fallback: direct file read (pre-PR-2 path, always available).
442
+ task_files = _iter_task_files(session_id, deadline)
443
+ for p in task_files:
444
+ if time.monotonic() > deadline:
445
+ break
446
+ t = _read_task(p)
447
+ if t is not None:
448
+ tasks.append(t)
449
+
450
+ metrics = _extract_metrics_from_tasks(tasks)
451
+ metrics["skip_reeval_count"] = extras["skip_reeval_count"]
452
+ metrics["complexity_delta"] = extras["complexity_delta"]
453
+ # Issue #719: convergence + scenario rollups join the per-session metric
454
+ # bag. Fail-open on both — empty zeros are better than dropped records.
455
+ # PR #730 review: pass `deadline` so these helpers respect the same
456
+ # _CAPTURE_BUDGET_SECONDS guardrail the task scanner honors.
457
+ # Scenario extractor also gets the previous session's recorded_at as
458
+ # `since_iso` so it counts session deltas, not lifetime cumulative.
459
+ prev_recorded_at: Optional[str] = None
460
+ try:
461
+ prior = read_timeline(resolved_project, limit=1)
462
+ if prior:
463
+ prev_recorded_at = prior[-1].get("recorded_at")
464
+ except Exception:
465
+ pass
466
+ metrics.update(_extract_convergence_metrics(raw_project, deadline=deadline))
467
+ metrics.update(_extract_scenario_metrics(raw_project, deadline=deadline, since_iso=prev_recorded_at))
468
+
469
+ # Build sample window from the first/last task timestamps observed.
470
+ first_ts: Optional[str] = None
471
+ last_ts: Optional[str] = None
472
+ for t in tasks:
473
+ c = t.get("created_at")
474
+ u = t.get("updated_at") or c
475
+ if isinstance(c, str):
476
+ first_ts = c if first_ts is None or c < first_ts else first_ts
477
+ if isinstance(u, str):
478
+ last_ts = u if last_ts is None or u > last_ts else last_ts
479
+
480
+ record = {
481
+ "version": SCHEMA_VERSION,
482
+ "session_id": _sanitize(session_id),
483
+ "project": resolved_project,
484
+ "recorded_at": _utc_now_iso(),
485
+ "sample_window": {
486
+ "first_observation": first_ts,
487
+ "last_observation": last_ts,
488
+ # tasks_observed counts tasks from whichever path ran (#660):
489
+ # daemon-routed happy path (len(tasks)) or direct file scan
490
+ # (also len(tasks) after tasks are populated from task_files).
491
+ # Previously used len(task_files) which was always 0 on the
492
+ # happy path, making the metric meaningless for daemon-routed
493
+ # sessions. Renamed from task_files_scanned for clarity.
494
+ "tasks_observed": len(tasks),
495
+ # Deprecated alias — emitted for one release (v8.3.x) so
496
+ # downstream consumers (dashboards, alerting rules) keyed on
497
+ # the old name stay green. Remove in v8.4.0. See PR #663
498
+ # council and CHANGELOG.
499
+ "task_files_scanned": len(tasks),
500
+ },
501
+ "metrics": metrics,
502
+ }
503
+
504
+ _append_record(resolved_project, record)
505
+ return record
506
+ except Exception as exc:
507
+ # Never break session teardown.
508
+ print(f"[wicked-garden] telemetry capture error: {exc}", file=sys.stderr)
509
+ return None
510
+
511
+
512
+ def _append_record(project: str, record: Dict[str, Any]) -> None:
513
+ """Append a JSON record as a single JSONL line. Parent dirs auto-created."""
514
+ path = _timeline_path(project)
515
+ path.parent.mkdir(parents=True, exist_ok=True)
516
+ # Use a single line — no embedded newlines in JSON default encoding.
517
+ line = json.dumps(record, separators=(",", ":"), ensure_ascii=False)
518
+ with path.open("a", encoding="utf-8") as fh:
519
+ fh.write(line + "\n")
520
+
521
+
522
+ def read_timeline(project: str, *, limit: Optional[int] = None) -> List[Dict[str, Any]]:
523
+ """Return the decoded records for a project's timeline.
524
+
525
+ Most-recent-last ordering matches append order. Corrupt lines are skipped
526
+ rather than raising — drift analysis is best-effort.
527
+ """
528
+ path = _timeline_path(project)
529
+ if not path.exists():
530
+ return []
531
+ out: List[Dict[str, Any]] = []
532
+ try:
533
+ with path.open("r", encoding="utf-8") as fh:
534
+ for line in fh:
535
+ line = line.strip()
536
+ if not line:
537
+ continue
538
+ try:
539
+ out.append(json.loads(line))
540
+ except json.JSONDecodeError:
541
+ continue
542
+ except OSError:
543
+ return []
544
+ if limit is not None and limit > 0:
545
+ out = out[-limit:]
546
+ return out
547
+
548
+
549
+ def timeline_path_for(project: str) -> str:
550
+ """String path helper for commands that need to surface the location."""
551
+ return str(_timeline_path(project))
552
+
553
+
554
+ # ---------------------------------------------------------------------------
555
+ # CLI entry — used by hook + status command
556
+ # ---------------------------------------------------------------------------
557
+
558
+ def _cli_capture(args: List[str]) -> int:
559
+ session_id = args[0] if args else os.environ.get("CLAUDE_SESSION_ID", "default")
560
+ project = args[1] if len(args) > 1 else None
561
+ rec = capture_session(session_id, project)
562
+ if rec is None:
563
+ print(json.dumps({"ok": False, "reason": "capture returned None"}))
564
+ return 0 # fail-open
565
+ print(json.dumps({"ok": True, "record": rec}))
566
+ return 0
567
+
568
+
569
+ def _cli_show(args: List[str]) -> int:
570
+ if not args:
571
+ print(json.dumps({"ok": False, "reason": "project required"}))
572
+ return 0
573
+ project = args[0]
574
+ limit = None
575
+ if len(args) > 1:
576
+ try:
577
+ limit = int(args[1])
578
+ except ValueError:
579
+ limit = None
580
+ records = read_timeline(project, limit=limit)
581
+ print(json.dumps({"ok": True, "project": project, "records": records,
582
+ "path": timeline_path_for(project)}))
583
+ return 0
584
+
585
+
586
+ def main(argv: Optional[List[str]] = None) -> int:
587
+ argv = list(argv if argv is not None else sys.argv[1:])
588
+ if not argv or argv[0] in ("-h", "--help", "help"):
589
+ print(
590
+ "Usage:\n"
591
+ " telemetry.py capture [session_id] [project]\n"
592
+ " telemetry.py show <project> [limit]\n"
593
+ " telemetry.py path <project>\n",
594
+ file=sys.stderr,
595
+ )
596
+ return 0
597
+ cmd = argv[0]
598
+ rest = argv[1:]
599
+ if cmd == "capture":
600
+ return _cli_capture(rest)
601
+ if cmd == "show":
602
+ return _cli_show(rest)
603
+ if cmd == "path":
604
+ if not rest:
605
+ print(json.dumps({"ok": False, "reason": "project required"}))
606
+ return 0
607
+ print(timeline_path_for(rest[0]))
608
+ return 0
609
+ print(json.dumps({"ok": False, "reason": f"unknown command: {cmd}"}))
610
+ return 0
611
+
612
+
613
+ if __name__ == "__main__":
614
+ sys.exit(main())