@1aboveio/skills 0.0.0-stage → 1.0.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 (633) hide show
  1. package/README.md +30 -2
  2. package/bin/cli.mjs +14 -0
  3. package/bin/select-core.mjs +172 -0
  4. package/package.json +146 -4
  5. package/skills/app-dev/airflow/LICENSE +3 -0
  6. package/skills/app-dev/airflow/SKILL.md +199 -0
  7. package/skills/app-dev/airflow/release-check.mjs +93 -0
  8. package/skills/app-dev/android-foundation/LICENSE +3 -0
  9. package/skills/app-dev/android-foundation/SKILL.md +192 -0
  10. package/skills/app-dev/android-foundation/assets/android-ci-job.yml +217 -0
  11. package/skills/app-dev/android-foundation/references/ci.md +87 -0
  12. package/skills/app-dev/android-foundation/references/gotchas.md +221 -0
  13. package/skills/app-dev/android-foundation/references/setup.md +164 -0
  14. package/skills/app-dev/android-foundation/release-check.mjs +93 -0
  15. package/skills/app-dev/android-foundation/scripts/device-run.sh +176 -0
  16. package/skills/app-dev/android-foundation/scripts/device-run.test.mjs +172 -0
  17. package/skills/app-dev/app-debug/LICENSE +3 -0
  18. package/skills/app-dev/app-debug/SKILL.md +110 -0
  19. package/skills/app-dev/app-debug/references/common-errors.md +128 -0
  20. package/skills/app-dev/app-debug/release-check.mjs +93 -0
  21. package/skills/app-dev/better-auth/LICENSE +3 -0
  22. package/skills/app-dev/better-auth/SKILL.md +598 -0
  23. package/skills/app-dev/better-auth/references/feishu-api.md +270 -0
  24. package/skills/app-dev/better-auth/release-check.mjs +93 -0
  25. package/skills/app-dev/data-catalog/LICENSE +3 -0
  26. package/skills/app-dev/data-catalog/SKILL.md +204 -0
  27. package/skills/app-dev/data-catalog/agents/openai.yaml +3 -0
  28. package/skills/app-dev/data-catalog/references/data-catalog-conventions.md +75 -0
  29. package/skills/app-dev/data-catalog/references/field-definitions.md +116 -0
  30. package/skills/app-dev/data-catalog/references/format.md +121 -0
  31. package/skills/app-dev/data-catalog/release-check.mjs +93 -0
  32. package/skills/app-dev/data-catalog/scripts/data-catalog.test.mjs +36 -0
  33. package/skills/app-dev/data-catalog/scripts/data_catalog.py +1392 -0
  34. package/skills/app-dev/data-catalog/scripts/persist-conventions-core.mjs +117 -0
  35. package/skills/app-dev/data-catalog/scripts/persist-conventions.mjs +17 -0
  36. package/skills/app-dev/data-catalog/scripts/test_data_catalog.py +571 -0
  37. package/skills/app-dev/ios-foundation/LICENSE +3 -0
  38. package/skills/app-dev/ios-foundation/SKILL.md +184 -0
  39. package/skills/app-dev/ios-foundation/references/setup.md +243 -0
  40. package/skills/app-dev/ios-foundation/release-check.mjs +93 -0
  41. package/skills/app-dev/monorepo/LICENSE +3 -0
  42. package/skills/app-dev/monorepo/SKILL.md +462 -0
  43. package/skills/app-dev/monorepo/release-check.mjs +93 -0
  44. package/skills/app-dev/nextjs-fullstack/LICENSE +3 -0
  45. package/skills/app-dev/nextjs-fullstack/SKILL.md +211 -0
  46. package/skills/app-dev/nextjs-fullstack/conventions.md +318 -0
  47. package/skills/app-dev/nextjs-fullstack/frontend-conventions.md +61 -0
  48. package/skills/app-dev/nextjs-fullstack/nextjs16.md +287 -0
  49. package/skills/app-dev/nextjs-fullstack/release-check.mjs +93 -0
  50. package/skills/app-dev/nextjs-fullstack/server-actions.md +409 -0
  51. package/skills/app-dev/prisma-setup/LICENSE +3 -0
  52. package/skills/app-dev/prisma-setup/SKILL.md +181 -0
  53. package/skills/app-dev/prisma-setup/nextjs.md +258 -0
  54. package/skills/app-dev/prisma-setup/release-check.mjs +93 -0
  55. package/skills/app-dev/prisma-setup/turborepo.md +301 -0
  56. package/skills/app-dev/pyspark/LICENSE +3 -0
  57. package/skills/app-dev/pyspark/SKILL.md +127 -0
  58. package/skills/app-dev/pyspark/assets/templates/etl.py +748 -0
  59. package/skills/app-dev/pyspark/assets/templates/utils/__init__.py +1 -0
  60. package/skills/app-dev/pyspark/assets/templates/utils/hudi_metadata.py +14 -0
  61. package/skills/app-dev/pyspark/references/diagnosis-and-profiling.md +169 -0
  62. package/skills/app-dev/pyspark/references/etl-contract.md +129 -0
  63. package/skills/app-dev/pyspark/references/production-validation.md +131 -0
  64. package/skills/app-dev/pyspark/references/reconciliation.md +38 -0
  65. package/skills/app-dev/pyspark/references/transformation-design.md +190 -0
  66. package/skills/app-dev/pyspark/references/velocity-feature-calculation.md +193 -0
  67. package/skills/app-dev/pyspark/release-check.mjs +93 -0
  68. package/skills/app-dev/pyspark/scripts/spark_eventlog_summary.py +223 -0
  69. package/skills/app-dev/python-backend/LICENSE +3 -0
  70. package/skills/app-dev/python-backend/SKILL.md +325 -0
  71. package/skills/app-dev/python-backend/assets/uv-install.sh +48 -0
  72. package/skills/app-dev/python-backend/references/uv-installs.md +83 -0
  73. package/skills/app-dev/python-backend/release-check.mjs +93 -0
  74. package/skills/app-dev/shadcn/LICENSE +3 -0
  75. package/skills/app-dev/shadcn/SKILL.md +120 -0
  76. package/skills/app-dev/shadcn/assets/shadcn-small.png +0 -0
  77. package/skills/app-dev/shadcn/assets/shadcn.png +0 -0
  78. package/skills/app-dev/shadcn/cli.md +411 -0
  79. package/skills/app-dev/shadcn/customization.md +224 -0
  80. package/skills/app-dev/shadcn/mcp.md +101 -0
  81. package/skills/app-dev/shadcn/release-check.mjs +93 -0
  82. package/skills/app-dev/shadcn/rules/base-vs-radix.md +323 -0
  83. package/skills/app-dev/shadcn/rules/component-selection.md +67 -0
  84. package/skills/app-dev/shadcn/rules/composition.md +195 -0
  85. package/skills/app-dev/shadcn/rules/data-table.md +201 -0
  86. package/skills/app-dev/shadcn/rules/forms.md +255 -0
  87. package/skills/app-dev/shadcn/rules/icons.md +103 -0
  88. package/skills/app-dev/shadcn/rules/styling.md +167 -0
  89. package/skills/app-dev/zod-v4/LICENSE +3 -0
  90. package/skills/app-dev/zod-v4/SKILL.md +286 -0
  91. package/skills/app-dev/zod-v4/release-check.mjs +93 -0
  92. package/skills/cicd/cloud-build/LICENSE +3 -0
  93. package/skills/cicd/cloud-build/SKILL.md +707 -0
  94. package/skills/cicd/cloud-build/release-check.mjs +93 -0
  95. package/skills/cicd/cloud-debug/LICENSE +3 -0
  96. package/skills/cicd/cloud-debug/SKILL.md +315 -0
  97. package/skills/cicd/cloud-debug/references/build-failures.md +238 -0
  98. package/skills/cicd/cloud-debug/references/deploy-failures.md +376 -0
  99. package/skills/cicd/cloud-debug/references/pipeline-failures.md +378 -0
  100. package/skills/cicd/cloud-debug/release-check.mjs +93 -0
  101. package/skills/cicd/cloud-deploy/LICENSE +3 -0
  102. package/skills/cicd/cloud-deploy/SKILL.md +230 -0
  103. package/skills/cicd/cloud-deploy/references/config-templates.md +257 -0
  104. package/skills/cicd/cloud-deploy/release-check.mjs +93 -0
  105. package/skills/cicd/docker/LICENSE +3 -0
  106. package/skills/cicd/docker/SKILL.md +151 -0
  107. package/skills/cicd/docker/release-check.mjs +93 -0
  108. package/skills/cicd/github-actions/LICENSE +3 -0
  109. package/skills/cicd/github-actions/SKILL.md +111 -0
  110. package/skills/cicd/github-actions/references/audit-profile-optimize.md +150 -0
  111. package/skills/cicd/github-actions/references/ci-case-studies.md +141 -0
  112. package/skills/cicd/github-actions/references/conditional-ci.md +214 -0
  113. package/skills/cicd/github-actions/references/debugging.md +13 -0
  114. package/skills/cicd/github-actions/references/pipeline.md +87 -0
  115. package/skills/cicd/github-actions/references/post-deploy-and-publishing.md +33 -0
  116. package/skills/cicd/github-actions/references/runners.md +253 -0
  117. package/skills/cicd/github-actions/references/security.md +29 -0
  118. package/skills/cicd/github-actions/references/speed-and-audit.md +115 -0
  119. package/skills/cicd/github-actions/references/two-pass-reading.md +92 -0
  120. package/skills/cicd/github-actions/release-check.mjs +93 -0
  121. package/skills/cicd/github-actions/scripts/ci-run-audit-core.mjs +612 -0
  122. package/skills/cicd/github-actions/scripts/ci-run-audit.mjs +4 -0
  123. package/skills/cicd/github-actions/scripts/ci-run-audit.test.mjs +637 -0
  124. package/skills/cicd/github-flow/LICENSE +3 -0
  125. package/skills/cicd/github-flow/SKILL.md +123 -0
  126. package/skills/cicd/github-flow/references/ci-conventions.md +14 -0
  127. package/skills/cicd/github-flow/release-check.mjs +93 -0
  128. package/skills/cicd/github-flow/scripts/flow-core.mjs +105 -0
  129. package/skills/cicd/github-flow/scripts/flow.mjs +81 -0
  130. package/skills/cicd/github-flow/scripts/flow.test.mjs +114 -0
  131. package/skills/cicd/github-flow/scripts/persist-conventions-core.mjs +117 -0
  132. package/skills/cicd/github-flow/scripts/persist-conventions.mjs +49 -0
  133. package/skills/cicd/github-flow/scripts/persist-conventions.test.mjs +108 -0
  134. package/skills/cicd/google-cloud/LICENSE +3 -0
  135. package/skills/cicd/google-cloud/SKILL.md +119 -0
  136. package/skills/cicd/google-cloud/references/gcs.md +469 -0
  137. package/skills/cicd/google-cloud/references/iam.md +451 -0
  138. package/skills/cicd/google-cloud/references/project.md +349 -0
  139. package/skills/cicd/google-cloud/references/secrets.md +336 -0
  140. package/skills/cicd/google-cloud/references/vpc.md +312 -0
  141. package/skills/cicd/google-cloud/release-check.mjs +93 -0
  142. package/skills/cicd/google-cloud/scripts/create-sa.sh +36 -0
  143. package/skills/cicd/google-cloud/scripts/gcp-config.sh +31 -0
  144. package/skills/cicd/google-cloud/scripts/grant-iap.sh +41 -0
  145. package/skills/cicd/google-cloud/scripts/setup-secrets.sh +48 -0
  146. package/skills/cicd/mergify/LICENSE +3 -0
  147. package/skills/cicd/mergify/SKILL.md +102 -0
  148. package/skills/cicd/mergify/assets/templates/mergify.yml +215 -0
  149. package/skills/cicd/mergify/assets/templates/ruleset.json +46 -0
  150. package/skills/cicd/mergify/references/branch-protection.md +282 -0
  151. package/skills/cicd/mergify/references/configuration.md +274 -0
  152. package/skills/cicd/mergify/references/diagnosis.md +109 -0
  153. package/skills/cicd/mergify/references/stacks.md +84 -0
  154. package/skills/cicd/mergify/references/traps.md +119 -0
  155. package/skills/cicd/mergify/references/watch-contract.md +274 -0
  156. package/skills/cicd/mergify/release-check.mjs +93 -0
  157. package/skills/cicd/mergify/scripts/audit-core.mjs +208 -0
  158. package/skills/cicd/mergify/scripts/audit.mjs +4 -0
  159. package/skills/cicd/mergify/scripts/audit.test.mjs +201 -0
  160. package/skills/cicd/mergify/scripts/entrypoints.test.mjs +106 -0
  161. package/skills/cicd/mergify/scripts/pr-620-mergify-comments.fixture.json +30 -0
  162. package/skills/cicd/mergify/scripts/stack-push-core.mjs +258 -0
  163. package/skills/cicd/mergify/scripts/stack-push.mjs +4 -0
  164. package/skills/cicd/mergify/scripts/stack-push.test.mjs +233 -0
  165. package/skills/cicd/mergify/scripts/watch-pr-delivery-core.mjs +1065 -0
  166. package/skills/cicd/mergify/scripts/watch-pr-delivery.mjs +4 -0
  167. package/skills/cicd/mergify/scripts/watch-pr-delivery.test.mjs +1826 -0
  168. package/skills/cicd/podman/LICENSE +3 -0
  169. package/skills/cicd/podman/SKILL.md +71 -0
  170. package/skills/cicd/podman/agents/openai.yaml +4 -0
  171. package/skills/cicd/podman/assets/templates/podman-compose-socket-directory.yml +6 -0
  172. package/skills/cicd/podman/assets/templates/podman-service-override.conf +3 -0
  173. package/skills/cicd/podman/references/compose-compatibility.md +70 -0
  174. package/skills/cicd/podman/references/networking-and-ports.md +74 -0
  175. package/skills/cicd/podman/references/rootless-services-and-sockets.md +156 -0
  176. package/skills/cicd/podman/references/troubleshooting.md +98 -0
  177. package/skills/cicd/podman/release-check.mjs +93 -0
  178. package/skills/content/article-review/LICENSE +3 -0
  179. package/skills/content/article-review/SKILL.md +66 -0
  180. package/skills/content/article-review/references/report-format.md +68 -0
  181. package/skills/content/article-review/references/template-guide.md +79 -0
  182. package/skills/content/article-review/references/template-wechat-payments.md +125 -0
  183. package/skills/content/article-review/release-check.mjs +93 -0
  184. package/skills/content/article-to-image/LICENSE +3 -0
  185. package/skills/content/article-to-image/SKILL.md +91 -0
  186. package/skills/content/article-to-image/references/formats.md +53 -0
  187. package/skills/content/article-to-image/release-check.mjs +93 -0
  188. package/skills/content/flowchart-svg/LICENSE +3 -0
  189. package/skills/content/flowchart-svg/SKILL.md +43 -0
  190. package/skills/content/flowchart-svg/release-check.mjs +93 -0
  191. package/skills/content/flowchart-svg/scripts/export_png.sh +8 -0
  192. package/skills/content/image-gen/LICENSE +3 -0
  193. package/skills/content/image-gen/SKILL.md +192 -0
  194. package/skills/content/image-gen/release-check.mjs +93 -0
  195. package/skills/content/image-gen/scripts/credentials.mjs +217 -0
  196. package/skills/content/image-gen/scripts/credentials.test.mjs +212 -0
  197. package/skills/content/image-gen/scripts/generate.mjs +240 -0
  198. package/skills/content/image-gen/scripts/options.mjs +293 -0
  199. package/skills/content/image-gen/scripts/options.test.mjs +245 -0
  200. package/skills/content/mermaid/LICENSE +3 -0
  201. package/skills/content/mermaid/SKILL.md +635 -0
  202. package/skills/content/mermaid/release-check.mjs +93 -0
  203. package/skills/content/wechat-article-writer/LICENSE +3 -0
  204. package/skills/content/wechat-article-writer/SKILL.md +92 -0
  205. package/skills/content/wechat-article-writer/references/style-selector.md +133 -0
  206. package/skills/content/wechat-article-writer/references/writing-rules.md +152 -0
  207. package/skills/content/wechat-article-writer/release-check.mjs +93 -0
  208. package/skills/content/wechat-article-writer/templates/wechat-comparison.md +52 -0
  209. package/skills/content/wechat-article-writer/templates/wechat-howto.md +51 -0
  210. package/skills/content/wechat-article-writer/templates/wechat-insight.md +50 -0
  211. package/skills/content/wechat-article-writer/templates/wechat-pitfall.md +52 -0
  212. package/skills/content/wechat-publisher/LICENSE +3 -0
  213. package/skills/content/wechat-publisher/SKILL.md +171 -0
  214. package/skills/content/wechat-publisher/references/api.md +105 -0
  215. package/skills/content/wechat-publisher/references/layout-rules.md +57 -0
  216. package/skills/content/wechat-publisher/references/wechat-safe-template.html +86 -0
  217. package/skills/content/wechat-publisher/release-check.mjs +93 -0
  218. package/skills/content/wechat-publisher/scripts/md_to_wechat_html.py +194 -0
  219. package/skills/content/wechat-publisher/scripts/publish.py +239 -0
  220. package/skills/content/wechat-search/LICENSE +3 -0
  221. package/skills/content/wechat-search/SKILL.md +211 -0
  222. package/skills/content/wechat-search/release-check.mjs +93 -0
  223. package/skills/content/wechat-search/scripts/start-chrome.sh +83 -0
  224. package/skills/content/xai-search/LICENSE +3 -0
  225. package/skills/content/xai-search/SKILL.md +79 -0
  226. package/skills/content/xai-search/release-check.mjs +93 -0
  227. package/skills/content/xai-search/scripts/xai_search.sh +187 -0
  228. package/skills/content/xai-search/tests/smoke_test.sh +36 -0
  229. package/skills/core/distill-writing/LICENSE +3 -0
  230. package/skills/core/distill-writing/SKILL.md +74 -0
  231. package/skills/core/distill-writing/references/extraction.md +95 -0
  232. package/skills/core/distill-writing/references/updating.md +46 -0
  233. package/skills/core/distill-writing/release-check.mjs +93 -0
  234. package/skills/core/doc-to-md/LICENSE +3 -0
  235. package/skills/core/doc-to-md/SKILL.md +78 -0
  236. package/skills/core/doc-to-md/release-check.mjs +93 -0
  237. package/skills/core/doc-to-md/scripts/convert.py +157 -0
  238. package/skills/core/editorial-review/LICENSE +3 -0
  239. package/skills/core/editorial-review/SKILL.md +79 -0
  240. package/skills/core/editorial-review/references/checklist.md +94 -0
  241. package/skills/core/editorial-review/release-check.mjs +93 -0
  242. package/skills/core/house-style/LICENSE +3 -0
  243. package/skills/core/house-style/SKILL.md +33 -0
  244. package/skills/core/house-style/references/defaults.md +66 -0
  245. package/skills/core/house-style/references/rules.md +267 -0
  246. package/skills/core/house-style/references/sources.md +27 -0
  247. package/skills/core/house-style/references/style-en.md +131 -0
  248. package/skills/core/house-style/references/style-zh.md +141 -0
  249. package/skills/core/house-style/references/terminology-zh.md +223 -0
  250. package/skills/core/house-style/release-check.mjs +93 -0
  251. package/skills/core/house-style/templates/brd.md +103 -0
  252. package/skills/core/house-style/templates/commercial-proposal.md +93 -0
  253. package/skills/core/house-style/templates/compliance-policy.md +109 -0
  254. package/skills/core/house-style/templates/gap-analysis.md +105 -0
  255. package/skills/core/house-style/templates/general.md +63 -0
  256. package/skills/core/house-style/templates/integration-guide.md +98 -0
  257. package/skills/core/house-style/templates/prd.md +81 -0
  258. package/skills/core/house-style/templates/risk-operations-procedure.md +94 -0
  259. package/skills/core/house-style/templates/technical-spec.md +96 -0
  260. package/skills/core/polish-cn/LICENSE +3 -0
  261. package/skills/core/polish-cn/SKILL.md +102 -0
  262. package/skills/core/polish-cn/references/brief.md +93 -0
  263. package/skills/core/polish-cn/references/models.md +76 -0
  264. package/skills/core/polish-cn/release-check.mjs +93 -0
  265. package/skills/core/polish-cn/scripts/polish-cn.test.mjs +244 -0
  266. package/skills/core/polish-cn/scripts/polish_blocks.py +489 -0
  267. package/skills/core/reg-parser/LICENSE +3 -0
  268. package/skills/core/reg-parser/SKILL.md +212 -0
  269. package/skills/core/reg-parser/references/checklist-schema.md +223 -0
  270. package/skills/core/reg-parser/references/checklists/hk-amlo-checklist.json +1306 -0
  271. package/skills/core/reg-parser/references/checklists/hk-amlo-checklist.md +469 -0
  272. package/skills/core/reg-parser/references/checklists/hk-fi-corporate-onboarding-cdd-checklist.json +634 -0
  273. package/skills/core/reg-parser/references/checklists/hk-fi-corporate-onboarding-cdd-checklist.md +233 -0
  274. package/skills/core/reg-parser/references/checklists/hk-mso-guideline-checklist.json +2194 -0
  275. package/skills/core/reg-parser/references/checklists/hk-mso-guideline-checklist.md +771 -0
  276. package/skills/core/reg-parser/references/checklists/kyc-aml-checklist.md +258 -0
  277. package/skills/core/reg-parser/references/checklists/visa-vars-checklist.md +1058 -0
  278. package/skills/core/reg-parser/references/mandates/hk-amlo-cap615.md +389 -0
  279. package/skills/core/reg-parser/references/mandates/visa-vars.md +205 -0
  280. package/skills/core/reg-parser/release-check.mjs +93 -0
  281. package/skills/core/reg-parser/scripts/compare_checklist.py +230 -0
  282. package/skills/core/reg-parser/scripts/dump_checklist.py +361 -0
  283. package/skills/core/reg-parser/scripts/preprocess-mandate.sh +187 -0
  284. package/skills/core/reg-parser/scripts/reg-parser.test.mjs +165 -0
  285. package/skills/core/reg-parser/scripts/test_quarantine.sh +105 -0
  286. package/skills/core/reg-parser/scripts/validate_checklist.py +563 -0
  287. package/skills/core/reg-parser/scripts/validate_mandate.py +273 -0
  288. package/skills/core/terminology/LICENSE +3 -0
  289. package/skills/core/terminology/SKILL.md +62 -0
  290. package/skills/core/terminology/references/format.md +50 -0
  291. package/skills/core/terminology/references/init.md +32 -0
  292. package/skills/core/terminology/release-check.mjs +93 -0
  293. package/skills/core/write-doc/LICENSE +3 -0
  294. package/skills/core/write-doc/SKILL.md +141 -0
  295. package/skills/core/write-doc/references/bilingual.md +60 -0
  296. package/skills/core/write-doc/release-check.mjs +93 -0
  297. package/skills/engineering/better-review/LICENSE +3 -0
  298. package/skills/engineering/better-review/SKILL.md +249 -0
  299. package/skills/engineering/better-review/agents/openai.yaml +9 -0
  300. package/skills/engineering/better-review/references/domain-hazards.md +53 -0
  301. package/skills/engineering/better-review/references/passes.md +147 -0
  302. package/skills/engineering/better-review/references/result.md +151 -0
  303. package/skills/engineering/better-review/release-check.mjs +93 -0
  304. package/skills/engineering/better-review/scripts/pr-context.mjs +212 -0
  305. package/skills/engineering/better-review/scripts/pr-context.test.mjs +168 -0
  306. package/skills/engineering/better-review/scripts/rereview-scope.mjs +503 -0
  307. package/skills/engineering/better-review/scripts/rereview-scope.test.mjs +587 -0
  308. package/skills/engineering/better-review/scripts/scan-diff.mjs +365 -0
  309. package/skills/engineering/better-review/scripts/scan-diff.test.mjs +414 -0
  310. package/skills/engineering/better-review/scripts/vendor-sync.test.mjs +96 -0
  311. package/skills/engineering/e2e-test/LICENSE +3 -0
  312. package/skills/engineering/e2e-test/SKILL.md +98 -0
  313. package/skills/engineering/e2e-test/assets/ci-gates.cloudbuild.yaml +24 -0
  314. package/skills/engineering/e2e-test/references/authoring/auth-flows.md +159 -0
  315. package/skills/engineering/e2e-test/references/authoring/playwright-config.md +73 -0
  316. package/skills/engineering/e2e-test/references/authoring/playwright-patterns.md +144 -0
  317. package/skills/engineering/e2e-test/references/ci-integration.md +25 -0
  318. package/skills/engineering/e2e-test/references/ci-playwright-container.md +290 -0
  319. package/skills/engineering/e2e-test/references/presentation-sweep.md +104 -0
  320. package/skills/engineering/e2e-test/references/reviewing.md +41 -0
  321. package/skills/engineering/e2e-test/references/route-manifest.md +51 -0
  322. package/skills/engineering/e2e-test/release-check.mjs +93 -0
  323. package/skills/engineering/e2e-test/scripts/detect-routes-nextjs.mjs +200 -0
  324. package/skills/engineering/e2e-test/scripts/presentation-checks.mjs +171 -0
  325. package/skills/engineering/e2e-test/scripts/presentation-checks.test.mjs +106 -0
  326. package/skills/engineering/e2e-test/scripts/presentation-perceivability.mjs +179 -0
  327. package/skills/engineering/e2e-test/scripts/presentation-perceivability.test.mjs +117 -0
  328. package/skills/engineering/e2e-test/scripts/presentation-reachability.mjs +154 -0
  329. package/skills/engineering/e2e-test/scripts/presentation-reachability.test.mjs +69 -0
  330. package/skills/engineering/e2e-test/scripts/presentation-render-health.mjs +141 -0
  331. package/skills/engineering/e2e-test/scripts/presentation-render-health.test.mjs +98 -0
  332. package/skills/engineering/e2e-test/scripts/presentation-sweep.mjs +147 -0
  333. package/skills/engineering/e2e-test/scripts/presentation-sweep.test.mjs +71 -0
  334. package/skills/engineering/e2e-test/scripts/presentation-temporal.mjs +127 -0
  335. package/skills/engineering/e2e-test/scripts/presentation-temporal.test.mjs +59 -0
  336. package/skills/engineering/e2e-test/scripts/project-route-manifest.mjs +82 -0
  337. package/skills/engineering/e2e-test/scripts/project-route-manifest.test.mjs +76 -0
  338. package/skills/engineering/e2e-test/scripts/validate-manifest.mjs +106 -0
  339. package/skills/engineering/engineering-runtime/LICENSE +3 -0
  340. package/skills/engineering/engineering-runtime/SKILL.md +11 -0
  341. package/skills/engineering/engineering-runtime/agents/openai.yaml +6 -0
  342. package/skills/engineering/engineering-runtime/coherence/workflow.json +597 -0
  343. package/skills/engineering/engineering-runtime/engineering-runtime.test.mjs +68 -0
  344. package/skills/engineering/engineering-runtime/release-check.mjs +93 -0
  345. package/skills/engineering/engineering-runtime/scripts/exact-head-artifact.mjs +131 -0
  346. package/skills/engineering/engineering-runtime/scripts/head-check-set.mjs +398 -0
  347. package/skills/engineering/engineering-runtime/scripts/invocation-policy.mjs +187 -0
  348. package/skills/engineering/engineering-runtime/scripts/invocation-policy.test.mjs +95 -0
  349. package/skills/engineering/engineering-runtime/scripts/main-module.mjs +79 -0
  350. package/skills/engineering/engineering-runtime/scripts/main-module.test.mjs +288 -0
  351. package/skills/engineering/engineering-runtime/scripts/mergify-yaml.mjs +11 -0
  352. package/skills/engineering/engineering-runtime/scripts/package-lock.json +43 -0
  353. package/skills/engineering/engineering-runtime/scripts/package.json +10 -0
  354. package/skills/engineering/engineering-runtime/scripts/required-check-plan.mjs +223 -0
  355. package/skills/engineering/engineering-runtime/scripts/required-check-plan.test.mjs +96 -0
  356. package/skills/engineering/engineering-runtime/scripts/review-completion.mjs +56 -0
  357. package/skills/engineering/engineering-runtime/scripts/workflow-coherence.mjs +595 -0
  358. package/skills/engineering/engineering-runtime/scripts/workflow-policy.mjs +189 -0
  359. package/skills/engineering/engineering-runtime/scripts/yaml-mapping.mjs +18 -0
  360. package/skills/engineering/ensure-coverage/LICENSE +3 -0
  361. package/skills/engineering/ensure-coverage/SKILL.md +129 -0
  362. package/skills/engineering/ensure-coverage/references/breadth/coverage-ledger.md +92 -0
  363. package/skills/engineering/ensure-coverage/references/breadth/inventory-contract.md +85 -0
  364. package/skills/engineering/ensure-coverage/references/breadth/surface-baseline.md +44 -0
  365. package/skills/engineering/ensure-coverage/references/breadth/surface-discovery.md +16 -0
  366. package/skills/engineering/ensure-coverage/references/depth/characterization.md +68 -0
  367. package/skills/engineering/ensure-coverage/references/depth/coverage.config.example.json +19 -0
  368. package/skills/engineering/ensure-coverage/references/depth/grading.md +35 -0
  369. package/skills/engineering/ensure-coverage/references/depth/mock-policy.md +57 -0
  370. package/skills/engineering/ensure-coverage/references/depth/test-smells.md +39 -0
  371. package/skills/engineering/ensure-coverage/references/enforcement/ci-contract.md +44 -0
  372. package/skills/engineering/ensure-coverage/references/examples/coverage-ledger.md +110 -0
  373. package/skills/engineering/ensure-coverage/references/examples/refund-flow.md +35 -0
  374. package/skills/engineering/ensure-coverage/references/presentation/axis.md +64 -0
  375. package/skills/engineering/ensure-coverage/references/process/audit-mode.md +27 -0
  376. package/skills/engineering/ensure-coverage/references/process/output-template.md +139 -0
  377. package/skills/engineering/ensure-coverage/references/process/test-strategy.md +56 -0
  378. package/skills/engineering/ensure-coverage/release-check.mjs +93 -0
  379. package/skills/engineering/ensure-coverage/schemas/coverage-config.schema.json +67 -0
  380. package/skills/engineering/ensure-coverage/schemas/coverage-file.schema.json +140 -0
  381. package/skills/engineering/ensure-coverage/scripts/README.md +99 -0
  382. package/skills/engineering/ensure-coverage/scripts/adapters/nextjs-inventory.mjs +182 -0
  383. package/skills/engineering/ensure-coverage/scripts/adapters/nextjs-inventory.test.mjs +96 -0
  384. package/skills/engineering/ensure-coverage/scripts/check-quarantine-expiry.mjs +105 -0
  385. package/skills/engineering/ensure-coverage/scripts/check-quarantine-expiry.test.mjs +47 -0
  386. package/skills/engineering/ensure-coverage/scripts/ci-audit.mjs +137 -0
  387. package/skills/engineering/ensure-coverage/scripts/ci-audit.test.mjs +86 -0
  388. package/skills/engineering/ensure-coverage/scripts/coverage-ledger.mjs +674 -0
  389. package/skills/engineering/ensure-coverage/scripts/coverage-ledger.test.mjs +447 -0
  390. package/skills/engineering/ensure-coverage/scripts/design-parity.mjs +591 -0
  391. package/skills/engineering/ensure-coverage/scripts/design-parity.test.mjs +552 -0
  392. package/skills/engineering/ensure-coverage/scripts/lint-tests.mjs +282 -0
  393. package/skills/engineering/ensure-coverage/scripts/lint-tests.test.mjs +289 -0
  394. package/skills/engineering/ensure-coverage/scripts/mock-policy-config.mjs +176 -0
  395. package/skills/engineering/ensure-coverage/scripts/mock-policy-config.test.mjs +119 -0
  396. package/skills/engineering/ensure-coverage/scripts/package.json +19 -0
  397. package/skills/engineering/golden-path/LICENSE +3 -0
  398. package/skills/engineering/golden-path/SKILL.md +230 -0
  399. package/skills/engineering/golden-path/agents/openai.yaml +3 -0
  400. package/skills/engineering/golden-path/assets/golden-paths.example.json +57 -0
  401. package/skills/engineering/golden-path/references/contract.md +239 -0
  402. package/skills/engineering/golden-path/references/migration.md +111 -0
  403. package/skills/engineering/golden-path/release-check.mjs +93 -0
  404. package/skills/engineering/golden-path/scripts/golden-path-core.mjs +1779 -0
  405. package/skills/engineering/golden-path/scripts/golden-path.mjs +6 -0
  406. package/skills/engineering/golden-path/scripts/golden-path.test.mjs +1457 -0
  407. package/skills/engineering/harness-runtime/LICENSE +3 -0
  408. package/skills/engineering/harness-runtime/SKILL.md +19 -0
  409. package/skills/engineering/harness-runtime/agents/openai.yaml +6 -0
  410. package/skills/engineering/harness-runtime/bin/discover-models.mjs +4 -0
  411. package/skills/engineering/harness-runtime/bin/model-catalog.mjs +4 -0
  412. package/skills/engineering/harness-runtime/contracts.md +15 -0
  413. package/skills/engineering/harness-runtime/discover-models.mjs +392 -0
  414. package/skills/engineering/harness-runtime/discover-models.test.mjs +363 -0
  415. package/skills/engineering/harness-runtime/fixtures/native-question-schemas.json +33 -0
  416. package/skills/engineering/harness-runtime/fixtures/question-responses.json +54 -0
  417. package/skills/engineering/harness-runtime/harness-runtime.test.mjs +967 -0
  418. package/skills/engineering/harness-runtime/index.mjs +767 -0
  419. package/skills/engineering/harness-runtime/model-catalog-seed.test.mjs +829 -0
  420. package/skills/engineering/harness-runtime/model-catalog.mjs +787 -0
  421. package/skills/engineering/harness-runtime/model-catalog.test.mjs +366 -0
  422. package/skills/engineering/harness-runtime/native-question-contracts.md +37 -0
  423. package/skills/engineering/harness-runtime/references/model-catalog-seed.json +408 -0
  424. package/skills/engineering/harness-runtime/references/model-catalog.md +57 -0
  425. package/skills/engineering/harness-runtime/release-check.mjs +93 -0
  426. package/skills/engineering/resolve-issues/LICENSE +3 -0
  427. package/skills/engineering/resolve-issues/SKILL.md +250 -0
  428. package/skills/engineering/resolve-issues/agents/openai.yaml +9 -0
  429. package/skills/engineering/resolve-issues/plugin-hooks.json +17 -0
  430. package/skills/engineering/resolve-issues/references/canary.md +28 -0
  431. package/skills/engineering/resolve-issues/references/ci.md +105 -0
  432. package/skills/engineering/resolve-issues/references/done.md +25 -0
  433. package/skills/engineering/resolve-issues/references/dropbox.md +90 -0
  434. package/skills/engineering/resolve-issues/references/expire.md +318 -0
  435. package/skills/engineering/resolve-issues/references/exploration.md +202 -0
  436. package/skills/engineering/resolve-issues/references/implementation.md +303 -0
  437. package/skills/engineering/resolve-issues/references/preflight.md +445 -0
  438. package/skills/engineering/resolve-issues/references/review.md +228 -0
  439. package/skills/engineering/resolve-issues/references/shared-modules.md +44 -0
  440. package/skills/engineering/resolve-issues/references/task-plan.md +264 -0
  441. package/skills/engineering/resolve-issues/release-check.mjs +93 -0
  442. package/skills/engineering/resolve-issues/scripts/cleanup-runs.mjs +364 -0
  443. package/skills/engineering/resolve-issues/scripts/cleanup-runs.test.mjs +280 -0
  444. package/skills/engineering/resolve-issues/scripts/discover-models.mjs +9 -0
  445. package/skills/engineering/resolve-issues/scripts/dropbox.mjs +473 -0
  446. package/skills/engineering/resolve-issues/scripts/dropbox.test.mjs +346 -0
  447. package/skills/engineering/resolve-issues/scripts/findings-reuse.mjs +98 -0
  448. package/skills/engineering/resolve-issues/scripts/findings-reuse.test.mjs +88 -0
  449. package/skills/engineering/resolve-issues/scripts/github-reviews.mjs +384 -0
  450. package/skills/engineering/resolve-issues/scripts/github-reviews.test.mjs +264 -0
  451. package/skills/engineering/resolve-issues/scripts/install-hooks.mjs +135 -0
  452. package/skills/engineering/resolve-issues/scripts/install-hooks.test.mjs +79 -0
  453. package/skills/engineering/resolve-issues/scripts/issue-tree.mjs +162 -0
  454. package/skills/engineering/resolve-issues/scripts/issue-tree.test.mjs +107 -0
  455. package/skills/engineering/resolve-issues/scripts/manual-invocation.test.mjs +14 -0
  456. package/skills/engineering/resolve-issues/scripts/model-catalog.mjs +9 -0
  457. package/skills/engineering/resolve-issues/scripts/next-actions-capacity.test.mjs +149 -0
  458. package/skills/engineering/resolve-issues/scripts/next-actions.mjs +856 -0
  459. package/skills/engineering/resolve-issues/scripts/next-actions.test.mjs +915 -0
  460. package/skills/engineering/resolve-issues/scripts/plan-sync.mjs +269 -0
  461. package/skills/engineering/resolve-issues/scripts/plan-sync.test.mjs +156 -0
  462. package/skills/engineering/resolve-issues/scripts/preflight-models.mjs +736 -0
  463. package/skills/engineering/resolve-issues/scripts/preflight-models.test.mjs +448 -0
  464. package/skills/engineering/resolve-issues/scripts/ready-check.mjs +185 -0
  465. package/skills/engineering/resolve-issues/scripts/ready-check.test.mjs +217 -0
  466. package/skills/engineering/resolve-issues/scripts/rehydrate.mjs +98 -0
  467. package/skills/engineering/resolve-issues/scripts/rehydrate.test.mjs +91 -0
  468. package/skills/engineering/resolve-issues/scripts/review-verdict.mjs +509 -0
  469. package/skills/engineering/resolve-issues/scripts/review-verdict.test.mjs +1060 -0
  470. package/skills/engineering/resolve-issues/scripts/size-check.mjs +492 -0
  471. package/skills/engineering/resolve-issues/scripts/size-check.test.mjs +458 -0
  472. package/skills/engineering/resolve-release/LICENSE +3 -0
  473. package/skills/engineering/resolve-release/SKILL.md +215 -0
  474. package/skills/engineering/resolve-release/agents/openai.yaml +8 -0
  475. package/skills/engineering/resolve-release/flows/cloud-run-canary.md +13 -0
  476. package/skills/engineering/resolve-release/flows/cloud-run.md +7 -0
  477. package/skills/engineering/resolve-release/flows/root-tag-npm.md +13 -0
  478. package/skills/engineering/resolve-release/flows/workspace-npm.md +22 -0
  479. package/skills/engineering/resolve-release/references/canary.md +51 -0
  480. package/skills/engineering/resolve-release/references/candidate.md +41 -0
  481. package/skills/engineering/resolve-release/references/cut.md +131 -0
  482. package/skills/engineering/resolve-release/references/dark-launch.md +66 -0
  483. package/skills/engineering/resolve-release/references/flows.md +150 -0
  484. package/skills/engineering/resolve-release/references/preflight.md +154 -0
  485. package/skills/engineering/resolve-release/references/prepared-metadata.md +260 -0
  486. package/skills/engineering/resolve-release/references/promotion.md +82 -0
  487. package/skills/engineering/resolve-release/references/publish.md +232 -0
  488. package/skills/engineering/resolve-release/references/workspace-npm.md +103 -0
  489. package/skills/engineering/resolve-release/release-check.mjs +93 -0
  490. package/skills/engineering/resolve-release/scripts/apply.mjs +212 -0
  491. package/skills/engineering/resolve-release/scripts/apply.test.mjs +99 -0
  492. package/skills/engineering/resolve-release/scripts/dark-flags.mjs +134 -0
  493. package/skills/engineering/resolve-release/scripts/dark-flags.test.mjs +100 -0
  494. package/skills/engineering/resolve-release/scripts/flow.mjs +500 -0
  495. package/skills/engineering/resolve-release/scripts/flow.test.mjs +340 -0
  496. package/skills/engineering/resolve-release/scripts/green-head.mjs +231 -0
  497. package/skills/engineering/resolve-release/scripts/green-head.test.mjs +101 -0
  498. package/skills/engineering/resolve-release/scripts/npm-version-absence.mjs +138 -0
  499. package/skills/engineering/resolve-release/scripts/npm-version-absence.test.mjs +426 -0
  500. package/skills/engineering/resolve-release/scripts/plan-npm.test.mjs +659 -0
  501. package/skills/engineering/resolve-release/scripts/plan-toml-boundary.test.mjs +317 -0
  502. package/skills/engineering/resolve-release/scripts/plan-uv.test.mjs +291 -0
  503. package/skills/engineering/resolve-release/scripts/plan.mjs +806 -0
  504. package/skills/engineering/resolve-release/scripts/plan.test.mjs +428 -0
  505. package/skills/engineering/rush-issues/LICENSE +3 -0
  506. package/skills/engineering/rush-issues/SKILL.md +58 -0
  507. package/skills/engineering/rush-issues/agents/openai.yaml +8 -0
  508. package/skills/engineering/rush-issues/rehydrate.mjs +10 -0
  509. package/skills/engineering/rush-issues/release-check.mjs +93 -0
  510. package/skills/engineering/rush-release/LICENSE +3 -0
  511. package/skills/engineering/rush-release/SKILL.md +35 -0
  512. package/skills/engineering/rush-release/agents/openai.yaml +8 -0
  513. package/skills/engineering/rush-release/release-check.mjs +93 -0
  514. package/skills/engineering/test-quality/LICENSE +3 -0
  515. package/skills/engineering/test-quality/SKILL.md +79 -0
  516. package/skills/engineering/test-quality/references/audit.md +80 -0
  517. package/skills/engineering/test-quality/references/lint.md +24 -0
  518. package/skills/engineering/test-quality/references/principles.md +143 -0
  519. package/skills/engineering/test-quality/references/testing-conventions.md +9 -0
  520. package/skills/engineering/test-quality/release-check.mjs +93 -0
  521. package/skills/engineering/test-quality/scripts/lint-tests.mjs +574 -0
  522. package/skills/engineering/test-quality/scripts/lint-tests.test.mjs +591 -0
  523. package/skills/engineering/test-quality/scripts/mock-policy-config.mjs +176 -0
  524. package/skills/engineering/test-quality/scripts/mock-policy-config.test.mjs +119 -0
  525. package/skills/engineering/test-quality/scripts/persist-conventions-core.mjs +117 -0
  526. package/skills/engineering/test-quality/scripts/persist-conventions.mjs +17 -0
  527. package/skills/engineering/test-quality/scripts/persist-conventions.test.mjs +104 -0
  528. package/skills/risk-compliance/compliance-audit/LICENSE +3 -0
  529. package/skills/risk-compliance/compliance-audit/SKILL.md +439 -0
  530. package/skills/risk-compliance/compliance-audit/references/findings-schema.md +293 -0
  531. package/skills/risk-compliance/compliance-audit/references/normalization-rules.md +45 -0
  532. package/skills/risk-compliance/compliance-audit/references/vars-checklist.md +1068 -0
  533. package/skills/risk-compliance/compliance-audit/references/vars-findings-schema.md +398 -0
  534. package/skills/risk-compliance/compliance-audit/release-check.mjs +93 -0
  535. package/skills/risk-compliance/compliance-audit/scripts/compliance-audit.test.mjs +14 -0
  536. package/skills/risk-compliance/compliance-audit/scripts/export_tracker_xlsx.py +221 -0
  537. package/skills/risk-compliance/compliance-audit/scripts/reconcile_tracker.py +458 -0
  538. package/skills/risk-compliance/compliance-audit/scripts/test_export_tracker_xlsx.py +97 -0
  539. package/skills/risk-compliance/compliance-audit/scripts/test_validate_tracker.py +157 -0
  540. package/skills/risk-compliance/compliance-audit/scripts/validate_tracker.py +829 -0
  541. package/skills/risk-compliance/contract-compare/LICENSE +3 -0
  542. package/skills/risk-compliance/contract-compare/SKILL.md +199 -0
  543. package/skills/risk-compliance/contract-compare/references/comparison-dimensions.md +209 -0
  544. package/skills/risk-compliance/contract-compare/release-check.mjs +93 -0
  545. package/skills/risk-compliance/contract-review/LICENSE +3 -0
  546. package/skills/risk-compliance/contract-review/SKILL.md +240 -0
  547. package/skills/risk-compliance/contract-review/references/review-criteria.md +223 -0
  548. package/skills/risk-compliance/contract-review/release-check.mjs +93 -0
  549. package/skills/risk-compliance/doc-authenticity/LICENSE +3 -0
  550. package/skills/risk-compliance/doc-authenticity/SKILL.md +160 -0
  551. package/skills/risk-compliance/doc-authenticity/agents/openai.yaml +8 -0
  552. package/skills/risk-compliance/doc-authenticity/manual-invocation.test.mjs +12 -0
  553. package/skills/risk-compliance/doc-authenticity/references/agreement.md +66 -0
  554. package/skills/risk-compliance/doc-authenticity/references/bank-statement.md +150 -0
  555. package/skills/risk-compliance/doc-authenticity/references/forensic-signals.md +157 -0
  556. package/skills/risk-compliance/doc-authenticity/references/image-signals.md +114 -0
  557. package/skills/risk-compliance/doc-authenticity/references/invoice.md +66 -0
  558. package/skills/risk-compliance/doc-authenticity/references/issuer-profiles.md +86 -0
  559. package/skills/risk-compliance/doc-authenticity/references/verdict-and-report.md +95 -0
  560. package/skills/risk-compliance/doc-authenticity/references/verdict.schema.json +81 -0
  561. package/skills/risk-compliance/doc-authenticity/release-check.mjs +93 -0
  562. package/skills/risk-compliance/doc-authenticity/scripts/image_forensics.py +294 -0
  563. package/skills/risk-compliance/doc-authenticity/scripts/pdf_forensics.py +401 -0
  564. package/skills/risk-compliance/doc-authenticity/scripts/validate_codes.py +224 -0
  565. package/skills/risk-compliance/doc-authenticity/scripts/validate_verdict.py +308 -0
  566. package/skills/risk-compliance/doc-authenticity/scripts/validate_verdict.test.mjs +212 -0
  567. package/skills/risk-compliance/fraud-analysis/LICENSE +3 -0
  568. package/skills/risk-compliance/fraud-analysis/SKILL.md +114 -0
  569. package/skills/risk-compliance/fraud-analysis/references/archetypes/authorized-payment-scam.md +41 -0
  570. package/skills/risk-compliance/fraud-analysis/references/archetypes/first-party-fraud.md +44 -0
  571. package/skills/risk-compliance/fraud-analysis/references/archetypes/third-party-fraud.md +27 -0
  572. package/skills/risk-compliance/fraud-analysis/references/contexts/bank-transfer.md +24 -0
  573. package/skills/risk-compliance/fraud-analysis/references/contexts/card-payment.md +30 -0
  574. package/skills/risk-compliance/fraud-analysis/references/contexts/payment-collection.md +20 -0
  575. package/skills/risk-compliance/fraud-analysis/references/contexts/payout.md +20 -0
  576. package/skills/risk-compliance/fraud-analysis/references/feature-engineering.md +158 -0
  577. package/skills/risk-compliance/fraud-analysis/references/mechanisms/account-takeover.md +36 -0
  578. package/skills/risk-compliance/fraud-analysis/references/report-rationale.md +45 -0
  579. package/skills/risk-compliance/fraud-analysis/references/report-template.md +190 -0
  580. package/skills/risk-compliance/fraud-analysis/references/review-checklist.md +175 -0
  581. package/skills/risk-compliance/fraud-analysis/references/taxonomy.md +79 -0
  582. package/skills/risk-compliance/fraud-analysis/references/terminology.md +108 -0
  583. package/skills/risk-compliance/fraud-analysis/references/workflow.md +175 -0
  584. package/skills/risk-compliance/fraud-analysis/release-check.mjs +93 -0
  585. package/skills/risk-compliance/payment-analysis/LICENSE +3 -0
  586. package/skills/risk-compliance/payment-analysis/SKILL.md +180 -0
  587. package/skills/risk-compliance/payment-analysis/references/auth-rate-actions.md +30 -0
  588. package/skills/risk-compliance/payment-analysis/references/chargebacks.md +208 -0
  589. package/skills/risk-compliance/payment-analysis/references/chinese-polish.md +51 -0
  590. package/skills/risk-compliance/payment-analysis/references/event-layers.md +127 -0
  591. package/skills/risk-compliance/payment-analysis/references/fx.md +59 -0
  592. package/skills/risk-compliance/payment-analysis/references/journey.md +79 -0
  593. package/skills/risk-compliance/payment-analysis/references/metrics.md +67 -0
  594. package/skills/risk-compliance/payment-analysis/references/report-template.md +119 -0
  595. package/skills/risk-compliance/payment-analysis/references/terminology.md +95 -0
  596. package/skills/risk-compliance/payment-analysis/references/visualization.md +56 -0
  597. package/skills/risk-compliance/payment-analysis/release-check.mjs +93 -0
  598. package/skills/risk-compliance/report-writing/LICENSE +3 -0
  599. package/skills/risk-compliance/report-writing/SKILL.md +220 -0
  600. package/skills/risk-compliance/report-writing/references/audit-report-template.md +121 -0
  601. package/skills/risk-compliance/report-writing/references/external-assessment-template.md +167 -0
  602. package/skills/risk-compliance/report-writing/references/management-report-template.md +145 -0
  603. package/skills/risk-compliance/report-writing/references/vars-report-template.md +224 -0
  604. package/skills/risk-compliance/report-writing/release-check.mjs +93 -0
  605. package/skills/risk-compliance/similar-domain/LICENSE +3 -0
  606. package/skills/risk-compliance/similar-domain/SKILL.md +203 -0
  607. package/skills/risk-compliance/similar-domain/references/entities.md +67 -0
  608. package/skills/risk-compliance/similar-domain/references/fingerprints.md +134 -0
  609. package/skills/risk-compliance/similar-domain/references/pivots.md +82 -0
  610. package/skills/risk-compliance/similar-domain/references/report-template.md +93 -0
  611. package/skills/risk-compliance/similar-domain/references/scoring.md +130 -0
  612. package/skills/risk-compliance/similar-domain/references/terminology.md +41 -0
  613. package/skills/risk-compliance/similar-domain/references/workflow.md +85 -0
  614. package/skills/risk-compliance/similar-domain/release-check.mjs +93 -0
  615. package/skills/risk-compliance/tld-detection/LICENSE +3 -0
  616. package/skills/risk-compliance/tld-detection/SKILL.md +245 -0
  617. package/skills/risk-compliance/tld-detection/agents/openai.yaml +9 -0
  618. package/skills/risk-compliance/tld-detection/references/chinese-polish.md +55 -0
  619. package/skills/risk-compliance/tld-detection/references/clean.md +51 -0
  620. package/skills/risk-compliance/tld-detection/references/clustering.md +235 -0
  621. package/skills/risk-compliance/tld-detection/references/decision.md +189 -0
  622. package/skills/risk-compliance/tld-detection/references/fx-conversion.md +232 -0
  623. package/skills/risk-compliance/tld-detection/references/report-template.md +272 -0
  624. package/skills/risk-compliance/tld-detection/references/streams.md +141 -0
  625. package/skills/risk-compliance/tld-detection/references/terminology.md +95 -0
  626. package/skills/risk-compliance/tld-detection/references/workflow.md +95 -0
  627. package/skills/risk-compliance/tld-detection/release-check.mjs +93 -0
  628. package/skills/risk-compliance/tld-detection/scripts/detect_ladders.py +390 -0
  629. package/skills/risk-compliance/tld-detection/scripts/detect_ladders.test.mjs +14 -0
  630. package/skills/risk-compliance/tld-detection/scripts/detect_streams.py +650 -0
  631. package/skills/risk-compliance/tld-detection/scripts/detect_streams.test.mjs +14 -0
  632. package/skills/risk-compliance/tld-detection/tests/test_detect_ladders.py +134 -0
  633. package/skills/risk-compliance/tld-detection/tests/test_detect_streams.py +520 -0
