@amsterdamdatalabs/adl-agent-control-linux-x64 0.1.30 → 0.1.33

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 (199) hide show
  1. package/bin/adl +2 -2
  2. package/bin/health-check +2 -2
  3. package/bin/reconcile +41 -21
  4. package/bin/setup +2 -1
  5. package/package.json +1 -1
  6. package/packages/agent-hooks/README.md +77 -8
  7. package/packages/agent-hooks/assets/opencode-plugin.template.ts +2 -6
  8. package/packages/agent-hooks/src/deploy/opencode-template.ts +5 -3
  9. package/packages/agent-hooks/src/hooks/crg/background.ts +7 -4
  10. package/packages/agent-hooks/src/hooks/log.ts +12 -12
  11. package/packages/agent-hooks/src/log/writer.ts +170 -24
  12. package/packages/agent-hooks/src/main.ts +1 -1
  13. package/packages/agent-hooks/src/rules/impl/adl-git-push-policy.ts +5 -4
  14. package/packages/agent-hooks/src/rules/impl/mcp-tool.ts +1 -1
  15. package/packages/agent-hooks/src/rules/shell/invocation.ts +2 -1
  16. package/packages/agent-hooks/src/rules/shell/protected-carriers.ts +19 -5
  17. package/packages/agent-settings/assets/GLOBAL-AGENTS.md +1 -1
  18. package/packages/agent-skills/assets/agent-search-tool-audit/SKILL.md +24 -2
  19. package/packages/agent-skills/assets/agent-search-tool-audit/scripts/audit.sh +19 -45
  20. package/packages/agent-skills/assets/diagnosing-bugs/SKILL.md +9 -0
  21. package/packages/agent-skills/assets/diagnosing-bugs/scripts/hitl-loop.template.sh +1 -12
  22. package/packages/azdo/src/lib/commit-types.ts +8 -0
  23. package/packages/azdo/src/lib/validate-pr-metadata.ts +4 -1
  24. package/packages/fleet/manifest.json +2 -1
  25. package/packages/fleet/src/repo-maintain.ts +5 -2
  26. package/packages/repo-controls/AGENTS.md +8 -5
  27. package/packages/repo-controls/README.md +348 -58
  28. package/packages/repo-controls/assets/GLOBAL-INVARIANTS.md +21 -0
  29. package/packages/repo-controls/assets/promote.ts +7 -85
  30. package/packages/repo-controls/assets/reconcile-guard.sh +1 -14
  31. package/packages/repo-controls/assets/scaffold/docs/AGENTS.md +25 -0
  32. package/packages/repo-controls/assets/scaffold/docs/CLAUDE.md +1 -0
  33. package/packages/repo-controls/assets/scaffold/docs/decisions/index.md +17 -0
  34. package/packages/repo-controls/assets/scaffold/docs/notes.md +20 -0
  35. package/packages/repo-controls/assets/scaffold/plans/AGENTS.md +28 -0
  36. package/packages/repo-controls/assets/scaffold/plans/CLAUDE.md +1 -0
  37. package/packages/repo-controls/assets/scaffold/plans/GAPS-AND-FINDINGS.md +12 -0
  38. package/packages/repo-controls/assets/scaffold/plans/LEDGER.md +8 -0
  39. package/packages/repo-controls/assets/scaffold/plans/features/.gitkeep +0 -0
  40. package/packages/repo-controls/assets/scaffold/root/AGENTS.md +22 -0
  41. package/packages/repo-controls/assets/scaffold/root/CLAUDE.md +1 -0
  42. package/packages/repo-controls/assets/scaffold/workflows/AGENTS.md +16 -0
  43. package/packages/repo-controls/assets/scaffold/workflows/CLAUDE.md +1 -0
  44. package/packages/repo-controls/assets/scaffold/workflows/pipelines/.gitkeep +0 -0
  45. package/packages/repo-controls/assets/scaffold/workflows/scripts/.gitkeep +0 -0
  46. package/packages/repo-controls/assets/version-bump.sh +7 -48
  47. package/packages/repo-controls/package/adl-compliance/AGENTS.md +25 -7
  48. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/__init__.py +6 -4
  49. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/adr_lifecycle/check.py +1 -1
  50. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/adr_lifecycle/test_check.py +1 -1
  51. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/english_only/check.py +7 -42
  52. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/english_only/fixtures/excluded/web/i18n/locales/zh-CN/strings.ts +1 -0
  53. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/english_only/test_check.py +10 -44
  54. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/architecture/ui-contract.md +1 -1
  55. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/research/UI-CONTRACT.md +1 -1
  56. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/test_check.py +1 -1
  57. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/index_updated/check.py +1 -7
  58. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/index_updated/test_check.py +12 -3
  59. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/indexes/check.py +15 -23
  60. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/indexes/docs-knowledge-indexes.yaml +0 -136
  61. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/indexes/test_check.py +18 -0
  62. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/docs-okf-profiles.yaml +2 -2
  63. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/register.py +0 -7
  64. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/semantics/check.py +2 -4
  65. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/semantics/fixtures/semantics-violations/docs/architecture/guides/stable-delivery.md +10 -0
  66. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/semantics/fixtures/semantics-violations/docs/architecture/guides/stable-recommendation.md +12 -0
  67. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/semantics/fixtures/semantics-violations/docs/architecture/guides/target-narration.md +10 -0
  68. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/semantics/test_check.py +6 -7
  69. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/ci_paths/test_check.py +3 -3
  70. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/check.py +10 -12
  71. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-clean/grants.yaml +1 -1
  72. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-clean/web/src/renderer/solo/item.ts +1 -0
  73. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-empty-register/web/src/a.ts +1 -0
  74. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-empty-register/web/src/b.ts +1 -0
  75. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/grants.yaml +1 -1
  76. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/web/src/renderer/fresh/fresh.ts +1 -0
  77. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/web/src/renderer/many/sub1/only.ts +1 -0
  78. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/web/src/renderer/many/sub10/only.ts +1 -0
  79. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/web/src/renderer/many/sub11/only.ts +1 -0
  80. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/web/src/renderer/many/sub2/only.ts +1 -0
  81. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/web/src/renderer/many/sub3/only.ts +1 -0
  82. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/web/src/renderer/many/sub4/only.ts +1 -0
  83. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/web/src/renderer/many/sub5/only.ts +1 -0
  84. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/web/src/renderer/many/sub6/only.ts +1 -0
  85. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/web/src/renderer/many/sub7/only.ts +1 -0
  86. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/web/src/renderer/many/sub8/only.ts +1 -0
  87. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/web/src/renderer/many/sub9/only.ts +1 -0
  88. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/web/src/renderer/services/i18n/locales/de/common.json +1 -0
  89. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/web/src/renderer/solo/item.ts +1 -0
  90. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/web/src/vendored-crate/Cargo.toml +2 -0
  91. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-missing-tree/grants.yaml +1 -1
  92. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-missing-tree/web/src/renderer/solo/item.ts +1 -0
  93. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-no-ceilings/grants.yaml +1 -1
  94. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-no-ceilings/web/src/a.ts +1 -0
  95. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-no-ceilings/web/src/b.ts +1 -0
  96. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-no-ceilings/web/src/c.ts +1 -0
  97. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-stale-entry/grants.yaml +2 -2
  98. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-stale-entry/web/src/renderer/solo/item.ts +1 -0
  99. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unbaselined/grants.yaml +1 -1
  100. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unbaselined/web/src/renderer/fresh/fresh.ts +1 -0
  101. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unbaselined/web/src/renderer/many/sub1/only.ts +1 -0
  102. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unbaselined/web/src/renderer/many/sub10/only.ts +1 -0
  103. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unbaselined/web/src/renderer/many/sub11/only.ts +1 -0
  104. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unbaselined/web/src/renderer/many/sub2/only.ts +1 -0
  105. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unbaselined/web/src/renderer/many/sub3/only.ts +1 -0
  106. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unbaselined/web/src/renderer/many/sub4/only.ts +1 -0
  107. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unbaselined/web/src/renderer/many/sub5/only.ts +1 -0
  108. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unbaselined/web/src/renderer/many/sub6/only.ts +1 -0
  109. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unbaselined/web/src/renderer/many/sub7/only.ts +1 -0
  110. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unbaselined/web/src/renderer/many/sub8/only.ts +1 -0
  111. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unbaselined/web/src/renderer/many/sub9/only.ts +1 -0
  112. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unbaselined/web/src/renderer/solo/item.ts +1 -0
  113. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unusable-register/web/src/renderer/solo/item.ts +1 -0
  114. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/test_check.py +46 -54
  115. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/markdown_trees/check.py +16 -76
  116. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/markdown_trees/test_check.py +35 -32
  117. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/placement/check.py +46 -213
  118. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/placement/fixtures/placement-allowed/README.md +1 -0
  119. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/placement/test_check.py +76 -194
  120. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/plans_layout/check.py +18 -2
  121. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/plans_layout/test_check.py +49 -0
  122. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/references/check.py +1 -1
  123. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/references/fixtures/link-targets-broken/docs/architecture/guides/links.md +20 -0
  124. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/references/fixtures/link-targets-broken/docs/architecture/guides/route-target.md +8 -0
  125. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/references/fixtures/link-targets-clean/docs/architecture/guides/links.md +20 -0
  126. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/references/fixtures/link-targets-clean/docs/architecture/guides/route-target.md +8 -0
  127. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/references/test_check.py +4 -4
  128. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/check.py +3 -3
  129. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/.notes/declared.txt +1 -0
  130. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/test_check.py +8 -1
  131. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_markdown_allowlist/check.py +15 -135
  132. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_markdown_allowlist/test_check.py +98 -50
  133. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/scripts_size_depth/check.py +1 -1
  134. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/scripts_size_depth/test_check.py +1 -1
  135. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/check.py +1 -1
  136. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/test_check.py +14 -10
  137. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/banned_commands/__init__.py +3 -10
  138. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/banned_commands/base.py +42 -0
  139. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/banned_commands/test_check.py +82 -49
  140. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/banned_commands/test_scope.py +71 -0
  141. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/legacy_search/__init__.py +7 -0
  142. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/legacy_search/check.py +15 -0
  143. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/legacy_search/test_check.py +32 -0
  144. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/cargo_lock.py +1 -1
  145. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/check.py +56 -124
  146. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/fixtures/clean/Cargo.lock +7 -0
  147. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/fixtures/clean/Cargo.toml +4 -0
  148. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/fixtures/clean/bun.lock +1 -0
  149. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/fixtures/clean/package.json +1 -0
  150. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/fixtures/clean/rust-toolchain.toml +3 -0
  151. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/fixtures/clean/src/main.rs +1 -0
  152. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/fixtures/empty-bun-lock/Cargo.lock +7 -0
  153. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/fixtures/empty-bun-lock/Cargo.toml +4 -0
  154. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/fixtures/empty-bun-lock/bun.lock +0 -0
  155. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/fixtures/empty-bun-lock/package.json +1 -0
  156. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/fixtures/empty-bun-lock/rust-toolchain.toml +3 -0
  157. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/fixtures/empty-bun-lock/src/main.rs +1 -0
  158. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/test_check.py +8 -37
  159. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/test_declared_paths.py +95 -130
  160. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/test_root_lockfiles.py +101 -0
  161. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/test_stale_lock.py +25 -13
  162. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/no_multiline_comments/__init__.py +7 -0
  163. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/no_multiline_comments/check.py +124 -0
  164. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/no_multiline_comments/fixtures/valid-register.yaml +4 -0
  165. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/no_multiline_comments/scanner.py +217 -0
  166. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/no_multiline_comments/test_check.py +391 -0
  167. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/vcs_in_scripts/__init__.py +7 -0
  168. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/vcs_in_scripts/check.py +16 -0
  169. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/vcs_in_scripts/test_check.py +32 -0
  170. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/cli.py +12 -1
  171. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/core/ast_grep.py +2 -3
  172. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/core/check.py +3 -0
  173. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/core/constants.py +1 -1
  174. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/core/declarations.py +24 -0
  175. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/core/receipt.py +2 -2
  176. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/core/scripts.py +120 -0
  177. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/config.py +1 -1
  178. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/config.toml +4 -4
  179. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/gate-registry.alt.yaml +93 -99
  180. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/gate-registry.yaml +93 -99
  181. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/registry.py +1 -1
  182. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/root_shape.py +6 -47
  183. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/runner.py +54 -8
  184. package/packages/repo-controls/scripts/hooks/commit-msg +1 -1
  185. package/packages/repo-controls/scripts/hooks/pre-commit +12 -2
  186. package/packages/repo-controls/scripts/hooks/pre-push +27 -19
  187. package/packages/repo-controls/src/cli.ts +22 -3
  188. package/packages/repo-controls/src/compliance-config.ts +132 -65
  189. package/packages/repo-controls/src/config.ts +62 -52
  190. package/packages/repo-controls/src/constants.ts +9 -0
  191. package/packages/repo-controls/src/coverage-ratchet.ts +19 -4
  192. package/packages/repo-controls/src/doctor.ts +20 -30
  193. package/packages/repo-controls/src/findings-ratchet.ts +14 -0
  194. package/packages/repo-controls/src/gitignore-block.ts +3 -13
  195. package/packages/repo-controls/src/hook-log.ts +7 -10
  196. package/packages/repo-controls/src/hook.ts +127 -83
  197. package/packages/repo-controls/src/install-compliance.ts +112 -0
  198. package/packages/repo-controls/src/install.ts +133 -30
  199. package/packages/repo-controls/src/integrity.ts +5 -18
