@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,599 @@
1
+ // green-gate — the mechanized unattended-promotion gate for the release lane (issue #405).
2
+ //
3
+ // `auto-when-green` (references/auto-when-green.md) lets a promotion run unattended, but
4
+ // only behind a real gate. Today an agent evaluates that gate's (a)-(e) conditions by
5
+ // reading prose, at the single most dangerous point in the system: an unattended
6
+ // production traffic shift with no human present. This script makes each condition a
7
+ // DECIDABLE ARTIFACT CHECK that FAILS CLOSED and NAMES the failing condition — so the
8
+ // green light is a comparison against a recorded fact, never a claim the agent makes
9
+ // about its own prior work.
10
+ //
11
+ // The doc has two authorization points, so this has two subcommands:
12
+ // green-gate.mjs promote --manifest <run-manifest.json>
13
+ // Gates the promotion + rc mint on (a)-(d) plus the "force the human even when
14
+ // green" carve-outs (major bump, rollback not armed, irreversible content).
15
+ // green-gate.mjs shift --manifest <run-manifest.json> --verdict <smoke-verdict.json>
16
+ // Gates the traffic shift on (e): the candidate's smoke verdict is ALIVE, on the
17
+ // EXACT candidate URL, was a --no-mutations run, and is still INSIDE the envelope's
18
+ // freshness window. This is the crux — "on that exact candidate" is a compared field
19
+ // (`target === candidateUrl`), never asserted; and "recently enough" is a compared
20
+ // field too (`generatedAt` vs `envelope.verdictFreshnessMinutes`), because the
21
+ // authorization this gate runs after can arrive hours after the validation.
22
+ //
23
+ // Contract:
24
+ // exit 0 = FIRE — every condition holds and no carve-out triggered.
25
+ // exit 1 = HOLD — fall back to a per-step human confirm; the SPECIFIC failing
26
+ // condition ids are named in `failed`.
27
+ // exit 2 = usage / unreadable-input error — bad flags, unknown subcommand, or a
28
+ // manifest that is absent / unparseable / not a resolve-release run.
29
+ //
30
+ // FAIL CLOSED is the invariant: EVERY missing / malformed / wrong-shape condition input
31
+ // is a HOLD, never a FIRE. A missing smoke-verdict.json HOLDs. A `release` field the gate
32
+ // needs but the manifest does not carry HOLDs and is named. The only inputs that produce
33
+ // exit 2 (not HOLD) are the ones that stop the gate from running at all: the CLI flags
34
+ // and the manifest file itself.
35
+ //
36
+ // WHAT A HOLD MEANS, doctrinally (principle 13, issue #439). The behaviour above was always
37
+ // right and was nowhere written down, which left the reading of it to whoever hit it: an
38
+ // APPLICABLE CONDITION WHOSE INPUT COULD NOT BE PRODUCED IS A FAILING CONDITION, NOT A
39
+ // MISSING ONE. The credential the readiness check needed was absent, the service it drives
40
+ // was down, the fixture had drifted — none of that is a step to note and continue past, and
41
+ // none of it is an `n/a` (which says the condition does not apply here, and is decided). So
42
+ // the gate never distinguishes "nobody filled this in" from "nobody could": it cannot, and
43
+ // neither is a result.
44
+ //
45
+ // AND THE HOLD IS SCOPED. It blocks THIS release — this SHA does not promote, this candidate
46
+ // does not take traffic. It is not a reason to pause the merge queue, dequeue an unrelated
47
+ // PR, or lift a branch protection: a fail-closed mechanism that also freezes the repair path
48
+ // is the one people bypass, and a bypassed gate has stopped existing without anyone deciding
49
+ // to remove it. The fix to the harness, the fixture or the credential is enqueued like any
50
+ // other unit and lands the way everything else lands.
51
+ //
52
+ // Every condition is read from an ARTIFACT the release lane already records:
53
+ // - the run manifest — resolve-issues' scripts/run-state.mjs, release variant
54
+ // (references/../resolve-issues/references/run-state.md): `envelope` (the pre-flight
55
+ // authorization block) and `release` (the version/candidate/CI record).
56
+ // - smoke-verdict.json — the smoke skill's verdict output (verdict/target/noMutations/
57
+ // generatedAt, all stamped by smoke's stampTarget).
58
+ // - version.mjs plan's recorded output, carried in `release.versionPlan`
59
+ // ({ bump, collision, ... }) — the gate trusts the plan computed at step 1b rather
60
+ // than re-running git, so the gate reads the same fact the human saw at the cut.
61
+ //
62
+ // NOTE ON THE MANIFEST SCHEMA. run-state.mjs validates the release variant LOOSELY (only
63
+ // `envelope` presence and the `step` enum). The `release.*` and `envelope.*` fields this
64
+ // gate reads are therefore not yet formally in that schema; the gate reads them from the
65
+ // raw JSON and fails closed on any it does not find. `envelope.reversibilityConfirmed` in
66
+ // particular is a field the pre-flight gate does not record today — until it does, the
67
+ // irreversible-content carve-out HOLDs (the safe default: force the human), rather than
68
+ // silently passing an unverifiable carve-out. See the PR body for the full field list.
69
+
70
+ import fs from 'node:fs'
71
+ import { isMainModule } from '../../engineering-runtime/scripts/main-module.mjs'
72
+ import { normalizeReleaseVerdict } from '../../resolve-issues/scripts/release-state-contract.mjs'
73
+ import { evaluateProductionFloor } from './production-endpoints.mjs'
74
+
75
+ // The conservative default freshness window for the step-4a verdict, in minutes (issue #431).
76
+ //
77
+ // (e) bounds WHICH candidate the evidence covers; it did not bound how OLD that evidence is,
78
+ // and step 4b's shape is "validate at 0% → wait for an authorization → shift" with nothing
79
+ // bounding the wait. A four-hour-old ALIVE describes coordinates that may have moved since:
80
+ // a newer build may hold the `candidate` tag, the previous revision may no longer hold 100%.
81
+ // So the shift gate reads the verdict's `generatedAt` stamp and refuses evidence older than
82
+ // the window the envelope declared (pre-flight item 3), defaulting to this when it declared
83
+ // none. Conservative on purpose — the default governs an unattended production traffic shift
84
+ // with no human present, so it must read evidence minted minutes ago, not hours; a release
85
+ // that legitimately needs a longer wait declares the longer window in the envelope, where a
86
+ // human saw it. Expiry routes back to step 4a (re-validate the candidate), not to the shift.
87
+ export const DEFAULT_VERDICT_FRESHNESS_MINUTES = 30
88
+
89
+ // ---- condition helpers (pure) ----
90
+
91
+ const isGreen = (v) => v === 'green'
92
+
93
+ // (b)'s SHA-keyed integration smoke sub-check. The integration environment may or may not
94
+ // run a SHA-keyed recorder (principle 11): the manifest declares which. An explicit
95
+ // "not-recorded" waives the sub-check; a recorded verdict must be ALIVE and on the EXACT
96
+ // promoted SHA (a verdict from another SHA is not evidence for this one). Anything else —
97
+ // absent, or a malformed value — fails closed: the presence of a recorder must be an
98
+ // explicit statement, never an inference from a missing field.
99
+ function integrationSmokeGreen(smoke, candidateSha) {
100
+ if (smoke === 'not-recorded') return true
101
+ if (!smoke || typeof smoke !== 'object') return false
102
+ // Require a real SHA match, not merely equal fields: an absent candidateSha and a
103
+ // sha-less verdict are both `undefined`, and `undefined === undefined` would fail OPEN —
104
+ // firing production on "a verdict for no particular SHA." A truthy-string match on both
105
+ // sides is the fail-closed form.
106
+ return (
107
+ smoke.verdict === 'ALIVE' &&
108
+ typeof candidateSha === 'string' &&
109
+ candidateSha.length > 0 &&
110
+ smoke.sha === candidateSha
111
+ )
112
+ }
113
+
114
+ // (c)'s evidence must BE a CHECKABLE LOCATOR, not a prose sentence that merely CONTAINS a
115
+ // locator-shaped token. An unattended production-promotion gate must not accept "looks good"
116
+ // as proof that a readiness row passed — it accepts only evidence a second reader could
117
+ // independently re-open. This is the coverage-checklist.mjs / review-contract evidence
118
+ // convention (ensure-coverage), widened to the forms a release-readiness row actually cites.
119
+ //
120
+ // THE ANCHORING RULE (why containment was a fail-OPEN). Every form below is anchored at `^`:
121
+ // the evidence must PRESENT as a locator — it must wholly BE one, or LEAD with one, with a
122
+ // trailing NOTE (whitespace/punctuation + free text) allowed after the complete token. A
123
+ // locator-shaped token buried inside a prose sentence is NO LONGER sufficient, because that
124
+ // containment let realistic prose fire the gate: a date ("verified 20260721") and a big number
125
+ // ("ran 1000000 iterations") are valid [0-9a-f]{7,40} SHAs; an all-hex English word ("acceded",
126
+ // "defaced") is too; a dotted abbreviation ("e.g.", "i.e.", "U.S."), a glued sentence ("wrapped
127
+ // up.Next steps"), and an email TLD ("a@b.com") all carry a "filename.ext"-shaped substring.
128
+ // Anchoring means only the LEADING token can qualify, so none of those pass. Accepted anchored
129
+ // forms (the trailing-note allowance, issue #412 fix 3, is IDENTICAL for every one — a complete
130
+ // token then end / whitespace / punctuation [ , ; ) ] } ] then any note; '.' is excluded so a
131
+ // leading abbreviation never reads as "file.ext" + a period note):
132
+ // - a file path with a REAL extension docs/release/checklist.md, run-state.mjs
133
+ // and an optional :line / :line-range path/to/file.ext:123 (or :12-20), then the tail.
134
+ // The extension must be LETTER-initial (`.md`, not a `.5` decimal). The name part accepts a
135
+ // leading '@' only at index 0 (npm scope `@scope/pkg/file.ts`); an '@' after index 0 makes
136
+ // it an email, not a path, so "ops@example.com confirmed" does NOT qualify (issue #412 fix
137
+ // 1). An abbreviation's trailing "." ("e.g. ok") has no ext char before the space, so it
138
+ // still fails.
139
+ // - an extensionless named file :line ./Makefile:5, path/to/file:12 — the :line is the
140
+ // discriminator, and the left side must be PATH-LIKE: contain a '/' or a real '.ext' (issue
141
+ // #412 fix 2). A bare "word:number" ("error:500", "attempt:2") is not a locator, and a bare
142
+ // "Makefile:5" must be path-qualified ("./Makefile:5"). The name part must contain a letter,
143
+ // so "12:30" is not a locator.
144
+ // - a URL http://… / https://…
145
+ // - an issue / PR ref #123
146
+ // - a backticked shell command `node --test …`
147
+ // - a bare git SHA 7-40 hex chars, the whole TOKEN (a trailing note is
148
+ // allowed, e.g. "AbCdEf1 rest"), containing BOTH a hex letter AND a digit — the digit+letter
149
+ // requirement is what separates a real SHA from an all-hex English word or an all-digit
150
+ // date/number, each of which is otherwise a valid hex string, and it is tested on the token,
151
+ // not the note. It rejects the ~0.1% of genuine SHAs that are all-letters — the safe
152
+ // direction for a production gate.
153
+ // RESIDUAL (shape-inherent, out of scope). A leading glued sentence or product name that is
154
+ // shape-identical to a real file — "Done.Next steps", "Next.js routes unchanged", "Mrs.Smith
155
+ // approved" — still qualifies: without a filesystem check they are indistinguishable from a
156
+ // legitimate ".js"/".ts"/".md" reference, and rejecting them would reject real file locators.
157
+ // Bare prose ("looks good", "done", "verified", "N/A", "TODO") leads with none of these →
158
+ // NOT a locator → the row is not green and condition (c) HOLDs (forces the human).
159
+ export function isCheckableLocator(s) {
160
+ if (typeof s !== 'string') return false
161
+ const t = s.trim()
162
+ if (t.length === 0) return false
163
+
164
+ // The shared trailing boundary (issue #412 fix 3): a COMPLETE locator token ends at
165
+ // end-of-string, whitespace, or a note-attaching punctuation ( , ; ) ] } ) — the SAME rule
166
+ // for every form below, so "AbCdEf1 rest" (SHA + note) and "CHANGELOG.md:1, note" (locator
167
+ // glued to a comma) qualify exactly as "docs/x.md:12 note" always did. It DELIBERATELY
168
+ // excludes '.' — a leading abbreviation ("e.g.", "U.S.") must never read as "file.ext" + a
169
+ // trailing period note (that is the dotted-abbreviation fail-open the anchoring closed) —
170
+ // and ':' / '-' / '/', which are locator-internal.
171
+ const TAIL = '(?:[\\s,;)\\]}]|$)'
172
+
173
+ // a file path with a letter-initial extension + optional :line, then the tail.
174
+ // The name part accepts a leading '@' at index 0 (npm scope: @scope/pkg/file.ts) but NO '@'
175
+ // after it (issue #412 fix 1): "ops@example.com confirmed" is an email TLD, not a path.
176
+ if (new RegExp('^\\S[^\\s@]*\\.[A-Za-z][\\w-]{0,9}(:\\d+(-\\d+)?)?' + TAIL).test(t)) return true
177
+
178
+ // an extensionless named file with a :line ref. The left side must be PATH-LIKE — contain a
179
+ // '/' or a real '.ext' (issue #412 fix 2) — so bare "word:number" prose ("error:500",
180
+ // "attempt:2", "Makefile:5") is NOT a locator; and the name part must contain a letter
181
+ // ("12:30" is a time, not a locator). A bare extensionless name needs a path: "./Makefile:5".
182
+ if (new RegExp('^(?=[\\w./-]*[A-Za-z])(?=[\\w./-]*(?:/|\\.[A-Za-z]))[\\w./-]+:\\d+(-\\d+)?' + TAIL).test(t)) return true
183
+
184
+ // a URL
185
+ if (/^https?:\/\//.test(t)) return true
186
+
187
+ // an issue / PR ref
188
+ if (/^#\d+/.test(t)) return true
189
+
190
+ // a backticked command / code span
191
+ if (/^`[^`]+`/.test(t)) return true
192
+
193
+ // a bare git SHA: a 7-40 hex token, then the shared tail (issue #412 fix 3 — a SHA + note
194
+ // now qualifies like every other form, not only a whole-string SHA). The digit-AND-hex-letter
195
+ // requirement — what separates a real SHA from an all-hex English word or an all-digit
196
+ // date/number — is tested on the captured TOKEN, never on the trailing note.
197
+ const sha = new RegExp('^([0-9a-f]{7,40})' + TAIL, 'i').exec(t)
198
+ if (sha && /[0-9]/.test(sha[1]) && /[a-f]/i.test(sha[1])) return true
199
+
200
+ return false
201
+ }
202
+
203
+ const SECRET_EVIDENCE = [
204
+ /-----BEGIN [^-]*PRIVATE KEY-----/i,
205
+ /(?:^|[?&\s,;])(?:access[_-]?token|id[_-]?token|token|secret|password|passwd|api[_-]?key|authorization|credential)\s*[:=]\s*\S+/i,
206
+ /\b(?:gh[pousr]_[A-Za-z0-9_]{20,}|sk-[A-Za-z0-9_-]{20,}|AIza[A-Za-z0-9_-]{20,})\b/,
207
+ ]
208
+
209
+ function diagnosticEvidence(value) {
210
+ let serialized
211
+ try {
212
+ serialized = typeof value === 'string' ? value : JSON.stringify(value)
213
+ } catch {
214
+ serialized = '[UNSERIALIZABLE]'
215
+ }
216
+ if (SECRET_EVIDENCE.some((pattern) => pattern.test(serialized || ''))) {
217
+ return { value: '[REDACTED]', redacted: true }
218
+ }
219
+ return { value: value ?? '', redacted: false }
220
+ }
221
+
222
+ export function releaseReadinessFailures(rows) {
223
+ if (!Array.isArray(rows) || rows.length === 0) {
224
+ return [{
225
+ index: null,
226
+ row: '(releaseReadiness)',
227
+ status: null,
228
+ evidenceValue: '',
229
+ evidenceRedacted: false,
230
+ violations: [{
231
+ rule: 'releaseReadiness-must-be-non-empty-array',
232
+ actual: Array.isArray(rows) ? 'empty-array' : rows == null ? null : typeof rows,
233
+ }],
234
+ }]
235
+ }
236
+
237
+ return rows.flatMap((entry, index) => {
238
+ const row = entry && typeof entry === 'object' ? entry : {}
239
+ const evidence = diagnosticEvidence(row.evidence)
240
+ const violations = []
241
+ if (row.status !== 'PASS') violations.push({ rule: 'status-must-be-PASS', actual: row.status ?? null })
242
+ if (!isCheckableLocator(row.evidence)) {
243
+ violations.push({ rule: 'evidence-must-start-with-checkable-locator', actual: evidence.value })
244
+ }
245
+ if (violations.length === 0) return []
246
+ return [{
247
+ index,
248
+ row: typeof row.row === 'string' && row.row ? row.row : `(row ${index})`,
249
+ status: row.status ?? null,
250
+ evidenceValue: evidence.value,
251
+ evidenceRedacted: evidence.redacted,
252
+ violations,
253
+ }]
254
+ })
255
+ }
256
+
257
+ // (c) release-readiness: every row decided PASS with a CHECKABLE evidence locator (see
258
+ // isCheckableLocator — prose alone is not evidence), no blank/TODO row (coverage-checklist.mjs
259
+ // validate semantics). Plus the version/changelog row: the cut is committed and the recorded
260
+ // plan reports no collision on the final tag.
261
+ function releaseReadinessGreen(release) {
262
+ const plan = release.versionPlan
263
+ const versionRowGreen =
264
+ typeof release.cutCommit === 'string' &&
265
+ release.cutCommit.length > 0 &&
266
+ !!plan &&
267
+ plan.collision === false
268
+ return releaseReadinessFailures(release.releaseReadiness).length === 0 && versionRowGreen
269
+ }
270
+
271
+ // ---- promote: (a)-(d) + carve-outs ----
272
+
273
+ export function evaluatePromote(manifest) {
274
+ const release = (manifest && manifest.release) || {}
275
+ const envelope = (manifest && manifest.envelope) || {}
276
+ const failed = []
277
+ const evidence = {}
278
+ const diagnostics = { readiness: releaseReadinessFailures(release.releaseReadiness) }
279
+
280
+ // (a) Fast-forwardable.
281
+ evidence.fastForwardable = release.fastForwardable
282
+ if (release.fastForwardable !== true) failed.push('a')
283
+
284
+ // (b) Gates green: PR-lane CI, integration CI, and (where recorded) the SHA-keyed smoke
285
+ // verdict ALIVE on the exact promoted SHA.
286
+ evidence.prLaneCi = release.prLaneCi
287
+ evidence.integrationCi = release.integrationCi
288
+ evidence.integrationSmoke = release.integrationSmoke
289
+ evidence.candidateSha = release.candidateSha
290
+ if (
291
+ !isGreen(release.prLaneCi) ||
292
+ !isGreen(release.integrationCi) ||
293
+ !integrationSmokeGreen(release.integrationSmoke, release.candidateSha)
294
+ ) {
295
+ failed.push('b')
296
+ }
297
+
298
+ // (c) Release-readiness fully decided (rows + the version/changelog row).
299
+ evidence.releaseReadiness = Array.isArray(release.releaseReadiness)
300
+ ? release.releaseReadiness.map((row) => {
301
+ const safe = diagnosticEvidence(row && row.evidence)
302
+ return { ...row, evidence: safe.value, evidenceRedacted: safe.redacted }
303
+ })
304
+ : release.releaseReadiness
305
+ evidence.cutCommit = release.cutCommit
306
+ evidence.versionPlan = release.versionPlan
307
+ if (!releaseReadinessGreen(release)) failed.push('c')
308
+
309
+ // (d) No unresolved blocking finding on the combined diff (from the integration-review
310
+ // verdict, a recorded manifest field). Absent count fails closed.
311
+ evidence.blockingFindings = release.blockingFindings
312
+ if (release.blockingFindings !== 0) failed.push('d')
313
+
314
+ // Carve-out: a major version bump reaches consumers who already pinned — irreversible
315
+ // for them whatever the rollback does. version.mjs plan names the bump, so it is
316
+ // mechanically checkable. FAIL CLOSED like every other carve-out: clear this ONLY on a
317
+ // positively-known non-major bump. version.mjs only ever emits lowercase major|minor|
318
+ // patch, so an absent versionPlan, an absent bump, or ANY non-canonical value ('Major',
319
+ // 'MAJOR', a typo) is a malformed input the gate cannot read as safe — it must force the
320
+ // human, never take the green branch. A knowably-major bump is named distinctly from a
321
+ // manifest we can't trust to be non-major.
322
+ const bump = release.versionPlan && release.versionPlan.bump
323
+ if (bump === 'major') failed.push('carveout:major-bump')
324
+ else if (bump !== 'patch' && bump !== 'minor') failed.push('malformed-version-plan')
325
+
326
+ // Carve-out: rollback must be armed — auto-rollback policy AND a candidate deletable
327
+ // without confirmation. Without the validate→expose→verify→rollback loop, auto-when-green
328
+ // is not available.
329
+ evidence.rollbackPolicy = envelope.rollbackPolicy
330
+ evidence.candidateDeletableWithoutConfirm = envelope.candidateDeletableWithoutConfirm
331
+ if (envelope.rollbackPolicy !== 'auto-rollback' || envelope.candidateDeletableWithoutConfirm !== true) {
332
+ failed.push('carveout:rollback-not-armed')
333
+ }
334
+
335
+ // Carve-out: irreversible content always forces the human. This depends on an input the
336
+ // pre-flight gate does not record today, so it fails closed: a positive
337
+ // `reversibilityConfirmed` is REQUIRED to clear it, and an explicit `irreversibleContent`
338
+ // flag forces the human. Absence HOLDs rather than silently passing.
339
+ evidence.reversibilityConfirmed = envelope.reversibilityConfirmed
340
+ evidence.irreversibleContent = envelope.irreversibleContent
341
+ if (envelope.reversibilityConfirmed !== true || envelope.irreversibleContent === true) {
342
+ failed.push('carveout:irreversible-content')
343
+ }
344
+
345
+ return { decision: failed.length === 0 ? 'fire' : 'hold', phase: 'promote', failed, evidence, diagnostics }
346
+ }
347
+
348
+ // ---- shift: (e) checked against the artifact, not asserted ----
349
+
350
+ // The freshness window in force for this release: the envelope's declared value when it is a
351
+ // usable one, the conservative default otherwise. Only a positive finite NUMBER counts —
352
+ // a string "240", a 0, a negative, NaN/Infinity, an object are all unreadable, and an
353
+ // unreadable window must never become "no window". Falling back NARROWS rather than widens,
354
+ // so the failure direction is a HOLD (fall back to the human), never an unbounded fire.
355
+ function freshnessWindowMinutes(envelope) {
356
+ const declared = envelope && envelope.verdictFreshnessMinutes
357
+ const usable = typeof declared === 'number' && Number.isFinite(declared) && declared > 0
358
+ return usable ? declared : DEFAULT_VERDICT_FRESHNESS_MINUTES
359
+ }
360
+
361
+ // Floor readiness before the first traffic shift (#800 / identity-v0.4.1).
362
+ //
363
+ // Applicability is decided before the RC mint by production-endpoints.mjs. The shift gate
364
+ // consumes that record rather than accepting a detached floor assertion: a distinct host cannot
365
+ // be skipped, ALIVE must target the recorded canonical URL, and Cloud Run-only is accepted only
366
+ // through the fingerprint-bound reasoned skip produced from equal endpoint reads.
367
+ export function evaluateFloorReadiness(manifest, now = Date.now()) {
368
+ const release = (manifest && manifest.release) || {}
369
+ const envelope = (manifest && manifest.envelope) || {}
370
+ const floor = release.floorReadiness || null
371
+ const result = evaluateProductionFloor(release.productionEndpoints, floor, {
372
+ now,
373
+ freshnessMinutes: freshnessWindowMinutes(envelope),
374
+ })
375
+ return result.ok
376
+ ? { ok: true, id: null, evidence: result.evidence }
377
+ : { ok: false, id: "e:floor-not-ready", evidence: { floorReadiness: floor }, detail: `${result.id}: ${result.detail}` }
378
+ }
379
+
380
+ export function evaluateShift(manifest, verdict, now = Date.now()) {
381
+ const release = (manifest && manifest.release) || {}
382
+ const envelope = (manifest && manifest.envelope) || {}
383
+ const candidateUrl = release.candidateUrl
384
+ const failed = []
385
+ const evidence = { candidateUrl }
386
+ const normalizedVerdict = normalizeReleaseVerdict(verdict)
387
+
388
+ // (e) The candidate's smoke verdict must be ALIVE, on the EXACT candidate URL, and a
389
+ // --no-mutations run. A missing/malformed verdict, a mismatched target, an EMPTY or DEAD
390
+ // verdict, or a mutating run all HOLD. Comparing the recorded target is the whole point:
391
+ // it turns "on that exact candidate" from an assertion into a check.
392
+ evidence.verdict = normalizedVerdict && normalizedVerdict.state
393
+ evidence.verdictTarget = normalizedVerdict && normalizedVerdict.target
394
+ evidence.noMutations = normalizedVerdict && normalizedVerdict.noMutations
395
+ const green =
396
+ !!normalizedVerdict &&
397
+ typeof candidateUrl === 'string' &&
398
+ candidateUrl.length > 0 &&
399
+ normalizedVerdict.state === 'ALIVE' &&
400
+ normalizedVerdict.target === candidateUrl &&
401
+ normalizedVerdict.noMutations === true
402
+ if (!green) {
403
+ // Issue #823: a CANNOT-RUN (or BLOCKED) verdict is a gate failure, not a candidate failure.
404
+ // Distinguish it so the operator repairs the gate rather than deleting a healthy candidate.
405
+ if (normalizedVerdict && (normalizedVerdict.state === 'CANNOT-RUN' || normalizedVerdict.state === 'BLOCKED')) {
406
+ failed.push('e:cannot-run')
407
+ } else {
408
+ failed.push('e')
409
+ }
410
+ }
411
+
412
+ // (e)'s freshness half. Named as its own condition rather than folded into `e` so the
413
+ // operator can tell the two routes apart: a failed `e` means the candidate did not pass
414
+ // (route to step 5's pre-exposure path), while a failed freshness check means the evidence
415
+ // aged out while the authorization was pending — the candidate may be perfectly fine, and
416
+ // the route is back to step 4a to re-validate it, never onward to the shift.
417
+ const windowMinutes = freshnessWindowMinutes(envelope)
418
+ evidence.verdictFreshnessMinutes = windowMinutes
419
+ evidence.generatedAt = normalizedVerdict && normalizedVerdict.generatedAt
420
+ const stampedAt =
421
+ normalizedVerdict && typeof normalizedVerdict.generatedAt === 'string' ? Date.parse(normalizedVerdict.generatedAt) : NaN
422
+ if (!Number.isFinite(stampedAt)) {
423
+ // Absent evidence is not fresh evidence. A verdict with no readable stamp cannot be aged,
424
+ // so it can never be shown to be fresh — the fail-closed reading is HOLD, and it is the
425
+ // one an older smoke build (which stamped no timestamp at all) lands on.
426
+ failed.push('e:unstamped-verdict')
427
+ } else {
428
+ const ageMinutes = (now - stampedAt) / 60_000
429
+ evidence.verdictAgeMinutes = Math.round(ageMinutes * 100) / 100
430
+ // A NEGATIVE age — a stamp ahead of now — is not freshness either: it is a clock the gate
431
+ // cannot trust, and left unchecked a future-dated verdict would read as fresh forever.
432
+ if (ageMinutes < 0 || ageMinutes > windowMinutes) failed.push('e:stale-verdict')
433
+ }
434
+
435
+ // Floor public-host readiness (#800). Independent of (e): the candidate can be ALIVE on
436
+ // *.run.app while the public host is DEAD for a pre-existing edge reason. Named so the
437
+ // operator can tell "candidate bad" from "floor already broken".
438
+ const floor = evaluateFloorReadiness(manifest, now)
439
+ Object.assign(evidence, floor.evidence)
440
+ if (!floor.ok) failed.push(floor.id)
441
+
442
+ return { decision: failed.length === 0 ? 'fire' : 'hold', phase: 'shift', failed, evidence }
443
+ }
444
+
445
+ // ---- CLI ----
446
+
447
+ const USAGE = `green-gate — the mechanized unattended-promotion gate for the release lane.
448
+
449
+ Every (a)-(e) condition of the auto-when-green envelope is decided from an ARTIFACT and
450
+ FAILS CLOSED: a missing or malformed input HOLDs, it never fires. The two subcommands
451
+ mirror the doc's two authorization points.
452
+
453
+ Usage:
454
+ green-gate promote --manifest <run-manifest.json>
455
+ Gate the promotion + rc mint on:
456
+ (a) fastForwardable === true
457
+ (b) PR-lane CI green, integration CI green, and (where the integration env records
458
+ one) the SHA-keyed smoke verdict ALIVE on the exact promoted SHA
459
+ (c) every release-readiness row PASS whose evidence BEGINS WITH a CHECKABLE
460
+ locator — a file path (real extension) / path:line / URL / #ref / backticked
461
+ command / mixed-hex SHA; prose that merely mentions a dotted abbreviation, a
462
+ date, or a hex word HOLDs — and the version cut committed with no tag collision
463
+ (d) no unresolved blocking finding on the combined diff
464
+ Carve-outs that force the human even when (a)-(d) hold:
465
+ - a major version bump (version.mjs plan bump === "major")
466
+ - rollback not armed (policy not auto-rollback, or candidate not deletable w/o confirm)
467
+ - irreversible content (destructive migration / unverifiable secret / first deploy)
468
+
469
+ green-gate shift --manifest <run-manifest.json> --verdict <smoke-verdict.json>
470
+ Gate the traffic shift on:
471
+ (e) verdict === "ALIVE" AND target === candidateUrl AND noMutations === true
472
+ (EMPTY, DEAD, missing, CANNOT-RUN/BLOCKED, or an ALIVE from a different target all HOLD)
473
+ e:stale-verdict the verdict's generatedAt is outside the freshness window
474
+ (envelope.verdictFreshnessMinutes; default ${DEFAULT_VERDICT_FRESHNESS_MINUTES} min, and an unreadable
475
+ declared window falls back to that default rather than widening). A future-dated
476
+ stamp is stale too. Route back to step 4a and re-validate the candidate — do NOT
477
+ shift on aged coordinates.
478
+ e:unstamped-verdict the verdict carries no readable generatedAt, so its age cannot
479
+ be bounded — absent evidence is not fresh evidence.
480
+ e:floor-not-ready public-host (prod-active) readiness on the CURRENT production
481
+ floor is missing, DEAD/blocked, or skipped without a reason. Candidate ALIVE on
482
+ *.run.app is not floor readiness — CF Insights / edge scripts only inject on the
483
+ proxied public host (identity-v0.4.1 / #800). Record release.floorReadiness
484
+ {status:"alive", profile:"prod-active", target, checkedAt} or
485
+ {status:"skipped", reason} before the first shift.
486
+
487
+ Exit codes:
488
+ 0 FIRE — every condition holds, no carve-out triggered
489
+ 1 HOLD — fall back to a per-step human confirm; the failing condition ids are named
490
+ 2 usage / unreadable-input error — bad flags, unknown subcommand, or a manifest that is
491
+ absent, unparseable, or not a resolve-release run
492
+
493
+ A condition whose input could not be produced is a FAILING condition, not a missing one: an
494
+ applicable gate that cannot run is a failure, not an absence (principle 13). An absent
495
+ credential, an unavailable service or a drifted fixture HOLDs exactly as a red result does —
496
+ this gate cannot tell "nobody filled it in" from "nobody could", and neither is a result. An
497
+ "n/a" is the other thing: a condition that does not apply here, decided, with a reason.
498
+
499
+ A HOLD blocks THIS release — this SHA does not promote, this candidate takes no traffic. It
500
+ is never a reason to pause the merge queue, dequeue an unrelated PR, or lift a branch
501
+ protection: the repair reaches the repo through that lane, and a block that freezes it too is
502
+ the one people bypass.
503
+
504
+ Output: JSON { decision: "fire"|"hold", phase, failed: [<condition ids>], evidence: {...} }
505
+
506
+ Doctrine (why each condition, the two authorization points, the (e)-must-be-artifact rule,
507
+ the carve-outs): references/auto-when-green.md.`
508
+
509
+ function parseArgs(argv) {
510
+ const opts = {}
511
+ const positional = []
512
+ for (let i = 0; i < argv.length; i++) {
513
+ const a = argv[i]
514
+ if (a === '--help' || a === '-h') opts.help = true
515
+ else if (a.startsWith('--')) opts[a.slice(2)] = argv[++i]
516
+ else positional.push(a)
517
+ }
518
+ return { opts, positional }
519
+ }
520
+
521
+ // Read + parse the run manifest. Distinguishes the two exit-2 causes (no path given, file
522
+ // unreadable/unparseable, wrong-shape run) from a HOLD: you cannot evaluate ANY condition
523
+ // without a readable resolve-release manifest, so those are operational errors, not
524
+ // condition failures.
525
+ function loadManifest(file) {
526
+ if (!file) return { error: 'usage: --manifest <run-manifest.json> is required' }
527
+ let raw
528
+ try {
529
+ raw = fs.readFileSync(file, 'utf8')
530
+ } catch {
531
+ return { error: `manifest not readable: ${file}` }
532
+ }
533
+ let manifest
534
+ try {
535
+ manifest = JSON.parse(raw)
536
+ } catch {
537
+ return { error: `manifest is not valid JSON: ${file}` }
538
+ }
539
+ if (!manifest || typeof manifest !== 'object' || !manifest.envelope) {
540
+ return { error: `not a resolve-release run manifest (no authorization envelope): ${file}` }
541
+ }
542
+ return { manifest }
543
+ }
544
+
545
+ // A verdict file that is absent or unparseable is a HOLD, not an error: a missing
546
+ // smoke-verdict.json must never fire the traffic shift. Returns null on any failure, which
547
+ // evaluateShift treats as a (e) HOLD.
548
+ function loadVerdict(file) {
549
+ if (!file) return null
550
+ try {
551
+ return JSON.parse(fs.readFileSync(file, 'utf8'))
552
+ } catch {
553
+ return null
554
+ }
555
+ }
556
+
557
+ export function main(argv) {
558
+ const { opts, positional } = parseArgs(argv)
559
+ const cmd = positional[0]
560
+
561
+ // Only an EXPLICIT help request earns exit 0. A missing subcommand fails CLOSED to the
562
+ // same exit-2 usage error as an unknown one: `green-gate <empty> --manifest …` (or a bare
563
+ // invocation) inside `green-gate … && shift-traffic` must NOT print usage and exit 0 — a
564
+ // 0 there is a FIRE, shifting production traffic on no gate at all.
565
+ if (opts.help || cmd === 'help') {
566
+ console.log(USAGE)
567
+ return 0
568
+ }
569
+
570
+ if (cmd !== 'promote' && cmd !== 'shift') {
571
+ const what = cmd ? `unknown command "${cmd}"` : 'no subcommand given'
572
+ console.error(`green-gate: ${what}. Use promote|shift (see --help).`)
573
+ return 2
574
+ }
575
+
576
+ const loaded = loadManifest(opts.manifest)
577
+ if (loaded.error) {
578
+ console.error(`green-gate: ${loaded.error}`)
579
+ return 2
580
+ }
581
+
582
+ let result
583
+ if (cmd === 'promote') {
584
+ result = evaluatePromote(loaded.manifest)
585
+ } else {
586
+ if (!opts.verdict) {
587
+ console.error('green-gate: usage: shift requires --verdict <smoke-verdict.json>')
588
+ return 2
589
+ }
590
+ result = evaluateShift(loaded.manifest, loadVerdict(opts.verdict))
591
+ }
592
+
593
+ console.log(JSON.stringify(result, null, 2))
594
+ return result.decision === 'fire' ? 0 : 1
595
+ }
596
+
597
+ if (isMainModule(import.meta.url)) {
598
+ process.exit(main(process.argv.slice(2)))
599
+ }