@1aboveio/skills 0.10.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 (397) hide show
  1. package/LICENSE +3 -0
  2. package/README.md +90 -0
  3. package/bin/1aboveio-skills.mjs +18 -0
  4. package/package.json +28 -0
  5. package/runtime/skills/distribution/generated/recipes.json +1189 -0
  6. package/runtime/skills/distribution/scripts/bundles.mjs +280 -0
  7. package/runtime/skills/engineering/engineering-runtime/scripts/main-module.mjs +80 -0
  8. package/skills/backend/airflow-dag-develop/LICENSE +3 -0
  9. package/skills/backend/airflow-dag-develop/SKILL.md +111 -0
  10. package/skills/backend/app-debug/LICENSE +3 -0
  11. package/skills/backend/app-debug/SKILL.md +109 -0
  12. package/skills/backend/app-debug/references/common-errors.md +128 -0
  13. package/skills/backend/python-backend/LICENSE +3 -0
  14. package/skills/backend/python-backend/SKILL.md +326 -0
  15. package/skills/cicd-pipeline/cloud-build/LICENSE +3 -0
  16. package/skills/cicd-pipeline/cloud-build/SKILL.md +707 -0
  17. package/skills/cicd-pipeline/cloud-debug/LICENSE +3 -0
  18. package/skills/cicd-pipeline/cloud-debug/SKILL.md +316 -0
  19. package/skills/cicd-pipeline/cloud-debug/references/build-failures.md +238 -0
  20. package/skills/cicd-pipeline/cloud-debug/references/deploy-failures.md +376 -0
  21. package/skills/cicd-pipeline/cloud-debug/references/pipeline-failures.md +378 -0
  22. package/skills/cicd-pipeline/cloud-deploy/LICENSE +3 -0
  23. package/skills/cicd-pipeline/cloud-deploy/SKILL.md +229 -0
  24. package/skills/cicd-pipeline/cloud-deploy/references/config-templates.md +257 -0
  25. package/skills/cicd-pipeline/docker/LICENSE +3 -0
  26. package/skills/cicd-pipeline/docker/SKILL.md +126 -0
  27. package/skills/cicd-pipeline/google-cloud/LICENSE +3 -0
  28. package/skills/cicd-pipeline/google-cloud/SKILL.md +118 -0
  29. package/skills/cicd-pipeline/google-cloud/references/gcs.md +469 -0
  30. package/skills/cicd-pipeline/google-cloud/references/iam.md +451 -0
  31. package/skills/cicd-pipeline/google-cloud/references/project.md +349 -0
  32. package/skills/cicd-pipeline/google-cloud/references/secrets.md +336 -0
  33. package/skills/cicd-pipeline/google-cloud/references/vpc.md +312 -0
  34. package/skills/cicd-pipeline/google-cloud/scripts/create-sa.sh +36 -0
  35. package/skills/cicd-pipeline/google-cloud/scripts/gcp-config.sh +31 -0
  36. package/skills/cicd-pipeline/google-cloud/scripts/grant-iap.sh +41 -0
  37. package/skills/cicd-pipeline/google-cloud/scripts/setup-secrets.sh +48 -0
  38. package/skills/cicd-pipeline/mergify/LICENSE +3 -0
  39. package/skills/cicd-pipeline/mergify/SKILL.md +138 -0
  40. package/skills/cicd-pipeline/mergify/assets/templates/mergify.yml +237 -0
  41. package/skills/cicd-pipeline/mergify/assets/templates/ruleset.json +46 -0
  42. package/skills/cicd-pipeline/mergify/references/branch-protection.md +277 -0
  43. package/skills/cicd-pipeline/mergify/references/configuration.md +183 -0
  44. package/skills/cicd-pipeline/mergify/references/diagnosis.md +73 -0
  45. package/skills/cicd-pipeline/mergify/references/traps.md +78 -0
  46. package/skills/cicd-pipeline/mergify/references/watch-contract.md +218 -0
  47. package/skills/cicd-pipeline/mergify/scripts/audit-core.mjs +131 -0
  48. package/skills/cicd-pipeline/mergify/scripts/audit.mjs +4 -0
  49. package/skills/cicd-pipeline/mergify/scripts/watch-pr-delivery-core.mjs +663 -0
  50. package/skills/cicd-pipeline/mergify/scripts/watch-pr-delivery.mjs +4 -0
  51. package/skills/cicd-pipeline/podman/LICENSE +3 -0
  52. package/skills/cicd-pipeline/podman/SKILL.md +70 -0
  53. package/skills/cicd-pipeline/podman/agents/openai.yaml +4 -0
  54. package/skills/cicd-pipeline/podman/assets/templates/podman-compose-socket-directory.yml +6 -0
  55. package/skills/cicd-pipeline/podman/assets/templates/podman-service-override.conf +3 -0
  56. package/skills/cicd-pipeline/podman/references/compose-compatibility.md +70 -0
  57. package/skills/cicd-pipeline/podman/references/networking-and-ports.md +74 -0
  58. package/skills/cicd-pipeline/podman/references/rootless-services-and-sockets.md +156 -0
  59. package/skills/cicd-pipeline/podman/references/troubleshooting.md +98 -0
  60. package/skills/engineering/e2e-test/LICENSE +3 -0
  61. package/skills/engineering/e2e-test/SKILL.md +156 -0
  62. package/skills/engineering/e2e-test/assets/ci-gates.cloudbuild.yaml +272 -0
  63. package/skills/engineering/e2e-test/assets/ci-gates.github.yml +451 -0
  64. package/skills/engineering/e2e-test/assets/e2e-workflow.yml +282 -0
  65. package/skills/engineering/e2e-test/references/authoring/auth-flows.md +159 -0
  66. package/skills/engineering/e2e-test/references/authoring/playwright-config.md +71 -0
  67. package/skills/engineering/e2e-test/references/authoring/playwright-patterns.md +219 -0
  68. package/skills/engineering/e2e-test/references/authoring/test-skipping.md +44 -0
  69. package/skills/engineering/e2e-test/references/ci-integration.md +121 -0
  70. package/skills/engineering/e2e-test/references/ci-playwright-container.md +280 -0
  71. package/skills/engineering/e2e-test/references/debugging.md +36 -0
  72. package/skills/engineering/e2e-test/references/presentation-sweep.md +131 -0
  73. package/skills/engineering/e2e-test/references/reviewing.md +39 -0
  74. package/skills/engineering/e2e-test/references/route-discovery.md +50 -0
  75. package/skills/engineering/e2e-test/references/route-manifest.md +44 -0
  76. package/skills/engineering/e2e-test/scripts/detect-routes-fastapi.py +290 -0
  77. package/skills/engineering/e2e-test/scripts/detect-routes-nextjs.mjs +200 -0
  78. package/skills/engineering/e2e-test/scripts/post-visual-evidence.mjs +158 -0
  79. package/skills/engineering/e2e-test/scripts/presentation-checks.mjs +171 -0
  80. package/skills/engineering/e2e-test/scripts/presentation-perceivability.mjs +179 -0
  81. package/skills/engineering/e2e-test/scripts/presentation-reachability.mjs +154 -0
  82. package/skills/engineering/e2e-test/scripts/presentation-render-health.mjs +141 -0
  83. package/skills/engineering/e2e-test/scripts/presentation-sweep.mjs +148 -0
  84. package/skills/engineering/e2e-test/scripts/presentation-temporal.mjs +127 -0
  85. package/skills/engineering/e2e-test/scripts/presentation-visual.mjs +84 -0
  86. package/skills/engineering/e2e-test/scripts/project-route-manifest.mjs +75 -0
  87. package/skills/engineering/e2e-test/scripts/validate-manifest.mjs +106 -0
  88. package/skills/engineering/engineering-runtime/LICENSE +3 -0
  89. package/skills/engineering/engineering-runtime/SKILL.md +10 -0
  90. package/skills/engineering/engineering-runtime/agents/openai.yaml +6 -0
  91. package/skills/engineering/engineering-runtime/coherence/workflow.json +553 -0
  92. package/skills/engineering/engineering-runtime/scripts/exact-head-artifact.mjs +131 -0
  93. package/skills/engineering/engineering-runtime/scripts/head-check-set.mjs +398 -0
  94. package/skills/engineering/engineering-runtime/scripts/main-module.mjs +80 -0
  95. package/skills/engineering/engineering-runtime/scripts/mergify-yaml.mjs +11 -0
  96. package/skills/engineering/engineering-runtime/scripts/package-lock.json +43 -0
  97. package/skills/engineering/engineering-runtime/scripts/package.json +10 -0
  98. package/skills/engineering/engineering-runtime/scripts/required-check-plan.mjs +223 -0
  99. package/skills/engineering/engineering-runtime/scripts/workflow-coherence.mjs +576 -0
  100. package/skills/engineering/engineering-runtime/scripts/workflow-policy.mjs +166 -0
  101. package/skills/engineering/ensure-coverage/LICENSE +3 -0
  102. package/skills/engineering/ensure-coverage/SKILL.md +136 -0
  103. package/skills/engineering/ensure-coverage/evals/evals.json +125 -0
  104. package/skills/engineering/ensure-coverage/references/breadth/coverage-ledger.md +91 -0
  105. package/skills/engineering/ensure-coverage/references/breadth/inventory-contract.md +83 -0
  106. package/skills/engineering/ensure-coverage/references/breadth/surface-baseline.md +44 -0
  107. package/skills/engineering/ensure-coverage/references/breadth/surface-discovery.md +16 -0
  108. package/skills/engineering/ensure-coverage/references/depth/characterization.md +68 -0
  109. package/skills/engineering/ensure-coverage/references/depth/coverage.config.example.json +25 -0
  110. package/skills/engineering/ensure-coverage/references/depth/grading.md +35 -0
  111. package/skills/engineering/ensure-coverage/references/depth/mock-policy.md +87 -0
  112. package/skills/engineering/ensure-coverage/references/depth/test-smells.md +23 -0
  113. package/skills/engineering/ensure-coverage/references/enforcement/ci-contract.md +164 -0
  114. package/skills/engineering/ensure-coverage/references/enforcement/hooks.md +85 -0
  115. package/skills/engineering/ensure-coverage/references/examples/coverage-ledger.md +109 -0
  116. package/skills/engineering/ensure-coverage/references/examples/refund-flow.md +33 -0
  117. package/skills/engineering/ensure-coverage/references/presentation/axis.md +78 -0
  118. package/skills/engineering/ensure-coverage/references/presentation/runner-contract.md +74 -0
  119. package/skills/engineering/ensure-coverage/references/process/audit-mode.md +33 -0
  120. package/skills/engineering/ensure-coverage/references/process/output-template.md +139 -0
  121. package/skills/engineering/ensure-coverage/references/process/review-contract-template.md +119 -0
  122. package/skills/engineering/ensure-coverage/references/process/scope-class.md +178 -0
  123. package/skills/engineering/ensure-coverage/references/process/test-strategy.md +55 -0
  124. package/skills/engineering/ensure-coverage/schemas/coverage-config.schema.json +45 -0
  125. package/skills/engineering/ensure-coverage/schemas/coverage-file.schema.json +93 -0
  126. package/skills/engineering/ensure-coverage/scripts/adapters/nextjs-inventory.mjs +178 -0
  127. package/skills/engineering/ensure-coverage/scripts/check-quarantine-expiry.mjs +101 -0
  128. package/skills/engineering/ensure-coverage/scripts/ci-audit.mjs +358 -0
  129. package/skills/engineering/ensure-coverage/scripts/coverage-checklist.mjs +494 -0
  130. package/skills/engineering/ensure-coverage/scripts/coverage-ledger.mjs +663 -0
  131. package/skills/engineering/ensure-coverage/scripts/design-parity.mjs +591 -0
  132. package/skills/engineering/ensure-coverage/scripts/evidence-block.mjs +367 -0
  133. package/skills/engineering/ensure-coverage/scripts/lint-tests.mjs +269 -0
  134. package/skills/engineering/ensure-coverage/scripts/mock-policy-config.mjs +176 -0
  135. package/skills/engineering/ensure-coverage/scripts/package-lock.json +76 -0
  136. package/skills/engineering/ensure-coverage/scripts/package.json +19 -0
  137. package/skills/engineering/ensure-coverage/scripts/scope-class.mjs +554 -0
  138. package/skills/engineering/harness-runtime/LICENSE +3 -0
  139. package/skills/engineering/harness-runtime/SKILL.md +18 -0
  140. package/skills/engineering/harness-runtime/agents/openai.yaml +6 -0
  141. package/skills/engineering/harness-runtime/bin/discover-models.mjs +4 -0
  142. package/skills/engineering/harness-runtime/bin/model-catalog.mjs +4 -0
  143. package/skills/engineering/harness-runtime/contracts.md +15 -0
  144. package/skills/engineering/harness-runtime/discover-models.mjs +392 -0
  145. package/skills/engineering/harness-runtime/fixtures/native-question-schemas.json +33 -0
  146. package/skills/engineering/harness-runtime/fixtures/question-responses.json +54 -0
  147. package/skills/engineering/harness-runtime/index.mjs +767 -0
  148. package/skills/engineering/harness-runtime/model-catalog.mjs +787 -0
  149. package/skills/engineering/harness-runtime/native-question-contracts.md +37 -0
  150. package/skills/engineering/harness-runtime/references/model-catalog-seed.json +159 -0
  151. package/skills/engineering/harness-runtime/references/model-catalog.md +57 -0
  152. package/skills/engineering/implement-and-pr/LICENSE +3 -0
  153. package/skills/engineering/implement-and-pr/SKILL.md +176 -0
  154. package/skills/engineering/implement-and-pr/references/ci-iteration.md +10 -0
  155. package/skills/engineering/implement-and-pr/references/closeout.md +27 -0
  156. package/skills/engineering/implement-and-pr/references/contract-complete-fix-rounds.md +34 -0
  157. package/skills/engineering/implement-and-pr/references/evidence-rules.md +39 -0
  158. package/skills/engineering/implement-and-pr/references/incremental-plan.md +16 -0
  159. package/skills/engineering/implement-and-pr/references/self-review.md +23 -0
  160. package/skills/engineering/implement-and-pr/references/tdd-mode.md +18 -0
  161. package/skills/engineering/resolve-issues/LICENSE +3 -0
  162. package/skills/engineering/resolve-issues/SKILL.md +167 -0
  163. package/skills/engineering/resolve-issues/generated/workflow-repair-policy.json +448 -0
  164. package/skills/engineering/resolve-issues/references/breaker.md +82 -0
  165. package/skills/engineering/resolve-issues/references/deliverables.md +27 -0
  166. package/skills/engineering/resolve-issues/references/delivery.md +108 -0
  167. package/skills/engineering/resolve-issues/references/evidence-lane.md +21 -0
  168. package/skills/engineering/resolve-issues/references/exact-head-ci.md +287 -0
  169. package/skills/engineering/resolve-issues/references/fan-out.md +33 -0
  170. package/skills/engineering/resolve-issues/references/finalization.md +68 -0
  171. package/skills/engineering/resolve-issues/references/guarantees.md +10 -0
  172. package/skills/engineering/resolve-issues/references/high-risk.md +29 -0
  173. package/skills/engineering/resolve-issues/references/incidents/848/README.md +156 -0
  174. package/skills/engineering/resolve-issues/references/intake.md +86 -0
  175. package/skills/engineering/resolve-issues/references/integration-gate.md +53 -0
  176. package/skills/engineering/resolve-issues/references/interference.md +87 -0
  177. package/skills/engineering/resolve-issues/references/loop.md +134 -0
  178. package/skills/engineering/resolve-issues/references/model-catalog.md +9 -0
  179. package/skills/engineering/resolve-issues/references/postmortem.md +27 -0
  180. package/skills/engineering/resolve-issues/references/pre-flight-model-slots.md +41 -0
  181. package/skills/engineering/resolve-issues/references/pre-flight-recording-and-checkout.md +48 -0
  182. package/skills/engineering/resolve-issues/references/pre-flight.md +41 -0
  183. package/skills/engineering/resolve-issues/references/regression-checklist.md +26 -0
  184. package/skills/engineering/resolve-issues/references/run-state.md +288 -0
  185. package/skills/engineering/resolve-issues/references/sandboxed-testing.md +48 -0
  186. package/skills/engineering/resolve-issues/references/spawn-contract.md +96 -0
  187. package/skills/engineering/resolve-issues/references/terminal-evidence-journal.md +40 -0
  188. package/skills/engineering/resolve-issues/references/why.md +653 -0
  189. package/skills/engineering/resolve-issues/schemas/fix-round.schema.json +49 -0
  190. package/skills/engineering/resolve-issues/scripts/combine-and-verify.mjs +721 -0
  191. package/skills/engineering/resolve-issues/scripts/component-candidate.mjs +962 -0
  192. package/skills/engineering/resolve-issues/scripts/contract-revision.mjs +220 -0
  193. package/skills/engineering/resolve-issues/scripts/detect-delivery-mode.mjs +420 -0
  194. package/skills/engineering/resolve-issues/scripts/detect-target-branch.mjs +256 -0
  195. package/skills/engineering/resolve-issues/scripts/detect-workspace-mode.mjs +168 -0
  196. package/skills/engineering/resolve-issues/scripts/discover-models.mjs +9 -0
  197. package/skills/engineering/resolve-issues/scripts/doctrine.mjs +62 -0
  198. package/skills/engineering/resolve-issues/scripts/evidence-lifecycle-contract.mjs +191 -0
  199. package/skills/engineering/resolve-issues/scripts/exact-head-ci.mjs +413 -0
  200. package/skills/engineering/resolve-issues/scripts/exact-head-github-provider.mjs +332 -0
  201. package/skills/engineering/resolve-issues/scripts/finalize.mjs +488 -0
  202. package/skills/engineering/resolve-issues/scripts/fix-rounds.mjs +3307 -0
  203. package/skills/engineering/resolve-issues/scripts/fixtures/evidence-lifecycle-circular-1001.json +16 -0
  204. package/skills/engineering/resolve-issues/scripts/fixtures/evidence-lifecycle-valid-sequencing.json +51 -0
  205. package/skills/engineering/resolve-issues/scripts/fixtures/fmm-express-830-component-candidate.json +17 -0
  206. package/skills/engineering/resolve-issues/scripts/fixtures/head-check-set-1081.json +166 -0
  207. package/skills/engineering/resolve-issues/scripts/gate-value-series.mjs +92 -0
  208. package/skills/engineering/resolve-issues/scripts/guide-index.mjs +73 -0
  209. package/skills/engineering/resolve-issues/scripts/head-check-set.mjs +159 -0
  210. package/skills/engineering/resolve-issues/scripts/interference.mjs +427 -0
  211. package/skills/engineering/resolve-issues/scripts/model-catalog.mjs +9 -0
  212. package/skills/engineering/resolve-issues/scripts/next-operations.mjs +419 -0
  213. package/skills/engineering/resolve-issues/scripts/postmortem.mjs +909 -0
  214. package/skills/engineering/resolve-issues/scripts/preflight-questions.mjs +322 -0
  215. package/skills/engineering/resolve-issues/scripts/reconcile-contained-unit-prs.mjs +415 -0
  216. package/skills/engineering/resolve-issues/scripts/release-state-contract.mjs +697 -0
  217. package/skills/engineering/resolve-issues/scripts/report.mjs +494 -0
  218. package/skills/engineering/resolve-issues/scripts/required-check-plan.mjs +172 -0
  219. package/skills/engineering/resolve-issues/scripts/round-metadata.mjs +79 -0
  220. package/skills/engineering/resolve-issues/scripts/run-state-review6-cases.mjs +334 -0
  221. package/skills/engineering/resolve-issues/scripts/run-state.mjs +4784 -0
  222. package/skills/engineering/resolve-issues/scripts/sandbox-selftest.mjs +395 -0
  223. package/skills/engineering/resolve-issues/scripts/spawn-contract.mjs +290 -0
  224. package/skills/engineering/resolve-issues/scripts/terminal-dispositions.mjs +170 -0
  225. package/skills/engineering/resolve-issues/scripts/terminal-evidence-journal.mjs +293 -0
  226. package/skills/engineering/resolve-issues/scripts/unit-kind.mjs +197 -0
  227. package/skills/engineering/resolve-issues/scripts/unit-lifecycle.mjs +127 -0
  228. package/skills/engineering/resolve-issues/scripts/watch-delivery.mjs +893 -0
  229. package/skills/engineering/resolve-issues/scripts/workspaces.mjs +829 -0
  230. package/skills/engineering/resolve-issues/workflows/independent-review.workflow.js +290 -0
  231. package/skills/engineering/resolve-issues/workflows/prior-art-scan.workflow.js +80 -0
  232. package/skills/engineering/resolve-issues/workflows/workflow-smoke.mjs +102 -0
  233. package/skills/engineering/resolve-release/LICENSE +3 -0
  234. package/skills/engineering/resolve-release/SKILL.md +112 -0
  235. package/skills/engineering/resolve-release/references/assembly.md +137 -0
  236. package/skills/engineering/resolve-release/references/auto-when-green.md +56 -0
  237. package/skills/engineering/resolve-release/references/candidate.md +167 -0
  238. package/skills/engineering/resolve-release/references/exposure.md +178 -0
  239. package/skills/engineering/resolve-release/references/handoff.md +24 -0
  240. package/skills/engineering/resolve-release/references/postmortem.md +230 -0
  241. package/skills/engineering/resolve-release/references/preflight.md +207 -0
  242. package/skills/engineering/resolve-release/references/principles.md +94 -0
  243. package/skills/engineering/resolve-release/references/regression-checklist.md +36 -0
  244. package/skills/engineering/resolve-release/references/related-skills.md +12 -0
  245. package/skills/engineering/resolve-release/references/routing.md +149 -0
  246. package/skills/engineering/resolve-release/references/verified-sha-github-flow.md +285 -0
  247. package/skills/engineering/resolve-release/references/versioning.md +202 -0
  248. package/skills/engineering/resolve-release/references/why.md +53 -0
  249. package/skills/engineering/resolve-release/scripts/adapter-completion-artifact.mjs +389 -0
  250. package/skills/engineering/resolve-release/scripts/build-changes.mjs +209 -0
  251. package/skills/engineering/resolve-release/scripts/candidate-hygiene.mjs +407 -0
  252. package/skills/engineering/resolve-release/scripts/candidate-identity.mjs +904 -0
  253. package/skills/engineering/resolve-release/scripts/candidate-traffic.mjs +81 -0
  254. package/skills/engineering/resolve-release/scripts/checked-adapter-loader.mjs +612 -0
  255. package/skills/engineering/resolve-release/scripts/close-attempt.mjs +135 -0
  256. package/skills/engineering/resolve-release/scripts/closeout-release.mjs +161 -0
  257. package/skills/engineering/resolve-release/scripts/doctrine.mjs +106 -0
  258. package/skills/engineering/resolve-release/scripts/durable-processing.mjs +522 -0
  259. package/skills/engineering/resolve-release/scripts/ensure-target-green.mjs +659 -0
  260. package/skills/engineering/resolve-release/scripts/evidence-bundle.mjs +1014 -0
  261. package/skills/engineering/resolve-release/scripts/finalize-release.mjs +526 -0
  262. package/skills/engineering/resolve-release/scripts/fixtures/durable-processing-adapter.mjs +169 -0
  263. package/skills/engineering/resolve-release/scripts/green-gate.mjs +599 -0
  264. package/skills/engineering/resolve-release/scripts/isolated-adapter-evaluator.mjs +752 -0
  265. package/skills/engineering/resolve-release/scripts/metadata-pr-status.mjs +56 -0
  266. package/skills/engineering/resolve-release/scripts/metadata-sync.mjs +1538 -0
  267. package/skills/engineering/resolve-release/scripts/postmortem.mjs +381 -0
  268. package/skills/engineering/resolve-release/scripts/preflight-probes.mjs +498 -0
  269. package/skills/engineering/resolve-release/scripts/production-endpoints.mjs +326 -0
  270. package/skills/engineering/resolve-release/scripts/rc-circuit-breaker.mjs +272 -0
  271. package/skills/engineering/resolve-release/scripts/report.mjs +417 -0
  272. package/skills/engineering/resolve-release/scripts/reprobe-credentials.mjs +114 -0
  273. package/skills/engineering/resolve-release/scripts/revalidate-candidate.mjs +238 -0
  274. package/skills/engineering/resolve-release/scripts/review-packet.mjs +503 -0
  275. package/skills/engineering/resolve-release/scripts/rollback-floor.mjs +263 -0
  276. package/skills/engineering/resolve-release/scripts/version-assert.mjs +339 -0
  277. package/skills/engineering/resolve-release/scripts/version-postmortem.mjs +485 -0
  278. package/skills/engineering/resolve-release/scripts/version.mjs +1199 -0
  279. package/skills/engineering/resolve-release/scripts/watch-candidate-delivery.mjs +449 -0
  280. package/skills/engineering/resolve-release/vendor/ACORN-LICENSE +21 -0
  281. package/skills/engineering/resolve-release/vendor/README.md +60 -0
  282. package/skills/engineering/resolve-release/vendor/acorn.mjs +6233 -0
  283. package/skills/engineering/resolve-release/vendor/quickjs/core/LICENSE +21 -0
  284. package/skills/engineering/resolve-release/vendor/quickjs/core/README.md +341 -0
  285. package/skills/engineering/resolve-release/vendor/quickjs/core/README.template.md +70 -0
  286. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/chunk-TAV5CUKK.mjs +2 -0
  287. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/chunk-TAV5CUKK.mjs.map +1 -0
  288. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/chunk-V2S4ZYJR.mjs +7 -0
  289. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/chunk-V2S4ZYJR.mjs.map +1 -0
  290. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/index.d.mts +2033 -0
  291. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/index.d.ts +2033 -0
  292. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/index.js +7 -0
  293. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/index.js.map +1 -0
  294. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/index.mjs +2 -0
  295. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/index.mjs.map +1 -0
  296. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/module-ES6BEMUI.mjs +2 -0
  297. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/module-ES6BEMUI.mjs.map +1 -0
  298. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/module-asyncify-2EFITU5U.mjs +2 -0
  299. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/module-asyncify-2EFITU5U.mjs.map +1 -0
  300. package/skills/engineering/resolve-release/vendor/quickjs/core/package.json +49 -0
  301. package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/LICENSE +21 -0
  302. package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/README.md +5 -0
  303. package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/dist/index.d.mts +549 -0
  304. package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/dist/index.d.ts +549 -0
  305. package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/dist/index.js +2 -0
  306. package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/dist/index.js.map +1 -0
  307. package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/dist/index.mjs +2 -0
  308. package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/dist/index.mjs.map +1 -0
  309. package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/package.json +36 -0
  310. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/LICENSE +47 -0
  311. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/README.md +82 -0
  312. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.browser.d.ts +11 -0
  313. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.browser.mjs +22 -0
  314. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.cjs +21 -0
  315. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.cloudflare.cjs +21 -0
  316. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.cloudflare.d.ts +11 -0
  317. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.d.ts +11 -0
  318. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.mjs +25 -0
  319. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.wasm +0 -0
  320. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/ffi.d.mts +85 -0
  321. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/ffi.d.ts +85 -0
  322. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/ffi.js +2 -0
  323. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/ffi.js.map +1 -0
  324. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/ffi.mjs +2 -0
  325. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/ffi.mjs.map +1 -0
  326. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/index.d.mts +20 -0
  327. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/index.d.ts +20 -0
  328. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/index.js +2 -0
  329. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/index.js.map +1 -0
  330. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/index.mjs +2 -0
  331. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/index.mjs.map +1 -0
  332. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/package.json +61 -0
  333. package/skills/engineering/review-pr/LICENSE +3 -0
  334. package/skills/engineering/review-pr/SKILL.md +123 -0
  335. package/skills/engineering/review-pr/references/adversarial-reviewer-prompt.md +42 -0
  336. package/skills/engineering/review-pr/references/code-correctness.md +5 -0
  337. package/skills/engineering/review-pr/references/contract-freshness.md +9 -0
  338. package/skills/engineering/review-pr/references/coordination.md +18 -0
  339. package/skills/engineering/review-pr/references/domain-hazards.md +123 -0
  340. package/skills/engineering/review-pr/references/finding-themes.md +7 -0
  341. package/skills/engineering/review-pr/references/github-posting.md +98 -0
  342. package/skills/engineering/review-pr/references/golden-path-smoke.md +5 -0
  343. package/skills/engineering/review-pr/references/incremental-output.md +16 -0
  344. package/skills/engineering/review-pr/references/inputs-and-discovery.md +31 -0
  345. package/skills/engineering/review-pr/references/output-format.md +99 -0
  346. package/skills/engineering/review-pr/references/over-mock-screen.md +7 -0
  347. package/skills/engineering/review-pr/references/promotion-prs.md +16 -0
  348. package/skills/engineering/review-pr/references/re-review.md +18 -0
  349. package/skills/engineering/review-pr/references/review-method.md +199 -0
  350. package/skills/engineering/review-pr/references/review-mode.md +30 -0
  351. package/skills/engineering/review-pr/references/review-posture.md +53 -0
  352. package/skills/engineering/review-pr/references/round1-depth.md +62 -0
  353. package/skills/engineering/review-pr/references/scripts.md +17 -0
  354. package/skills/engineering/review-pr/references/workflow.md +16 -0
  355. package/skills/engineering/review-pr/schemas/findings.schema.json +282 -0
  356. package/skills/engineering/review-pr/scripts/finding-contract.mjs +285 -0
  357. package/skills/engineering/review-pr/scripts/post-review.mjs +405 -0
  358. package/skills/engineering/review-pr/scripts/pr-context.mjs +207 -0
  359. package/skills/engineering/review-pr/scripts/scan-diff.mjs +365 -0
  360. package/skills/engineering/review-pr/scripts/theme-contract.mjs +57 -0
  361. package/skills/engineering/smoke/LICENSE +3 -0
  362. package/skills/engineering/smoke/SKILL.md +131 -0
  363. package/skills/engineering/smoke/assets/smoke.manifest.example.json +53 -0
  364. package/skills/engineering/smoke/references/manifest.md +192 -0
  365. package/skills/engineering/smoke/scripts/smoke.mjs +713 -0
  366. package/skills/fullstack/better-auth/LICENSE +3 -0
  367. package/skills/fullstack/better-auth/SKILL.md +601 -0
  368. package/skills/fullstack/better-auth/references/feishu-api.md +270 -0
  369. package/skills/fullstack/monorepo/LICENSE +3 -0
  370. package/skills/fullstack/monorepo/SKILL.md +465 -0
  371. package/skills/fullstack/nextjs-fullstack/LICENSE +3 -0
  372. package/skills/fullstack/nextjs-fullstack/SKILL.md +210 -0
  373. package/skills/fullstack/nextjs-fullstack/conventions.md +318 -0
  374. package/skills/fullstack/nextjs-fullstack/frontend-conventions.md +61 -0
  375. package/skills/fullstack/nextjs-fullstack/nextjs16.md +287 -0
  376. package/skills/fullstack/nextjs-fullstack/server-actions.md +409 -0
  377. package/skills/fullstack/prisma-setup/LICENSE +3 -0
  378. package/skills/fullstack/prisma-setup/SKILL.md +180 -0
  379. package/skills/fullstack/prisma-setup/nextjs.md +258 -0
  380. package/skills/fullstack/prisma-setup/turborepo.md +301 -0
  381. package/skills/fullstack/shadcn/LICENSE +3 -0
  382. package/skills/fullstack/shadcn/SKILL.md +119 -0
  383. package/skills/fullstack/shadcn/assets/shadcn-small.png +0 -0
  384. package/skills/fullstack/shadcn/assets/shadcn.png +0 -0
  385. package/skills/fullstack/shadcn/cli.md +411 -0
  386. package/skills/fullstack/shadcn/customization.md +224 -0
  387. package/skills/fullstack/shadcn/evals/evals.json +90 -0
  388. package/skills/fullstack/shadcn/mcp.md +101 -0
  389. package/skills/fullstack/shadcn/rules/base-vs-radix.md +323 -0
  390. package/skills/fullstack/shadcn/rules/component-selection.md +67 -0
  391. package/skills/fullstack/shadcn/rules/composition.md +195 -0
  392. package/skills/fullstack/shadcn/rules/data-table.md +201 -0
  393. package/skills/fullstack/shadcn/rules/forms.md +255 -0
  394. package/skills/fullstack/shadcn/rules/icons.md +103 -0
  395. package/skills/fullstack/shadcn/rules/styling.md +167 -0
  396. package/skills/fullstack/zod-v4/LICENSE +3 -0
  397. package/skills/fullstack/zod-v4/SKILL.md +287 -0
