@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,83 @@
1
+ # Surface Inventory Contract
2
+
3
+ Surface **discovery** is the one repo-specific part of the Coverage Ledger: enumerating routes/APIs/tables/events depends entirely on the stack. The reference tool (`scripts/coverage-ledger.mjs`) does **not** discover surfaces — your repo supplies them by emitting an inventory file that satisfies this contract. Everything downstream (aggregation, orphan detection, status) is generic and handled by the tool.
4
+
5
+ ## Output
6
+
7
+ Write JSON to `docs/tests/_generated/surface-inventory.json` (or wherever `--inventory` points). This file is **generated, never hand-edited**, and regenerated on every change so staleness is detectable.
8
+
9
+ ### Canonical form
10
+
11
+ ```json
12
+ {
13
+ "surfaces": [
14
+ { "id": "/settings/models", "kind": "route", "class": "mutation", "reachability": "reachable" },
15
+ { "id": "/about", "kind": "route", "class": "read", "reachability": "reachable" },
16
+ { "id": "/api/settings/model-allowlist", "kind": "api", "class": "mutation" },
17
+ { "id": "model_allowlist", "kind": "table" },
18
+ { "id": "model.allowlist.updated", "kind": "event" }
19
+ ]
20
+ }
21
+ ```
22
+
23
+ - `id` — the surface identifier. It must match exactly how the curated `*.coverage.yml` files and the test `@covers` annotations name the surface.
24
+ - `kind` — one of `route`, `api`, `table`, `event`, `job`, `permission`, `integration` (extend as needed; used only for reporting).
25
+ - `class` — the **mechanical taxonomy** that drives the Surface Baseline Contract floor. The adapter derives it deterministically from code, never from a session judgment:
26
+ - `route`: `read` (no write form) · `detail` (dynamic segment, renders one entity) · `mutation` (contains a write form / submit action).
27
+ - `api`: `read` (GET only) · `mutation` (exports POST/PUT/PATCH/DELETE).
28
+ - Omit for internal kinds (`table`/`event`/`job`) — they carry no baseline.
29
+ - The adapter emits **only** the mechanical class. `sensitive` (credential/admin escalation) and exclusion are human-declared in the curated `*.coverage.yml`, never guessed here — a path heuristic that under-classifies an admin route would silently hand it the weak floor.
30
+ - `reachability` — `reachable | guarded | blocked | unreachable | unknown`, from walking the guard/layout/middleware chain (see the Route Reachability Protocol). Drives the **exclusion gate**: a `reachable` `mutation` route can never be excluded below its journey floor. Omit for non-route kinds.
31
+
32
+ The baseline floor is computed from `(kind, class)`; the grouped lenient form below omits `class`/`reachability`, so entry surfaces fall back to the kind's `_default` floor (still enforced, just not class-refined). Prefer the canonical form so the floor is precise.
33
+
34
+ ### Smoke candidate discovery
35
+
36
+ The same generated inventory can seed the curated smoke manifest: `smoke/scripts/smoke.mjs suggest --inventory docs/tests/_generated/surface-inventory.json` ranks likely golden-path candidates from deterministic signals (route/API kind, `class: mutation`, reachability, auth/payment/liveness-looking names). The output is a `candidates` list, **not** a runnable smoke `paths` manifest — product/release judgment decides which candidates are truly do-not-ship flows and writes the concrete observables.
37
+
38
+ ### Presentation axis (browser routes)
39
+
40
+ Every surface with `kind: "route"` auto-carries the **Presentation** floor on top of its functional floor (the five `presentation:*` levels — [../presentation/axis.md](../presentation/axis.md)). The adapter emits **no extra field**: `kind: "route"` *is* the browser-route fact the floor keys on. These floors are *graded* by the ledger and *run* by the `e2e-test` presentation sweep ([../presentation/runner-contract.md](../presentation/runner-contract.md)). The condition-matrix floor — viewports `[375, 1280]`, default theme, seeded data — is a ledger constant (`PRESENTATION_VIEWPORT_FLOOR` in `coverage-ledger.mjs`), not per-surface data.
41
+
42
+ ### Feature-derived escalation signals (optional)
43
+
44
+ A route surface may carry an optional `signals` object that the adapter derives **deterministically** from code. Each signal *raises* the presentation floor by adding a cell-qualified obligation (Dimension B of the condition matrix). Optional and additive — absent signals just leave the surface at the fixed floor.
45
+
46
+ ```json
47
+ { "id": "/app", "kind": "route", "class": "read", "reachability": "reachable",
48
+ "signals": { "themeToggle": true, "i18n": true } }
49
+ ```
50
+
51
+ | signal | derived from | adds required level(s) |
52
+ |---|---|---|
53
+ | `themeToggle` | a `next-themes` dep, or `useTheme`/`<ThemeProvider>`/`data-theme` in source | `presentation:perceivability@dark` |
54
+ | `i18n` | a known i18n dependency (next-intl, react-i18next, i18next, …) | `presentation:spatial@long-locale`, `presentation:spatial@rtl` |
55
+
56
+ Signals must be **deterministic** (same code → same signals) so two agents compute identical obligations. The reference Next.js adapter detects them at the app level and attaches to every route; a stack may refine to per-route detection. An escalated (`@`-qualified) cell can be dropped only via a gated `excludeCells` entry (category + reason, surfaced in the census); the base mechanical floor can never be removed.
57
+
58
+ ### Lenient grouped form (also accepted)
59
+
60
+ ```json
61
+ {
62
+ "routes": ["/settings/models"],
63
+ "apis": ["/api/settings/model-allowlist"],
64
+ "tables": ["model_allowlist"],
65
+ "events": ["model.allowlist.updated"]
66
+ }
67
+ ```
68
+
69
+ The tool flattens this, deriving `kind` from the group name (`routes` → `route`).
70
+
71
+ ## Adapter expectations
72
+
73
+ - **Deterministic**: same code → same inventory. No timestamps or ordering noise (the tool sorts).
74
+ - **Complete for the kinds it claims**: if it emits `route`s, it must emit *all* reachable routes, or orphan detection becomes unsound.
75
+ - **CI staleness check**: run the adapter with a `--check` mode (or `git diff --exit-code` on the output) so a PR that changes surfaces but not the inventory fails.
76
+
77
+ A reference Next.js App Router adapter ships at `scripts/adapters/nextjs-inventory.mjs` — copy and adapt it, or write your own per framework.
78
+
79
+ ## How the tool consumes it
80
+
81
+ `coverage-ledger.mjs aggregate` reads this inventory, the curated files, and `@covers` tests to build the index; `validate` runs the reconciliation checks. Commands and checks are documented in `coverage-ledger.md`.
82
+
83
+ `Orphan surface` = a surface in this inventory owned by no curated file. It is a `warn` (a traceability gap), but the surface still carries — and is graded against — its Surface Baseline Contract floor, so an unowned route is not silently uncovered. The inventory's completeness is therefore what makes all three axes sound: an adapter that under-reports surfaces, or under-classifies an entry surface's `class`/`reachability`, hides exactly the gaps the ledger exists to catch — including the per-route presentation floor, which keys off `kind: route`.
@@ -0,0 +1,44 @@
1
+ # Surface Baseline Contract (breadth)
2
+
3
+ > Read when: computing the minimum required-level floor a surface owes. The breadth axis enumerates surfaces; this is the floor each one carries the instant it's discovered. Sibling refs: [coverage-ledger.md](coverage-ledger.md) (the ledger that holds these obligations), [surface-discovery.md](surface-discovery.md) (how surfaces and their `reachability` are found), [inventory-contract.md](inventory-contract.md) (the adapter that emits the taxonomy).
4
+
5
+ A requirement source (ADR/PRD/spec) is **not** a precondition for a test obligation. Most production gaps are organically-added routes nobody wrote an ADR for; if coverage waited on someone authoring a requirement, the surface would sit silently uncovered. So **every surface in the inventory carries a minimum required-level floor the instant it is discovered**, graded at depth automatically — safe by default. Orphan detection alone is worthless without a *default obligation* attached; it just relocates the judgment call to whoever notices — the session-variance that produced the gaps.
6
+
7
+ **The baseline keys off an adapter-emitted taxonomy, never inference at grading time** — inference-per-session is how "covered" came to mean different things. The adapter tags each surface deterministically so two agents on the same code compute the same floor.
8
+
9
+ - **`class` (mechanical, adapter-owned)**: `read | detail | mutation` for routes (does the page contain a write form / does `route.*` export a write method); derived from code with no human input.
10
+ - **`reachability` (adapter-owned)**: `reachable | guarded | blocked | unreachable | unknown` from the guard/layout/middleware chain (see [surface-discovery.md](surface-discovery.md)).
11
+ - **`sensitive` / exclusion (human-declared)**: credential/admin judgment and out-of-scope intent are *not* reliably derivable from syntax. Humans may only **raise** the floor (`sensitive`) or **exclude** (gated below) — never weaken the mechanical floor. `effectiveLevels = strictest(baseline, curated requiredLevels, sensitive escalation)`.
12
+
13
+ ## Baseline table
14
+
15
+ Baseline only **entry surfaces** (`route`, `api`). **Internal surfaces** (`table`, `event`, `job`) carry no independent obligation — they are proven transitively by the entry surface that writes/emits them, and only **dead-surface-warned** when no evidence reaches them (a table nothing writes is likely dead code, not a coverage gap).
16
+
17
+ | kind | class | baseline `requiredLevels` | the journey must additionally assert |
18
+ |---|---|---|---|
19
+ | route | read | `browser-journey` | page renders real data (drive the rendered page, no first-party mock) |
20
+ | route | detail | `browser-journey` | seeded real entity renders |
21
+ | route | mutation | `browser-journey` | fill real form → backend accepts → **durable state changes** |
22
+ | route | +sensitive | `browser-journey` + `api` | + auth / tenant-isolation assertion |
23
+ | api | read (GET) | `api` | status, shape, auth |
24
+ | api | mutation (write) | `api` + `integration` | durable state changed |
25
+ | api | +sensitive | + auth | mandatory auth / tenant isolation |
26
+ | table / event / job | — | none (transitive) | dead-surface-warned if unreached |
27
+ | permission | — | `integration` | resolves an auth test |
28
+ | integration (external) | — | fake adapter + contract | — |
29
+
30
+ Every **live browser route is `browser-journey` at minimum** — `class` changes only *what the journey additionally proves*, not *whether* you drive the page. A genuinely static/content page (marketing, docs) is downgraded via the **`static` exclusion category** to a `render-health` floor — a cheap reachability guarantee, never weakening the floor for real app pages. (`render-health` was formerly named `smoke` as a per-route *level*, still accepted as an alias — **not** the curated `smoke` *gate* #8, which is a separate cross-flow liveness check, not a per-route level.) **`render-health` is a browser-level check, not an API ping**: a real browser must load the rendered page and confirm it renders without error (externals may be faked). An HTTP-200 / API-level test does **not** satisfy it. The other exclusion categories (`seed`/`deprecated`/`internal`) drop to manifest-only. `render-health` is the one level a present-but-shallow test can satisfy, precisely because it is definitionally shallow. (Same "page loads/renders" concept as e2e-test's Tier-1 and the `presentation:render-health` spine.)
31
+
32
+ Every live browser route *also* auto-carries the **Presentation floor** on top of the functional floor above — see [../presentation/axis.md](../presentation/axis.md).
33
+
34
+ ## Exclusion is gated, not honored on a reason
35
+
36
+ An exclusion downgrades a surface to manifest-only — the exact move that re-opens the gap if trusted on a prose reason. So exclusion is **permitted only when the adapter's deterministic signals agree the surface cannot hurt a user**:
37
+
38
+ - A `Reachable` `mutation` route can **never** be excluded below its journey floor, regardless of any human "internal" claim — a reachable write form is a first-week bug surface.
39
+ - Manifest-only is permitted only when reachability is `blocked`/`unreachable`, or the surface is a read-only page (static/content), or a non-mutation API. The `static` category is the exception that downgrades to a `render-health` floor rather than manifest-only, so a content page still proves it loads.
40
+ - Every exclusion requires `category` (seed/static/deprecated/internal) + `reason` + optional `gapIssue`, and the validator prints a **visible exclusion census** every run. No silent caps.
41
+
42
+ ## The feature card is a deviation record, not a precondition
43
+
44
+ Because the baseline auto-applies, a surface with no requirement is **not blocked on authoring a file** — it is already graded at its floor. A curated `…coverage.yml` (the "feature card") is required only to **deviate**: raise above baseline, mark `sensitive`, exclude, attest (`verified`), or attach `owner`/`purpose`/`userVisibleContract` ownership. Pure happy-path baseline surfaces need no card. Requirement *ownership* (traceability) is a `warn`; the baseline *test obligation* is the hard gate.
@@ -0,0 +1,16 @@
1
+ # Route Discovery & Reachability Protocol (breadth)
2
+
3
+ > Read when: enumerating the surfaces that must be proven, and classifying whether each route is actually reachable. This is the *requirement-inward enumeration* that builds the surface inventory — a breadth activity. Its `reachability` output feeds the baseline floor and the exclusion gate ([surface-baseline.md](surface-baseline.md)).
4
+ >
5
+ > **Guard-chain vs navigational reachability.** This protocol determines **guard-chain** reachability — "can the URL load past middleware/auth." That is *different* from `presentation:reachability` ([../presentation/axis.md](../presentation/axis.md)), which is **navigational** — "can a user *click* their way here from an entry point." A route can be guard-reachable yet navigation-orphaned. Both matter; they are different checks.
6
+
7
+ Use this inline protocol for E2E audits even if `e2e-test` is unavailable. Route discovery is not complete after listing route files; verify whether each route can actually be reached through layouts, middleware, redirects, guards, rewrites, and route groups. For Next.js App Router and similar file-based routers:
8
+
9
+ 1. Enumerate all `page.*` and `route.*` files, including route groups, dynamic segments, parallel/intercepting routes, and exported HTTP methods for `route.*`. Tag each by kind — **browser route** (`page.*`) or **API route** (`route.*`) — because they carry different depth obligations and proof types ([../depth/grading.md](../depth/grading.md)). Never let one stand in for the other.
10
+ 2. For each page route, walk the layout chain root → route group → segment; inspect `layout.*`, `middleware.*`, redirects, `notFound`, auth/session checks, role/tenant guards, feature flags, rewrites.
11
+ 3. Classify reachability as `Reachable`, `Redirected`, `Guarded`, `Blocked`, or `Unknown`, with the guard/layout/middleware evidence.
12
+ 4. For each `Reachable` page, inventory its user-actionable mutations (forms, submit buttons, write actions) and the backend endpoint each targets. Record one **journey obligation** per mutation (operator completes form → backend accepts → state changes), separate from the page merely rendering. A write form with no journey test is uncovered, even when the route renders.
13
+ 5. Cross-reference discovered routes against PRD/spec claims, route manifests, navigation links, product journeys, and the smoke candidate list. Discovery may suggest golden-path candidates, but the smoke manifest is curated: a route is not release-blocking merely for being a mutation route or containing an auth/payment-looking word.
14
+ 6. Flag routes that are unreachable, misplaced, stale, missing from the manifest, absent from code, or contradicting design docs — and reachable pages whose mutation forms have no journey coverage.
15
+
16
+ Do not classify a route as covered, missing, or part of a valid journey solely because a `page.*`/`route.*` file exists — a route file is only a declared route until its guard chain and journey validity are checked.
@@ -0,0 +1,68 @@
1
+ # Depth: Characterization — pin existing behavior before you change it
2
+
3
+ > Read when: a change **modifies existing behavior** (edits/deletes lines in a non-test source file) rather than adding a brand-new surface. Sibling: [grading.md](grading.md) (how each obligation is graded), [mock-policy.md](mock-policy.md) (the boundary). New-surface work is TDD red→green; *this* is the obligation for touching code that already runs in production.
4
+
5
+ Michael Feathers' rule: *"Characterization tests document the actual behavior of the code, not the intended behavior."* The common agent failure mode: it refactors or "fixes" a function, the existing tests stay green (they never covered the changed path), and an **observable behavior silently shifts**. A green suite after the change proves nothing if no test pinned the behavior *before* it.
6
+
7
+ So a modification carries a depth obligation a fresh feature does not: **before you change existing behavior, write a test that captures what the code does today, and make it pass against the unchanged tree.** That test becomes a boundary the change cannot silently cross — the seam ([below](#seams-where-to-pin)) at which you alter behavior deliberately.
8
+
9
+ ## The obligation: when it is owed
10
+
11
+ A change owes a characterization test when **all** hold:
12
+
13
+ - It **edits or removes** existing lines of a non-test **source** file (a pure addition into a new file, or appended-only code, is new behavior → TDD path).
14
+ - The touched code has **observable behavior** — return value, durable-state effect, emitted event, HTTP contract, rendered output. (Internal-only renames with no behavioral surface don't.)
15
+ - The surface is **non-trivial** — anything carrying a Surface Baseline floor, or logic a user/caller depends on.
16
+
17
+ When owed, the test must: **(1) capture actual, not intended, behavior** including quirks/bugs (if current behavior is wrong, characterize it *then* fix it in a separate declared step); **(2) pass on the pre-change tree** (GREEN on `HEAD~`/base before your edit — capture as evidence); **(3) still pass after the change**, unless the change is a declared intended behavior change.
18
+
19
+ ## When it is waived
20
+
21
+ Mark the waiver explicitly (Review Contract / Coverage Checklist evidence), never silently:
22
+
23
+ - **Already pinned** — an existing behavior test covers the exact changed path and still passes unchanged. Cite it (`file:line`); that test *is* the characterization.
24
+ - **Declared intended behavior change** — deliberately alters observable behavior per an AC/bug brief. The obligation inverts: update/author the test to assert the **new** behavior, and the diff must show the old assertion changing to the new (a behavior change with no test delta is the suspicious case). Cite the AC.
25
+ - **Trivial / generated / non-behavioral** — formatting, comments, type-only edits, generated code with no behavior delta.
26
+
27
+ ## The `@characterizes` convention
28
+
29
+ Tag a characterization test so the gate can resolve it, parallel to `@covers`:
30
+
31
+ ```js
32
+ // @characterizes <surface-id> // pins prior behavior of a surface being modified
33
+ // @covers <surface-id> // (a characterization test usually also @covers it)
34
+ // @level <level>
35
+ ```
36
+
37
+ `@characterizes` is the signal that *this* test exists to hold a modification's behavior boundary. A modifying diff with no `@characterizes` test and no declared waiver is the gap this obligation names.
38
+
39
+ ## Grading
40
+
41
+ Characterization is a **depth** concern, graded with the [shared vocabulary](grading.md):
42
+
43
+ - A modifying diff whose changed behavior is pinned by a passing characterization test (or cited pre-existing behavior test) → that surface can reach `Covered` on the normal evidence rules.
44
+ - A modifying diff with **no** characterization test and **no** declared intended-change → `Partial` at best; the reviewer raises the `modifies-existing-behavior` lead (below). Not a hard `Missing` (existing tests may incidentally cover it) — a **lead to adjudicate**, because whether a characterization test is *needed and adequate* is judgment.
45
+
46
+ ## Detection (mechanical) → adjudication (judgment)
47
+
48
+ The decidable half is surfaced by `review-pr`'s `scan-diff.mjs`: any non-test source file with **removed/changed** lines emits a `modifies-existing-behavior` **lead** ("look here and verify," never an auto-finding). The reviewer checks for a `@characterizes` test (or a declared change) and adjudicates, citing `file:line`. This pairs with the **`depth.characterization`** row in the [Coverage Checklist](../process/review-contract-template.md), a `lead`-method row resolved with a locator, not prose. The split matches the GATE-vs-LEAD line everywhere in this skill: detecting *that behavior changed* is mechanical; deciding *whether the pinning test is adequate* is semantic.
49
+
50
+ ## Seams: where to pin
51
+
52
+ A characterization test is writable only where you can observe behavior without rewriting the thing you're about to change — a **seam** (*"a place where you can alter behavior without editing the code in that place"*). Pin at the nearest observable seam: the public function's return/throw, the endpoint's HTTP contract, the rendered page's output, the emitted event. If there's no seam, that itself is the finding — introduce one first (extract the call, expose the boundary), pin, *then* change. Do not skip characterization because "it's hard to test as written"; hard-to-pin is the legacy-code smell the obligation exists to surface.
53
+
54
+ ## Fails-first: bug-fix AND feature-AC — prove the test fails when the behavior is broken
55
+
56
+ The shared property: **a test is evidence for a behavior only if it would go red were that behavior broken.** A green test that passes with *and* without the behavior it claims is **vacuous coverage** — it locks in nothing. Two cases:
57
+
58
+ **Bug-fix sibling.** A bug fix changes behavior that's *already wrong*, so it owes the inverse of characterization: at least one test demonstrated to **fail on the unfixed code and pass on the fixed code** (RED→GREEN, run in that order), tagged `// @fails-without-fix <surface>`. Reverting the fix must turn the test red. Waive only with a cited reason the failure can't be reproduced in-suite (a tracked `Unverified` manual check, not a silent skip).
59
+
60
+ **Feature-AC sibling.** The same test applies to a *new feature's* AC, where it's most-missed: a green test cited for an AC clears it only if it would go red were the AC's behavior removed — it exercises the AC's real code path, not a proxy. Recurring vacuous forms:
61
+ - a fixture that **early-returns before the code runs** (a 0-step workflow "proving" a multi-step reset that never executes);
62
+ - a `.fill()`/`setValue` that sets state in one shot and so **masks a re-render/defocus bug** a character-by-character `pressSequentially` would expose;
63
+ - an assertion **pinned to a stand-in value the real producer never emits**;
64
+ - asserting **the mock was called** rather than that the outcome happened.
65
+
66
+ **Grading the two outcomes** (they differ from [grading.md](grading.md)'s `Unverified`): can't-yet-confirm it would go red → `Unverified` (blocking); confirm it would **still pass** with the behavior gone → `Missing`/`Over-mocked` (a proven-vacuous test is *worse* than unchecked).
67
+
68
+ This is the doctrine the login-regression case (#237) slipped: the shipped sweep asserted nothing the bug could trip — an assertion swallowed by `.catch`, a fixed `waitForTimeout` — so it stayed green while the primary button rendered invisible. The two **decidable** vacuous forms are gated by `lint-tests` (`no-swallowed-assertion`, `no-fixed-timeout`); the semantic "would it have been red?" property is verified at review and by running the test against the broken tree.
@@ -0,0 +1,25 @@
1
+ {
2
+ "//": "OPTIONAL. The mock-internal-seam lint rule is default-on and zero-tolerance (references/depth/mock-policy.md); a conventional @/-aliased repo needs NO config. Copy this to coverage.config.json at your repo root only to declare non-conventional TOPOLOGY (a monorepo's own package scope, generated dirs to exempt). It cannot disable the gate, and there is no waiver.",
3
+ "mockPolicy": {
4
+ "firstPartyAliasPrefixes": ["@/", "~/"],
5
+ "firstPartyPackages": ["@your-scope/"],
6
+ "externals": ["^@/generated/"]
7
+ },
8
+ "//scopeClass": "OPTIONAL. Tunes the pattern -> oracle table scope-class.mjs uses to infer a unit's scope class (references/process/scope-class.md). The built-in default set already covers merge policy, CI workflows, deploy config, IAM, docs, lockfiles, generated files and tests. `extraClasses` is additive and checked BEFORE the defaults, so your declaration wins over an overlapping built-in guess; `classes` replaces the table wholesale. The `oracle` is a REQUIREMENT, not a waiver: a matched class with no oracle is a blocking finding. Declare a class unproven-by-design with \"oracle\": null plus \"unprovenReason\". `highRisk: true` RAISES the review tier alongside scopeClass no-surface — it never lowers it, and it never lightens the review.",
9
+ "scopeClass": {
10
+ "extraClasses": [
11
+ {
12
+ "id": "terraform",
13
+ "patterns": ["infra/**/*.tf", "infra/**/*.tfvars"],
14
+ "oracle": "`terraform plan` against the target workspace, plan output attached",
15
+ "highRisk": true
16
+ },
17
+ {
18
+ "id": "changelog",
19
+ "patterns": ["CHANGELOG.md"],
20
+ "oracle": null,
21
+ "unprovenReason": "release prose has no executable oracle — unproven by design; say so in the Review Contract"
22
+ }
23
+ ]
24
+ }
25
+ }
@@ -0,0 +1,35 @@
1
+ # Depth: Proving Each Obligation
2
+
3
+ > Read when: grading whether a test actually proves the behavior against real state. Sibling: [mock-policy.md](mock-policy.md) (the boundary principle this grading enforces). Depth grades each `Aligned` row — and each `Orphan surface` carrying a [Surface Baseline Contract](../breadth/surface-baseline.md) floor — by inspecting its actual tests.
4
+
5
+ The canonical depth failure is **internal interception counted as behavior**: a Playwright `route.fulfill`/`page.route(` faking your own endpoint's response, or any substitute standing in for an internal seam. It makes a surface *look* covered while proving only proxy wiring — the boundary violation the [Mocking Stance](mock-policy.md) forbids. Classify it `Over-mocked`, never `Covered`.
6
+
7
+ **Separate browser routes from API routes; prove each with its own evidence kind.** Prove an API route (`route.*`) by hitting the endpoint and asserting the HTTP contract, auth, and durable state. Prove a browser route (`page.*`) by driving the rendered page: what it displays, what the user can do, and what happens when they do. Never grade a browser route `Covered` because its backing endpoints are covered (the `/settings/connectors` miss) — a green API test under a page is necessary but never sufficient.
8
+
9
+ **For any write form, require one test that fills the rendered UI and asserts the mutation end to end** — operator fills the actual form and submits → backend accepts → durable state changes. Keep the render-health watcher attached **through** the submit (compose with `presentation:render-health`, [../presentation/axis.md](../presentation/axis.md)), so an uncaught error / `console.error` / first-party 5xx fired *during* the write fails the test even when the durable-state assertion would pass — the "mutate-health" gap. Do not accept seam tests in its place: a schema endpoint returning fields, a validator rejecting bad input, and an API forwarding a hand-built payload all pass while the rendered form silently drops a backend-required field. This is acute for the **split-contract form**, whose fields come from one source (schema endpoint, config descriptor, generated form spec) and validation from another (the backend contract); only a rendered-form submission proves the form emits a payload the backend accepts.
10
+
11
+ ## Evidence Hierarchy
12
+
13
+ Do not trust prior coverage documents, audit reports, PR summaries, issue comments, or agent claims as proof of coverage. Treat them only as leads to verify against current code.
14
+
15
+ Use evidence in this order:
16
+
17
+ 1. Actual test code and assertions.
18
+ 2. Test execution evidence: CI logs, local command output, traces, screenshots, or reports.
19
+ 3. Runtime/code discovery: routes, endpoints, schemas, public interfaces, and changed code paths.
20
+ 4. Prior docs/reports/PR summaries only as context to verify, never as authoritative evidence.
21
+
22
+ Classify coverage as `Covered` only after inspecting the relevant test file/case and confirming it asserts the required behavior at the required level. CI logs prove execution, not coverage quality. If actual test code cannot be inspected, classify as `BLOCKED` or `Unverified`, never `Covered`.
23
+
24
+ ## Coverage classifications (the shared vocabulary)
25
+
26
+ A self-declared `@level` is a claim the validator must try to **refute**, and can never alone reach `Covered`. The three terminal states are marked below.
27
+
28
+ - `Covered` (green, terminal): inspected test code validates the AC at the right level with meaningful assertions and acceptable mock/fake use, **and** is reviewer-attested. A self-declared `@level` alone never reaches it.
29
+ - `Partial`: some behavior is tested, but edge cases, failures, permissions, state, or evidence are incomplete.
30
+ - `Missing`: no meaningful test maps to the AC.
31
+ - `Wrong Level`: test exists but is too shallow for the risk — e.g. unit-only for stateful workflow, API contract, auth, money movement, concurrency, or event behavior.
32
+ - `Over-mocked` (red, terminal): mocks bypass the behavior the AC must prove — a behavior/journey test that intercepts first-party traffic (`page.route`, `route.fulfill`, MSW, first-party fixtures), or a `mutation` journey that never resolves a real durable-state path. Proves only proxy wiring.
33
+ - `Unverified` (blocking yellow, terminal): the level is satisfied statically (or claimed by docs/reports/CI) but assertion/execution quality is unconfirmed. It **blocks** the gate (not a passive warn) until a reviewer attests `verified: true` (plus evidence), which promotes it to `Covered`. The residual variance is over *quality of an existing test*, not *whether a surface exists*.
34
+ - `Excluded`: a human marked the surface out of scope with category + reason and the adapter signals permit it; surfaced in the exclusion census.
35
+ - `BLOCKED`: required source, code, tests, route discovery, environment, or product decision is unavailable.
@@ -0,0 +1,87 @@
1
+ # Mock And Integration Policy (depth)
2
+
3
+ > Read when: deciding what may be substituted in a test. The boundary principle the [depth grading](grading.md) enforces.
4
+
5
+ ## Mocking Stance
6
+
7
+ Default to real. The governing principle is **real internals, faked externals, nothing in between**:
8
+
9
+ - A test substitute is permitted **only at a trust boundary you do not own**: third-party HTTP APIs, payment/KYC providers, email/SMS, the clock, randomness.
10
+ - Everything **inside** your own system runs for real: database, repositories, service layer, internal endpoints, event bus. A substitute for an internal seam is a design smell or coverage gap, not a testing choice.
11
+ - The rule is **two-sided**: don't mock inward, don't reach outward — externals must be replaced by a fake/stub adapter so tests stay deterministic and never call a live third party in CI. "Be pure by calling the real provider" is the opposite failure, also rejected.
12
+
13
+ The problem we reject is **mock-only coverage of behavior that must be proven against real state** — not the presence of mocks. Fakes/stubs that keep failure-path and edge tests fast and deterministic are good and expected.
14
+
15
+ ## Glossary
16
+
17
+ - **Dummy**: placeholder passed only to satisfy a signature; never exercised.
18
+ - **Stub**: returns canned data so the test can proceed; no assertions on it.
19
+ - **Spy**: a stub that also records calls, so the test can assert a call happened or did not happen.
20
+ - **Mock**: a pre-programmed object with expectations; the test fails if it is not called exactly as specified (behavior verification of internal call sequences).
21
+ - **Fake**: a real, lightweight working implementation (in-memory DB, fake HTTP adapter) — behaves like the real thing, just not production-grade.
22
+
23
+ Rule of thumb: prefer **fakes** at external boundaries; use **stub/spy** for failure injection and "was-not-called" assertions; avoid **mocks** that encode internal call sequences — that tests implementation, not behavior.
24
+
25
+ ## Where substitutes are allowed
26
+
27
+ Use a fake/stub/spy at the external boundary for:
28
+
29
+ - External provider timeout, decline, malformed response, and rare failure paths (stub/fake the provider adapter).
30
+ - Isolating pure decision logic.
31
+ - Asserting an external provider or side effect was not called after validation failure (spy; there is no real call to observe).
32
+ - Keeping tests deterministic when the external system is not the subject under test.
33
+
34
+ These are **internal** and are therefore never covered by substitutes alone:
35
+
36
+ - Database transaction behavior.
37
+ - Idempotency and duplicate delivery.
38
+ - Concurrency/race conditions.
39
+ - Event publishing, outbox, retry, and recovery behavior.
40
+ - Auth, tenant isolation, and permission boundaries.
41
+ - Serialization, schema, and API compatibility.
42
+ - Orchestrator recovery after crash/retry.
43
+
44
+ Prefer integration tests with real app/service code, real DB or test containers with migrations, queue/pub-sub emulators where practical, fake external provider adapters, and assertions on final durable state, emitted events, and externally visible outcomes.
45
+
46
+ ## Mechanized gate: `mock-internal-seam` (zero-tolerance, default-on)
47
+
48
+ The stance above is mostly a review judgment — but its decidable core is a **hard CI gate**, because over-mock is the failure mode that shipped a production incident behind green tests. What makes it gate-worthy (near-zero false positives) is the **externals-allowlist inversion**: you cannot enumerate every internal seam (unbounded, per-project), but the set of things that may *legitimately* be faked is small, stable, and known. So flip the question — **a mock whose target resolves to first-party code is a defect; anything on the declared externals allowlist (or the stdlib) is exempt.** That makes "real internals, faked externals" decidable from a tiny per-project *topology* declaration, so the same rule works in any repo.
49
+
50
+ `lint-tests`'s `mock-internal-seam` rule (engine: `scripts/mock-policy-config.mjs`) implements it. For each `vi.mock`/`jest.mock`/`vitest.mock` it extracts the target and classifies via the declared topology:
51
+
52
+ - **External (exempt):** declared `externals` regexes, `node:` builtins, bare npm packages, relative imports into a test util / fixture / `__mocks__`.
53
+ - **Internal seam (flagged):** first-party alias prefixes (`@/`, `~/` by default), declared first-party workspace packages (a monorepo's `@acme/`), relative imports into source.
54
+
55
+ **Zero tolerance — no off switch, no waiver, no grandfathering:**
56
+
57
+ - **Default-on.** Runs in the standard `lint-tests` set with no opt-in. `coverage.config.json` only *declares topology*; it **cannot turn the gate off**. With no config, the `@/`/`~/` defaults apply.
58
+ - **Both lanes, including inherited.** Diff-scoped (`--diff <base>`) catches newly-added seams; a **whole-tree** scan (no `--diff`) holds the line on **inherited** mocks — a tree with existing over-mock stays red until it is *removed*.
59
+ - **No waiver.** No `// @mock-ok` escape hatch. A believed *false positive* (target genuinely external) is fixed by correcting **topology** in `coverage.config.json` — declaring truth, not waiving.
60
+
61
+ > **Over-mock is worse than no test — so "delete it" is a first-class fix.** A route with no test is an *honest* gap; an over-mocked test is *dishonest green* hiding the gap behind a passing check. The finding has exactly three resolutions, and "keep it" is never one: **(a)** replace with a real-boundary test; **(b)** fake only the external behind it; or **(c) delete the over-mocked test outright.** Deletion is always allowed — you are not forced to write a real test to clear an over-mock. But it removes only the *dishonest* signal: the route then follows normal breadth rules — `Missing` if in-scope and still owing a floor test (the [accounting gate](../enforcement/ci-contract.md) still requires it), or `Excluded` if out of scope. Test-*existence* is the per-route declarable breadth question; over-mock — test-*honesty* — is never negotiable.
62
+
63
+ > **The gate's *visibility* never depends on config — this has misled auditors twice.** (1) **The scripts live in this skill, not the audited repo** (`<skill>/scripts/lint-tests.mjs` + `mock-policy-config.mjs`); you run them *against* a repo, so their absence there means nothing — never conclude "gate unavailable." (2) **A missing `coverage.config.json` means "run on defaults," not "not applicable."** In **audit mode** ([../process/audit-mode.md](../process/audit-mode.md)) run it **whole-tree** and **quantify every hit** as an `Over-mocked` row — an automatic no-ship contributor, never an omittable "advisory" side note.
64
+
65
+ What stays a **review lead**, not this gate: whether a real-boundary sibling actually exists (cross-file), shallow assertions, semantically-wrong fakes. The gate proves the decidable shell (this mock targets an internal seam → defect); the reviewer judges the rest.
66
+
67
+ **Gate on the count, trend on the rate.** The gate is binary and zero-tolerance — *any* over-mock fails. But "is it 0?" says nothing about whether honesty is improving across an evolving suite, since a raw count climbs just as tests are added. So the ledger also emits an **over-mock rate** (`overMocked / tested` depth-graded surfaces, split behaviour vs presentation) to `coverage-metrics.json` and the `validate`/`report` summary ([../breadth/coverage-ledger.md](../breadth/coverage-ledger.md) → Outputs). The rate is a **trend signal for `review-pr` and dashboards, not a second gate** — the merge bar stays "count == 0." A `Missing` surface (no test) is honest absence, excluded from the denominator.
68
+
69
+ ### Declare topology (`coverage.config.json` at repo root)
70
+
71
+ Config tunes *what counts as first-party* — not whether the gate runs.
72
+
73
+ ```json
74
+ {
75
+ "mockPolicy": {
76
+ "firstPartyAliasPrefixes": ["@/", "~/"],
77
+ "firstPartyPackages": ["@acme/"],
78
+ "externals": ["^@/generated/"]
79
+ }
80
+ }
81
+ ```
82
+
83
+ Everything has a generic default (`DEFAULT_MOCK_POLICY`); a conventional `@/`-aliased repo needs **no config**. `firstPartyPackages` is the one fact most monorepos declare (their own package scope); `externals` is for the rare first-party-looking specifier that is actually generated/external. (`enabled` is accepted but inert — no opt-out.) A ready-to-copy example sits at `coverage.config.example.json`; the full field reference is `schemas/coverage-config.schema.json`.
84
+
85
+ ### Adapting to other ecosystems
86
+
87
+ Only the *front-end* (finding a mock call + its target) is language-specific — `extractMockTarget` covers the JS/TS `vi`/`jest`/`vitest` family; the classify core (target → first-party vs external) is shared. A new stack (e.g. Python `unittest.mock.patch('a.b.c')`) is a one-function adapter feeding the same classifier; until one exists the policy degrades to the prose review-lead, not a false block.
@@ -0,0 +1,23 @@
1
+ # Depth: Test smells — the diagnostic vocabulary and where each is enforced
2
+
3
+ > Read when: judging test *quality* (not just presence), or deciding whether a smell belongs in a blocking gate or a review lead. Sibling: [grading.md](grading.md) (the coverage classifications), [mock-policy.md](mock-policy.md) (the boundary).
4
+
5
+ A passing test is not automatically a good test. The classic catalog (Meszaros' *xUnit Test Patterns*, Martin's FIRST) names the ways a green suite still fails its job. Each smell maps to an enforcement point — and to **whether it is mechanically decidable (a gate) or judgment (a lead).** Same dividing line [lint-tests](../../scripts/lint-tests.mjs) draws everywhere: a check blocks only if a legitimate test could never trip it; otherwise it's a lead the reviewer adjudicates.
6
+
7
+ | Smell | What it is | Decidable? | Enforced as |
8
+ |---|---|---|---|
9
+ | **Erratic** (flaky) | Passes/fails non-deterministically — usually a fixed sleep instead of an explicit wait | **Yes** (the sleep forms) | **Gate**: `lint-tests` `no-fixed-timeout`. Genuine un-sandboxable flake → `@quarantine` lane (runs, non-blocking, graded `Unverified`), never `test.skip` ([test-skipping.md](../../../e2e-test/references/authoring/test-skipping.md)) |
10
+ | **Missing Assertion** | A test that runs but proves nothing | **Partly** | **Gate** for the decidable floors — an **empty body** (`it('x', () => {})`): `lint-tests` `no-empty-test`; and an **assertion whose rejection is swallowed** by a chained `.catch(...)` so it can never fail (`expect(...).not.toBeVisible().catch(() => {})`): `lint-tests` `no-swallowed-assertion`. **Lead** for the rest: a test with statements but no assertion *may still assert through a helper*, so "no `expect`/`assert` token" is not zero-FP — the reviewer reads it (`depth.asserts-something` checklist row) |
11
+ | **Slow** | Violates FIRST's *Fast* — too slow to run every loop | **No** (runtime is environment-sensitive) | **Lead**: a review observation, not a blocking gate — a threshold that fails on a loaded CI runner gets disabled. Flag a test that is slow *for its tier* (a unit test doing real IO, a journey with avoidable waits) and push it down the pyramid or fix the wait |
12
+ | **Fragile** | Breaks on unrelated/implementation changes — couples to structure, not behavior | **No** | **Principle**, not a gate: *test observable behavior, not internal structure* (Core Principles). A test asserting private call-order/shape is the smell; a reviewer judgment |
13
+ | **Obscure** | You can't tell what it tests from reading it — non-DAMP name, hidden setup | **No** | **Lead**: the reviewer checks the test name describes the behavior it asserts (DAMP — Descriptive And Meaningful Phrases), and that a failure message would point at the cause |
14
+ | **Over-mocked** | Mocks bypass the behavior under test (first-party interception) | **Yes/Lead** | **Gate + lead**: ledger `Over-mocked` classification + `scan-diff` interception lead ([grading.md](grading.md), [mock-policy.md](mock-policy.md)) |
15
+
16
+ ## The gate-vs-lead split, stated once
17
+
18
+ - **Missing Assertion** is the instructive case. Its decidable floor — a literal empty test body — is a gate (`no-empty-test`), because nothing legitimate is an empty-bodied `it(...)`. But the *general* form ("has code, asserts nothing") can't be a zero-FP gate: a test may assert entirely through a helper (`await verifyDashboard(page)`), so flagging "no `expect` on the test's own lines" would false-block it. That residual is a **lead** — the reviewer reads the test and the helper.
19
+ - **Slow** stays a lead for an orthogonal reason — not false positives but **non-determinism of the signal**: the same test's wall-clock varies with the runner. A hard threshold is enforcement built on sand.
20
+
21
+ ## What the reviewer does with the leads
22
+
23
+ For the `lead` smells above, `review-pr` carries them in its method as named checks, each "look here and verify," resolved on the Coverage Checklist with a `file:line` + verdict — never prose. A smell that later becomes mechanizable is promoted to a `lint-tests`/ledger rule (and a gate-lint checklist row), the same promotion path every other lead follows.
@@ -0,0 +1,164 @@
1
+ # CI Contract (Coverage Gate Standard)
2
+
3
+ The standard set of gates a repo must wire so the three coverage axes are actually *enforced*, not just *documented*. This is a **benchmark for audits**: run an audit against this list and report each gate as `present` / `warn-only` / `absent`. A repo can have impeccable test criteria and still ship a crashing route because the enforcement is missing or in phase-in mode — that gap is a finding in its own right.
4
+
5
+ The central rule: **doctrine is not enforcement, and accounting is not rendering.**
6
+
7
+ ## Required gates
8
+
9
+ | # | Gate | Command (reference) | Proves | Blocking? |
10
+ |---|---|---|---|---|
11
+ | 1 | **Inventory freshness** | regenerate **every tracked generated artifact** (`surface-inventory.json`, the route manifest, any committed ledger index/report), fail if any differs from committed | the surface list is not stale (new routes are discovered, not silently uncovered) | yes |
12
+ | 2 | **Accounting gate** | `coverage-ledger.mjs validate` | every surface's floor is *owned and proven by a clean authored test* (orphans, `Missing`, `Over-mocked`, blocking `Unverified` all fail) | yes |
13
+ | 3 | **Render sweep** | the `e2e-test` presentation sweep over every manifest route ([../presentation/runner-contract.md](../presentation/runner-contract.md)) | every browser route *actually renders* without `pageerror`/overflow/overlap/shift — the thing accounting cannot see | yes |
14
+ | 4 | **Functional + journey E2E** | the repo's Playwright suite | forms, flows, error paths behave | yes — **integration/nightly/release lane, not per-PR** (broad, slow; the per-PR golden-path floor is the smoke gate, #8) |
15
+ | 5 | **No over-mock** (**depth** axis) | `lint-tests.mjs --rules mock-internal-seam` — PR lane `--diff <base>` (new seams) **and** whole-tree (inherited) | no test fakes a first-party internal seam (zero-tolerance: default-on, no waiver, no grandfathering — [../depth/mock-policy.md](../depth/mock-policy.md)) | yes |
16
+ | 8 | **Curated E2E smoke** (golden-path liveness) | drive the smoke manifest paths to `smoke-results.json`, then `smoke.mjs verdict --target local --results smoke-results.json` ([../../../smoke/SKILL.md](../../../smoke/SKILL.md)) | the handful of do-not-ship journeys (sign in → core action → pay) are **alive against the real running app** | yes — **per-PR floor** |
17
+
18
+ (Gates 6/7 are `coverage-checklist.mjs validate` and `check-quarantine-expiry.mjs`, wired per the audit checklist below.)
19
+
20
+ Gates 2, 3, 4, and 8 are **distinct jobs** — the load-bearing point of this contract:
21
+
22
+ - Gate 2 (accounting) is a static analyzer: it proves a *qualifying test was authored*. It never opens a browser, so it cannot catch a runtime crash.
23
+ - Gate 3 (rendering) opens the real page: it catches the crash but does not track ownership/attestation.
24
+ - Gate 4 (functional E2E) is **not** gate 3. A functional spec may intercept its own API and still pass while the real route throws; the sweep forbids first-party interception and asserts perceivability. **A green functional E2E suite is not the presentation gate.**
25
+ - Gate 8 (smoke) is **not** gate 4. Browser smoke is the *curated* handful of critical journeys driven against the **real running app with no first-party interception** — a fast liveness floor gating every PR. Gate 4 is the *broad* behavioral suite (every form, error path, edge case), which may legitimately intercept for failure-injection and is too slow to block every PR — so it runs on the integration/nightly/release lane.
26
+
27
+ Skipping any one of 2/3/4/8 by folding it into another is the defect this contract names: "manifest validation passed" ≠ "the page renders"; "E2E is green" ≠ "presentation is proven"; "smoke is alive" ≠ "every behavior is exercised." **Per-PR lane = gates 1, 2, 3, 5, 6, 7, 8. The broad functional+journey suite (4) is required before release on the integration/nightly lane — demoted off the per-PR critical path, never dropped.**
28
+
29
+ ### Gate 1 ergonomics: regen is a command, drift is a gate, audits never fix
30
+
31
+ Catching drift is only half the contract — resolving it must be **one command**, or agents resolve it by hand-editing generated files (or merging around the gate). Three modes, strictly separated:
32
+
33
+ - **CI: regenerate + diff, never write.** Regenerate every tracked artifact, `git diff --exit-code`, fail on drift. CI never commits the fix — a bot-commit "fix" would let a surface change land without its author ever seeing the obligation it created.
34
+ - **Local fix: one first-class command** (e.g. `pnpm coverage:regen`, or the freshness check's `--fix` flag) that overwrites the tracked artifacts in place. The gate's failure message must *name this command*.
35
+ - **Audit: read-only, always.** Audit/validate commands report drift but never regenerate — a stale artifact is *evidence* (it dates when discovery last ran), and an audit that quietly repairs its own inputs destroys the finding it should report.
36
+
37
+ Caution: regenerated artifacts must be **deterministic** (stable ordering, no timestamps) — a regen that diffs on every run turns gate 1 into noise, and noisy gates get disabled.
38
+
39
+ ## Visual regression jobs (gated on opt-in)
40
+
41
+ **`presentation:visual` is the one opt-in presentation level** ([../presentation/runner-contract.md](../presentation/runner-contract.md)), so its enforcement is conditional: when *any* surface opts in, two CI jobs must exist. Both run **only in a pinned Playwright container** (`mcr.microsoft.com/playwright:vX.Y`) so baselines and the gate share one rendering environment — a baseline minted on macOS and gated on Linux fails on anti-aliasing, and that is how visual gates get disabled.
42
+
43
+ - **`visual-gate` (blocking).** Runs the sweep's visual instrument (`toHaveScreenshot()`) for opted-in `(route, viewport)` cells against the **committed** baselines. On drift it exits non-zero and uploads the 3-up actual/expected/diff as a CI artifact. It **never writes baselines**.
44
+ - **`visual-baseline-regen` (on-demand, label/dispatch-triggered).** Runs the instrument with `--update-snapshots` in the same container, then **commits the regenerated PNGs back to the PR branch** — the only sanctioned writer of baselines. Never part of the blocking run.
45
+
46
+ Baselines are **committed to the repo** (Playwright's `*-snapshots/` convention), not artifact-hosted: the gate compares against them so they must exist at test time, and the committed PNGs are the durable evidence a reviewer reads in the diff.
47
+
48
+ ### Evidence-posting step (after baseline-regen)
49
+
50
+ `visual-baseline-regen` ends by persisting the visual evidence back to the work item — **mechanized, not a prose reminder** (a described step degrades to a lookalike). `post-visual-evidence.mjs` (`e2e-test`) **upserts** a single marker-tagged comment (`<!-- visual-evidence:<unit> -->`, updated in place, never appended) to **both the source issue and the PR**, carrying the **durable** committed-baseline link at the regenerated SHA and the **ephemeral** diff/preview artifact URL with its expiry. The same two URLs are **returned** as a value (`--evidence-out`, plus stdout) for the `resolve-issues` orchestrator to record on the unit — a CI job never writes the run manifest itself, because the orchestrator is its only writer (ADR 0001 decision 5 (`docs/adr/0001-interference-is-the-scheduling-primitive.md`)). **Both shipped lanes pass `--evidence-out`** (`assets/ci-gates.github.yml` and `assets/ci-gates.cloudbuild.yaml`); a lane that only comments leaves the orchestrator nothing to record. The idempotent upsert keeps re-runs from spamming.
51
+
52
+ ## Three lanes: PR, integration/nightly, release
53
+
54
+ **PR lane (per-PR, fast):** gates 1, 2, 3, 5, 6, 7, **8** — scoped to the changed surface, run against a seeded test DB / ephemeral env. The minimal valuable floor: the page renders, the ledger is honest, no over-mock, golden paths are *alive*. Deliberately excludes the broad functional+journey suite.
55
+
56
+ **Integration lane (heavy, before release):** gate **4 (functional + journey E2E)** — the full behavioral suite. Runs on the **integration-branch push** (the `resolve-issues` epic integration gate already boots and smokes the assembled branch here), **not on every PR**. **Required before release** — demoting a slow, low-yield broad suite to a cheaper lane is legitimate placement tuning (per **obligation ≠ placement**); dropping it is not. A journey-only regression is therefore caught at integration, not on the PR that caused it — the accepted cost. A **nightly schedule is optional**; the integration-branch run, not the cron, is the gate that blocks release.
57
+
58
+ **Release lane (promotion to production):** a fast-forward promotion (see `review-pr`'s Promotion PRs) — you cannot and must not run the mutating suite against production:
59
+
60
+ - **Gate on the *promoted SHA's* lane results, don't re-run the heavy gates on `main`/prod.** Where the promotion fast-forwards (review-pr rule 1), the promoted tip is the **exact commit** already exercised by gates 1–8 on the integration branch, and the release gate is a **lookup**: "were the gates green at the SHA being promoted?" **That premise is topology-dependent.** Under a single-branch model (GitHub Flow) the release branch is rebased onto `main` before merging, so the shipped SHA carries commits that never earned those results — there the lookup is a **pre-filter**, and the gate that actually holds is the pre-exposure check below (`resolve-release` principle 11).
61
+ - **The env/data delta is what's left** — config, secrets, migrations, flag defaults, data. Cover it with the release-readiness checklist (review-pr rule 2) **pre-merge**, plus a prod check that runs **before any user reaches the new code**: the candidate is deployed at **0% traffic**, smoked read-only, and traffic shifts only on ALIVE (`resolve-release` step 4; `cloud-build` → Post-deploy smoke gate for the pipeline placement). Ordering is the whole point — a smoke that runs *after* traffic shifts is a monitor, and the bug is already live when it goes red.
62
+ - **Against production, the tenant rule is not enough.** Run smoke under a **read-only production Validation Profile** (`prod-preview` / `prod-active`), which excludes every `mutates:true` path *regardless of declared tenant*. Read-only is a property of the *named profile*, not a flag the caller must remember — a production profile that is anything but read-only fails smoke's own `validate`. The synthetic-tenant rule governs other deployed targets; production is stricter because the candidate is wired to the real production database, and "it isn't serving traffic yet" says nothing about whether a write is safe. **Never run mutating journeys against production data.**
63
+
64
+ The **quarantine lane is orthogonal** — not a fourth lane but the one sanctioned *non-blocking* adjunct (still **runs and reports**, doesn't block, dated auto-resurfacing exit), per [test-strategy.md](../process/test-strategy.md). Demoting a gate to a different *blocking* lane (PR → integration) is placement tuning; the *non-blocking* quarantine lane is a separate, tightly-bounded escape hatch for un-sandboxable externals / flakes-under-fix, never a way to stop running an obligation.
65
+
66
+ ## Wiring conventions (audited alongside the gates)
67
+
68
+ `ci-audit.mjs` classifies these per platform (`n/a` where a platform satisfies one by construction); the first two are **required**, the third **preferred**:
69
+
70
+ 1. **One umbrella check (required, GitHub).** Branch protection requires exactly **one** status check: an `all-gates` job that `needs:` every blocking gate and fails on any `failure`/`cancelled`. Listing gate jobs in the protection config by name is the anti-pattern this kills — a renamed/added gate silently falls out of protection, and a conditionally-skipped job counts as passing. Cloud Build is `n/a`. The non-blocking quarantine lane is never in `needs`.
71
+ 2. **Time budget (required).** PR-lane jobs carry an explicit timeout (`timeout-minutes: 5` / `timeout: 300s`) — the per-PR floor targets **≤5 min wall clock**, kept there by parallel golden paths and 15s action/assertion timeouts, not by dropping gates. The demoted integration-lane suite gets longer leashes. The audit's check is presence-only — it proves *a* timeout exists, not that the PR lane is bounded at 5 minutes; the value lives in the templates and is the reviewer's job to hold.
72
+ 3. **Docker-preferred (preferred).** Browser jobs run in the **pinned official Playwright container** — browsers ship in the image, and the rendering environment is pinned (the same property the visual gate requires). Every pin must be identical and match `@playwright/test`. Details + both options: `e2e-test` → `references/ci-playwright-container.md`.
73
+
74
+ ## The meta-gate (auditing the wiring)
75
+
76
+ The gates above catch bugs; **this audit catches the gates being deleted, never added, or quietly turned to warn-only.** Run it in ensure-coverage audit mode, and optionally as its own CI check:
77
+
78
+ ```bash
79
+ node <ensure-coverage>/scripts/ci-audit.mjs --files .github/workflows/ci.yml,cloudbuild.gates.yaml
80
+ ```
81
+
82
+ It scans CI config for each gate's command signature and reports `present` / `warn-only` / `absent` (comment-stripped, proximity-scoped weakening detection). It is **best-effort and false-negative-safe**: a gate wired under an unrecognized command reads as `absent` → a reviewer confirms, rather than the audit green-lighting a gate it couldn't see. `absent` and `warn-only` fail the audit (use `--allow-warn` only during a dated phase-in).
83
+
84
+ **Where the pieces live:** this contract (the *spec*) lives in `ensure-coverage`; the **runnable templates** live in `e2e-test/assets/` — `ci-gates.cloudbuild.yaml` and `ci-gates.github.yml`. A repo copies a template, fills the `<…>` placeholders, and `ci-audit.mjs` verifies it stays wired.
85
+
86
+ **Script-path placeholder convention:** reference a script by its **owning skill** — `<ensure-coverage>/scripts/<name>.mjs` for the coverage/lint/gate engine (`lint-tests`, `coverage-ledger`, `coverage-checklist`, `ci-audit`, `check-quarantine-expiry`) and `<e2e-test>/scripts/<name>.mjs` for the browser layer (`project-route-manifest`, `presentation-sweep`). Never a bare `<skill>` (ambiguous). The owning skill of each script is its directory under `skills/engineering/`.
87
+
88
+ ### Static lint gates vs. reviewer leads
89
+
90
+ Wherever a doctrine check is **syntactically decidable**, prefer a lint over an instruction: faster, free, robust, and it can't be rationalized away. `lint-tests.mjs` is the gate engine for the test-authoring rules; `no-skip`, `no-fixed-timeout`, `no-empty-test`, and `no-swallowed-assertion` (an assertion matcher whose rejection is eaten by a chained `.catch(...)`) are its always-on rules, and a new decidable rule is a few lines in the `RULES` registry. It also ships `mock-internal-seam` — the decidable core of over-mocking (a test that mocks a first-party seam module), the **depth-axis** gate (gate 5) — **default-on and zero-tolerance**: no opt-in, no `@mock-ok` waiver, inherited mocks not grandfathered. A false positive is fixed by correcting the declared *topology* in `coverage.config.json`, not by waiving; see [../depth/mock-policy.md](../depth/mock-policy.md).
91
+
92
+ **Only near-certain checks belong in a blocking lint** — a judgment call turned into a gate produces false positives, and a noisy lint gets disabled.
93
+
94
+ - **Gate (block CI):** decidable, ~zero false positives — added skip/focus/xfail, a fixed `waitForTimeout`/`sleep`, a missing manifest entry, a missing gate in CI config. These are `lint-tests.mjs` / `ci-audit.mjs` / the manifest validators.
95
+ - **Lead (inform the reviewer, never auto-block):** heuristic — "is this assertion meaningful?", over-mocking *beyond its decidable core*, asserting on an error page, an under-anchored regex. These live in `review-pr` → `scripts/scan-diff.mjs`. When a lead's evidence *does* become syntactically decidable (as the seam subset did), promote that slice and leave the judgment remainder a lead.
96
+
97
+ ### Adopting the contract into a pre-existing CI
98
+
99
+ A skill enforces nothing against a pipeline that already exists — the gates must be physically wired in, a **one-time migration per repo**. Until that lands, the only thing enforcing the contract is the *reviewing agent*. Run `ci-audit.mjs` in **adoption mode** to turn the gap into one reviewable issue:
100
+
101
+ ```bash
102
+ node <ensure-coverage>/scripts/ci-audit.mjs --adoption --files <your ci files> # → issue body on stdout
103
+ node <ensure-coverage>/scripts/ci-audit.mjs --adoption --json --files … # → structured plan
104
+ ```
105
+
106
+ It detects the platform (→ matching template) and emits a checklist **scoped to only the gaps** — never re-wiring a gate that already passes. The plan always includes the **bootstrap step**: wire `ci-audit.mjs` *itself* as a CI check (the meta-gate only guards the gates if CI actually runs it, and that wiring must be added by the same adoption PR). Exit code is `1` when adoption is needed, `0` when nothing is left to wire.
107
+
108
+ **Lifecycle hook:** when audit mode finds gates `absent`, pipe `--adoption` into `to-issues` (e.g. `gh issue create --body-file -`) so the contract gets installed by the same `to-issues → implement-and-pr → review-pr` loop that enforces everything else.
109
+
110
+ ## Phase-in is a finding, not a steady state
111
+
112
+ The tools support a phase-in mode (downgrade blocking `Unverified` → warn; `--warn-only`). Acceptable *temporarily* while a repo backfills, but a warn-only gate is **not enforcing** — an audit must report it as `warn-only`, treat it as `absent` for ship decisions, and require a dated exit plan. A render sweep that runs but does not fail the build is the same as no sweep.
113
+
114
+ ## Audit checklist (use in ensure-coverage audit mode)
115
+
116
+ Each item maps to a gate above; verify each is *present, blocking, and not folded into another*:
117
+
118
+ - [ ] Gate 1: inventory + every tracked generated artifact regenerated in CI, drift fails the build, CI never auto-commits; a first-class local regen command exists and the failure message names it.
119
+ - [ ] Gate 2: `coverage-ledger.mjs validate` **fails** on `Missing` / `Over-mocked` / blocking `Unverified` (not warn-only).
120
+ - [ ] Gate 3: the **render sweep** is a **separate job** over every manifest route, drives the **real** render path (no first-party interception — `page.route('**/api/**')`, MSW, fixtures), has its fixtures (auth bypass, seed, dynamic params), reports unrenderable routes `blocked` not `pass`, fails on any `fail`/`blocked`; `render-health` (spine) is in every browser route's floor.
121
+ - [ ] Gate 4: the **broad functional + journey E2E suite** blocks on the **integration/nightly lane** (not per-PR), verified green before release.
122
+ - [ ] The functional suite is **not** counted as the presentation gate, and smoke is **not** counted as the full functional suite.
123
+ - [ ] Gate 5: **`mock-internal-seam`** default-on — PR-lane `--diff` **and** whole-tree (inherited seam mocks block until removed); no `@mock-ok` waiver, false positives fixed via `coverage.config.json` topology.
124
+ - [ ] Gate 8: **curated E2E smoke** blocks **per-PR** — boots the app, drives the manifest into `smoke-results.json`, `smoke.mjs verdict --results smoke-results.json`; any `fail`/`blocked`/`missing` reds the build.
125
+ - [ ] **Static test-lint** (`lint-tests.mjs --diff <base>`, blocking) — no added `no-skip` / `no-fixed-timeout` / `no-empty-test` / `no-swallowed-assertion`. Tests never skipped (`../process/test-strategy.md`).
126
+ - [ ] Gate 6: **`coverage-checklist.mjs validate <checklist> --diff <merge-base>`** blocks against the Review-Contract checklist — every PASS/FAIL row carries a locator that **resolves in the tree**, every gate row carries the gate's *result* and not just its command, no gate row TODO (tier per [hooks.md](hooks.md)). The `--diff` is required in CI, not optional: it exempts the paths the PR deletes, and it is what lets the gate *block* on a missing file rather than only warn — without it, stale and deleted are indistinguishable and the gate declines to guess.
127
+ - [ ] Gate 6b: **`evidence-block.mjs validate`** blocks — the Review-Contract evidence block's stamp must equal current HEAD, so a commit landing after the block was collected can't ship stale evidence. (`--source` is comma-separated; on GitHub the job must check out the PR head SHA, not the default merge ref.)
128
+ - [ ] Gate 7: **`check-quarantine-expiry.mjs`** in the **blocking** lane — a dated quarantine exit past its `until=` re-blocks CI.
129
+ - [ ] Any **quarantine lane** is non-blocking, *still runs and reports* (`@quarantine`), keeps surfaces `Unverified`, carries a dated exit — never a substitute for a skip.
130
+ - [ ] Any surface opting into `presentation:visual`: blocking **`visual-gate`** in a pinned container vs **committed** baselines; baselines written **only** by on-demand `visual-baseline-regen`; **`post-visual-evidence.mjs`** upserts durable baseline link + ephemeral diff URL to **both** issue and PR.
131
+ - [ ] **(GitHub) branch protection requires only the `all-gates` umbrella job** (`needs:` every blocking gate, quarantine excluded); no gate listed by name. Cloud Build: the build's single status.
132
+ - [ ] **PR-lane jobs carry an explicit timeout** (`timeout-minutes: 5` / `timeout: 300s`, ≤5 min); golden paths parallel; per-action/assertion timeouts 15s; only integration gets a longer leash.
133
+ - [ ] Browser jobs run in the **pinned official Playwright container**, every pin identical and matching `@playwright/test`.
134
+ - [ ] Seeded accounts/tenants follow the **`e2e-*` naming convention** (`e2e-test` → `references/authoring/auth-flows.md`); `smoke.mjs validate` warns on unprefixed tenants.
135
+ - [ ] No gate is in phase-in/warn-only mode without a dated exit plan.
136
+
137
+ ## Reference wiring (illustrative — adapt to the repo)
138
+
139
+ ```yaml
140
+ # Distinct jobs, not one. Accounting is fast and static; the sweep needs a DB + browser.
141
+ jobs:
142
+ coverage-accounting:
143
+ steps:
144
+ - run: node scripts/gen-inventory.mjs # gate 1: your inventory adapter — regenerate + diff
145
+ - run: git diff --exit-code docs/tests/_generated/surface-inventory.json
146
+ - run: node coverage-ledger.mjs validate # gate 2: fail on Missing/Over-mocked/Unverified
147
+ presentation-sweep: # gate 3: separate job, real browser + seeded DB
148
+ services: [postgres]
149
+ steps:
150
+ - run: <seed + migrate>
151
+ - run: E2E_AUTH_BYPASS=1 node e2e/presentation-sweep.mjs # opens every manifest route
152
+ e2e: # gate 4: functional + journey suite (distinct from the sweep)
153
+ steps:
154
+ - run: <seed + migrate>
155
+ - run: pnpm playwright test
156
+ ```
157
+
158
+ The exact commands are repo-specific; what this contract fixes is the **shape**: inventory freshness + accounting + a separate render sweep + the functional suite, each blocking, none standing in for another.
159
+
160
+ ## Agentic coding lifecycle gates
161
+
162
+ The CI gates are merge-time; the surrounding lifecycle adds gate points. **Before implementation:** the `…criteria.md` exists and is approved for non-trivial features, given to the coding agent as task context. **During:** the agent adds/updates tests in the same PR, runs relevant tests/coverage before handoff with an `AC → test/evidence` mapping, and states the mock/fake policy per AC. **Before merge:** CI passes with the gates above wired (accounting **and** — distinct — the render sweep); the reviewer checks changed-code/missing-AC coverage, over-mocking, disabled/skipped tests, and shallow assertions, rejects mock-only coverage where integration is required, and a human approves any unautomated AC or mock-only exception.
163
+
164
+ Downstream PRs map stable AC IDs to tests/evidence and update the Coverage Ledger for any surface they add or change (the "obligation impact" block — touched obligations, `requirementRefs`, proving evidence, mock-only exceptions — is the breadth-axis maintenance that keeps the ledger from rotting). ensure-coverage defines correctness and test requirements; `implement-and-pr`/`review-pr` handle PR mechanics.