@@ -0,0 +1,509 @@
1
+ #!/usr/bin/env node
2
+ // Decide what follows a resolve-issues review round, from the reviewer's result file
3
+ // alone, so a P2 can never send a PR back for fixes and a P3 is ignored: never deferred,
4
+ // never filed, never checked.
5
+ //
6
+ // review-verdict.mjs --review <run>/reviews/<unit>-r<N>.json --head <sha> [--base <ref>] [--decision <id>] [--exit-verdict]
7
+ // review-verdict.mjs --carry --review <run>/reviews/<unit>-r<N+1>.json --head <sha> --base <ref>
8
+ //
9
+ // --carry: a HEAD pushed after a passing review (a CI fix or a base update) gets no
10
+ // reviewer. Run it in the unit's review clone with --head fetched. It writes the carry
11
+ // record for --head, a skip with `carry: "after-pass"` that carries round N's approval and
12
+ // records --head's merge-base and patch identity (so a later tier can anchor on it), and
13
+ // exits 0; then run github-reviews.mjs merge and this verdict on it as on any round. Round N
14
+ // is always the file just before it, and no later round may exist. It refuses (exit 3) when
15
+ // round N did not pass: incomplete, a P0/P1 open, or a GitHub re-review awaited. Only a P0/P1
16
+ // fix is reviewed. The verdict refuses a carry whose round is not its file's number.
17
+ //
18
+ // A skip record (`tier: "skip"`, written by better-review's rereview-scope.mjs
19
+ // --write-skip) is not taken on its word: each skip back to the last real review must
20
+ // carry the record just before it (same unit, previous round, complete, no open P0/P1,
21
+ // same fixRound), walked by filename; and with --base, the scope script is run again
22
+ // against the prior round and must still pick `skip` for --head. A carry record needs no
23
+ // rerun: the chain alone shows the approval it carries.
24
+ //
25
+ // Prints a JSON verdict. The verdict is in the output (`verdict`: pass, fix, handback, wait,
26
+ // decide, or review-again), and the exit code is 0 whenever the script ran and decided; 2 when
27
+ // it could not (bad command, unreadable file). --exit-verdict restores the old verdict exit
28
+ // codes below for one release (DEPRECATED: read `verdict` instead). Old exit codes:
29
+ // 0 pass: no P0/P1 on --head (or a confirmed skip); record `reviewedHead`; ready
30
+ // once CI is green
31
+ // 1 fix: the printed `fixBrief` file holds the P0/P1 findings only; it is
32
+ // the fix worker's whole finding list. `action` says how to fix, from a
33
+ // comparison with the previous round's file (`<unit>-r<N-1>.json` beside
34
+ // it, or --prior):
35
+ // fix first blocking round: fix each finding's rule at its one
36
+ // owner and close every row in its paths
37
+ // test-first a P0/P1 came back after a fix: name the rule it breaks,
38
+ // list every path that can break it, test each path, see
39
+ // the tests fail, then fix until all pass, with the
40
+ // escalation model
41
+ // one-by-one only new P0/P1, introduced by the last fix: one finding
42
+ // per fix worker, in turn, the smallest change that closes
43
+ // every row at the rule's owner
44
+ // 5 wait: no P0/P1 is open, but a GitHub reviewer whose changes request a fix brief
45
+ // already carried has not re-reviewed (`awaiting`, from github-reviews.mjs merge);
46
+ // request their re-review and run the merge and this verdict again when it lands
47
+ // 6 decide: a recurring spec finding came back with the same trigger and the same open
48
+ // paths, so implementer and reviewer read the requirement differently
49
+ // (`reason: "spec-question"`). The printed `decide` file (`<unit>-r<N>.decide.json`)
50
+ // holds the question; answer it in the plan's `decisions` (`answers` names the file),
51
+ // then run this verdict again with --decision <that entry's id>: it writes a test-first
52
+ // fix brief that carries the decision. A changed trigger or new open paths is an
53
+ // incomplete fix, fixed test-first, never a question
54
+ // 4 hand back: stop fixing. Two fix rounds passed without a new low of open P0/P1 path
55
+ // rows (`reason: "not-converging"`, read from every `<unit>-r<K>.json` before this one);
56
+ // hand back the PR and open findings
57
+ // 2 bad command or unreadable file (still 2 without --exit-verdict)
58
+ // 3 review-again: incomplete review (unfinished passes, an unresolved execution incident,
59
+ // no checks run, a P2 with neither a follow-up URL nor a dropbox id, a bad finding (a P0/P1
60
+ // needs trigger, rule, and paths with an open row), or another
61
+ // HEAD); finish the review after resolving any execution incident
62
+ // Completion is checked first; the reviewer's verdict is ignored and only
63
+ // P0/P1 findings decide whether a completed review needs product fixes. `gh-review-<n>` and
64
+ // `gh-comment-<n>` findings come from github-reviews.mjs merge and block like the reviewer's,
65
+ // on a skip record too, which carries only the reviewer's approval.
66
+
67
+ import { existsSync, readdirSync, readFileSync, writeFileSync } from 'node:fs'
68
+ import { basename, dirname, join } from 'node:path'
69
+
70
+ import { execFileSync } from 'node:child_process'
71
+
72
+ import { prPatchFingerprint, prPatchId, rereviewScope } from '../../better-review/scripts/rereview-scope.mjs'
73
+ import { isMainModule } from '../../engineering-runtime/scripts/main-module.mjs'
74
+ import { reviewCompletionProblems, reviewTier } from '../../engineering-runtime/scripts/review-completion.mjs'
75
+
76
+ export const REVIEW_VERSION = 1
77
+ export const BLOCKING = Object.freeze(['P0', 'P1'])
78
+ export const DEFERRABLE = Object.freeze(['P2'])
79
+ // Read and ignored: no dropbox entry, no follow-up issue, never in `deferred`.
80
+ export const SKIPPED = Object.freeze(['P3'])
81
+ // Fixes converge while the open P0/P1 path rows keep reaching new lows; STALLED_ROUNDS fix
82
+ // rounds without a new low are not converging: stop and hand back. No fixed round cap.
83
+ export const STALLED_ROUNDS = 2
84
+
85
+ export class ReviewVerdictError extends Error {}
86
+
87
+ // The reviewer, not the orchestrator, fixes an incomplete review.
88
+ export class ReviewIncomplete extends ReviewVerdictError {}
89
+
90
+
91
+ const isText = (value) => typeof value === 'string' && value.trim() !== ''
92
+ const isRecord = (value) => value !== null && typeof value === 'object' && !Array.isArray(value)
93
+ const hasFixRound = (review) => Object.hasOwn(review ?? {}, 'fixRound')
94
+ const isCounter = (value) => Number.isSafeInteger(value) && value >= 1
95
+ // github-reviews.mjs merge owns these ids; only they may ride on a skip record.
96
+ const GITHUB_ID = /^gh-(?:review|comment)-\d+$/
97
+ // A skip record that carries a passing review to a HEAD pushed after it, whatever changed.
98
+ export const AFTER_PASS = 'after-pass'
99
+ const isCarry = (review) => reviewTier(review) === 'skip' && review?.carry === AFTER_PASS
100
+ // A blocking finding names its rule and every path that must hold it, at least one open; a P0/P1
101
+ // with every row closed is resolved and belongs out of the file. Checked on the current review
102
+ // only, so earlier records written without the fields stay readable as priors.
103
+ function blockingShapeProblems(f, label) {
104
+ const problems = []
105
+ if (!isText(f?.trigger)) problems.push(`${label} (P0/P1) has no trigger`)
106
+ if (!isText(f?.rule)) problems.push(`${label} (P0/P1) has no rule`)
107
+ if (!Array.isArray(f?.paths) || f.paths.length === 0) return [...problems, `${label} (P0/P1) has no paths rows`]
108
+ for (const [j, row] of f.paths.entries()) {
109
+ if (!isText(row?.path)) problems.push(`${label}.paths[${j}] has no path`)
110
+ if (!['open', 'closed'].includes(row?.status)) problems.push(`${label}.paths[${j}] status is ${JSON.stringify(row?.status)}, expected open or closed`)
111
+ else if (row.status === 'closed' && !isText(row?.evidence)) problems.push(`${label}.paths[${j}] is closed without evidence`)
112
+ }
113
+ if (!f.paths.some((row) => row?.status === 'open')) problems.push(`${label} (P0/P1) has no open paths row; a resolved finding is left out of the file`)
114
+ return problems
115
+ }
116
+
117
+ function checkReview(review, head, { requireCompletion = true, requireRulePaths = false } = {}) {
118
+ const problems = requireCompletion ? reviewCompletionProblems(review) : []
119
+ if (review?.version !== REVIEW_VERSION) problems.push(`review version is ${JSON.stringify(review?.version)}, expected ${REVIEW_VERSION}`)
120
+ if (!isText(review?.unit)) problems.push('review has no unit')
121
+ if (!isCounter(review?.round)) problems.push('review has no round (a safe integer from 1)')
122
+ if (hasFixRound(review) && (!isCounter(review.fixRound) || review.fixRound > review.round)) {
123
+ problems.push('review fixRound must be a positive safe integer no greater than round')
124
+ }
125
+ if (review?.head !== head) problems.push(`review is of HEAD ${JSON.stringify(review?.head)}, not ${head}`)
126
+
127
+ const findings = Array.isArray(review?.findings) ? review.findings : null
128
+ if (!findings) problems.push('review has no findings array (use [] for none)')
129
+ const ids = new Set()
130
+ for (const [i, f] of (findings ?? []).entries()) {
131
+ if (SKIPPED.includes(f?.severity)) continue
132
+ const label = isText(f?.id) ? f.id : `findings[${i}]`
133
+ if (!isText(f?.id)) problems.push(`${label} has no id`)
134
+ else if (ids.has(f.id)) problems.push(`duplicate finding id ${f.id}`)
135
+ else ids.add(f.id)
136
+ if (![...BLOCKING, ...DEFERRABLE].includes(f?.severity)) problems.push(`${label} has severity ${JSON.stringify(f?.severity)}, expected P0-P3`)
137
+ if (!isText(f?.summary)) problems.push(`${label} has no summary`)
138
+ if (requireRulePaths && BLOCKING.includes(f?.severity)) problems.push(...blockingShapeProblems(f, label))
139
+ }
140
+ return problems
141
+ }
142
+
143
+ // Blocking finding ids from the previous round's file, or null when there is none.
144
+ function priorBlockingIds(prior) {
145
+ if (!isRecord(prior) || !Array.isArray(prior.findings)) return null
146
+ return new Set(prior.findings.filter((f) => BLOCKING.includes(f?.severity) && isText(f?.id)).map((f) => f.id))
147
+ }
148
+
149
+ // New counters need an identified immediate predecessor, not caller-authored cap relief.
150
+ // Legacy records keep their attempt-based accounting, including when used as a prior.
151
+ function effectiveFixRound(review, prior) {
152
+ if (!isCounter(review?.round)) throw new ReviewIncomplete('review round must be a positive safe integer')
153
+ const fixRound = hasFixRound(review) ? review.fixRound : review.round
154
+ if (!isCounter(fixRound) || fixRound > review.round) {
155
+ throw new ReviewIncomplete('review fixRound must be a positive safe integer no greater than round')
156
+ }
157
+ if (!hasFixRound(review) && !hasFixRound(prior)) return fixRound
158
+ if (prior === null || prior === undefined) {
159
+ if (fixRound !== review.round) throw new ReviewIncomplete('review fixRound cannot be lower than round without a prior review')
160
+ return fixRound
161
+ }
162
+ const problems = checkReview(prior, prior?.head, { requireCompletion: reviewTier(review) !== 'full' })
163
+ if (!isText(prior?.head)) problems.push('prior review has no HEAD')
164
+ if (prior?.unit !== review.unit) problems.push('prior review unit does not match current review')
165
+ if (prior?.round !== review.round - 1) problems.push('prior review round must immediately precede current round')
166
+ if (problems.length) throw new ReviewIncomplete(`invalid prior review for fixRound:\n- ${problems.join('\n- ')}`)
167
+ if (reviewCompletionProblems(prior).length > 0) {
168
+ const currentProblems = reviewCompletionProblems(review, { requirePasses: true })
169
+ if (currentProblems.length) throw new ReviewIncomplete(`full retry must complete every pass:\n- ${currentProblems.join('\n- ')}`)
170
+ }
171
+ const priorRound = hasFixRound(prior) ? prior.fixRound : prior.round
172
+ const expected = priorRound + (reviewCompletionProblems(prior).length === 0 && priorBlockingIds(prior).size > 0 ? 1 : 0)
173
+ if (fixRound !== expected) throw new ReviewIncomplete(`review fixRound is ${fixRound}, expected ${expected} from prior review`)
174
+ return expected
175
+ }
176
+
177
+ const openPaths = (f) => (Array.isArray(f?.paths) ? f.paths : []).filter((row) => row?.status === 'open').map((row) => String(row.path)).sort().join('\n')
178
+ function sameOpenPaths(finding, prior) {
179
+ const before = prior.findings.find((f) => f?.id === finding.id)
180
+ return openPaths(before) === openPaths(finding)
181
+ }
182
+ const squash = (text) => String(text ?? '').trim().replace(/\s+/g, ' ')
183
+ function sameTrigger(finding, prior) {
184
+ const before = prior.findings.find((f) => f?.id === finding.id)
185
+ return squash(before?.trigger) === squash(finding.trigger)
186
+ }
187
+ // What the decide file asks: the finding's requirement as the reviewer reads it.
188
+ const questionOf = ({ id, summary, rule, trigger, specReference, requestedAction }) => ({ id, summary, rule, trigger, specReference, requestedAction })
189
+
190
+ // The work a fix still owes: open path rows across P0/P1 findings.
191
+ export function openBlockingRows(review) {
192
+ return (Array.isArray(review?.findings) ? review.findings : [])
193
+ .filter((f) => BLOCKING.includes(f?.severity))
194
+ .reduce((n, f) => n + (Array.isArray(f.paths) ? f.paths.filter((row) => row?.status === 'open').length : 0), 0)
195
+ }
196
+
197
+ // Rounds since the last new low of open P0/P1 path rows, over this blocking loop: the completed
198
+ // records after the last completed pass, oldest first, ending with `review`. Incomplete records
199
+ // are passed over, never counted as progress; a record with a P0/P1 that has no `paths` (legacy)
200
+ // cannot be measured and is left out. Lows only fall and never go below 0, so a loop that hands
201
+ // back at 2 rounds without a new low always ends, whatever the counts do between lows.
202
+ export function roundsWithoutNewLow(review, history = []) {
203
+ const done = [...history, review].filter((r) => isRecord(r) && Array.isArray(r.findings) && reviewCompletionProblems(r).length === 0)
204
+ const lastPass = done.findLastIndex((r) => !r.findings.some((f) => BLOCKING.includes(f?.severity)))
205
+ const loop = done.slice(lastPass + 1).filter((r) => r.findings.every((f) => !BLOCKING.includes(f?.severity) || Array.isArray(f.paths)))
206
+ let low = Infinity
207
+ let since = 0
208
+ for (const r of loop) {
209
+ const rows = openBlockingRows(r)
210
+ if (rows < low) { low = rows; since = 0 } else since++
211
+ }
212
+ return since
213
+ }
214
+
215
+ // How to act on a blocking round. better-review keeps a still-open finding's id across
216
+ // rounds, so a shared id means the last fix did not resolve it.
217
+ // `history` is every record before `prior`, oldest first, or a function that reads them; it is
218
+ // read only after the counters check out.
219
+ // `decision` is the id of the plan's `decisions` entry that answered this round's question:
220
+ // the fix it starts is new work, so this verdict skips the stall guard; later rounds count as usual.
221
+ export function fixAction(review, blocking, prior = null, history = [], { decision = null } = {}) {
222
+ effectiveFixRound(review, prior)
223
+ const earlier = typeof history === 'function' ? history() : history
224
+ if (!decision && roundsWithoutNewLow(review, [...earlier, prior]) >= STALLED_ROUNDS) return { verdict: 'handback', reason: 'not-converging' }
225
+ const before = review.round > 1 && reviewCompletionProblems(prior).length === 0 ? priorBlockingIds(prior) : null
226
+ if (!before || before.size === 0) return { verdict: 'fix', action: 'fix', recurring: [], introduced: [] }
227
+ const recurring = blocking.filter((f) => before.has(f.id)).map((f) => f.id)
228
+ const introduced = blocking.filter((f) => !before.has(f.id)).map((f) => f.id)
229
+ // A recurring spec finding is a question only when nothing about it moved: the same trigger
230
+ // fails on the same open paths, so the fix and the review read the requirement differently.
231
+ // A new trigger on the same line, or new open paths, is an incomplete fix.
232
+ const questions = blocking.filter((f) => before.has(f.id) && f.pass === 'spec' && sameOpenPaths(f, prior) && sameTrigger(f, prior))
233
+ if (questions.length && !decision) return { verdict: 'decide', reason: 'spec-question', question: questions.map(questionOf), recurring, introduced }
234
+ if (questions.length) return { verdict: 'fix', action: 'test-first', decision, recurring, introduced }
235
+ if (recurring.length > 0) return { verdict: 'fix', action: 'test-first', recurring, introduced }
236
+ return { verdict: 'fix', action: 'one-by-one', recurring, introduced }
237
+ }
238
+
239
+ // One link of a skip chain: `link` must carry the record just before it, which is
240
+ // complete, of the same unit and the previous round, and left no P0/P1 open.
241
+ function skipLinkProblems(link, before) {
242
+ if (!isRecord(before)) return ['the review it carries is missing']
243
+ const problems = reviewCompletionProblems(before, { requirePasses: true }).map((p) => `the review it carries: ${p}`)
244
+ if (link.carriedFrom !== before.head) problems.push(`it carries ${JSON.stringify(link.carriedFrom)}, but the review before it is of ${JSON.stringify(before.head)}`)
245
+ if (before.unit !== link.unit) problems.push('its unit differs from the review it carries')
246
+ if (before.round !== link.round - 1) problems.push('its round does not follow the review it carries')
247
+ if (!Array.isArray(before.findings)) problems.push('the review it carries has no findings array')
248
+ else if (before.findings.some((f) => BLOCKING.includes(f?.severity))) problems.push('the review it carries has an open P0/P1')
249
+ const beforeFixRound = hasFixRound(before) ? before.fixRound : before.round
250
+ if (link.fixRound !== beforeFixRound) problems.push(`its fixRound is ${JSON.stringify(link.fixRound)}, expected ${beforeFixRound}`)
251
+ return problems
252
+ }
253
+
254
+ // A skip carries an approval only when every link back to a real review holds, and the
255
+ // scope script, rerun now, still picks skip. `chain` is the previous record, then the
256
+ // ones before it, newest first; `confirmSkip()` returns the rerun's { tier, reasons }.
257
+ function checkSkip(review, chain, confirmSkip) {
258
+ let link = review
259
+ for (const [i, before] of [...chain, undefined].entries()) {
260
+ if (i > 0) {
261
+ const own = checkReview(link, link.head)
262
+ if (own.length) throw new ReviewIncomplete(`skip chain: round ${link.round} is not a valid record; spawn the reviewer:\n- ${own.join('\n- ')}`)
263
+ }
264
+ const problems = skipLinkProblems(link, before)
265
+ if (problems.length) throw new ReviewIncomplete(`skip record does not hold: round ${link.round}: ${problems.join('; ')}; spawn the reviewer`)
266
+ if (reviewTier(before) !== 'skip') break
267
+ link = before
268
+ }
269
+ if (isCarry(review)) return
270
+ if (typeof confirmSkip !== 'function') throw new ReviewVerdictError('--base is required to confirm a skip record')
271
+ const rerun = confirmSkip()
272
+ if (rerun?.tier !== 'skip') {
273
+ throw new ReviewIncomplete(`skip record does not hold: the scope script picks ${JSON.stringify(rerun?.tier)} for this HEAD; spawn the reviewer${rerun?.reasons?.length ? `:\n- ${rerun.reasons.join('\n- ')}` : ''}`)
274
+ }
275
+ }
276
+
277
+ export function reviewVerdict(review, head, prior = null, { confirmSkip, earlier = [], history = [], decision = null } = {}) {
278
+ if (!isText(head)) throw new ReviewVerdictError('--head is required')
279
+ const problems = checkReview(review, head, { requireRulePaths: true })
280
+ if (problems.length) throw new ReviewIncomplete(`incomplete review; spawn the reviewer again only after resolving any execution incident:\n- ${problems.join('\n- ')}`)
281
+ const skip = reviewTier(review) === 'skip'
282
+ if (skip) checkSkip(review, [prior, ...earlier], confirmSkip)
283
+
284
+ const fixRound = effectiveFixRound(review, prior)
285
+ const blocking = review.findings.filter((f) => BLOCKING.includes(f.severity))
286
+ const deferred = review.findings
287
+ .filter((f) => DEFERRABLE.includes(f.severity))
288
+ .map(({ id, severity, summary, followUpUrl, dropboxId }) => ({ id, severity, summary, followUpUrl, dropboxId }))
289
+ const awaiting = Array.isArray(review.external?.awaiting) ? review.external.awaiting : []
290
+ const base = { unit: review.unit, round: review.round, fixRound, head, commands: review.commands, deferred, ...(awaiting.length ? { awaiting } : {}) }
291
+ const skipped = skip ? { tier: 'skip', carriedFrom: review.carriedFrom } : {}
292
+ if (blocking.length === 0) {
293
+ return awaiting.length ? { verdict: 'wait', ...base, ...skipped } : { verdict: 'pass', reviewedHead: head, ...base, ...skipped }
294
+ }
295
+ if (skip && blocking.some((f) => !GITHUB_ID.test(String(f.id)))) throw new ReviewIncomplete('a skip record cannot hold findings; spawn the reviewer')
296
+ return { ...fixAction(review, blocking, prior, history, { decision }), ...base, fix: blocking }
297
+ }
298
+
299
+ // The record --carry writes for `head`: the previous round's approval, carried with no
300
+ // reviewer. The previous round must have passed: complete, every pass done, no P0/P1, and no
301
+ // GitHub re-review awaited.
302
+ // `identity` is --head's { mergeBase, patchId, patchFingerprint }.
303
+ export function carryRecord(prior, head, identity = {}) {
304
+ if (!isText(head)) throw new ReviewVerdictError('--head is required')
305
+ if (!isRecord(prior)) throw new ReviewIncomplete('no previous round to carry; spawn the reviewer')
306
+ const problems = [...new Set([...checkReview(prior, prior.head), ...reviewCompletionProblems(prior, { requirePasses: true })])]
307
+ if (!isText(prior.head)) problems.push('it has no head')
308
+ if (prior.complete !== true) problems.push('it is not marked complete')
309
+ if (Array.isArray(prior.findings) && prior.findings.some((f) => BLOCKING.includes(f?.severity))) problems.push('it has an open P0/P1')
310
+ if (Array.isArray(prior.external?.awaiting) && prior.external.awaiting.length > 0) problems.push('it awaits a GitHub re-review')
311
+ if (prior.head === head) problems.push(`it is already of ${head}`)
312
+ if (problems.length) throw new ReviewIncomplete(`round ${prior.round} did not pass, so ${head} cannot carry it; review it:\n- ${problems.join('\n- ')}`)
313
+ return {
314
+ version: prior.version,
315
+ unit: prior.unit,
316
+ round: prior.round + 1,
317
+ fixRound: hasFixRound(prior) ? prior.fixRound : prior.round,
318
+ head,
319
+ ...identity,
320
+ tier: 'skip',
321
+ carry: AFTER_PASS,
322
+ carriedFrom: prior.head,
323
+ ...(Number.isInteger(prior.fixLinesSinceFull) ? { fixLinesSinceFull: prior.fixLinesSinceFull } : {}),
324
+ oversize: false,
325
+ complete: true,
326
+ passes: prior.passes,
327
+ commands: [],
328
+ sweeps: prior.sweeps ?? [],
329
+ boundaries: prior.boundaries ?? [],
330
+ findings: [],
331
+ }
332
+ }
333
+
334
+ const INSTRUCTIONS = {
335
+ 'fix': 'Fix only these findings. For each, fix its `rule` at the one place every path passes through, never by copying a guard to each path, and close every row in its `paths`.',
336
+ 'test-first': 'The findings listed in `recurring` survived a fix: the last fix closed one path and missed others. For each, before changing code: name the rule the bug breaks; list every code path that can break it, including the trigger of this finding id in each earlier round\'s review file beside this one; write a test per path from its trigger and run them: see it fail on each open path. Then fix the rule at its one owner, the place every path passes through, not path by path, until every test passes. "Fixed" is every path\'s test passing. Fix the rest as usual.',
337
+ 'one-by-one': 'The last fix introduced these findings. Fix them one at a time, one fix worker each, with the smallest change that closes every row of its `paths` at the rule\'s owner; touch nothing else.',
338
+ }
339
+
340
+ // The fix worker's brief carries only P0/P1 findings; P2/P3 never reach it.
341
+ export function fixBriefOf(result) {
342
+ const fixRound = hasFixRound(result) ? result.fixRound : result.round
343
+ if (!isCounter(result.round) || !isCounter(fixRound) || fixRound > result.round) {
344
+ throw new ReviewIncomplete('fix brief round and fixRound must be positive safe integers with fixRound no greater than round')
345
+ }
346
+ return {
347
+ unit: result.unit,
348
+ round: result.round,
349
+ fixRound,
350
+ head: result.head,
351
+ action: result.action,
352
+ instruction: `${INSTRUCTIONS[result.action]}${result.decision ? ` Decision ${result.decision} in the plan's \`decisions\` settles what the recurring spec finding requires: fix it as that decision reads.` : ''} Every other finding is out of scope: a P2 is deferred to the dropbox or a follow-up issue, and a P3 is skipped.`,
353
+ ...(result.decision ? { decision: result.decision } : {}),
354
+ recurring: result.recurring,
355
+ fix: result.fix,
356
+ }
357
+ }
358
+
359
+ const USAGE = 'usage: review-verdict.mjs --review <reviews/<unit>-r<N>.json> --head <sha> [--prior <reviews/<unit>-r<N-1>.json>] [--base <ref> (required for a scope-script skip record)] [--decision <decisions id>]\n review-verdict.mjs --carry --review <reviews/<unit>-r<N+1>.json> --head <sha> --base <ref>'
360
+
361
+ const ROUND_FILE = /^(.*-r)(\d+)\.json$/
362
+ // The round a review file's name gives it, or null when the name has none.
363
+ const roundOfFile = (path) => { const m = basename(path).match(ROUND_FILE); return m ? Number(m[2]) : null }
364
+
365
+ function parseArgs(argv) {
366
+ const opts = {}
367
+ for (let i = 0; i < argv.length; i += 2) {
368
+ if (argv[i] === '--carry') { opts.carry = true; i--; continue }
369
+ if (argv[i] === '--exit-verdict') { opts.exitVerdict = true; i--; continue }
370
+ if (argv[i] === '--json') { i--; continue } // the output is always JSON
371
+ if (!argv[i]?.startsWith('--') || argv[i + 1] === undefined) throw new ReviewVerdictError(USAGE)
372
+ opts[argv[i].slice(2)] = argv[i + 1]
373
+ }
374
+ if (!opts.review || !opts.head) throw new ReviewVerdictError(USAGE)
375
+ return opts
376
+ }
377
+
378
+ function readJson(path) {
379
+ let text
380
+ try {
381
+ text = readFileSync(path, 'utf8')
382
+ } catch (error) {
383
+ throw new ReviewVerdictError(`cannot read ${path}: ${error.message}`)
384
+ }
385
+ try {
386
+ return JSON.parse(text)
387
+ } catch (error) {
388
+ throw new ReviewIncomplete(`incomplete review; spawn the reviewer again:\n- ${path} is not JSON: ${error.message}`)
389
+ }
390
+ }
391
+
392
+ // The records before a skip prior, newest first, by filename, back to the first non-skip.
393
+ // A chain that cannot be walked stays short, and the skip check then fails closed.
394
+ function readEarlier(opts, prior) {
395
+ const path = opts.prior ?? opts.review
396
+ const m = basename(path).match(/^(.*-r)(\d+)\.json$/)
397
+ if (!m) return []
398
+ const out = []
399
+ let current = prior
400
+ let n = Number(m[2]) - (opts.prior ? 1 : 2)
401
+ while (reviewTier(current) === 'skip' && n >= 1) {
402
+ try { current = JSON.parse(readFileSync(join(dirname(path), `${m[1]}${n}.json`), 'utf8')) } catch { break }
403
+ out.push(current)
404
+ n--
405
+ }
406
+ return out
407
+ }
408
+
409
+ // Legacy unreadable priors remain optional. New counters must not silently discard
410
+ // a supplied or malformed prior; a missing inferred file still means no evidence.
411
+ function readPrior(opts, review) {
412
+ let path = opts.prior
413
+ if (!path) {
414
+ const m = basename(opts.review).match(/^(.*-r)(\d+)\.json$/)
415
+ if (!m || Number(m[2]) < 2) return null
416
+ path = join(dirname(opts.review), `${m[1]}${Number(m[2]) - 1}.json`)
417
+ }
418
+ try {
419
+ const prior = JSON.parse(readFileSync(path, 'utf8'))
420
+ if (hasFixRound(review) && !isRecord(prior)) throw new ReviewIncomplete('prior review must be an object')
421
+ return prior
422
+ } catch (error) {
423
+ if (hasFixRound(review) && (opts.prior || error.code !== 'ENOENT')) {
424
+ throw new ReviewIncomplete(`cannot use prior review for fixRound at ${path}: ${error.message}`)
425
+ }
426
+ return null
427
+ }
428
+ }
429
+
430
+ // Every record before the prior, oldest first, for the stall guard: `<unit>-r1.json` up to the
431
+ // one before the prior, beside the prior (or the review). Fails closed: the guard cannot be
432
+ // skipped by a missing file or a name it cannot number.
433
+ function readHistory(opts, review) {
434
+ const from = opts.prior ?? opts.review
435
+ const m = basename(from).match(/^(.*-r)(\d+)\.json$/)
436
+ const last = m && Number(m[2]) - (opts.prior ? 1 : 2)
437
+ if (!m) {
438
+ if (isCounter(review?.round) && review.round >= 3) {
439
+ throw new ReviewIncomplete(`cannot number earlier reviews from ${from}; name review files <unit>-r<N>.json so the stall guard can read every round`)
440
+ }
441
+ return []
442
+ }
443
+ const out = []
444
+ for (let n = 1; n <= last; n++) {
445
+ const path = join(dirname(from), `${m[1]}${m[2].startsWith('0') ? String(n).padStart(m[2].length, '0') : n}.json`)
446
+ try { out.push(JSON.parse(readFileSync(path, 'utf8'))) } catch (error) {
447
+ throw new ReviewIncomplete(`cannot read earlier review ${path} for the stall guard: ${error.message}`)
448
+ }
449
+ }
450
+ return out
451
+ }
452
+
453
+ if (isMainModule(import.meta.url)) {
454
+ try {
455
+ const opts = parseArgs(process.argv.slice(2))
456
+ if (opts.carry) {
457
+ const n = roundOfFile(opts.review)
458
+ if (n === null || n < 2) throw new ReviewVerdictError(`--carry needs --review named <unit>-r<N>.json with N from 2: ${opts.review}`)
459
+ if (opts.prior) throw new ReviewVerdictError('--carry always carries the round just before --review; drop --prior')
460
+ if (!opts.base) throw new ReviewVerdictError('--carry needs --base <review base> to record the merge-base')
461
+ if (existsSync(opts.review)) throw new ReviewVerdictError(`${opts.review} exists; carry writes a new round`)
462
+ const stem = basename(opts.review).match(ROUND_FILE)[1]
463
+ const later = readdirSync(dirname(opts.review)).find((name) => name.startsWith(stem) && roundOfFile(name) > n)
464
+ if (later) throw new ReviewVerdictError(`${later} exists; carry only the newest round`)
465
+ const prior = readPrior(opts, { fixRound: 1 })
466
+ if (isRecord(prior) && prior.round !== n - 1) throw new ReviewIncomplete(`the round before ${basename(opts.review)} records round ${prior.round}, not ${n - 1}; review it`)
467
+ carryRecord(prior, opts.head) // refuse a round that did not pass before touching git
468
+ const git = (args) => execFileSync('git', args, { encoding: 'utf8' }).trim()
469
+ let identity
470
+ try {
471
+ const mergeBase = git(['merge-base', opts.base, opts.head])
472
+ identity = { mergeBase, patchId: prPatchId(mergeBase, opts.head), patchFingerprint: prPatchFingerprint(mergeBase, opts.head) }
473
+ } catch (error) {
474
+ throw new ReviewVerdictError(`cannot read ${opts.head} against ${opts.base} here; run --carry in the unit's review clone with both fetched: ${String(error.stderr || error.message).trim()}`)
475
+ }
476
+ const record = carryRecord(prior, opts.head, identity)
477
+ writeFileSync(opts.review, `${JSON.stringify(record, null, 2)}\n`)
478
+ process.stdout.write(`${JSON.stringify({ carried: opts.review, round: record.round, carriedFrom: record.carriedFrom, head: record.head }, null, 2)}\n`)
479
+ } else {
480
+ const review = readJson(opts.review)
481
+ const n = roundOfFile(opts.review)
482
+ if (isCarry(review) && n !== review.round) throw new ReviewIncomplete(`carry record ${opts.review} records round ${JSON.stringify(review.round)}, not its file's ${n}; review it`)
483
+ const prior = readPrior(opts, review)
484
+ const confirmSkip = opts.base ? () => rereviewScope({ prior, base: opts.base, head: opts.head }) : undefined
485
+ const earlier = reviewTier(review) === 'skip' ? readEarlier(opts, prior) : []
486
+ const history = () => readHistory(opts, review)
487
+ const result = reviewVerdict(review, opts.head, prior, { confirmSkip, earlier, history, decision: opts.decision ?? null })
488
+ if (result.verdict === 'fix') {
489
+ result.fixBrief = join(dirname(opts.review), `${basename(opts.review, '.json')}.fix.json`)
490
+ writeFileSync(result.fixBrief, `${JSON.stringify(fixBriefOf(result), null, 2)}\n`)
491
+ }
492
+ if (result.verdict === 'decide') {
493
+ result.decide = join(dirname(opts.review), `${basename(opts.review, '.json')}.decide.json`)
494
+ writeFileSync(result.decide, `${JSON.stringify({ unit: result.unit, round: result.round, head: result.head, reason: result.reason, question: result.question }, null, 2)}\n`)
495
+ }
496
+ process.stdout.write(`${JSON.stringify(result, null, 2)}\n`)
497
+ process.exitCode = opts.exitVerdict ? { pass: 0, fix: 1, handback: 4, wait: 5, decide: 6 }[result.verdict] : 0
498
+ }
499
+ } catch (error) {
500
+ if (error instanceof ReviewIncomplete) {
501
+ // An incomplete review is an answer (review again), not a failure of the script.
502
+ process.stdout.write(`${JSON.stringify({ verdict: 'review-again', reason: error.message }, null, 2)}\n`)
503
+ process.exitCode = process.argv.includes('--exit-verdict') ? 3 : 0
504
+ } else {
505
+ process.stderr.write(`${error instanceof ReviewVerdictError ? error.message : error.stack}\n`)
506
+ process.exitCode = 2
507
+ }
508
+ }
509
+ }