@soleur/opencode 0.0.0-stage → 3.354.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (832) hide show
  1. package/.claude-plugin/agents.manifest.json +476 -0
  2. package/.claude-plugin/plugin.json +42 -0
  3. package/README.md +44 -2
  4. package/agents/community/.gitkeep +0 -0
  5. package/agents/engineering/cto.md +87 -0
  6. package/agents/engineering/design/ddd-architect.md +95 -0
  7. package/agents/engineering/discovery/agent-finder.md +214 -0
  8. package/agents/engineering/discovery/functional-discovery.md +182 -0
  9. package/agents/engineering/infra/infra-security.md +151 -0
  10. package/agents/engineering/infra/platform-strategist.md +109 -0
  11. package/agents/engineering/infra/terraform-architect.md +171 -0
  12. package/agents/engineering/prompt-engineer.md +37 -0
  13. package/agents/engineering/research/best-practices-researcher.md +115 -0
  14. package/agents/engineering/research/framework-docs-researcher.md +93 -0
  15. package/agents/engineering/research/git-history-analyzer.md +53 -0
  16. package/agents/engineering/research/learnings-researcher.md +285 -0
  17. package/agents/engineering/research/repo-research-analyst.md +118 -0
  18. package/agents/engineering/review/agent-native-reviewer.md +279 -0
  19. package/agents/engineering/review/architecture-strategist.md +61 -0
  20. package/agents/engineering/review/code-quality-analyst.md +92 -0
  21. package/agents/engineering/review/code-simplicity-reviewer.md +109 -0
  22. package/agents/engineering/review/data-integrity-guardian.md +82 -0
  23. package/agents/engineering/review/data-migration-expert.md +98 -0
  24. package/agents/engineering/review/deployment-verification-agent.md +183 -0
  25. package/agents/engineering/review/dhh-rails-reviewer.md +46 -0
  26. package/agents/engineering/review/kieran-rails-reviewer.md +87 -0
  27. package/agents/engineering/review/legacy-code-expert.md +55 -0
  28. package/agents/engineering/review/observability-coverage-reviewer.md +147 -0
  29. package/agents/engineering/review/pattern-recognition-specialist.md +59 -0
  30. package/agents/engineering/review/performance-oracle.md +130 -0
  31. package/agents/engineering/review/security-sentinel.md +167 -0
  32. package/agents/engineering/review/semgrep-sast.md +36 -0
  33. package/agents/engineering/review/test-design-reviewer.md +150 -0
  34. package/agents/engineering/review/user-impact-reviewer.md +70 -0
  35. package/agents/engineering/workflow/pr-comment-resolver.md +69 -0
  36. package/agents/finance/budget-analyst.md +29 -0
  37. package/agents/finance/cfo.md +44 -0
  38. package/agents/finance/financial-reporter.md +30 -0
  39. package/agents/finance/revenue-analyst.md +30 -0
  40. package/agents/legal/clo.md +115 -0
  41. package/agents/legal/legal-compliance-auditor.md +110 -0
  42. package/agents/legal/legal-document-generator.md +134 -0
  43. package/agents/marketing/analytics-analyst.md +25 -0
  44. package/agents/marketing/brand-architect.md +181 -0
  45. package/agents/marketing/cmo.md +76 -0
  46. package/agents/marketing/conversion-optimizer.md +19 -0
  47. package/agents/marketing/copywriter.md +20 -0
  48. package/agents/marketing/fact-checker.md +70 -0
  49. package/agents/marketing/growth-strategist.md +145 -0
  50. package/agents/marketing/paid-media-strategist.md +28 -0
  51. package/agents/marketing/pricing-strategist.md +17 -0
  52. package/agents/marketing/programmatic-seo-specialist.md +25 -0
  53. package/agents/marketing/retention-strategist.md +23 -0
  54. package/agents/marketing/seo-aeo-analyst.md +164 -0
  55. package/agents/operations/coo.md +50 -0
  56. package/agents/operations/ops-advisor.md +78 -0
  57. package/agents/operations/ops-provisioner.md +101 -0
  58. package/agents/operations/ops-research.md +52 -0
  59. package/agents/operations/service-automator.md +278 -0
  60. package/agents/product/business-validator.md +206 -0
  61. package/agents/product/competitive-intelligence.md +89 -0
  62. package/agents/product/cpo.md +63 -0
  63. package/agents/product/design/ux-design-lead.md +209 -0
  64. package/agents/product/spec-flow-analyzer.md +122 -0
  65. package/agents/sales/cro.md +44 -0
  66. package/agents/sales/deal-architect.md +29 -0
  67. package/agents/sales/outbound-strategist.md +29 -0
  68. package/agents/sales/pipeline-analyst.md +29 -0
  69. package/agents/support/cco.md +48 -0
  70. package/agents/support/community-manager.md +570 -0
  71. package/agents/support/ticket-triage.md +70 -0
  72. package/bin/soleur-opencode.js +29 -0
  73. package/commands/go.md +660 -0
  74. package/commands/help.md +273 -0
  75. package/commands/sync.md +977 -0
  76. package/commands/version.md +103 -0
  77. package/hooks/antigravity-hooks.json +84 -0
  78. package/hooks/antigravity-session-start.sh +15 -0
  79. package/hooks/bare-root-cwd-guard.sh +131 -0
  80. package/hooks/browser-snapshot-credential-guard.sh +200 -0
  81. package/hooks/codex-session-start.sh +9 -0
  82. package/hooks/compaction-state.sh +525 -0
  83. package/hooks/destructive-command-guard.sh +1387 -0
  84. package/hooks/devin-session-start.sh +90 -0
  85. package/hooks/ext-filter-detect.sh +171 -0
  86. package/hooks/hooks.json +133 -0
  87. package/hooks/lib/hook-tool-kind.sh +24 -0
  88. package/hooks/lib/log-rotation.sh +176 -0
  89. package/hooks/lib/shell-argv.pl +576 -0
  90. package/hooks/memory-backstop.sh +1114 -0
  91. package/hooks/operator-stage-approval.sh +391 -0
  92. package/hooks/stop-hook.sh +367 -0
  93. package/hooks/unkept-promise-hook.sh +383 -0
  94. package/hooks/version-banner.sh +127 -0
  95. package/hooks/welcome-hook.sh +50 -0
  96. package/install.js +29 -0
  97. package/lib/agent-registry.ts +154 -0
  98. package/lib/c4-canonical-cli.mjs +34 -0
  99. package/lib/c4-canonical.mjs +46 -0
  100. package/lib/c4-from-components.ts +554 -0
  101. package/lib/go-routing.ts +81 -0
  102. package/lib/grok-inspect-contract.ts +311 -0
  103. package/lib/harness-model-map.ts +101 -0
  104. package/lib/harness-parity.ts +726 -0
  105. package/lib/harness-tool-map.ts +180 -0
  106. package/lib/harness.ts +716 -0
  107. package/lib/heartbeat-live-reconcile.ts +1153 -0
  108. package/lib/heartbeat-manifest.ts +361 -0
  109. package/lib/kb-coverage.ts +252 -0
  110. package/lib/pr-merge-poll.ts +103 -0
  111. package/lib/workflow-fidelity.ts +388 -0
  112. package/opencode/INSTRUCTIONS.md +171 -0
  113. package/opencode/agents/engineering/cto.md +10 -0
  114. package/opencode/agents/engineering/design/ddd-architect.md +10 -0
  115. package/opencode/agents/engineering/discovery/agent-finder.md +10 -0
  116. package/opencode/agents/engineering/discovery/functional-discovery.md +10 -0
  117. package/opencode/agents/engineering/infra/infra-security.md +10 -0
  118. package/opencode/agents/engineering/infra/platform-strategist.md +10 -0
  119. package/opencode/agents/engineering/infra/terraform-architect.md +10 -0
  120. package/opencode/agents/engineering/prompt-engineer.md +10 -0
  121. package/opencode/agents/engineering/research/best-practices-researcher.md +10 -0
  122. package/opencode/agents/engineering/research/framework-docs-researcher.md +10 -0
  123. package/opencode/agents/engineering/research/git-history-analyzer.md +10 -0
  124. package/opencode/agents/engineering/research/learnings-researcher.md +10 -0
  125. package/opencode/agents/engineering/research/repo-research-analyst.md +10 -0
  126. package/opencode/agents/engineering/review/agent-native-reviewer.md +10 -0
  127. package/opencode/agents/engineering/review/architecture-strategist.md +10 -0
  128. package/opencode/agents/engineering/review/code-quality-analyst.md +10 -0
  129. package/opencode/agents/engineering/review/code-simplicity-reviewer.md +10 -0
  130. package/opencode/agents/engineering/review/data-integrity-guardian.md +10 -0
  131. package/opencode/agents/engineering/review/data-migration-expert.md +10 -0
  132. package/opencode/agents/engineering/review/deployment-verification-agent.md +10 -0
  133. package/opencode/agents/engineering/review/dhh-rails-reviewer.md +10 -0
  134. package/opencode/agents/engineering/review/kieran-rails-reviewer.md +10 -0
  135. package/opencode/agents/engineering/review/legacy-code-expert.md +10 -0
  136. package/opencode/agents/engineering/review/observability-coverage-reviewer.md +10 -0
  137. package/opencode/agents/engineering/review/pattern-recognition-specialist.md +10 -0
  138. package/opencode/agents/engineering/review/performance-oracle.md +10 -0
  139. package/opencode/agents/engineering/review/security-sentinel.md +10 -0
  140. package/opencode/agents/engineering/review/semgrep-sast.md +10 -0
  141. package/opencode/agents/engineering/review/test-design-reviewer.md +10 -0
  142. package/opencode/agents/engineering/review/user-impact-reviewer.md +10 -0
  143. package/opencode/agents/engineering/workflow/pr-comment-resolver.md +10 -0
  144. package/opencode/agents/finance/budget-analyst.md +10 -0
  145. package/opencode/agents/finance/cfo.md +10 -0
  146. package/opencode/agents/finance/financial-reporter.md +10 -0
  147. package/opencode/agents/finance/revenue-analyst.md +10 -0
  148. package/opencode/agents/legal/clo.md +10 -0
  149. package/opencode/agents/legal/legal-compliance-auditor.md +10 -0
  150. package/opencode/agents/legal/legal-document-generator.md +10 -0
  151. package/opencode/agents/marketing/analytics-analyst.md +10 -0
  152. package/opencode/agents/marketing/brand-architect.md +10 -0
  153. package/opencode/agents/marketing/cmo.md +10 -0
  154. package/opencode/agents/marketing/conversion-optimizer.md +10 -0
  155. package/opencode/agents/marketing/copywriter.md +10 -0
  156. package/opencode/agents/marketing/fact-checker.md +10 -0
  157. package/opencode/agents/marketing/growth-strategist.md +10 -0
  158. package/opencode/agents/marketing/paid-media-strategist.md +10 -0
  159. package/opencode/agents/marketing/pricing-strategist.md +10 -0
  160. package/opencode/agents/marketing/programmatic-seo-specialist.md +10 -0
  161. package/opencode/agents/marketing/retention-strategist.md +10 -0
  162. package/opencode/agents/marketing/seo-aeo-analyst.md +10 -0
  163. package/opencode/agents/operations/coo.md +10 -0
  164. package/opencode/agents/operations/ops-advisor.md +10 -0
  165. package/opencode/agents/operations/ops-provisioner.md +10 -0
  166. package/opencode/agents/operations/ops-research.md +10 -0
  167. package/opencode/agents/operations/service-automator.md +10 -0
  168. package/opencode/agents/product/business-validator.md +10 -0
  169. package/opencode/agents/product/competitive-intelligence.md +10 -0
  170. package/opencode/agents/product/cpo.md +10 -0
  171. package/opencode/agents/product/design/ux-design-lead.md +10 -0
  172. package/opencode/agents/product/spec-flow-analyzer.md +10 -0
  173. package/opencode/agents/sales/cro.md +10 -0
  174. package/opencode/agents/sales/deal-architect.md +10 -0
  175. package/opencode/agents/sales/outbound-strategist.md +10 -0
  176. package/opencode/agents/sales/pipeline-analyst.md +10 -0
  177. package/opencode/agents/support/cco.md +10 -0
  178. package/opencode/agents/support/community-manager.md +10 -0
  179. package/opencode/agents/support/ticket-triage.md +10 -0
  180. package/opencode/commands/go.md +10 -0
  181. package/opencode/commands/help.md +10 -0
  182. package/opencode/commands/sync.md +10 -0
  183. package/opencode/commands/version.md +11 -0
  184. package/opencode/opencode.json +8 -0
  185. package/opencode/plugin.ts +818 -0
  186. package/package.json +36 -4
  187. package/scripts/admin-merge-ready.sh +545 -0
  188. package/scripts/admin-merge-ready.test.sh +753 -0
  189. package/scripts/affected-tests.sh +908 -0
  190. package/scripts/affected-tests.test.sh +1797 -0
  191. package/scripts/alpha-metrics.sh +78 -0
  192. package/scripts/alpha-metrics.test.sh +115 -0
  193. package/scripts/ancestor-signal-helpers.baseline.txt +16 -0
  194. package/scripts/audit-flag-flip.sh +107 -0
  195. package/scripts/check-red-on-main.sh +316 -0
  196. package/scripts/ci-head-verdict.sh +411 -0
  197. package/scripts/cloud-detect.sh +193 -0
  198. package/scripts/delegation-verify.sh +657 -0
  199. package/scripts/delegation-verify.test.sh +1424 -0
  200. package/scripts/deploy-arm.sh +475 -0
  201. package/scripts/domain-model-drift.sh +419 -0
  202. package/scripts/emit-decision.sh +144 -0
  203. package/scripts/emit-decision.test.sh +144 -0
  204. package/scripts/ext-filter-divergence-corpus.txt +15 -0
  205. package/scripts/ext-filter-divergence.sh +189 -0
  206. package/scripts/generate-c4-from-components.ts +442 -0
  207. package/scripts/grok-fidelity-gate.sh +68 -0
  208. package/scripts/grok-pre-push-gate.sh +232 -0
  209. package/scripts/harness-discovery-smoke.ts +906 -0
  210. package/scripts/harness-parity-census.ts +92 -0
  211. package/scripts/inngest-luks-alert-armed-probe.ts +29 -0
  212. package/scripts/install-opencode-adapter.ts +509 -0
  213. package/scripts/lib/affected-tests/common.sh +365 -0
  214. package/scripts/lib/affected-tests/go.sh +157 -0
  215. package/scripts/lib/affected-tests/js.sh +188 -0
  216. package/scripts/lib/affected-tests/nx-turbo.sh +98 -0
  217. package/scripts/lib/affected-tests/python.sh +185 -0
  218. package/scripts/lib/context-sanitize.sh +49 -0
  219. package/scripts/lib/domain-model-lib.sh +180 -0
  220. package/scripts/lib/ext-filter-grammar.tsv +34 -0
  221. package/scripts/lib/operator-script.sh +1236 -0
  222. package/scripts/lib/proc.sh +580 -0
  223. package/scripts/lib/session-state.sh +748 -0
  224. package/scripts/lib/tmp-classify.sh +843 -0
  225. package/scripts/lib/wrapper-boundary.sh +47 -0
  226. package/scripts/lint-ratchet.py +1547 -0
  227. package/scripts/monitor-pr-checks.sh +441 -0
  228. package/scripts/pipeline-tally.sh +756 -0
  229. package/scripts/pipeline-tally.test.sh +740 -0
  230. package/scripts/plugin-version.sh +528 -0
  231. package/scripts/precommit-guard.sh +115 -0
  232. package/scripts/precommit-guard.test.sh +254 -0
  233. package/scripts/reconcile-live-heartbeats.ts +705 -0
  234. package/scripts/render-c4-model.sh +217 -0
  235. package/scripts/resolve-git-root.sh +55 -0
  236. package/scripts/resolve-regenerable-conflicts.sh +363 -0
  237. package/scripts/resolve-regenerable-conflicts.test.sh +780 -0
  238. package/scripts/ruff-requirements.txt +22 -0
  239. package/scripts/run-in-pid-namespace.sh +98 -0
  240. package/scripts/run-in-pid-namespace.test.sh +290 -0
  241. package/scripts/scan-ancestor-signal-helpers.py +556 -0
  242. package/scripts/scan-ancestor-signal-helpers.test.sh +670 -0
  243. package/scripts/setup-ralph-loop.sh +238 -0
  244. package/scripts/sync-cursor-name-map.ts +316 -0
  245. package/scripts/sync-grok-agent-compat.ts +188 -0
  246. package/scripts/sync-npm-package.ts +165 -0
  247. package/scripts/sync-opencode-adapter.ts +498 -0
  248. package/scripts/sync-pr-behind.sh +647 -0
  249. package/scripts/sync-pr-behind.test.sh +252 -0
  250. package/scripts/taste-profile-update.sh +180 -0
  251. package/scripts/taste-profile-update.test.sh +167 -0
  252. package/scripts/write-budget-marker.sh +23 -0
  253. package/scripts/write-kb-coverage.ts +113 -0
  254. package/skills/admin-ip-refresh/SKILL.md +81 -0
  255. package/skills/admin-ip-refresh/references/admin-ip-refresh-procedure.md +201 -0
  256. package/skills/agent-browser/SKILL.md +698 -0
  257. package/skills/agent-browser/scripts/playwright-mcp-profile-slot.sh +304 -0
  258. package/skills/agent-browser/scripts/playwright-mcp-redact-proxy.py +964 -0
  259. package/skills/agent-browser/scripts/redact-a11y-snapshot.py +443 -0
  260. package/skills/agent-browser/test/fixtures/capture-playwright-mcp-fixtures.py +217 -0
  261. package/skills/agent-browser/test/fixtures/fake-passthrough-proxy.py +24 -0
  262. package/skills/agent-browser/test/fixtures/fake-playwright-mcp.py +131 -0
  263. package/skills/agent-browser/test/fixtures/make-proxy-mutant.py +48 -0
  264. package/skills/agent-browser/test/fixtures/odd-shapes/dialog-link-injection.json +10 -0
  265. package/skills/agent-browser/test/fixtures/odd-shapes/empty-content.json +5 -0
  266. package/skills/agent-browser/test/fixtures/odd-shapes/error-and-result.json +4 -0
  267. package/skills/agent-browser/test/fixtures/odd-shapes/error-code-bool.json +6 -0
  268. package/skills/agent-browser/test/fixtures/odd-shapes/error-code-string.json +6 -0
  269. package/skills/agent-browser/test/fixtures/odd-shapes/error-message-tree.json +6 -0
  270. package/skills/agent-browser/test/fixtures/odd-shapes/error-no-data.json +6 -0
  271. package/skills/agent-browser/test/fixtures/odd-shapes/error-string.json +4 -0
  272. package/skills/agent-browser/test/fixtures/odd-shapes/error-with-data.json +9 -0
  273. package/skills/agent-browser/test/fixtures/odd-shapes/evaluate-escaped-object.json +10 -0
  274. package/skills/agent-browser/test/fixtures/odd-shapes/invalid-utf8.json +4 -0
  275. package/skills/agent-browser/test/fixtures/odd-shapes/link-result.json +10 -0
  276. package/skills/agent-browser/test/fixtures/odd-shapes/list-two-results.json +6 -0
  277. package/skills/agent-browser/test/fixtures/odd-shapes/meta-in-result.json +13 -0
  278. package/skills/agent-browser/test/fixtures/odd-shapes/no-content.json +5 -0
  279. package/skills/agent-browser/test/fixtures/odd-shapes/quoted-key.json +10 -0
  280. package/skills/agent-browser/test/fixtures/odd-shapes/resource-block.json +18 -0
  281. package/skills/agent-browser/test/fixtures/odd-shapes/result-and-method.json +11 -0
  282. package/skills/agent-browser/test/fixtures/odd-shapes/result-string.json +3 -0
  283. package/skills/agent-browser/test/fixtures/odd-shapes/run-code-escaped-one-row.json +10 -0
  284. package/skills/agent-browser/test/fixtures/odd-shapes/run-code-escaped.json +10 -0
  285. package/skills/agent-browser/test/fixtures/odd-shapes/structured-content.json +13 -0
  286. package/skills/agent-browser/test/fixtures/odd-shapes/tools-list-no-tools.json +5 -0
  287. package/skills/agent-browser/test/fixtures/odd-shapes/tree-no-credential.json +10 -0
  288. package/skills/agent-browser/test/fixtures/odd-shapes/two-text-blocks.json +14 -0
  289. package/skills/agent-browser/test/fixtures/odd-shapes/unparsable-line.json +3 -0
  290. package/skills/agent-browser/test/fixtures/odd-shapes/value-contains-brace.json +10 -0
  291. package/skills/agent-browser/test/fixtures/odd-shapes/value-contains-link-substring.json +10 -0
  292. package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/close.json +12 -0
  293. package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/evaluate.json +12 -0
  294. package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/find.json +12 -0
  295. package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/framing.json +6 -0
  296. package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/initialize.json +14 -0
  297. package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/navigate-link.json +12 -0
  298. package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/navigate.json +12 -0
  299. package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/roots-list-request.json +5 -0
  300. package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/screenshot.json +17 -0
  301. package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/snapshot-filename.json +12 -0
  302. package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/snapshot-meta-json.json +12 -0
  303. package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/snapshot-meta-raw.json +12 -0
  304. package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/snapshot.json +12 -0
  305. package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/tools-list.json +827 -0
  306. package/skills/agent-browser/test/fixtures/proxy-session-driver.py +138 -0
  307. package/skills/agent-browser/test/fixtures/session-facts.py +102 -0
  308. package/skills/agent-browser/test/playwright-mcp-lifetime.test.sh +1620 -0
  309. package/skills/agent-browser/test/playwright-mcp-redact-proxy.test.sh +1599 -0
  310. package/skills/agent-browser/test/redact-a11y-snapshot.test.sh +527 -0
  311. package/skills/agent-native-architecture/SKILL.md +479 -0
  312. package/skills/agent-native-architecture/references/action-parity-discipline.md +430 -0
  313. package/skills/agent-native-architecture/references/agent-execution-patterns.md +483 -0
  314. package/skills/agent-native-architecture/references/agent-native-testing.md +605 -0
  315. package/skills/agent-native-architecture/references/architecture-patterns.md +493 -0
  316. package/skills/agent-native-architecture/references/dynamic-context-injection.md +358 -0
  317. package/skills/agent-native-architecture/references/files-universal-interface.md +314 -0
  318. package/skills/agent-native-architecture/references/from-primitives-to-domain-tools.md +381 -0
  319. package/skills/agent-native-architecture/references/mcp-tool-design.md +524 -0
  320. package/skills/agent-native-architecture/references/mobile-patterns.md +897 -0
  321. package/skills/agent-native-architecture/references/product-implications.md +478 -0
  322. package/skills/agent-native-architecture/references/refactoring-to-prompt-native.md +342 -0
  323. package/skills/agent-native-architecture/references/self-modification.md +294 -0
  324. package/skills/agent-native-architecture/references/shared-workspace-architecture.md +700 -0
  325. package/skills/agent-native-architecture/references/system-prompt-design.md +263 -0
  326. package/skills/agent-native-audit/SKILL.md +300 -0
  327. package/skills/agent-native-audit/workflows/agent-native-audit.workflow.js +423 -0
  328. package/skills/andrew-kane-gem-writer/SKILL.md +189 -0
  329. package/skills/andrew-kane-gem-writer/references/database-adapters.md +231 -0
  330. package/skills/andrew-kane-gem-writer/references/module-organization.md +121 -0
  331. package/skills/andrew-kane-gem-writer/references/rails-integration.md +183 -0
  332. package/skills/andrew-kane-gem-writer/references/resources.md +126 -0
  333. package/skills/andrew-kane-gem-writer/references/testing-patterns.md +261 -0
  334. package/skills/architecture/SKILL.md +436 -0
  335. package/skills/architecture/references/adr-template.md +154 -0
  336. package/skills/architecture/references/likec4-reference.md +136 -0
  337. package/skills/architecture/references/nfr-reference.md +126 -0
  338. package/skills/archive-kb/SKILL.md +86 -0
  339. package/skills/archive-kb/scripts/archive-kb.sh +300 -0
  340. package/skills/archive-kb/test/archive-kb-partial-run.test.sh +276 -0
  341. package/skills/atdd-developer/SKILL.md +65 -0
  342. package/skills/brainstorm/SKILL.md +701 -0
  343. package/skills/brainstorm/references/brainstorm-brand-workshop.md +153 -0
  344. package/skills/brainstorm/references/brainstorm-domain-config.md +63 -0
  345. package/skills/brainstorm/references/brainstorm-validation-workshop.md +65 -0
  346. package/skills/brainstorm/references/ui-surface-terms.md +42 -0
  347. package/skills/brainstorm-techniques/SKILL.md +231 -0
  348. package/skills/brainstorm-techniques/references/decision-principles.md +150 -0
  349. package/skills/brainstorm-techniques/references/phase-boundaries.md +103 -0
  350. package/skills/brainstorm-techniques/references/standing-delegation.md +407 -0
  351. package/skills/brainstorm-techniques/references/technical-ruling-delegation.md +174 -0
  352. package/skills/campaign-calendar/SKILL.md +145 -0
  353. package/skills/cf-token-scope/SKILL.md +164 -0
  354. package/skills/cf-token-scope/references/widen-playbook.md +114 -0
  355. package/skills/cf-token-scope/scripts/cf-token-scope.sh +253 -0
  356. package/skills/changelog/SKILL.md +142 -0
  357. package/skills/code-to-prd/SKILL.md +66 -0
  358. package/skills/code-to-prd/references/banner-template.md +12 -0
  359. package/skills/code-to-prd/references/prd-template.md +41 -0
  360. package/skills/code-to-prd/scripts/code-to-prd.sh +634 -0
  361. package/skills/code-to-prd/test/code-to-prd.test.sh +447 -0
  362. package/skills/code-to-prd/test/fixture/.env.example +7 -0
  363. package/skills/code-to-prd/test/fixture/app/about/page.tsx +11 -0
  364. package/skills/code-to-prd/test/fixture/app/api/health/route.ts +10 -0
  365. package/skills/code-to-prd/test/fixture/app/page.tsx +14 -0
  366. package/skills/code-to-prd/test/fixture/next.config.mjs +3 -0
  367. package/skills/code-to-prd/test/fixture/package.json +6 -0
  368. package/skills/cohort-status/SKILL.md +62 -0
  369. package/skills/community/SKILL.md +210 -0
  370. package/skills/community/scripts/bsky-community.sh +644 -0
  371. package/skills/community/scripts/bsky-setup.sh +631 -0
  372. package/skills/community/scripts/community-router.sh +93 -0
  373. package/skills/community/scripts/discord-community.sh +487 -0
  374. package/skills/community/scripts/discord-setup.sh +784 -0
  375. package/skills/community/scripts/github-community.sh +706 -0
  376. package/skills/community/scripts/hn-community.sh +233 -0
  377. package/skills/community/scripts/lib/hmac-sha1-b64.sh +126 -0
  378. package/skills/community/scripts/linkedin-community.sh +750 -0
  379. package/skills/community/scripts/linkedin-setup.sh +758 -0
  380. package/skills/community/scripts/x-community.sh +890 -0
  381. package/skills/community/scripts/x-setup.sh +713 -0
  382. package/skills/community/test/community-argv.test.sh +2922 -0
  383. package/skills/community/test/github-community.test.sh +981 -0
  384. package/skills/competitive-analysis/SKILL.md +69 -0
  385. package/skills/competitive-analysis/references/peer-plugin-audit.md +218 -0
  386. package/skills/compound/SKILL.md +673 -0
  387. package/skills/compound/scripts/token-efficiency-report.sh +334 -0
  388. package/skills/compound/test/phase-16.test.sh +379 -0
  389. package/skills/compound-capture/SKILL.md +791 -0
  390. package/skills/compound-capture/assets/critical-pattern-template.md +37 -0
  391. package/skills/compound-capture/assets/resolution-template.md +116 -0
  392. package/skills/compound-capture/references/yaml-schema.md +67 -0
  393. package/skills/compound-capture/schema.yaml +181 -0
  394. package/skills/constraint-scaffold/SKILL.md +175 -0
  395. package/skills/constraint-scaffold/references/boundary-readme.template +35 -0
  396. package/skills/constraint-scaffold/references/constraint-gates-workflow.template +69 -0
  397. package/skills/constraint-scaffold/references/depcruise-config.template +230 -0
  398. package/skills/constraint-scaffold/references/fix-constraints-stage-a.template +240 -0
  399. package/skills/constraint-scaffold/references/fix-constraints-stage-b.template +313 -0
  400. package/skills/constraint-scaffold/references/shared-runner.template +135 -0
  401. package/skills/constraint-scaffold/scripts/constraint-scaffold.sh +589 -0
  402. package/skills/constraint-scaffold/test/bite-proof.test.sh +1338 -0
  403. package/skills/constraint-scaffold/test/boundary.test.sh +734 -0
  404. package/skills/constraint-scaffold/test/emit-fix-constraints.test.sh +193 -0
  405. package/skills/constraint-scaffold/test/generator.test.sh +93 -0
  406. package/skills/constraint-scaffold/test/parity.test.sh +285 -0
  407. package/skills/content-writer/SKILL.md +242 -0
  408. package/skills/content-writer/scripts/blog-jargon-scan.sh +42 -0
  409. package/skills/cron-delete/SKILL.md +56 -0
  410. package/skills/cron-list/SKILL.md +54 -0
  411. package/skills/deepen-plan/SKILL.md +937 -0
  412. package/skills/deepen-plan/workflows/deepen-plan.workflow.js +488 -0
  413. package/skills/deploy/SKILL.md +115 -0
  414. package/skills/deploy/references/hetzner-setup.md +67 -0
  415. package/skills/deploy/scripts/deploy.sh +37 -0
  416. package/skills/deploy-docs/SKILL.md +95 -0
  417. package/skills/dhh-rails-style/SKILL.md +203 -0
  418. package/skills/dhh-rails-style/references/architecture.md +717 -0
  419. package/skills/dhh-rails-style/references/controllers.md +323 -0
  420. package/skills/dhh-rails-style/references/frontend.md +556 -0
  421. package/skills/dhh-rails-style/references/gems.md +316 -0
  422. package/skills/dhh-rails-style/references/models.md +388 -0
  423. package/skills/dhh-rails-style/references/testing.md +354 -0
  424. package/skills/discord-content/SKILL.md +126 -0
  425. package/skills/docs-site/SKILL.md +214 -0
  426. package/skills/drain-labeled-backlog/SKILL.md +203 -0
  427. package/skills/drain-labeled-backlog/scripts/group-by-area.sh +208 -0
  428. package/skills/drain-labeled-backlog/workflows/drain-labeled-backlog.workflow.js +433 -0
  429. package/skills/drain-prs/SKILL.md +143 -0
  430. package/skills/drain-prs/scripts/triage-prs.sh +192 -0
  431. package/skills/drain-prs/test/argv-ceiling.test.sh +183 -0
  432. package/skills/dspy-ruby/SKILL.md +634 -0
  433. package/skills/dspy-ruby/assets/config-template.rb +359 -0
  434. package/skills/dspy-ruby/assets/module-template.rb +326 -0
  435. package/skills/dspy-ruby/assets/signature-template.rb +143 -0
  436. package/skills/dspy-ruby/references/core-concepts.md +268 -0
  437. package/skills/dspy-ruby/references/optimization.md +623 -0
  438. package/skills/dspy-ruby/references/providers.md +335 -0
  439. package/skills/eval-harness/README.md +194 -0
  440. package/skills/eval-harness/SKILL.md +157 -0
  441. package/skills/eval-harness/enums/go-routes.json +13 -0
  442. package/skills/eval-harness/enums/incident-threshold.json +5 -0
  443. package/skills/eval-harness/enums/lane.json +5 -0
  444. package/skills/eval-harness/enums/tool-selection.json +20 -0
  445. package/skills/eval-harness/enums/triage-levels.json +5 -0
  446. package/skills/eval-harness/gated-skills.json +34 -0
  447. package/skills/eval-harness/models.generated.json +5 -0
  448. package/skills/eval-harness/promptfooconfig-go-routing.yaml +35 -0
  449. package/skills/eval-harness/promptfooconfig-incident-threshold.yaml +32 -0
  450. package/skills/eval-harness/promptfooconfig-lane-inference.yaml +33 -0
  451. package/skills/eval-harness/promptfooconfig-ticket-triage.yaml +34 -0
  452. package/skills/eval-harness/promptfooconfig-tool-selection.yaml +33 -0
  453. package/skills/eval-harness/prompts/go-baseline.txt +6 -0
  454. package/skills/eval-harness/prompts/go-skill.txt +21 -0
  455. package/skills/eval-harness/prompts/incident-threshold-baseline.txt +6 -0
  456. package/skills/eval-harness/prompts/incident-threshold-skill.txt +12 -0
  457. package/skills/eval-harness/prompts/lane-inference-baseline.txt +6 -0
  458. package/skills/eval-harness/prompts/lane-inference-skill.txt +15 -0
  459. package/skills/eval-harness/prompts/tool-selection-baseline.txt +19 -0
  460. package/skills/eval-harness/prompts/tool-selection-skill.txt +22 -0
  461. package/skills/eval-harness/prompts/triage-baseline.txt +7 -0
  462. package/skills/eval-harness/prompts/triage-skill.txt +10 -0
  463. package/skills/eval-harness/scripts/eval-gate.cjs +318 -0
  464. package/skills/eval-harness/scripts/extract-block.cjs +87 -0
  465. package/skills/eval-harness/scripts/gate-classification.cjs +28 -0
  466. package/skills/eval-harness/scripts/gen-models.sh +41 -0
  467. package/skills/eval-harness/scripts/gen-skill-prompt.cjs +177 -0
  468. package/skills/eval-harness/scripts/measure-classification.cjs +30 -0
  469. package/skills/eval-harness/scripts/parse-label.cjs +93 -0
  470. package/skills/eval-harness/scripts/verdict.cjs +132 -0
  471. package/skills/eval-harness/tasks/go-routing.jsonl +8 -0
  472. package/skills/eval-harness/tasks/incident-threshold.jsonl +7 -0
  473. package/skills/eval-harness/tasks/lane-inference.jsonl +7 -0
  474. package/skills/eval-harness/tasks/ticket-triage.jsonl +6 -0
  475. package/skills/eval-harness/tasks/tool-selection.jsonl +15 -0
  476. package/skills/eval-harness/test/eval-gate.test.sh +132 -0
  477. package/skills/eval-harness/test/extract-block.test.sh +87 -0
  478. package/skills/eval-harness/test/gate-classification.test.sh +77 -0
  479. package/skills/eval-harness/test/gen-models.test.sh +75 -0
  480. package/skills/eval-harness/test/measure-classification.test.sh +74 -0
  481. package/skills/eval-harness/test/parse-label.test.sh +129 -0
  482. package/skills/eval-harness/test/registry-completeness.test.sh +109 -0
  483. package/skills/eval-harness/test/verdict.test.sh +123 -0
  484. package/skills/every-style-editor/SKILL.md +142 -0
  485. package/skills/every-style-editor/references/EVERY_WRITE_STYLE.md +529 -0
  486. package/skills/feature-tweet/SKILL.md +199 -0
  487. package/skills/feature-video/SKILL.md +412 -0
  488. package/skills/feature-video/scripts/check_deps.sh +281 -0
  489. package/skills/file-todos/SKILL.md +267 -0
  490. package/skills/file-todos/assets/todo-template.md +166 -0
  491. package/skills/fix-issue/SKILL.md +278 -0
  492. package/skills/fix-issue/references/agent-authored-exclusion.md +120 -0
  493. package/skills/fix-issue/references/exclude-label-jq-snippet.md +97 -0
  494. package/skills/flag-bootstrap/SETUP.md +142 -0
  495. package/skills/flag-create/SKILL.md +145 -0
  496. package/skills/flag-create/scripts/create.sh +273 -0
  497. package/skills/flag-delete/SKILL.md +167 -0
  498. package/skills/flag-delete/scripts/delete.sh +288 -0
  499. package/skills/flag-list/SKILL.md +99 -0
  500. package/skills/flag-list/scripts/list.sh +275 -0
  501. package/skills/flag-set-role/SKILL.md +229 -0
  502. package/skills/flag-set-role/scripts/flip.sh +774 -0
  503. package/skills/frontend-anti-slop/SKILL.md +106 -0
  504. package/skills/frontend-anti-slop/references/anti-patterns.md +199 -0
  505. package/skills/frontend-anti-slop/references/slop-rules.md +65 -0
  506. package/skills/frontend-anti-slop/scripts/tier1-scan.ts +525 -0
  507. package/skills/frontend-design/SKILL.md +77 -0
  508. package/skills/gdpr-gate/NOTICE +136 -0
  509. package/skills/gdpr-gate/SKILL.md +341 -0
  510. package/skills/gdpr-gate/references/fields.md +160 -0
  511. package/skills/gdpr-gate/references/layers/api-layer.md +355 -0
  512. package/skills/gdpr-gate/references/layers/auth-sessions.md +290 -0
  513. package/skills/gdpr-gate/references/layers/data-in-transit.md +331 -0
  514. package/skills/gdpr-gate/references/layers/data-lifecycle.md +341 -0
  515. package/skills/gdpr-gate/references/layers/frontend.md +249 -0
  516. package/skills/gdpr-gate/references/layers/testing-seeding.md +256 -0
  517. package/skills/gdpr-gate/references/leakage-vectors.md +248 -0
  518. package/skills/gdpr-gate/references/legacy/legal-consent-v1-prose.md +48 -0
  519. package/skills/gdpr-gate/references/legal-consent.md +140 -0
  520. package/skills/gdpr-gate/references/non-negotiables.md +60 -0
  521. package/skills/gdpr-gate/scripts/gdpr-gate.sh +271 -0
  522. package/skills/gdpr-gate/scripts/notice-frontmatter.sh +337 -0
  523. package/skills/gdpr-gate/scripts/path-denylist.txt +39 -0
  524. package/skills/gdpr-gate/scripts/repo-scan.sh +158 -0
  525. package/skills/gdpr-gate/scripts/vendor-drift-classify.sh +120 -0
  526. package/skills/gdpr-gate/scripts/vendor-pin-integrity.sh +237 -0
  527. package/skills/gemini-imagegen/SKILL.md +283 -0
  528. package/skills/gemini-imagegen/requirements.txt +5 -0
  529. package/skills/gemini-imagegen/scripts/_error_handling.py +146 -0
  530. package/skills/gemini-imagegen/scripts/compose_images.py +150 -0
  531. package/skills/gemini-imagegen/scripts/edit_image.py +137 -0
  532. package/skills/gemini-imagegen/scripts/gemini_images.py +256 -0
  533. package/skills/gemini-imagegen/scripts/generate_image.py +147 -0
  534. package/skills/gemini-imagegen/scripts/multi_turn_chat.py +223 -0
  535. package/skills/gemini-imagegen/scripts/test_error_handling.py +179 -0
  536. package/skills/git-worktree/SKILL.md +534 -0
  537. package/skills/git-worktree/scripts/git-repo-readiness-diag.sh +98 -0
  538. package/skills/git-worktree/scripts/worktree-manager.sh +4773 -0
  539. package/skills/git-worktree/test/create-from-origin-main.test.sh +116 -0
  540. package/skills/git-worktree/test/lease-protects-active.test.sh +1056 -0
  541. package/skills/git-worktree/test/no-repo-fail-loud.test.sh +88 -0
  542. package/skills/git-worktree/test/orphan-reaper-honest-count.test.sh +379 -0
  543. package/skills/git-worktree/test/reap-archive-persistence.test.sh +725 -0
  544. package/skills/git-worktree/test/stale-lock-sweep.test.sh +176 -0
  545. package/skills/go/SKILL.md +54 -0
  546. package/skills/growth/SKILL.md +164 -0
  547. package/skills/harvest-debt/SKILL.md +78 -0
  548. package/skills/harvest-debt/scripts/harvest-debt.sh +114 -0
  549. package/skills/heal-skill/SKILL.md +173 -0
  550. package/skills/help/SKILL.md +46 -0
  551. package/skills/incident/NOTICE +39 -0
  552. package/skills/incident/SKILL.md +395 -0
  553. package/skills/incident/scripts/dry-run.sh +448 -0
  554. package/skills/incident/scripts/redact-engine.py +412 -0
  555. package/skills/incident/scripts/redact-sentinel.sh +44 -0
  556. package/skills/incident/templates/pir.md +139 -0
  557. package/skills/incident/test/fixtures/dry-run-incident.json +26 -0
  558. package/skills/incident/test/fixtures/dry-run-secret-leak.json +26 -0
  559. package/skills/incident/test/fixtures/legacy-bash-scanner.sh +82 -0
  560. package/skills/incident/test/fixtures/positive-corpus.md +87 -0
  561. package/skills/incident/test/redact-sentinel.test.sh +1420 -0
  562. package/skills/invoice/SKILL.md +206 -0
  563. package/skills/kb-glossary/SKILL.md +71 -0
  564. package/skills/kb-glossary/references/glossary-format.md +111 -0
  565. package/skills/kb-glossary/references/rejected-request-register.md +115 -0
  566. package/skills/kb-search/SKILL.md +276 -0
  567. package/skills/kb-search/scripts/kb-search-cache.sh +123 -0
  568. package/skills/legal-audit/SKILL.md +161 -0
  569. package/skills/legal-generate/NOTICE +242 -0
  570. package/skills/legal-generate/SKILL.md +244 -0
  571. package/skills/legal-generate/references/templates/advisor-agreement/template.md +12 -0
  572. package/skills/legal-generate/references/templates/business-associate-agreement/template.md +112 -0
  573. package/skills/legal-generate/references/templates/cookie-notice/template.md +82 -0
  574. package/skills/legal-generate/references/templates/dpa-global/template.md +439 -0
  575. package/skills/legal-generate/references/templates/dpa-us/template.md +222 -0
  576. package/skills/legal-generate/references/templates/employee-offer-letter/template.md +75 -0
  577. package/skills/legal-generate/references/templates/master-services-agreement/template.md +252 -0
  578. package/skills/legal-generate/references/templates/mutual-nda/template.md +66 -0
  579. package/skills/legal-generate/references/templates/one-way-nda/template.md +38 -0
  580. package/skills/legal-generate/references/templates/privacy-policy-gdpr/template.md +427 -0
  581. package/skills/legal-generate/references/templates/privacy-policy-us/template.md +313 -0
  582. package/skills/legal-generate/references/templates/terms-of-use/template.md +75 -0
  583. package/skills/legal-generate/scripts/strip-vendor-credit.sh +96 -0
  584. package/skills/linear-fetch/SKILL.md +247 -0
  585. package/skills/linear-fetch/scripts/assert-no-linear-telemetry.sh +66 -0
  586. package/skills/linear-fetch/scripts/redact-linear-urls.sh +51 -0
  587. package/skills/linear-fetch/scripts/render-caller-template.sh +36 -0
  588. package/skills/linear-fetch/test/assert-no-linear-telemetry.test.sh +113 -0
  589. package/skills/linear-fetch/test/parity.test.sh +112 -0
  590. package/skills/linear-fetch/test/persist-safe-integration.test.sh +191 -0
  591. package/skills/linear-fetch/test/redact-linear-urls.test.sh +226 -0
  592. package/skills/merge-pr/SKILL.md +670 -0
  593. package/skills/model-launch-review/SKILL.md +255 -0
  594. package/skills/model-launch-review/scripts/audit-models.sh +501 -0
  595. package/skills/one-shot/SKILL.md +316 -0
  596. package/skills/one-shot/references/token-discipline.md +74 -0
  597. package/skills/operator-bootstrap/SKILL.md +412 -0
  598. package/skills/operator-bootstrap/template.sh +439 -0
  599. package/skills/operator-digest/SKILL.md +287 -0
  600. package/skills/operator-digest/assets/operator-digest.workflow.yml +175 -0
  601. package/skills/operator-digest/scripts/digest-scrub.sh +119 -0
  602. package/skills/operator-digest/scripts/provision-operator-digest-repo.sh +147 -0
  603. package/skills/operator-rephrase/SKILL.md +98 -0
  604. package/skills/pencil-setup/SKILL.md +201 -0
  605. package/skills/pencil-setup/scripts/check_deps.sh +556 -0
  606. package/skills/pencil-setup/scripts/copy_adapter.sh +80 -0
  607. package/skills/pencil-setup/scripts/package-lock.json +1172 -0
  608. package/skills/pencil-setup/scripts/package.json +14 -0
  609. package/skills/pencil-setup/scripts/pencil-error-enrichment.mjs +21 -0
  610. package/skills/pencil-setup/scripts/pencil-mcp-adapter.mjs +733 -0
  611. package/skills/pencil-setup/scripts/pencil-response-classify.mjs +38 -0
  612. package/skills/pencil-setup/scripts/pencil-save-gate.mjs +26 -0
  613. package/skills/pencil-setup/scripts/sanitize-filename.mjs +25 -0
  614. package/skills/plan/SKILL.md +1140 -0
  615. package/skills/plan/references/differential-migration-testing.md +185 -0
  616. package/skills/plan/references/plan-community-discovery.md +42 -0
  617. package/skills/plan/references/plan-founder-check.md +137 -0
  618. package/skills/plan/references/plan-functional-overlap.md +25 -0
  619. package/skills/plan/references/plan-host-fanout.md +51 -0
  620. package/skills/plan/references/plan-issue-templates.md +779 -0
  621. package/skills/plan/references/plan-network-outage-checklist.md +131 -0
  622. package/skills/plan/references/plan-scope-check.md +126 -0
  623. package/skills/plan/references/plan-sharp-edges.md +331 -0
  624. package/skills/plan/references/plan-signoff-lifecycle.md +12 -0
  625. package/skills/plan/references/webapp-cwv-observability.md +143 -0
  626. package/skills/plan-review/SKILL.md +91 -0
  627. package/skills/plan-review/lib/named-panel.mjs +58 -0
  628. package/skills/plan-review/workflows/plan-review.workflow.js +477 -0
  629. package/skills/postmerge/SKILL.md +642 -0
  630. package/skills/postmerge/references/deploy-status-debugging.md +141 -0
  631. package/skills/postmerge/references/graceful-degradation.md +20 -0
  632. package/skills/postmerge/references/sentry-error-count-delta.md +137 -0
  633. package/skills/preflight/SKILL.md +1553 -0
  634. package/skills/preflight/references/check-13-founder-check.md +286 -0
  635. package/skills/preflight/scripts/founder-check.py +1640 -0
  636. package/skills/preflight/scripts/parse-form-a.awk +107 -0
  637. package/skills/preflight/scripts/probe-verb-gate.sh +108 -0
  638. package/skills/product-roadmap/SKILL.md +357 -0
  639. package/skills/product-roadmap/scripts/roadmap-reconcile.sh +327 -0
  640. package/skills/provision-cloudflare/SKILL.md +67 -0
  641. package/skills/provision-cloudflare/scripts/provision-cloudflare.sh +271 -0
  642. package/skills/provision-doppler/SKILL.md +58 -0
  643. package/skills/provision-doppler/scripts/provision-doppler.sh +358 -0
  644. package/skills/provision-github/SKILL.md +59 -0
  645. package/skills/provision-github/scripts/provision-github.sh +300 -0
  646. package/skills/provision-hetzner/SKILL.md +76 -0
  647. package/skills/provision-hetzner/scripts/provision-hetzner.sh +262 -0
  648. package/skills/provision-hetzner/test/fixture/knowledge-base/legal/tenant-dpa-register.md +26 -0
  649. package/skills/provision-hetzner/test/fixture/provision-hetzner-dry-run.golden +34 -0
  650. package/skills/provision-hetzner/test/provision-hetzner-characterization.test.sh +227 -0
  651. package/skills/qa/SKILL.md +263 -0
  652. package/skills/qa/references/browser-preflight.md +22 -0
  653. package/skills/questionnaire-generate/SKILL.md +328 -0
  654. package/skills/questionnaire-generate/references/questionnaire.template +60 -0
  655. package/skills/rclone/SKILL.md +162 -0
  656. package/skills/rclone/scripts/check_setup.sh +63 -0
  657. package/skills/release-announce/SKILL.md +65 -0
  658. package/skills/release-docs/SKILL.md +92 -0
  659. package/skills/reproduce-bug/SKILL.md +358 -0
  660. package/skills/resolve-debt/SKILL.md +85 -0
  661. package/skills/resolve-debt/scripts/resolve-debt.py +584 -0
  662. package/skills/resolve-parallel/SKILL.md +45 -0
  663. package/skills/resolve-parallel/workflows/resolve-parallel.workflow.js +415 -0
  664. package/skills/resolve-pr-parallel/SKILL.md +68 -0
  665. package/skills/resolve-pr-parallel/workflows/resolve-pr-parallel.workflow.js +419 -0
  666. package/skills/resolve-todo-parallel/SKILL.md +57 -0
  667. package/skills/resolve-todo-parallel/workflows/resolve-todo-parallel.workflow.js +398 -0
  668. package/skills/review/SKILL.md +1620 -0
  669. package/skills/review/references/anti-slop-scanner-hook.md +40 -0
  670. package/skills/review/references/defect-classes-migrations.md +9 -0
  671. package/skills/review/references/generated-input-oracle-surfaces.md +15 -0
  672. package/skills/review/references/review-e2e-testing.md +116 -0
  673. package/skills/review/references/review-evidence-comment.md +36 -0
  674. package/skills/review/references/review-todo-structure.md +165 -0
  675. package/skills/review/references/risk-tier-and-fix-rounds.md +97 -0
  676. package/skills/review/references/semgrep-custom-rules.yaml +174 -0
  677. package/skills/review/references/ultrathink-phases.md +98 -0
  678. package/skills/review/references/wfs.md +6 -0
  679. package/skills/review/scripts/emit-review-trailer.sh +499 -0
  680. package/skills/review/scripts/ensure-semgrep.sh +99 -0
  681. package/skills/review/scripts/fix-round-seats.sh +197 -0
  682. package/skills/review/test/emit-review-trailer.test.sh +387 -0
  683. package/skills/review/test/ensure-semgrep.test.sh +111 -0
  684. package/skills/review/test/fix-round-seats.test.sh +237 -0
  685. package/skills/review/workflows/README.md +147 -0
  686. package/skills/review/workflows/review.workflow.js +667 -0
  687. package/skills/schedule/SKILL.md +796 -0
  688. package/skills/seo-aeo/SKILL.md +139 -0
  689. package/skills/seo-aeo/scripts/validate-csp.sh +233 -0
  690. package/skills/seo-aeo/scripts/validate-seo.sh +262 -0
  691. package/skills/ship/SKILL.md +3023 -0
  692. package/skills/ship/references/adr-ordinal-collision.md +47 -0
  693. package/skills/ship/references/affected-gate-contract.md +115 -0
  694. package/skills/ship/references/ci-run-diagnosis.md +29 -0
  695. package/skills/ship/references/ci-workflow-authoring.md +68 -0
  696. package/skills/ship/references/cleanup-merged-archival.md +39 -0
  697. package/skills/ship/references/counsel-review-clo-attestation.md +38 -0
  698. package/skills/ship/references/cto-ruling-armed-push.md +5 -0
  699. package/skills/ship/references/decision-challenges-render.md +71 -0
  700. package/skills/ship/references/delegated-act-authoring-form.md +7 -0
  701. package/skills/ship/references/detached-battery-verdict.md +13 -0
  702. package/skills/ship/references/epic-close-sweep.md +62 -0
  703. package/skills/ship/references/feature-tweet-draft.md +42 -0
  704. package/skills/ship/references/followthrough-issue-body-template.md +47 -0
  705. package/skills/ship/references/followthrough-stub-template.sh +92 -0
  706. package/skills/ship/references/merge-queue-dequeue.md +39 -0
  707. package/skills/ship/references/operator-holds.md +179 -0
  708. package/skills/ship/references/pipeline-tally-render.md +43 -0
  709. package/skills/ship/references/pr-overlap.md +153 -0
  710. package/skills/ship/references/queue-mode.md +7 -0
  711. package/skills/ship/references/ready-run-wait.md +36 -0
  712. package/skills/ship/references/red-on-main-quarantine.md +110 -0
  713. package/skills/ship/references/register-update-pr-pattern.md +88 -0
  714. package/skills/ship/references/settle-then-admin-merge.md +130 -0
  715. package/skills/ship/references/supabase-column-probe.md +13 -0
  716. package/skills/ship/scripts/auto-close-scan.sh +76 -0
  717. package/skills/ship/scripts/battery-owed.sh +403 -0
  718. package/skills/ship/scripts/hold-gate-eval.sh +410 -0
  719. package/skills/ship/scripts/net-issue-flow.sh +665 -0
  720. package/skills/ship/scripts/pr-overlap-preflight.sh +483 -0
  721. package/skills/ship/scripts/ship-pir-action-items-gate.sh +246 -0
  722. package/skills/ship/scripts/technical-ruling-gate.sh +444 -0
  723. package/skills/skill-creator/SKILL.md +299 -0
  724. package/skills/skill-creator/references/api-security.md +248 -0
  725. package/skills/skill-creator/references/authoring-levers.md +110 -0
  726. package/skills/skill-creator/references/be-clear-and-direct.md +587 -0
  727. package/skills/skill-creator/references/best-practices.md +431 -0
  728. package/skills/skill-creator/references/common-patterns.md +639 -0
  729. package/skills/skill-creator/references/core-principles.md +193 -0
  730. package/skills/skill-creator/references/executable-code.md +188 -0
  731. package/skills/skill-creator/references/iteration-and-testing.md +509 -0
  732. package/skills/skill-creator/references/official-spec.md +193 -0
  733. package/skills/skill-creator/references/recommended-structure.md +180 -0
  734. package/skills/skill-creator/references/skill-structure.md +396 -0
  735. package/skills/skill-creator/references/using-scripts.md +122 -0
  736. package/skills/skill-creator/references/using-templates.md +120 -0
  737. package/skills/skill-creator/references/workflows-and-validation.md +541 -0
  738. package/skills/skill-creator/scripts/init_skill.py +322 -0
  739. package/skills/skill-creator/scripts/package_skill.py +110 -0
  740. package/skills/skill-creator/scripts/quick_validate.py +64 -0
  741. package/skills/skill-creator/templates/router-skill.md +73 -0
  742. package/skills/skill-creator/templates/simple-skill.md +34 -0
  743. package/skills/skill-creator/workflows/add-reference.md +96 -0
  744. package/skills/skill-creator/workflows/add-script.md +104 -0
  745. package/skills/skill-creator/workflows/add-template.md +83 -0
  746. package/skills/skill-creator/workflows/add-workflow.md +128 -0
  747. package/skills/skill-creator/workflows/audit-skill.md +159 -0
  748. package/skills/skill-creator/workflows/create-domain-expertise-skill.md +623 -0
  749. package/skills/skill-creator/workflows/create-new-skill.md +207 -0
  750. package/skills/skill-creator/workflows/get-guidance.md +134 -0
  751. package/skills/skill-creator/workflows/upgrade-to-router.md +170 -0
  752. package/skills/skill-creator/workflows/verify-skill.md +226 -0
  753. package/skills/skill-security-scan/SKILL.md +145 -0
  754. package/skills/skill-security-scan/references/disclaimer.md +21 -0
  755. package/skills/skill-security-scan/references/first-party-allowlist.yaml +38 -0
  756. package/skills/skill-security-scan/references/override-artifact-schema.json +68 -0
  757. package/skills/skill-security-scan/references/override-mechanism.md +171 -0
  758. package/skills/skill-security-scan/references/redirect-domains.yaml +27 -0
  759. package/skills/skill-security-scan/references/regex-patterns.md +136 -0
  760. package/skills/skill-security-scan/references/rules/code-exec.yaml +70 -0
  761. package/skills/skill-security-scan/references/rules/filesystem-boundary.yaml +29 -0
  762. package/skills/skill-security-scan/references/rules/manifest.yaml +44 -0
  763. package/skills/skill-security-scan/references/rules/supply-chain.yaml +36 -0
  764. package/skills/skill-security-scan/references/scan-meta-schema.json +63 -0
  765. package/skills/skill-security-scan/references/test-fixtures/clean-soleur-style.skill.md +23 -0
  766. package/skills/skill-security-scan/references/test-fixtures/clean-third-party.skill.md +26 -0
  767. package/skills/skill-security-scan/references/test-fixtures/malicious-codeexec.skill.md +23 -0
  768. package/skills/skill-security-scan/references/test-fixtures/malicious-curl-pipe-bash.skill.md +69 -0
  769. package/skills/skill-security-scan/references/test-fixtures/malicious-prompt-injection.skill.md +17 -0
  770. package/skills/skill-security-scan/references/test-fixtures/malicious-telemetry-beacon.skill.md +23 -0
  771. package/skills/skill-security-scan/references/typosquat-targets.yaml +65 -0
  772. package/skills/skill-security-scan/scripts/check-codeexec.sh +41 -0
  773. package/skills/skill-security-scan/scripts/check-filesystem-boundary.sh +19 -0
  774. package/skills/skill-security-scan/scripts/check-prompt-injection.sh +95 -0
  775. package/skills/skill-security-scan/scripts/check-supply-chain.sh +219 -0
  776. package/skills/skill-security-scan/scripts/check-telemetry-surface.sh +126 -0
  777. package/skills/skill-security-scan/scripts/lib.sh +197 -0
  778. package/skills/skill-security-scan/scripts/parse-override.sh +231 -0
  779. package/skills/skill-security-scan/scripts/run-scan.sh +342 -0
  780. package/skills/skill-security-scan/scripts/run-self-test.sh +95 -0
  781. package/skills/skill-security-scan/test/argv-ceiling.test.sh +180 -0
  782. package/skills/skill-security-scan/test/meta-dir-reap.test.sh +411 -0
  783. package/skills/skill-security-scan/test/parse-override.test.sh +607 -0
  784. package/skills/skill-security-scan/test/redact-pii-ghs-shape.test.sh +251 -0
  785. package/skills/social-distribute/SKILL.md +485 -0
  786. package/skills/spec-templates/SKILL.md +274 -0
  787. package/skills/sync/SKILL.md +49 -0
  788. package/skills/test-browser/SKILL.md +464 -0
  789. package/skills/test-browser/references/feature-map.md +161 -0
  790. package/skills/test-fix-loop/SKILL.md +159 -0
  791. package/skills/test-fix-loop/references/determinism-checklist.md +154 -0
  792. package/skills/triage/SKILL.md +402 -0
  793. package/skills/trigger-cron/SKILL.md +136 -0
  794. package/skills/trigger-cron/scripts/trigger.sh +198 -0
  795. package/skills/user-set-role/SKILL.md +147 -0
  796. package/skills/user-set-role/scripts/set-role.sh +218 -0
  797. package/skills/user-story-writer/SKILL.md +77 -0
  798. package/skills/ux-audit/SKILL.md +251 -0
  799. package/skills/ux-audit/references/finding.schema.json +62 -0
  800. package/skills/ux-audit/references/route-list.yaml +95 -0
  801. package/skills/ux-audit/scripts/bot-fixture.ts +270 -0
  802. package/skills/ux-audit/scripts/bot-signin.ts +135 -0
  803. package/skills/ux-audit/scripts/dedup-hash.ts +46 -0
  804. package/skills/verification-scaffold/SKILL.md +73 -0
  805. package/skills/verification-scaffold/references/gitleaks.toml.template +13 -0
  806. package/skills/verification-scaffold/references/guardrail-audit.md +156 -0
  807. package/skills/verification-scaffold/references/guards/block-stash-hook.sh.template +72 -0
  808. package/skills/verification-scaffold/references/guards/commit-on-main-hook.sh.template +82 -0
  809. package/skills/verification-scaffold/references/guards/orphan-test-check.sh.template +102 -0
  810. package/skills/verification-scaffold/references/guards/precommit-guard.sh.template +115 -0
  811. package/skills/verification-scaffold/references/guards/secret-scan-hook.sh.template +176 -0
  812. package/skills/verification-scaffold/references/guards/verification-gates.yml.template +49 -0
  813. package/skills/verification-scaffold/references/guards/wrapper-boundary.sh.template +47 -0
  814. package/skills/verification-scaffold/references/guards.tsv +21 -0
  815. package/skills/verification-scaffold/references/verification-readme.template +55 -0
  816. package/skills/verification-scaffold/scripts/verification-scaffold.sh +785 -0
  817. package/skills/verification-scaffold/test/bite-proof.test.sh +159 -0
  818. package/skills/verification-scaffold/test/generator.test.sh +319 -0
  819. package/skills/verification-scaffold/test/manifest.test.sh +144 -0
  820. package/skills/work/SKILL.md +1480 -0
  821. package/skills/work/references/end-of-work-resume.md +7 -0
  822. package/skills/work/references/hook-test-main-cwd.md +24 -0
  823. package/skills/work/references/key-principles.md +83 -0
  824. package/skills/work/references/property-testing.md +122 -0
  825. package/skills/work/references/sql-security-definer-rpc-scaffold.sql +78 -0
  826. package/skills/work/references/work-agent-teams.md +97 -0
  827. package/skills/work/references/work-lifecycle-parallel.md +147 -0
  828. package/skills/work/references/work-lockfile-bumps.md +97 -0
  829. package/skills/work/references/work-scratch-sandboxes.md +212 -0
  830. package/skills/work/references/work-subagent-fanout.md +61 -0
  831. package/skills/work/references/work-test-harness-sharp-edges.md +73 -0
  832. package/skills/xcode-test/SKILL.md +360 -0
