@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,263 @@
1
+ #!/usr/bin/env node
2
+ // rollback-floor — terminal close when floor smoke cannot go ALIVE after a correct restore (#800).
3
+ //
4
+ // Doctrine wants smoke ALIVE for verified-rollback (routing.md). identity-v0.4.1 attempt.1
5
+ // restored traffic to v0.4.0 correctly, then prod-active stayed DEAD on the incumbent for the
6
+ // same pre-existing CF Insights vs app CSP reason (identity#677). Agents had no terminal path
7
+ // and invented lease states or blamed the candidate code.
8
+ //
9
+ // This module defines the close:
10
+ // state: rolled-back
11
+ // closedBy: verified-rollback
12
+ // smoke: blocked-by-preexisting-gate
13
+ // incident: REQUIRED
14
+ // when traffic+attestation prove restore AND the floor itself fails the same check.
15
+ //
16
+ // Pure classifier — the agent (or a thin CLI) still issues the traffic restore and the
17
+ // record-release-attempt call; this only decides whether that close is legal and shapes
18
+ // the evidence string. It does not invent a new lease state.
19
+ //
20
+ // Doctrine: references/routing.md § Verification failed after exposure.
21
+ // Regression: identity-v0.4.1 · identity#677 · #800.
22
+
23
+ import { isMainModule } from '../../engineering-runtime/scripts/main-module.mjs'
24
+
25
+ export const SMOKE_BLOCKED_BY_PREEXISTING_GATE = 'blocked-by-preexisting-gate'
26
+
27
+ /**
28
+ * Concrete traffic attestation is required for any verified-rollback close.
29
+ * A missing/empty/malformed attestation must not produce evidence that claims
30
+ * "traffic+attestation verified" (#800 / identity-v0.4.1).
31
+ */
32
+ export function hasConcreteAttestation(attestation) {
33
+ if (!attestation || typeof attestation !== 'object' || Array.isArray(attestation)) return false
34
+ // Accept a revision id, a source SHA, a resource name, or an explicit verified flag.
35
+ const revision = attestation.revision != null ? String(attestation.revision).trim() : ''
36
+ const sourceSha = attestation.sourceSha != null ? String(attestation.sourceSha).trim() : ''
37
+ const resource = attestation.resource != null ? String(attestation.resource).trim() : ''
38
+ if (revision || sourceSha || resource) return true
39
+ if (attestation.verified === true || attestation.ok === true) return true
40
+ return false
41
+ }
42
+
43
+ /**
44
+ * @param {object} input
45
+ * @param {{ previousRevision?: string, previousPercent?: number, candidatePercent?: number, attestation?: object }} input.traffic
46
+ * @param {{ verdict?: string, profile?: string, target?: string, floorAlsoDead?: boolean, reason?: string }} input.smoke
47
+ * @param {{ number?: number, url?: string } | null} input.incidentIssue
48
+ */
49
+ export function classifyRollbackClose({ traffic = {}, smoke = {}, incidentIssue = null } = {}) {
50
+ const prevPct = Number(traffic.previousPercent)
51
+ const candPct = traffic.candidatePercent == null ? 0 : Number(traffic.candidatePercent)
52
+ const percentsRestored =
53
+ typeof traffic.previousRevision === 'string' &&
54
+ traffic.previousRevision.length > 0 &&
55
+ Number.isFinite(prevPct) &&
56
+ prevPct === 100 &&
57
+ Number.isFinite(candPct) &&
58
+ candPct === 0
59
+
60
+ if (!percentsRestored) {
61
+ return {
62
+ closeable: false,
63
+ reason: 'traffic-not-restored',
64
+ detail: 'verified-rollback requires previousRevision at exactly 100% and candidate at 0%',
65
+ }
66
+ }
67
+
68
+ // Attestation is part of the restore proof, not optional garnish. Without it the
69
+ // close cannot claim "traffic+attestation verified".
70
+ if (!hasConcreteAttestation(traffic.attestation)) {
71
+ return {
72
+ closeable: false,
73
+ reason: 'attestation-missing',
74
+ detail:
75
+ 'verified-rollback requires traffic.attestation with a concrete revision/sourceSha/resource (or verified:true); percents alone are not enough',
76
+ }
77
+ }
78
+
79
+ const verdict = String(smoke.verdict || '').toUpperCase()
80
+ if (verdict === 'ALIVE') {
81
+ // Standard path — still requires an incident on post-exposure rollback (routing.md).
82
+ if (!hasIncident(incidentIssue)) {
83
+ return {
84
+ closeable: false,
85
+ reason: 'incident-required',
86
+ detail: 'post-exposure rollback always files an incident issue',
87
+ closedBy: 'verified-rollback',
88
+ smoke: 'ALIVE',
89
+ }
90
+ }
91
+ return {
92
+ closeable: true,
93
+ closedBy: 'verified-rollback',
94
+ smoke: 'ALIVE',
95
+ requiresIncident: true,
96
+ incidentIssue: normalizeIncident(incidentIssue),
97
+ traffic: {
98
+ previousRevision: traffic.previousRevision,
99
+ previousPercent: 100,
100
+ candidatePercent: 0,
101
+ attestation: traffic.attestation,
102
+ },
103
+ }
104
+ }
105
+
106
+ // DEAD / EMPTY / cannot-run: only closeable when the floor itself is known to fail the
107
+ // same check (pre-existing gate/env), not when the restore may have left production bad.
108
+ if (verdict === 'DEAD' || verdict === 'EMPTY' || verdict === 'CANNOT-RUN' || verdict === 'CANNOT_RUN') {
109
+ if (!smoke.floorAlsoDead) {
110
+ return {
111
+ closeable: false,
112
+ reason: 'smoke-dead-without-floor-preexistence',
113
+ detail:
114
+ 'prod-active DEAD after restore without floorAlsoDead evidence — do not invent a close; page and establish whether the incumbent itself fails the same check',
115
+ }
116
+ }
117
+ if (!hasIncident(incidentIssue)) {
118
+ return {
119
+ closeable: false,
120
+ reason: 'incident-required',
121
+ detail: 'blocked-by-preexisting-gate requires a filed incident issue (identity#677 class)',
122
+ smoke: SMOKE_BLOCKED_BY_PREEXISTING_GATE,
123
+ }
124
+ }
125
+ return {
126
+ closeable: true,
127
+ closedBy: 'verified-rollback',
128
+ smoke: SMOKE_BLOCKED_BY_PREEXISTING_GATE,
129
+ requiresIncident: true,
130
+ incidentIssue: normalizeIncident(incidentIssue),
131
+ floorReason: smoke.reason || 'pre-existing floor gate/env failure',
132
+ traffic: {
133
+ previousRevision: traffic.previousRevision,
134
+ previousPercent: 100,
135
+ candidatePercent: 0,
136
+ attestation: traffic.attestation,
137
+ },
138
+ }
139
+ }
140
+
141
+ return {
142
+ closeable: false,
143
+ reason: 'smoke-unreadable',
144
+ detail: `smoke verdict ${JSON.stringify(smoke.verdict)} is not ALIVE or a floor-preexistence DEAD`,
145
+ }
146
+ }
147
+
148
+ export function buildRollbackClosePayload(classified) {
149
+ if (!classified || !classified.closeable) {
150
+ throw new Error(
151
+ `buildRollbackClosePayload: not closeable (${classified && classified.reason}) — ${classified && classified.detail}`,
152
+ )
153
+ }
154
+ const rev = classified.traffic.previousRevision
155
+ const incident = classified.incidentIssue
156
+ const incidentRef = incident.number != null ? `#${incident.number}` : incident.url
157
+ let evidence
158
+ if (classified.smoke === SMOKE_BLOCKED_BY_PREEXISTING_GATE) {
159
+ evidence =
160
+ `${rev} restored to 100%; traffic+attestation verified; ` +
161
+ `smoke: ${SMOKE_BLOCKED_BY_PREEXISTING_GATE} (${classified.floorReason}); ` +
162
+ `incident ${incidentRef}`
163
+ } else {
164
+ evidence =
165
+ `${rev} restored to 100%; smoke ALIVE against live service; incident ${incidentRef}`
166
+ }
167
+ return {
168
+ state: 'rolled-back',
169
+ closedBy: classified.closedBy,
170
+ evidence,
171
+ smoke: classified.smoke,
172
+ incidentIssue: incident,
173
+ }
174
+ }
175
+
176
+ function hasIncident(issue) {
177
+ return !!(issue && (issue.number != null || issue.url))
178
+ }
179
+
180
+ function normalizeIncident(issue) {
181
+ if (!issue) return null
182
+ return {
183
+ number: issue.number != null ? Number(issue.number) : null,
184
+ url: issue.url || null,
185
+ }
186
+ }
187
+
188
+ export const USAGE = `rollback-floor — classify a post-exposure rollback close when floor smoke cannot pass.
189
+
190
+ rollback-floor classify --traffic <json> --smoke <json> [--incident <json>]
191
+ Pure decision. Prints {closeable, closedBy, smoke, ...}. Exit 0 always when readable;
192
+ exit 2 on usage.
193
+
194
+ rollback-floor payload --traffic <json> --smoke <json> --incident <json>
195
+ Shape the record-release-attempt JSON when closeable. Exit 0 on closeable, 1 otherwise.
196
+
197
+ Why: identity-v0.4.1 restored traffic correctly then prod-active stayed DEAD on the
198
+ incumbent (CF Insights vs CSP, identity#677). Without this path agents invent lease
199
+ states. See references/routing.md and issue #800.`
200
+
201
+ export function parseArgs(argv) {
202
+ const args = { positional: [] }
203
+ for (let i = 0; i < argv.length; i += 1) {
204
+ const a = argv[i]
205
+ if (a === '--help' || a === '-h') args.help = true
206
+ else if (a === '--traffic') args.traffic = argv[++i]
207
+ else if (a === '--smoke') args.smoke = argv[++i]
208
+ else if (a === '--incident') args.incident = argv[++i]
209
+ else if (a.startsWith('-')) args.unknown = a
210
+ else args.positional.push(a)
211
+ }
212
+ args.cmd = args.positional[0] || null
213
+ return args
214
+ }
215
+
216
+ function parseJsonFlag(raw, name) {
217
+ if (!raw) return null
218
+ try {
219
+ return JSON.parse(raw)
220
+ } catch (err) {
221
+ throw new Error(`${name} is not valid JSON: ${err.message}`)
222
+ }
223
+ }
224
+
225
+ export function main(argv) {
226
+ const args = parseArgs(argv)
227
+ if (args.help || args.cmd === 'help') {
228
+ console.log(USAGE)
229
+ return 0
230
+ }
231
+ if (args.unknown) {
232
+ console.error(`rollback-floor: unknown flag ${args.unknown}`)
233
+ return 2
234
+ }
235
+ if (!args.cmd || !['classify', 'payload'].includes(args.cmd)) {
236
+ console.error('rollback-floor: use classify|payload (see --help)')
237
+ return 2
238
+ }
239
+ try {
240
+ const traffic = parseJsonFlag(args.traffic, '--traffic') || {}
241
+ const smoke = parseJsonFlag(args.smoke, '--smoke') || {}
242
+ const incidentIssue = parseJsonFlag(args.incident, '--incident')
243
+ const classified = classifyRollbackClose({ traffic, smoke, incidentIssue })
244
+ if (args.cmd === 'classify') {
245
+ console.log(JSON.stringify(classified, null, 2))
246
+ return 0
247
+ }
248
+ if (!classified.closeable) {
249
+ console.error(`rollback-floor: not closeable — ${classified.reason}: ${classified.detail}`)
250
+ console.log(JSON.stringify(classified, null, 2))
251
+ return 1
252
+ }
253
+ console.log(JSON.stringify(buildRollbackClosePayload(classified), null, 2))
254
+ return 0
255
+ } catch (err) {
256
+ console.error(`rollback-floor: ${err.message}`)
257
+ return 2
258
+ }
259
+ }
260
+
261
+ if (isMainModule(import.meta.url)) {
262
+ process.exit(main(process.argv.slice(2)))
263
+ }
@@ -0,0 +1,339 @@
1
+ // version-assert — display-version policy check for the release lane (issue #822).
2
+ //
3
+ // A release has two version concepts:
4
+ // - identity version: the immutable tag / SHA that names what is running
5
+ // (candidate-identity.mjs owns this: sourceSha, revision, imageDigest).
6
+ // - display version: the string the running service prints in UI and /api/health.
7
+ //
8
+ // Under rc-tag deploy topology the pipeline triggers on vX.Y.Z-rc.N, but the version
9
+ // that should be SHOWN to operators is the final vX.Y.Z — otherwise a verified release
10
+ // leaves every dashboard claiming it is still an rc. This script asserts that the
11
+ // serving health endpoint's displayed version matches the policy declared in the
12
+ // authorization envelope, or records an explicit exception.
13
+ //
14
+ // Contract:
15
+ // version-assert serving --health <health.json> --settings <settings.json> --frontend-asset <asset.json> [--policy <policy>] [--deploy-trigger <topology>] [--version <v>] [--sha <sha>] [--trigger-tag <tag>] [--record-mismatch <reason>]
16
+ // Reads the health, settings, and frontend-asset JSON files, extracts each `version`
17
+ // display value, and checks every one against the policy. Prints JSON
18
+ // { decision, policy, displayed, expected, mismatch, failed }.
19
+ // final-semver --version <v> displayed version must equal the final semver vX.Y.Z
20
+ // trigger-tag --trigger-tag <t> displayed version must equal the attempt tag (e.g. vX.Y.Z-rc.N)
21
+ // short-sha --sha <sha> displayed version must match the short SHA
22
+ // --deploy-trigger rc-tag when --policy is omitted, resolves to final-semver (the rc-tag default).
23
+ // --record-mismatch <reason> on mismatch, record a declared exception and ACCEPT instead of refusing.
24
+ //
25
+ // exit 0 = ACCEPT — display version matches policy, or a mismatch was recorded with reason.
26
+ // exit 1 = REFUSE — display version does not match policy and no exception was recorded.
27
+ // exit 2 = usage / unreadable-input error.
28
+
29
+ import fs from 'node:fs'
30
+ import { shaMatches } from './candidate-identity.mjs'
31
+ import { isMainModule } from '../../engineering-runtime/scripts/main-module.mjs'
32
+
33
+ export const DISPLAY_VERSION_POLICIES = ['final-semver', 'trigger-tag', 'short-sha']
34
+
35
+ // Health endpoints may render with or without a leading 'v'. Normalize so the policy
36
+ // comparison is about the version, not the rendering choice.
37
+ export function normalizeVersion(s) {
38
+ if (typeof s !== 'string') return ''
39
+ return s.trim().toLowerCase().replace(/^v/, '')
40
+ }
41
+
42
+ export function isSemver(s) {
43
+ return /^\d+\.\d+\.\d+(?:-[0-9a-z.-]+)?(?:\+[0-9a-z.-]+)?$/i.test(String(s ?? '').replace(/^v/, ''))
44
+ }
45
+
46
+ // Compute the expected display string from the policy and the supplied identity inputs.
47
+ export function expectedDisplayVersion(policy, { version, triggerTag, sha } = {}) {
48
+ if (policy === 'final-semver') {
49
+ const v = normalizeVersion(version)
50
+ if (!isSemver(v)) return null
51
+ // Expected display is the release semver, with no prerelease segment.
52
+ const base = v.split('-')[0].split('+')[0]
53
+ return base
54
+ }
55
+ if (policy === 'trigger-tag') {
56
+ const t = normalizeVersion(triggerTag)
57
+ return t || null
58
+ }
59
+ if (policy === 'short-sha') {
60
+ const s = String(sha ?? '').trim().toLowerCase()
61
+ if (!s) return null
62
+ return s.slice(0, 7)
63
+ }
64
+ return null
65
+ }
66
+
67
+ // Resolve an omitted policy against the deploy topology. rc-tag defaults to
68
+ // final-semver so a verified release does not leave operators staring at the
69
+ // attempt tag while the published tag is the final semver.
70
+ export function resolveDisplayVersionPolicy(policy, deployTrigger) {
71
+ if (policy) return { policy }
72
+ if (deployTrigger === 'rc-tag') return { policy: 'final-semver' }
73
+ return { error: 'e:missing-display-version-policy' }
74
+ }
75
+
76
+ // Read the display version from a health JSON payload. Field aliases are intentionally
77
+ // narrow: the point is to read a real endpoint, not to accept anything version-shaped.
78
+ export function readDisplayVersion(health) {
79
+ if (!health || typeof health !== 'object') return { error: 'e:unreadable-health' }
80
+ const version = health.version ?? health.displayVersion ?? health.deployedVersion ?? health.DEPLOYED_VERSION
81
+ if (typeof version !== 'string' || version.trim().length === 0) {
82
+ return { error: 'e:no-display-version', missing: ['version'] }
83
+ }
84
+ return { version: version.trim() }
85
+ }
86
+
87
+ export function evaluateDisplayVersion({ health, settings, frontendAsset, policy, version, triggerTag, sha, recordMismatch = null }) {
88
+ if (!DISPLAY_VERSION_POLICIES.includes(policy)) {
89
+ return { decision: 'refuse', phase: 'display-version', policy, failed: ['e:unknown-policy'], evidence: {} }
90
+ }
91
+
92
+ const sourceInputs = [
93
+ ['health', health],
94
+ ['settings', settings],
95
+ ['frontend-asset', frontendAsset],
96
+ ].filter(([, value]) => value !== undefined)
97
+ const displayedBySource = {}
98
+ for (const [source, input] of sourceInputs) {
99
+ const read = readDisplayVersion(input)
100
+ if (read.error) {
101
+ const error = source === 'health' ? read.error : `${read.error}:${source}`
102
+ return { decision: 'refuse', phase: 'display-version', policy, failed: [error], evidence: { missing: read.missing } }
103
+ }
104
+ displayedBySource[source] = read.version
105
+ }
106
+
107
+ const displayed = sourceInputs.length === 1 ? displayedBySource.health : displayedBySource
108
+ const expected = expectedDisplayVersion(policy, { version, triggerTag, sha })
109
+ if (expected == null) {
110
+ return {
111
+ decision: 'refuse',
112
+ phase: 'display-version',
113
+ policy,
114
+ displayed,
115
+ failed: ['e:missing-expected-input'],
116
+ evidence: { policy, version, triggerTag, sha },
117
+ }
118
+ }
119
+
120
+ const mismatchedSources = Object.entries(displayedBySource)
121
+ .filter(([, sourceDisplayed]) => (
122
+ policy === 'short-sha'
123
+ ? !shaMatches(sourceDisplayed, expected)
124
+ : normalizeVersion(sourceDisplayed) !== normalizeVersion(expected)
125
+ ))
126
+ .map(([source]) => source)
127
+
128
+ if (mismatchedSources.length === 0) {
129
+ return {
130
+ decision: 'accept',
131
+ phase: 'display-version',
132
+ policy,
133
+ displayed,
134
+ expected,
135
+ mismatch: null,
136
+ failed: [],
137
+ }
138
+ }
139
+
140
+ if (recordMismatch && String(recordMismatch).trim().length > 0) {
141
+ return {
142
+ decision: 'accept',
143
+ phase: 'display-version',
144
+ policy,
145
+ displayed,
146
+ expected,
147
+ mismatch: { recorded: true, reason: String(recordMismatch).trim(), sources: mismatchedSources },
148
+ failed: [],
149
+ }
150
+ }
151
+
152
+ return {
153
+ decision: 'refuse',
154
+ phase: 'display-version',
155
+ policy,
156
+ displayed,
157
+ expected,
158
+ mismatch: null,
159
+ failed: mismatchedSources.map((source) => (
160
+ source === 'health' ? 'e:display-version-mismatch' : `e:display-version-mismatch:${source}`
161
+ )),
162
+ }
163
+ }
164
+
165
+ const USAGE = `version-assert — display-version policy check for the release lane.
166
+
167
+ A release has an identity version (the immutable tag/SHA that names what is running,
168
+ owned by candidate-identity.mjs) and a display version (the string UI and /api/health
169
+ show). Under rc-tag topology the pipeline triggers on vX.Y.Z-rc.N, but the operator-
170
+ visible version should be vX.Y.Z unless the envelope deliberately says otherwise.
171
+
172
+ Usage:
173
+ version-assert serving --health <health.json> --settings <settings.json> --frontend-asset <asset.json> --policy <policy> [policy-inputs] [--record-mismatch <reason>]
174
+ version-assert serving --health <health.json> --settings <settings.json> --frontend-asset <asset.json> --deploy-trigger rc-tag [policy-inputs] [--record-mismatch <reason>]
175
+
176
+ All three JSON inputs must expose the operator-visible version under version,
177
+ displayVersion, deployedVersion, or DEPLOYED_VERSION.
178
+
179
+ Policies:
180
+ final-semver --version <v> displayed version must equal the final semver vX.Y.Z
181
+ trigger-tag --trigger-tag <t> displayed version must equal the attempt tag (e.g. vX.Y.Z-rc.N)
182
+ short-sha --sha <sha> displayed version must match the short SHA
183
+
184
+ --deploy-trigger <rc-tag|branch-push|final-tag|no-deploy>
185
+ when --policy is omitted, rc-tag resolves to final-semver;
186
+ other topologies must declare the policy explicitly.
187
+ --record-mismatch <reason> on mismatch, record a declared exception and ACCEPT instead of refusing.
188
+
189
+ Exit codes:
190
+ 0 ACCEPT — display version matches policy, or a mismatch was recorded with reason
191
+ 1 REFUSE — display version does not match policy and no exception was recorded
192
+ 2 usage / unreadable-input error / missing policy on a topology with no default
193
+
194
+ Output: JSON { decision, phase, policy, displayed, expected, mismatch, failed }
195
+
196
+ Doctrine (display vs identity version, rc-tag default, Cloud Build strip pattern):
197
+ references/versioning.md.`
198
+
199
+ /** Known serving flags that take a value. Anything else is refused (exit 2). */
200
+ const KNOWN_VALUE_FLAGS = new Set([
201
+ 'health',
202
+ 'settings',
203
+ 'frontend-asset',
204
+ 'policy',
205
+ 'version',
206
+ 'sha',
207
+ 'trigger-tag',
208
+ 'deploy-trigger',
209
+ 'record-mismatch',
210
+ ])
211
+
212
+ function parseArgs(argv) {
213
+ const opts = {}
214
+ const positional = []
215
+ const unknown = []
216
+ const missing = []
217
+ for (let i = 0; i < argv.length; i++) {
218
+ const a = argv[i]
219
+ if (a === '--help' || a === '-h') {
220
+ opts.help = true
221
+ continue
222
+ }
223
+ if (a.startsWith('--')) {
224
+ const key = a.slice(2)
225
+ if (!KNOWN_VALUE_FLAGS.has(key)) {
226
+ unknown.push(a)
227
+ // If the next token looks like a value (not a flag), consume it so it is not
228
+ // re-classified as a bare positional — the flag itself is the error.
229
+ const next = argv[i + 1]
230
+ if (next !== undefined && !next.startsWith('-')) i++
231
+ continue
232
+ }
233
+ const next = argv[i + 1]
234
+ if (next === undefined || next.startsWith('-')) {
235
+ if (next !== undefined && next.startsWith('-')) {
236
+ // leave next token for the next iteration (flag/unknown)
237
+ }
238
+ missing.push(a)
239
+ continue
240
+ }
241
+ opts[key] = next
242
+ i++
243
+ continue
244
+ }
245
+ positional.push(a)
246
+ }
247
+ return { opts, positional, unknown, missing }
248
+ }
249
+
250
+ function readJson(file, what) {
251
+ if (!file) return { error: `usage: --${what} <file> is required` }
252
+ let raw
253
+ try {
254
+ raw = fs.readFileSync(file, 'utf8')
255
+ } catch {
256
+ return { error: `${what} not readable: ${file}` }
257
+ }
258
+ try {
259
+ return { value: JSON.parse(raw) }
260
+ } catch {
261
+ return { error: `${what} is not valid JSON: ${file}` }
262
+ }
263
+ }
264
+
265
+ export function main(argv) {
266
+ const { opts, positional, unknown, missing } = parseArgs(argv)
267
+ const cmd = positional[0]
268
+ const extraPositionals = positional.slice(1)
269
+
270
+ if (opts.help || cmd === 'help') {
271
+ console.log(USAGE)
272
+ return 0
273
+ }
274
+
275
+ if (unknown.length > 0) {
276
+ console.error(`version-assert: unknown argument(s): ${unknown.join(', ')}`)
277
+ return 2
278
+ }
279
+ if (missing.length > 0) {
280
+ console.error(`version-assert: missing or invalid value for: ${missing.join(', ')}`)
281
+ return 2
282
+ }
283
+ if (extraPositionals.length > 0) {
284
+ console.error(`version-assert: unexpected positional argument(s): ${extraPositionals.join(', ')}`)
285
+ return 2
286
+ }
287
+
288
+ if (cmd !== 'serving') {
289
+ const what = cmd ? `unknown command "${cmd}"` : 'no subcommand given'
290
+ console.error(`version-assert: ${what}. Use serving (see --help).`)
291
+ return 2
292
+ }
293
+
294
+ const health = readJson(opts.health, 'health')
295
+ const settings = readJson(opts.settings, 'settings')
296
+ const frontendAsset = readJson(opts['frontend-asset'], 'frontend-asset')
297
+ for (const source of [health, settings, frontendAsset]) {
298
+ if (source.error) {
299
+ console.error(`version-assert: ${source.error}`)
300
+ return 2
301
+ }
302
+ }
303
+
304
+ if (!opts.policy && !opts['deploy-trigger']) {
305
+ console.error('version-assert: serving requires --policy <final-semver|trigger-tag|short-sha>, or --deploy-trigger <topology> to resolve a default')
306
+ return 2
307
+ }
308
+
309
+ // Explicit --policy must be a known policy before we evaluate health. An invalid
310
+ // policy is a usage error (exit 2), not a display-version mismatch (exit 1).
311
+ if (opts.policy && !DISPLAY_VERSION_POLICIES.includes(opts.policy)) {
312
+ console.error(`version-assert: unknown policy "${opts.policy}". Use one of: ${DISPLAY_VERSION_POLICIES.join(', ')}`)
313
+ return 2
314
+ }
315
+
316
+ const resolved = resolveDisplayVersionPolicy(opts.policy, opts['deploy-trigger'])
317
+ if (resolved.error) {
318
+ console.error(`version-assert: ${resolved.error}: --policy is required when --deploy-trigger is not rc-tag`)
319
+ return 2
320
+ }
321
+
322
+ const result = evaluateDisplayVersion({
323
+ health: health.value,
324
+ settings: settings.value,
325
+ frontendAsset: frontendAsset.value,
326
+ policy: resolved.policy,
327
+ version: opts.version ?? null,
328
+ triggerTag: opts['trigger-tag'] ?? null,
329
+ sha: opts.sha ?? null,
330
+ recordMismatch: opts['record-mismatch'] ?? null,
331
+ })
332
+
333
+ console.log(JSON.stringify(result, null, 2))
334
+ return result.decision === 'accept' ? 0 : 1
335
+ }
336
+
337
+ if (isMainModule(import.meta.url)) {
338
+ process.exit(main(process.argv.slice(2)))
339
+ }