@amsterdamdatalabs/adl-agent-control-darwin-arm64 0.1.4

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 (741) hide show
  1. package/bin/adl +4 -0
  2. package/bin/cursor-settings +14 -0
  3. package/bin/default-agent-file +14 -0
  4. package/bin/git +670 -0
  5. package/bin/git-ado +425 -0
  6. package/bin/global-agents +14 -0
  7. package/bin/global-surface-sweep +14 -0
  8. package/bin/health-check +38 -0
  9. package/bin/kimi-hooks +14 -0
  10. package/bin/lean-ctx-observe-strip +361 -0
  11. package/bin/lib/bun-compile-build.sh +34 -0
  12. package/bin/lib/lean-ctx-observe-hooks.sh +634 -0
  13. package/bin/managed-settings +14 -0
  14. package/bin/opencode-hooks +14 -0
  15. package/bin/reconcile +2648 -0
  16. package/bin/scratch-reap +14 -0
  17. package/bin/shell-path-policy +64 -0
  18. package/bin/surface-policy +14 -0
  19. package/bin/sync-and-reconcile +215 -0
  20. package/bin/update-azure-agent-pool +29 -0
  21. package/bin/validate-manifest +171 -0
  22. package/bin/vscode-settings +14 -0
  23. package/package.json +44 -0
  24. package/packages/agent-hooks/README.md +411 -0
  25. package/packages/agent-hooks/assets/hooks.json +97 -0
  26. package/packages/agent-hooks/assets/opencode-plugin.template.ts +224 -0
  27. package/packages/agent-hooks/bunfig.toml +27 -0
  28. package/packages/agent-hooks/deploy-profile.json +53 -0
  29. package/packages/agent-hooks/deploy-profile.schema.json +120 -0
  30. package/packages/agent-hooks/package.json +23 -0
  31. package/packages/agent-hooks/src/cli/args.ts +99 -0
  32. package/packages/agent-hooks/src/cli/doctor.ts +241 -0
  33. package/packages/agent-hooks/src/cli/rules.ts +133 -0
  34. package/packages/agent-hooks/src/deploy/deploy.ts +181 -0
  35. package/packages/agent-hooks/src/deploy/doctor.ts +158 -0
  36. package/packages/agent-hooks/src/deploy/index.ts +17 -0
  37. package/packages/agent-hooks/src/deploy/json-merge.ts +115 -0
  38. package/packages/agent-hooks/src/deploy/legacy-lock.ts +213 -0
  39. package/packages/agent-hooks/src/deploy/list.ts +117 -0
  40. package/packages/agent-hooks/src/deploy/lock.ts +65 -0
  41. package/packages/agent-hooks/src/deploy/opencode-template.ts +74 -0
  42. package/packages/agent-hooks/src/deploy/profile.ts +117 -0
  43. package/packages/agent-hooks/src/deploy/render.ts +162 -0
  44. package/packages/agent-hooks/src/deploy/source.ts +84 -0
  45. package/packages/agent-hooks/src/gating/config.ts +514 -0
  46. package/packages/agent-hooks/src/gating/root.ts +117 -0
  47. package/packages/agent-hooks/src/hooks/briefing/handler.ts +22 -0
  48. package/packages/agent-hooks/src/hooks/briefing/index.ts +320 -0
  49. package/packages/agent-hooks/src/hooks/contract.ts +112 -0
  50. package/packages/agent-hooks/src/hooks/crg/handler.ts +22 -0
  51. package/packages/agent-hooks/src/hooks/crg/index.ts +209 -0
  52. package/packages/agent-hooks/src/hooks/lean-ctx/handler.ts +22 -0
  53. package/packages/agent-hooks/src/hooks/lean-ctx/index.ts +173 -0
  54. package/packages/agent-hooks/src/hooks/lean-ctx/mapping.ts +121 -0
  55. package/packages/agent-hooks/src/hooks/lean-ctx/scope-rewrite.ts +207 -0
  56. package/packages/agent-hooks/src/hooks/log.ts +233 -0
  57. package/packages/agent-hooks/src/hooks/user-prompt-submit/config.ts +58 -0
  58. package/packages/agent-hooks/src/hooks/user-prompt-submit/constants.ts +149 -0
  59. package/packages/agent-hooks/src/hooks/user-prompt-submit/handler.ts +72 -0
  60. package/packages/agent-hooks/src/hooks/user-prompt-submit/index.ts +203 -0
  61. package/packages/agent-hooks/src/hooks/user-prompt-submit/match.ts +212 -0
  62. package/packages/agent-hooks/src/hooks/user-prompt-submit/skill-roots.ts +73 -0
  63. package/packages/agent-hooks/src/hooks/user-prompt-submit/skills.ts +98 -0
  64. package/packages/agent-hooks/src/hooks/user-prompt-submit/tokenizer.ts +115 -0
  65. package/packages/agent-hooks/src/hooks/user-prompt-submit/vector.ts +174 -0
  66. package/packages/agent-hooks/src/hosts/impl/claude.ts +47 -0
  67. package/packages/agent-hooks/src/hosts/impl/codex.ts +47 -0
  68. package/packages/agent-hooks/src/hosts/impl/cursor.ts +40 -0
  69. package/packages/agent-hooks/src/hosts/impl/kimi.ts +47 -0
  70. package/packages/agent-hooks/src/hosts/impl/opencode.ts +54 -0
  71. package/packages/agent-hooks/src/hosts/registry.ts +29 -0
  72. package/packages/agent-hooks/src/hosts/spec.ts +113 -0
  73. package/packages/agent-hooks/src/lean-ctx/env.ts +106 -0
  74. package/packages/agent-hooks/src/lean-ctx/mcp.ts +140 -0
  75. package/packages/agent-hooks/src/lib/spawn-with-timeout.ts +120 -0
  76. package/packages/agent-hooks/src/log/writer.ts +230 -0
  77. package/packages/agent-hooks/src/main.ts +269 -0
  78. package/packages/agent-hooks/src/pre-tool-use/handler.ts +549 -0
  79. package/packages/agent-hooks/src/rules/engine.ts +293 -0
  80. package/packages/agent-hooks/src/rules/impl/adl-build-run-denied.ts +51 -0
  81. package/packages/agent-hooks/src/rules/impl/adl-git-credential-bypass.ts +320 -0
  82. package/packages/agent-hooks/src/rules/impl/adl-git-identity.ts +249 -0
  83. package/packages/agent-hooks/src/rules/impl/adl-git-push-policy.ts +258 -0
  84. package/packages/agent-hooks/src/rules/impl/adl-human-azdo-bypass.ts +731 -0
  85. package/packages/agent-hooks/src/rules/impl/adl-identity.ts +128 -0
  86. package/packages/agent-hooks/src/rules/impl/adl-mcp-cli.ts +179 -0
  87. package/packages/agent-hooks/src/rules/impl/adl-pr-complete-pending.ts +65 -0
  88. package/packages/agent-hooks/src/rules/impl/adl-pr-review-role.ts +156 -0
  89. package/packages/agent-hooks/src/rules/impl/adl-pr-role.ts +121 -0
  90. package/packages/agent-hooks/src/rules/impl/adl-session-required.ts +403 -0
  91. package/packages/agent-hooks/src/rules/impl/adl-token-minting-role.ts +92 -0
  92. package/packages/agent-hooks/src/rules/impl/adl-workitem-role.ts +74 -0
  93. package/packages/agent-hooks/src/rules/impl/advisory-coverage.ts +43 -0
  94. package/packages/agent-hooks/src/rules/impl/advisory-finder.ts +62 -0
  95. package/packages/agent-hooks/src/rules/impl/agent-secrets-stay-unread.ts +173 -0
  96. package/packages/agent-hooks/src/rules/impl/agent-tamper-protection.ts +508 -0
  97. package/packages/agent-hooks/src/rules/impl/fs-canonical-checkout.ts +86 -0
  98. package/packages/agent-hooks/src/rules/impl/fs-git-internals.ts +75 -0
  99. package/packages/agent-hooks/src/rules/impl/fs-mv.ts +66 -0
  100. package/packages/agent-hooks/src/rules/impl/fs-rm.ts +83 -0
  101. package/packages/agent-hooks/src/rules/impl/fs-trash.ts +140 -0
  102. package/packages/agent-hooks/src/rules/impl/git-core.ts +101 -0
  103. package/packages/agent-hooks/src/rules/impl/git-helpers.ts +408 -0
  104. package/packages/agent-hooks/src/rules/impl/git-history.ts +77 -0
  105. package/packages/agent-hooks/src/rules/impl/git-paths.ts +139 -0
  106. package/packages/agent-hooks/src/rules/impl/git-plumbing.ts +167 -0
  107. package/packages/agent-hooks/src/rules/impl/git-protected-tree.ts +132 -0
  108. package/packages/agent-hooks/src/rules/impl/git-transitions.ts +292 -0
  109. package/packages/agent-hooks/src/rules/impl/git-verify.ts +95 -0
  110. package/packages/agent-hooks/src/rules/impl/git-worktree.ts +265 -0
  111. package/packages/agent-hooks/src/rules/impl/mcp-tool.ts +76 -0
  112. package/packages/agent-hooks/src/rules/impl/messages.ts +128 -0
  113. package/packages/agent-hooks/src/rules/impl/parse-uncertain.ts +143 -0
  114. package/packages/agent-hooks/src/rules/impl/pr-completion.ts +35 -0
  115. package/packages/agent-hooks/src/rules/impl/shell-remote-script-exec.ts +63 -0
  116. package/packages/agent-hooks/src/rules/impl/tool-azure-devops.ts +283 -0
  117. package/packages/agent-hooks/src/rules/impl/tool-bun-test.ts +81 -0
  118. package/packages/agent-hooks/src/rules/impl/tool-cargo.ts +66 -0
  119. package/packages/agent-hooks/src/rules/impl/tool-chmod-hook.ts +42 -0
  120. package/packages/agent-hooks/src/rules/impl/tool-find.ts +82 -0
  121. package/packages/agent-hooks/src/rules/impl/tool-frontend.ts +83 -0
  122. package/packages/agent-hooks/src/rules/impl/tool-grep.ts +93 -0
  123. package/packages/agent-hooks/src/rules/impl/tool-lean-ctx-global.ts +594 -0
  124. package/packages/agent-hooks/src/rules/impl/tool-native-search.ts +77 -0
  125. package/packages/agent-hooks/src/rules/ports.ts +178 -0
  126. package/packages/agent-hooks/src/rules/registry.ts +233 -0
  127. package/packages/agent-hooks/src/rules/shell/git-identity.ts +1415 -0
  128. package/packages/agent-hooks/src/rules/shell/git-internals.ts +186 -0
  129. package/packages/agent-hooks/src/rules/shell/invocation.ts +1083 -0
  130. package/packages/agent-hooks/src/rules/shell/piped-script.ts +201 -0
  131. package/packages/agent-hooks/src/rules/shell/prefixes.ts +214 -0
  132. package/packages/agent-hooks/src/rules/shell/protected-carrier-writes.ts +108 -0
  133. package/packages/agent-hooks/src/rules/shell/protected-carriers.ts +149 -0
  134. package/packages/agent-hooks/src/rules/shell/split.ts +179 -0
  135. package/packages/agent-hooks/src/rules/shell/substitution.ts +394 -0
  136. package/packages/agent-hooks/src/rules/shell/token.ts +180 -0
  137. package/packages/agent-hooks/src/rules/shell/xargs.ts +81 -0
  138. package/packages/agent-hooks/src/rules/spec.ts +152 -0
  139. package/packages/agent-hooks/src/surface-policy.ts +37 -0
  140. package/packages/agent-hooks/tsconfig.json +23 -0
  141. package/packages/agent-settings/assets/GLOBAL-AGENTS.md +107 -0
  142. package/packages/agent-settings/assets/agents/architect.toml +30 -0
  143. package/packages/agent-settings/assets/agents/code-reviewer.toml +27 -0
  144. package/packages/agent-settings/assets/agents/critic.toml +35 -0
  145. package/packages/agent-settings/assets/agents/executor.toml +28 -0
  146. package/packages/agent-settings/assets/agents/explore.toml +25 -0
  147. package/packages/agent-settings/assets/agents/planner.toml +29 -0
  148. package/packages/agent-settings/assets/lean-ctx/config.toml +39 -0
  149. package/packages/agent-settings/assets/lean-ctx/gitignore +6 -0
  150. package/packages/agent-settings/assets/lean-ctx/layout.toml +5 -0
  151. package/packages/agent-settings/assets/mcp.json +20 -0
  152. package/packages/agent-settings/managed/README.md +331 -0
  153. package/packages/agent-settings/managed/claude-managed-settings.json +150 -0
  154. package/packages/agent-settings/managed/codex-requirements.toml +105 -0
  155. package/packages/agent-settings/protected.json +470 -0
  156. package/packages/agent-settings/src/deploy/agent-render.ts +94 -0
  157. package/packages/agent-settings/src/deploy/agent-toml.ts +76 -0
  158. package/packages/agent-settings/src/deploy/agents-deploy.ts +129 -0
  159. package/packages/agent-settings/src/deploy/doctor.ts +201 -0
  160. package/packages/agent-settings/src/deploy/index.ts +33 -0
  161. package/packages/agent-settings/src/deploy/json-pretty.ts +66 -0
  162. package/packages/agent-settings/src/deploy/lean-ctx-deploy.ts +138 -0
  163. package/packages/agent-settings/src/deploy/legacy-lock.ts +286 -0
  164. package/packages/agent-settings/src/deploy/list.ts +135 -0
  165. package/packages/agent-settings/src/deploy/lock.ts +112 -0
  166. package/packages/agent-settings/src/deploy/mcp-deploy.ts +175 -0
  167. package/packages/agent-settings/src/deploy/mcp-inspect.ts +56 -0
  168. package/packages/agent-settings/src/deploy/mcp-merge.ts +164 -0
  169. package/packages/agent-settings/src/deploy/mcp-render.ts +80 -0
  170. package/packages/agent-settings/src/deploy/mcp-source.ts +43 -0
  171. package/packages/agent-settings/src/deploy/profile.ts +296 -0
  172. package/packages/agent-settings/src/deploy/settings.ts +65 -0
  173. package/packages/agent-settings/src/global-agents.ts +230 -0
  174. package/packages/agent-settings/src/global-surface-sweep.ts +2179 -0
  175. package/packages/agent-settings/src/kimi-hooks.ts +455 -0
  176. package/packages/agent-settings/src/opencode-hooks.ts +76 -0
  177. package/packages/agent-settings/src/surface-policy.ts +441 -0
  178. package/packages/agent-settings/surface-policy.json +20 -0
  179. package/packages/agent-skills/assets/code-review/SKILL.md +100 -0
  180. package/packages/agent-skills/assets/codebase-design/SKILL.md +98 -0
  181. package/packages/agent-skills/assets/codebase-design/references/DEEPENING.md +37 -0
  182. package/packages/agent-skills/assets/codebase-design/references/DESIGN-IT-TWICE.md +44 -0
  183. package/packages/agent-skills/assets/codebase-design/references/TESTABILITY.md +29 -0
  184. package/packages/agent-skills/assets/debug-issue/SKILL.md +40 -0
  185. package/packages/agent-skills/assets/diagnosing-bugs/SKILL.md +100 -0
  186. package/packages/agent-skills/assets/diagnosing-bugs/references/FEEDBACK-LOOP-TACTICS.md +34 -0
  187. package/packages/agent-skills/assets/diagnosing-bugs/scripts/hitl-loop.template.sh +41 -0
  188. package/packages/agent-skills/assets/domain-modeling/SKILL.md +86 -0
  189. package/packages/agent-skills/assets/domain-modeling/references/ADR-FORMAT.md +47 -0
  190. package/packages/agent-skills/assets/domain-modeling/references/CONTEXT-FORMAT.md +60 -0
  191. package/packages/agent-skills/assets/explore-codebase/SKILL.md +41 -0
  192. package/packages/agent-skills/assets/handoff/SKILL.md +28 -0
  193. package/packages/agent-skills/assets/implement/SKILL.md +28 -0
  194. package/packages/agent-skills/assets/refactor-safely/SKILL.md +44 -0
  195. package/packages/agent-skills/assets/review-changes/SKILL.md +45 -0
  196. package/packages/agent-skills/assets/tdd/SKILL.md +49 -0
  197. package/packages/agent-skills/assets/tdd/references/mocking.md +59 -0
  198. package/packages/agent-skills/assets/tdd/references/tests.md +77 -0
  199. package/packages/agent-skills/assets/testing/SKILL.md +54 -0
  200. package/packages/agent-skills/assets/to-feature/SKILL.md +91 -0
  201. package/packages/agent-skills/assets/to-feature/references/FEATURE-SPEC-TEMPLATE.md +88 -0
  202. package/packages/agent-skills/assets/to-workitems/SKILL.md +90 -0
  203. package/packages/agent-skills/assets/to-workitems/references/AZURE-DEVOPS-HIERARCHY.md +118 -0
  204. package/packages/agent-skills/assets/to-workitems/references/TICKET-TEMPLATES.md +70 -0
  205. package/packages/agent-skills/assets/wayfinder/SKILL.md +100 -0
  206. package/packages/agent-skills/assets/wayfinder/references/TEMPLATES.md +35 -0
  207. package/packages/agent-skills/assets/wayfinder/references/TICKET-TYPES.md +8 -0
  208. package/packages/agent-skills/deploy-profile.json +9 -0
  209. package/packages/agent-skills/deploy-profile.schema.json +45 -0
  210. package/packages/agent-skills/dist/deploy.d.ts +27 -0
  211. package/packages/agent-skills/dist/deploy.d.ts.map +1 -0
  212. package/packages/agent-skills/dist/deploy.js +186 -0
  213. package/packages/agent-skills/dist/deploy.js.map +1 -0
  214. package/packages/agent-skills/dist/doctor.d.ts +24 -0
  215. package/packages/agent-skills/dist/doctor.d.ts.map +1 -0
  216. package/packages/agent-skills/dist/doctor.js +141 -0
  217. package/packages/agent-skills/dist/doctor.js.map +1 -0
  218. package/packages/agent-skills/dist/fs-utils.d.ts +8 -0
  219. package/packages/agent-skills/dist/fs-utils.d.ts.map +1 -0
  220. package/packages/agent-skills/dist/fs-utils.js +40 -0
  221. package/packages/agent-skills/dist/fs-utils.js.map +1 -0
  222. package/packages/agent-skills/dist/index.d.ts +8 -0
  223. package/packages/agent-skills/dist/index.d.ts.map +1 -0
  224. package/packages/agent-skills/dist/index.js +8 -0
  225. package/packages/agent-skills/dist/index.js.map +1 -0
  226. package/packages/agent-skills/dist/legacy-lock.d.ts +44 -0
  227. package/packages/agent-skills/dist/legacy-lock.d.ts.map +1 -0
  228. package/packages/agent-skills/dist/legacy-lock.js +121 -0
  229. package/packages/agent-skills/dist/legacy-lock.js.map +1 -0
  230. package/packages/agent-skills/dist/list.d.ts +23 -0
  231. package/packages/agent-skills/dist/list.d.ts.map +1 -0
  232. package/packages/agent-skills/dist/list.js +75 -0
  233. package/packages/agent-skills/dist/list.js.map +1 -0
  234. package/packages/agent-skills/dist/manifest.d.ts +15 -0
  235. package/packages/agent-skills/dist/manifest.d.ts.map +1 -0
  236. package/packages/agent-skills/dist/manifest.js +57 -0
  237. package/packages/agent-skills/dist/manifest.js.map +1 -0
  238. package/packages/agent-skills/dist/profile.d.ts +41 -0
  239. package/packages/agent-skills/dist/profile.d.ts.map +1 -0
  240. package/packages/agent-skills/dist/profile.js +86 -0
  241. package/packages/agent-skills/dist/profile.js.map +1 -0
  242. package/packages/agent-skills/dist/skill-config.d.ts +24 -0
  243. package/packages/agent-skills/dist/skill-config.d.ts.map +1 -0
  244. package/packages/agent-skills/dist/skill-config.js +68 -0
  245. package/packages/agent-skills/dist/skill-config.js.map +1 -0
  246. package/packages/agent-skills/dist/skill-meta.d.ts +17 -0
  247. package/packages/agent-skills/dist/skill-meta.d.ts.map +1 -0
  248. package/packages/agent-skills/dist/skill-meta.js +67 -0
  249. package/packages/agent-skills/dist/skill-meta.js.map +1 -0
  250. package/packages/agent-skills/package.json +31 -0
  251. package/packages/agent-skills/src/deploy.ts +222 -0
  252. package/packages/agent-skills/src/doctor.ts +178 -0
  253. package/packages/agent-skills/src/fs-utils.ts +40 -0
  254. package/packages/agent-skills/src/index.ts +29 -0
  255. package/packages/agent-skills/src/legacy-lock.ts +152 -0
  256. package/packages/agent-skills/src/list.ts +94 -0
  257. package/packages/agent-skills/src/manifest.ts +66 -0
  258. package/packages/agent-skills/src/profile.ts +128 -0
  259. package/packages/agent-skills/src/skill-config.ts +75 -0
  260. package/packages/agent-skills/src/skill-meta.ts +78 -0
  261. package/packages/agent-skills/tsconfig.build.json +13 -0
  262. package/packages/agent-skills/tsconfig.json +23 -0
  263. package/packages/azdo/README.md +111 -0
  264. package/packages/azdo/package.json +21 -0
  265. package/packages/azdo/src/azdo-pl.ts +275 -0
  266. package/packages/azdo/src/azdo-pr-review.ts +160 -0
  267. package/packages/azdo/src/azdo-pr.ts +289 -0
  268. package/packages/azdo/src/azdo-repo-doctor.ts +839 -0
  269. package/packages/azdo/src/azdo-wit.ts +145 -0
  270. package/packages/azdo/src/cli.ts +251 -0
  271. package/packages/azdo/src/lib/agent-identity.ts +198 -0
  272. package/packages/azdo/src/lib/agent-token.ts +167 -0
  273. package/packages/azdo/src/lib/client.ts +259 -0
  274. package/packages/azdo/src/lib/graph-identity.ts +153 -0
  275. package/packages/azdo/src/lib/validate-pr-metadata.ts +57 -0
  276. package/packages/azdo/src/mcp-server.ts +209 -0
  277. package/packages/azdo/src/tool-dispatch.ts +204 -0
  278. package/packages/azdo/tsconfig.json +13 -0
  279. package/packages/fleet/jobs/git-maintain/src/main.ts +588 -0
  280. package/packages/fleet/manifest.json +207 -0
  281. package/packages/fleet/manifest.schema.json +283 -0
  282. package/packages/fleet/src/default-agent-file.ts +144 -0
  283. package/packages/fleet/src/install-adl-package.ts +178 -0
  284. package/packages/fleet/src/install-embedding-model.ts +412 -0
  285. package/packages/fleet/src/launch-agents.ts +649 -0
  286. package/packages/fleet/src/managed-settings.ts +278 -0
  287. package/packages/fleet/src/scratch-reap.ts +601 -0
  288. package/packages/fleet/src/vscode-settings.ts +705 -0
  289. package/packages/fleet/systemd/adl-azure-agent-update.service +13 -0
  290. package/packages/fleet/systemd/adl-azure-agent-update.timer +10 -0
  291. package/packages/repo-controls/AGENTS.md +96 -0
  292. package/packages/repo-controls/CLAUDE.md +1 -0
  293. package/packages/repo-controls/LICENSE +20 -0
  294. package/packages/repo-controls/README.md +493 -0
  295. package/packages/repo-controls/assets/enable-integration-auto-complete.mjs +79 -0
  296. package/packages/repo-controls/assets/promote.ts +371 -0
  297. package/packages/repo-controls/assets/version-bump.sh +189 -0
  298. package/packages/repo-controls/azure-pipelines.yml +274 -0
  299. package/packages/repo-controls/bin/adl-repo-controls.ts +10 -0
  300. package/packages/repo-controls/bunfig.toml +58 -0
  301. package/packages/repo-controls/package/adl-compliance/AGENTS.md +163 -0
  302. package/packages/repo-controls/package/adl-compliance/CLAUDE.md +1 -0
  303. package/packages/repo-controls/package/adl-compliance/conftest.py +78 -0
  304. package/packages/repo-controls/package/adl-compliance/pyproject.toml +31 -0
  305. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/__init__.py +50 -0
  306. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/__init__.py +98 -0
  307. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/__init__.py +1 -0
  308. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/adr_lifecycle/__init__.py +12 -0
  309. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/adr_lifecycle/check.py +210 -0
  310. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/adr_lifecycle/fixtures/adr-lifecycle-bad-status/docs/architecture/overview.md +8 -0
  311. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/adr_lifecycle/fixtures/adr-lifecycle-bad-status/docs/decisions/adr-901-proposed.md +10 -0
  312. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/adr_lifecycle/fixtures/adr-lifecycle-broken-backlink/docs/decisions/adr-902-dangling.md +11 -0
  313. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/adr_lifecycle/fixtures/adr-lifecycle-clean/docs/architecture/overview.md +8 -0
  314. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/adr_lifecycle/fixtures/adr-lifecycle-clean/docs/decisions/adr-900-example.md +10 -0
  315. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/adr_lifecycle/fixtures/adr-lifecycle-frontmatter-mismatch/.plans/b_committed/26-08-08-lifecycle-fixture.md +3 -0
  316. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/adr_lifecycle/fixtures/adr-lifecycle-frontmatter-mismatch/.specs/demo/lifecycle.md +7 -0
  317. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/adr_lifecycle/fixtures/adr-lifecycle-frontmatter-mismatch/docs/decisions/adr-903-frontmatter-mismatch.md +11 -0
  318. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/adr_lifecycle/fixtures/adr-lifecycle-inactive-plan/.plans/c_done/26-08-08-completed-fixture.md +3 -0
  319. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/adr_lifecycle/fixtures/adr-lifecycle-inactive-plan/.specs/demo/lifecycle.md +7 -0
  320. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/adr_lifecycle/fixtures/adr-lifecycle-inactive-plan/docs/decisions/adr-904-completed-plan.md +11 -0
  321. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/adr_lifecycle/test_check.py +127 -0
  322. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/closed_set/__init__.py +7 -0
  323. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/closed_set/check.py +91 -0
  324. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/closed_set/fixtures/docs/AGENTS.md +1 -0
  325. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/closed_set/fixtures/docs/CLAUDE.md +1 -0
  326. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/closed_set/fixtures/docs/architecture/declared.txt +1 -0
  327. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/closed_set/fixtures/docs/compliance/declared.txt +1 -0
  328. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/closed_set/fixtures/docs/decisions/declared.txt +1 -0
  329. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/closed_set/fixtures/docs/index.md +1 -0
  330. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/closed_set/fixtures/docs/operations/declared.txt +1 -0
  331. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/closed_set/fixtures/docs/research/declared.txt +1 -0
  332. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/closed_set/fixtures/docs/stray-root-file.md +1 -0
  333. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/closed_set/fixtures/docs/totally-made-up/nonsense.md +1 -0
  334. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/closed_set/test_check.py +106 -0
  335. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/english_only/__init__.py +7 -0
  336. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/english_only/check.py +291 -0
  337. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/english_only/fixtures/clean/backend/clean.rs +1 -0
  338. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/english_only/fixtures/excluded/frontend/mobile/src/i18n/locales/zh-CN/strings.ts +1 -0
  339. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/english_only/fixtures/violation/backend/escaped.rs +2 -0
  340. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/english_only/fixtures/violation/backend/raw.rs +1 -0
  341. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/english_only/fixtures/violation/backend//346/226/207/344/273/266.rs +1 -0
  342. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/english_only/test_check.py +193 -0
  343. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/index_updated/__init__.py +12 -0
  344. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/index_updated/check.py +140 -0
  345. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/index_updated/fixtures/index-updated-clean/docs/architecture/foo.md +7 -0
  346. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/index_updated/fixtures/index-updated-clean/docs/architecture/index.md +10 -0
  347. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/index_updated/fixtures/index-updated-violation/docs/architecture/foo.md +7 -0
  348. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/index_updated/fixtures/index-updated-violation/docs/architecture/index.md +9 -0
  349. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/index_updated/test_check.py +98 -0
  350. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/indexes/__init__.py +12 -0
  351. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/indexes/check.py +378 -0
  352. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/indexes/docs-knowledge-indexes.yaml +192 -0
  353. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/indexes/fixtures/knowledge-indexes-clean/docs/index.md +14 -0
  354. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/indexes/fixtures/knowledge-indexes-clean/docs/one.md +7 -0
  355. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/indexes/fixtures/knowledge-indexes-clean/docs/two.md +7 -0
  356. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/indexes/fixtures/knowledge-indexes-clean/docs-knowledge-indexes.yaml +20 -0
  357. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/indexes/fixtures/knowledge-indexes-duplicate/docs/index.md +15 -0
  358. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/indexes/fixtures/knowledge-indexes-duplicate/docs/one.md +7 -0
  359. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/indexes/fixtures/knowledge-indexes-duplicate/docs/two.md +7 -0
  360. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/indexes/fixtures/knowledge-indexes-duplicate/docs-knowledge-indexes.yaml +16 -0
  361. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/indexes/fixtures/knowledge-indexes-missing-entry/docs/index.md +13 -0
  362. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/indexes/fixtures/knowledge-indexes-missing-entry/docs/one.md +7 -0
  363. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/indexes/fixtures/knowledge-indexes-missing-entry/docs/two.md +7 -0
  364. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/indexes/fixtures/knowledge-indexes-missing-entry/docs-knowledge-indexes.yaml +16 -0
  365. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/indexes/test_check.py +102 -0
  366. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/ledger/__init__.py +12 -0
  367. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/ledger/check.py +387 -0
  368. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/ledger/fixtures/ledger-bad-date/plans/LEDGER.md +5 -0
  369. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/ledger/fixtures/ledger-clean/plans/LEDGER.md +6 -0
  370. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/ledger/fixtures/ledger-empty-table/plans/LEDGER.md +4 -0
  371. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/ledger/fixtures/ledger-long-event/plans/LEDGER.md +5 -0
  372. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/ledger/fixtures/ledger-violation/plans/LEDGER.md +5 -0
  373. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/ledger/test_check.py +427 -0
  374. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/markdown_ast/__init__.py +11 -0
  375. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/markdown_ast/check.py +84 -0
  376. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/markdown_ast/fixtures/markdown-structure-bad-fence/docs/bad-fence.md +2 -0
  377. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/markdown_ast/fixtures/markdown-structure-bad-fence/docs/valid.md +5 -0
  378. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/markdown_ast/fixtures/markdown-structure-bad-frontmatter/docs/bad-front-matter.md +2 -0
  379. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/markdown_ast/fixtures/markdown-structure-bad-frontmatter/docs/valid.md +5 -0
  380. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/markdown_ast/fixtures/markdown-structure-clean/docs/valid.md +7 -0
  381. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/markdown_ast/test_check.py +126 -0
  382. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/__init__.py +12 -0
  383. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/check.py +210 -0
  384. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/docs-okf-profiles.yaml +119 -0
  385. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-profile-clean/docs/architecture/demo.md +17 -0
  386. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-profile-clean/docs-okf-profiles.yaml +8 -0
  387. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-profile-violation/docs/architecture/bad-status.md +17 -0
  388. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-profile-violation/docs-okf-profiles.yaml +8 -0
  389. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/test_check.py +49 -0
  390. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/register.py +159 -0
  391. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/semantics/__init__.py +12 -0
  392. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/semantics/check.py +578 -0
  393. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/semantics/fixtures/semantics-clean/docs/architecture/backend/crate-overview.md +8 -0
  394. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/semantics/fixtures/semantics-clean/docs/architecture/team/team-overview.md +8 -0
  395. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/semantics/fixtures/semantics-clean/docs/compliance/controls/control-matrix.md +12 -0
  396. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/semantics/fixtures/semantics-clean/docs/compliance/controls/control-matrix.yaml +10 -0
  397. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/semantics/fixtures/semantics-clean/docs/research/benchmarks/note.md +24 -0
  398. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/semantics/fixtures/semantics-violations/docs/architecture/backend/crate-overview.md +8 -0
  399. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/semantics/fixtures/semantics-violations/docs/architecture/product/stable-delivery.md +10 -0
  400. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/semantics/fixtures/semantics-violations/docs/architecture/product/stable-recommendation.md +12 -0
  401. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/semantics/fixtures/semantics-violations/docs/architecture/product/target-narration.md +10 -0
  402. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/semantics/fixtures/semantics-violations/docs/architecture/team/team-overview.md +8 -0
  403. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/semantics/fixtures/semantics-violations/docs/compliance/controls/control-matrix.md +8 -0
  404. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/semantics/fixtures/semantics-violations/docs/compliance/controls/control-matrix.yaml +17 -0
  405. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/semantics/fixtures/semantics-violations/docs/research/benchmarks/bad-research.md +8 -0
  406. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/semantics/test_check.py +461 -0
  407. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/__init__.py +1 -0
  408. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/agents_layout/__init__.py +12 -0
  409. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/agents_layout/check.py +124 -0
  410. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/agents_layout/fixtures/.workflows/AGENTS.md +1 -0
  411. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/agents_layout/fixtures/.workflows/CLAUDE.md +1 -0
  412. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/agents_layout/fixtures/AGENTS.md +3 -0
  413. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/agents_layout/fixtures/CLAUDE.md +2 -0
  414. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/agents_layout/fixtures/INVARIANTS.md +3 -0
  415. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/agents_layout/fixtures/bad-pointer/AGENTS.md +3 -0
  416. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/agents_layout/fixtures/bad-pointer/CLAUDE.md +1 -0
  417. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/agents_layout/fixtures/docs/AGENTS.md +1 -0
  418. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/agents_layout/fixtures/docs/CLAUDE.md +1 -0
  419. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/agents_layout/fixtures/missing-pair/AGENTS.md +3 -0
  420. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/agents_layout/fixtures/owned/AGENTS.md +1 -0
  421. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/agents_layout/fixtures/owned/CLAUDE.md +2 -0
  422. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/agents_layout/test_check.py +116 -0
  423. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/ci_paths/__init__.py +13 -0
  424. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/ci_paths/check.py +380 -0
  425. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/ci_paths/fixtures/redeclared-workflows-tree/automation/pipelines/pr-validation.yaml +1 -0
  426. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/ci_paths/test_check.py +274 -0
  427. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/__init__.py +12 -0
  428. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/check.py +227 -0
  429. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-clean/frontend/packages/desktop/src/renderer/solo/item.ts +1 -0
  430. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-clean/grants.yaml +6 -0
  431. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/frontend/packages/desktop/src/renderer/fresh/fresh.ts +1 -0
  432. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/frontend/packages/desktop/src/renderer/many/sub1/only.ts +1 -0
  433. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/frontend/packages/desktop/src/renderer/many/sub10/only.ts +1 -0
  434. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/frontend/packages/desktop/src/renderer/many/sub11/only.ts +1 -0
  435. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/frontend/packages/desktop/src/renderer/many/sub2/only.ts +1 -0
  436. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/frontend/packages/desktop/src/renderer/many/sub3/only.ts +1 -0
  437. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/frontend/packages/desktop/src/renderer/many/sub4/only.ts +1 -0
  438. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/frontend/packages/desktop/src/renderer/many/sub5/only.ts +1 -0
  439. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/frontend/packages/desktop/src/renderer/many/sub6/only.ts +1 -0
  440. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/frontend/packages/desktop/src/renderer/many/sub7/only.ts +1 -0
  441. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/frontend/packages/desktop/src/renderer/many/sub8/only.ts +1 -0
  442. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/frontend/packages/desktop/src/renderer/many/sub9/only.ts +1 -0
  443. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/frontend/packages/desktop/src/renderer/services/i18n/locales/de/common.json +1 -0
  444. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/frontend/packages/desktop/src/renderer/solo/item.ts +1 -0
  445. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/frontend/packages/desktop/src/vendored-crate/Cargo.toml +2 -0
  446. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/grants.yaml +6 -0
  447. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unbaselined/frontend/packages/desktop/src/renderer/fresh/fresh.ts +1 -0
  448. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unbaselined/frontend/packages/desktop/src/renderer/many/sub1/only.ts +1 -0
  449. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unbaselined/frontend/packages/desktop/src/renderer/many/sub10/only.ts +1 -0
  450. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unbaselined/frontend/packages/desktop/src/renderer/many/sub11/only.ts +1 -0
  451. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unbaselined/frontend/packages/desktop/src/renderer/many/sub2/only.ts +1 -0
  452. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unbaselined/frontend/packages/desktop/src/renderer/many/sub3/only.ts +1 -0
  453. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unbaselined/frontend/packages/desktop/src/renderer/many/sub4/only.ts +1 -0
  454. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unbaselined/frontend/packages/desktop/src/renderer/many/sub5/only.ts +1 -0
  455. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unbaselined/frontend/packages/desktop/src/renderer/many/sub6/only.ts +1 -0
  456. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unbaselined/frontend/packages/desktop/src/renderer/many/sub7/only.ts +1 -0
  457. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unbaselined/frontend/packages/desktop/src/renderer/many/sub8/only.ts +1 -0
  458. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unbaselined/frontend/packages/desktop/src/renderer/many/sub9/only.ts +1 -0
  459. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unbaselined/frontend/packages/desktop/src/renderer/solo/item.ts +1 -0
  460. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unbaselined/grants.yaml +6 -0
  461. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/test_check.py +138 -0
  462. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/markdown_trees/__init__.py +12 -0
  463. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/markdown_trees/check.py +240 -0
  464. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/markdown_trees/fixtures/markdown-trees-clean/.plans/a_new/plan.md +7 -0
  465. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/markdown_trees/fixtures/markdown-trees-clean/backend/AGENTS.md +4 -0
  466. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/markdown_trees/fixtures/markdown-trees-clean/docs/page.md +7 -0
  467. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/markdown_trees/fixtures/markdown-trees-stray/backend/notes.md +4 -0
  468. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/markdown_trees/fixtures/markdown-trees-stray/docs/page.md +8 -0
  469. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/markdown_trees/test_check.py +220 -0
  470. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/open_work_cap/__init__.py +5 -0
  471. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/open_work_cap/check.py +225 -0
  472. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/open_work_cap/fixtures/open-work-cap-clean/plans/GAPS-AND-FINDINGS.md +5 -0
  473. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/open_work_cap/fixtures/open-work-cap-clean/plans/features/az601-clean/spec.md +10 -0
  474. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/open_work_cap/test_check.py +330 -0
  475. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/placement/__init__.py +12 -0
  476. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/placement/check.py +240 -0
  477. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/placement/fixtures/placement-allowed/agent/crates/enact-providers/src/snapshots/README.md +1 -0
  478. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/placement/fixtures/placement-allowed/backend/crates/enact-app/assets/builtin-assistants/avatars/assistant.jpg +1 -0
  479. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/placement/fixtures/placement-allowed/backend/crates/enact-assets/assets/logos/tools/coding/tool.png +1 -0
  480. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/placement/fixtures/placement-allowed/backend/crates/enact-session/src/backend/codex_init_prompt.md +1 -0
  481. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/placement/fixtures/placement-allowed/frontend/mobile/assets/images/icon.png +1 -0
  482. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/placement/fixtures/placement-allowed/frontend/packages/desktop/src/renderer/assets/logos/brand/app.png +1 -0
  483. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/placement/fixtures/placement-allowed/frontend/packages/desktop/src/renderer/assets/themes/default-theme.png +1 -0
  484. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/placement/fixtures/placement-allowed/frontend/public/pwa/icon-192.png +1 -0
  485. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/placement/fixtures/placement-allowed/frontend/resources/product.png +1 -0
  486. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/placement/fixtures/placement-stray/apps/legacy/file.ts +1 -0
  487. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/placement/fixtures/placement-stray/backend/crates/enact-session/src/backend/README.md +1 -0
  488. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/placement/fixtures/placement-stray/frontend/unapproved/screenshot.png +1 -0
  489. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/placement/test_check.py +230 -0
  490. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/plan_metadata.py +53 -0
  491. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/plans_layout/__init__.py +7 -0
  492. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/plans_layout/check.py +438 -0
  493. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/plans_layout/fixtures/plans-layout-clean/plans/AGENTS.md +1 -0
  494. 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 +9 -0
  495. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/plans_layout/fixtures/plans-layout-clean/plans/features/az347-test-coverage/spec.md +12 -0
  496. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/plans_layout/fixtures/plans-layout-clean/plans/templates/feature.md +1 -0
  497. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/plans_layout/fixtures/plans-layout-violation/plans/features/az347-test-coverage/items/az351-restore-entrypoint.md +9 -0
  498. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/plans_layout/fixtures/plans-layout-violation/plans/features/az347-test-coverage/spec.md +12 -0
  499. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/plans_layout/test_check.py +461 -0
  500. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/profile_data/__init__.py +11 -0
  501. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/profile_data/check.py +62 -0
  502. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/profile_data/fixtures/migration-filenames/backend/crates/demo/NotAMigration.sql +1 -0
  503. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/profile_data/fixtures/migration-filenames/backend/crates/demo/migrations/0001_long_prefix.sql +1 -0
  504. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/profile_data/fixtures/migration-filenames/backend/crates/demo/migrations/001_init.sql +1 -0
  505. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/profile_data/fixtures/migration-filenames/backend/crates/demo/migrations/002_add_index.sql +1 -0
  506. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/profile_data/fixtures/migration-filenames/backend/crates/demo/migrations/003-dashed-slug.sql +1 -0
  507. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/profile_data/fixtures/migration-filenames/backend/crates/demo/migrations/004_MixedCase.sql +1 -0
  508. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/profile_data/fixtures/migration-filenames/backend/crates/demo/migrations/005_trailing space.sql +1 -0
  509. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/profile_data/fixtures/migration-filenames/backend/crates/demo/migrations/01_short_prefix.sql +1 -0
  510. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/profile_data/fixtures/migration-filenames/backend/crates/demo/migrations/not-a-migration.sql +1 -0
  511. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/profile_data/test_check.py +116 -0
  512. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/references/__init__.py +11 -0
  513. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/references/check.py +188 -0
  514. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/references/fixtures/link-targets-broken/.plans/c_done/26-07-27-history.md +3 -0
  515. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/references/fixtures/link-targets-broken/docs/README.md +8 -0
  516. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/references/fixtures/link-targets-broken/docs/architecture/product/links.md +20 -0
  517. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/references/fixtures/link-targets-broken/docs/architecture/product/route-target.md +8 -0
  518. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/references/fixtures/link-targets-clean/.plans/c_done/26-07-27-history.md +3 -0
  519. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/references/fixtures/link-targets-clean/docs/README.md +8 -0
  520. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/references/fixtures/link-targets-clean/docs/architecture/product/links.md +20 -0
  521. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/references/fixtures/link-targets-clean/docs/architecture/product/route-target.md +8 -0
  522. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/references/test_check.py +166 -0
  523. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/__init__.py +11 -0
  524. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/check.py +135 -0
  525. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/.agents/declared.txt +1 -0
  526. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/.changeset/declared.txt +1 -0
  527. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/.claude/declared.txt +1 -0
  528. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/.code-review-graph/declared.txt +1 -0
  529. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/.code-review-graph_old/declared.txt +1 -0
  530. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/.codex/declared.txt +1 -0
  531. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/.cursor/declared.txt +1 -0
  532. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/.cursorrules +1 -0
  533. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/.dockerignore +1 -0
  534. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/.docs/declared.txt +1 -0
  535. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/.donors/declared.txt +1 -0
  536. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/.gitattributes +1 -0
  537. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/.kimi-code/declared.txt +1 -0
  538. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/.lfsconfig +1 -0
  539. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/.mcp.json +1 -0
  540. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/.opencode/declared.txt +1 -0
  541. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/.workflows/declared.txt +1 -0
  542. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/AGENTS.md +1 -0
  543. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/CHANGELOG.md +1 -0
  544. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/CLAUDE-INVARIANTS.md +1 -0
  545. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/CLAUDE.md +1 -0
  546. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/INDEPENDENT-VERIFICATION.md +1 -0
  547. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/INVARIANTS.md +1 -0
  548. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/LICENSE +1 -0
  549. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/NOTICE +1 -0
  550. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/README.md +1 -0
  551. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/RELEASE.md +1 -0
  552. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/VERSION +1 -0
  553. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/backend/declared.txt +1 -0
  554. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/compliance/declared.txt +1 -0
  555. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/dev/declared.txt +1 -0
  556. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/docker/declared.txt +1 -0
  557. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/docs/declared.txt +1 -0
  558. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/frontend/declared.txt +1 -0
  559. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/infra/declared.txt +1 -0
  560. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/justfile +1 -0
  561. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/opencode.jsonc +1 -0
  562. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/rule-tests/undeclared.txt +1 -0
  563. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/rules/undeclared.txt +1 -0
  564. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/unapproved-root/undeclared.txt +1 -0
  565. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/undeclared-root-file.txt +1 -0
  566. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/test_check.py +122 -0
  567. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_markdown_allowlist/__init__.py +12 -0
  568. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_markdown_allowlist/check.py +290 -0
  569. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_markdown_allowlist/fixtures/root-markdown-clean/.changeset/some-change.md +3 -0
  570. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_markdown_allowlist/fixtures/root-markdown-clean/.plans/AGENTS.md +3 -0
  571. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_markdown_allowlist/fixtures/root-markdown-clean/.specs/AGENTS.md +3 -0
  572. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_markdown_allowlist/fixtures/root-markdown-clean/.workflows/AGENTS.md +3 -0
  573. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_markdown_allowlist/fixtures/root-markdown-clean/AGENTS.md +3 -0
  574. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_markdown_allowlist/fixtures/root-markdown-clean/CHANGELOG.md +3 -0
  575. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_markdown_allowlist/fixtures/root-markdown-clean/CLAUDE.md +3 -0
  576. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_markdown_allowlist/fixtures/root-markdown-clean/INDEPENDENT-VERIFICATION.md +3 -0
  577. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_markdown_allowlist/fixtures/root-markdown-clean/INVARIANTS.md +3 -0
  578. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_markdown_allowlist/fixtures/root-markdown-clean/README.md +3 -0
  579. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_markdown_allowlist/fixtures/root-markdown-clean/RELEASE.md +3 -0
  580. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_markdown_allowlist/fixtures/root-markdown-clean/STRAY.md +3 -0
  581. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_markdown_allowlist/fixtures/root-markdown-clean/docs/AGENTS.md +3 -0
  582. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_markdown_allowlist/fixtures/root-markdown-clean/docs/architecture/note.md +3 -0
  583. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_markdown_allowlist/fixtures/root-markdown-clean/frontend/README.md +3 -0
  584. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_markdown_allowlist/fixtures/root-markdown-missing-guide/.workflows/AGENTS.md +1 -0
  585. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_markdown_allowlist/fixtures/root-markdown-missing-guide/AGENTS.md +1 -0
  586. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_markdown_allowlist/fixtures/root-markdown-missing-guide/README.md +1 -0
  587. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_markdown_allowlist/fixtures/root-markdown-missing-guide/docs/overview.md +1 -0
  588. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_markdown_allowlist/fixtures/root-markdown-missing-guide/plans/AGENTS.md +1 -0
  589. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_markdown_allowlist/test_check.py +329 -0
  590. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/scripts_size_depth/__init__.py +12 -0
  591. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/scripts_size_depth/check.py +127 -0
  592. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/scripts_size_depth/fixtures/scripts-layout/.workflows/scripts/a/b/c/d/at-limit.sh +3 -0
  593. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/scripts_size_depth/fixtures/scripts-layout/.workflows/scripts/a/b/c/d/e/too-deep.sh +3 -0
  594. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/scripts_size_depth/fixtures/scripts-layout/.workflows/scripts/direct-01.sh +3 -0
  595. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/scripts_size_depth/fixtures/scripts-layout/.workflows/scripts/direct-02.sh +3 -0
  596. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/scripts_size_depth/fixtures/scripts-layout/.workflows/scripts/direct-03.sh +3 -0
  597. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/scripts_size_depth/fixtures/scripts-layout/.workflows/scripts/direct-04.sh +3 -0
  598. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/scripts_size_depth/fixtures/scripts-layout/.workflows/scripts/direct-05.sh +3 -0
  599. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/scripts_size_depth/fixtures/scripts-layout/.workflows/scripts/direct-06.sh +3 -0
  600. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/scripts_size_depth/fixtures/scripts-layout/.workflows/scripts/direct-07.sh +3 -0
  601. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/scripts_size_depth/fixtures/scripts-layout/.workflows/scripts/direct-08.sh +3 -0
  602. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/scripts_size_depth/fixtures/scripts-layout/.workflows/scripts/direct-09.sh +3 -0
  603. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/scripts_size_depth/fixtures/scripts-layout/.workflows/scripts/direct-10.sh +3 -0
  604. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/scripts_size_depth/fixtures/scripts-layout/.workflows/scripts/direct-11.sh +3 -0
  605. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/scripts_size_depth/fixtures/scripts-layout/.workflows/scripts/direct-12.sh +3 -0
  606. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/scripts_size_depth/fixtures/scripts-layout/.workflows/scripts/direct-13.sh +3 -0
  607. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/scripts_size_depth/fixtures/scripts-layout/.workflows/scripts/direct-14.sh +3 -0
  608. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/scripts_size_depth/fixtures/scripts-layout/.workflows/scripts/direct-15.sh +3 -0
  609. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/scripts_size_depth/fixtures/scripts-layout/.workflows/scripts/direct-16.sh +3 -0
  610. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/scripts_size_depth/test_check.py +163 -0
  611. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/__init__.py +1 -0
  612. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/__init__.py +11 -0
  613. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/check.py +169 -0
  614. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/attribute-without-conversion/.gitattributes +1 -0
  615. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/attribute-without-conversion/large file.bin +3 -0
  616. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/clean/.gitattributes +1 -0
  617. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/clean/large file.bin +3 -0
  618. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/clean/small.txt +1 -0
  619. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/missing-filter/large file.bin +0 -0
  620. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/unmatched-extension/.gitattributes +1 -0
  621. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/unmatched-extension/payload.dat +0 -0
  622. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/test_check.py +133 -0
  623. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/pipeline/__init__.py +1 -0
  624. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/pipeline/phase_disjoint/__init__.py +12 -0
  625. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/pipeline/phase_disjoint/check.py +129 -0
  626. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/pipeline/phase_disjoint/fixtures/disjoint/gate-registry.yaml +13 -0
  627. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/pipeline/phase_disjoint/fixtures/empty/gate-registry.yaml +7 -0
  628. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/pipeline/phase_disjoint/fixtures/overlapping/gate-registry.yaml +13 -0
  629. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/pipeline/phase_disjoint/test_check.py +109 -0
  630. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/release/__init__.py +1 -0
  631. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/release/changeset_plan/__init__.py +11 -0
  632. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/release/changeset_plan/check.py +149 -0
  633. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/release/changeset_plan/fixtures/clean/docs/readme.md +4 -0
  634. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/release/changeset_plan/fixtures/relevant/VERSION +1 -0
  635. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/release/changeset_plan/test_check.py +151 -0
  636. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/release/version_release/__init__.py +11 -0
  637. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/release/version_release/check.py +202 -0
  638. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/release/version_release/fixtures/aligned/.workflows/changesets/package.json +5 -0
  639. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/release/version_release/fixtures/aligned/.workflows/package.json +5 -0
  640. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/release/version_release/fixtures/aligned/CHANGELOG.md +5 -0
  641. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/release/version_release/fixtures/aligned/VERSION +1 -0
  642. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/release/version_release/fixtures/mismatched/.workflows/changesets/package.json +5 -0
  643. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/release/version_release/fixtures/mismatched/.workflows/package.json +5 -0
  644. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/release/version_release/fixtures/mismatched/CHANGELOG.md +5 -0
  645. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/release/version_release/fixtures/mismatched/VERSION +1 -0
  646. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/release/version_release/test_check.py +162 -0
  647. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/__init__.py +1 -0
  648. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/banned_commands/__init__.py +12 -0
  649. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/banned_commands/check.py +103 -0
  650. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/banned_commands/fixtures/no-banned-commands/compliance_py/checks/git-bad.sh +2 -0
  651. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/banned_commands/fixtures/no-banned-commands/compliance_py/checks/git-note.sh +3 -0
  652. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/banned_commands/fixtures/no-banned-commands/compliance_py/checks/good.sh +2 -0
  653. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/banned_commands/fixtures/no-banned-commands/compliance_py/checks/grep-bad.sh +2 -0
  654. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/banned_commands/fixtures/no-banned-commands/compliance_py/checks/grep-note.sh +3 -0
  655. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/banned_commands/fixtures/no-banned-commands/compliance_py/checks/grep-trailing.sh +2 -0
  656. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/banned_commands/fixtures/no-banned-commands/compliance_py/checks/notes.md +1 -0
  657. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/banned_commands/fixtures/no-banned-commands/elsewhere/loose-git.sh +6 -0
  658. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/banned_commands/fixtures/no-banned-commands/elsewhere/loose-grep.sh +4 -0
  659. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/banned_commands/test_check.py +117 -0
  660. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/ignored_paths/__init__.py +13 -0
  661. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/ignored_paths/check.py +265 -0
  662. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/ignored_paths/fixtures/ignored-paths/keep.log +1 -0
  663. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/ignored_paths/fixtures/ignored-paths/src/main.rs +1 -0
  664. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/ignored_paths/test_check.py +180 -0
  665. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/license_declared/__init__.py +12 -0
  666. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/license_declared/check.py +84 -0
  667. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/license_declared/fixtures/license-declared-clean/LICENSE +10 -0
  668. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/license_declared/fixtures/license-declared-mismatch/LICENSE +3 -0
  669. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/license_declared/fixtures/license-declared-missing/README.md +1 -0
  670. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/license_declared/test_check.py +66 -0
  671. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/__init__.py +11 -0
  672. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/check.py +167 -0
  673. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/fixtures/clean/backend/Cargo.lock +7 -0
  674. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/fixtures/clean/backend/Cargo.toml +4 -0
  675. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/fixtures/clean/backend/rust-toolchain.toml +3 -0
  676. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/fixtures/clean/backend/src/main.rs +1 -0
  677. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/fixtures/clean/frontend/bun.lock +1 -0
  678. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/fixtures/empty-bun-lock/backend/Cargo.lock +7 -0
  679. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/fixtures/empty-bun-lock/backend/Cargo.toml +4 -0
  680. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/fixtures/empty-bun-lock/backend/rust-toolchain.toml +3 -0
  681. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/fixtures/empty-bun-lock/backend/src/main.rs +1 -0
  682. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/fixtures/empty-bun-lock/frontend/bun.lock +0 -0
  683. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/test_check.py +109 -0
  684. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/cli.py +483 -0
  685. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/core/__init__.py +1 -0
  686. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/core/ast_grep.py +199 -0
  687. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/core/batch.py +52 -0
  688. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/core/check.py +303 -0
  689. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/core/constants.py +106 -0
  690. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/core/context.py +99 -0
  691. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/core/errors.py +32 -0
  692. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/core/finding.py +65 -0
  693. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/core/models.py +40 -0
  694. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/core/receipt.py +63 -0
  695. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/core/scope.py +82 -0
  696. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/core/verdict.py +161 -0
  697. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/__init__.py +1 -0
  698. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/config.py +131 -0
  699. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/config.toml +30 -0
  700. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/docs_shape.py +65 -0
  701. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/gate-registry.alt.yaml +791 -0
  702. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/gate-registry.schema.yaml +176 -0
  703. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/gate-registry.yaml +791 -0
  704. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/grants-registry.yaml +112 -0
  705. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/grants.py +129 -0
  706. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/registry.py +281 -0
  707. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/root_shape.py +250 -0
  708. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/severity-policy.yaml +114 -0
  709. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/providers/__init__.py +11 -0
  710. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/runner.py +371 -0
  711. package/packages/repo-controls/package/adl-compliance/uv.lock +199 -0
  712. package/packages/repo-controls/package.json +33 -0
  713. package/packages/repo-controls/scripts/hooks/commit-msg +63 -0
  714. package/packages/repo-controls/scripts/hooks/lib/hook-log.sh +62 -0
  715. package/packages/repo-controls/scripts/hooks/post-checkout +15 -0
  716. package/packages/repo-controls/scripts/hooks/post-commit +18 -0
  717. package/packages/repo-controls/scripts/hooks/pre-commit +82 -0
  718. package/packages/repo-controls/scripts/hooks/pre-push +144 -0
  719. package/packages/repo-controls/src/azdo-push.ts +463 -0
  720. package/packages/repo-controls/src/azure-devops-governance.ts +248 -0
  721. package/packages/repo-controls/src/azure-devops-remote.ts +61 -0
  722. package/packages/repo-controls/src/cli.ts +188 -0
  723. package/packages/repo-controls/src/compliance-config.ts +200 -0
  724. package/packages/repo-controls/src/config.ts +690 -0
  725. package/packages/repo-controls/src/constants.ts +97 -0
  726. package/packages/repo-controls/src/coverage-ratchet.ts +153 -0
  727. package/packages/repo-controls/src/doc-freshness.ts +172 -0
  728. package/packages/repo-controls/src/doctor.ts +304 -0
  729. package/packages/repo-controls/src/findings-ratchet.ts +163 -0
  730. package/packages/repo-controls/src/gitignore-block.ts +253 -0
  731. package/packages/repo-controls/src/hook-log.ts +72 -0
  732. package/packages/repo-controls/src/hook.ts +694 -0
  733. package/packages/repo-controls/src/install.ts +506 -0
  734. package/packages/repo-controls/src/integrity.ts +104 -0
  735. package/packages/repo-controls/src/promote.ts +25 -0
  736. package/packages/repo-controls/src/runtime.ts +110 -0
  737. package/packages/repo-controls/src/workflows-drift.ts +106 -0
  738. package/packages/repo-controls/src/worktree-guard.ts +272 -0
  739. package/packages/repo-controls/src/worktree-limit.ts +11 -0
  740. package/packages/repo-controls/tsconfig.json +14 -0
  741. package/packages/repo-controls/workflows/scripts/release/verify-npm-artifact.ts +119 -0
