@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
@@ -22,12 +22,20 @@
22
22
  * integration/main/master/develop and HEAD are never deleted, the KEEP
23
23
  * most recent branches are kept, and only "[gone]" upstreams (-D) or
24
24
  * branches merged into the baseline (-d) are deleted;
25
- * 4. `adl install --repo <repo>` -- the existing per-repo enrolment.
25
+ * 4. the stale-branch prune (only when `branchMaxAgeDays` is configured, from
26
+ * the manifest's `config.repo_maintain.branch_max_age_days`): every local
27
+ * branch whose TIP commit is older than that many days is deleted with
28
+ * `git branch -D` -- never integration/main/master/develop, the checked-out
29
+ * HEAD, or a branch checked out in any worktree. Each deletion is a
30
+ * `WARN repo-maintain: <repo>: deleted stale branch <name> at <sha> (last
31
+ * commit <date>)` line, which is how a deleted branch is recovered from the
32
+ * log (`git branch <name> <sha>`); a dry run lists them without deleting;
33
+ * 5. `adl install --repo <repo>` -- the existing per-repo enrolment.
26
34
  *
27
35
  * This runs as the device administrator, never root (the caller,
28
36
  * bin/reconcile-host, drops privileges and `adl maintain --expect-user`
29
- * refuses otherwise). It never migrates enact-config.toml: a repo that has
30
- * both markers is a named failure.
37
+ * refuses otherwise). It never reads, migrates or modifies enact-config.toml:
38
+ * a repo may carry both markers, and adl-config.toml alone decides scope.
31
39
  *
32
40
  * Reporting: plain progress lines go to `out`; every warning and failure goes
