@amsterdamdatalabs/adl-agent-control-linux-x64 0.1.12 → 0.1.28

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 (410) hide show
  1. package/bin/adl +2 -2
  2. package/bin/git +16 -17
  3. package/bin/git-ado +25 -24
  4. package/bin/git-defaults +173 -0
  5. package/bin/health-check +8 -1
  6. package/bin/kimi-hooks +1 -1
  7. package/bin/lib/adl-package.sh +257 -0
  8. package/bin/lib/fleet-host.sh +8 -5
  9. package/bin/reconcile +482 -232
  10. package/bin/reconcile-host +30 -20
  11. package/bin/setup +20 -17
  12. package/bin/shell-path-policy +15 -5
  13. package/bin/sync-and-reconcile +62 -64
  14. package/bin/validate-manifest +33 -9
  15. package/package.json +2 -10
  16. package/packages/agent-hooks/README.md +14 -9
  17. package/packages/agent-hooks/assets/hooks.json +0 -20
  18. package/packages/agent-hooks/src/cli/args.ts +1 -1
  19. package/packages/agent-hooks/src/cli/doctor.ts +6 -58
  20. package/packages/agent-hooks/src/deploy/deploy.ts +12 -41
  21. package/packages/agent-hooks/src/deploy/doctor.ts +8 -11
  22. package/packages/agent-hooks/src/deploy/index.ts +14 -14
  23. package/packages/agent-hooks/src/deploy/json-merge.ts +7 -8
  24. package/packages/agent-hooks/src/deploy/legacy-lock.ts +2 -2
  25. package/packages/agent-hooks/src/deploy/list.ts +1 -1
  26. package/packages/agent-hooks/src/deploy/lock.ts +31 -12
  27. package/packages/agent-hooks/src/deploy/profile.ts +3 -4
  28. package/packages/agent-hooks/src/deploy/source.ts +1 -1
  29. package/packages/agent-hooks/src/gating/config.ts +12 -24
  30. package/packages/agent-hooks/src/gating/root.ts +3 -3
  31. package/packages/agent-hooks/src/hooks/briefing/handler.ts +2 -2
  32. package/packages/agent-hooks/src/hooks/briefing/index.ts +27 -287
  33. package/packages/agent-hooks/src/hooks/contract.ts +17 -17
  34. package/packages/agent-hooks/src/hooks/crg/background.ts +27 -0
  35. package/packages/agent-hooks/src/hooks/crg/index.ts +7 -6
  36. package/packages/agent-hooks/src/hooks/log.ts +8 -10
  37. package/packages/agent-hooks/src/hooks/user-prompt-submit/match.ts +1 -1
  38. package/packages/agent-hooks/src/hooks/user-prompt-submit/tokenizer.ts +1 -1
  39. package/packages/agent-hooks/src/hooks/user-prompt-submit/vector.ts +6 -5
  40. package/packages/agent-hooks/src/hosts/registry.ts +1 -1
  41. package/packages/agent-hooks/src/log/adl-dir.ts +44 -0
  42. package/packages/agent-hooks/src/log/writer.ts +16 -2
  43. package/packages/agent-hooks/src/main.ts +7 -41
  44. package/packages/agent-hooks/src/pre-tool-use/handler.ts +71 -82
  45. package/packages/agent-hooks/src/rules/engine.ts +13 -17
  46. package/packages/agent-hooks/src/rules/impl/adl-build-run-denied.ts +3 -3
  47. package/packages/agent-hooks/src/rules/impl/adl-git-credential-bypass.ts +12 -14
  48. package/packages/agent-hooks/src/rules/impl/adl-git-identity.ts +28 -28
  49. package/packages/agent-hooks/src/rules/impl/adl-git-push-policy.ts +8 -9
  50. package/packages/agent-hooks/src/rules/impl/adl-human-azdo-bypass.ts +56 -59
  51. package/packages/agent-hooks/src/rules/impl/adl-identity.ts +16 -23
  52. package/packages/agent-hooks/src/rules/impl/adl-mcp-cli.ts +19 -16
  53. package/packages/agent-hooks/src/rules/impl/adl-pr-complete-pending.ts +2 -2
  54. package/packages/agent-hooks/src/rules/impl/adl-pr-review-role.ts +9 -12
  55. package/packages/agent-hooks/src/rules/impl/adl-pr-role.ts +5 -7
  56. package/packages/agent-hooks/src/rules/impl/adl-run-required.ts +411 -0
  57. package/packages/agent-hooks/src/rules/impl/adl-token-minting-role.ts +4 -5
  58. package/packages/agent-hooks/src/rules/impl/adl-workitem-role.ts +6 -7
  59. package/packages/agent-hooks/src/rules/impl/agent-tamper-protection.ts +77 -70
  60. package/packages/agent-hooks/src/rules/impl/deny-allowlist.ts +131 -0
  61. package/packages/agent-hooks/src/rules/impl/git-helpers.ts +21 -23
  62. package/packages/agent-hooks/src/rules/impl/git-worktree.ts +14 -28
  63. package/packages/agent-hooks/src/rules/impl/mcp-tool.ts +3 -3
  64. package/packages/agent-hooks/src/rules/impl/messages.ts +1 -1
  65. package/packages/agent-hooks/src/rules/impl/pr-completion.ts +1 -1
  66. package/packages/agent-hooks/src/rules/impl/tool-azure-devops.ts +35 -46
  67. package/packages/agent-hooks/src/rules/impl/tool-find.ts +34 -7
  68. package/packages/agent-hooks/src/rules/impl/tool-grep.ts +33 -12
  69. package/packages/agent-hooks/src/rules/impl/tool-native-search.ts +52 -9
  70. package/packages/agent-hooks/src/rules/ports.ts +5 -7
  71. package/packages/agent-hooks/src/rules/registry.ts +4 -6
  72. package/packages/agent-hooks/src/rules/shell/git-identity.ts +86 -101
  73. package/packages/agent-hooks/src/rules/shell/git-internals.ts +1 -1
  74. package/packages/agent-hooks/src/rules/shell/invocation.ts +24 -118
  75. package/packages/agent-hooks/src/rules/shell/piped-script.ts +1 -1
  76. package/packages/agent-hooks/src/rules/shell/prefixes.ts +1 -1
  77. package/packages/agent-hooks/src/rules/shell/protected-carrier-writes.ts +11 -10
  78. package/packages/agent-hooks/src/rules/shell/protected-carriers.ts +26 -26
  79. package/packages/agent-hooks/src/rules/shell/substitution.ts +1 -1
  80. package/packages/agent-hooks/src/rules/shell/xargs.ts +2 -2
  81. package/packages/agent-hooks/src/rules/spec.ts +2 -2
  82. package/packages/agent-settings/README.md +287 -0
  83. package/packages/agent-settings/assets/GLOBAL-AGENTS.md +14 -16
  84. package/packages/agent-settings/assets/agents/architect.toml +2 -0
  85. package/packages/agent-settings/assets/agents/code-reviewer.toml +2 -0
  86. package/packages/agent-settings/assets/agents/executor.toml +2 -0
  87. package/packages/agent-settings/assets/agents/explore.toml +2 -0
  88. package/packages/agent-settings/assets/agents/planner.toml +2 -0
  89. package/packages/agent-settings/assets/mcp.json +0 -4
  90. package/packages/agent-settings/deploy-profile.json +139 -0
  91. package/packages/agent-settings/deploy-profile.schema.json +147 -0
  92. package/packages/agent-settings/managed/README.md +29 -30
  93. package/packages/agent-settings/managed/codex-requirements.toml +9 -9
  94. package/packages/agent-settings/package.json +20 -0
  95. package/packages/agent-settings/src/deploy/agent-render.ts +2 -2
  96. package/packages/agent-settings/src/deploy/agent-toml.ts +1 -1
  97. package/packages/agent-settings/src/deploy/agents-deploy.ts +17 -3
  98. package/packages/agent-settings/src/deploy/doctor.ts +3 -83
  99. package/packages/agent-settings/src/deploy/index.ts +6 -33
  100. package/packages/agent-settings/src/deploy/legacy-lock.ts +6 -6
  101. package/packages/agent-settings/src/deploy/list.ts +5 -19
  102. package/packages/agent-settings/src/deploy/lock.ts +8 -18
  103. package/packages/agent-settings/src/deploy/mcp-deploy.ts +10 -5
  104. package/packages/agent-settings/src/deploy/mcp-merge.ts +22 -3
  105. package/packages/agent-settings/src/deploy/mcp-source.ts +1 -1
  106. package/packages/agent-settings/src/deploy/profile.ts +11 -35
  107. package/packages/agent-settings/src/deploy/retire-lean-ctx.ts +184 -0
  108. package/packages/agent-settings/src/deploy/settings.ts +17 -22
  109. package/packages/agent-settings/src/global-surface-sweep.ts +0 -2
  110. package/packages/agent-settings/src/kimi-hooks.ts +339 -192
  111. package/packages/agent-settings/src/opencode-hooks.ts +1 -1
  112. package/packages/agent-settings/tsconfig.json +23 -0
  113. package/packages/agent-skills/assets/agent-search-tool-audit/SKILL.md +120 -0
  114. package/packages/agent-skills/assets/agent-search-tool-audit/scripts/audit.sh +276 -0
  115. package/packages/agent-skills/assets/debug-issue/SKILL.md +8 -7
  116. package/packages/agent-skills/assets/explore-codebase/SKILL.md +13 -13
  117. package/packages/agent-skills/assets/refactor-safely/SKILL.md +12 -11
  118. package/packages/agent-skills/assets/review-changes/SKILL.md +7 -7
  119. package/packages/agent-skills/assets/testing/references/e2e.md +37 -0
  120. package/packages/agent-skills/assets/testing/references/integration.md +37 -0
  121. package/packages/agent-skills/assets/testing/references/unit.md +32 -0
  122. package/packages/agent-skills/dist/deploy.d.ts +2 -0
  123. package/packages/agent-skills/dist/deploy.d.ts.map +1 -1
  124. package/packages/agent-skills/dist/deploy.js +27 -1
  125. package/packages/agent-skills/dist/deploy.js.map +1 -1
  126. package/packages/agent-skills/dist/doctor.d.ts +0 -2
  127. package/packages/agent-skills/dist/doctor.d.ts.map +1 -1
  128. package/packages/agent-skills/dist/doctor.js +1 -1
  129. package/packages/agent-skills/dist/doctor.js.map +1 -1
  130. package/packages/agent-skills/dist/fs-utils.d.ts +0 -1
  131. package/packages/agent-skills/dist/fs-utils.d.ts.map +1 -1
  132. package/packages/agent-skills/dist/fs-utils.js +1 -1
  133. package/packages/agent-skills/dist/fs-utils.js.map +1 -1
  134. package/packages/agent-skills/src/deploy.ts +29 -1
  135. package/packages/agent-skills/src/doctor.ts +1 -1
  136. package/packages/agent-skills/src/fs-utils.ts +1 -1
  137. package/packages/azdo/README.md +10 -9
  138. package/packages/azdo/package.json +1 -3
  139. package/packages/azdo/scripts/probe-ado-rules.ts +311 -0
  140. package/packages/azdo/src/azdo-pl.ts +2 -54
  141. package/packages/azdo/src/azdo-pr-review.ts +4 -4
  142. package/packages/azdo/src/azdo-repo-doctor.ts +101 -52
  143. package/packages/azdo/src/azdo-wit.ts +44 -2
  144. package/packages/azdo/src/lib/agent-identity.ts +12 -14
  145. package/packages/azdo/src/lib/agent-token.ts +2 -2
  146. package/packages/azdo/src/lib/client.ts +0 -5
  147. package/packages/azdo/src/lib/graph-identity.ts +4 -4
  148. package/packages/azdo/src/workflow-ladder.csv +241 -0
  149. package/packages/azdo/src/workflow-rules-matrix.csv +85 -0
  150. package/packages/azdo/src/workflow-rules.ts +194 -0
  151. package/packages/fleet/manifest.json +35 -11
  152. package/packages/fleet/manifest.schema.json +62 -10
  153. package/packages/fleet/src/default-agent-file.ts +3 -3
  154. package/packages/fleet/src/install-adl-package.ts +73 -15
  155. package/packages/fleet/src/install-embedding-model.ts +13 -13
  156. package/packages/fleet/src/managed-settings.ts +7 -7
  157. package/packages/fleet/src/repo-maintain.ts +91 -55
  158. package/packages/fleet/src/scratch-reap.ts +5 -5
  159. package/packages/fleet/src/vscode-settings.ts +5 -5
  160. package/packages/repo-controls/README.md +141 -43
  161. package/packages/repo-controls/assets/promote.ts +4 -4
  162. package/packages/repo-controls/assets/reconcile-guard.sh +10 -46
  163. package/packages/repo-controls/assets/version-bump.sh +31 -84
  164. package/packages/repo-controls/bunfig.toml +6 -7
  165. package/packages/repo-controls/package/adl-compliance/AGENTS.md +5 -6
  166. package/packages/repo-controls/package/adl-compliance/conftest.py +3 -1
  167. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/__init__.py +4 -16
  168. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/adr_lifecycle/test_check.py +9 -2
  169. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/closed_set/fixtures/docs/notes.md +1 -0
  170. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/closed_set/test_check.py +11 -0
  171. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/__init__.py +7 -0
  172. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/check.py +266 -0
  173. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/docs/guide/.drafts/c.md +1 -0
  174. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/docs/guide/.drafts/d.md +1 -0
  175. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/docs/guide/.hidden.md +1 -0
  176. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/docs/guide/a.md +1 -0
  177. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/docs/guide/b.md +1 -0
  178. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/docs/guide/data.csv +1 -0
  179. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/docs/guide/diagram.png +1 -0
  180. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/docs/guide/mock.png +1 -0
  181. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/docs/guide/sub/nested.md +1 -0
  182. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/docs.md +1 -0
  183. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/grants.yaml +4 -0
  184. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/plans/deep/p1.md +1 -0
  185. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/plans/deep/p2.md +1 -0
  186. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/plans/deep/p3.md +1 -0
  187. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/plans/deep/p4.md +1 -0
  188. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/plans/deep/p5.md +1 -0
  189. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-clean/docs/architecture/build.md +1 -0
  190. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-clean/docs/architecture/overview.md +1 -0
  191. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-clean/docs/guide/install.md +1 -0
  192. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-clean/docs/guide/start.md +1 -0
  193. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-clean/grants.yaml +4 -0
  194. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-decisions/docs/decisions/adr-001-tenancy.md +1 -0
  195. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-decisions/docs/decisions/adr-002-carrier.md +1 -0
  196. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-decisions/docs/decisions/adr-003-cli.md +1 -0
  197. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-decisions/docs/decisions/archive/adr-000-old.md +1 -0
  198. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-decisions/docs/decisions/archive/adr-000-older.md +1 -0
  199. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-decisions/docs/guide/a.md +1 -0
  200. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-decisions/docs/guide/b.md +1 -0
  201. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-decisions/docs/guide/c.md +1 -0
  202. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-decisions/grants.yaml +4 -0
  203. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-default-cap/docs/guide/page-01.md +1 -0
  204. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-default-cap/docs/guide/page-02.md +1 -0
  205. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-default-cap/docs/guide/page-03.md +1 -0
  206. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-default-cap/docs/guide/page-04.md +1 -0
  207. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-default-cap/docs/guide/page-05.md +1 -0
  208. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-default-cap/docs/guide/page-06.md +1 -0
  209. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-default-cap/docs/guide/page-07.md +1 -0
  210. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-default-cap/docs/guide/page-08.md +1 -0
  211. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-default-cap/docs/guide/page-09.md +1 -0
  212. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-default-cap/docs/guide/page-10.md +1 -0
  213. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-default-cap/docs/guide/page-11.md +1 -0
  214. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-default-cap/docs/guide/page-12.md +1 -0
  215. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-default-cap/docs/guide/page-13.md +1 -0
  216. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-default-cap/docs/guide/page-14.md +1 -0
  217. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-default-cap/docs/guide/page-15.md +1 -0
  218. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-default-cap/docs/guide/page-16.md +1 -0
  219. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-default-cap/grants.yaml +4 -0
  220. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-exempt/docs/guide/a.md +1 -0
  221. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-exempt/docs/guide/b.md +1 -0
  222. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-exempt/docs/guide/c.md +1 -0
  223. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-exempt/grants.yaml +4 -0
  224. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-grew/docs/guide/a.md +1 -0
  225. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-grew/docs/guide/b.md +1 -0
  226. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-grew/docs/guide/c.md +1 -0
  227. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-grew/grants.yaml +4 -0
  228. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-no-section/docs/guide/a.md +1 -0
  229. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-no-section/docs/guide/b.md +1 -0
  230. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-no-section/docs/guide/c.md +1 -0
  231. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-no-section/docs/guide/d.md +1 -0
  232. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-no-section/docs/guide/e.md +1 -0
  233. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-no-section/grants.yaml +4 -0
  234. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-over-cap/docs/guide/a.md +1 -0
  235. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-over-cap/docs/guide/b.md +1 -0
  236. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-over-cap/docs/guide/c.md +1 -0
  237. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-over-cap/docs/short/only.md +1 -0
  238. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-over-cap/grants.yaml +4 -0
  239. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-stale/docs/held/a.md +1 -0
  240. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-stale/docs/held/b.md +1 -0
  241. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-stale/docs/held/c.md +1 -0
  242. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-stale/docs/held/d.md +1 -0
  243. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-stale/docs/shrunk/a.md +1 -0
  244. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-stale/docs/shrunk/b.md +1 -0
  245. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-stale/grants.yaml +6 -0
  246. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-unusable/docs/guide/a.md +1 -0
  247. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-unusable/docs/guide/b.md +1 -0
  248. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-unusable/docs/guide/c.md +1 -0
  249. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-unusable/grants.yaml +3 -0
  250. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/test_check.py +345 -0
  251. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/english_only/check.py +18 -5
  252. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/english_only/test_check.py +35 -0
  253. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/__init__.py +7 -0
  254. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/check.py +91 -0
  255. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/AGENTS.md +3 -0
  256. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/CLAUDE.md +3 -0
  257. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/architecture/-leading-hyphen.md +3 -0
  258. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/architecture/AGENTS.md +3 -0
  259. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/architecture/double--hyphen.md +3 -0
  260. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/architecture/getting started.md +3 -0
  261. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/architecture/nested/page-here.md +3 -0
  262. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/architecture/trailing-hyphen-.md +3 -0
  263. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/architecture/ui-contract.md +4 -0
  264. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/architecture/user_profile.md +3 -0
  265. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/assets/UI-CONTRACT.png +2 -0
  266. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/assets/diagram.png +1 -0
  267. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/index.md +4 -0
  268. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/notes.md +3 -0
  269. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/reference.html +1 -0
  270. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/research/2026-10-experiment.md +3 -0
  271. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/research/UI-CONTRACT.md +6 -0
  272. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs.md +5 -0
  273. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/test_check.py +194 -0
  274. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/indexes/check.py +14 -2
  275. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/indexes/docs-knowledge-indexes.yaml +5 -5
  276. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/indexes/fixtures/knowledge-indexes-shipped-register-legacy/docs/compliance/index.md +10 -0
  277. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/indexes/fixtures/knowledge-indexes-shipped-register-type/docs/compliance/index.md +10 -0
  278. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/indexes/test_check.py +58 -6
  279. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/ledger/test_check.py +0 -1
  280. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/check.py +64 -17
  281. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/docs-okf-profiles.yaml +60 -9
  282. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-ledger-clean/docs/notes.md +17 -0
  283. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-ledger-no-lines/docs/notes.md +13 -0
  284. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-profile-clean/docs/architecture/demo.md +0 -1
  285. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-profile-clean/docs-okf-profiles.yaml +0 -1
  286. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-profile-untyped/docs/research/no-type.md +9 -0
  287. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-profile-untyped/docs/research/typed-experiment.md +10 -0
  288. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-profile-untyped/docs/research/typed-research.md +10 -0
  289. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-profile-untyped/docs-okf-profiles.yaml +5 -0
  290. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-profile-violation/docs/architecture/bad-status.md +0 -1
  291. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-profile-violation/docs-okf-profiles.yaml +0 -1
  292. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/experiment-ok.md +15 -0
  293. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/extra-key.md +15 -0
  294. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/extra-keys.md +16 -0
  295. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/missing-created.md +11 -0
  296. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/missing-description.md +11 -0
  297. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/missing-last-update.md +11 -0
  298. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/missing-sources.md +10 -0
  299. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/missing-status.md +11 -0
  300. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/missing-title.md +11 -0
  301. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/optional-keys.md +16 -0
  302. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/research-ok.md +14 -0
  303. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research-neighbours/docs/architecture/created-date.md +21 -0
  304. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research-neighbours/docs/architecture/research-shaped.md +19 -0
  305. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research-neighbours/docs/operations/runbook.md +26 -0
  306. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/test_check.py +228 -2
  307. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/register.py +5 -0
  308. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/semantics/test_check.py +11 -2
  309. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/__init__.py +5 -3
  310. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/check.py +160 -44
  311. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-clean/grants.yaml +0 -2
  312. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-empty-register/frontend/packages/desktop/src/a.ts +1 -0
  313. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-empty-register/frontend/packages/desktop/src/b.ts +1 -0
  314. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-empty-register/grants.yaml +3 -0
  315. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/grants.yaml +0 -2
  316. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-missing-tree/frontend/packages/desktop/src/renderer/solo/item.ts +1 -0
  317. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-missing-tree/grants.yaml +5 -0
  318. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-no-ceilings/frontend/packages/desktop/src/a.ts +1 -0
  319. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-no-ceilings/frontend/packages/desktop/src/b.ts +1 -0
  320. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-no-ceilings/frontend/packages/desktop/src/c.ts +1 -0
  321. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-no-ceilings/grants.yaml +4 -0
  322. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-stale-entry/frontend/packages/desktop/src/renderer/solo/item.ts +1 -0
  323. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-stale-entry/grants.yaml +5 -0
  324. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unbaselined/grants.yaml +0 -2
  325. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unusable-register/frontend/packages/desktop/src/renderer/solo/item.ts +1 -0
  326. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unusable-register/grants.yaml +3 -0
  327. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/register.py +127 -0
  328. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/test_check.py +265 -29
  329. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/markdown_trees/check.py +75 -2
  330. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/markdown_trees/test_check.py +194 -0
  331. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/open_work_cap/check.py +56 -10
  332. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/open_work_cap/test_check.py +258 -2
  333. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/placement/check.py +40 -12
  334. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/placement/test_check.py +108 -0
  335. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/plan_metadata.py +9 -4
  336. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/plans_layout/check.py +1 -1
  337. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/plans_layout/fixtures/plans-layout-clean/plans/features/az347-test-coverage/items/az351-restore-entrypoint.md +1 -1
  338. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/plans_layout/test_check.py +3 -3
  339. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/references/check.py +2 -3
  340. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/check.py +23 -6
  341. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/test_check.py +76 -0
  342. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_markdown_allowlist/check.py +58 -17
  343. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_markdown_allowlist/test_check.py +161 -0
  344. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/scripts_size_depth/check.py +35 -3
  345. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/scripts_size_depth/test_check.py +108 -1
  346. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/check.py +281 -61
  347. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/absolute-path.yaml +3 -0
  348. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/backslash-path.yaml +3 -0
  349. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/baseline-is-a-list.yaml +2 -0
  350. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/boolean-size.yaml +3 -0
  351. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/dot-segment.yaml +3 -0
  352. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/duplicate-path.yaml +4 -0
  353. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/empty-file.yaml +0 -0
  354. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/empty-segment.yaml +3 -0
  355. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/float-size.yaml +3 -0
  356. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/negative-size.yaml +3 -0
  357. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/no-over-limit-baseline.yaml +1 -0
  358. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/no-schema-version.yaml +1 -0
  359. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/non-string-path.yaml +3 -0
  360. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/not-yaml.yaml +2 -0
  361. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/null-size.yaml +3 -0
  362. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/parent-segment.yaml +3 -0
  363. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/string-size.yaml +3 -0
  364. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/top-level-is-a-list.yaml +2 -0
  365. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/trailing-slash.yaml +3 -0
  366. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/unknown-key.yaml +3 -0
  367. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/wrong-schema-version.yaml +2 -0
  368. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/zero-size.yaml +3 -0
  369. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/valid.yaml +4 -0
  370. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/test_check.py +758 -45
  371. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/ignored_paths/check.py +4 -3
  372. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/ignored_paths/test_check.py +2 -2
  373. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/cargo_lock.py +490 -0
  374. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/check.py +368 -55
  375. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/test_check.py +4 -2
  376. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/test_declared_paths.py +523 -0
  377. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/test_stale_lock.py +1179 -0
  378. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/cli.py +122 -3
  379. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/core/check.py +33 -1
  380. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/core/constants.py +0 -11
  381. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/core/context.py +16 -1
  382. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/config.py +1 -2
  383. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/docs_shape.py +12 -1
  384. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/gate-registry.alt.yaml +133 -147
  385. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/gate-registry.yaml +133 -147
  386. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/registry.py +1 -1
  387. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/root_shape.py +52 -10
  388. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/runner.py +23 -4
  389. package/packages/repo-controls/package.json +2 -9
  390. package/packages/repo-controls/scripts/hooks/post-merge +13 -0
  391. package/packages/repo-controls/scripts/hooks/pre-push +3 -3
  392. package/packages/repo-controls/src/azdo-push.ts +64 -36
  393. package/packages/repo-controls/src/azure-devops-governance.ts +7 -9
  394. package/packages/repo-controls/src/azure-devops-remote.ts +1 -1
  395. package/packages/repo-controls/src/cli.ts +29 -8
  396. package/packages/repo-controls/src/compliance-config.ts +410 -2
  397. package/packages/repo-controls/src/config.ts +133 -60
  398. package/packages/repo-controls/src/constants.ts +13 -27
  399. package/packages/repo-controls/src/coverage-ratchet.ts +4 -4
  400. package/packages/repo-controls/src/doctor.ts +46 -19
  401. package/packages/repo-controls/src/gitignore-block.ts +5 -29
  402. package/packages/repo-controls/src/hook-log.ts +1 -2
  403. package/packages/repo-controls/src/hook.ts +201 -45
  404. package/packages/repo-controls/src/install.ts +14 -8
  405. package/packages/repo-controls/src/integrity.ts +3 -3
  406. package/packages/repo-controls/src/lfs.ts +111 -0
  407. package/packages/repo-controls/src/promote.ts +8 -8
  408. package/packages/repo-controls/src/runtime.ts +9 -1
  409. package/packages/repo-controls/src/workflows-drift.ts +4 -5
  410. package/packages/repo-controls/src/worktree-guard.ts +3 -3