@@ -0,0 +1,839 @@
1
+ /**
2
+ * C9 (docs/specs/two-branch-standard-2026-09-27.md §3.3, §1a): read-only
3
+ * check of one repository against the two-branch standard. Same token path
4
+ * as every other tool in this package (the session's own agent identity via
5
+ * lib/agent-identity.ts) — no separate credential, no mutation.
6
+ *
7
+ * REPO_STANDARD below is the single place the standard's expected values
8
+ * live; every check reads from it rather than repeating a literal.
9
+ *
10
+ * REST APIs used (verified against Microsoft's docs 2026-09-27):
11
+ * - Git Repositories — Get Repository
12
+ * GET {org}/{project}/_apis/git/repositories/{repository}?api-version=7.1
13
+ * https://learn.microsoft.com/en-us/rest/api/azure/devops/git/repositories/get-repository
14
+ * - Git Refs — List (branches)
15
+ * GET {org}/{project}/_apis/git/repositories/{repositoryId}/refs?filter=heads/&api-version=7.1
16
+ * https://learn.microsoft.com/en-us/rest/api/azure/devops/git/refs/list
17
+ * - Build Definitions — List (has-a-pipeline probe; already used by azdo-pl.ts)
18
+ * GET {org}/{project}/_apis/build/definitions?repositoryId=..&repositoryType=TfsGit&api-version=7.1
19
+ * - Git-scoped Policy Configurations (repository + branch scoped; the plain
20
+ * /_apis/policy/configurations List doc itself names this as the one to
21
+ * use for scope filtering: "Instead, use the /_apis/git/policy/configurations
22
+ * API, which provides first class scope filtering support." Already used
23
+ * the same way by packages/repo-controls/src/azure-devops-governance.ts.)
24
+ * GET {org}/{project}/_apis/git/policy/configurations?repositoryId=..&refName=refs/heads/{branch}&api-version=7.1
25
+ * https://learn.microsoft.com/en-us/rest/api/azure/devops/policy/configurations/list
26
+ * - Security — Access Control Lists Query (Git Repositories namespace)
27
+ * GET {org}/_apis/accesscontrollists/{namespaceId}?token=repoV2/{projectId}/{repositoryId}
28
+ * &descriptors=<comma-separated>&includeExtendedInfo=true&api-version=7.1
29
+ * https://learn.microsoft.com/en-us/rest/api/azure/devops/security/access-control-lists/query
30
+ * (namespace id, token shape and the READ/CONTRIBUTE/PR_CONTRIBUTE bit
31
+ * values below are the same ones already read live and recorded in
32
+ * ADL-ISMS-Policies/docs/scripts/enact-agent-git-permissions.py and
33
+ * .../docs/evidence/vanta-documents/100-.../azure-devops-git-security-namespace.json)
34
+ * - Graph — Subject Query (resolve a service principal's descriptor by display name)
35
+ * POST https://vssps.dev.azure.com/{org}/_apis/graph/subjectquery?api-version=7.1-preview.1
36
+ * body: { query: <displayName>, subjectKind: ['User'] }
37
+ * https://learn.microsoft.com/en-us/rest/api/azure/devops/graph/subject-query/query
38
+ * - Identities — Read Identities (resolve a BUILD SERVICE's descriptor by
39
+ * exact display name — a build service is not a Graph 'User'/'Group'
40
+ * subject, so Subject Query above cannot find it; used only by
41
+ * checkBuildServiceCanRelease() below, lib/graph-identity.ts's
42
+ * resolveIdentityByDisplayName())
43
+ * GET https://vssps.dev.azure.com/{org}/_apis/identities?searchFilter=General&filterValue=<name>&queryMembership=None&api-version=7.1
44
+ * https://learn.microsoft.com/en-us/rest/api/azure/devops/ims/identities/read-identities
45
+ * - Build — General Settings — Get (which build service identity actually
46
+ * runs the pipeline: `enforceJobAuthScope` is "Limit job authorization
47
+ * scope to current project" in the UI — true means the PROJECT-scoped
48
+ * build service runs the job, false means the ORG/COLLECTION-scoped one
49
+ * does; used only by checkBuildServiceCanRelease() below)
50
+ * GET {org}/{project}/_apis/build/generalsettings?api-version=7.1
51
+ * https://learn.microsoft.com/en-us/rest/api/azure/devops/build/general-settings/get
52
+ *
53
+ * checkBuildServiceCanRelease() (C9 follow-up, Tarun 2026-09-29): a real
54
+ * pipeline failure — agent-identities build 4897, stage "Create integration
55
+ * to main PR" (packages/repo-controls/assets/promote.ts) — 403'd with
56
+ * `TF401027: You need the Git 'PullRequestContribute' permission ... identity
57
+ * 'Build\<projectId>', scope 'repository'`. checkBuildServicePermissions()
58
+ * above already checks a DIFFERENT, finer-grained set of per-branch bits for
59
+ * a different purpose (branch-scoped PolicyExempt allow/deny) and stops at
60
+ * "not found" for an unresolvable identity; it does not name the exact
61
+ * identity display name or the fix path, and a 403 reading the ACL itself
62
+ * propagates out of `repoDoctorCheck()` uncaught rather than being reported
63
+ * as its own finding. checkBuildServiceCanRelease() answers one narrow
64
+ * question directly, per the real failure above: can the identity that
65
+ * ACTUALLY RUNS THE PIPELINE (repo scope) push a `***NO_CI***` bump commit
66
+ * to `integration` (GenericContribute), bypass `integration`'s own policies
67
+ * while doing so (PolicyExempt), and create/update the `integration -> main`
68
+ * PR and set auto-complete (PullRequestContribute) — and it FAILS loudly,
69
+ * naming the permission, the identity's display name and the fix path, on
70
+ * any of: the permission not effectively allowed, the identity not
71
+ * resolvable, or the ACL itself not readable by the calling agent.
72
+ *
73
+ * Policy type GUIDs (verified against the azure-devops-cli-extension source,
74
+ * packages/repo-controls already hardcodes the first three the same way):
75
+ * minimum reviewers fa4e907d-c16b-4a4c-9dfa-4906e5d171dd
76
+ * required reviewers fd2167ab-b0be-447a-8ec8-39368250530e
77
+ * build validation 0609b952-1397-4640-95ec-e00a01b2c241
78
+ * merge strategy fa4e907d-c16b-4a4c-9dfa-4916e5d171ab
79
+ * comment requirements c6a1889d-b943-4856-b76f-9e46bb6b0df2
80
+ */
81
+
82
+ import { resolveAgentIdentity } from "./lib/agent-identity.ts";
83
+ import { AdoClient, resolveOrg, resolveProject, resolveRepository } from "./lib/client.ts";
84
+ import { fetchJson, resolveAgentDescriptor, resolveIdentityByDisplayName } from "./lib/graph-identity.ts";
85
+
86
+ /** Treat blank and whitespace-only env overrides as unset, like lib/client.ts's own `configured()`. */
87
+ function configured(value: string | undefined): string | undefined {
88
+ const trimmed = value?.trim();
89
+ return trimmed ? trimmed : undefined;
90
+ }
91
+
92
+ /** The org-root REST base (no project segment) — accesscontrollists lives here, not under a project. */
93
+ function orgBaseUrl(): string {
94
+ return configured(process.env.AZURE_DEVOPS_ORG_BASE_URL) ?? `https://dev.azure.com/${resolveOrg()}`;
95
+ }
96
+
97
+ // fetchJson/postJson (bearer-token GET/POST against an arbitrary Azure DevOps
98
+ // host) and resolveAgentDescriptor (Graph Subject Query) live in
99
+ // ./lib/graph-identity.ts — this file only adds its own orgBaseUrl() (the
100
+ // accesscontrollists host); vsspsBaseUrl() moved with the Graph helpers.
101
+
102
+ // -------------------------------------------------------------------------
103
+ // The standard, in one place.
104
+ // -------------------------------------------------------------------------
105
+
106
+ export const POLICY_TYPE = {
107
+ minimumReviewers: "fa4e907d-c16b-4a4c-9dfa-4906e5d171dd",
108
+ requiredReviewers: "fd2167ab-b0be-447a-8ec8-39368250530e",
109
+ build: "0609b952-1397-4640-95ec-e00a01b2c241",
110
+ mergeStrategy: "fa4e907d-c16b-4a4c-9dfa-4916e5d171ab",
111
+ commentRequirements: "c6a1889d-b943-4856-b76f-9e46bb6b0df2",
112
+ } as const;
113
+
114
+ /** Git Repositories security namespace (2e9eb7ed-3c0a-47d4-87c1-0ffdd275fd87) permission bits, read live 2026-09-26 — see the file header for the source. */
115
+ export const GIT_REPO_PERMISSION_BIT = {
116
+ genericRead: 2,
117
+ genericContribute: 4,
118
+ forcePush: 8,
119
+ policyExempt: 128,
120
+ pullRequestContribute: 16384,
121
+ pullRequestBypassPolicy: 32768,
122
+ } as const;
123
+
124
+ export const GIT_REPOSITORIES_NAMESPACE_ID = "2e9eb7ed-3c0a-47d4-87c1-0ffdd275fd87";
125
+
126
+ type PermissionBitName = keyof typeof GIT_REPO_PERMISSION_BIT;
127
+
128
+ export const REPO_STANDARD = {
129
+ branches: {
130
+ required: ["integration", "main"] as const,
131
+ forbidden: ["develop"] as const,
132
+ defaultBranch: "main",
133
+ },
134
+ integration: {
135
+ // No human gate: neither a minimum-reviewer nor a required-reviewer
136
+ // policy may be enabled here.
137
+ forbiddenReviewerPolicies: [POLICY_TYPE.minimumReviewers, POLICY_TYPE.requiredReviewers] as const,
138
+ mergeStrategy: { allowSquash: true, allowRebase: false, allowRebaseMerge: false, allowNoFastForward: false },
139
+ buildValidationRequiredWhenPipelineExists: true,
140
+ },
141
+ main: {
142
+ minimumReviewers: { minimumApproverCount: 1, creatorVoteCounts: false, resetOnSourcePush: true, isBlocking: true },
143
+ // A named required reviewer is forbidden, not merely optional: Tarun,
144
+ // 2026-09-27, "I should not be required for it" — the promotion PR
145
+ // (raised by the pipeline, not directed by a human) is approved by ANY
146
+ // one human via the minimum-reviewer policy above; naming one reviewer
147
+ // would make that person a standing approval bottleneck the standard
148
+ // never asked for. docs/specs/two-branch-standard-2026-09-27.md §1b.1,
149
+ // §1b.6; ADL-ISMS-Policies docs/questions.md A121.
150
+ forbiddenReviewerPolicies: [POLICY_TYPE.requiredReviewers] as const,
151
+ mergeStrategy: { allowSquash: false, allowRebase: false, allowRebaseMerge: false, allowNoFastForward: true },
152
+ commentRequirementsRequired: true,
153
+ buildValidationRequiredWhenPipelineExists: true,
154
+ },
155
+ // One table for every effective-permission expectation this checker reads
156
+ // via the Git Repositories security namespace ACL, so the standard never
157
+ // repeats a bit name or a token shape in two places.
158
+ permissions: {
159
+ namespaceId: GIT_REPOSITORIES_NAMESPACE_ID,
160
+ agents: {
161
+ "agent-tarun": {
162
+ allow: ["genericContribute", "pullRequestContribute"],
163
+ deny: ["forcePush", "policyExempt", "pullRequestBypassPolicy"],
164
+ },
165
+ "agent-vivek": {
166
+ allow: ["genericContribute", "pullRequestContribute"],
167
+ deny: ["forcePush", "policyExempt", "pullRequestBypassPolicy"],
168
+ },
169
+ "agent-reviewer": { allow: ["pullRequestContribute"], deny: ["genericContribute"] },
170
+ } as Record<string, { allow: readonly PermissionBitName[]; deny: readonly PermissionBitName[] }>,
171
+ /**
172
+ * The project's build service identity (display name `Build\<projectId>`,
173
+ * descriptor `Microsoft.TeamFoundation.ServiceIdentity;...<projectId>...`
174
+ * — Tarun, 2026-09-27, cross-checked against
175
+ * /Users/tarunrana/Documents/ADL-ISMS-Policies/.scratchpad/ci_build_service_grant.py,
176
+ * which grants exactly these bits on adl-agent-control). CI needs to push
177
+ * tags/branches and complete PRs on the repo, and needs PolicyExempt only
178
+ * on `integration` (so a version-bump commit made by CI itself is not
179
+ * blocked by its own policies) — never on `main`.
180
+ */
181
+ buildService: {
182
+ repo: { allow: ["genericContribute", "forcePush", "pullRequestContribute"] } as {
183
+ allow: readonly PermissionBitName[];
184
+ },
185
+ integrationRef: { allow: ["policyExempt"] } as { allow: readonly PermissionBitName[] },
186
+ mainRef: { deny: ["policyExempt"] } as { deny: readonly PermissionBitName[] },
187
+ },
188
+ /**
189
+ * checkBuildServiceCanRelease() (file header, "checkBuildServiceCanRelease()"):
190
+ * the exact three repo-scope permissions the release flow needs from
191
+ * whichever build service identity actually runs the pipeline — the real
192
+ * failure this check exists for was a 403 on the third one.
193
+ */
194
+ buildServiceRelease: {
195
+ required: ["genericContribute", "policyExempt", "pullRequestContribute"] as const,
196
+ },
197
+ },
198
+ } as const;
199
+
200
+ /**
201
+ * The Azure DevOps Repos "Security" tab's own label for each permission bit
202
+ * (Set Git repository permissions —
203
+ * https://learn.microsoft.com/en-us/azure/devops/repos/git/set-git-repository-permissions),
204
+ * used only to build the fix-path message a human follows in that same UI.
205
+ */
206
+ export const GIT_REPO_PERMISSION_UI_LABEL: Record<PermissionBitName, string> = {
207
+ genericRead: "Read",
208
+ genericContribute: "Contribute",
209
+ forcePush: "Force push (rewrite history, delete branches and tags)",
210
+ policyExempt: "Bypass policies when pushing",
211
+ pullRequestContribute: "Contribute to pull requests",
212
+ pullRequestBypassPolicy: "Bypass policies when completing pull requests",
213
+ };
214
+
215
+ // -------------------------------------------------------------------------
216
+ // Azure DevOps response shapes (only the fields this checker reads).
217
+ // -------------------------------------------------------------------------
218
+
219
+ interface GitRepositoryResponse {
220
+ id: string;
221
+ defaultBranch?: string;
222
+ project?: { id?: string };
223
+ }
224
+
225
+ interface GitRefsResponse {
226
+ value?: Array<{ name: string }>;
227
+ }
228
+
229
+ interface BuildDefinitionsResponse {
230
+ value?: Array<{ id: number }>;
231
+ }
232
+
233
+ /** Build — General Settings — Get response (only the field this checker reads). */
234
+ interface BuildGeneralSettingsResponse {
235
+ enforceJobAuthScope?: boolean;
236
+ }
237
+
238
+ interface PolicyConfiguration {
239
+ id?: number;
240
+ isEnabled?: boolean;
241
+ isBlocking?: boolean;
242
+ type?: { id?: string };
243
+ settings?: {
244
+ minimumApproverCount?: number;
245
+ creatorVoteCounts?: boolean;
246
+ resetOnSourcePush?: boolean;
247
+ buildDefinitionId?: number;
248
+ allowSquash?: boolean;
249
+ allowRebase?: boolean;
250
+ allowRebaseMerge?: boolean;
251
+ allowNoFastForward?: boolean;
252
+ };
253
+ }
254
+
255
+ interface PolicyConfigurationsResponse {
256
+ value?: PolicyConfiguration[];
257
+ }
258
+
259
+ interface AccessControlListsResponse {
260
+ value?: Array<{
261
+ acesDictionary?: Record<
262
+ string,
263
+ { allow?: number; deny?: number; extendedInfo?: { effectiveAllow?: number; effectiveDeny?: number } }
264
+ >;
265
+ }>;
266
+ }
267
+
268
+ export interface RepoDoctorDrift {
269
+ id: string;
270
+ message: string;
271
+ }
272
+
273
+ export interface RepoDoctorReport {
274
+ repository: string;
275
+ compliant: boolean;
276
+ drifts: RepoDoctorDrift[];
277
+ }
278
+
279
+ export interface RepoDoctorOptions {
280
+ /** Repository name; defaults to the current checkout's origin (via resolveRepository()). */
281
+ repository?: string;
282
+ /** Test seam: an AdoClient pointed at a stub, in place of the default singleton. */
283
+ client?: AdoClient;
284
+ }
285
+
286
+ function enabledPolicyOfType(
287
+ policies: readonly PolicyConfiguration[],
288
+ typeId: string,
289
+ ): PolicyConfiguration | undefined {
290
+ return policies.find((policy) => policy.type?.id === typeId && policy.isEnabled === true);
291
+ }
292
+
293
+ async function fetchBranchPolicies(c: AdoClient, repositoryId: string, branch: string): Promise<PolicyConfiguration[]> {
294
+ const result = await c.get<PolicyConfigurationsResponse>("/git/policy/configurations", {
295
+ repositoryId,
296
+ refName: `refs/heads/${branch}`,
297
+ "api-version": "7.1",
298
+ });
299
+ return result.value ?? [];
300
+ }
301
+
302
+ async function repositoryHasAPipeline(c: AdoClient, repositoryId: string): Promise<boolean> {
303
+ const result = await c.get<BuildDefinitionsResponse>("/build/definitions", {
304
+ repositoryId,
305
+ repositoryType: "TfsGit",
306
+ "api-version": "7.1",
307
+ });
308
+ return (result.value ?? []).length > 0;
309
+ }
310
+
311
+ function checkIntegrationPolicies(
312
+ policies: readonly PolicyConfiguration[],
313
+ hasPipeline: boolean,
314
+ drifts: RepoDoctorDrift[],
315
+ ): void {
316
+ const minReviewer = enabledPolicyOfType(policies, POLICY_TYPE.minimumReviewers);
317
+ if (minReviewer) {
318
+ drifts.push({
319
+ id: "integration.minimum-reviewers-enabled",
320
+ message: `integration has an enabled minimum-reviewer policy (#${minReviewer.id}); integration must have no human reviewer gate`,
321
+ });
322
+ }
323
+ const requiredReviewer = enabledPolicyOfType(policies, POLICY_TYPE.requiredReviewers);
324
+ if (requiredReviewer) {
325
+ drifts.push({
326
+ id: "integration.required-reviewer-enabled",
327
+ message: `integration has an enabled required-reviewer policy (#${requiredReviewer.id}); integration must have no human reviewer gate`,
328
+ });
329
+ }
330
+
331
+ const merge = enabledPolicyOfType(policies, POLICY_TYPE.mergeStrategy);
332
+ if (!merge) {
333
+ drifts.push({
334
+ id: "integration.merge-strategy-missing",
335
+ message: "integration is missing an enabled merge-strategy policy restricting merges to squash",
336
+ });
337
+ } else {
338
+ const settings = merge.settings ?? {};
339
+ const expected = REPO_STANDARD.integration.mergeStrategy;
340
+ const squashOnly =
341
+ Boolean(settings.allowSquash) === expected.allowSquash &&
342
+ Boolean(settings.allowRebase) === expected.allowRebase &&
343
+ Boolean(settings.allowRebaseMerge) === expected.allowRebaseMerge &&
344
+ Boolean(settings.allowNoFastForward) === expected.allowNoFastForward;
345
+ if (!squashOnly) {
346
+ drifts.push({
347
+ id: "integration.merge-strategy-not-squash-only",
348
+ message: `integration merge-strategy policy (#${merge.id}) does not restrict merges to squash only`,
349
+ });
350
+ }
351
+ }
352
+
353
+ if (hasPipeline) {
354
+ const build = enabledPolicyOfType(policies, POLICY_TYPE.build);
355
+ if (!build) drifts.push({ id: "integration.build-validation-missing", message: "missing build validation" });
356
+ }
357
+ }
358
+
359
+ // A named required reviewer on main is DRIFT (A121: "I should not be
360
+ // required for it" — see REPO_STANDARD.main's comment above).
361
+ function checkMainRequiredReviewer(policies: readonly PolicyConfiguration[], drifts: RepoDoctorDrift[]): void {
362
+ const requiredReviewer = enabledPolicyOfType(policies, POLICY_TYPE.requiredReviewers);
363
+ if (!requiredReviewer) return;
364
+ drifts.push({
365
+ id: "main.required-reviewer-enabled",
366
+ message: `main has an enabled required-reviewer policy (#${requiredReviewer.id}); no human may be named — any one approver satisfies the minimum-reviewer policy (A121)`,
367
+ });
368
+ }
369
+
370
+ function checkMainMinimumReviewers(policies: readonly PolicyConfiguration[], drifts: RepoDoctorDrift[]): void {
371
+ const minReviewer = enabledPolicyOfType(policies, POLICY_TYPE.minimumReviewers);
372
+ if (!minReviewer) {
373
+ drifts.push({
374
+ id: "main.minimum-reviewers-missing",
375
+ message: "main is missing an enabled minimum-reviewer policy",
376
+ });
377
+ return;
378
+ }
379
+ const settings = minReviewer.settings ?? {};
380
+ const expected = REPO_STANDARD.main.minimumReviewers;
381
+ const problems: string[] = [];
382
+ if (minReviewer.isBlocking !== expected.isBlocking) problems.push(`isBlocking must be ${expected.isBlocking}`);
383
+ if ((settings.minimumApproverCount ?? 0) < expected.minimumApproverCount)
384
+ problems.push(`minimumApproverCount must be at least ${expected.minimumApproverCount}`);
385
+ if (Boolean(settings.creatorVoteCounts) !== expected.creatorVoteCounts)
386
+ problems.push(`creatorVoteCounts must be ${expected.creatorVoteCounts}`);
387
+ if (Boolean(settings.resetOnSourcePush) !== expected.resetOnSourcePush)
388
+ problems.push(`resetOnSourcePush must be ${expected.resetOnSourcePush}`);
389
+ if (problems.length === 0) return;
390
+ drifts.push({
391
+ id: "main.minimum-reviewers-misconfigured",
392
+ message: `main minimum-reviewer policy (#${minReviewer.id}) is misconfigured: ${problems.join("; ")}`,
393
+ });
394
+ }
395
+
396
+ function checkMainMergeStrategy(policies: readonly PolicyConfiguration[], drifts: RepoDoctorDrift[]): void {
397
+ const merge = enabledPolicyOfType(policies, POLICY_TYPE.mergeStrategy);
398
+ if (!merge) {
399
+ drifts.push({
400
+ id: "main.merge-strategy-missing",
401
+ message: "main is missing an enabled merge-strategy policy restricting merges to no-fast-forward",
402
+ });
403
+ return;
404
+ }
405
+ const settings = merge.settings ?? {};
406
+ const expected = REPO_STANDARD.main.mergeStrategy;
407
+ const noFastForwardOnly =
408
+ Boolean(settings.allowSquash) === expected.allowSquash &&
409
+ Boolean(settings.allowRebase) === expected.allowRebase &&
410
+ Boolean(settings.allowRebaseMerge) === expected.allowRebaseMerge &&
411
+ Boolean(settings.allowNoFastForward) === expected.allowNoFastForward;
412
+ if (noFastForwardOnly) return;
413
+ drifts.push({
414
+ id: "main.merge-strategy-not-no-ff-only",
415
+ message: `main merge-strategy policy (#${merge.id}) does not restrict merges to no-fast-forward only`,
416
+ });
417
+ }
418
+
419
+ function checkMainCommentsAndBuild(
420
+ policies: readonly PolicyConfiguration[],
421
+ hasPipeline: boolean,
422
+ drifts: RepoDoctorDrift[],
423
+ ): void {
424
+ const comments = enabledPolicyOfType(policies, POLICY_TYPE.commentRequirements);
425
+ if (!comments) {
426
+ drifts.push({
427
+ id: "main.comment-requirements-missing",
428
+ message: "main is missing an enabled comment-requirements policy",
429
+ });
430
+ }
431
+
432
+ if (!hasPipeline) return;
433
+ const build = enabledPolicyOfType(policies, POLICY_TYPE.build);
434
+ if (!build) drifts.push({ id: "main.build-validation-missing", message: "missing build validation" });
435
+ }
436
+
437
+ function checkMainPolicies(
438
+ policies: readonly PolicyConfiguration[],
439
+ hasPipeline: boolean,
440
+ drifts: RepoDoctorDrift[],
441
+ ): void {
442
+ checkMainRequiredReviewer(policies, drifts);
443
+ checkMainMinimumReviewers(policies, drifts);
444
+ checkMainMergeStrategy(policies, drifts);
445
+ checkMainCommentsAndBuild(policies, hasPipeline, drifts);
446
+ }
447
+
448
+ /**
449
+ * One Access Control Lists Query call for `token`. `descriptors` narrows the
450
+ * ACEs returned (comma-separated, per the REST docs); omitted or empty means
451
+ * "every ACE on this token", which is how `resolveBuildServiceDescriptor()`
452
+ * below finds a descriptor it does not know yet.
453
+ */
454
+ async function fetchAccessControlLists(
455
+ namespaceId: string,
456
+ token: string,
457
+ descriptors?: readonly string[],
458
+ ): Promise<AccessControlListsResponse> {
459
+ const params = new URLSearchParams({ token, includeExtendedInfo: "true", "api-version": "7.1" });
460
+ if (descriptors && descriptors.length > 0) params.set("descriptors", descriptors.join(","));
461
+ const url = `${orgBaseUrl()}/_apis/accesscontrollists/${namespaceId}?${params.toString()}`;
462
+ return fetchJson<AccessControlListsResponse>(url, "Access control lists query");
463
+ }
464
+
465
+ async function fetchEffectivePermissions(
466
+ namespaceId: string,
467
+ token: string,
468
+ descriptors: readonly string[],
469
+ ): Promise<Map<string, { allow: number; deny: number }>> {
470
+ const byDescriptor = new Map<string, { allow: number; deny: number }>();
471
+ if (descriptors.length === 0) return byDescriptor;
472
+ const result = await fetchAccessControlLists(namespaceId, token, descriptors);
473
+ for (const acl of result.value ?? []) {
474
+ for (const [descriptor, ace] of Object.entries(acl.acesDictionary ?? {})) {
475
+ byDescriptor.set(descriptor, {
476
+ allow: ace.extendedInfo?.effectiveAllow ?? ace.allow ?? 0,
477
+ deny: ace.extendedInfo?.effectiveDeny ?? ace.deny ?? 0,
478
+ });
479
+ }
480
+ }
481
+ return byDescriptor;
482
+ }
483
+
484
+ /** Resolves every agent's Graph descriptor, reporting an unresolved name as its own drift rather than throwing. */
485
+ async function resolveAgentDescriptors(drifts: RepoDoctorDrift[]): Promise<Map<string, string>> {
486
+ const descriptorByAgent = new Map<string, string>();
487
+ for (const name of Object.keys(REPO_STANDARD.permissions.agents)) {
488
+ const descriptor = await resolveAgentDescriptor(name);
489
+ if (!descriptor) {
490
+ drifts.push({
491
+ id: `permissions.${name}.not-found`,
492
+ message: `could not resolve a Graph descriptor for '${name}' (Graph subject query returned no exact display-name match)`,
493
+ });
494
+ continue;
495
+ }
496
+ descriptorByAgent.set(name, descriptor);
497
+ }
498
+ return descriptorByAgent;
499
+ }
500
+
501
+ function checkAgentBits(
502
+ name: string,
503
+ ace: { allow: number; deny: number },
504
+ expected: { allow: readonly PermissionBitName[]; deny: readonly PermissionBitName[] },
505
+ drifts: RepoDoctorDrift[],
506
+ ): void {
507
+ for (const bitName of expected.allow) {
508
+ if ((ace.allow & GIT_REPO_PERMISSION_BIT[bitName]) === 0) {
509
+ drifts.push({
510
+ id: `permissions.${name}.missing-${bitName}`,
511
+ message: `${name} does not effectively have ${bitName} on this repository`,
512
+ });
513
+ }
514
+ }
515
+ for (const bitName of expected.deny) {
516
+ if ((ace.allow & GIT_REPO_PERMISSION_BIT[bitName]) !== 0) {
517
+ drifts.push({
518
+ id: `permissions.${name}.has-${bitName}`,
519
+ message: `${name} effectively has ${bitName} on this repository, which the standard forbids`,
520
+ });
521
+ }
522
+ }
523
+ }
524
+
525
+ async function checkAgentPermissions(
526
+ projectId: string | undefined,
527
+ repositoryId: string,
528
+ drifts: RepoDoctorDrift[],
529
+ ): Promise<void> {
530
+ if (!projectId) {
531
+ drifts.push({
532
+ id: "permissions.no-project-id",
533
+ message: "could not determine the project id needed to build the permissions token",
534
+ });
535
+ return;
536
+ }
537
+ const descriptorByAgent = await resolveAgentDescriptors(drifts);
538
+
539
+ const token = `repoV2/${projectId}/${repositoryId}`;
540
+ const effective = await fetchEffectivePermissions(REPO_STANDARD.permissions.namespaceId, token, [
541
+ ...descriptorByAgent.values(),
542
+ ]);
543
+
544
+ for (const [name, expected] of Object.entries(REPO_STANDARD.permissions.agents)) {
545
+ const descriptor = descriptorByAgent.get(name);
546
+ if (!descriptor) continue; // already reported above
547
+ checkAgentBits(name, effective.get(descriptor) ?? { allow: 0, deny: 0 }, expected, drifts);
548
+ }
549
+ }
550
+
551
+ /**
552
+ * The Git Repositories token for a branch is `<repoToken>/refs/heads/<hex>`,
553
+ * where `<hex>` is the branch's ref name UTF-16LE-encoded and hex-dumped —
554
+ * https://devblogs.microsoft.com/devops/git-repo-tokens-for-the-security-service/,
555
+ * the same encoding
556
+ * ADL-ISMS-Policies/.scratchpad/ci_build_service_grant.py uses
557
+ * (`"integration".encode("utf-16-le")`). Branch names here are ASCII, so a
558
+ * plain per-character two-byte little-endian dump matches it exactly.
559
+ */
560
+ export function refNameHexUtf16Le(name: string): string {
561
+ let hex = "";
562
+ for (let i = 0; i < name.length; i += 1) {
563
+ const code = name.charCodeAt(i);
564
+ hex += (code & 0xff).toString(16).padStart(2, "0");
565
+ hex += ((code >> 8) & 0xff).toString(16).padStart(2, "0");
566
+ }
567
+ return hex;
568
+ }
569
+
570
+ /**
571
+ * The project's build service identity is not resolved through Graph (it is
572
+ * a `Microsoft.TeamFoundation.ServiceIdentity` descriptor, not a Graph
573
+ * subject) — it is found the same way
574
+ * ADL-ISMS-Policies/.scratchpad/ci_build_service_grant.py finds it: read the
575
+ * PROJECT-level ACL for this namespace (token `repoV2/<projectId>`, no
576
+ * descriptor filter — every ACE on that token comes back) and take the one
577
+ * service-identity descriptor that carries the project id.
578
+ */
579
+ async function resolveBuildServiceDescriptor(namespaceId: string, projectId: string): Promise<string | undefined> {
580
+ const result = await fetchAccessControlLists(namespaceId, `repoV2/${projectId}`);
581
+ for (const acl of result.value ?? []) {
582
+ for (const descriptor of Object.keys(acl.acesDictionary ?? {})) {
583
+ if (descriptor.startsWith("Microsoft.TeamFoundation.ServiceIdentity") && descriptor.includes(projectId))
584
+ return descriptor;
585
+ }
586
+ }
587
+ return undefined;
588
+ }
589
+
590
+ /**
591
+ * CI needs to push and complete PRs on the repo itself, and needs to bypass
592
+ * policy only on `integration` (so its own version-bump commit is not
593
+ * blocked by the very policies it satisfies) — never on `main`, where a
594
+ * bypass would defeat the human-reviewer gate entirely.
595
+ */
596
+ async function checkBuildServicePermissions(
597
+ namespaceId: string,
598
+ projectId: string | undefined,
599
+ repositoryId: string,
600
+ drifts: RepoDoctorDrift[],
601
+ ): Promise<void> {
602
+ if (!projectId) return; // already reported by checkAgentPermissions()
603
+
604
+ const descriptor = await resolveBuildServiceDescriptor(namespaceId, projectId);
605
+ if (!descriptor) {
606
+ drifts.push({
607
+ id: "permissions.build-service.not-found",
608
+ message: `could not resolve the project's build service identity (Microsoft.TeamFoundation.ServiceIdentity;...${projectId}...) on the Git Repositories namespace`,
609
+ });
610
+ return;
611
+ }
612
+
613
+ const repoToken = `repoV2/${projectId}/${repositoryId}`;
614
+ const repoEffective = (await fetchEffectivePermissions(namespaceId, repoToken, [descriptor])).get(descriptor) ?? {
615
+ allow: 0,
616
+ deny: 0,
617
+ };
618
+ for (const bitName of REPO_STANDARD.permissions.buildService.repo.allow) {
619
+ if ((repoEffective.allow & GIT_REPO_PERMISSION_BIT[bitName]) === 0) {
620
+ drifts.push({
621
+ id: `permissions.build-service.missing-${bitName}`,
622
+ message: `the project build service does not effectively have ${bitName} on this repository`,
623
+ });
624
+ }
625
+ }
626
+
627
+ const integrationToken = `${repoToken}/refs/heads/${refNameHexUtf16Le("integration")}`;
628
+ const integrationEffective = (await fetchEffectivePermissions(namespaceId, integrationToken, [descriptor])).get(
629
+ descriptor,
630
+ ) ?? { allow: 0, deny: 0 };
631
+ for (const bitName of REPO_STANDARD.permissions.buildService.integrationRef.allow) {
632
+ if ((integrationEffective.allow & GIT_REPO_PERMISSION_BIT[bitName]) === 0) {
633
+ drifts.push({
634
+ id: `permissions.build-service.missing-${bitName}-integration`,
635
+ message: `the project build service does not effectively have ${bitName} on refs/heads/integration`,
636
+ });
637
+ }
638
+ }
639
+
640
+ const mainToken = `${repoToken}/refs/heads/${refNameHexUtf16Le("main")}`;
641
+ const mainEffective = (await fetchEffectivePermissions(namespaceId, mainToken, [descriptor])).get(descriptor) ?? {
642
+ allow: 0,
643
+ deny: 0,
644
+ };
645
+ for (const bitName of REPO_STANDARD.permissions.buildService.mainRef.deny) {
646
+ if ((mainEffective.allow & GIT_REPO_PERMISSION_BIT[bitName]) !== 0) {
647
+ drifts.push({
648
+ id: `permissions.build-service.has-${bitName}-main`,
649
+ message: `the project build service effectively has ${bitName} on refs/heads/main, which the standard forbids`,
650
+ });
651
+ }
652
+ }
653
+ }
654
+
655
+ /** "<project> Build Service (<org>)" / "Project Collection Build Service (<org>)" — the exact Security-tab display names of the two identities that could actually be running the pipeline. */
656
+ function buildServiceDisplayNames(org: string, project: string): { projectScoped: string; collectionScoped: string } {
657
+ return {
658
+ projectScoped: `${project} Build Service (${org})`,
659
+ collectionScoped: `Project Collection Build Service (${org})`,
660
+ };
661
+ }
662
+
663
+ /** Stable, readable drift-id fragment from a display name, e.g. "Enact Build Service (amsterdamdatalabs)" -> "enact-build-service-amsterdamdatalabs". */
664
+ function identitySlug(displayName: string): string {
665
+ return displayName
666
+ .toLowerCase()
667
+ .replace(/[^a-z0-9]+/g, "-")
668
+ .replace(/^-+|-+$/g, "");
669
+ }
670
+
671
+ function releaseFixPath(repository: string, identityDisplayName: string, bitName: PermissionBitName): string {
672
+ return `Project settings → Repositories → \`${repository}\` → Security → \`${identityDisplayName}\` → \`${GIT_REPO_PERMISSION_UI_LABEL[bitName]}\` = Allow`;
673
+ }
674
+
675
+ /**
676
+ * Which build service identity actually runs the pipeline, per Build —
677
+ * General Settings — Get's `enforceJobAuthScope` (file header) — "Limit job
678
+ * authorization scope to current project" in the UI: true means the
679
+ * PROJECT-scoped build service runs the job, false means the
680
+ * ORG/COLLECTION-scoped one does. `undefined` means the read itself failed
681
+ * (the calling agent may lack rights to read project settings) — "could not
682
+ * determine", not "assume project-scoped": the caller checks BOTH identities
683
+ * in that case rather than guessing one and staying silent about the other.
684
+ */
685
+ async function fetchEnforceJobAuthScope(c: AdoClient): Promise<boolean | undefined> {
686
+ try {
687
+ const result = await c.get<BuildGeneralSettingsResponse>("/build/generalsettings", { "api-version": "7.1" });
688
+ return result.enforceJobAuthScope;
689
+ } catch {
690
+ return undefined;
691
+ }
692
+ }
693
+
694
+ /**
695
+ * One identity's answer to "can it release": resolve its descriptor by exact
696
+ * display name (Identities — Read Identities, file header), then check the
697
+ * three REPO_STANDARD.permissions.buildServiceRelease.required bits on the
698
+ * repository token. Every failure mode is its own loud, distinct drift — an
699
+ * unresolvable identity, an ACL the calling agent cannot read, and each
700
+ * missing permission named with its fix path — never a silent pass.
701
+ */
702
+ async function checkOneBuildServiceCanRelease(
703
+ namespaceId: string,
704
+ repoToken: string,
705
+ repository: string,
706
+ displayName: string,
707
+ drifts: RepoDoctorDrift[],
708
+ ): Promise<void> {
709
+ const slug = identitySlug(displayName);
710
+
711
+ let descriptor: string | undefined;
712
+ try {
713
+ descriptor = await resolveIdentityByDisplayName(displayName);
714
+ } catch (error) {
715
+ const detail = error instanceof Error ? error.message : String(error);
716
+ drifts.push({
717
+ id: `permissions.release.${slug}.identity-lookup-failed`,
718
+ message: `could not look up the Azure DevOps identity '${displayName}' (Identities - Read Identities call failed) — cannot confirm it can release: ${detail}`,
719
+ });
720
+ return;
721
+ }
722
+ if (!descriptor) {
723
+ drifts.push({
724
+ id: `permissions.release.${slug}.not-found`,
725
+ message: `could not resolve an Azure DevOps identity named '${displayName}' (Identities - Read Identities returned no exact display-name match) — cannot confirm it can release`,
726
+ });
727
+ return;
728
+ }
729
+
730
+ let effective: { allow: number; deny: number };
731
+ try {
732
+ effective = (await fetchEffectivePermissions(namespaceId, repoToken, [descriptor])).get(descriptor) ?? {
733
+ allow: 0,
734
+ deny: 0,
735
+ };
736
+ } catch (error) {
737
+ const detail = error instanceof Error ? error.message : String(error);
738
+ drifts.push({
739
+ id: `permissions.release.${slug}.acl-read-forbidden`,
740
+ message: `could not read the Git Repositories security ACL for '${displayName}' on '${repository}' — the calling agent identity may lack rights to read repository security, so this cannot be confirmed either way: ${detail}`,
741
+ });
742
+ return;
743
+ }
744
+
745
+ for (const bitName of REPO_STANDARD.permissions.buildServiceRelease.required) {
746
+ if ((effective.allow & GIT_REPO_PERMISSION_BIT[bitName]) !== 0) continue;
747
+ drifts.push({
748
+ id: `permissions.release.${slug}.missing-${bitName}`,
749
+ 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)}`,
750
+ });
751
+ }
752
+ }
753
+
754
+ /**
755
+ * checkBuildServiceCanRelease() — see the file header for the real failure
756
+ * (agent-identities build 4897, TF401027 on PullRequestContribute) this
757
+ * exists to catch loudly instead of at pipeline-run time. Picks ONE identity
758
+ * to check when the project's own pipeline settings say which one runs the
759
+ * job; when that read itself fails, checks BOTH the project-scoped and the
760
+ * collection-scoped identity and reports each on its own.
761
+ */
762
+ async function checkBuildServiceCanRelease(
763
+ c: AdoClient,
764
+ namespaceId: string,
765
+ projectId: string | undefined,
766
+ repositoryId: string,
767
+ repository: string,
768
+ drifts: RepoDoctorDrift[],
769
+ ): Promise<void> {
770
+ if (!projectId) return; // already reported by checkAgentPermissions()
771
+
772
+ const { projectScoped, collectionScoped } = buildServiceDisplayNames(resolveOrg(), resolveProject());
773
+ const enforceJobAuthScope = await fetchEnforceJobAuthScope(c);
774
+ const displayNames =
775
+ enforceJobAuthScope === true
776
+ ? [projectScoped]
777
+ : enforceJobAuthScope === false
778
+ ? [collectionScoped]
779
+ : [projectScoped, collectionScoped];
780
+
781
+ const repoToken = `repoV2/${projectId}/${repositoryId}`;
782
+ for (const displayName of displayNames) {
783
+ await checkOneBuildServiceCanRelease(namespaceId, repoToken, repository, displayName, drifts);
784
+ }
785
+ }
786
+
787
+ /**
788
+ * Read-only check of `repository` (default: the current checkout's origin)
789
+ * against the two-branch standard (REPO_STANDARD above). Never mutates
790
+ * anything in Azure DevOps. Throws only on identity/auth/transport failure —
791
+ * a compliance drift is reported in the returned list, not thrown.
792
+ */
793
+ export async function repoDoctorCheck(options: RepoDoctorOptions = {}): Promise<RepoDoctorReport> {
794
+ resolveAgentIdentity();
795
+ const repository = resolveRepository(options.repository);
796
+ const c = options.client ?? new AdoClient();
797
+ const drifts: RepoDoctorDrift[] = [];
798
+
799
+ const repoInfo = await c.get<GitRepositoryResponse>(`/git/repositories/${repository}`, { "api-version": "7.1" });
800
+ const repositoryId = repoInfo.id;
801
+ const projectId = repoInfo.project?.id;
802
+
803
+ const refs = await c.get<GitRefsResponse>(`/git/repositories/${repositoryId}/refs`, {
804
+ filter: "heads/",
805
+ "api-version": "7.1",
806
+ });
807
+ const branchNames = new Set((refs.value ?? []).map((ref) => ref.name.replace(/^refs\/heads\//, "")));
808
+
809
+ for (const required of REPO_STANDARD.branches.required) {
810
+ if (!branchNames.has(required))
811
+ drifts.push({ id: `branches.missing-${required}`, message: `branch '${required}' does not exist` });
812
+ }
813
+ for (const forbidden of REPO_STANDARD.branches.forbidden) {
814
+ if (branchNames.has(forbidden))
815
+ drifts.push({
816
+ id: `branches.forbidden-${forbidden}`,
817
+ message: `branch '${forbidden}' exists and must be removed`,
818
+ });
819
+ }
820
+ const defaultBranch = (repoInfo.defaultBranch ?? "").replace(/^refs\/heads\//, "");
821
+ if (defaultBranch !== REPO_STANDARD.branches.defaultBranch) {
822
+ drifts.push({
823
+ id: "branches.default-branch",
824
+ message: `default branch is '${defaultBranch || "(unset)"}', expected '${REPO_STANDARD.branches.defaultBranch}'`,
825
+ });
826
+ }
827
+
828
+ const hasPipeline = await repositoryHasAPipeline(c, repositoryId);
829
+ const integrationPolicies = await fetchBranchPolicies(c, repositoryId, "integration");
830
+ const mainPolicies = await fetchBranchPolicies(c, repositoryId, "main");
831
+ checkIntegrationPolicies(integrationPolicies, hasPipeline, drifts);
832
+ checkMainPolicies(mainPolicies, hasPipeline, drifts);
833
+
834
+ await checkAgentPermissions(projectId, repositoryId, drifts);
835
+ await checkBuildServicePermissions(REPO_STANDARD.permissions.namespaceId, projectId, repositoryId, drifts);
836
+ await checkBuildServiceCanRelease(c, REPO_STANDARD.permissions.namespaceId, projectId, repositoryId, repository, drifts);
837
+
838
+ return { repository, compliant: drifts.length === 0, drifts };
839
+ }