@@ -0,0 +1,365 @@
1
+ // Cheap scan of a unified diff. It emits TWO channels, and the distinction is
2
+ // load-bearing:
3
+ // • LEADS (heuristic) — "look here and verify"; the reviewer reads the code and
4
+ // builds the counterexample before any becomes a finding (see review-method.md).
5
+ // • FINDINGS (decidable) — near-zero-false-positive checks that ARE blockers on
6
+ // their own. Currently: `over-mock-internal-seam` (a vi/jest.mock of a
7
+ // first-party seam = Over-mocked, zero-tolerance). This makes review-pr the
8
+ // standalone first line of enforcement — no dependency on ensure-coverage's
9
+ // gate being wired in the repo.
10
+ //
11
+ // git diff <merge-base>...HEAD | node scan-diff.mjs # leads + findings from stdin
12
+ // node scan-diff.mjs --diff changes.patch
13
+ //
14
+ // Best-effort and JS/TS-oriented (regex/branch heuristics are language-bound; the
15
+ // mock/interception checks are framework-specific). On other languages it simply
16
+ // finds fewer — it is additive, and absence means "the scanner found nothing,"
17
+ // not "the code is fine."
18
+
19
+ import fs from 'node:fs'
20
+ import path from 'node:path'
21
+ import { isMainModule } from '../../engineering-runtime/scripts/main-module.mjs'
22
+
23
+ // ---- pure core ----
24
+
25
+ // Parse a unified diff into added lines with their NEW-file line numbers.
26
+ export function parseAddedLines(diffText) {
27
+ const out = []
28
+ let file = null
29
+ let newLine = 0
30
+ for (const raw of (diffText || '').split(/\r?\n/)) {
31
+ if (raw.startsWith('+++ ')) {
32
+ const m = raw.match(/^\+\+\+ b\/(.+)$/)
33
+ file = m ? m[1] : raw.slice(4).replace(/^b\//, '')
34
+ continue
35
+ }
36
+ if (raw.startsWith('diff --git')) { file = null; continue }
37
+ const hm = raw.match(/^@@ -\d+(?:,\d+)? \+(\d+)(?:,\d+)? @@/)
38
+ if (hm) { newLine = parseInt(hm[1], 10); continue }
39
+ if (raw.startsWith('+')) { out.push({ file, line: newLine, text: raw.slice(1) }); newLine++; continue }
40
+ if (raw.startsWith('-')) continue // removed line: no advance in new file
41
+ if (raw.startsWith('\\')) continue // ""
42
+ newLine++ // context line
43
+ }
44
+ return out
45
+ }
46
+
47
+ const TEST_FILE = /\.(test|spec)\.[jt]sx?$/
48
+ const INTERCEPT = /\broute\.fulfill\b|\bpage\.route\s*\(|\bsetupServer\s*\(|\bsetupWorker\s*\(|from\s+['"]msw['"]/
49
+
50
+ export function interceptionLeads(added) {
51
+ return added
52
+ .filter((a) => a.file && TEST_FILE.test(a.file) && INTERCEPT.test(a.text))
53
+ .map((a) => ({ type: 'first-party-interception', file: a.file, line: a.line, snippet: a.text.trim(),
54
+ note: 'first-party interception in a test — over-mock risk; verify the real path is actually proven (browser/journey, not stub). Skip if: the route is a third-party/external boundary, or this is a Tier-2 functional failure-injection test (interception is correct there).' }))
55
+ }
56
+
57
+ // Regex literals / RegExp() added without ^ or $ anchors → boundary-leak risk.
58
+ export function regexLeads(added) {
59
+ const out = []
60
+ for (const a of added) {
61
+ for (const lit of a.text.match(/\/(?:[^/\n\\]|\\.){2,}\/[gimsuy]*/g) || []) {
62
+ const body = lit.replace(/\/[gimsuy]*$/, '').slice(1)
63
+ if (!/[\^$]/.test(body) && /[A-Za-z0-9]/.test(body)) {
64
+ out.push({ type: 'unanchored-pattern', file: a.file, line: a.line, snippet: lit,
65
+ note: 'regex without ^/$ anchors — verify prefix/substring leakage at boundaries (does /foo also match /foobar?). Skip if: inputs are a closed/validated set where leakage cannot occur, or a substring match is intended — produce the breaking input or drop it.' })
66
+ }
67
+ }
68
+ const re = a.text.match(/new RegExp\(([^)]*)\)/)
69
+ if (re && !/[\^$]/.test(re[1])) {
70
+ out.push({ type: 'unanchored-pattern', file: a.file, line: a.line, snippet: re[0].trim(),
71
+ note: 'RegExp without ^/$ — verify boundary behavior.' })
72
+ }
73
+ }
74
+ return out
75
+ }
76
+
77
+ // Weakened assertions in tests → a test that can't fail the way its name promises.
78
+ // Two tells from real "smoke wearing a journey label" specs:
79
+ // - `.catch(() => false)` (or null/undefined/0/'') swallows a locator/await throw
80
+ // into a falsy, defeating Playwright's web-first retry and any assertion on it.
81
+ // - `expect(a || b || c).toBeTruthy()` / `.toBe(true)` — a disjunctive truthiness
82
+ // assertion passes if ANY branch holds, so it pins down no specific behavior.
83
+ // Reviewer then checks the test's @level: a journey/functional test asserting only
84
+ // these is Wrong Level (review-method.md → Spec Compliance).
85
+ const CATCH_SWALLOW = /\.catch\s*\(\s*\(\s*\)\s*=>\s*(?:false|null|undefined|0|''|""|``)\s*\)/
86
+ const DISJUNCTIVE_TRUTHY = /\bexpect\s*\([^;]*\|\|[^;]*\)\s*\.\s*(?:toBeTruthy\b|toBe\s*\(\s*true\s*\))/
87
+ export function weakAssertionLeads(added) {
88
+ const out = []
89
+ for (const a of added) {
90
+ if (!a.file || !TEST_FILE.test(a.file)) continue
91
+ if (CATCH_SWALLOW.test(a.text)) out.push({ type: 'swallowed-assertion', file: a.file, line: a.line, snippet: a.text.trim(),
92
+ note: 'catch swallows a locator/await throw into a falsy — defeats web-first retry and hides real failures; assert directly (web-first expect), do not catch-to-false. Skip if: the falsy genuinely feeds a non-assertion control-flow decision and the real outcome is asserted separately.' })
93
+ if (DISJUNCTIVE_TRUTHY.test(a.text)) out.push({ type: 'weak-assertion', file: a.file, line: a.line, snippet: a.text.trim(),
94
+ note: 'disjunctive truthiness — passes if any branch holds, so it proves nothing specific; if this is a @level journey/functional test it is Wrong Level (drive the flow to a concrete outcome). Skip if: this is a @level render-health test (alias: smoke) where "renders at all" is the whole contract.' })
95
+ }
96
+ return out
97
+ }
98
+
99
+ // A test that *names itself* a race but reads state some earlier test already created
100
+ // cannot exercise the first-writer path: both "concurrent" callers take the
101
+ // already-exists early return, and the contended create never runs. The tell is a
102
+ // pre-existing capture (`x!.id`, `find*OrThrow`) reached before the `Promise.all`.
103
+ // Kept a LEAD, not a finding: post-seal/replay races legitimately look exactly like
104
+ // this. What makes it a defect is the test being cited as first-writer proof — a
105
+ // judgment about the AC mapping that no regex can make.
106
+ const ANY_TEST_TITLE = /\b(?:it|test)\s*(?:\.\w+)?\s*\(\s*['"`]/
107
+ const CONCURRENCY_TEST_TITLE = /\b(?:it|test)\s*(?:\.\w+)?\s*\(\s*['"`][^'"`]*\b(?:race|races|racing|concurrent|concurrently|simultaneous(?:ly)?|parallel)\b/i
108
+ const PREEXISTING_CAPTURE = /\w\s*!\s*\.\s*\w|\bfind(?:First|Unique)OrThrow\s*\(/
109
+ const CONCURRENT_CALL = /\bPromise\s*\.\s*(?:all|allSettled|race)\s*\(/
110
+
111
+ export function concurrencyFixtureLeads(added) {
112
+ const out = []
113
+ const byFile = new Map()
114
+ for (const a of added) {
115
+ if (!a.file || !TEST_FILE_ANY.test(a.file)) continue
116
+ if (!byFile.has(a.file)) byFile.set(a.file, [])
117
+ byFile.get(a.file).push(a)
118
+ }
119
+ for (const [, lines] of byFile) {
120
+ lines.sort((x, y) => x.line - y.line)
121
+ let title = null // the concurrency-named test we are inside
122
+ let capture = null // first pre-existing capture seen since that title
123
+ for (const a of lines) {
124
+ // Any test title closes the previous body. Tracking only concurrency titles
125
+ // would leave scope open across the rest of the file, so the next ordinary
126
+ // test's fixture would be attributed to a race test that already ended.
127
+ if (ANY_TEST_TITLE.test(a.text)) {
128
+ title = CONCURRENCY_TEST_TITLE.test(a.text) ? a : null
129
+ capture = null
130
+ continue
131
+ }
132
+ if (!title) continue
133
+ if (!capture && PREEXISTING_CAPTURE.test(a.text)) { capture = a; continue }
134
+ if (capture && CONCURRENT_CALL.test(a.text)) {
135
+ out.push({ type: 'concurrency-test-preexisting-fixture', file: capture.file, line: capture.line, snippet: capture.text.trim(),
136
+ note: `test named as a race/concurrent case reads pre-existing state before ${a.text.trim().slice(0, 40)}… — if that state is what the concurrent calls are supposed to be creating, every caller takes the already-exists path and the contended first-write is never exercised (a green test for an untested race). Verify the fixture starts from ABSENT, with independent clients/connections and a barrier. Skip if: this is deliberately a post-create replay/idempotency case AND a separate test covers the first-write race — then check that the AC cites that one, not this.` })
137
+ title = null; capture = null
138
+ }
139
+ }
140
+ }
141
+ return out
142
+ }
143
+
144
+ // New conditional branches → each needs a test (line coverage ≠ branch coverage).
145
+ export function branchLeads(added) {
146
+ return added
147
+ .filter((a) => /\b(if|else if|case)\b/.test(a.text) || /\?[^?]*:/.test(a.text))
148
+ .map((a) => ({ type: 'new-branch', file: a.file, line: a.line, snippet: a.text.trim(),
149
+ note: 'new branch — name a test that exercises it; line coverage is not branch coverage. Skip if: an integration/E2E test already drives it, or the branch is a trivial guard whose failure is inert.' }))
150
+ }
151
+
152
+ // Files whose EXISTING behavior is modified (edited/removed lines in a non-test
153
+ // SOURCE file) owe a characterization test pinning prior behavior before the
154
+ // change (ensure-coverage → depth/characterization.md). A new file or a test
155
+ // file is excluded; only changed/removed content in a non-test source file
156
+ // signals an existing-behavior modification. The *detection* is decidable; the
157
+ // adjudication ("is there an adequate @characterizes test, or a declared intended
158
+ // change?") is the reviewer's — hence a lead, not a finding.
159
+ const TEST_FILE_ANY = /\.(test|spec)\.[cm]?[jt]sx?$|(^|\/)(e2e|tests?|__tests__)\/|(^|\/)test_[^/]*\.py$|_test\.py$/
160
+ const NON_SOURCE = /\.(md|markdown|json|ya?ml|txt|lock|svg|png|jpe?g|gif|webp|ico|csv|tsv|toml|ini|cfg|snap)$/i
161
+
162
+ // Parse a diff into per-file change shape: { isNew, removed, added, firstLine }.
163
+ // `removed` counts changed/deleted content lines (the modify signal); a new file
164
+ // (--- /dev/null or `new file mode`) is flagged so it's treated as addition.
165
+ export function parseFileChanges(diffText) {
166
+ const files = new Map()
167
+ let file = null
168
+ let pendingNew = false
169
+ let newLine = 0
170
+ for (const raw of (diffText || '').split(/\r?\n/)) {
171
+ if (raw.startsWith('diff --git')) { file = null; pendingNew = false; continue }
172
+ if (raw.startsWith('new file mode')) { pendingNew = true; continue }
173
+ if (raw.startsWith('--- ')) { if (/\/dev\/null/.test(raw)) pendingNew = true; continue }
174
+ if (raw.startsWith('+++ ')) {
175
+ const m = raw.match(/^\+\+\+ (?:b\/)?(.+)$/)
176
+ file = m && m[1] !== '/dev/null' ? m[1] : null
177
+ if (file && !files.has(file)) files.set(file, { isNew: pendingNew, removed: 0, added: 0, firstLine: 0 })
178
+ pendingNew = false
179
+ continue
180
+ }
181
+ if (!file) continue
182
+ const hm = raw.match(/^@@ -\d+(?:,\d+)? \+(\d+)(?:,\d+)? @@/)
183
+ if (hm) { newLine = parseInt(hm[1], 10); continue }
184
+ const rec = files.get(file)
185
+ if (!rec) continue
186
+ if (raw.startsWith('-')) { rec.removed++; if (!rec.firstLine) rec.firstLine = newLine; continue } // no new-line advance
187
+ if (raw.startsWith('+')) { rec.added++; if (!rec.firstLine) rec.firstLine = newLine; newLine++; continue }
188
+ if (raw.startsWith('\\')) continue
189
+ newLine++ // context
190
+ }
191
+ return files
192
+ }
193
+
194
+ export function characterizationLeads(diffText) {
195
+ const out = []
196
+ for (const [file, rec] of parseFileChanges(diffText)) {
197
+ if (rec.isNew) continue // new file = new behavior, not a modification
198
+ if (TEST_FILE_ANY.test(file)) continue // editing tests is not modifying production behavior
199
+ if (NON_SOURCE.test(file)) continue // docs/config/snapshots carry no behavior to pin
200
+ if (rec.removed === 0) continue // pure addition into an existing file = added behavior
201
+ out.push({ type: 'modifies-existing-behavior', file, line: rec.firstLine || 1,
202
+ snippet: `${rec.removed} existing line(s) changed/removed`,
203
+ note: 'existing behavior modified — verify a characterization test pins the PRIOR behavior (authored to pass on the pre-change tree) so this diff is proven not to shift observable behavior unintentionally; tag it `// @characterizes <surface>`. Skip if: an existing behavior test already covers this exact path and still passes unchanged (cite it), this is a declared intended behavior change with its AC and the assertion delta is in the diff, or the edit is trivial/generated/non-behavioral. See ensure-coverage depth/characterization.md.' })
204
+ }
205
+ return out
206
+ }
207
+
208
+ // ---- VENDORED over-mock classifier — DECIDABLE FINDING, not a lead ----
209
+ //
210
+ // Self-contained copy of ensure-coverage's `mock-internal-seam` classifier
211
+ // (skills/engineering/ensure-coverage/scripts/mock-policy-config.mjs), vendored
212
+ // here so review-pr enforces no-over-mock with ZERO dependency on ensure-coverage
213
+ // being installed/wired. ensure-coverage stays CANONICAL: if the two diverge,
214
+ // ensure-coverage wins and this copy is stale → resync. Kept tiny on purpose.
215
+ //
216
+ // The "externals-allowlist inversion": you can't enumerate internal seams, but
217
+ // the legitimately-fakeable set (third-party/stdlib) is small and known — so a
218
+ // mock whose target resolves to first-party code is a seam (a defect), and the
219
+ // declared externals / stdlib / bare packages are exempt. Unlike the heuristic
220
+ // leads above this is DECIDABLE, so its hits are emitted as `findings`.
221
+
222
+ export const DEFAULT_MOCK_TOPOLOGY = {
223
+ firstPartyAliasPrefixes: ['@/', '~/'],
224
+ firstPartyPackages: [], // e.g. a monorepo's own scope '@acme/'
225
+ externals: [], // regex SOURCES for first-party-looking-but-external targets
226
+ testUtilHints: ['__mocks__', '__fixtures__', 'fixtures', 'mocks', 'helpers',
227
+ 'test-utils', 'testing', 'support', 'stubs', 'factories'],
228
+ }
229
+
230
+ // Best-effort read of coverage.config.json topology (so a monorepo's own @scope
231
+ // is recognized); never throws — defaults to conventional @/ ~/ when absent.
232
+ // Config declares TOPOLOGY only; it cannot disable the check (zero-tolerance).
233
+ export function loadMockTopology(cwd = process.cwd()) {
234
+ for (const name of ['coverage.config.json', '.coverage.config.json']) {
235
+ try {
236
+ const mp = (JSON.parse(fs.readFileSync(path.join(cwd, name), 'utf8')).mockPolicy) || {}
237
+ return {
238
+ firstPartyAliasPrefixes: mp.firstPartyAliasPrefixes ?? DEFAULT_MOCK_TOPOLOGY.firstPartyAliasPrefixes,
239
+ firstPartyPackages: mp.firstPartyPackages ?? DEFAULT_MOCK_TOPOLOGY.firstPartyPackages,
240
+ externals: mp.externals ?? DEFAULT_MOCK_TOPOLOGY.externals,
241
+ testUtilHints: mp.testUtilHints ?? DEFAULT_MOCK_TOPOLOGY.testUtilHints,
242
+ }
243
+ } catch { /* missing or malformed → try next, else defaults */ }
244
+ }
245
+ return { ...DEFAULT_MOCK_TOPOLOGY }
246
+ }
247
+
248
+ // Pull the mocked specifier from a vi/jest/vitest `.mock`/`.doMock(...)` call.
249
+ export function extractMockTarget(codeLine) {
250
+ const m = /\b(?:vi|jest|vitest)\s*\.\s*(?:mock|doMock)\s*\(\s*(['"`])([^'"`]+)\1/.exec(codeLine || '')
251
+ return m ? m[2] : null
252
+ }
253
+
254
+ // Classify a mock target as an internal seam (a defect) or an allowed external.
255
+ // Precedence: declared externals > stdlib > relative(util vs source) >
256
+ // first-party alias > first-party package > bare package (external default).
257
+ export function classifyMockTarget(target, topo = DEFAULT_MOCK_TOPOLOGY) {
258
+ if (!target) return { internal: false, reason: 'no target' }
259
+ for (const src of topo.externals || []) {
260
+ try { if (new RegExp(src).test(target)) return { internal: false, reason: 'declared external' } } catch { /* ignore bad regex */ }
261
+ }
262
+ if (target.startsWith('node:')) return { internal: false, reason: 'node builtin' }
263
+ if (target.startsWith('.')) {
264
+ if (target.split('/').some((s) => (topo.testUtilHints || []).includes(s))) return { internal: false, reason: 'relative test util/fixture/mock' }
265
+ return { internal: true, reason: 'relative import into first-party source' }
266
+ }
267
+ for (const pre of topo.firstPartyAliasPrefixes || []) {
268
+ if (target.startsWith(pre)) return { internal: true, reason: `first-party alias "${pre}"` }
269
+ }
270
+ for (const fp of topo.firstPartyPackages || []) {
271
+ const base = fp.endsWith('/') ? fp.slice(0, -1) : fp
272
+ if (target === base || target.startsWith(`${base}/`)) return { internal: true, reason: `first-party package "${fp}"` }
273
+ }
274
+ return { internal: false, reason: 'external package' }
275
+ }
276
+
277
+ // Diff-scoped over-mock FINDINGS: a vi/jest/vitest.mock of a first-party internal
278
+ // seam ADDED in a test file → Over-mocked (a blocker), not a lead. Diff-scoped is
279
+ // the right scope for a PR review (review the diff; pre-existing mocks are notes by
280
+ // diff-discipline) — the whole-tree inherited burndown is ensure-coverage's audit lint.
281
+ export function overMockFindings(added, topo = DEFAULT_MOCK_TOPOLOGY) {
282
+ const out = []
283
+ for (const a of added) {
284
+ if (!a.file || !TEST_FILE_ANY.test(a.file)) continue
285
+ const target = extractMockTarget(a.text)
286
+ if (!target) continue
287
+ const { internal, reason } = classifyMockTarget(target, topo)
288
+ if (!internal) continue
289
+ out.push({ type: 'over-mock-internal-seam', file: a.file, line: a.line, snippet: a.text.trim(), target, reason,
290
+ note: 'mocks a first-party internal seam → Over-mocked (dishonest green): zero-tolerance, NO @mock-ok waiver and no "approved with justification" (ensure-coverage depth/mock-policy.md). Resolve by making the test real, faking only the external, or DELETING it (over-mock is worse than no test). Only NOT a finding if the target is genuinely external — then declare it as topology in coverage.config.json.' })
291
+ }
292
+ return out
293
+ }
294
+
295
+ export function scanDiff(diffText, topo = DEFAULT_MOCK_TOPOLOGY) {
296
+ const added = parseAddedLines(diffText)
297
+ const byPlace = (a, b) => (a.file || '').localeCompare(b.file || '') || a.line - b.line
298
+ const leads = [...interceptionLeads(added), ...regexLeads(added), ...weakAssertionLeads(added), ...branchLeads(added),
299
+ ...concurrencyFixtureLeads(added), ...characterizationLeads(diffText)].sort(byPlace)
300
+ const findings = overMockFindings(added, topo).sort(byPlace)
301
+ const tally = (xs) => xs.reduce((m, l) => ((m[l.type] = (m[l.type] || 0) + 1), m), {})
302
+ // `counts`/`leads` kept for back-compat; `findings` is the decidable, blocker-grade channel.
303
+ return { kind: 'leads+findings', counts: tally(leads), leads, findingCounts: tally(findings), findings }
304
+ }
305
+
306
+ // ---- CLI ----
307
+
308
+ // Exit codes. Both are usage errors (distinct from 0 = scanned OK, and from a
309
+ // generic crash). NO_INPUT is the fail-open this tool exists NOT to have: a
310
+ // parity proof that returns "all clear" on zero bytes proved nothing about the
311
+ // diff (issue #416). USAGE catches the `--base/--head` invocation producers
312
+ // invented — flags this tool never had, which used to fall through to an empty
313
+ // stdin read and a vacuous clean result.
314
+ export const NO_INPUT_EXIT = 2
315
+ export const USAGE_EXIT = 2
316
+
317
+ // The ONE correct invocation, echoed in every error so a wrong call self-corrects.
318
+ const USAGE = 'Pipe the net diff: git diff <merge-base>...HEAD | node scan-diff.mjs (or: node scan-diff.mjs --diff <file>). This tool takes NO --base/--head.'
319
+
320
+ // A usage/no-input error carrying its own process exit code. Thrown by the arg
321
+ // parser and the empty-input guard; main() prints .message to stderr and exits.
322
+ export class ScanDiffCliError extends Error {
323
+ constructor(message, code = USAGE_EXIT) { super(message); this.name = 'ScanDiffCliError'; this.code = code }
324
+ }
325
+
326
+ // Parse argv (already sliced of node + script). Returns { diffPath } — null means
327
+ // read stdin. Anything that isn't `--diff <file>` HARD-FAILS: an unknown flag
328
+ // (the `--base/--head` mistake) or a stray positional would otherwise be silently
329
+ // ignored, dropping through to an empty stdin read and a false-clean proof.
330
+ export function parseCliArgs(argv) {
331
+ let diffPath = null
332
+ for (let i = 0; i < argv.length; i++) {
333
+ const arg = argv[i]
334
+ if (arg === '--diff') {
335
+ diffPath = argv[i + 1]
336
+ if (diffPath == null) throw new ScanDiffCliError(`scan-diff: --diff requires a file path. ${USAGE}`)
337
+ i++
338
+ continue
339
+ }
340
+ if (arg.startsWith('-')) throw new ScanDiffCliError(`scan-diff: unknown flag "${arg}". ${USAGE}`)
341
+ throw new ScanDiffCliError(`scan-diff: unexpected argument "${arg}". ${USAGE}`)
342
+ }
343
+ return { diffPath }
344
+ }
345
+
346
+ function main() {
347
+ let diff
348
+ try {
349
+ const { diffPath } = parseCliArgs(process.argv.slice(2))
350
+ diff = diffPath != null ? fs.readFileSync(diffPath, 'utf8') : fs.readFileSync(0, 'utf8') // --diff <file> or stdin
351
+ // Fail LOUD on no input. Empty/whitespace-only means the diff never arrived
352
+ // (a non-piped context, or the `--base/--head` fall-through) — NOT a clean
353
+ // diff. A real diff with content but zero findings still exits 0 below;
354
+ // "no INPUT" and "input with no findings" are different answers.
355
+ if (!diff.trim()) throw new ScanDiffCliError(`scan-diff: no diff on stdin (or --diff <file> is empty). ${USAGE}`, NO_INPUT_EXIT)
356
+ } catch (err) {
357
+ if (err instanceof ScanDiffCliError) { process.stderr.write(`${err.message}\n`); process.exit(err.code) }
358
+ throw err
359
+ }
360
+ const result = scanDiff(diff, loadMockTopology())
361
+ result.disclaimer = 'TWO channels. `leads` = heuristic "look here and verify" (read the code, build the counterexample first). `findings` = DECIDABLE blockers (over-mock-internal-seam): a vi/jest.mock of a first-party seam is Over-mocked, zero-tolerance, no waiver — fix it, do not merge over it. Best-effort, JS/TS-oriented; absence != code is fine.'
362
+ console.log(JSON.stringify(result, null, 2))
363
+ }
364
+
365
+ if (isMainModule(import.meta.url)) main()
@@ -0,0 +1,57 @@
1
+ // Shared review-finding theme contract. resolve-issues imports this validator so
2
+ // reviewer output and durable fix-round state cannot disagree about identity or
3
+ // state-space completeness.
4
+
5
+ export const THEME_KINDS = ['other', 'state-machine', 'concurrency']
6
+ export const CONTRACT_COMPLETE_KINDS = new Set(['state-machine', 'concurrency'])
7
+
8
+ const isObject = (value) => value != null && typeof value === 'object' && !Array.isArray(value)
9
+ const nonEmptyString = (value) => typeof value === 'string' && value.trim().length > 0
10
+
11
+ export function stateSpaceCells(theme) {
12
+ const states = theme?.stateSpace?.states || []
13
+ const taskKinds = theme?.stateSpace?.taskKinds || []
14
+ return states.flatMap((state) => taskKinds.map((taskKind) => ({ state, taskKind })))
15
+ }
16
+
17
+ function uniqueNonEmptyStrings(values, label) {
18
+ const errors = []
19
+ if (!Array.isArray(values) || values.length === 0) {
20
+ errors.push(`${label} must contain at least one value`)
21
+ return errors
22
+ }
23
+ const seen = new Set()
24
+ values.forEach((value) => {
25
+ if (!nonEmptyString(value)) errors.push(`${label} must contain non-empty strings`)
26
+ if (seen.has(value)) errors.push(`${label} must not contain duplicates: ${value}`)
27
+ seen.add(value)
28
+ })
29
+ return errors
30
+ }
31
+
32
+ export function validateTheme(theme) {
33
+ const errors = []
34
+ if (!isObject(theme)) return ['theme is required and must be an object']
35
+ errors.push(...uniqueKeys(theme, ['id', 'kind', 'contract', 'stateSpace'], 'theme'))
36
+ if (!nonEmptyString(theme.id) || !/^[a-z][a-z0-9-]*$/.test(theme.id)) {
37
+ errors.push('theme.id must be a stable kebab-case identity')
38
+ }
39
+ if (!THEME_KINDS.includes(theme.kind)) errors.push(`theme.kind must be one of ${THEME_KINDS.join('|')}`)
40
+ if (!nonEmptyString(theme.contract)) errors.push('theme.contract must name the general violated contract')
41
+ if (CONTRACT_COMPLETE_KINDS.has(theme.kind)) {
42
+ if (!isObject(theme.stateSpace)) {
43
+ errors.push('state-machine/concurrency theme requires stateSpace')
44
+ } else {
45
+ errors.push(...uniqueKeys(theme.stateSpace, ['states', 'taskKinds'], 'theme.stateSpace'))
46
+ errors.push(...uniqueNonEmptyStrings(theme.stateSpace.states, 'stateSpace.states'))
47
+ errors.push(...uniqueNonEmptyStrings(theme.stateSpace.taskKinds, 'stateSpace.taskKinds'))
48
+ }
49
+ } else if (theme.stateSpace !== undefined) {
50
+ errors.push('theme.stateSpace is only allowed for state-machine/concurrency themes')
51
+ }
52
+ return errors
53
+ }
54
+
55
+ function uniqueKeys(value, allowed, label) {
56
+ return Object.keys(value).filter((key) => !allowed.includes(key)).map((key) => `${label} has unknown property: ${key}`)
57
+ }
@@ -0,0 +1,3 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 1AboveIO
@@ -0,0 +1,131 @@
1
+ ---
2
+ name: smoke
3
+ description: "Curated E2E smoke gate over the golden paths: one ALIVE/DEAD verdict naming the broken path, driving the real app (browser via e2e-test's Playwright; api/cli via runtime observation); also creates/curates the golden-path manifest. Runs standalone, as the per-PR CI floor, the epic integration gate, or post-deploy verification. NOT for authoring tiered specs (e2e-test) or defining what to prove (ensure-coverage)."
4
+ dependencies:
5
+ - e2e-test
6
+ ---
7
+
8
+ # Smoke (curated E2E happy-path liveness gate)
9
+
10
+ Answer one question fast: **if a real user walked the few flows that matter right now, would the build be alive?** Smoke runs a small, curated set of **golden paths** against a *running* app and returns a binary **ALIVE / DEAD** verdict plus which path broke. For browser paths this is mechanically E2E — it drives the real UI through `e2e-test`'s Playwright runner — but stays *smoke* by selection, placement, and verdict: tiny, critical, fast enough for every gate, binary. It catches the integrated, render-time, only-breaks-in-the-real-app bugs a green unit/functional suite proves nothing about (the #237 class: a primary button that computed to transparent; a Feishu-QR component that crashed on unmount).
11
+
12
+ Smoke **owns only** the curated manifest, target-safe selection, the drive-result contract, and the ALIVE/DEAD verdict. It does **not** define coverage (`ensure-coverage`), author tiered specs (`e2e-test`), or review code (`review-pr`) — for browser paths it *drives through* `e2e-test`'s runner rather than forking it.
13
+
14
+ ## It's `/verify` applied to a standing set
15
+
16
+ Same discipline as `/verify`, pointed at a curated manifest instead of one ad-hoc diff:
17
+
18
+ - **A verdict is runtime observation — nothing else.** Build it, run it, drive the real interface to where the flow executes, capture what you see. That capture is the evidence — not a green test suite, a typecheck, or import-and-call.
19
+ - **Drive end to end; probe the cheap adjacents.** If users click buttons, click buttons — don't curl the API underneath; seams are where bugs hide. Push one step past the happy path where it's cheap (a 🔍 step).
20
+ - **Capture is evidence; memory isn't.** Screenshots, response bodies, pane dumps. Isolate shared process state (ports, tmux, tmp dirs).
21
+ - **When in doubt, FAIL.** A false ALIVE ships broken code; a false DEAD costs one more look. No partial pass — "3 of 4 worked" is DEAD until the 4th passes or is explained away.
22
+
23
+ Where it differs:
24
+
25
+ | | `/verify` | `smoke` |
26
+ |---|---|---|
27
+ | Subject | one change / diff | a **curated standing manifest** |
28
+ | Question | "does *this change* work?" | "is *the build* alive?" |
29
+ | Output | PASS/FAIL/BLOCKED/SKIP | **ALIVE/DEAD** + which path broke |
30
+ | Run by | a human/agent reviewing a PR | callers as a **gate** (epic integration, release, /smoke) |
31
+ | Target | wherever the change surfaces | **configurable**: local build or deployed revision |
32
+
33
+ ## The curated manifest (and ensuring it exists)
34
+
35
+ The value is the *curation*: the manifest is the **handful of flows whose failure means "do not ship"** — the critical-revenue / critical-trust journeys (sign in, sign up, the core action, pay), not a route census (that's `e2e-test`'s manifest). Keep it small and ruthless. Each path declares its `id`, `surface`, and target-safety (`mutates`/`tenant`); a **browser path references its `@smoke` Tier-3 journey** rather than re-specifying the flow (the spec owns the steps + observable), while `api`/`cli` paths carry their own `start`/`command` + `observable`. Format and fields: [references/manifest.md](references/manifest.md). Starter: [assets/smoke.manifest.example.json](assets/smoke.manifest.example.json).
36
+
37
+ **Ensure the manifest exists before you gate — the first move, every time.** No manifest = a vacuous pass; a stale one green-lights a flow nobody re-curated. So `validate` is the *ensure* step, not just a lint. Route on what you find:
38
+
39
+ | Situation | What "ensure" means |
40
+ |---|---|
41
+ | **No manifest** (`validate` reports *no manifest at …*) | **Bootstrap — never fabricate from memory.** Discover candidates (below), get the do-not-ship call from product/release, write concrete observables + synthetic tenants, then `validate`. A guessed "login + dashboard" set is the false-ALIVE this prevents; if the release-blocking decision needs a human, **stop and ask**. |
42
+ | **Manifest exists, this golden path isn't in it** (a new critical flow) | **Add the entry, then `validate`** — a run driving only the old paths silently misses the new do-not-ship flow. |
43
+ | **Manifest covers the path** | Straight to gating — but still `validate` first (a malformed manifest passes vacuously). |
44
+
45
+ **Discover candidates, then curate.** Discovery is automatable; the do-not-ship decision stays human (a guessed set gives a false ALIVE). Draw candidates strongest-source-first — the already-curated `@smoke`-taggable Tier-3 journeys; core-entity state transitions (each user-driven, money/irreversible transition is a candidate, target state = its observable); ADRs as a ranking signal; the surface inventory (`suggest`) as the crude fallback — none *decide* the set, they stop you starting from memory. Detail: [references/manifest.md](references/manifest.md#where-candidates-come-from-discover-then-curate).
46
+
47
+ ```bash
48
+ node <smoke>/scripts/smoke.mjs validate --manifest smoke.manifest.json --journeys e2e/journeys
49
+ ```
50
+
51
+ `--journeys` **reconciles the browser→journey references against the actual `@smoke` tags** — both directions are errors: a path pointing at a journey that isn't `@smoke`-tagged (the gate can't drive it), *and* a spec tagged `@smoke` that no path references (it silently never runs — a false ALIVE). Wire it into CI wherever the specs are reachable; without it the reference is unchecked prose.
52
+
53
+ **Prerequisites live in the manifest's `setup` block, not in `AGENTS.md`.** How to boot, env/secrets, the auth-bypass, seed data, synthetic tenants — co-located with the paths so they load with the gate and `validate` can *check* them. Reuse what owns each piece (`setup.fixtures` → `e2e-test`'s harness, `setup.boot` → the `run` skill); keep a one-line pointer in `AGENTS.md`. Fields + reuse rule: [references/manifest.md](references/manifest.md#the-setup-block-prerequisites--co-located-with-the-gate).
54
+
55
+ ## Selection is by Validation Profile (`--profile`), not free-form targeting
56
+
57
+ The gate selects paths by a **named Validation Profile** from the manifest's `profiles` registry — one name decides *which* paths run and *whether* writes are allowed. Each profile binds three axes the old single `--target` string conflated — a **gate** (why evidence is required), an **environment** (`local`/`dev`/`prod`), an **endpoint** (`local`/`preview`/`active`) — plus its `prerequisites`, `evidencePolicy`, and `mutationPolicy`. Format and the five initial profiles (`pr-local`, `queue-local`, `dev-active`, `prod-preview`, `prod-active`): [references/manifest.md](references/manifest.md#validation-profiles-the-profiles-registry).
58
+
59
+ ```bash
60
+ node <smoke>/scripts/smoke.mjs plan --manifest smoke.manifest.json --profile pr-local
61
+ node <smoke>/scripts/smoke.mjs plan --manifest smoke.manifest.json --profile prod-preview --target https://rev-xyz.run.app
62
+ ```
63
+
64
+ `--target` is now **just the address to drive against** (the deployed candidate/service URL; defaults to `local`) — it no longer participates in selection. The profile does. For a `local` profile, boot the build yourself the `/verify` way (a `run-*`/`verifier-*` skill in `.claude/skills/`, else the **`run`** skill, else cold-start from README/package.json, timebox ~15 min → BLOCKED); for a deployed profile, point `--target` at the revision and confirm it is the SHA you mean to verify.
65
+
66
+ **Prod safety is mechanical, and it lives on the profile.** A path runs in a profile only if it declares that profile AND the profile's `mutationPolicy` admits it. The **production profiles (`prod-preview`, `prod-active`) are read-only** — every `mutates:true` path is excluded, **tenant or not** (a synthetic tenant still writes to the real production database, and a revision at 0% traffic is not a reason those writes are safe: `resolve-release` principle 4). `dev-active` allows a `mutates:true` path **only with a declared synthetic tenant**; the local profiles allow isolated writes. This is the old `--no-mutations` flag turned into a property of the *named profile*, so nobody has to remember to pass it — and because one name drives both the run and the verdict, the two **cannot disagree** about the selected set (the old run/verdict flag-mismatch is unrepresentable).
67
+
68
+ **Gate before promote.** On a deployed target the smoke is a gate only if it runs *before* the revision is irreversible — a smoke after traffic shifts is a monitor, not a gate. Deploy the candidate at **0% traffic** (stable, addressable) → smoke that URL under `prod-preview` → **promote only on ALIVE** → confirm the serving revision is the one you smoked, then re-smoke the live service under `prod-active`. Bonus: a DEAD is re-investigable against the same 0%-traffic revision with no rebuild — most of what a deployed smoke catches is config/secret/packaging. **Reuse the platform's deploy notification** (the CI/deploy build-failure → Pub/Sub/webhook path), carrying `smoke-verdict.json` so the alert names the broken path; the concrete placement lives in `cloud-build` / `cloud-deploy`.
69
+
70
+ ## Drive each path, then compute the verdict
71
+
72
+ 1. **Get a handle on the target** (boot via `run`, or point at the URL).
73
+ 2. **Drive each selected path through its surface** and observe the declared observable — the drive step emits `smoke-results.json`:
74
+ - **browser** → run its `@smoke` Tier-3 journey in a real browser via **`e2e-test`'s Playwright runner**. Real render, no first-party interception (a stubbed DOM hides exactly these bugs). The spec asserts the observable *and* render-health (no `pageerror` / `console.error` / error-boundary / 5xx); stub only the true external boundary (CDN SDK, provider endpoint), never the component itself.
75
+ - **api** → send the request, capture the response, assert the observable.
76
+ - **cli** → run the command, capture the pane, assert the observable.
77
+ Each path yields `{ id, status: pass|fail|blocked, evidence, note }`. A path you cannot reach is `blocked` — **never silently skipped or passed**.
78
+ 3. **Compute the verdict** (the *same* `--profile` the run used):
79
+ ```bash
80
+ node <smoke>/scripts/smoke.mjs verdict --manifest smoke.manifest.json --profile <name> --target <url> \
81
+ --results smoke-results.json --out smoke-verdict.json
82
+ ```
83
+ **ALIVE** iff every selected path PASSED. Any `fail`, `blocked`, or `missing` → **DEAD**, naming the path(s). Exit code is the gate (0 = ALIVE, 1 = DEAD). Selection is a pure function of `--profile` + the manifest, so the run and the verdict select the **same** set by construction — there is no second flag assembly for the verdict to disagree with, which is the whole point: the run/verdict mismatch that free-form targeting permitted is now unrepresentable.
84
+
85
+ `smoke-verdict.json` is stamped with the facts an automated consumer needs to judge the evidence rather than trust it: **`profile`** (the Validation Profile it selected under), **`target`** (which URL it ran against), **`noMutations`** (DERIVED from the profile's `mutationPolicy` — `true` for the read-only production profiles), and **`generatedAt`** (an ISO-8601 instant — *when*, so a consumer can bound how old the evidence is). `resolve-release`'s traffic-shift gate compares these; an ALIVE from the wrong target, a mutating run, or too long ago is not a green light.
86
+
87
+ **`generatedAt` dates the verdict, not the run.** `verdict` reduces whatever `--results` file you hand it, however old, and stamps the current instant on the result — so re-running `verdict` alone re-mints freshness without re-validating anything, and a consumer bounding the age cannot tell the difference. That is not a substitute for a stale gate's re-check: when what expired is the *evidence about a live target*, re-drive the paths into a new `smoke-results.json` — re-minting a verdict is not re-validation.
88
+
89
+ ## Report (the `/verify` shape, gate-flavored)
90
+
91
+ Lead with the verdict, then the per-path steps and findings:
92
+
93
+ ```
94
+ ## Smoke: <target>
95
+ **Verdict:** ALIVE | DEAD
96
+ **Target:** local (booted <how>) | <url> (revision <sha>)
97
+ **Paths:** <n passed>/<n run> (<excluded count> excluded: <why>)
98
+ ### Paths
99
+ 1. ✅/❌/⚠️/🔍 <path id> — <what you drove> → <what you observed>
100
+ <evidence: screenshot / response body / pane capture>
101
+ ### Findings
102
+ <anything that made you pause — friction, surprise, a near-miss — even on an ALIVE run>
103
+ ```
104
+
105
+ Findings matter even when ALIVE — you're the only check that actually *ran the integrated thing*. A DEAD verdict hands the broken path's evidence to the caller (the epic gate reopens the owning unit; in the release lane the response depends on whether users were ever exposed — before the traffic shift it discards the candidate, after it triggers the rollback policy, both routing to `app-debug`/`diagnose`).
106
+
107
+ ## Where this fits (the callers)
108
+
109
+ The **per-PR golden-path liveness floor** (`ensure-coverage` CI contract, gate 8) — enforced at every lane:
110
+
111
+ - **`implement-and-pr` (step 6)** — before opening the PR, boot what you built (`--target local`) and run the golden paths the change touches; a DEAD blocks readiness. New critical flow → it owes a manifest entry.
112
+ - **`review-pr`** — a Review-Contract row: the manifest covers the change's golden path (a new critical flow with no entry is a finding), and the attached `smoke-results.json` + `smoke-verdict.json` are ALIVE against HEAD. A smoke you cannot *run* — no build, no target, missing credential — leaves the row `BLOCKED`, never a finding against the diff ([review-pr](../review-pr/SKILL.md) § Verdicts and the blocking bar); an inability to verify is not evidence the golden path is broken.
113
+ - **CI (gate 8, blocking)** — wired in `e2e-test/assets/ci-gates.*`; boots the app, drives the paths into `smoke-results.json`, runs `smoke.mjs verdict`. The mechanical backstop.
114
+ - **`resolve-issues`** — final step of the [epic integration gate](../resolve-issues/references/deliverables.md#deliverables-the-shippable-component-not-the-whole-epic): boot the assembled integration branch and run the golden paths; a DEAD whose broken paths are `fail` belongs to a specific unit → reopen its fix loop. **A DEAD built from `blocked`/`missing` paths is a gate-environment problem, not a unit's defect** — report it and fix the environment; reopening a fix loop on it spends a producer spawn and an adversarial review on code that is fine, and the round lands in the unit's budget all the same.
115
+ - **`/smoke`** — standalone, any time, against `local` or a URL.
116
+ - **`resolve-release`** — [the exposure gate](../resolve-release/SKILL.md#the-release-loop): the `prod-preview` profile against the 0%-traffic candidate URL (read-only, so it excludes every mutating path), then the `prod-active` profile against the live service after the shift. A DEAD **before** exposure deletes the candidate (no rollback, no user impact); a DEAD after it triggers the rollback policy.
117
+ - **The dev-deploy recorder** (`cloud-build` → Post-deploy smoke gate) — the integration pipeline runs this gate after its 100%-traffic deploy and publishes the verdict as a **SHA-keyed commit status**, never failing the build; that recorded ALIVE is what `resolve-release` requires when pinning a release candidate (its principle 11).
118
+
119
+ ## Reference Map
120
+
121
+ | When you need to… | Read |
122
+ |---|---|
123
+ | author/validate the manifest (fields, surface→driver, what earns a slot, candidate sources) | [references/manifest.md](references/manifest.md) |
124
+ | a starting manifest to adapt | [assets/smoke.manifest.example.json](assets/smoke.manifest.example.json) |
125
+ | the runtime-observation discipline this borrows | the built-in `/verify` skill |
126
+ | drive a browser path / the Playwright runner + render-health | `e2e-test` → [presentation-sweep.md](../e2e-test/references/presentation-sweep.md) |
127
+ | boot a local build to drive | the `run` skill |
128
+
129
+ ## Scripts
130
+
131
+ - `scripts/smoke.mjs` — the gate shell: `suggest` (inventory → non-runnable candidates), `validate` (manifest shape + the `profiles` registry + `--journeys` reconciliation of browser paths against the `@smoke` tags, both drift directions), `plan` (profile-based selection + exclusions), `verdict` (reduce results → ALIVE/DEAD, exit code = gate). Pure core (`validateManifest`/`validateProfile`/`selectPathsForProfile`/`computeVerdict`/`suggestCandidates`/`reconcileJourneys`/`journeyCoversId`) is unit-tested in `scripts/smoke.test.mjs`; the driving itself is runtime observation (Playwright / request / pane capture), not this script.
@@ -0,0 +1,53 @@
1
+ {
2
+ "_comment": "EXAMPLE ONLY — these paths are specific to one consumer auth product. They are NOT a universal template: a payments app's golden paths are checkout/pay/receipt, a docs app's are create/edit/share. Author your own per-app set whose failure means 'do not ship', then DELETE this example. There is no fixed number of paths. See references/manifest.md.",
3
+ "profiles": {
4
+ "pr-local": { "gate": "pull-request", "environment": "local", "endpoint": "local", "prerequisites": ["boot", "seed", "auth-bypass"], "evidencePolicy": "per-PR screens attached to the PR", "mutationPolicy": "isolated-writes" },
5
+ "queue-local": { "gate": "merge-queue", "environment": "local", "endpoint": "local", "prerequisites": ["boot", "seed", "auth-bypass"], "evidencePolicy": "batch-gate screens", "mutationPolicy": "isolated-writes" },
6
+ "dev-active": { "gate": "trunk-integration", "environment": "dev", "endpoint": "active", "prerequisites": ["deployed-revision", "synthetic-tenant-cleanup"], "evidencePolicy": "SHA-keyed recorder verdict", "mutationPolicy": "synthetic-tenant" },
7
+ "prod-preview": { "gate": "pre-promotion", "environment": "prod", "endpoint": "preview", "prerequisites": ["candidate-revision-at-0pct"], "evidencePolicy": "attested identity tuple + smoke-verdict.json", "mutationPolicy": "read-only" },
8
+ "prod-active": { "gate": "post-promotion", "environment": "prod", "endpoint": "active", "prerequisites": ["live-service-at-100pct"], "evidencePolicy": "attested identity tuple + smoke-verdict.json", "mutationPolicy": "read-only" }
9
+ },
10
+ "setup": {
11
+ "boot": "use the run skill (else: pnpm --filter app dev)",
12
+ "env": ["DATABASE_URL", "AUTH_SECRET", "FEISHU_APP_ID"],
13
+ "authBypass": "E2E_AUTH_BYPASS=1 (see e2e-test global-setup)",
14
+ "seed": "pnpm seed:smoke",
15
+ "fixtures": "reuse e2e-test's Playwright fixtures — do not recreate auth here",
16
+ "tenants": ["e2e-synthetic"]
17
+ },
18
+ "paths": [
19
+ {
20
+ "id": "login-to-dashboard",
21
+ "surface": "browser",
22
+ "journey": "@smoke login-to-dashboard",
23
+ "intent": "org-entry → credential card → dashboard heading visible; primary button non-transparent; no console errors (the referenced journey asserts this)",
24
+ "mutates": false,
25
+ "profiles": ["pr-local", "queue-local", "dev-active", "prod-preview", "prod-active"]
26
+ },
27
+ {
28
+ "id": "sso-qr-mount",
29
+ "surface": "browser",
30
+ "journey": "@smoke sso-qr-mount",
31
+ "intent": "SSO QR panel mounts (real component, CDN SDK stubbed at the boundary); switching to password does not crash",
32
+ "mutates": false,
33
+ "profiles": ["pr-local", "queue-local", "dev-active", "prod-preview", "prod-active"]
34
+ },
35
+ {
36
+ "id": "signup-verify-otp",
37
+ "surface": "browser",
38
+ "journey": "@smoke signup-verify-otp",
39
+ "intent": "sign up → OTP (email boundary faked) → lands authenticated on the dashboard",
40
+ "mutates": true,
41
+ "tenant": "e2e-synthetic",
42
+ "profiles": ["pr-local", "queue-local", "dev-active"]
43
+ },
44
+ {
45
+ "id": "health",
46
+ "surface": "api",
47
+ "start": "GET /healthz",
48
+ "observable": "200 with body { status: \"ok\" }",
49
+ "mutates": false,
50
+ "profiles": ["pr-local", "queue-local", "dev-active", "prod-preview", "prod-active"]
51
+ }
52
+ ]
53
+ }