@@ -26,11 +26,26 @@ declared. `<rust>` resolves to `backend` and `<typescript>` resolves to
26
26
  defaults, just reached through `ctx.inputs` now, the same as every other
27
27
  check that names a consumer path.
28
28
 
29
+ A tree declared absent (`rust = ""` or `typescript = ""` in
30
+ `[controls.compliance.trees]`) drops the inputs naming it, and each half of this
31
+ row is then graded on its own: a repository declaring no Rust tree is graded on
32
+ its TypeScript lockfile alone and is never asked for a `Cargo.lock`. With
33
+ neither tree left the row is could-not-run (see `structural`) -- it used to raise
34
+ `KeyError`.
35
+
36
+ Retired 2026-10-01: `coverage.backend-ratchet` and `coverage.backend-crate`,
37
+ named here as precedents, were deleted with the `coverage` domain
38
+ (COV-001..005); the references record the pattern this check followed.
39
+
29
40
  LCK-001 a required lockfile is missing or empty (`[ -s FILE ]` in check.sh
30
41
  — MISSING and EMPTY are the same finding, worded the same way).
31
42
  LCK-002 `cargo metadata --locked` rejects `backend/Cargo.lock` against
32
43
  `backend/Cargo.toml` — the lock exists but does not satisfy the
33
- manifest.
44
+ manifest — or the lock's CONTENT fails the validation in
45
+ `cargo_lock.py` (see "`--no-deps` never reads the lockfile" below):
46
+ not TOML, an unsupported `version`, no packages, a package listed
47
+ as a dependency but absent, a workspace member or a direct
48
+ dependency of one missing from it.
34
49
 