@@ -1,52 +1,8 @@
1
- // Managed by adl-repo-controls — do not edit.
2
- // Regenerate with: adl-repo-controls install --repo .
3
- //
4
- // Vendored into `.workflows/` byte-for-byte so CI depends on nothing: no
5
- // adl-repo-controls on PATH, no MCP client, no package install. A pipeline
6
- // agent is a cold environment, and a promotion that needs a global npm binary
7
- // fails there for reasons that have nothing to do with the promotion.
8
- //
9
- // Byte-identical in every repository, deliberately. Refs come from the
10
- // environment, never baked in — otherwise each consumer's copy would hash
11
- // differently and one published hash could not verify any of them.
1
+ // Managed by adl-repo-controls, do not edit; regenerate with: adl-repo-controls install --repo . (README "Managed workflow scripts").
12
2
 
13
- /**
14
- * Promote one branch to another through an Azure DevOps pull request.
15
- *
16
- * Standard, not repo-local: every repository in this estate is on Azure DevOps,
17
- * and promoting a branch to its trunk is find-or-reuse a PR, then set
18
- * auto-complete. Ported from enact-m5's `workflows/scripts/release/
19
- * promote-main.ts`, where the mechanism was already injectable — fetch,
20
- * collection, project, repository and token were all parameters — and only
21
- * three module-scoped literals made it that repository's:
22
- *
23
- * SOURCE_REF = 'refs/heads/integration'
24
- * TARGET_REF = 'refs/heads/main'
25
- * title = 'release: promote integration to main'
26
- *
27
- * The refs are declared as `[controls.release].source` / `.target`. The title is
28
- * DERIVED from them rather than being a third key: a title that can disagree
29
- * with the refs it describes is a bug waiting for someone to change one and
30
- * forget the other, and the derived form satisfies this package's own
31
- * commit-msg grammar for any pair.
32
- *
33
- * The target branch's gate is Tarun's approval alone (Tarun, 2026-09-30): the
34
- * promotion PR gets NO build validation and CD runs after the merge into the
35
- * target. The pre-flight proves the minimum-reviewer policy (>=1 approver,
36
- * resetOnSourcePush=true) and does not require a build policy.
37
- *
38
- * There is no default pair. Defaulting to integration -> main would put one
39
- * repository's branch names back into the package by the back door.
40
- */
3
+ /** Promote one branch to another through an Azure DevOps pull request; see README "Managed workflow scripts". */
41
4
 