33
41
  * to `err` as `WARN repo-maintain: ...` / `ERROR repo-maintain: ...` (the
@@ -42,9 +50,7 @@ import { NO_AGENT_IDENTITY_MESSAGE, resolveAgentIdentity } from '../../azdo/src/
42
50
  export const TCC_DENIED_MARKER = 'TCC denied'
43
51
 
44
52
  /** The file whose presence puts a repository in this step's scope. */
45
- export const MARKER = 'adl-config.toml'
46
- /** The retired marker; a repo with both is ambiguous and fails loud. */
47
- const LEGACY_MARKER = 'enact-config.toml'
53
+ const MARKER = 'adl-config.toml'
48
54
 
49
55
  /** Branches fast-forwarded, in this order. */
50
56
  const SYNCED_BRANCHES = ['integration', 'main'] as const
@@ -65,6 +71,14 @@ export interface MaintainOptions {
65
71
  readonly keep?: number
66
72
  /** Report only: fetches, but never moves a ref, deletes a branch or runs install. */
67
73
  readonly dryRun?: boolean
74
+ /**
75
+ * Delete local branches whose tip commit is older than this many days (a
76
+ * positive whole number). Unset: no age-based deletion. The manifest's
77
+ * `config.repo_maintain.branch_max_age_days`, never an environment variable.
78
+ */
79
+ readonly branchMaxAgeDays?: number
80
+ /** The clock, injectable for tests. Default: the current time. */
81
+ readonly now?: () => Date
68
82
  /** Environment for identity resolution and every child. Default process.env. */
69
83
  readonly env?: NodeJS.ProcessEnv
70
84
  readonly out?: (line: string) => void
@@ -87,15 +101,18 @@ export function listFailureLines(root: string, error: unknown, executable: strin
87
101
  const code = (error as { code?: unknown } | null)?.code
88
102
  if (code === 'ENOTDIR') return [`${root}: ${message}`]
89
103
  const lines = [`${root}: cannot list: ${message}`]
90
- if (code === 'EPERM') {
91
- lines.push(
92
- `${root}: ${TCC_DENIED_MARKER}: macOS privacy protection blocked ${executable}; ` +
93
- `one-time fix: System Settings › Privacy & Security › Full Disk Access › + › add ${executable}`,
94
- )
95
- }
104
+ if (code === 'EPERM') lines.push(tccDeniedLine(root, executable))
96
105
  return lines
97
106
  }
98
107
 
108
+ /** The one Full Disk Access hint, for a refused readdir and for a git child refused the same way. */
109
+ function tccDeniedLine(path: string, executable: string): string {
110
+ return (
111
+ `${path}: ${TCC_DENIED_MARKER}: macOS privacy protection blocked ${executable}; ` +
112
+ `one-time fix: System Settings › Privacy & Security › Full Disk Access › + › add ${executable}`
113
+ )
114
+ }
115
+
99
116
  interface GitResult {
100
117
  readonly ok: boolean
101
118
  readonly stdout: string
@@ -120,29 +137,6 @@ function isForbiddenAzurePipelinesPath(path: string): boolean {
120
137
  }
121
138
  }
122
139
 
123
- /** `packages/<name>/enact-config.toml` -- the per-package copies of the retired marker. */
124
- function legacyMarkers(repo: string): string[] {
125
- const found: string[] = []
126
- const tryStat = (relative: string): void => {
127
- try {
128
- if (statSync(join(repo, relative)).isFile()) found.push(relative)
129
- } catch (error) {
130
- if (errorCode(error) !== 'ENOENT' && errorCode(error) !== 'ENOTDIR') throw error
131
- }
132
- }
133
- tryStat(LEGACY_MARKER)
134
- let packages: Dirent[] = []
135
- try {
136
- packages = readdirSync(join(repo, 'packages'), { withFileTypes: true })
137
- } catch (error) {
138
- if (errorCode(error) !== 'ENOENT' && errorCode(error) !== 'ENOTDIR') throw error
139
- }
140
- for (const entry of packages.sort((a, b) => a.name.localeCompare(b.name))) {
141
- if (entry.isDirectory()) tryStat(join('packages', entry.name, LEGACY_MARKER))
142
- }
143
- return found
144
- }
145
-
146
140
  export function maintainRepositories(options: MaintainOptions): MaintainResult {
147
141
  const env = options.env ?? process.env
148
142
  const keep = options.keep ?? DEFAULT_KEEP
@@ -165,6 +159,13 @@ export function maintainRepositories(options: MaintainOptions): MaintainResult {
165
159
  return { ok: result.status === 0, stdout: result.stdout, stderr: result.stderr ?? '' }
166
160
  }
167
161
 
162
+ const maxAgeDays = options.branchMaxAgeDays
163
+ if (maxAgeDays !== undefined && (!Number.isInteger(maxAgeDays) || maxAgeDays < 1)) {
164
+ fail(`branch max age must be a positive whole number of days: ${maxAgeDays}`, 'branch-max-age-days')
165
+ return { ok: false, repositories: 0, failures }
166
+ }
167
+ const now = options.now ?? ((): Date => new Date())
168
+
168
169
  const { location } = options
169
170
  if (!isAbsolute(location)) {
170
171
  fail(`location must be an absolute path: ${location}`, location)
@@ -196,7 +197,7 @@ export function maintainRepositories(options: MaintainOptions): MaintainResult {
196
197
  }
197
198
  if (agent !== undefined) identityEnv = { ADL_AGENT_ID_AGENT: agent }
198
199
 
199
- info(`start location=${location} keep=${keep} dry=${dry ? 1 : 0}`)
200
+ info(`start location=${location} keep=${keep} dry=${dry ? 1 : 0}${maxAgeDays === undefined ? '' : ` branch_max_age_days=${maxAgeDays}`}`)
200
201
 
201
202
  let entries: Dirent[]
202
203
  let locationReal: string
@@ -242,19 +243,10 @@ export function maintainRepositories(options: MaintainOptions): MaintainResult {
242
243
  }
243
244
  seen.add(real)
244
245
 
245
- // 3. In scope from here on.
246
- let legacy: string[]
247
- try {
248
- legacy = legacyMarkers(real)
249
- } catch (error) {
250
- fail(`${real}: cannot read: ${error instanceof Error ? error.message : String(error)}`, real)
251
- continue
252
- }
253
- if (legacy.length > 0) {
254
- fail(`${real}: duplicate markers: ${MARKER} and ${LEGACY_MARKER} (${legacy.join(', ')}); migrate or remove one`, real)
255
- continue
256
- }
257
- if (!isGitToplevel(real)) {
246
+ // 3. In scope from here on. enact-config.toml may sit beside the marker; it is never read.
247
+ const toplevel = gitToplevelState(real)
248
+ if (toplevel === 'failed') continue
249
+ if (toplevel === 'not-toplevel') {
258
250
  warn(`${real}: ${MARKER} but not a git top-level; skipped`)
259
251
  continue
260
252
  }
@@ -265,13 +257,33 @@ export function maintainRepositories(options: MaintainOptions): MaintainResult {
265
257
  info(`done (${repositories} repositories, ${failures.length} failed)`)
266
258
  return { ok: failures.length === 0, repositories, failures }
267
259
 
268
- function isGitToplevel(directory: string): boolean {
260
+ /**
261
+ * 'not-toplevel' only on git's own "not a git repository" answer (exit 128) or
262
+ * a toplevel that is a different directory. Anything else (spawn error, other
263
+ * exit status, unresolvable toplevel) is reported here as a failure naming the
264
+ * directory, and the repo is not maintained: it may hide an in-scope repository.
265
+ */
266
+ function gitToplevelState(directory: string): 'toplevel' | 'not-toplevel' | 'failed' {
267
+ const command = 'git rev-parse --show-toplevel'
269
268
  const top = spawnSync('git', ['-C', directory, 'rev-parse', '--show-toplevel'], { encoding: 'utf8', env: childEnv() })
270
- if (top.error !== undefined || top.status !== 0) return false
269
+ if (top.error !== undefined) {
270
+ fail(`${directory}: cannot run ${command}: ${top.error.message}`, directory)
271
+ return 'failed'
272
+ }
273
+ const stderr = (top.stderr ?? '').trim()
274
+ if (top.status === 128 && stderr.includes('not a git repository')) return 'not-toplevel'
275
+ if (top.status !== 0) {
276
+ const shown = stderr.split('\n').slice(0, 3).join(' | ')
277
+ fail(`${directory}: ${command} exited ${top.status ?? `by signal ${top.signal}`}: ${shown}`, directory)
278
+ // git's "Operation not permitted" is TCC refusing the files to this job's responsible process (adl).
279
+ if (stderr.includes('Operation not permitted')) errOut(`ERROR repo-maintain: ${tccDeniedLine(directory, options.executable)}`)
280
+ return 'failed'
281
+ }
271
282
  try {
272
- return realpathSync(top.stdout.trim()) === directory
273
- } catch {
274
- return false
283
+ return realpathSync(top.stdout.trim()) === directory ? 'toplevel' : 'not-toplevel'
284
+ } catch (error) {
285
+ fail(`${directory}: cannot resolve git toplevel ${top.stdout.trim()}: ${error instanceof Error ? error.message : String(error)}`, directory)
286
+ return 'failed'
275
287
  }
276
288
  }
277
289
 
@@ -312,7 +324,10 @@ export function maintainRepositories(options: MaintainOptions): MaintainResult {
312
324
  // 3. guarded prune.
313
325
  prune(repo, name, current)
314
326
 
315
- // 4. the per-repo enrolment.
327
+ // 4. stale-branch prune: by the tip commit's age.
328
+ if (maxAgeDays !== undefined) pruneStale(repo, name, current, maxAgeDays)
329
+
330
+ // 5. the per-repo enrolment.
316
331
  const argv = [...options.install.leadingArgs, 'install', '--repo', repo]
317
332
  const shown = `adl install --repo ${repo}`
318
333
  if (dry) {
@@ -368,6 +383,27 @@ export function maintainRepositories(options: MaintainOptions): MaintainResult {
368
383
  }
369
384
  }
370
385
 
386
+ function pruneStale(repo: string, name: string, current: string, days: number): void {
387
+ const cutoff = now().getTime() / 1000 - days * 86_400
388
+ // %1f (unit separator) cannot appear in a ref name, unlike `|`.
389
+ const format = '%(refname:short)%1f%(objectname)%1f%(committerdate:unix)%1f%(worktreepath)'
390
+ for (const line of lines(git(repo, 'for-each-ref', 'refs/heads/', `--format=${format}`).stdout)) {
391
+ const [branch = '', sha = '', committed = '', worktree = ''] = line.split('\x1f')
392
+ if (branch === '' || PROTECTED.has(branch) || branch === current) continue
393
+ const tip = Number(committed)
394
+ if (!Number.isFinite(tip) || tip >= cutoff) continue
395
+ // A branch checked out in any worktree (the main one included) is in use.
396
+ if (worktree !== '') {
397
+ info(`${name}: kept stale branch ${branch} (checked out in ${worktree})`)
398
+ continue
399
+ }
400
+ const described = `stale branch ${branch} at ${sha} (last commit ${new Date(tip * 1000).toISOString().slice(0, 10)})`
401
+ if (dry) info(`${name}: [dry] would delete ${described}`)
402
+ else if (git(repo, 'branch', '-D', branch).ok) warn(`${name}: deleted ${described}`)
403
+ else warn(`${name}: could not delete ${described}`)
404
+ }
405
+ }
406
+
371
407
  function prune(repo: string, name: string, current: string): void {
372
408
  const base = baselineFor(repo)
373
409
  const keptRecent = new Set(
@@ -34,12 +34,12 @@ import { defaultAgentFilePath, type FleetPlatform } from './default-agent-file.t
34
34
  // apps/cli/src/commands/mcp.ts's own cross-package import of packages/azdo:
35
35
  // this workspace has no node_modules/@adl/* symlinks without `bun install`.
36
36
  // packages/azdo/src/lib/agent-identity.ts is now THE one place the
37
- // default-agent file is READ from (STATUS.md 12p,
38
- // W1); this package's own default-agent-file.ts keeps only the WRITE side
39
- // (`reconcileDefaultAgentFile`) plus the path computation both sides need.
37
+ // default-agent file is READ from; this package's own default-agent-file.ts
38
+ // keeps only the WRITE side (`reconcileDefaultAgentFile`) plus the path
39
+ // computation both sides need.
40
40
  import { NO_AGENT_IDENTITY_MESSAGE, resolveAgentIdentity } from '../../azdo/src/lib/agent-identity.ts'
41
41
 
42
- export type Mode = 'plan' | 'apply'
42
+ type Mode = 'plan' | 'apply'
43
43
 
44
44
  export type GitResult = { ok: boolean; stdout: string; stderr: string }
45
45
  export type Git = (args: string[], cwd: string) => GitResult
@@ -530,7 +530,7 @@ function usage(): never {
530
530
  process.exit(2)
531
531
  }
532
532
 
533
- export function main(argv: string[]): number {
533
+ function main(argv: string[]): number {
534
534
  const repos: string[] = []
535
535
  let mode: Mode = 'plan'
536
536
  let idleDays = 1
@@ -21,7 +21,7 @@
21
21
  * format and default/named-profile directory shape, under its own
22
22
  * `Application Support`/`.config` folder name (`Cursor` instead of `Code`) —
23
23
  * this is the standard, well-known Cursor Application Support location
24
- * (docs/operations/research-2026-09-27-worktree-controls-per-surface.md confirms
24
+ * (docs/research/research-2026-09-27-worktree-controls-per-surface.md confirms
25
25
  * `~/.cursor/worktrees/<repo>/` for worktree storage and that
26
26
  * `cursor.worktreeMaxCount` lives in "the regular Cursor settings.json (user
27
27
  * or workspace scope, VS Code-style)", but does not separately spell out the
@@ -51,14 +51,14 @@ import { basename, dirname, isAbsolute, join } from 'node:path'
51
51
  export type VscodePlatform = 'mac' | 'linux'
52
52
 
53
53
  /** A managed setting's value: VS Code's two owned keys are boolean; Cursor's `worktreeMaxCount` is numeric. */
54
- export type SettingValue = boolean | number
54
+ type SettingValue = boolean | number
55
55
 
56
56
  export const REQUIRED_VSCODE_SETTINGS = {
57
57
  'git.detectWorktrees': true,
58
58
  'scm.alwaysShowRepositories': true,
59
59
  } as const
60
60
 
61
- export const APPLY_TO_ALL_PROFILES_SETTING = 'workbench.settings.applyToAllProfiles'
61
+ const APPLY_TO_ALL_PROFILES_SETTING = 'workbench.settings.applyToAllProfiles'
62
62
 
63
63
  /**
64
64
  * `cursor.worktreeMaxCount` — docs/operations/worktree-guard.md L0. Deployed as a
@@ -75,7 +75,7 @@ export const REQUIRED_CURSOR_SETTINGS = {
75
75
  'cursor.worktreeMaxCount': 3,
76
76
  } as const
77
77
 
78
- export interface EditorSettingsSpec {
78
+ interface EditorSettingsSpec {
79
79
  readonly requiredSettings: Readonly<Record<string, SettingValue>>
80
80
  /** VS Code only: the setting id that collects a profile-wide apply-to-all list. Omit for editors with no confirmed equivalent (Cursor). */
81
81
  readonly applyToAllProfilesSetting?: string
@@ -90,7 +90,7 @@ const CURSOR_SPEC: EditorSettingsSpec = {
90
90
  requiredSettings: REQUIRED_CURSOR_SETTINGS,
91
91
  }
92
92
 
93
- export interface VscodeSettingsFileResult {
93
+ interface VscodeSettingsFileResult {
94
94
  readonly path: string
95
95
  readonly changed: boolean
96
96
  readonly missing: boolean
@@ -16,7 +16,8 @@ target repo (committed) adl (fleet-installed; see below)
16
16
  .workflows/hooks/commit-msg ├─ sh stub ──▶ ├─ validates adl-config.toml [controls]
17
17
  .workflows/hooks/pre-push │ exec ├─ checks bash >= 4
18
18
  .workflows/hooks/post-commit │ └─ runs scripts/hooks/<name>
19
- .workflows/hooks/post-checkout ─┘
19
+ .workflows/hooks/post-checkout │
20
+ .workflows/hooks/post-merge ─┘
20
21
  adl-config.toml [controls] (config, shared file — see below) (package-owned script, config via env)
21
22
  .workflows/repo-controls.lock.json (hashes)
22
23
  local .git/config: core.hooksPath = .workflows/hooks
@@ -25,9 +26,9 @@ local .git/config: core.hooksPath = .workflows/hooks
25
26
  - **Stubs** are POSIX `sh`, contain no paths, and fail loudly (with the install
26
27
  command) when `adl` is not on `PATH` — never a silent skip. This package is
27
28
  folded into the `adl` binary's `repo controls` namespace
28
- (docs/architecture/cli-design.md §6, STATUS.md item 10); it is never itself a
29
+ (docs/architecture/cli-design.md §6); it is never itself a
29
30
  standalone global command — hard cut, no `adl-repo-controls` compat shim
30
- (adl-m3-finish item 1, 2026-09-27).
31
+ (2026-09-27).
31
32
  - **Bundled scripts** in `scripts/hooks/` are package-owned implementations.
32
33
  They originated in enact-m5; commit `20ec790` removed the former byte-copy
33
34
  tree and manifest when mechanism moved into this package. Their current
@@ -77,6 +78,53 @@ a release-configured pre-commit commits successfully with no network-capable
77
78
  binary on `PATH` at all, and pre-push blocks by name when the token mint
78
79
  fails and permits the push once it succeeds.
79
80
 
81
+ ## Git LFS chaining (`pre-push`, `post-checkout`, `post-commit`, `post-merge`)
82
+
83
+ Installed repositories set `core.hooksPath=.workflows/hooks`, so git never runs
84
+ the `.git/hooks/{pre-push,post-checkout,post-commit,post-merge}` that
85
+ `git lfs install` writes. Before 2026-10-01 nothing in adl called git-lfs, so a
86
+ push of a commit carrying an LFS pointer succeeded **without uploading the
87
+ object** and left a broken pointer on the remote (live, enact-combined: a
88
+ broken WebM pointer had to be deleted by hand). `runHook` (`src/hook.ts`) now
89
+ chains each of those four hooks to `git lfs <hook> "$@"` (`src/lfs.ts`):
90
+
91
+ - **Only when the repository uses LFS:** a `filter=lfs` attribute in any
92
+ `.gitattributes` (tracked or untracked, nested included) or in
93
+ `.git/info/attributes`, a `.lfsconfig`, or `lfs.*` in the repository's own git
94
+ config. A repository without LFS never calls `git lfs`.
95
+ - **Fail loud, never skip:** LFS in use and no `git-lfs` on `PATH` is a hard
96
+ failure with the install command in the message; a failing `git lfs <hook>`
97
+ fails the hook (for `pre-push`, the push). A FAIL row is also written to the
98
+ hook log, because the bundled script has already logged its PASS by then.
99
+ - **`pre-push` order and stdin:** git writes the pushed ref lines once. `runHook`
100
+ reads them once and feeds the same bytes to the bundled script (branch rules)
101
+ and to `git lfs pre-push`. The LFS upload is the LAST step, after every adl
102
+ check passed, so a refused push uploads nothing. `post-merge` is a new hook
103
+ (`HOOK_NAMES`) whose only job is this chain; `doctor` therefore reports
104
+ `hook:post-merge`, and an already-installed repository needs `adl repo
105
+ controls install --repo .` once to project the stub.
106
+ - **Credentials — one boundary, no second path.** `bin/git-ado` authenticates an
107
+ agent's `git push` by exporting `GIT_CONFIG_COUNT` and a
108
+ `GIT_CONFIG_KEY_n=http.https://<host>/.extraHeader` /
109
+ `GIT_CONFIG_VALUE_n=Authorization: Bearer <token>` pair (`bin/git-ado`, the
110
+ two `exec env ... GIT_CONFIG_COUNT=` blocks); git passes its environment to
111
+ the hook. `runBundled` strips every `GIT_CONFIG_*` (`childEnv`) so adl's own
112
+ checks never hold the token, which is why the chain is TypeScript and not
113
+ bash: `runHook` still has the unstripped environment, and the one
114
+ `git lfs` spawn (`spawnGitLfs`) is the only child given it. git-lfs therefore
115
+ authenticates with exactly the pairs the parent `git push` had: same
116
+ mechanism, no second token mint, never the human's credential helper.
117
+ `tests/lfs-credential-boundary.test.ts` is the proof (real git-lfs, a local
118
+ LFS endpoint that requires the Bearer token and answers 401 otherwise, a
119
+ credential helper that records every call): every request carried the header,
120
+ the helper was never called, and with the header absent the helper IS called
121
+ (the control that makes the first claim falsifiable).
122
+ - **Explicit `git lfs push|pull|fetch` for agents** was refused in `bin/git-ado`
123
+ until that proof existed; it now takes the ordinary agent path. The refusal
124
+ must come back if `lfs-credential-boundary.test.ts` ever goes red. No agent-hooks
125
+ rule mentions LFS, so `git push` -> hook -> `git lfs pre-push` is not a
126
+ command an agent types and is not intercepted by any rule.
127
+
80
128
  ## Worktree-count backstop (`post-checkout`)
81
129
 
82
130
  `MAX_WORKTREES` (`src/constants.ts`) is `3` — a repository may have at most 3
@@ -144,7 +192,7 @@ or a `Task`/`Agent` launch with `isolation: "worktree"`) — see
144
192
 
145
193
  ### Why bun (and not node)
146
194
 
147
- This package is never distributed standalone (adl-m3-finish item 1/2, 2026-09-27):
195
+ This package is never distributed standalone (since 2026-09-27):
148
196
  `adl repo controls <command>` folds it into the one `adl` binary
149
197
  (docs/architecture/cli-design.md §6), which the fleet installs via `bin/reconcile`'s
150
198
  `bun-compile` manager; `apps/cli/src/commands/repo-controls.ts` resolves this
@@ -186,7 +234,7 @@ centralization are documented in
186
234
  adl-repo-controls install --repo <path> [--dry-run]
187
235
  adl-repo-controls uninstall --repo <path> [--dry-run]
188
236
  adl-repo-controls doctor --repo <path> [--json]
189
- adl-repo-controls hook <pre-commit|commit-msg|pre-push|post-commit> [git hook args]
237
+ adl-repo-controls hook <pre-commit|commit-msg|pre-push|post-commit|post-checkout|post-merge> [git hook args]
190
238
  adl-repo-controls log <hook-name> <reason> [context] [message] (internal — called by the bundled hooks)
191
239
  adl-repo-controls promote --repo <path>
192
240
  adl-repo-controls run <azdo-push|coverage|repo-hygiene|validate-pr-metadata> --repo <path> [-- args]
@@ -229,21 +277,56 @@ merge into `integration`) runs.
229
277
  **doctor** is read-only and exits 1 on any failure: bash >= 4, bun, binary on
230
278
  PATH, the bundled compliance package present at its packaged path, repository
231
279
  root, `[controls]` config validity, (warning) `coverage/coverage-summary.json`
232
- exists whenever `pre_push.coverage_ratchet` is enabled, `[controls.compliance]` config
233
- validity, `uv` on PATH (only checked once `[controls.compliance].enabled` is non-empty;
234
- otherwise reported ok unconditionally, same off-by-default posture as the
235
- coverage-summary check), (warning only, same conditioning) `ast-grep` on PATH,
236
- lock, each stub (present, unedited, executable), `core.hooksPath`, `.gitignore`
237
- lines, and (warning) lock version skew. When `[controls.release]` is declared,
238
- it also derives the configured `origin` remote, loads the validated canonical
239
- Agent Vault file before reading Azure DevOps, and records separate fail-closed receipts for the HTTPS handle,
240
- required owner reviewer, minimum-review reset, and (only when one is present) build policy.
280
+ exists whenever `pre_push.coverage_ratchet` is enabled (`coverage_ratchet`
281
+ defaults ON; the gate is a no-op until the file lands, so this is informational
282
+ rather than blocking), (warning) `pre_push.coverage_produce` enabled with no
283
+ `[controls.coverage].produce_push` declared (the push gate fails loud there, so
284
+ doctor names it first), `[controls.compliance]` config validity, `uv` on PATH
285
+ (only checked once `[controls.compliance].enabled` is non-empty; otherwise
286
+ reported ok unconditionally, same on-by-default posture as the coverage-summary
287
+ check), (warning only, same conditioning) `ast-grep` on PATH, lock, each stub
288
+ (present, unedited, executable), `core.hooksPath`, `.gitignore` lines, and
289
+ (warning) lock version skew. When `[controls.release]` is declared, it also
290
+ derives the configured `origin` remote, loads the validated canonical Agent
291
+ Vault file before reading Azure DevOps, and records separate fail-closed
292
+ receipts for the HTTPS handle, required owner reviewer, minimum-review reset,
293
+ and (only when one is present) build policy.
241
294
 
242
295
  **run** executes a bundled enact-m5 tool against the repository with the config
243
296
  exported: `azdo-push` (Azure DevOps push with push lock + behind-origin refusal),
244
297
  `coverage <check-push|prewarm-push|status|unlock|...>`, `repo-hygiene` (CI
245
298
  entrypoint), `validate-pr-metadata` (Azure PR title/description policy).
246
299
 
300
+ #### azdo-push: one credential boundary
301
+
302
+ `azdo-push` mints and injects **no credential** (Tarun, 2026-10-01). Its git
303
+ children run through the managed front controller (`/usr/local/bin/git` ->
304
+ `bin/git-ado`), the only place a token is minted and a header added. What
305
+ `azdo-push` does contribute is `ADL_AGENT_ID_AGENT=<resolved agent>` on every
306
+ git spawn (so the controller mints for the right agent) and the removal of any
307
+ inherited `ADL_HUMAN_AZDO`. It refuses, before any network call, when no agent
308
+ identity resolves, and when the `git` on `PATH` does not carry the
309
+ `# Managed by adl global-tools.` marker (a plain git would fall to the human
310
+ credential helper).
311
+
312
+ **Verify on the wire** that a request carries exactly one `Authorization`
313
+ header. Git redacts the value by default (`GIT_TRACE_REDACT`, on unless set to
314
+ `0` -- never set it), so the trace is safe to read and to paste:
315
+
316
+ ```
317
+ GIT_TRACE_CURL=1 GIT_TRACE_CURL_NO_DATA=1 git ls-remote origin HEAD 2>&1 \
318
+ | rg '=> Send header: (GET|POST|Authorization)'
319
+ ```
320
+
321
+ Expect each `GET`/`POST` line to be followed by exactly one
322
+ `=> Send header: Authorization: Bearer <redacted>` line. Count them with
323
+ `... | rg -c '=> Send header: Authorization'` -- 1 for the single request of
324
+ `ls-remote`. Two per request means a second credential path is back (the old
325
+ behaviour was a global `http.extraheader` from `azdo-push` plus git-ado's own
326
+ URL-scoped header). `ls-remote` is read-only; to trace the push path itself, run
327
+ `GIT_TRACE_CURL=1 GIT_TRACE_CURL_NO_DATA=1 adl repo controls azdo-push` on a
328
+ branch you mean to push.
329
+
247
330
  **run compliance** runs the bundled `adl-compliance` Python engine (via `uv`)
248
331
  against the repository. `--root <repo>` is always injected first from `--repo`;
249
332
  once `[controls.compliance].enabled` is non-empty, `--only <the enabled list, comma-joined>`
@@ -285,41 +368,47 @@ an inline table is one attribute, because editing inside one means rewriting byt
285
368
  you own. Nothing is parsed and re-serialized; text is spliced into the table's span.
286
369
 
287
370
  `[controls]` is strictly validated: unknown keys and wrong types are errors. An
288
- **absent** optional key is its documented default, never an error.
371
+ **absent** key takes its documented default, never an error. Most gates default
372
+ ON; the matching `[controls.<gate>]` keys are what configure them. A gate whose
373
+ wrapper is ON but whose configuration is missing is a no-op at hook time and a
374
+ *warning* at `doctor` time — informational, never blocking.
289
375
 
290
376
  | Key | Seeded by install | Default when absent | enact-m5 | Effect |
291
377
  |---|---|---|---|---|
292
378
  | `branches.protected` | yes | *required* | `["main", "integration"]` | pre-push refuses while on these branches |
293
379
  | `branches.prefixes` | yes | *required* | `["feat", "fix", "docs", "chore"]` | pre-push / azdo-push branch pattern `<prefix>/<kebab>` |
294
380
  | `pre_push.remote` | yes | *required* | `"origin"` | remote azdo-push pushes to and reads status from |
295
- | `pre_commit.biome` | no | `false` | `true` | Biome format+lint on the staged index snapshot |
296
- | `pre_commit.staged_coverage` | no | `false` | `true` | enact-m5-only staged coverage measurement |
297
- | `pre_commit.doc_freshness` | no | `false` | opt in | a staged `docs/` or `plans/` `.md` carries a `last_update` stamped within 5h |
298
- | `pre_push.coverage_ratchet` | no | `false` | `true` | per outgoing commit, `coverage/coverage-summary.json` must exist and not regress |
299
- | `pre_push.findings_ratchet` | no | `false` | opt in | per outgoing commit, every declared static-analysis counter's findings must not exceed the committed floor |
381
+ | `pre_commit.staged_coverage` | no | `true` | `true` | enact-m5-only staged coverage measurement (no-op until `[controls.coverage].produce` is declared) |
382
+ | `pre_commit.doc_freshness` | no | `true` | opt in | a staged `docs/` or `plans/` `.md` carries a `last_update` stamped within 5h (no-op when no docs are staged) |
383
+ | `pre_commit.compliance` | no | `true` | `true` | staged adl-compliance gates (no-op until `[controls.compliance].enabled` is non-empty) |
384
+ | `pre_push.coverage_ratchet` | no | `true` | `true` | per outgoing commit, `coverage/coverage-summary.json` must exist and not regress (no-op until the file lands) |
385
+ | `pre_push.coverage_produce` | no | `false` | opt in | run the coverage MEASUREMENT at push via `[controls.coverage].produce_push` (fails the push when armed with no command declared) |
386
+ | `pre_push.findings_ratchet` | no | `true` | opt in | per outgoing commit, every declared static-analysis counter's findings must not exceed the committed floor (no-op until `[controls.findings].counters` is declared and the floor file lands) |
300
387
  | `pre_push.static_checks` | no | `[]` | tsc, knip, svelte-check | `{ label, run }` commands run on an export of HEAD, pass cached per tree OID |
301
388
  | `release.source` | no | `""` | `"integration"` | source branch for the managed promotion PR; no branch pair is guessed |
302
389
  | `release.target` | no | `""` | `"main"` | target branch for the managed promotion PR |
303
390
  | `release.merge_strategy` | no | `"squash"` | `"no-fast-forward"` | one of `squash`, `rebase`, `rebase-merge`, or `no-fast-forward` — sent to Azure DevOps as the matching wire value (`squash`, `rebase`, `rebaseMerge`, `noFastForward`) |
304
- | `release.pre_bump` | no | `[]` | — | ordered, repository-relative script paths `version-bump.sh` runs from the repo root before the bump commit (the CI pipeline's Bump stage, on the PR's source branch) |
305
-
306
- ### Release scripts — Bump and Guard (Tarun, 2026-09-30)
307
-
308
- One clean hard cutover to three pipelines (CI on PRs into `integration`,
309
- Promote on `integration`, CD on `main`; `docs/architecture/cli-design.md` §6a).
310
- Two managed scripts run in the CI pipeline, and neither ever pushes to
311
- `integration`:
312
-
313
- - **`.workflows/version-bump.sh --file package.json --pr-source <source> --base
314
- integration --push`** (Bump stage) sets the PR's SOURCE branch to
315
- `integration`'s version + 1 patch, running `release.pre_bump` scripts in the
316
- same commit, and pushes it (a plain push as the build service, never an
317
- agent identity, never force). It refuses a source that does not contain
318
- `integration`'s tip. The old `--integration` mode is gone: it is an unknown
319
- argument.
320
- - **`.workflows/reconcile-guard.sh`** (Guard stage) fails, printing the
321
- reconcile command (`git pull origin integration && git push`), unless the
322
- source contains `integration`'s tip and is at `integration` + 1.
391
+ | `release.pre_bump` | no | `[]` | — | ordered, repository-relative script paths `version-bump.sh` runs from the repo root before the bump commit (the Promote pipeline's Bump stage, on the checkout of the `integration` commit that triggered it) |
392
+
393
+ ### Release scripts — Guard and Bump (Tarun, 2026-09-30; bump moved 2026-10-01)
394
+
395
+ Three pipelines (CI on PRs into `integration`, Promote on `integration`, CD on
396
+ `main`; `docs/architecture/cli-design.md` §6a). Two managed scripts:
397
+
398
+ - **`.workflows/reconcile-guard.sh --pr-source <source> --base integration`**
399
+ (CI pipeline, Guard stage) is read-only and fails, printing the reconcile
400
+ command (`git pull origin integration, then push`), unless the source
401
+ contains `integration`'s tip. It checks no version: PR CI bumps nothing,
402
+ because a PR's build-validation policy ignores `[skip ci]`.
403
+ - **`.workflows/version-bump.sh --file package.json --integration --push`**
404
+ (Promote pipeline, Bump stage) sets the manifest to the checked-out
405
+ `integration` commit's version + 1 patch, runs `release.pre_bump` scripts in
406
+ the same commit, commits `chore: bump version A to B [skip ci]` and pushes
407
+ `HEAD:refs/heads/integration` (a plain fast-forward as the build service,
408
+ which needs Contribute and "Bypass policies when pushing" there; never an
409
+ agent identity, never force). If `integration` moved since the checkout the
410
+ push is rejected and the script fails loud; the next merge's run bumps. The
411
+ old `--pr-source` mode is gone: it is an unknown argument.
323
412
 
324
413
  ### `release.pre_bump` — multi-language version bumps
325
414
 
@@ -395,10 +484,9 @@ sed -i.bak -E "s/^const Version = \".*\"/const Version = \"${ADL_NEXT_VERSION}\"
395
484
  rm -f "${file}.bak"
396
485
  ```
397
486
 
398
- `install` copies four package-owned standalone CI assets byte-for-byte:
487
+ `install` copies three package-owned standalone CI assets byte-for-byte:
399
488
 
400
489
  - `.workflows/promote.ts`
401
- - `.workflows/scripts/enable-integration-auto-complete.mjs`
402
490
  - `.workflows/version-bump.sh`
403
491
  - `.workflows/reconcile-guard.sh`
404
492
 
@@ -469,6 +557,13 @@ Note: with `coverage_ratchet = true` every pushed commit and its parent must
469
557
  contain `coverage/coverage-summary.json` (Istanbul json-summary); commit a
470
558
  baseline first or set it to `false`.
471
559
 
560
+ Note: with `coverage_produce = true` the coverage MEASUREMENT runs at push too,
561
+ through `[controls.coverage].produce_push` — measurement at push, grading at
562
+ push, so commits stay fast. `produce_push` is the push-appropriate command: it
563
+ runs against immutable HEAD before the push, so a check-mode run that never
564
+ mutates the index is the shape. Armed with no command declared, the gate fails
565
+ the push by name — a step that measures nothing is not a pass.
566
+
472
567
  Note: with `findings_ratchet = true`, `[controls.findings]` says where the
473
568
  floor lives (`floor`, default `compliance/ratchets/static-analysis-findings.yaml`)
474
569
  and `[controls.findings.counters]` names the repository's own static-analysis
@@ -512,6 +607,9 @@ non-empty string.
512
607
  | `enabled` | `[]` | gate ids (`RST-001`) or `domain.name` addresses (`rust.acp-boundary`) to grade; empty = installed, nothing runs |
513
608
  | `registry` | `"default"` | forward-compatible; today both values point at the same packaged registry YAML |
514
609
  | `[controls.compliance.trees]` | `{}` (no entries) | per-key path overrides; a key absent here keeps the packaged (source-shaped) default for that key |
610
+ | `[controls.compliance.limits]` | absent (engine defaults) | per-repository engine limits, strictly validated. `scripts_direct_files` (positive integer) replaces LAY-014's default of 15 direct files per scripts directory and reaches the engine as `--declare scripts-direct-files=N`; a value the engine cannot read as a positive integer is could-not-run, never a fall back to 15. The depth limit is not configurable. `open_gaps` and `open_plans` (each a positive integer) replace LAY-016's default cap of 10 open gaps and 10 open plans, independently, and reach the engine as `--declare open-gaps=N` / `--declare open-plans=N`; the same could-not-run rule applies to each, and a finding names the effective cap as `N open gaps, cap is M`. The engine default stays 10: a repository declares today's measured count and ratchets it down |
611
+ | `[controls.compliance.markdown]` | absent (no extra Markdown roots) | extra Markdown roots for LAY-006 (`layout.markdown-trees`), strictly validated. `roots` is an array of repository-relative directories whose Markdown is site or application content rather than documentation (an Astro site's `src/content/**/*.md`); LAY-006 admits `.md` and `.mdx` beneath each, in addition to the docs trees, so a declared root only ever widens the allowlist and absent is the stricter grade. Reaches the engine as one `--declare markdown-roots=a,b`. An entry that is empty, absolute, contains `,` or `=`, or has a `.`, `..` or empty path segment is rejected when the config loads (a trailing `/` is dropped); the engine refuses the same values as could-not-run (exit 2) |
612
+ | `[controls.compliance.lockfiles]` | absent (REP-002 keeps its tree-derived scope) | exactly which manifest and lockfile paths REP-002 (`repository.lockfile-integrity`) scans and grades, strictly validated. Four arrays: `bun_manifests` / `bun_lockfiles` and `cargo_manifests` / `cargo_lockfiles`. A manifest entry is a repository-relative path or glob ending in `package.json` (`Cargo.toml`), such as `package.json` or `apps/*/package.json`; a lockfile entry is a literal path (a missing one is reported by name). An ecosystem is declared as a pair, and a declared pair replaces that ecosystem's default (`<typescript>/package.json` + `<typescript>/bun.lock`, the `<rust>` pair) in both what selects the gate and what it grades; an undeclared ecosystem is unchanged. Reaches the engine as `--declare bun-manifests=a,b`, `bun-lockfiles=`, `cargo-manifests=`, `cargo-lockfiles=` (a list is omitted when empty); a declared manifest that matches no file is could-not-run naming it. An entry that is empty, absolute, duplicated, contains `,` `=` `\` `<` `>` `{` `}`, starts with `!`, has a `.`, `..` or empty path segment, ends in the wrong file name, or (for a lockfile) is a glob, an ecosystem with only one of its two lists, and a `REP-002:bun_lock` / `cargo_lock` / `cargo_manifest` / `workspace` input beside the pair it supersedes are all rejected when the config loads; the engine refuses the same values as could-not-run (exit 2) |
515
613
 
516
614
  ### Registry curation
517
615
 
@@ -534,5 +632,5 @@ bun test --coverage # 100% lines + functions gate (bunfig.toml)
534
632
  ```
535
633
 
536
634
  Tests run real git in temporary repositories under `.scratchpad/test-tmp/`
537
- (gitignored), exercising the installed stubs end to end. CI:
538
- `azure-pipelines.yml` (publishing present but disabled).
635
+ (gitignored), exercising the installed stubs end to end. CI runs them through
636
+ the repository's root pipelines under `workflows/pipelines/`.
@@ -90,7 +90,7 @@ interface PullRequestList {
90
90
  value?: PullRequest[]
91
91
  }
92
92
 
93
- export interface PolicyScope {
93
+ interface PolicyScope {
94
94
  repositoryId?: string
95
95
  refName?: string
96
96
  matchKind?: string
@@ -111,12 +111,12 @@ export interface PolicyConfiguration {
111
111
  }
112
112
  }
113
113
 
114
- export interface PolicyConfigurationList {
114
+ interface PolicyConfigurationList {
115
115
  value?: PolicyConfiguration[]
116
116
  }
117
117
 
118
- export const MINIMUM_REVIEWER_POLICY_TYPE = 'fa4e907d-c16b-4a4c-9dfa-4906e5d171dd'
119
- export const BUILD_POLICY_TYPE = '0609b952-1397-4640-95ec-e00a01b2c241'
118
+ const MINIMUM_REVIEWER_POLICY_TYPE = 'fa4e907d-c16b-4a4c-9dfa-4906e5d171dd'
119
+ const BUILD_POLICY_TYPE = '0609b952-1397-4640-95ec-e00a01b2c241'
120
120
 
121
121
  /** `release: promote <source> to <target>` — derived, never declared. */
122
122
  export function promotionTitle(source: string, target: string): string {