35
50
  **check.sh stops at the first problem.** Each of the three failure branches
36
51
  ends in `report_summary; exit` — a missing frontend lockfile is never reported
@@ -56,29 +71,112 @@ finding (`LCK-002`) here exactly as it is in check.sh — this check trusts
56
71
  `cargo --version` having already ruled out "cargo cannot run at all" for the
57
72
  same reason check.sh does.
58
73
 
74
+ **`--no-deps` never reads the lockfile (measured 2026-10-01).** check.sh's command,
75
+ kept unchanged, passes `--no-deps`, so cargo never resolves and never opens
76
+ `Cargo.lock`: a lock that was `version = 4` alone, one that was not TOML, and one
77
+ with `version = 99` all came out CLEAN through this check, and only a missing or
78
+ empty lock was ever reported. Dropping `--no-deps` is not the fix: cargo then loads
79
+ every dependency's manifest, which fails offline whenever the crate sources are not
80
+ in the registry cache, so the gate would pass on one machine and fail or be
81
+ could-not-run on another. The lock's CONTENT is therefore judged in Python, in
82
+ addition to the cargo call and after it (`cargo_lock.CargoLock`, `tomllib`, no cargo,
83
+ no registry, no network; what it checks, and what it cannot judge and so refuses with
84
+ could-not-run, is that module's docstring). Per lock the order is: `cargo --version`;
85
+ `cargo metadata`, whose rejection is the one finding for that lock (cargo is the
86
+ authority on a manifest it refuses, and a lock cannot be compared with one); only when
87
+ cargo accepts, the content validation, one `LCK-002` per problem with the same remedy.
88
+ The limit, stated plainly: version-REQUIREMENT drift (a manifest raising a requirement
89
+ past the locked version) is not detected offline; `cargo metadata` without `--no-deps`
90
+ is the authority for that and needs the registry.
91
+
59
92
  cargo resolves its toolchain from the WORKING DIRECTORY — rustup applies
60
93
  `backend/rust-toolchain.toml` as a directory override, and `--manifest-path`
61
94
  does not change that: toolchain selection precedes reading the manifest. So
62
95
  both cargo calls run with `cwd` set to the workspace directory, not the
63
96
  manifest's own directory, matching check.sh's identical comment.
97
+
98
+ **A repository can declare exactly which paths this gate scans and grades**
99
+ (Tarun, 2026-10-01: "it should be configurable and declarative on what paths
100
+ should be scanned"). `[controls.compliance.lockfiles]` in `adl-config.toml`
101
+ reaches the engine as four comma-list declarations, a HALF (Bun, Cargo) being
102
+ declared by its manifests list and its lockfiles list together:
103
+
104
+ bun-manifests / bun-lockfiles `package.json` paths or globs / `bun.lock` paths
105
+ cargo-manifests / cargo-lockfiles `Cargo.toml` paths or globs / `Cargo.lock` paths
106
+
107
+ Why: the registry scope is `<typescript>/package.json` and `<typescript>/bun.lock`
108
+ (and the `<rust>` pair), a tree placeholder joined to a ONE-level file name.
109
+ enact-combined's `typescript` tree is a brace union of directories and its
110
+ manifests sit at the repository ROOT and under `apps/*/` and `packages/*/`, so on
111
+ a whole-tree run `engine.scope` matched no file and the row was could-not-run
112
+ (measured live: a narrowed run passed, the exhaustive run could not). The
113
+ per-gate `bun_lock` input moved the grade and never the scope.
114
+
115
+ A declared half REPLACES that half's tree defaults, in both places the paths are
116
+ used:
117
+
118
+ * scope (`declared_scope`): which changed files select the gate, and, because a
119
+ restated scope is graded whole, which files `graded` is handed;
120
+ * grade (`structural`): each declared lockfile must exist and be non-empty
121
+ (LCK-001, same wording and remedy as before); each declared Cargo lockfile's
122
+ directory is the cargo workspace and `<that directory>/Cargo.toml` its
123
+ manifest (LCK-002 as before).
124
+
125
+ `graded` makes the declaration honest: every declared manifest entry must match
126
+ at least one file of the complete in-scope set, or the row is could-not-run
127
+ naming the declaration and the entry. A declared glob that matches nothing would
128
+ otherwise shrink what the gate scans to nothing and say OK.
129
+
130
+ An undeclared half is exactly what it was: tree defaults, the `inputs`, the same
131
+ early-return shape. A malformed declaration (empty, absolute, backslash, `.`/`..`
132
+ segments, placeholder or brace or negation syntax, duplicate, the wrong file
133
+ name, a glob in a lockfile entry, or a half with only one of its two lists) is
134
+ could-not-run naming the declaration; the engine never grades against a guess at
135
+ what was meant. `adl` refuses the same values when it reads `adl-config.toml`.
64
136
  """
65
137
 
66
138
  from __future__ import annotations
67
139
 
68
140
  import shutil
69
141
  import subprocess
70
- from collections.abc import Iterable
71
- from typing import ClassVar
142
+ from collections.abc import Iterable, Mapping
143
+ from pathlib import Path
144
+ from typing import ClassVar, NamedTuple
72
145
 
73
146
  from ....core.check import Check, FileState
74
- from ....core.context import Context
147
+ from ....core.context import Context, FileSet
75
148
  from ....core.errors import CouldNotRun
76
149
  from ....core.finding import Report
150
+ from ....core.scope import matches
151
+ from .cargo_lock import CargoLock, Undecidable
152
+
153
+
154
+ class Half(NamedTuple):
155
+ """One of the two ecosystems this row grades, and the names that declare it."""
156
+
157
+ manifests: str
158
+ """The `--declare` name carrying the manifest paths or globs."""
159
+ lockfiles: str
160
+ """The `--declare` name carrying the literal lockfile paths."""
161
+ manifest_name: str
162
+ """The file name every manifest entry must end in."""
163
+ tree: str
164
+ """Prefix of the registry scope entries a declaration of this half replaces."""
165
+
166
+
167
+ class Declared(NamedTuple):
168
+ manifests: tuple[str, ...]
169
+ lockfiles: tuple[str, ...]
77
170
 
78
171
 
79
172
  class LockfileIntegrity(Check):
80
173
  id: ClassVar[str] = "REP-002"
81
174
 
175
+ CARGO: ClassVar[Half] = Half("cargo-manifests", "cargo-lockfiles", "Cargo.toml", "<rust>/")
176
+ BUN: ClassVar[Half] = Half("bun-manifests", "bun-lockfiles", "package.json", "<typescript>/")
177
+ # Cargo first, as the registry lists it and as `structural` grades it.
178
+ HALVES: ClassVar[tuple[Half, ...]] = (CARGO, BUN)
179
+
82
180
  inputs: ClassVar[dict[str, str]] = {
83
181
  "workspace": "<rust>",
84
182
  "cargo_lock": "<rust>/Cargo.lock",
@@ -94,33 +192,208 @@ class LockfileIntegrity(Check):
94
192
  MISSING: ClassVar[str] = "LCK-001"
95
193
  STALE: ClassVar[str] = "LCK-002"
96
194
 
195
+
196
+ # ------------------------------------------------------------ declarations
197
+
198
+ @classmethod
199
+ def _entries(
200
+ cls, declarations: Mapping[str, str], name: str, manifest_name: str | None
201
+ ) -> tuple[str, ...] | None:
202
+ """The validated entries of one comma-list declaration, `None` when absent.
203
+
204
+ `manifest_name` is the file name a manifest entry must end in; `None`
205
+ marks a lockfile list, whose entries are literal paths. Present but blank
206
+ is not absent: an empty entry is refused, never read as "declared nothing".
207
+ """
208
+ raw = declarations.get(name)
209
+ if raw is None:
210
+ return None
211
+ entries = tuple(part.strip() for part in raw.split(","))
212
+ for entry in entries:
213
+ why = cls._refusal(entry, manifest_name)
214
+ if why is not None:
215
+ raise CouldNotRun(
216
+ f"{cls.id}: declaration `{name}` entry {entry!r} {why}; fix "
217
+ f"[controls.compliance.lockfiles].{name.replace('-', '_')} in "
218
+ "adl-config.toml -- the gate does not guess which path was meant"
219
+ )
220
+ for index, entry in enumerate(entries):
221
+ if entry in entries[:index]:
222
+ raise CouldNotRun(
223
+ f"{cls.id}: declaration `{name}` lists {entry!r} twice; fix "
224
+ f"[controls.compliance.lockfiles].{name.replace('-', '_')} in adl-config.toml"
225
+ )
226
+ return entries
227
+
228
+ @staticmethod
229
+ def _refusal(entry: str, manifest_name: str | None) -> str | None:
230
+ """Why `entry` is not a repository-relative path this row can scan, or None.
231
+
232
+ The same set `adl` refuses when it reads `adl-config.toml`. Placeholder,
233
+ brace and negation syntax are scope SYNTAX, and a declared entry is a
234
+ path: letting one through would be a pattern that means more or less than
235
+ the repository wrote.
236
+ """
237
+ if entry == "":
238
+ return "is empty"
239
+ if entry.startswith("/"):
240
+ return "is absolute"
241
+ if "\\" in entry:
242
+ return "contains a backslash"
243
+ if entry.startswith("!") or any(char in entry for char in "<>{}"):
244
+ return "contains scope syntax (a leading '!', a <placeholder>, or braces)"
245
+ if any(segment in ("", ".", "..") for segment in entry.split("/")):
246
+ return "has a `.`, `..` or empty path segment"
247
+ if manifest_name is not None:
248
+ if entry.rsplit("/", 1)[-1] != manifest_name:
249
+ return f"does not end in {manifest_name}"
250
+ elif any(char in entry for char in "*?[]"):
251
+ return (
252
+ "is a glob, but a lockfile is a literal path: a missing one is "
253
+ "reported by name"
254
+ )
255
+ return None
256
+
257
+ @classmethod
258
+ def declared(cls, half: Half, declarations: Mapping[str, str]) -> Declared | None:
259
+ """What the repository declares for one half, or `None` when it declares nothing.
260
+
261
+ A half is declared by BOTH lists. One without the other is refused: the
262
+ missing list would have to fall back to a tree default, and which default
263
+ is exactly the guess this declaration exists to remove.
264
+ """
265
+ manifests = cls._entries(declarations, half.manifests, half.manifest_name)
266
+ lockfiles = cls._entries(declarations, half.lockfiles, None)
267
+ if manifests is None and lockfiles is None:
268
+ return None
269
+ if manifests is None or lockfiles is None:
270
+ present, missing = (
271
+ (half.lockfiles, half.manifests) if manifests is None else (half.manifests, half.lockfiles)
272
+ )
273
+ raise CouldNotRun(
274
+ f"{cls.id}: declaration `{present}` is set without `{missing}`; a half is "
275
+ "declared as a pair -- set both under [controls.compliance.lockfiles] in "
276
+ "adl-config.toml"
277
+ )
278
+ return Declared(manifests, lockfiles)
279
+
280
+ @classmethod
281
+ def declared_scope(
282
+ cls, scope: tuple[str, ...], declarations: Mapping[str, str]
283
+ ) -> tuple[str, ...] | None:
284
+ """The registry scope with each declared half's tree defaults replaced.
285
+
286
+ A half's defaults are the registry entries under its tree prefix
287
+ (`<rust>/...`, `<typescript>/...`); `test_the_registry_scope_the_hook_
288
+ replaces_is_two_entries_per_tree` pins that shape. The other half, and
289
+ anything else the row lists, is kept as it was.
290
+ """
291
+ restated = scope
292
+ any_declared = False
293
+ for half in cls.HALVES:
294
+ declared = cls.declared(half, declarations)
295
+ if declared is None:
296
+ continue
297
+ any_declared = True
298
+ restated = (
299
+ *(pattern for pattern in restated if not pattern.startswith(half.tree)),
300
+ *declared.manifests,
301
+ *declared.lockfiles,
302
+ )
303
+ return restated if any_declared else None
304
+
97
305
  # ------------------------------------------------------------- structural
98
306
 
307
+ # The three inputs that all name the `<rust>` tree. They are resolved or
308
+ # dropped together, so seeing only some of them means a per-gate
309
+ # `--input REP-002:<name>=...` replaced part of the triple.
310
+ CARGO_INPUTS: ClassVar[tuple[str, ...]] = ("workspace", "cargo_lock", "cargo_manifest")
311
+
99
312
  def structural(self, ctx: Context) -> Iterable[Report]:
100
- cargo_lock = ctx.inputs["cargo_lock"]
101
- bun_lock = ctx.inputs["bun_lock"]
102
-
103
- if self.state(ctx, cargo_lock) is not FileState.PRESENT:
104
- shown = ctx.relative(cargo_lock)
105
- yield self.report(
106
- shown,
107
- f"missing {shown}",
108
- f"run: (cd {ctx.relative(ctx.inputs['workspace'])} && "
109
- "cargo generate-lockfile) and commit the result",
110
- rule=self.MISSING,
313
+ # Decision for a tree declared absent (`rust = ""` / `typescript = ""`,
314
+ # which drops every input naming the tree). Unlike an exclusion path, a
315
+ # lockfile IS what this row grades, so each half is judged on its own:
316
+ #
317
+ # * a half whose tree is declared absent is not graded -- the owner
318
+ # stated there is no such lockfile to require, which is the narrower,
319
+ # honest verdict `resolve_inputs` documents ("grades a smaller scope");
320
+ # * with NEITHER half left there is nothing to grade, and an empty set of
321
+ # findings would read as a pass -- `CouldNotRun`, naming both inputs and
322
+ # trees;
323
+ # * a half-resolved Cargo triple is `CouldNotRun`, naming what is missing.
324
+ #
325
+ # This read `ctx.inputs["cargo_lock"]` and `["bun_lock"]` unguarded: a
326
+ # `KeyError` traceback (exit 1), not a verdict, whenever either tree was
327
+ # declared absent.
328
+ #
329
+ # A half the repository DECLARES (see the module docstring) is graded from
330
+ # its declaration and never from the tree or the inputs; the rules above
331
+ # apply to the halves it did not declare.
332
+ cargo_declared = self.declared(self.CARGO, ctx.declarations)
333
+ bun_declared = self.declared(self.BUN, ctx.declarations)
334
+
335
+ present_cargo = [name for name in self.CARGO_INPUTS if name in ctx.inputs]
336
+ if cargo_declared is None and present_cargo and len(present_cargo) != len(self.CARGO_INPUTS):
337
+ missing = [name for name in self.CARGO_INPUTS if name not in ctx.inputs]
338
+ raise CouldNotRun(
339
+ f"{self.id}: the Cargo inputs resolve together from <rust>, but only "
340
+ f"{present_cargo} are set; missing {missing} -- declare "
341
+ "[controls.compliance.trees].rust, or override all three"
111
342
  )
112
- return
113
343
 
114
- if self.state(ctx, bun_lock) is not FileState.PRESENT:
115
- shown = ctx.relative(bun_lock)
116
- typescript_dir = shown.rsplit("/", 1)[0] if "/" in shown else "."
117
- yield self.report(
118
- shown,
119
- f"missing {shown}",
120
- f"run: (cd {typescript_dir} && bun install) to generate the "
121
- "lockfile and commit the result",
122
- rule=self.MISSING,
344
+ # (lockfile, cargo workspace, manifest) per Cargo lockfile to grade.
345
+ cargo: list[tuple[Path, Path, Path]] = []
346
+ if cargo_declared is not None:
347
+ for relative in cargo_declared.lockfiles:
348
+ lock = ctx.path(relative)
349
+ cargo.append((lock, lock.parent, lock.parent / "Cargo.toml"))
350
+ elif "cargo_lock" in ctx.inputs:
351
+ cargo.append(
352
+ (ctx.inputs["cargo_lock"], ctx.inputs["workspace"], ctx.inputs["cargo_manifest"])
353
+ )
354
+
355
+ bun: list[Path] = []
356
+ if bun_declared is not None:
357
+ bun = [ctx.path(relative) for relative in bun_declared.lockfiles]
358
+ elif "bun_lock" in ctx.inputs:
359
+ bun = [ctx.inputs["bun_lock"]]
360
+
361
+ if not cargo and not bun:
362
+ raise CouldNotRun(
363
+ f"{self.id}: no lockfile to grade -- `cargo_lock` (<rust>/Cargo.lock) and "
364
+ "`bun_lock` (<typescript>/bun.lock) are both absent because the trees "
365
+ "<rust> and <typescript> are both declared absent in "
366
+ "[controls.compliance.trees]; a row that grades nothing is could-not-run, "
367
+ "never a clean pass"
123
368
  )
369
+
370
+ for lock, workspace, _manifest in cargo:
371
+ if self.state(ctx, lock) is not FileState.PRESENT:
372
+ shown = ctx.relative(lock)
373
+ yield self.report(
374
+ shown,
375
+ f"missing {shown}",
376
+ f"run: (cd {ctx.relative(workspace)} && "
377
+ "cargo generate-lockfile) and commit the result",
378
+ rule=self.MISSING,
379
+ )
380
+ return
381
+
382
+ for lock in bun:
383
+ if self.state(ctx, lock) is not FileState.PRESENT:
384
+ shown = ctx.relative(lock)
385
+ typescript_dir = shown.rsplit("/", 1)[0] if "/" in shown else "."
386
+ yield self.report(
387
+ shown,
388
+ f"missing {shown}",
389
+ f"run: (cd {typescript_dir} && bun install) to generate the "
390
+ "lockfile and commit the result",
391
+ rule=self.MISSING,
392
+ )
393
+ return
394
+
395
+ if not cargo:
396
+ # Rust declared absent: the TypeScript lockfile above was the whole row.
124
397
  return
125
398
 
126
399
  if shutil.which("cargo") is None:
@@ -129,39 +402,79 @@ class LockfileIntegrity(Check):
129
402
  "not a finding"
130
403
  )
131
404
 
132
- workspace = ctx.inputs["workspace"]
133
- version_check = subprocess.run(
134
- ["cargo", "--version"],
135
- cwd=workspace,
136
- capture_output=True,
137
- text=True,
138
- check=False,
139
- )
140
- if version_check.returncode != 0:
141
- raise CouldNotRun(
142
- f"repository.lockfile-integrity: cargo could not run in "
143
- f"{ctx.relative(workspace)}; tool failure, not a finding"
405
+ for lock, workspace, manifest in cargo:
406
+ version_check = subprocess.run(
407
+ ["cargo", "--version"],
408
+ cwd=workspace,
409
+ capture_output=True,
410
+ text=True,
411
+ check=False,
144
412
  )
413
+ if version_check.returncode != 0:
414
+ raise CouldNotRun(
415
+ f"repository.lockfile-integrity: cargo could not run in "
416
+ f"{ctx.relative(workspace)}; tool failure, not a finding"
417
+ )
145
418
 
146
- manifest = ctx.inputs["cargo_manifest"]
147
- metadata_run = subprocess.run(
148
- [
149
- "cargo", "metadata", "--locked", "--offline", "--no-deps",
150
- "--format-version", "1", "--manifest-path", str(manifest),
151
- ],
152
- cwd=workspace,
153
- capture_output=True,
154
- text=True,
155
- check=False,
156
- )
157
- if metadata_run.returncode != 0:
158
- lock_shown = ctx.relative(cargo_lock)
419
+ metadata_run = subprocess.run(
420
+ [
421
+ "cargo", "metadata", "--locked", "--offline", "--no-deps",
422
+ "--format-version", "1", "--manifest-path", str(manifest),
423
+ ],
424
+ cwd=workspace,
425
+ capture_output=True,
426
+ text=True,
427
+ check=False,
428
+ )
429
+ lock_shown = ctx.relative(lock)
159
430
  manifest_shown = ctx.relative(manifest)
160
- yield self.report(
161
- lock_shown,
162
- f"{lock_shown} does not satisfy {manifest_shown}",
431
+ remedy = (
163
432
  f"run: (cd {ctx.relative(workspace)} && cargo update) to "
164
433
  f"resync {lock_shown} with {manifest_shown}, then commit "
165
- "the result",
166
- rule=self.STALE,
434
+ "the result"
167
435
  )
436
+ if metadata_run.returncode != 0:
437
+ yield self.report(
438
+ lock_shown,
439
+ f"{lock_shown} does not satisfy {manifest_shown}",
440
+ remedy,
441
+ rule=self.STALE,
442
+ )
443
+ continue
444
+
445
+ # `--no-deps` never reads the lockfile (see the module docstring), so cargo
446
+ # accepting the manifest says nothing about the lock. The content is judged
447
+ # here, deterministically and without cargo; a lock this cannot judge is
448
+ # could-not-run, never a pass.
449
+ try:
450
+ problems = CargoLock(lock, manifest, ctx.relative).problems()
451
+ except Undecidable as exc:
452
+ raise CouldNotRun(f"{self.id}: cannot judge {lock_shown}: {exc}") from exc
453
+ for problem in problems:
454
+ yield self.report(lock_shown, problem, remedy, rule=self.STALE)
455
+
456
+ # ----------------------------------------------------------------- graded
457
+
458
+ def graded(self, ctx: Context, files: FileSet) -> Iterable[Report]:
459
+ """A declared manifest entry that matches no file is could-not-run.
460
+
461
+ `files` is the COMPLETE in-scope set here: a declared half restates the
462
+ row's scope, and a restated scope is graded whole (`Check.declared_scope`),
463
+ so "matches nothing" is a statement about the repository and not about
464
+ which files happened to change. Matched with the scope's own matcher.
465
+ """
466
+ paths = tuple(files)
467
+ for half in self.HALVES:
468
+ declared = self.declared(half, ctx.declarations)
469
+ if declared is None:
470
+ continue
471
+ for pattern in declared.manifests:
472
+ if not any(matches(pattern, path) for path in paths):
473
+ raise CouldNotRun(
474
+ f"{self.id}: declaration `{half.manifests}` names {pattern!r}, which "
475
+ "matches no file in the repository; fix "
476
+ f"[controls.compliance.lockfiles].{half.manifests.replace('-', '_')} "
477
+ "in adl-config.toml -- a declared manifest that is not there would "
478
+ "shrink what this gate scans to nothing and still read OK"
479
+ )
480
+ return ()
@@ -14,7 +14,7 @@ Ported here as two COMMITTED fixture directories built the identical way (see
14
14
  file for the exact commands that produced them), rather than reconstructed at
15
15
  test time — the same shift every other ported check.sh/test.sh pair in this
16
16
  package already made, and the one this task calls out `coverage.backend-ratchet`
17
- (`COV-002`) as its concrete precedent for.
17
+ (`COV-002`, retired 2026-10-01) as its concrete precedent for.
18
18
 
19
19
  A real Rust toolchain and a real `cargo` invocation are both required to prove
20
20
  the `LCK-002` branch (`cargo metadata --locked` rejecting a stale lock), but
@@ -100,7 +100,9 @@ def test_a_redeclared_rust_tree_is_honoured(tmp_path: Path) -> None:
100
100
  graded against `rust-workspace/Cargo.lock`, never the packaged default.
101
101
  """
102
102
  trees = effective_trees({"rust": "rust-workspace", "typescript": "ts-workspace"})
103
- verdict = runner.run(ROW, tmp_path, corpus_files(tmp_path), trees=trees)
103
+ # The subject here is an EMPTY tree: the lockfile is reported missing because
104
+ # nothing exists, so the empty corpus is opted into explicitly.
105
+ verdict = runner.run(ROW, tmp_path, corpus_files(tmp_path, allow_empty=True), trees=trees)
104
106
  assert verdict.outcome is Outcome.FINDINGS, verdict.render()
105
107
  assert len(verdict.findings) == 1
106
108
  finding = verdict.findings[0]