42
- /**
43
- * Azure DevOps' `GitPullRequestCompletionOptions.mergeStrategy`, by name.
44
- * The REST API's wire values are the camelCase strings below (confirmed
45
- * against a live PR: sending the numeric `GitPullRequestMergeStrategy` enum
46
- * ordinal here is silently accepted by the type system but is not what the
47
- * API expects — PR 1477, 2026-09-27, armed auto-complete with `rebase`
48
- * although "no-fast-forward" was intended). `squash` is the standard.
49
- */
5
+ /** Azure DevOps' `mergeStrategy` by name; see README "Managed workflow scripts". */
50
6
  export const MERGE_STRATEGIES = {
51
7
  squash: 'squash',
52
8
  rebase: 'rebase',
@@ -68,12 +24,7 @@ export interface PromotionRequest {
68
24
  /** Declared branch names, WITHOUT the `refs/heads/` prefix. */
69
25
  source?: string
70
26
  target?: string
71
- /**
72
- * Azure's `GitPullRequestMergeStrategy`. Defaults to the standard the MCP
73
- * server defines -- its PR tool admits `enum: ['Squash']` and nothing else.
74
- * A repository wanting something else declares it, so the deviation is
75
- * visible instead of welded into this file.
76
- */
27
+ /** Azure's `GitPullRequestMergeStrategy`; see README "Managed workflow scripts". */
77
28
  mergeStrategy?: MergeStrategy
78
29
  }
79
30
 
@@ -192,26 +143,7 @@ export interface PromotionPolicyReceipts {
192
143
  build: PolicyConfiguration | null
193
144
  }
194
145
 
195
- /**
196
- * The one policy contract used by both promotion and doctor. A configuration
197
- * only counts when it is enabled, blocking, and scoped exactly to the target
198
- * branch; a project-wide or path-filtered lookalike cannot guard a promotion.
199
- *
200
- * The target's gate is the minimum-reviewer policy ONLY (Tarun, 2026-09-30):
201
- * the integration -> main promotion PR gets no build validation, Tarun's
202
- * approval is the only gate, and CD runs after the merge into main. Promotion
203
- * therefore never requires a build policy. `build` is still reported so a
204
- * caller can show one that happens to be present, but nothing here demands it.
205
- *
206
- * No named-reviewer policy is checked here, deliberately (Tarun,
207
- * 2026-09-27): the two-branch standard's `main` gate is "exactly one human
208
- * reviewer, author's vote excluded" via the minimum-reviewer policy below —
209
- * never a specific named individual. A required-reviewer-by-identity policy
210
- * on `main` was PR 1477's second live bug: it named the person who pushed to
211
- * `integration` as a mandatory approver, which both self-approves (that
212
- * person is usually the change's author) and contradicts "agent-reviewer is
213
- * optional, never required".
214
- */
146
+ /** The one policy contract used by promotion and doctor (see README "Managed workflow scripts"). */
215
147
  export function promotionPolicyReceipts(
216
148
  policies: readonly PolicyConfiguration[],
217
149
  { repositoryId, targetRef }: PromotionPolicyRequirement,
@@ -326,11 +258,7 @@ export async function ensurePromotionPullRequest({
326
258
  status = 'created'
327
259
  }
328
260
 
329
- // No reviewer is named here, deliberately (Tarun, 2026-09-27): naming one —
330
- // typically the person who pushed to `integration` — is a self-approval
331
- // risk and contradicts "agent-reviewer is optional, never required". The
332
- // gate is the target branch's own minimum-reviewer policy (verified above),
333
- // which excludes the author's own vote.
261
+ // No reviewer is named: see README "Managed workflow scripts".
334
262
  await azureRequest(fetchImpl, `${repositoryUrl}/pullrequests/${pullRequest.pullRequestId}?api-version=7.1`, authToken, {
335
263
  method: 'PATCH',
336
264
  body: JSON.stringify({
@@ -347,13 +275,7 @@ export async function ensurePromotionPullRequest({
347
275
  }
348
276
 
349
277
 
350
- /**
351
- * Standalone entry point. Reads the refs from the ENVIRONMENT, not from config:
352
- * this file is vendored into `.workflows/` byte-for-byte, so its content must
353
- * be identical in every repository or a single published hash cannot verify
354
- * any of them. The pipeline supplies the repository-specific values through
355
- * environment variables while the managed implementation stays identical.
356
- */
278
+ /** Standalone entry point; refs come from the environment (see README "Managed workflow scripts"). */
357
279
  export async function main(env: Record<string, string | undefined> = process.env): Promise<void> {
358
280
  const result = await ensurePromotionPullRequest({
359
281
  collectionUri: env.AZURE_DEVOPS_COLLECTION_URI,
@@ -1,20 +1,7 @@
1
1
  #!/usr/bin/env bash
2
2
  set -euo pipefail
3
3
 
4
- # Stage 1 of the CI pipeline for pull requests into `integration` (stage 2
5
- # runs the tests). It forces the PR author, usually an agent, to reconcile with
6
- # integration before anything merges:
7
- #
8
- # the PR source branch contains integration's tip
9
- #
10
- # That is the only check. The version bump is not a PR concern any more: the
11
- # integration-merge pipeline bumps after the merge (Tarun, 2026-10-01).
12
- #
13
- # Read-only: this script only fetches and reads. It never pushes, and the only
14
- # refs it writes are the two remote-tracking refs it fetches.
15
-
16
- # CI never carries an agent identity. Never set one here, and never inherit
17
- # one from the caller.
4
+ # Stage 1 PR guard; see README "Managed workflow scripts".
18
5
  unset ADL_AGENT_ID_AGENT
19
6
 
20
7
  die() {
@@ -0,0 +1,25 @@
1
+ # docs/ — what belongs here
2
+
3
+ Reference documentation for this repository: how it works and why it is shaped
4
+ the way it is.
5
+
6
+ ## Layout
7
+
8
+ - Standing reference pages live directly under this directory, one topic per
9
+ page.
10
+ - Sub-directories group related pages (for example `decisions/` for
11
+ architecture decision records, `research/` for dated investigations). Add one
12
+ only when it has pages to hold.
13
+ - `notes.md` is the repository's task ledger: one line when an agent starts a
14
+ task and one when it finishes.
15
+
16
+ ## Conventions
17
+
18
+ - Every page carries YAML frontmatter with at least `type`, `title`,
19
+ `description`, `status` and `last_update` (ISO-8601 UTC,
20
+ `YYYY-MM-DDTHH:MM:SSZ`).
21
+ - `notes.md` is append-only: newest line at the bottom, earlier lines are never
22
+ rewritten. Format `YYYY-MM-DD HH:MM <surface> <note>`, at most 100
23
+ characters per line.
24
+ - A page that is catalogued in an index stays listed there; add the entry in
25
+ the same change that adds or renames the page.
@@ -0,0 +1,17 @@
1
+ ---
2
+ last_update: '2026-10-08T00:00:00Z'
3
+ title: Architecture decision records
4
+ description: The index of this repository's architecture decision records, one adr-<slug>.md page per decision.
5
+ type: Reference
6
+ status: stable
7
+ sources: the repository's documentation conventions (decision records)
8
+ ---
9
+
10
+ # Architecture decision records
11
+
12
+ One page per decision, named `adr-<slug>.md`. Each carries an inline
13
+ `**Status:**` line (OPEN, DECIDED or STABLE) and the backlinks that state owes.
14
+
15
+ ## Decisions
16
+
17
+ None yet. List each new record here in the same change that adds it.
@@ -0,0 +1,20 @@
1
+ ---
2
+ last_update: '2026-10-08T00:00:00Z'
3
+ title: Agent notes ledger
4
+ description: One append-only ledger per repository for every agent, one line when you start a task and one when you finish it.
5
+ type: Operations
6
+ status: stable
7
+ sources: the repository's agent rules (task ledger convention)
8
+ ---
9
+
10
+ # Agent notes ledger
11
+
12
+ A short, append-only log so anyone landing in the repository can see at a glance
13
+ what every agent is doing. Every line is at most 100 characters, format
14
+ `YYYY-MM-DD HH:MM <surface> <note>` (for example
15
+ `2026-10-08 13:30 claude start: add retry to the uploader`). Agents append one
16
+ line when they start a task and one when they finish it. The ledger is never
17
+ edited or sorted; earlier lines are never rewritten, only appended to, newest
18
+ at the bottom.
19
+
20
+ ## Lines
@@ -0,0 +1,28 @@
1
+ # plans/ — what belongs here
2
+
3
+ Work items: Features, and the PBIs/Bugs that hang under them. The work-item
4
+ board is the only place status lives; the files here describe the work.
5
+
6
+ ## Layout
7
+
8
+ - `plans/features/az<id>-<slug>/spec.md` — one Feature, one file, for its whole
9
+ life. Frontmatter: `type: feature`, `title`, `status` (the board state),
10
+ `epic:` (the parent Epic's board URL), `work_item:` (this Feature's own board
11
+ URL), `last_update`. The Feature's own `## Items` table is the one place it
12
+ may list its children.
13
+ - `plans/features/az<id>-<slug>/items/az<item-id>-<slug>.md` — one PBI or Bug.
14
+ Frontmatter: `type: pbi` or `type: bug`, `title`, `status`, `feature:` (the
15
+ parent Feature's slug), `work_item:`, `last_update`.
16
+ - `plans/GAPS-AND-FINDINGS.md` — a register of gaps found while planning or
17
+ building something else. A row is deleted, not marked done, once its linked
18
+ item closes.
19
+ - `plans/LEDGER.md` — the plan-event ledger, a Markdown table, newest entry
20
+ first.
21
+
22
+ ## Conventions
23
+
24
+ - The board is the only place status lives. A file's `status:` mirrors the
25
+ board state.
26
+ - An item is allocated on the board first; the file is named `az<id>-<slug>`
27
+ only once that id exists. Files never move between directories.
28
+ - `epic:` and `feature:` are authored by hand, never tool-generated.
@@ -0,0 +1,12 @@
1
+ # Gaps and findings
2
+
3
+ Anything found while planning or building that is not the work in hand. Each row
4
+ becomes an item file with `item_type: bug`, parented under the same Feature as
5
+ the plan it was found from, so the fix stays attached to the effort that
6
+ surfaced it.
7
+
8
+ Each row states how it was verified, because a finding nobody can re-check is a
9
+ rumour. A row is deleted, not marked done, once it stops being a gap.
10
+
11
+ | Found | Finding | From plan | Item file | Work item |
12
+ | --- | --- | --- | --- | --- |
@@ -0,0 +1,8 @@
1
+ # Ledger
2
+
3
+ Plan events, newest first. Each row has a kebab-case unique `Id`, an ISO `Date`,
4
+ an `Area`, a short `Event`, and `Refs` (repository-relative paths that exist).
5
+
6
+ | Date | Id | Area | Event | Refs |
7
+ | --- | --- | --- | --- | --- |
8
+ | 2026-10-08 | plans-tree-bootstrapped | plans | Plans tree scaffolded by adl repo controls install | — |
@@ -0,0 +1,22 @@
1
+ # Agent entry point
2
+
3
+ This is the first file a human or agent should read on arriving at this
4
+ repository. Edit it to describe what this repository is; the sections below
5
+ describe the layout the adl repo controls enforce.
6
+
7
+ ## Layout
8
+
9
+ | Path | What lives there |
10
+ | --- | --- |
11
+ | `docs/` | reference documentation, see `docs/AGENTS.md` |
12
+ | `plans/` | Features and the PBIs/Bugs under them, see `plans/AGENTS.md` |
13
+ | `workflows/` | CI pipelines and build/release scripts, see `workflows/AGENTS.md` |
14
+ | `.workflows/` | managed hook stubs and lock, rebuilt by `adl repo controls install`; never hand-edit |
15
+
16
+ ## Rules
17
+
18
+ - This repository is graded by `adl-compliance` on every commit; the enabled
19
+ gates are `[controls.compliance].enabled` in `adl-config.toml`. A failing
20
+ gate is fixed, not skipped.
21
+ - `INVARIANTS.md` lists what this repository must never regress.
22
+ - Work-item status lives on the board, never in a file.
@@ -0,0 +1,16 @@
1
+ # workflows/ — what belongs here
2
+
3
+ The CI tree: pipeline definitions and the scripts they run.
4
+
5
+ ## Layout
6
+
7
+ - `workflows/pipelines/` — pipeline definitions and their shared templates.
8
+ - `workflows/scripts/` — the scripts the pipelines invoke, grouped in
9
+ sub-directories by purpose (for example `build/`, `release/`).
10
+
11
+ ## Conventions
12
+
13
+ - A script here is invoked by a pipeline, never by a git hook.
14
+ - Keep each scripts directory small; split by purpose before it grows past a
15
+ screenful of files.
16
+ - A pipeline and the scripts it references must resolve: move them together.
@@ -1,26 +1,8 @@
1
1
  #!/usr/bin/env bash
2
2
  set -euo pipefail
3
3
 
4
- # STAGE 1 of the promote pipeline (push to `integration`): the integration-merge
5
- # build owns package version allocation (Tarun, 2026-10-01 -- a PR's
6
- # build-validation policy ignores `[skip ci]`, so a bump pushed from PR CI
7
- # re-queued itself; a push to a branch honours it). After a merge lands on
8
- # `integration` this sets the manifest to that commit's version + patch 1:
9
- #
10
- # version-bump.sh --file package.json --integration --push
11
- #
12
- # The Azure Pipelines build checks out the detached commit that triggered the
13
- # run with persisted credentials, so `git push` authenticates as the project
14
- # build service (which needs Contribute + "Bypass policies when pushing" on
15
- # `integration`). The bump commit is created on that checkout, carries
16
- # `[skip ci]` so the push does not trigger this pipeline again, and is pushed
17
- # with a plain fast-forward -- never forced. If integration moved since the
18
- # checkout the push is rejected and the script fails loud; the newer merge's
19
- # own run bumps. No npm query, no PR.
20
-
21
- # CI never carries an agent identity: the push below authenticates as the
22
- # project build service through the checkout's persisted System.AccessToken.
23
- # Never set an agent identity here, and never inherit one from the caller.
4
+ # Rationale: packages/repo-controls/README.md, "Managed workflow scripts", version-bump.sh.
5
+
24
6
  unset ADL_AGENT_ID_AGENT
25
7
 
26
8
  die() {
@@ -82,13 +64,6 @@ node -e '
82
64
  fs.writeFileSync(file, `${JSON.stringify(manifest, null, 2)}\n`)
83
65
  ' "$version_file" "$next_version"
84
66
 
85
- # `[controls.release].pre_bump` (adl-config.toml, repo root): ordered,
86
- # repository-relative scripts a multi-language repo runs before the bump
87
- # commit — e.g. agent-identities updates a Go version constant nothing about
88
- # package.json can reach. No file, or no `pre_bump` key: no scripts, and
89
- # everything below this comment is a no-op, so the resulting commit is
90
- # byte-identical to the behaviour before this feature existed (see
91
- # packages/repo-controls/tests/version-bump-integration-pre-bump.test.ts).
92
67
  config_path="$repo_root/adl-config.toml"
93
68
  pre_bump_list=''
94
69
  if [[ -f "$config_path" ]]; then
@@ -129,31 +104,17 @@ if [[ -n "$pre_bump_list" ]]; then
129
104
  fi
130
105
 
131
106
  if [[ ${#pre_bump_scripts[@]} -gt 0 ]]; then
132
- # Validated before any of them run, so a bad declaration fails clearly
133
- # instead of leaving the repo half-way through a partial run.
134
107
  for script in "${pre_bump_scripts[@]}"; do
135
108
  [[ -f "$repo_root/$script" ]] || die "pre_bump script not found: $script"
136
109
  done
137
110
 
138
- # Every var whose name ends _TOKEN/_PAT/_SECRET/_PASSWORD, plus the two
139
- # Azure DevOps credentials by their exact names (SYSTEM_ACCESSTOKEN does
140
- # not end in "_TOKEN"), is stripped from each script's environment. A
141
- # pre_bump script is repo-authored, unreviewed by this package, and has no
142
- # business ever seeing the pipeline's push/PR credentials.
143
111
  unset_flags=(-u SYSTEM_ACCESSTOKEN -u AZURE_DEVOPS_EXT_PAT -u AZURE_DEVOPS_TOKEN -u AZURE_DEVOPS_PAT)
144
112
  while IFS= read -r var_name; do
145
- unset_flags+=(-u "$var_name")
146
- done < <(compgen -v | grep -Ei '_(TOKEN|PAT|SECRET|PASSWORD)$' || true)
147
-
148
- # A pre_bump script that edits `.git` directly (hooks, config, refs) would
149
- # never show up in `git status` — `.git` sits outside the working tree that
150
- # diffs against — so this is a separate, explicit check. There is no
151
- # equivalent check for a script writing to an absolute path OUTSIDE the
152
- # repository entirely: a plain shell script has no sandbox to enforce
153
- # that, so this refuses `.git` tampering only, honestly, rather than
154
- # claiming a guarantee this script cannot keep. Changes INSIDE the repo
155
- # tree are never "outside the repo" by construction: every add below is
156
- # scoped to `$repo_root`, so nothing beyond it can ever be staged.
113
+ if [[ "$var_name" =~ _([Tt][Oo][Kk][Ee][Nn]|[Pp][Aa][Tt]|[Ss][Ee][Cc][Rr][Ee][Tt]|[Pp][Aa][Ss][Ss][Ww][Oo][Rr][Dd])$ ]]; then
114
+ unset_flags+=(-u "$var_name")
115
+ fi
116
+ done < <(compgen -v)
117
+
157
118
  git_marker="$(mktemp)"
158
119
  for script in "${pre_bump_scripts[@]}"; do
159
120
  if ! ( cd "$repo_root" && env "${unset_flags[@]}" \
@@ -172,8 +133,6 @@ fi
172
133
 
173
134
  git -C "$repo_root" add -A
174
135
  git diff --cached --quiet && die "version bump produced no staged change (expected at least $version_file)"
175
- # `[skip ci]` (Azure DevOps: a push whose commits contain it does not trigger CI
176
- # pipelines) keeps this push from re-running the promote pipeline that made it.
177
136
  git commit -m "chore: bump version $current_version to $next_version [skip ci]"
178
137
  if ! git push origin "HEAD:refs/heads/integration"; then
179
138
  die "push to integration rejected: integration moved since checkout, so this bump is stale; the next merge's run bumps"
@@ -98,15 +98,15 @@ the rest, so ast-grep's next release does not fail a gate.
98
98
 
99
99
  ## The consumer's layout arrives
100
100
 
101
- A row names a logical tree; `policy/trees.toml` says where it currently lives.
101
+ A row names a logical tree; the consumer's `[controls.compliance.trees]` says where it lives (`policy/config.toml` ships no defaults).
102
102
 
103
103
  ```yaml
104
104
  scope:
105
- - <rust>/crates/**/src/*.rs # backend/crates/**/src/*.rs
106
- - <compliance>/policy/inputs/rust-policy.json
105
+ - <docs>/guides/**/*.md # documentation/guides/**/*.md
106
+ - <plans>/features/**/spec.md
107
107
  ```
108
108
 
109
- 253 of the registry's 325 scope entries are placeholders, and named-input
109
+ Most of the registry's scope entries are placeholders, and named-input
110
110
  defaults and `grants:` paths resolve through the same table — so no consumer path
111
111
  is written in this package's rows, and moving a tree is one line. `<name>`, not
112
112
  `{name}`: braces are already glob alternation and eleven rows use it. An unknown
@@ -125,8 +125,8 @@ never enter a set and no row needs to exclude `node_modules/`.
125
125
  ## Running
126
126
 
127
127
  ```bash
128
- uv run adl-compliance rust.acp-boundary
129
- uv run adl-compliance RST-001 --files changed.list
128
+ uv run adl-compliance layout.references
129
+ uv run adl-compliance DOC-001 --files changed.list
130
130
  uv run adl-compliance # every row
131
131
  ```
132
132
 
@@ -150,7 +150,7 @@ it. `tests/core/` is the one exception, for the spine (`Check`, `scope`,
150
150
 
151
151
  ## Status
152
152
 
153
- Every row of the registry is implemented — 28 of 28, counted by importing
153
+ Every row of the registry is implemented — 29 of 29, counted by importing
154
154
  `adl_compliance.checks` and measuring `len(CHECKS)` (`checks/__init__.py`'s
155
155
  explicit registry tuple), not by re-reading this paragraph. The shell
156
156
  `compliance_new/` tree this package ported from is gone, not frozen: a row
@@ -160,3 +160,21 @@ never a silent pass, and today no row reaches that.
160
160
  [`docs/operations/adl-compliance-invariants.md`](../../../../docs/operations/adl-compliance-invariants.md)
161
161
  records what is not true yet, including two rows that do not
162
162
  trigger on their own named inputs and one whose register does not exist.
163
+
164
+ ## Rationale moved out of code comments (Bug 602)
165
+
166
+ - A check that subscripts an input dropped because its tree is declared `""`
167
+ (`[controls.compliance.trees] <tree> = ""`) is could-not-run, never clean: a
168
+ clean verdict would read as a pass for a gate that graded nothing (Bug 597).
169
+ Checks that can honestly narrow (LAY-006/008/013, DOC-002) guard the read.
170
+ Any other `KeyError` is a plain crash, reported as that row's could-not-run so
171
+ it cannot erase the other rows' verdicts.
172
+ - A widening input (a register of grants) whose tree is unknown is "no register",
173
+ never an error: its absence can only grade stricter (PBI 599).
174
+ - Central root trees are only adl's own or language-neutral ones (`compliance`,
175
+ `workflows`, `bin`, `packages`, `scripts`, `src`, `tests`); any other layout is
176
+ declared under `[controls.compliance.root] dirs` (PBI 601).
177
+ - `.workflows/` is deliberately not in the root-Markdown guide list: it is
178
+ machine-managed, written wholesale by `adl-repo-controls install`.
179
+ - `markdown_trees` root names come from `[controls.compliance.root] files` and
180
+ match exactly; a glob is refused by `declared_root_files`.
@@ -36,16 +36,16 @@ from .layout.root_closed_set import RootClosedSet
36
36
  from .layout.root_markdown_allowlist import RootMarkdownAllowlist
37
37
  from .layout.scripts_size_depth import ScriptsSizeDepth
38
38
  from .lfs.integrity import Integrity
39
- from .pipeline.phase_disjoint import PhaseDisjoint
40
- from .repository.banned_commands import BannedCommands
41
39
  from .repository.ignored_paths import IgnoredPaths
40
+ from .repository.legacy_search import LegacySearch
42
41
  from .repository.license_declared import LicenseDeclared
43
42
  from .repository.lockfile_integrity import LockfileIntegrity
43
+ from .repository.no_multiline_comments import NoMultilineComments
44
+ from .repository.vcs_in_scripts import VcsInScripts
44
45
 
45
46
  CHECKS: tuple[type[Check], ...] = (
46
47
  AdrLifecycle,
47
48
  AgentsLayout,
48
- BannedCommands,
49
49
  CiPaths,
50
50
  DirectoryRatchet,
51
51
  DocsClosedSet,
@@ -59,18 +59,20 @@ CHECKS: tuple[type[Check], ...] = (
59
59
  Indexes,
60
60
  Integrity,
61
61
  LicenseDeclared,
62
+ LegacySearch,
62
63
  LockfileIntegrity,
63
64
  MarkdownAst,
64
65
  MarkdownTrees,
66
+ NoMultilineComments,
65
67
  OkfProfile,
66
68
  OpenWorkCap,
67
- PhaseDisjoint,
68
69
  Placement,
69
70
  PlansLayout,
70
71
  References,
71
72
  RootClosedSet,
72
73
  RootMarkdownAllowlist,
73
74
  ScriptsSizeDepth,
75
+ VcsInScripts,
74
76
  )
75
77
 
76
78
  _BY_ID: dict[str, type[Check]] = {check.id: check for check in CHECKS}
@@ -7,7 +7,7 @@ owes a different set of backlinks.
7
7
  docs/architecture/decisions/ entirely would pass in silence.
8
8
  graded the ADRs, which are the given set.
9
9
 
10
- BACKLINK TARGETS ARE RESOLVED, NOT GRADED. `.specs/`, `.plans/` and
10
+ BACKLINK TARGETS ARE RESOLVED, NOT GRADED. `.plans/` and
11
11
  `docs/architecture/` references are read from disk even though the row's scope
12
12
  excludes them. That is not a second discovery pass: the set says which ADRs are
13
13
  graded, and whether an ADR's own link resolves is a property OF that ADR.
@@ -54,7 +54,7 @@ def test_a_linked_plan_is_no_longer_graded_on_the_directory_it_sits_in() -> None
54
54
  So whether a linked plan is active is no longer answerable from disk, and this
55
55
  gate does not try. What remains is the backlink itself, asserted below. The rule
56
56
  survived the tree's deletion by eighteen months of nobody writing a DECIDED ADR —
57
- DOC-001 was armed and green on enact-m5 the whole time."""
57
+ DOC-001 was armed and green on a managed repository the whole time."""
58
58
  verdict = verdict_for("DOC-001", CORPORA / "adr-lifecycle-inactive-plan")
59
59
  assert "requires a linked active plan" not in verdict.render()
60
60
 
@@ -35,12 +35,10 @@ One finding per (path, line, kind), not per matched character or codepoint —
35
35
  the matched value (a two-character Han word on one line is one finding, not
36
36
  two).
37
37
 
38
- The row's `engine.scope` (`policy/gate-registry.yaml`, `DOC-002`) excludes
39
- four specific frontend fixture files — SCOPE, decided by the row, not by this
40
- check. `scan_excluded`'s three rules below are a different thing: SUBJECT-MATTER
38
+ The row's `engine.scope` (`policy/gate-registry.yaml`, `DOC-002`) decides
39
+ SCOPE, not this check. `scan_excluded`'s rules below are a different thing: SUBJECT-MATTER
41
40
  exclusions this gate owns, because they say what kind of content Han text is
42
- allowed to be (hidden paths, the one named i18n directory, any locale-named
43
- data directory), not where in the tree it lives.
41
+ allowed to be (hidden paths, any locale-named data directory), not where in the tree it lives.
44
42
  """
45
43
 
46
44
  from __future__ import annotations
@@ -124,19 +122,6 @@ class DocsEnglishOnly(Check):
124
122
  and `.../i18n/locales/<locale>/...` — where non-English text is the point,
125
123
  not a defect. Mirrors check.sh's `scan_excluded` rule 3."""
126
124
 
127
- inputs: ClassVar[dict[str, str]] = {"frontend_src": "<frontend>"}
128
- """FIXED 2026-09-16 (K-42 sweep, LOUD form, approved): `I18N_OWNER` was a
129
- hardcoded `frontend/mobile/src/i18n` literal, matched against the given
130
- set with `==`/`startswith` inside `_excluded` -- a rule 2 EXEMPTION, not a
131
- filter over what gets scanned. A repository whose frontend root is not the
132
- packaged default had its real i18n directory fail this match, so its
133
- genuinely-translated strings were no longer exempt -- every one of them
134
- became a false "raw Han text" finding. LOUD, not silent: the wrong path
135
- does not go quiet, it makes real translated content look like a defect.
136
- `mobile/src/i18n` stays literal below the resolved root: the settled
137
- platform path, not a resolvable one, the same call TS-001's `MOBILE_SRC`
138
- fix already made."""
139
-
140
125
  FIX_BY_KIND: ClassVar[dict[str, str]] = {
141
126
  "Han Unicode escape": "replace the \\u/\\U escape with the equivalent English text",
142
127
  "raw Han text": "translate this Han-script text into English",
@@ -172,15 +157,14 @@ class DocsEnglishOnly(Check):
172
157
  # it still exists on disk — check.sh's ALL_RELPATHS is filled before
173
158
  # its own `[ -f "$rel" ]` guard, because a Han PATH is the finding
174
159
  # there, distinct from Han CONTENT, which a deleted file no longer has.
175
- i18n_owner = self._i18n_owner(ctx)
176
160
  for relative in files:
177
- if self._excluded(relative, i18n_owner):
161
+ if self._excluded(relative):
178
162
  continue
179
163
  if self.HAN_PATTERN.search(relative):
180
164
  yield self._finding(relative, "Han filename")
181
165
 
182
166
  for relative in files.existing(ctx.root):
183
- if self._excluded(relative, i18n_owner):
167
+ if self._excluded(relative):
184
168
  continue
185
169
  suffix = self._path_suffix(relative).lower()
186
170
  if suffix in self.OFFICE_SUFFIXES:
@@ -190,30 +174,11 @@ class DocsEnglishOnly(Check):
190
174
 
191
175
  # ------------------------------------------------------ subject-matter scope
192
176
 
193
- def _i18n_owner(self, ctx: Context) -> str | None:
194
- # Decision for a tree declared absent (`frontend = ""`, which drops
195
- # `frontend_src` from the resolved inputs): this input only contributes
196
- # the i18n OWNER exemption, an extra path that excuses translated strings
197
- # beneath it. A repository with no frontend tree has no such directory, so
198
- # there is no exemption to grant -- Han text anywhere is graded by the rule
199
- # as written, and the generic locale-directory exemption below still
200
- # applies. This read `ctx.inputs['frontend_src']` unguarded -- a `KeyError`
201
- # traceback (exit 1), not a verdict, on any file.
202
- frontend_src = ctx.inputs.get("frontend_src")
203
- if frontend_src is None:
204
- return None
205
- return f"{ctx.relative(frontend_src)}/mobile/src/i18n"
206
-
207
- def _excluded(self, relative: str, i18n_owner: str | None) -> bool:
177
+ def _excluded(self, relative: str) -> bool:
208
178
  # 1. Hidden paths, by decision. Every component is tested.
209
179
  if any(part.startswith(".") for part in relative.split("/")):
210
180
  return True
211
- # 2. The one named i18n owner exemption (absent when the frontend tree is).
212
- if i18n_owner is not None and (
213
- relative == i18n_owner or relative.startswith(i18n_owner + "/")
214
- ):
215
- return True
216
- # 3. Any locale-named data directory, anywhere.
181
+ # 2. Any locale-named data directory, anywhere.
217
182
  if self.LOCALE_DIR.search(relative):
218
183
  return True
219
184
  return False