@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
@@ -84,24 +84,26 @@
84
84
  * propagates out of `repoDoctorCheck()` uncaught rather than being reported
85
85
  * as its own finding. checkBuildServiceCanRelease() answers one narrow
86
86
  * question directly, per the real failure above: can the identity that
87
- * ACTUALLY RUNS THE PIPELINE (repo scope) push a `***NO_CI***` bump commit
88
- * to the PR's source (feature) branch (GenericContribute), and create/update
89
- * the `integration -> main` PR and set auto-complete
87
+ * ACTUALLY RUNS THE PIPELINE (repo scope) push a `[skip ci]` bump commit
88
+ * to `integration` (GenericContribute), bypass `integration`'s own policies
89
+ * while doing so (PolicyExempt, read at the integration REF token), and
90
+ * create/update the `integration -> main` PR and set auto-complete
90
91
  * (PullRequestContribute) — and it FAILS loudly,
91
92
  * naming the permission, the identity's display name and the fix path, on
92
93
  * any of: the permission not effectively allowed, the identity not
93
94
  * resolvable, or the ACL itself not readable by the calling agent.
94
95
  *
95
- * New release flow (Tarun, 2026-09-30): the CI pipeline runs on PRs into
96
- * `integration` and its stage 1 pushes the version bump to the PR's SOURCE
97
- * (feature) branch; a promote pipeline on `integration` pushes only opens the
98
- * `integration -> main` PR; a CD pipeline runs on pushes to `main`. Nothing
99
- * pushes directly to `integration` any more, so (a) the build service no
100
- * longer needs PolicyExempt on `integration` — and, by least privilege,
101
- * having it there is drift; (b) the release-identity check no longer needs
102
- * PolicyExempt; (c) the promotion PR gets NO build validation (Tarun's
103
- * approval is the only gate; CD runs after the merge), so `main` no longer
104
- * requires a build-validation policy and an enabled one is drift.
96
+ * Release flow (Tarun, 2026-09-30, amended 2026-10-01): the CI pipeline runs
97
+ * on PRs into `integration` and bumps nothing; the promote pipeline runs on
98
+ * every push to `integration`, bumps the version with a plain fast-forward
99
+ * push of a `[skip ci]` commit straight to `integration` as the build
100
+ * service, then opens the `integration -> main` PR; a CD pipeline runs on
101
+ * pushes to `main`. So (a) the build service REQUIRES PolicyExempt on
102
+ * `integration` (and Contribute on the repo) — never on `main`, never
103
+ * ForcePush; (b) the release-identity check requires PolicyExempt at the
104
+ * integration ref token; (c) the promotion PR gets NO build validation
105
+ * (Tarun's approval is the only gate; CD runs after the merge), so `main`
106
+ * does not require a build-validation policy and an enabled one is drift.
105
107
  *
106
108
  * Policy type GUIDs (verified against the azure-devops-cli-extension source,
107
109
  * packages/repo-controls already hardcodes the first three the same way):
@@ -164,7 +166,7 @@ export const GIT_REPOSITORIES_NAMESPACE_ID = "2e9eb7ed-3c0a-47d4-87c1-0ffdd275fd
164
166
 
165
167
  type PermissionBitName = keyof typeof GIT_REPO_PERMISSION_BIT;
166
168
 
167
- export const REPO_STANDARD = {
169
+ const REPO_STANDARD = {
168
170
  branches: {
169
171
  required: ["integration", "main"] as const,
170
172
  forbidden: ["develop"] as const,
@@ -231,13 +233,10 @@ export const REPO_STANDARD = {
231
233
  * — Tarun, 2026-09-27, cross-checked against
232
234
  * /Users/tarunrana/Documents/ADL-ISMS-Policies/.scratchpad/ci_build_service_grant.py,
233
235
  * which grants exactly these bits on adl-agent-control). CI needs to push
234
- * and complete PRs on the repo (Contribute is also what the version-bump
235
- * push to the PR's SOURCE feature branch needs — Tarun, 2026-09-30, new
236
- * release flow). It needs PolicyExempt NOWHERE: nothing pushes directly to
237
- * `integration` any more (the bump lands on the feature branch), so
238
- * PolicyExempt on `integration` is no longer required and, by least
239
- * privilege, is drift (`permissions.build-service.has-policyExempt-integration`);
240
- * never on `main` either (existing rule).
236
+ * and complete PRs on the repo, and needs PolicyExempt only on
237
+ * `integration` (Tarun, 2026-10-01: the integration-merge pipeline pushes
238
+ * the `[skip ci]` version bump straight to `integration`, which its own
239
+ * policies would block) — never on `main`.
241
240
  *
242
241
  * NOT forcePush (Tarun, 2026-09-30): the bump is a plain fast-forward
243
242
  * `git push origin HEAD:integration`; agent-identities' build service has
@@ -248,28 +247,37 @@ export const REPO_STANDARD = {
248
247
  repo: { allow: ["genericContribute", "pullRequestContribute"] } as {
249
248
  allow: readonly PermissionBitName[];
250
249
  },
251
- integrationRef: { deny: ["policyExempt"] } as { deny: readonly PermissionBitName[] },
250
+ // Tarun, 2026-10-01: an explicit gate on the build service's EFFECTIVE permissions on
251
+ // refs/heads/integration -- Contribute and "Bypass policies when pushing" (the
252
+ // `[skip ci]` bump push) required, Force push forbidden. Live reference: effective
253
+ // allow 16550 = read + contribute + createTag + policyExempt + pullRequestContribute.
254
+ integrationRef: { allow: ["genericContribute", "policyExempt"], deny: ["forcePush"] } as {
255
+ allow: readonly PermissionBitName[];
256
+ deny: readonly PermissionBitName[];
257
+ },
252
258
  mainRef: { deny: ["policyExempt"] } as { deny: readonly PermissionBitName[] },
253
259
  },
254
260
  /**
255
261
  * checkBuildServiceCanRelease() (file header, "checkBuildServiceCanRelease()"):
256
- * the permissions the release flow needs from whichever build service
257
- * identity actually runs the pipeline — the real failure this check
258
- * exists for was a 403 on `pullRequestContribute`.
262
+ * the exact three permissions the release flow needs from whichever
263
+ * build service identity actually runs the pipeline — the real failure
264
+ * this check exists for was a 403 on `pullRequestContribute`.
259
265
  *
260
- * `policyExempt` ("Bypass policies when pushing") is NOT required any
261
- * more (Tarun, 2026-09-30, new release flow): the version bump now lands
262
- * on the PR's SOURCE (feature) branch, not on `integration`, so nothing
263
- * needs to bypass `integration`'s policies. (History: it used to be
264
- * checked at the `integration` REF token, never repo scope — verified
265
- * live 2026-09-30 against adl-agent-control, where the build service
266
- * pushed `chore: bump version 0.1.6 to 0.1.7 ***NO_CI***` (c966e6a)
267
- * straight to `integration`.) `genericContribute` (the bump push to the
268
- * feature branch) and `pullRequestContribute` stay checked at repo scope
269
- * — PR operations are a repo-level, not branch-level, permission.
266
+ * `policyExempt` ("Bypass policies when pushing") is checked at the
267
+ * `integration` REF token, never the repo-scope token — verified live
268
+ * 2026-09-30 against adl-agent-control: the Infrastructure-AzDo Build
269
+ * Service demonstrably bypassed `integration`'s own policies to push
270
+ * its bump straight to that protected branch, yet its repo-scope
271
+ * effective allow bitmask (16430) does not include PolicyExempt (128) at
272
+ * all — only its `refs/heads/integration`-scope effective allow (16558)
273
+ * does. `genericContribute` and `pullRequestContribute` stay checked at
274
+ * repo scope — both bits ARE present there for real, and PR operations
275
+ * are a repo-level, not branch-level, permission.
270
276
  */
271
277
  buildServiceRelease: {
272
278
  repoScoped: ["genericContribute", "pullRequestContribute"] as const,
279
+ integrationRefScoped: ["genericContribute", "policyExempt"] as const,
280
+ integrationRefForbidden: ["forcePush"] as const,
273
281
  },
274
282
  },
275
283
  } as const;
@@ -280,7 +288,7 @@ export const REPO_STANDARD = {
280
288
  * https://learn.microsoft.com/en-us/azure/devops/repos/git/set-git-repository-permissions),
281
289
  * used only to build the fix-path message a human follows in that same UI.
282
290
  */
283
- export const GIT_REPO_PERMISSION_UI_LABEL: Record<PermissionBitName, string> = {
291
+ const GIT_REPO_PERMISSION_UI_LABEL: Record<PermissionBitName, string> = {
284
292
  genericRead: "Read",
285
293
  genericContribute: "Contribute",
286
294
  forcePush: "Force push (rewrite history, delete branches and tags)",
@@ -369,7 +377,7 @@ interface AccessControlListsResponse {
369
377
  * this; a per-repository override, if one is ever genuinely needed, belongs
370
378
  * in that repository's own adl-config.toml / manifest, never an env var.
371
379
  */
372
- export const STRICT_MAIN_BRANCH_PROJECT = "Enact";
380
+ const STRICT_MAIN_BRANCH_PROJECT = "Enact";
373
381
 
374
382
  function strictMainBranchRulesApply(project: string): boolean {
375
383
  return project.toLowerCase() === STRICT_MAIN_BRANCH_PROJECT.toLowerCase();
@@ -839,11 +847,11 @@ async function resolveBuildServiceDescriptor(namespaceId: string, projectId: str
839
847
  }
840
848
 
841
849
  /**
842
- * CI needs to push (the version bump to the PR's source branch) and complete
843
- * PRs on the repo itself. It needs to bypass policy NOWHERE (Tarun,
844
- * 2026-09-30, new release flow: nothing pushes directly to `integration`
845
- * any more, so PolicyExempt there is drift; on `main` a bypass would defeat
846
- * the human-reviewer gate entirely).
850
+ * CI needs to push and complete PRs on the repo itself, and needs to bypass
851
+ * policy only on `integration` (so the `[skip ci]` version-bump commit the
852
+ * integration-merge pipeline pushes there is not blocked by the very
853
+ * policies it satisfies) — never on `main`, where a bypass would defeat the
854
+ * human-reviewer gate entirely.
847
855
  */
848
856
  async function checkBuildServicePermissions(
849
857
  namespaceId: string,
@@ -902,14 +910,19 @@ async function checkBuildServicePermissions(
902
910
  drifts,
903
911
  );
904
912
  if (integrationEffective) {
905
- // Tarun, 2026-09-30, new release flow: nothing pushes directly to
906
- // integration any more, so PolicyExempt there is no longer required and
907
- // is flagged when effectively allowed (least privilege).
913
+ for (const bitName of REPO_STANDARD.permissions.buildService.integrationRef.allow) {
914
+ if ((effectiveAllowBits(integrationEffective) & GIT_REPO_PERMISSION_BIT[bitName]) === 0) {
915
+ drifts.push({
916
+ id: `permissions.build-service.missing-${bitName}-integration`,
917
+ message: `the project build service does not effectively have ${bitName} on refs/heads/integration`,
918
+ });
919
+ }
920
+ }
908
921
  for (const bitName of REPO_STANDARD.permissions.buildService.integrationRef.deny) {
909
922
  if ((effectiveAllowBits(integrationEffective) & GIT_REPO_PERMISSION_BIT[bitName]) !== 0) {
910
923
  drifts.push({
911
924
  id: `permissions.build-service.has-${bitName}-integration`,
912
- message: `the project build service effectively has ${bitName} on refs/heads/integration, which the standard forbids (nothing pushes directly to integration; the version bump lands on the PR's source branch)`,
925
+ message: `the project build service effectively has ${bitName} (${GIT_REPO_PERMISSION_UI_LABEL[bitName]}) on refs/heads/integration, which the standard forbids: the bump is a plain fast-forward push and force push is required of no identity`,
913
926
  });
914
927
  }
915
928
  }
@@ -961,6 +974,16 @@ function releaseFixPath(repository: string, identityDisplayName: string, bitName
961
974
  return `Project settings → Repositories → \`${repository}\` → Security → \`${identityDisplayName}\` → \`${GIT_REPO_PERMISSION_UI_LABEL[bitName]}\` = Allow`;
962
975
  }
963
976
 
977
+ /** Same as releaseFixPath() but for a bit that is granted per-BRANCH (verified live 2026-09-30: PolicyExempt on this org's build service lives on refs/heads/integration's own security page, never the repo-root one). */
978
+ function releaseFixPathForRef(
979
+ repository: string,
980
+ ref: string,
981
+ identityDisplayName: string,
982
+ bitName: PermissionBitName,
983
+ ): string {
984
+ return `Repos → \`${repository}\` → Branches → \`${ref}\` → ⋯ → Branch security → \`${identityDisplayName}\` → \`${GIT_REPO_PERMISSION_UI_LABEL[bitName]}\` = Allow`;
985
+ }
986
+
964
987
  /**
965
988
  * Which build service identity actually runs the pipeline, per Build —
966
989
  * General Settings — Get's `enforceJobAuthScope` (file header) — "Limit job
@@ -983,10 +1006,12 @@ async function fetchEnforceJobAuthScope(c: AdoClient): Promise<boolean | undefin
983
1006
  /**
984
1007
  * One identity's answer to "can it release": resolve its descriptor by exact
985
1008
  * display name (Identities — Read Identities, file header), then check
986
- * `buildServiceRelease.repoScoped` on the repository token. PolicyExempt is
987
- * no longer part of what a release needs (Tarun, 2026-09-30, new release
988
- * flow: the bump lands on the PR's source branch, not on integration — see
989
- * REPO_STANDARD.permissions.buildServiceRelease's own doc comment). Every
1009
+ * `buildServiceRelease.repoScoped` on the repository token AND
1010
+ * `buildServiceRelease.integrationRefScoped` on the `integration` ref token
1011
+ * — NOT the same token for all three (see REPO_STANDARD.permissions.
1012
+ * buildServiceRelease's own doc comment: PolicyExempt is a per-BRANCH grant
1013
+ * in this org, verified live against real bypass-on-push evidence, and
1014
+ * checking it at repo scope produced a false "missing" finding). Every
990
1015
  * failure mode is its own loud, distinct drift — an unresolvable identity,
991
1016
  * an ACL the calling agent cannot read, and each missing permission named
992
1017
  * with its fix path — never a silent pass.
@@ -994,6 +1019,7 @@ async function fetchEnforceJobAuthScope(c: AdoClient): Promise<boolean | undefin
994
1019
  async function checkOneBuildServiceCanRelease(
995
1020
  namespaceId: string,
996
1021
  repoToken: string,
1022
+ integrationRefToken: string,
997
1023
  repository: string,
998
1024
  displayName: string,
999
1025
  drifts: RepoDoctorDrift[],
@@ -1020,7 +1046,8 @@ async function checkOneBuildServiceCanRelease(
1020
1046
  }
1021
1047
 
1022
1048
  // LOW, independent review 2026-09-30: name WHICH token failed — "the ACL"
1023
- // alone left a human unable to tell which token's read 403'd.
1049
+ // alone left a human unable to tell a repo-scope 403 from a
1050
+ // refs/heads/integration-scope one without re-running this by hand.
1024
1051
  async function effectiveAt(token: string, tokenLabel: string): Promise<{ allow: number; deny: number } | undefined> {
1025
1052
  let effective: EffectivePermissionsResult;
1026
1053
  try {
@@ -1045,6 +1072,23 @@ async function checkOneBuildServiceCanRelease(
1045
1072
  message: `'${displayName}' does not effectively have ${GIT_REPO_PERMISSION_UI_LABEL[bitName]} on '${repository}' — the release pipeline will 403 the way agent-identities build 4897 did. Fix: ${releaseFixPath(repository, displayName, bitName)}`,
1046
1073
  });
1047
1074
  }
1075
+
1076
+ const integrationEffective = await effectiveAt(integrationRefToken, "refs/heads/integration");
1077
+ if (!integrationEffective) return;
1078
+ for (const bitName of REPO_STANDARD.permissions.buildServiceRelease.integrationRefScoped) {
1079
+ if ((effectiveAllowBits(integrationEffective) & GIT_REPO_PERMISSION_BIT[bitName]) !== 0) continue;
1080
+ drifts.push({
1081
+ id: `permissions.release.${slug}.missing-${bitName}`,
1082
+ message: `'${displayName}' does not effectively have ${GIT_REPO_PERMISSION_UI_LABEL[bitName]} on 'refs/heads/integration' of '${repository}' — its own version-bump push to integration would be refused. Fix: ${releaseFixPathForRef(repository, "integration", displayName, bitName)}`,
1083
+ });
1084
+ }
1085
+ for (const bitName of REPO_STANDARD.permissions.buildServiceRelease.integrationRefForbidden) {
1086
+ if ((effectiveAllowBits(integrationEffective) & GIT_REPO_PERMISSION_BIT[bitName]) === 0) continue;
1087
+ drifts.push({
1088
+ id: `permissions.release.${slug}.has-${bitName}`,
1089
+ message: `'${displayName}' effectively has ${GIT_REPO_PERMISSION_UI_LABEL[bitName]} on 'refs/heads/integration' of '${repository}', which the standard forbids (the version bump is a plain fast-forward push; force push is required of no identity)`,
1090
+ });
1091
+ }
1048
1092
  }
1049
1093
 
1050
1094
  /**
@@ -1075,8 +1119,9 @@ async function checkBuildServiceCanRelease(
1075
1119
  : [projectScoped, collectionScoped];
1076
1120
 
1077
1121
  const repoToken = `repoV2/${projectId}/${repositoryId}`;
1122
+ const integrationRefToken = `${repoToken}/refs/heads/${refNameHexUtf16Le("integration")}`;
1078
1123
  for (const displayName of displayNames) {
1079
- await checkOneBuildServiceCanRelease(namespaceId, repoToken, repository, displayName, drifts);
1124
+ await checkOneBuildServiceCanRelease(namespaceId, repoToken, integrationRefToken, repository, displayName, drifts);
1080
1125
  }
1081
1126
  }
1082
1127
 
@@ -1094,6 +1139,10 @@ export async function repoDoctorCheck(options: RepoDoctorOptions = {}): Promise<
1094
1139
 
1095
1140
  const repoInfo = await c.get<GitRepositoryResponse>(`/git/repositories/${repository}`, { "api-version": "7.1" });
1096
1141
  const repositoryId = repoInfo.id;
1142
+ if (typeof repositoryId !== "string" || repositoryId === "") {
1143
+ // `--repo .` (a path) reaches the list endpoint; never carry on with an `undefined` id.
1144
+ throw new Error(`Azure DevOps returned no repository for '${repository}' — --repo takes a repository name, not a path`);
1145
+ }
1097
1146
  const projectId = repoInfo.project?.id;
1098
1147
 
1099
1148
  const refs = await c.get<GitRefsResponse>(`/git/repositories/${repositoryId}/refs`, {
@@ -2,6 +2,7 @@
2
2
  // mcp-server.ts — there is no CLI entry point here (nothing else in the
3
3
  // repo invoked this file as a CLI).
4
4
  import { AdoClient, adoProjectUrl, resolveProject } from './lib/client.ts'
5
+ import { evaluateWorkflowTransition, formatWorkflowRefusal } from './workflow-rules.ts'
5
6
 
6
7
  // Work-item calls use the SAME org/project resolution as every other tool in
7
8
  // this package (`lib/client.ts`). They used to carry their own `config` object
@@ -28,7 +29,7 @@ export function resetClientForTests(): void {
28
29
  }
29
30
 
30
31
  /** Canonical work-item contract: only these board levels are user-facing. */
31
- export const ALLOWED_TYPES = ['Feature', 'Product Backlog Item', 'Bug'] as const;
32
+ const ALLOWED_TYPES = ['Feature', 'Product Backlog Item', 'Bug'] as const;
32
33
  type AllowedType = (typeof ALLOWED_TYPES)[number];
33
34
  export type WorkItemListOrGetArgs = { id?: number; ids?: number[]; type?: string; state?: string; assignedTo?: string; limit?: number; raw?: boolean };
34
35
  export type WorkItemWriteArgs = {
@@ -107,6 +108,24 @@ function buildWriteOps(args: WorkItemWriteArgs): any[] {
107
108
  export async function workitemCreateOrUpdate(args: WorkItemWriteArgs): Promise<string> {
108
109
  if (args.id === undefined) {
109
110
  assertAllowedType(args.type); if (!args.title) throw new Error('title is required for create'); if (args.parentId === undefined) throw new Error(`${args.type} requires parentId`);
111
+ // FENCE 1 (create): System.State via the raw fields escape hatch is
112
+ // fenced for the gated types — the dedicated `state` argument exists so
113
+ // the workflow gate can evaluate the resulting state. Features carry no
114
+ // flags; for them the generic managed-field refusal in buildWriteOps
115
+ // still applies (unchanged behavior).
116
+ if (args.type !== 'Feature' && args.fields !== undefined && 'System.State' in args.fields) {
117
+ throw new Error('System.State via raw fields is fenced — pass the dedicated `state` argument so the workflow gate can evaluate it.');
118
+ }
119
+ // FENCE 2 (create): a new PBI/Bug starts at New, so a create whose
120
+ // `state` lands anywhere past New is already a ladder refusal — G1
121
+ // approval, merge automation and human cancellation all happen after
122
+ // create.
123
+ if (args.type !== 'Feature') {
124
+ if (args.state !== undefined && args.state !== 'New') {
125
+ const violations = evaluateWorkflowTransition(args.type, 'New', args.state)
126
+ if (violations.length) throw new Error(formatWorkflowRefusal(violations))
127
+ }
128
+ }
110
129
  const ops = buildWriteOps(args);
111
130
  const c = await getClient();
112
131
  const parent = await c.get<any>(`/wit/workitems/${args.parentId}`, { 'api-version': '7.1' });
@@ -116,10 +135,33 @@ export async function workitemCreateOrUpdate(args: WorkItemWriteArgs): Promise<s
116
135
  return JSON.stringify(formatItem(created, false), null, 2);
117
136
  }
118
137
  if (args.type !== undefined) throw new Error('type cannot be changed on an existing work item');
119
- let ops = buildWriteOps(args); if (!ops.length) throw new Error('nothing to write: no fields, state, comment, or relations were supplied');
138
+ // System.State arriving through the raw fields escape hatch is deferred:
139
+ // its refusal is type-dependent (FENCE 1 below) and the type is only known
140
+ // after the read. Every OTHER managed field is still refused inside
141
+ // buildWriteOps, before any network, exactly as before.
142
+ const fields = args.fields ?? {};
143
+ const stateViaRawFields = 'System.State' in fields;
144
+ const fieldsForOps = stateViaRawFields ? Object.fromEntries(Object.entries(fields).filter(([name]) => name !== 'System.State')) : fields;
145
+ let ops = buildWriteOps({ ...args, fields: fieldsForOps }); if (!ops.length && !stateViaRawFields) throw new Error('nothing to write: no fields, state, comment, or relations were supplied');
120
146
  const c = await getClient();
121
147
  const current = await c.get<any>(`/wit/workitems/${args.id}`, { 'api-version': '7.1', $expand: 'all' });
122
148
  assertTracked(current);
149
+ const currentType: AllowedType = current.fields?.['System.WorkItemType'];
150
+ // FENCE 1: System.State via raw fields on a gated type. Features carry no
151
+ // flags and keep the generic managed-field refusal instead.
152
+ if (stateViaRawFields) {
153
+ if (currentType === 'Feature') throw new Error(`fields may only set Custom.* fields; 'System.State' is managed by this tool`);
154
+ throw new Error('System.State via raw fields is fenced — pass the dedicated `state` argument so the workflow gate can evaluate it.');
155
+ }
156
+ // FENCE 2 (state ladder): evaluate the RESULTING transition on every write
157
+ // that moves System.State — a move that skips gates, reaches a human-owned
158
+ // state (Approved/Done/Removed) or walks off the ladder is refused. Writes
159
+ // that leave the state untouched are not gated.
160
+ if (currentType !== 'Feature') {
161
+ const currentState = current.fields?.['System.State']
162
+ const violations = evaluateWorkflowTransition(currentType, currentState, args.state ?? currentState)
163
+ if (violations.length) throw new Error(formatWorkflowRefusal(violations))
164
+ }
123
165
  if (args.parentId !== undefined) {
124
166
  // A parent is singular. Read the existing item so the write can remove all
125
167
  // old parent links before adding the one validated replacement.
@@ -1,6 +1,5 @@
1
- // Azure DevOps identity RESOLUTION ONLY (P2, Tarun, 2026-09-27; standard
2
- // finalized 2026-09-28 in STATUS.md 12p "The
3
- // standard"; split from token minting 2026-09-28 -- see
1
+ // Azure DevOps identity RESOLUTION ONLY (Tarun, 2026-09-27; one agent-identity
2
+ // standard for every surface, 2026-09-28; split from token minting -- see
4
3
  // ./agent-token.ts's header for why).
5
4
  //
6
5
  // This module is THE one identity resolver -- every other Azure DevOps
@@ -35,7 +34,7 @@ export function isValidAgent(name: string): name is ValidAgent {
35
34
 
36
35
  /** The one message every surface shows when no agent identity can be resolved at all. */
37
36
  export const NO_AGENT_IDENTITY_MESSAGE =
38
- 'no agent identity: prefix the command with ADL_AGENT_ID_AGENT=<agent-tarun|agent-vivek|agent-reviewer>, or start the session with `adl run <surface> --as <agent>`';
37
+ 'no agent identity: prefix the command with ADL_AGENT_ID_AGENT=<agent-tarun|agent-vivek|agent-reviewer>';
39
38
 
40
39
  /** Treat blank and whitespace-only values as unset. */
41
40
  function configured(value: string | undefined): string | undefined {
@@ -129,9 +128,8 @@ export interface AgentIdentityResolution {
129
128
  }
130
129
 
131
130
  /**
132
- * The human Azure DevOps pass-through check (STATUS.md 12p decision 1: fail
133
- * closed, the human opts in; 1b: TTY + env marker; 1c: the marker is
134
- * `ADL_HUMAN_AZDO=1`). This is the ONE place the rule is expressed in
131
+ * The human Azure DevOps pass-through check (fail closed, the human opts in:
132
+ * a real TTY plus the env marker `ADL_HUMAN_AZDO=1`; Tarun, 2026-09-29). This is the ONE place the rule is expressed in
135
133
  * TypeScript -- `adl id whoami` (apps/cli/src/commands/id.ts) calls this
136
134
  * rather than re-implementing it. `bin/git-ado`'s own human-pass-through
137
135
  * branch implements the IDENTICAL rule in bash (it cannot import this
@@ -142,9 +140,10 @@ export interface AgentIdentityResolution {
142
140
  *
143
141
  * Both halves are required:
144
142
  * - `stdinIsTTY`: the caller's stdin is a real terminal, not a pipe, a
145
- * closed fd, or a non-interactive automation shell (evidence 2026-09-29,
146
- * STATUS.md 12p: the desktop agent shell has no TTY and does not inherit
147
- * `.zshrc` exports either -- the TTY half alone already excludes it).
143
+ * closed fd, or a non-interactive automation shell (observed 2026-09-29:
144
+ * the desktop agent shell has no TTY and does not inherit `.zshrc`
145
+ * exports either; agents started directly from a terminal DO inherit its
146
+ * env, which is why the TTY half is required alongside the marker).
148
147
  * - `env.ADL_HUMAN_AZDO === '1'`: the EXACT string `"1"`, not `"true"`,
149
148
  * not `"yes"`, not trimmed whitespace -- Tarun exports it from his own
150
149
  * `.zshrc`. An agent must never set it (packages/agent-settings'
@@ -160,12 +159,11 @@ export function isMarkedHumanAzdoCaller(env: NodeJS.ProcessEnv, stdinIsTTY: bool
160
159
 
161
160
  /**
162
161
  * The one agent-identity resolver every Azure DevOps surface in this repo
163
- * shares (STATUS.md 12p, "The standard"). One
164
- * function; first match wins; an invalid name is refused, never skipped:
162
+ * shares (Tarun, 2026-09-28). One function; first match wins; an invalid name is refused, never skipped:
165
163
  *
166
164
  * 1. `ADL_AGENT_ID_AGENT` from the environment (blank/whitespace-only
167
- * counts as unset) -- set by an `adl run --as <agent>` session, or by
168
- * a surface's managed default (e.g. Claude's managed-settings env).
165
+ * counts as unset) -- set by a surface's managed default (e.g.
166
+ * Claude's managed-settings env).
169
167
  * 2. Else the machine default-agent file, written by fleet reconcile.
170
168
  * 3. Else refuse with `NO_AGENT_IDENTITY_MESSAGE` -- there is never a
171
169
  * human fallback for an agent.
@@ -136,8 +136,8 @@ export async function getAccessToken(agent: string): Promise<string> {
136
136
  * addresses and the same in-memory cache -- for callers whose call sites are
137
137
  * all sync (packages/repo-controls' doctor/hook checks), where importing the
138
138
  * async mint across the package boundary would mean threading `await`
139
- * through code that has none today. STATUS.md 12p finding M9: this is the
140
- * ONE mint every surface uses now; packages/repo-controls/src/azure-devops-governance.ts
139
+ * through code that has none today. This is the ONE mint every surface
140
+ * uses; packages/repo-controls/src/azure-devops-governance.ts
141
141
  * no longer keeps its own copy.
142
142
  *
143
143
  * `env` defaults to `process.env` (matching `getAccessToken`) but is
@@ -110,11 +110,6 @@ export function currentRemote(cwd?: string): AzureRemote | null {
110
110
  return remoteCache;
111
111
  }
112
112
 
113
- /** Test seam: forget the cached remote. */
114
- export function resetRemoteCache(): void {
115
- remoteCache = undefined;
116
- }
117
-
118
113
  export function resolveOrg(cwd?: string): string {
119
114
  return configured(process.env.AZURE_DEVOPS_ORG) ?? currentRemote(cwd)?.org ?? DEFAULT_ORG;
120
115
  }
@@ -79,7 +79,7 @@ function configured(value: string | undefined): string | undefined {
79
79
  }
80
80
 
81
81
  /** The Graph service host — a different host from dev.azure.com entirely. */
82
- export function vsspsBaseUrl(): string {
82
+ function vsspsBaseUrl(): string {
83
83
  return configured(process.env.AZURE_DEVOPS_VSSPS_BASE_URL) ?? `https://vssps.dev.azure.com/${resolveOrg()}`;
84
84
  }
85
85
 
@@ -92,7 +92,7 @@ export async function fetchJson<T>(url: string, label: string): Promise<T> {
92
92
  return resp.json() as Promise<T>;
93
93
  }
94
94
 
95
- export async function postJson<T>(url: string, body: unknown, label: string): Promise<T> {
95
+ async function postJson<T>(url: string, body: unknown, label: string): Promise<T> {
96
96
  const token = await getAccessToken(resolveAgentIdentity().agent);
97
97
  const resp = await fetch(url, {
98
98
  method: 'POST',
@@ -106,7 +106,7 @@ export async function postJson<T>(url: string, body: unknown, label: string): Pr
106
106
  return resp.json() as Promise<T>;
107
107
  }
108
108
 
109
- export interface GraphSubjectQueryResponse {
109
+ interface GraphSubjectQueryResponse {
110
110
  value?: Array<{ displayName?: string; descriptor?: string }>;
111
111
  }
112
112
 
@@ -142,7 +142,7 @@ interface GraphStorageKeyResponse {
142
142
  }
143
143
 
144
144
  /** Resolve a Graph `descriptor` to its legacy GUID storage key, or undefined when Graph has none on file. */
145
- export async function resolveIdentityStorageKey(descriptor: string): Promise<string | undefined> {
145
+ async function resolveIdentityStorageKey(descriptor: string): Promise<string | undefined> {
146
146
  const result = await fetchJson<GraphStorageKeyResponse>(
147
147
  `${vsspsBaseUrl()}/_apis/graph/storagekeys/${encodeURIComponent(descriptor)}?api-version=7.1`,
148
148
  'Graph storage key',