@@ -0,0 +1,412 @@
1
+ #!/usr/bin/env python3
2
+ # Hardened redaction engine (#5987). Adapted from gstack `redact-engine` (clean-room;
3
+ # see plugins/soleur/NOTICE). Contract preserved 1:1 with the former bash engine so the
4
+ # three in-repo consumers (incident dry-run.sh, code-to-prd Layer 2, legal-generate gate)
5
+ # need no change:
6
+ # argv[1] = path to scan.
7
+ # exit 0 = clean / 1 = redaction needed (incl. synthetic HIGH) / 2 = cannot-evaluate.
8
+ # stdout finding lines: "at offset <normOffset>: <prefix>***<suffix> matched pattern <class>"
9
+ #
10
+ # Pipeline: cap -> strip -> NFKC(whole-string) -> strip -> confusable-fold -> match -> meta-redact.
11
+ # Detection matches over ONE whole-string NFKC(strip(text)): per-codepoint normalization is NOT
12
+ # equal to whole-string NFKC (a decomposed/combining sequence folds to an ASCII secret char only
13
+ # whole-string), so per-codepoint would be a fail-OPEN. The sentinel halts; it never rewrites in
14
+ # place and no consumer parses the offset, so there is no offset-map back to the original.
15
+ import base64
16
+ import binascii
17
+ import contextlib
18
+ import os
19
+ import re
20
+ import sys
21
+ import unicodedata
22
+ import urllib.parse
23
+
24
+ # 1 MiB default cap. Overridable via env for tests/tuning.
25
+ MAX = int(os.environ.get("REDACT_MAX_INPUT_BYTES", str(1024 * 1024)))
26
+
27
+ # Invisible / break-rendering / bidi / format characters that NFKC does NOT remove and that splice
28
+ # tokens invisibly. Built by Unicode CATEGORY, not a hand-picked codepoint list — an enumeration
29
+ # silently misses whole families (C0 controls, DEL, variation selectors, the Tags block U+E0000-E007F,
30
+ # combining grapheme joiner), each the SAME evasion class this engine defeats. Strip:
31
+ # - categories Cc (control), Cf (format), Cs (surrogate) — EXCEPT the meaningful ASCII whitespace
32
+ # controls (tab/LF/VT/FF/CR), which are kept (whitespace token-splitting is a documented non-goal);
33
+ # - variation selectors (U+FE00-FE0F, U+E0100-E01EF), combining grapheme joiner (U+034F), and the
34
+ # Mongolian free variation selectors (U+180B-180D) — invisible marks NFKC leaves intact.
35
+ # Plus an explicit tail for the invisibles that are NOT in Cc/Cf/Cs: line/para separators (Zl/Zp),
36
+ # the replacement char (So, from an invalid-byte splice), and the Hangul/Khmer fillers that render as
37
+ # nothing (Lo/Mn). Keys are ordinals throughout (escapes-only per `cq-regex-unicode-separators-escape-only`).
38
+ _KEEP_WHITESPACE = {0x09, 0x0A, 0x0B, 0x0C, 0x0D}
39
+ _EXPLICIT_STRIP = (
40
+ 0x2028, 0x2029, # line / paragraph separators (Zl / Zp)
41
+ 0xFFFD, # decode-replacement char (So — invalid-byte splice)
42
+ 0x115F, 0x1160, 0x3164, 0xFFA0, # Hangul fillers (Lo) — incl. halfwidth U+FFA0 (NFKC->U+1160)
43
+ 0x17B4, 0x17B5, # Khmer inherent vowels (Mn) — render as nothing
44
+ )
45
+
46
+
47
+ def _strippable(o):
48
+ if o in _KEEP_WHITESPACE:
49
+ return False
50
+ if unicodedata.category(chr(o)) in ("Cc", "Cf", "Cs"):
51
+ return True
52
+ return 0xFE00 <= o <= 0xFE0F or 0xE0100 <= o <= 0xE01EF or o == 0x034F or 0x180B <= o <= 0x180D
53
+
54
+
55
+ # Built once at import over the bounded ranges that hold every Cc/Cf/Cs + invisible-mark codepoint
56
+ # (all below U+30000, plus the Tags/variation-selector-supplement block U+E0000-E01FF). ~0.1s, ~2.5k keys.
57
+ STRIP = {o: None for o in _EXPLICIT_STRIP}
58
+ STRIP.update({o: None for o in range(0x30000) if _strippable(o)})
59
+ STRIP.update({o: None for o in range(0xE0000, 0xE0200) if _strippable(o)})
60
+
61
+ # Targeted ASCII-lookalike fold for the strong Cyrillic/Greek homoglyphs that appear in secret
62
+ # prefixes/bodies. Cheap partial cross-script coverage so AC1 is HONEST; the full TR39 skeleton is a
63
+ # named non-goal and the residual gap is version-controlled by redact-sentinel.test.sh Test 12.
64
+ # Deliberately NO ->t mapping: no Cyrillic/Greek 't' lookalike is folded (Test 12b pins this gap).
65
+ _CONFUSABLE_PAIRS = {
66
+ # Cyrillic -> Latin
67
+ "а": "a", "е": "e", "о": "o", "р": "p", "с": "c",
68
+ "ѕ": "s", "х": "x", "у": "y", "і": "i", "ј": "j",
69
+ "к": "k", "ԛ": "q", "ԁ": "d", "ѵ": "v", "ԝ": "w",
70
+ "һ": "h", "ɡ": "g",
71
+ # Greek -> Latin
72
+ "ο": "o", "ρ": "p", "ν": "v", "α": "a", "ε": "e",
73
+ "κ": "k", "ι": "i", "υ": "u", "χ": "x",
74
+ }
75
+ CONFUSABLE_MAP = {ord(k): v for k, v in _CONFUSABLE_PAIRS.items()}
76
+
77
+ # All classes compiled with re.ASCII so \b/\w/\s keep grep's C-locale (ASCII) semantics. WITHOUT
78
+ # re.ASCII, Python's Unicode \b makes "Юsk-ant-..." a MISS the bash version caught (a NEW evasion).
79
+ # POSIX [^[:space:]] is hand-translated to \S (a literal [^[:space:]] in Python re is the char set
80
+ # {[ : s p a c e ]} — a silent narrowing).
81
+ F = re.ASCII
82
+ PATTERNS = [
83
+ ("github_token", re.compile(r"\b(ghp|gho|ghu|ghs|ghr)_[A-Za-z0-9._~+/=-]{30,}|\bgithub_pat_[A-Za-z0-9._~+/=-]{20,}", F)),
84
+ ("JWT", re.compile(r"eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}", F)),
85
+ # Local-part/domain quantifiers are BOUNDED (RFC 5321: local <=64, domain <=255) — an unbounded
86
+ # `+` backtracks O(n^2) on a long email-class run with no '@', hanging the fail-closed gate on a
87
+ # crafted ~1 MiB input (#6045 security review). Bounding keeps it linear without narrowing real emails.
88
+ ("email", re.compile(r"\b[A-Za-z0-9._%+-]{1,64}@[A-Za-z0-9.-]{1,255}\.[A-Za-z]{2,}\b", F)),
89
+ # UUID broadened to [0-9A-Fa-f] (uppercase — a latent lowercase-only gap in the bash baseline).
90
+ ("UUID", re.compile(r"\b[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}\b", F)),
91
+ ("stripe_key", re.compile(r"\b(sk|pk|rk)_(live|test)_[A-Za-z0-9]{16,}\b", F)),
92
+ ("stripe_whsec", re.compile(r"\bwhsec_[A-Za-z0-9]{16,}\b", F)),
93
+ ("stripe_acct", re.compile(r"\bacct_[A-Za-z0-9]{16,}\b", F)),
94
+ ("stripe_cust_pi_seti_sub_in", re.compile(r"\b(cus|pi|seti|sub|in)_[A-Za-z0-9]{14,}\b", F)),
95
+ ("IPv4", re.compile(r"\b(([0-9]{1,3})\.){3}[0-9]{1,3}\b", F)),
96
+ # env_var vendor list broadened (+HETZNER|FLAGSMITH|RESEND|TAILSCALE); \S+ (NOT [^[:space:]]+).
97
+ ("env_var", re.compile(
98
+ r"\b(DOPPLER|SENTRY|STRIPE|SUPABASE|OPENAI|ANTHROPIC|GITHUB|VERCEL|CLOUDFLARE"
99
+ r"|HETZNER|FLAGSMITH|RESEND|TAILSCALE)_[A-Z_]+=\S+", F)),
100
+ ("anthropic_key", re.compile(r"\bsk-ant-[A-Za-z0-9_-]{32,}\b", F)),
101
+ ("openai_key", re.compile(r"\bsk-(proj-)?[A-Za-z0-9_-]{20,}\b", F)),
102
+ ("supabase_pat", re.compile(r"\bsbp_[a-z0-9]{20,}\b|\b(sb_secret|sb_publishable)_[A-Za-z0-9]{20,}\b", F)),
103
+ # PEM header broadened to catch ENCRYPTED / SSH2 / any [A-Z0-9 ]* qualifier.
104
+ ("pem_private_key", re.compile(r"-----BEGIN [A-Z0-9 ]*PRIVATE KEY-----", F)),
105
+ # New Soleur crown-jewel classes (distinctive prefixes, low false-positive). Doppler token kinds:
106
+ # service (st), personal (pt), CLI (ct), service-account (sa), scim, audit. Slack token kinds:
107
+ # bot/user/app/refresh/legacy (baprs) + config (c) + config-refresh (e).
108
+ ("doppler_token", re.compile(r"\bdp\.(st|pt|ct|sa|scim|audit)\.[A-Za-z0-9._-]{16,}", F)),
109
+ ("slack_token", re.compile(r"\bxox[baprsce]-[A-Za-z0-9-]{10,}", F)),
110
+ # Cloudflare API tokens are exactly 40 chars of [A-Za-z0-9_-] with NO vendor prefix (#6045 item 6).
111
+ # A 40-char lowercase-hex git SHA collides on length (incident PIRs cite SHAs constantly), so the
112
+ # class carries an anti-SHA PREDICATE (below) requiring BOTH an uppercase letter AND a digit. Explicit
113
+ # non-class boundaries (lookaround), NOT \b — '-' is a non-word char and \b mis-anchors at token ends.
114
+ # The boundary ALSO rejects `+` / `/` / `=` adjacency (base64 specials) so a 40-char SEGMENT of a
115
+ # standard-base64 blob (split by +//) does not fire — that FP fail-closes a legitimate embedded asset
116
+ # (#6045 review F4). Real tokens sit on whitespace / quote / colon boundaries; the `=`-prefixed env-var
117
+ # case (`CLOUDFLARE_*_TOKEN=…`) is already caught by the env_var class.
118
+ ("cloudflare_token", re.compile(r"(?<![A-Za-z0-9_+/=-])[A-Za-z0-9_-]{40}(?![A-Za-z0-9_+/=-])", F)),
119
+ ]
120
+
121
+ # Per-class post-match predicates: a match is kept only if the predicate returns truthy. The bare-length
122
+ # Cloudflare class must be gated or it fires on a 40-char lowercase-hex git SHA and 40-char kebab prose.
123
+ # A real CF API token is high-entropy base64url, so require BOTH an uppercase letter AND a digit — hex
124
+ # SHAs have no uppercase; kebab prose has neither. Deliberate ~0.1% miss (a real token lacking a digit or
125
+ # uppercase) to preserve the engine's low-false-positive posture. No entry = always kept. Shared by the
126
+ # base pass and the decoded-content pass so the gate cannot be bypassed via an encoded blob.
127
+ PREDICATES = {
128
+ "cloudflare_token": lambda t: bool(re.search(r"[A-Z]", t)) and bool(re.search(r"[0-9]", t)),
129
+ }
130
+
131
+ PAT_BY_NAME = dict(PATTERNS)
132
+
133
+ # #6045 item 1 — whitespace / newline token-splitting re-scan. strip() KEEPS meaningful whitespace (a
134
+ # documented non-goal of the base pass), so a secret reflowed across a line break by a markdown/PDF
135
+ # renderer survives normalization. For each DISTINCTIVE-prefix class, locate the prefix at a real word
136
+ # boundary and rejoin the token across a BOUNDED number of whitespace runs (a reflowed token is split a
137
+ # few times by a renderer; prose has a whitespace run every few chars, so the bound admits reflow and
138
+ # rejects prose). Excludes the short/ambiguous openai `sk-` prefix and the prefixless Cloudflare class.
139
+ # REFLOW_PREFIXES keys MUST be PATTERNS names (asserted at import — no silent drift).
140
+ REFLOW_WINDOW = 512 # ~2.5x the longest anchored body; a 4096 window would be wasted work.
141
+ _MAX_REFLOW_SPLITS = 4 # rejoin across at most 4 whitespace runs — a reflowed token wrapped a
142
+ # few times is caught; prose (a run every few chars) never reaches a
143
+ # class's min length within 4 joins, so it is rejected (no manufactured FP).
144
+ _MAX_REFLOW_CANDIDATES = 4000 # cap prefix occurrences per class so a prefix-flooded 1 MiB input stays
145
+ # linear (code-to-prd scans attacker-controlled rendered text). Safe only
146
+ # while the 1 MiB MAX input cap dominates; re-evaluate if MAX is raised.
147
+ REFLOW_PREFIXES = {
148
+ "JWT": re.compile(r"eyJ", F),
149
+ "stripe_key": re.compile(r"(sk|pk|rk)_(live|test)_", F),
150
+ "stripe_whsec": re.compile(r"whsec_", F),
151
+ "stripe_acct": re.compile(r"acct_", F),
152
+ "github_token": re.compile(r"(gh[pousr]_|github_pat_)", F),
153
+ "anthropic_key": re.compile(r"sk-ant-", F),
154
+ "supabase_pat": re.compile(r"(sbp_|sb_secret_|sb_publishable_)", F),
155
+ "doppler_token": re.compile(r"dp\.(st|pt|ct|sa|scim|audit)\.", F),
156
+ "slack_token": re.compile(r"xox[baprsce]-", F),
157
+ }
158
+ assert set(REFLOW_PREFIXES) <= {n for n, _ in PATTERNS}, "REFLOW_PREFIXES has an unknown class name"
159
+
160
+
161
+ def _is_word(ch):
162
+ # ASCII word char (matches re.ASCII \w): [A-Za-z0-9_]. Confirms a real boundary before a prefix.
163
+ return ch == "_" or (ch.isascii() and ch.isalnum())
164
+
165
+
166
+ def _meta_redact(t):
167
+ # Never emit a full token. Cap the revealed entropy — finding lines hit the transcript.
168
+ if len(t) > 24:
169
+ return f"{t[:4]}***{t[-4:]}"
170
+ if len(t) > 12:
171
+ return f"{t[:4]}***"
172
+ return "***"
173
+
174
+
175
+ def _emit(name, value, offset, tag, seen):
176
+ # Dedup on (class, raw value) so a token found by the base pass is not re-reported by the reflow /
177
+ # decode passes. Offsets are NOT part of the key — base-pass offsets are norm-space, derived-pass
178
+ # offsets are decoded-space, so they are not comparable; dedup affects finding-line noise only, never
179
+ # the exit code. The tag note ALWAYS starts with " (" so the parity grep 'matched pattern [A-Za-z_]+'
180
+ # (which stops at the space) never absorbs it. Returns 1 on a new emit, 0 on a dedup hit.
181
+ key = (name, value)
182
+ if key in seen:
183
+ return 0
184
+ seen.add(key)
185
+ note = f" ({tag})" if tag else ""
186
+ print(f"at offset {offset}: {_meta_redact(value)} matched pattern {name}{note}")
187
+ return 1
188
+
189
+
190
+ def _scan_reflow(norm, seen):
191
+ hits = 0
192
+ for name, prefix_rx in REFLOW_PREFIXES.items():
193
+ full_rx = PAT_BY_NAME[name]
194
+ count = 0
195
+ for pm in prefix_rx.finditer(norm):
196
+ count += 1
197
+ if count > _MAX_REFLOW_CANDIDATES:
198
+ break # bound total prefix occurrences EXAMINED per class (incremented before the skips)
199
+ p = pm.start()
200
+ if p > 0 and _is_word(norm[p - 1]):
201
+ continue # interior substring, not a real boundary — would fabricate a match
202
+ window = norm[p : p + REFLOW_WINDOW]
203
+ parts = re.split(r"\s+", window, maxsplit=_MAX_REFLOW_SPLITS)
204
+ if len(parts) < 2:
205
+ continue # no whitespace in window — the base pass already saw this exact run
206
+ # If the split cap was hit (len == _MAX_REFLOW_SPLITS+1), the last element is an unbounded
207
+ # prose remainder — drop it so prose cannot be glued into a spurious token. A token split at
208
+ # more than _MAX_REFLOW_SPLITS points is missed — a recorded residual (ADR-095). Joining
209
+ # removes the whitespace separators, so the candidate is always shorter than the window.
210
+ joinable = parts[:-1] if len(parts) == _MAX_REFLOW_SPLITS + 1 else parts
211
+ m = full_rx.match("".join(joinable))
212
+ if m:
213
+ hits += _emit(name, m.group(0), p, "whitespace-rejoin", seen)
214
+ return hits
215
+
216
+
217
+ # #6045 items 2 & 3 — reversibly-encoded secrets + headerless-PEM private-key body.
218
+ # Classes EXCLUDED from the decoded-content re-scan: weakly-anchored classes manufacture false positives
219
+ # on decoded high-entropy bytes (an IPv4/UUID/email surfacing INSIDE decoded bytes is far likelier a false
220
+ # positive than a real leak — over-redaction fail-closes a legitimate write). cloudflare_token (bare 40-char
221
+ # + predicate) is likewise excluded — a base64 blob is routinely 40 chars.
222
+ _DECODE_SKIP = {"IPv4", "UUID", "email", "cloudflare_token"}
223
+ # Bounds on the decode fan-out: the 1 MiB MAX input cap already bounds total input; these keep adversarial
224
+ # input (many candidate blobs) linear. Safe ONLY while MAX dominates — re-evaluate if MAX is raised.
225
+ _MAX_ENCODED_CANDIDATES = 4000
226
+ _MAX_CANDIDATE_LEN = 200000
227
+
228
+
229
+ def _b64_decode(s):
230
+ # Try standard then url-safe base64; tolerate missing padding. None on failure (never raises).
231
+ for alt in (s, s.replace("-", "+").replace("_", "/")):
232
+ body = alt.rstrip("=")
233
+ try:
234
+ decoded = base64.b64decode(body + "=" * ((-len(body)) % 4), validate=True)
235
+ except (binascii.Error, ValueError):
236
+ decoded = None # a per-candidate decode probe: most candidates are not base64 (ADR-095, 2026-07-06 amendment item 2: decode errors are swallowed, never bubble to exit 2)
237
+ if decoded is not None:
238
+ return decoded
239
+ return None
240
+
241
+
242
+ def _is_der_private_key(raw):
243
+ # #6045 item 3. True iff `raw` looks like an UNENCRYPTED private-key body: an outer DER SEQUENCE whose
244
+ # FIRST inner element is an INTEGER (the version field of PKCS#1 / SEC1 / PKCS#8). A cert / SPKI /
245
+ # EncryptedPrivateKeyInfo opens with an inner SEQUENCE and is REJECTED — those are public/encrypted
246
+ # material and flagging them would fail-close a legitimate write (a public cert in a legal draft is fine).
247
+ # Handles BOTH short-form (EC ~118B, Ed25519 ~48-85B) and long-form (RSA >=128B) length encodings; a
248
+ # long-form-only check would silently miss EC/Ed25519. Residual gap: EncryptedPrivateKeyInfo (inner
249
+ # SEQUENCE) is not caught — a named non-goal recorded in ADR-095. Floor guards tiny innocent DER.
250
+ if len(raw) < 48 or raw[0] != 0x30:
251
+ return False
252
+ lb = raw[1]
253
+ if lb < 0x80:
254
+ content_start = 2
255
+ elif lb in (0x81, 0x82, 0x83, 0x84):
256
+ content_start = 2 + (lb - 0x80)
257
+ else:
258
+ return False
259
+ return content_start < len(raw) and raw[content_start] == 0x02
260
+
261
+
262
+ def _scan_text(text, offset, tag, seen):
263
+ # Re-run only the vendor-prefix/format-ANCHORED secret classes over a derived string (a decoded blob).
264
+ # _DECODE_SKIP excludes the weakly-anchored classes that FP on decoded high-entropy bytes.
265
+ hits = 0
266
+ for name, rx in PATTERNS:
267
+ if name in _DECODE_SKIP:
268
+ continue
269
+ pred = PREDICATES.get(name)
270
+ for m in rx.finditer(text):
271
+ val = m.group(0)
272
+ if pred and not pred(val):
273
+ continue
274
+ hits += _emit(name, val, offset, tag, seen)
275
+ return hits
276
+
277
+
278
+ def _mostly_text(raw):
279
+ # Only re-scan decoded content that is plausibly TEXT. A real base64/hex-encoded secret decodes to
280
+ # printable text; a legitimate embedded BINARY asset (font/wasm/image) decodes to bytes that can carry
281
+ # an INCIDENTAL short-anchored run (e.g. `sk-…`, `whsec_…`) and manufacture a false positive that
282
+ # fail-closes the write (#6045 review F4). A private-key body is binary but is handled by the DER check
283
+ # BEFORE this gate. Empty → not text.
284
+ if not raw:
285
+ return False
286
+ printable = sum(1 for b in raw if 0x20 <= b < 0x7F or b in (0x09, 0x0A, 0x0D))
287
+ return printable / len(raw) >= 0.85
288
+
289
+
290
+ def _scan_encoded(norm, seen):
291
+ hits = 0
292
+ candidates = [] # (blob, offset)
293
+ # (1) single-line / inline base64 runs (inline blobs).
294
+ for m in re.finditer(r"[A-Za-z0-9+/_-]{24,}={0,2}", norm):
295
+ candidates.append((m.group(0), m.start()))
296
+ # (2) multi-line base64 BLOCKS: consecutive whole-line base64 joined into one blob — real PEM/DER
297
+ # bodies are 64-char line-wrapped, and k8s Secret / Helm `data:` values are INDENTED, so `.strip()`
298
+ # each line (not just rstrip) before the fullmatch or an indented wrapped body never assembles.
299
+ block_lines = []
300
+ block_off = None
301
+ pos = 0
302
+ for line in norm.splitlines(keepends=True):
303
+ stripped = line.strip()
304
+ if re.fullmatch(r"[A-Za-z0-9+/_-]{16,}={0,2}", stripped):
305
+ if not block_lines:
306
+ block_off = pos
307
+ block_lines.append(stripped)
308
+ else:
309
+ if len(block_lines) >= 2:
310
+ candidates.append(("".join(block_lines), block_off))
311
+ block_lines = []
312
+ pos += len(line)
313
+ if len(block_lines) >= 2:
314
+ candidates.append(("".join(block_lines), block_off))
315
+
316
+ b64_count = 0
317
+ for blob, off in candidates:
318
+ if b64_count >= _MAX_ENCODED_CANDIDATES:
319
+ break
320
+ if len(blob) > _MAX_CANDIDATE_LEN:
321
+ continue
322
+ b64_count += 1
323
+ raw = _b64_decode(blob) # never raises — returns None on failure (no exit-2 bubble)
324
+ if raw is None:
325
+ continue
326
+ if _is_der_private_key(raw): # binary key body — DER-checked BEFORE the text gate
327
+ hits += _emit("pem_key_body", blob, off, "headerless-PEM-DER", seen)
328
+ if _mostly_text(raw):
329
+ hits += _scan_text(raw.decode("utf-8", "replace"), off, "decoded base64", seen)
330
+ # hex runs (even length only — an odd run cannot be whole bytes).
331
+ hex_count = 0
332
+ for m in re.finditer(r"\b[0-9A-Fa-f]{32,}\b", norm):
333
+ if hex_count >= _MAX_ENCODED_CANDIDATES:
334
+ break
335
+ blob = m.group(0)
336
+ if len(blob) % 2 or len(blob) > _MAX_CANDIDATE_LEN:
337
+ continue
338
+ hex_count += 1
339
+ try:
340
+ raw = bytes.fromhex(blob)
341
+ except ValueError:
342
+ raw = None # defensive: the regex and the parity filter above leave only valid even-length hex, so this does not fire today (ADR-095, 2026-07-06 amendment item 2: decode errors never bubble to exit 2)
343
+ if raw is None:
344
+ continue
345
+ if _mostly_text(raw):
346
+ hits += _scan_text(raw.decode("utf-8", "replace"), m.start(), "decoded hex", seen)
347
+ # percent-encoding: unquote once over the normalized text (bounded like the base64/hex paths; a
348
+ # >_MAX_CANDIDATE_LEN document skips the decoded layer — its raw form is still scanned by the base pass).
349
+ if re.search(r"%[0-9A-Fa-f]{2}", norm) and len(norm) <= _MAX_CANDIDATE_LEN:
350
+ decoded = urllib.parse.unquote(norm)
351
+ if decoded != norm:
352
+ hits += _scan_text(decoded, 0, "decoded percent", seen)
353
+ return hits
354
+
355
+
356
+ def scan(path):
357
+ if not os.path.isfile(path) or not os.access(path, os.R_OK):
358
+ sys.stderr.write(f"redact-engine: file not readable: {path}\n")
359
+ return 2
360
+ with open(path, "rb") as fh:
361
+ raw = fh.read()
362
+ if len(raw) > MAX:
363
+ print(f"SYNTHETIC HIGH: input exceeds {MAX} bytes ({len(raw)}) — fail closed")
364
+ return 1
365
+ stripped = raw.decode("utf-8", "replace").translate(STRIP)
366
+ # strip -> NFKC -> strip again: NFKC can FOLD a compatibility character into a strippable one that
367
+ # was not present in the raw input — e.g. U+FFA0 (halfwidth Hangul filler) -> U+1160 (Hangul filler,
368
+ # in STRIP). The second strip closes that re-opened splitter; it is idempotent on already-clean text.
369
+ # Then the targeted confusable fold.
370
+ norm = unicodedata.normalize("NFKC", stripped).translate(STRIP).translate(CONFUSABLE_MAP)
371
+ if len(norm.encode("utf-8")) > MAX: # post-NFKC re-check (NFKC can expand 1 cp -> up to 18)
372
+ print(f"SYNTHETIC HIGH: normalized input exceeds {MAX} bytes — fail closed")
373
+ return 1
374
+ seen = set()
375
+ hits = 0
376
+ # Base pass over the whole normalized string (real offsets). PREDICATES gate the bare-length classes.
377
+ for name, rx in PATTERNS:
378
+ pred = PREDICATES.get(name)
379
+ for m in rx.finditer(norm):
380
+ val = m.group(0)
381
+ if pred and not pred(val):
382
+ continue
383
+ hits += _emit(name, val, m.start(), "", seen)
384
+ hits += _scan_reflow(norm, seen) # #6045 item 1 — whitespace/newline token-splitting re-scan
385
+ hits += _scan_encoded(norm, seen) # #6045 items 2 & 3 — reversibly-encoded + headerless-PEM DER body
386
+ return 1 if hits else 0
387
+
388
+
389
+ def main():
390
+ if len(sys.argv) != 2:
391
+ sys.stderr.write("usage: redact-engine.py <path>\n")
392
+ return 2
393
+ try:
394
+ return scan(sys.argv[1])
395
+ except Exception as e: # any engine crash = cannot-evaluate, fail closed
396
+ tb, own, last = e.__traceback__, None, None
397
+ while tb is not None:
398
+ last = tb
399
+ if tb.tb_frame.f_code.co_filename == __file__:
400
+ own = tb
401
+ tb = tb.tb_next
402
+ tb = own or last
403
+ where = "" if tb is None else " at %s:%s" % (tb.tb_frame.f_code.co_name, tb.tb_lineno)
404
+ # class name and innermost frame in this file only: exception text can carry scanned content (mirrors founder-check _locator)
405
+ # a closed stderr (None when fd 2 is closed) must not turn the fail-closed rc 2 into an uncaught crash (rc 1 reads as "redaction needed")
406
+ with contextlib.suppress(OSError, ValueError, AttributeError):
407
+ sys.stderr.write(f"redact-engine: internal error: {type(e).__name__}{where}\n")
408
+ return 2
409
+
410
+
411
+ if __name__ == "__main__":
412
+ sys.exit(main())
@@ -0,0 +1,44 @@
1
+ #!/usr/bin/env bash
2
+ # Pre-write redaction sentinel for /soleur:incident, code-to-prd Layer 2, and the
3
+ # legal-generate gate. Thin shim (#5987) — the engine is now redact-engine.py.
4
+ #
5
+ # Contract preserved 1:1 (argv, exit codes, output shape) so all consumers are unchanged:
6
+ # 0 = clean — no matches found
7
+ # 1 = redaction needed — at least one match found (incl. synthetic HIGH on oversize input)
8
+ # 2 = cannot-evaluate — missing/unreadable file, no python3, engine crash, or any non-{0,1,2}
9
+ #
10
+ # Output format (per FR3, now capped by the engine's meta-redaction — never a full token):
11
+ # at offset N: <=4-prefix>***<=4-suffix> matched pattern <class>
12
+ #
13
+ # Exit is NORMALIZED to {0,1,2}: any engine-cannot-run/unexpected code -> 2 (cannot-evaluate),
14
+ # which every consumer already treats as fail-closed (code-to-prd Layer 2, incident Phase 6,
15
+ # dry-run any-nonzero). python3 absent -> 2 (NOT 1: exit 1 means "matches found", which would give
16
+ # a false "secrets found" message and trap the incident operator in an unsatisfiable redact loop).
17
+ #
18
+ # The hardened engine defeats compatibility-char / invisible / bidi / control / invalid-byte /
19
+ # soft-hyphen / prefix-homoglyph evasion (matching runs over strip -> NFKC -> strip -> confusable-fold;
20
+ # invisibles are stripped by Unicode category, not a hand-picked list), whitespace / newline
21
+ # token-splitting (#6045 item 1 — bounded-rejoin re-scan), the bare Cloudflare 40-char token class
22
+ # (#6045 item 6), reversibly-encoded secrets (base64/hex/percent decode + block assembly, #6045 item 2),
23
+ # and a headerless-PEM private-key DER body (#6045 item 3). It does NOT defeat the full cross-script
24
+ # homoglyph space (TR39 skeleton), an EncryptedPrivateKeyInfo body, MULTIPLY-encoded secrets (decode is
25
+ # single-level), a token reflowed across >4 whitespace runs, or unprefixed/high-entropy tokens — each a
26
+ # named non-goal / recorded residual (see ADR-095).
27
+ set -uo pipefail
28
+
29
+ DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
30
+
31
+ command -v python3 >/dev/null 2>&1 || {
32
+ echo "redact-sentinel: python3 not found — failing closed (exit 2)." >&2
33
+ exit 2
34
+ }
35
+
36
+ python3 "${DIR}/redact-engine.py" "$@"
37
+ rc=$?
38
+ case "${rc}" in
39
+ 0 | 1 | 2) exit "${rc}" ;;
40
+ *)
41
+ echo "redact-sentinel: engine exit ${rc} normalized to 2 (cannot-evaluate)." >&2
42
+ exit 2
43
+ ;;
44
+ esac
@@ -0,0 +1,139 @@
1
+ ---
2
+ title: "{{TITLE}}"
3
+ date: {{DATE}}
4
+ incident_pr: {{INCIDENT_PR}}
5
+ incident_window: "{{INCIDENT_WINDOW}}"
6
+ recovery_at: "{{RECOVERY_AT}}"
7
+ suspected_change: "{{SUSPECTED_CHANGE}}"
8
+ brand_survival_threshold: {{BRAND_SURVIVAL_THRESHOLD}}
9
+ status: {{STATUS}}
10
+ triggers:
11
+ {{TRIGGERS_LIST}}
12
+ art_33_triggered: {{ART_33_TRIGGERED}}
13
+ art_34_triggered: {{ART_34_TRIGGERED}}
14
+ art_33_deadline: "{{ART_33_DEADLINE}}"
15
+ {{CLASSIFICATION_OVERRIDE_BLOCK}}
16
+ ---
17
+
18
+ ## Actor key
19
+
20
+ - `agent` — Claude Code did this autonomously (no operator ack required).
21
+ - `agent-with-ack` — Claude Code did this AFTER operator confirmed via menu option per `hr-menu-option-ack-not-prod-write-auth`.
22
+ - `human` — Operator did this directly.
23
+
24
+ {{SECRET_LEAK_PREAMBLE}}
25
+
26
+ # Incident Overview
27
+
28
+ {{INCIDENT_OVERVIEW}}
29
+
30
+ ## Status
31
+
32
+ {{STATUS}} — one of `resolved` / `unresolved but ended` / `ongoing`. Mirrors the `status:` frontmatter above; do not introduce a second source of truth.
33
+
34
+ ## Symptom
35
+
36
+ {{SYMPTOM}}
37
+
38
+ ## Incident Timeline
39
+
40
+ - **Start time (detected):** {{DETECTED_AT}}
41
+ - **End time (recovered):** {{RECOVERY_AT}}
42
+ - **Duration (MTTR):** {{MTTR}}
43
+
44
+ Order of events (load-bearing: the redaction sentinel scans this table; the Actor key feeds the Actor column):
45
+
46
+ | Actor | Time (UTC) | Action |
47
+ |---|---|---|
48
+ | human | {{DETECTED_AT}} | Incident detected. |
49
+
50
+ ## Participants and Systems Involved
51
+
52
+ {{PARTICIPANTS}}
53
+
54
+ ## Detection (+ MTTD)
55
+
56
+ - **How detected:** {{DETECTION_METHOD}} — monitoring system vs. external/manual report.
57
+ - **MTTD (mean time to detect):** {{MTTD}}
58
+
59
+ ## Triggered by
60
+
61
+ {{TRIGGERED_BY}} — one of user / system / market movement / provider.
62
+
63
+ ## Root-cause hypothesis (triage)
64
+
65
+ Triage-time competing hypotheses; the post-resolution final root cause lives in the 5-Whys section below.
66
+
67
+ | Hypothesis | Supporting evidence | Disconfirming evidence | Status |
68
+ |---|---|---|---|
69
+ | {{ROOT_CAUSE_HYPOTHESIS}} | TBD | TBD | TBD |
70
+
71
+ ## Resolution
72
+
73
+ {{RESOLUTION}}
74
+
75
+ ## Recovery verification
76
+
77
+ TBD — describe the artifact or probe proving recovery. Cite a green workflow run, dashboard screenshot, or query result.
78
+
79
+ ---
80
+
81
+ # Incident Post-Mortem Analysis
82
+
83
+ ## Root Cause(s) — 5-Whys
84
+
85
+ {{ROOT_CAUSE_5WHYS}}
86
+
87
+ ## Versions of Components
88
+
89
+ - **Version(s) that triggered the outage:** {{VERSION_TRIGGERED}}
90
+ - **Version(s) that restored the service:** {{VERSION_RESTORED}}
91
+
92
+ ## Impact details
93
+
94
+ ### Services Impacted
95
+
96
+ {{SERVICES_IMPACTED}}
97
+
98
+ ### Customer Impact (by role)
99
+
100
+ Per learning `2026-05-06-user-impact-section-by-role-not-surface.md` — enumerate by USER ROLE, not by surface. This is the canonical "Customer Impact"; do NOT add a second free-text Customer Impact block.
101
+
102
+ - Prospect: TBD
103
+ - Authenticated app user: TBD
104
+ - Legal-document signer: TBD
105
+ - Admin via Access: TBD
106
+ - Billing customer: TBD
107
+ - OAuth installation owner: TBD
108
+
109
+ ### Revenue Impact
110
+
111
+ {{REVENUE_IMPACT}}
112
+
113
+ ### Team Impact
114
+
115
+ {{TEAM_IMPACT}}
116
+
117
+ ## Lessons Learned
118
+
119
+ ### Where we got lucky
120
+
121
+ {{LUCKY}}
122
+
123
+ ### What went well
124
+
125
+ {{WENT_WELL}}
126
+
127
+ ### What went wrong
128
+
129
+ {{WENT_WRONG}}
130
+
131
+ ## Action Items & Follow-ups
132
+
133
+ Every action item and follow-up so this incident cannot recur (save logs, add tests, set up alerts, automation, documentation, code sweeps, PRs).
134
+
135
+ **Each row MUST cite a filed GitHub issue number.** A bare bullet or a `TBD`/`(none)` placeholder is not allowed — file the issue first (`gh issue create`, cross-referencing the source PR in the body), then record its number here. An item with no `#NNNN` is shelf-ware that rots the moment the session ends; the `/ship` Incident-PIR gate blocks merge on any item that lacks an issue reference. If there are genuinely zero follow-ups, write exactly `No action items — incident fully resolved in the source PR with no residual work.` as a line of its own, with no emphasis — the permitted no-item form is plain so that the markdown linter (MD049, emphasis-style) cannot restyle it; the `/ship` gate accepts the plain line (and the underscore/asterisk-wrapped spellings shipped before this template changed).
136
+
137
+ | Issue | Action | Status |
138
+ |---|---|---|
139
+ | #{{ACTION_ITEM_ISSUE}} | {{ACTION_ITEM_DESC}} | open |
@@ -0,0 +1,26 @@
1
+ {
2
+ "title": "Synthetic dashboard outage for dry-run",
3
+ "detected_at": "2026-05-14T10:00:00Z",
4
+ "recovery_at": "2026-05-14T10:20:00Z",
5
+ "monitoring_detected_at": "2026-05-14T10:05:00Z",
6
+ "detection_method": "monitoring",
7
+ "triggered_by": "system",
8
+ "symptom": "Synthetic incident: dashboard error.tsx renders blank for authenticated app users after deploy",
9
+ "incident_overview": "Synthetic: authenticated dashboard rendered the error boundary after a deploy; recovered by a follow-up build.",
10
+ "suspected_change": "PR #9999 (synthetic)",
11
+ "resolution": "Synthetic: triggered a new release build that re-inlined the corrected bundle; canary swap verified.",
12
+ "version_triggered": "soleur-web-platform synthetic v0.0.1 (PR #9999)",
13
+ "version_restored": "soleur-web-platform synthetic v0.0.2",
14
+ "participants": "Operator (single founder); systems: synthetic web-platform, synthetic canary harness",
15
+ "services_impacted": "Synthetic authenticated dashboard surface",
16
+ "revenue_impact": "Unknown / N/A (synthetic fixture)",
17
+ "team_impact": "Unknown / N/A (synthetic fixture)",
18
+ "affected_user_count": 1,
19
+ "brand_survival_threshold": "single-user incident",
20
+ "art_33": {
21
+ "data_categories_breached": [],
22
+ "risk_to_subjects": "none"
23
+ },
24
+ "triggers": ["dashboard error boundary", "module-load throw"],
25
+ "status": "open"
26
+ }
@@ -0,0 +1,26 @@
1
+ {
2
+ "title": "Synthetic api-key leak for dry-run",
3
+ "detected_at": "2026-05-14T10:00:00Z",
4
+ "recovery_at": "",
5
+ "monitoring_detected_at": "",
6
+ "detection_method": "external",
7
+ "triggered_by": "system",
8
+ "symptom": "Synthetic incident: STRIPE_SECRET_KEY committed to public repo via debug log",
9
+ "incident_overview": "Synthetic: a Stripe secret was committed to a public repo via a debug log line; revoke-first path exercised.",
10
+ "suspected_change": "PR #9998 (synthetic)",
11
+ "resolution": "Synthetic: revoked the leaked credential at the issuer, then rotated and re-deployed.",
12
+ "version_triggered": "soleur-web-platform synthetic v0.0.1 (PR #9998)",
13
+ "version_restored": "N/A — not yet restored",
14
+ "participants": "Operator (single founder); systems: synthetic web-platform, Stripe",
15
+ "services_impacted": "Synthetic billing credential surface",
16
+ "revenue_impact": "Unknown / N/A (synthetic fixture)",
17
+ "team_impact": "Unknown / N/A (synthetic fixture)",
18
+ "affected_user_count": 0,
19
+ "brand_survival_threshold": "single-user incident",
20
+ "art_33": {
21
+ "data_categories_breached": ["email", "userId"],
22
+ "risk_to_subjects": "high"
23
+ },
24
+ "triggers": ["api_key_leaked"],
25
+ "status": "open"
26
+ }