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

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 (192) 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/mcp-tool.ts +1 -1
  14. package/packages/agent-hooks/src/rules/shell/invocation.ts +2 -1
  15. package/packages/agent-skills/assets/agent-search-tool-audit/SKILL.md +24 -2
  16. package/packages/agent-skills/assets/agent-search-tool-audit/scripts/audit.sh +19 -45
  17. package/packages/agent-skills/assets/diagnosing-bugs/SKILL.md +9 -0
  18. package/packages/agent-skills/assets/diagnosing-bugs/scripts/hitl-loop.template.sh +1 -12
  19. package/packages/fleet/manifest.json +2 -1
  20. package/packages/fleet/src/repo-maintain.ts +5 -2
  21. package/packages/repo-controls/AGENTS.md +7 -4
  22. package/packages/repo-controls/README.md +346 -56
  23. package/packages/repo-controls/assets/GLOBAL-INVARIANTS.md +21 -0
  24. package/packages/repo-controls/assets/promote.ts +7 -85
  25. package/packages/repo-controls/assets/reconcile-guard.sh +1 -14
  26. package/packages/repo-controls/assets/scaffold/docs/AGENTS.md +25 -0
  27. package/packages/repo-controls/assets/scaffold/docs/CLAUDE.md +1 -0
  28. package/packages/repo-controls/assets/scaffold/docs/decisions/index.md +17 -0
  29. package/packages/repo-controls/assets/scaffold/docs/notes.md +20 -0
  30. package/packages/repo-controls/assets/scaffold/plans/AGENTS.md +28 -0
  31. package/packages/repo-controls/assets/scaffold/plans/CLAUDE.md +1 -0
  32. package/packages/repo-controls/assets/scaffold/plans/GAPS-AND-FINDINGS.md +12 -0
  33. package/packages/repo-controls/assets/scaffold/plans/LEDGER.md +8 -0
  34. package/packages/repo-controls/assets/scaffold/plans/features/.gitkeep +0 -0
  35. package/packages/repo-controls/assets/scaffold/root/AGENTS.md +22 -0
  36. package/packages/repo-controls/assets/scaffold/root/CLAUDE.md +1 -0
  37. package/packages/repo-controls/assets/scaffold/workflows/AGENTS.md +16 -0
  38. package/packages/repo-controls/assets/scaffold/workflows/CLAUDE.md +1 -0
  39. package/packages/repo-controls/assets/scaffold/workflows/pipelines/.gitkeep +0 -0
  40. package/packages/repo-controls/assets/scaffold/workflows/scripts/.gitkeep +0 -0
  41. package/packages/repo-controls/assets/version-bump.sh +7 -48
  42. package/packages/repo-controls/package/adl-compliance/AGENTS.md +25 -7
  43. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/__init__.py +6 -4
  44. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/adr_lifecycle/check.py +1 -1
  45. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/adr_lifecycle/test_check.py +1 -1
  46. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/english_only/check.py +7 -42
  47. 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
  48. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/english_only/test_check.py +10 -44
  49. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/architecture/ui-contract.md +1 -1
  50. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/research/UI-CONTRACT.md +1 -1
  51. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/test_check.py +1 -1
  52. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/index_updated/check.py +1 -7
  53. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/index_updated/test_check.py +12 -3
  54. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/indexes/check.py +15 -23
  55. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/indexes/docs-knowledge-indexes.yaml +0 -136
  56. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/indexes/test_check.py +18 -0
  57. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/docs-okf-profiles.yaml +2 -2
  58. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/register.py +0 -7
  59. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/semantics/check.py +2 -4
  60. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/semantics/fixtures/semantics-violations/docs/architecture/guides/stable-delivery.md +10 -0
  61. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/semantics/fixtures/semantics-violations/docs/architecture/guides/stable-recommendation.md +12 -0
  62. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/semantics/fixtures/semantics-violations/docs/architecture/guides/target-narration.md +10 -0
  63. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/semantics/test_check.py +6 -7
  64. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/ci_paths/test_check.py +3 -3
  65. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/check.py +10 -12
  66. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-clean/grants.yaml +1 -1
  67. 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
  68. 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
  69. 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
  70. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/grants.yaml +1 -1
  71. 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
  72. 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
  73. 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
  74. 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
  75. 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
  76. 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
  77. 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
  78. 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
  79. 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
  80. 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
  81. 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
  82. 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
  83. 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
  84. 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
  85. 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
  86. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-missing-tree/grants.yaml +1 -1
  87. 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
  88. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-no-ceilings/grants.yaml +1 -1
  89. 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
  90. 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
  91. 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
  92. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-stale-entry/grants.yaml +2 -2
  93. 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
  94. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unbaselined/grants.yaml +1 -1
  95. 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
  96. 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
  97. 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
  98. 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
  99. 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
  100. 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
  101. 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
  102. 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
  103. 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
  104. 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
  105. 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
  106. 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
  107. 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
  108. 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
  109. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/test_check.py +46 -54
  110. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/markdown_trees/check.py +16 -76
  111. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/markdown_trees/test_check.py +35 -32
  112. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/placement/check.py +46 -213
  113. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/placement/fixtures/placement-allowed/README.md +1 -0
  114. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/placement/test_check.py +76 -194
  115. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/plans_layout/check.py +18 -2
  116. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/plans_layout/test_check.py +49 -0
  117. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/references/check.py +1 -1
  118. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/references/fixtures/link-targets-broken/docs/architecture/guides/links.md +20 -0
  119. 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
  120. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/references/fixtures/link-targets-clean/docs/architecture/guides/links.md +20 -0
  121. 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
  122. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/references/test_check.py +4 -4
  123. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/check.py +3 -3
  124. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/.notes/declared.txt +1 -0
  125. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/test_check.py +8 -1
  126. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_markdown_allowlist/check.py +15 -135
  127. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_markdown_allowlist/test_check.py +98 -50
  128. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/scripts_size_depth/check.py +1 -1
  129. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/scripts_size_depth/test_check.py +1 -1
  130. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/check.py +1 -1
  131. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/test_check.py +14 -10
  132. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/banned_commands/__init__.py +3 -10
  133. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/banned_commands/base.py +42 -0
  134. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/banned_commands/test_check.py +82 -49
  135. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/banned_commands/test_scope.py +71 -0
  136. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/legacy_search/__init__.py +7 -0
  137. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/legacy_search/check.py +15 -0
  138. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/legacy_search/test_check.py +32 -0
  139. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/cargo_lock.py +1 -1
  140. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/check.py +56 -124
  141. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/fixtures/clean/Cargo.lock +7 -0
  142. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/fixtures/clean/Cargo.toml +4 -0
  143. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/fixtures/clean/bun.lock +1 -0
  144. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/fixtures/clean/package.json +1 -0
  145. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/fixtures/clean/rust-toolchain.toml +3 -0
  146. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/fixtures/clean/src/main.rs +1 -0
  147. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/fixtures/empty-bun-lock/Cargo.lock +7 -0
  148. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/fixtures/empty-bun-lock/Cargo.toml +4 -0
  149. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/fixtures/empty-bun-lock/bun.lock +0 -0
  150. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/fixtures/empty-bun-lock/package.json +1 -0
  151. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/fixtures/empty-bun-lock/rust-toolchain.toml +3 -0
  152. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/fixtures/empty-bun-lock/src/main.rs +1 -0
  153. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/test_check.py +8 -37
  154. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/test_declared_paths.py +95 -130
  155. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/test_root_lockfiles.py +101 -0
  156. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/test_stale_lock.py +25 -13
  157. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/no_multiline_comments/__init__.py +7 -0
  158. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/no_multiline_comments/check.py +124 -0
  159. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/no_multiline_comments/fixtures/valid-register.yaml +4 -0
  160. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/no_multiline_comments/scanner.py +217 -0
  161. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/no_multiline_comments/test_check.py +391 -0
  162. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/vcs_in_scripts/__init__.py +7 -0
  163. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/vcs_in_scripts/check.py +16 -0
  164. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/vcs_in_scripts/test_check.py +32 -0
  165. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/cli.py +12 -1
  166. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/core/ast_grep.py +2 -3
  167. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/core/check.py +3 -0
  168. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/core/constants.py +1 -1
  169. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/core/declarations.py +24 -0
  170. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/core/receipt.py +2 -2
  171. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/core/scripts.py +120 -0
  172. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/config.py +1 -1
  173. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/config.toml +4 -4
  174. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/gate-registry.alt.yaml +93 -99
  175. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/gate-registry.yaml +93 -99
  176. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/registry.py +1 -1
  177. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/root_shape.py +6 -47
  178. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/runner.py +54 -8
  179. package/packages/repo-controls/scripts/hooks/pre-commit +12 -2
  180. package/packages/repo-controls/scripts/hooks/pre-push +27 -19
  181. package/packages/repo-controls/src/cli.ts +22 -3
  182. package/packages/repo-controls/src/compliance-config.ts +132 -65
  183. package/packages/repo-controls/src/config.ts +55 -46
  184. package/packages/repo-controls/src/constants.ts +9 -0
  185. package/packages/repo-controls/src/coverage-ratchet.ts +19 -4
  186. package/packages/repo-controls/src/doctor.ts +20 -30
  187. package/packages/repo-controls/src/findings-ratchet.ts +14 -0
  188. package/packages/repo-controls/src/gitignore-block.ts +3 -13
  189. package/packages/repo-controls/src/hook-log.ts +7 -10
  190. package/packages/repo-controls/src/hook.ts +127 -83
  191. package/packages/repo-controls/src/install-compliance.ts +112 -0
  192. package/packages/repo-controls/src/install.ts +133 -30
@@ -0,0 +1,120 @@
1
+ """Which language a code file is in, by name or shebang: one selector for every gate that grades scripts."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import re
6
+ from collections.abc import Callable
7
+
8
+
9
+ class Names:
10
+ """The literals the selector reads, on a class like every gate's."""
11
+
12
+ TYPESCRIPT_SUFFIXES = (".ts", ".mts", ".cts")
13
+ SLASH_SUFFIXES = (*TYPESCRIPT_SUFFIXES, ".tsx", ".js", ".jsx", ".mjs", ".cjs")
14
+ RUST_SUFFIX = ".rs"
15
+ PYTHON_SUFFIX = ".py"
16
+ SHELL_SUFFIXES = (".sh", ".bash")
17
+ ZSH_SUFFIX = ".zsh"
18
+ JUSTFILE_SUFFIXES = (".just", ".justfile")
19
+ JUSTFILES = ("justfile", ".justfile")
20
+
21
+ SHEBANG_POSIX = frozenset({"sh", "dash"})
22
+ SHEBANG_BASH = "bash"
23
+ SHEBANG_KSH = frozenset({"ksh", "ksh93", "mksh"})
24
+ SHEBANG_SPLIT = "--split-string="
25
+ SHEBANG_ZSH = "zsh"
26
+ SHEBANG_NODES = frozenset({"node", "bun", "deno", "tsx", "ts-node"})
27
+ SHEBANG_PYTHON = re.compile(r"python[0-9.]*|uv")
28
+ SHEBANG_ENV_VALUED = frozenset({"-u", "--unset", "-C", "--chdir"})
29
+
30
+ SHELL_LANGUAGES = frozenset({"shell", "posix", "mksh", "zsh", "justfile"})
31
+ DIALECT_SUFFIXES = (".sh", ".bash")
32
+
33
+
34
+ def language(relative: str, text: str) -> str | None:
35
+ """`python`, `rust`, `typescript`, `slash`, `shell` (bash), `posix`, `mksh`, `zsh`, `justfile`, or None when the file is none of them."""
36
+ name = relative.rsplit("/", 1)[-1]
37
+ if relative.endswith(Names.PYTHON_SUFFIX):
38
+ return "python"
39
+ if relative.endswith(Names.RUST_SUFFIX):
40
+ return "rust"
41
+ if relative.endswith(Names.TYPESCRIPT_SUFFIXES):
42
+ return "typescript"
43
+ if relative.endswith(Names.SLASH_SUFFIXES):
44
+ return "slash"
45
+ if name.lower() in Names.JUSTFILES or relative.endswith(Names.JUSTFILE_SUFFIXES):
46
+ return "justfile"
47
+ if relative.endswith(Names.SHELL_SUFFIXES):
48
+ declared = _shebang_language(text)
49
+ return declared if declared in Names.SHELL_LANGUAGES else "shell"
50
+ if relative.endswith(Names.ZSH_SUFFIX):
51
+ return "zsh"
52
+ if "." in name:
53
+ return None
54
+ return _shebang_language(text)
55
+
56
+
57
+ def _shebang_language(text: str) -> str | None:
58
+ first = text.split("\n", 1)[0].rstrip("\r")
59
+ if not first.startswith("#!"):
60
+ return None
61
+ words = first[2:].split()
62
+ if not words:
63
+ return None
64
+ program = words[0].rsplit("/", 1)[-1]
65
+ if program == "env":
66
+ rest = _env_command(words[1:])
67
+ if not rest:
68
+ return None
69
+ program = rest[0].rsplit("/", 1)[-1]
70
+ if program in Names.SHEBANG_POSIX:
71
+ return "posix"
72
+ if program == Names.SHEBANG_BASH:
73
+ return "shell"
74
+ if program in Names.SHEBANG_KSH:
75
+ return "mksh"
76
+ if program == Names.SHEBANG_ZSH:
77
+ return "zsh"
78
+ if program in Names.SHEBANG_NODES:
79
+ return "slash"
80
+ if Names.SHEBANG_PYTHON.fullmatch(program):
81
+ return "python"
82
+ return None
83
+
84
+
85
+ def _env_command(words: list[str]) -> list[str]:
86
+ """The command `env` runs: its own options, their values and NAME=value words skipped."""
87
+ rest: list[str] = []
88
+ skip = False
89
+ for word in words:
90
+ if skip:
91
+ skip = False
92
+ elif rest:
93
+ rest.append(word)
94
+ elif word in Names.SHEBANG_ENV_VALUED:
95
+ skip = True
96
+ elif word.startswith(Names.SHEBANG_SPLIT):
97
+ rest.append(word[len(Names.SHEBANG_SPLIT) :])
98
+ elif word.startswith("-S") and len(word) > 2:
99
+ rest.append(word[2:])
100
+ elif not word.startswith("-") and "=" not in word:
101
+ rest.append(word)
102
+ return rest
103
+
104
+
105
+ def _selects(relative: str, head: Callable[[], str | None] | None, wanted: frozenset[str] | None) -> bool:
106
+ name = relative.rsplit("/", 1)[-1]
107
+ found = language(relative, "")
108
+ if found is None and "." not in name and head is not None:
109
+ found = _shebang_language(head() or "")
110
+ return found is not None and (wanted is None or found in wanted)
111
+
112
+
113
+ def is_code_file(relative: str, head: Callable[[], str | None] | None = None) -> bool:
114
+ """Whether the file is code in a language this estate grades; an extensionless file is read for its shebang."""
115
+ return _selects(relative, head, None)
116
+
117
+
118
+ def is_shell_script(relative: str, head: Callable[[], str | None] | None = None) -> bool:
119
+ """Whether the file is a shell, zsh or just script, by name or shebang."""
120
+ return _selects(relative, head, Names.SHELL_LANGUAGES)
@@ -1,6 +1,6 @@
1
1
  """`<name>` in a scope pattern, and the one file that says what it means.
2
2
 
3
- A row declares what its rule is ABOUT — `<rust>/crates/**/src/*.rs` — and
3
+ A row declares what its rule is ABOUT — `<docs>/**/*.md` — and
4
4
  `trees.toml` says where that currently lives. The registry therefore contains no
5
5
  consumer path at all, which is K-42: a path outside this package, written inside
6
6
  it, is a dependency on this particular checkout's shape.
@@ -1,9 +1,9 @@
1
1
  # The consumer's layout, declared once.
2
2
  #
3
3
  # A registry row names a LOGICAL tree and never a physical path, so
4
- # `<rust>/crates/**/src/*.rs` is a rule about Rust crates and this file is the
5
- # only place that says Rust lives in `backend/`. Move the tree, edit one line,
6
- # and all 82 backend-rooted scope entries follow.
4
+ # `<docs>/**/*.md` is a rule about documentation and this file is the
5
+ # only place that says documentation lives in `docs/`. Move the tree, edit one line,
6
+ # and every docs-rooted scope entry follows.
7
7
  #
8
8
  # This closes K-42 for the registry. A path outside this package written inside
9
9
  # it is a dependency on THIS checkout's shape; the rule is that the consumer's
@@ -12,7 +12,7 @@
12
12
  # line here, not 79 edits across the rows.
13
13
  #
14
14
  # SYNTAX IS `<name>`, NOT `{name}`. Braces are already glob alternation and 11
15
- # rows use it -- `{docs,.plans,.specs}/**`, `{schema,compliance}/**`. A `{rust}`
15
+ # rows use it -- `{docs,plans}/**`, `{schema,compliance}/**`. A `{rust}`
16
16
  # placeholder would be indistinguishable from a one-element alternation, and
17
17
  # resolving that by "a placeholder has no comma" is the silent-ambiguity trap
18
18
  # K-13 records. Angle brackets appear in no scope entry and in no path.
@@ -74,19 +74,19 @@ rows:
74
74
  # Same reasoning, the TypeScript-shaped colocated test file: this scope
75
75
  # excluded `test_*.py` but nothing that names a TypeScript test the way
76
76
  # every managed repo's own convention does. Caught live against
77
- # enact-vps-m5: `global-tools/test/install-embedding-model.test.ts`
77
+ # a managed repository: `global-tools/test/install-embedding-model.test.ts`
78
78
  # asserts that `selectVocabulary` DROPS non-Latin-script tokens, and
79
79
  # embeds a CJK literal as the negative-test input -- exactly
80
80
  # the "test asserting a non-English string" case above, just in `.ts`
81
81
  # rather than `.py`. COVERAGE COST, stated not buried: 548 colocated
82
82
  # `*.test.ts`/`*.test.tsx` files across the four managed repos
83
- # (enact-m5 400, enact-vps-m5 134, enact-repo-controls-m5 14,
84
- # enact-extensions 0) stop being graded for english-only.
83
+ # (400, 134, 14 and 0 in the four
84
+ # repositories) stop being graded for english-only.
85
85
  - '!**/*.test.ts'
86
86
  - '!**/*.test.tsx'
87
87
  # The four exclusions removed here named
88
- # `<typescript>/packages/desktop/...` and `<typescript>/tests/unit/...`
89
- # -- one repository's files written into the shared package. Measured
88
+ # one repository's application and unit-test files, written into the
89
+ # shared package under a tree placeholder. Measured
90
90
  # before removing: 0 of the 4 exist in ANY of the four managed
91
91
  # repositories, so they excluded nothing anywhere. If a consumer ever
92
92
  # has legitimately non-English source, it declares that itself.
@@ -363,7 +363,6 @@ rows:
363
363
  scope:
364
364
  - '{AGENTS,CLAUDE}.md'
365
365
  - '**/{AGENTS,CLAUDE}.md'
366
- - <compliance>/checks/layout/agents-layout/check.sh
367
366
  - '!**/fixtures/**'
368
367
  grants: 0
369
368
  timeout_ms: 60000
@@ -386,7 +385,7 @@ rows:
386
385
  #
387
386
  # Same shape as LAY-014's `!<workflows>/scripts/**/fixtures/**`, one
388
387
  # level up. COVERAGE COST, stated rather than buried: this drops 19 of
389
- # enact-m5's 44 `workflows/scripts/` files (43%) from the gate. The risk
388
+ # one managed repository's 44 `workflows/scripts/` files (43%) from the gate. The risk
390
389
  # it trades away is small — a TEST that truly needs a gitignored file
391
390
  # fails loudly in CI, whereas a production CI script referencing one can
392
391
  # silently skip, and production scripts are all still graded.
@@ -410,29 +409,14 @@ rows:
410
409
  # recorded state the register file is deleted. No ceilings declared
411
410
  # means nothing to enforce — the gate is inert.
412
411
  scope:
413
- - <typescript>/**
414
- - <rust>/**
415
- - <infra>/**
416
- - <dev>/**
417
- - <workflows>/**
418
- # A single '*' cannot cross a '/': it is one path segment, not "the rest
419
- # of the subtree". Confirmed live against this checkout, not just the
420
- # ported test fixture — locales/de/common.json sits two segments below
421
- # locales/, and real crate/build/terraform files sit at varying depths
422
- # below their prefix (`rg`/`find` measured 2 and 4 segments for
423
- # Cargo.toml, 4 for build.rs, 2 through 5 for main.tf) — every nested
424
- # occurrence was silently unexcluded until these five became '**'.
425
- - '!<typescript>/packages/desktop/src/renderer/services/i18n/locales/**'
426
- - '!<rust>/crates/enact-app/assets/builtin-skills/**'
427
- - '!<rust>/crates/enact-app/assets/builtin-harnesses/*'
428
- - '!<dev>/seed/access/*'
429
- - '!<dev>/seed/infra/*'
430
- - '!<dev>/seed/tenancy/*'
431
- - '!<dev>/scripts/*'
432
- - '!<dev>/ops/*'
433
- - '!**/Cargo.toml'
434
- - '!**/build.rs'
435
- - '!**/main.tf'
412
+ # The WHOLE repository (Tarun, 2026-10-08, PBI 598): the ratchet is
413
+ # repo-wide and hardcodes no exclusion. `**` matches every path of the
414
+ # Git-visible universe the CLI hands over (`ls-files --cached --others
415
+ # --exclude-standard`), and the measurement itself skips dot-prefixed
416
+ # components. What a repository exempts it declares itself: a ceiling
417
+ # per tree in [controls.compliance.directory-ratchet].max_children and
418
+ # its over-limit / single-file baselines in the ratchet register below.
419
+ - '**'
436
420
  # The ratchet register is a named INPUT of this gate, not a scope entry:
437
421
  # it is the CONSUMER's own file (<compliance>/ratchets/
438
422
  # LAY-004-over-limit-directory.yaml -- the estate's settled location for
@@ -485,21 +469,21 @@ rows:
485
469
  - id: LAY-008
486
470
  name: placement
487
471
  domain: layout
488
- title: Run retained placement gate
472
+ title: Reject throwaway files and undeclared image placement
489
473
  severity: M
490
474
  controls:
491
475
  - EC-A.5.36
492
476
  engine:
477
+ # Every file: a throwaway extension is reported anywhere, and an image or
478
+ # screenshot-named file is reported unless it sits in a directory the
479
+ # repository declares in `asset-dirs`. (The root allowlist is LAY-012's
480
+ # `root-closed-set`, not this row's.)
493
481
  scope:
494
- - '*'
495
- - '*.{log,tmp,bak,swp}'
496
- - '**/*.{log,tmp,bak,swp}'
497
- - <compliance>/checks/layout/placement/check.sh
482
+ - '**'
498
483
  # The corpora under placement-allowed/ and placement-stray/ are the
499
- # gate's own test input: enumerated asset paths, a screenshot, a
500
- # markdown file inside a crate src/ tree, and a file under retired
501
- # apps/. Graded as production content they are exactly the findings
502
- # the gate exists to raise.
484
+ # gate's own test input: a screenshot and a throwaway file. Graded as
485
+ # production content they are exactly the findings the gate exists to
486
+ # raise.
503
487
  - '!**/fixtures/**'
504
488
  grants: 0
505
489
  timeout_ms: 60000
@@ -567,7 +551,6 @@ rows:
567
551
  - '!.git/**'
568
552
  - '!.DS_Store'
569
553
  - '!.cache/**'
570
- - '!.enactrs/**'
571
554
  - '!.pytest_cache/**'
572
555
  - '!.ruff_cache/**'
573
556
  - '!.scratch/**'
@@ -652,27 +635,6 @@ rows:
652
635
  grants: 0
653
636
  timeout_ms: 60000
654
637
 
655
- # ---- pipeline ----
656
- - id: PIP-004
657
- name: phase-disjoint
658
- domain: pipeline
659
- title: Enforce phase mutual exclusion across every registry row
660
- severity: M
661
- controls:
662
- - EC-A.5.36
663
- engine:
664
- # Scope is SELECTION, not resolution. The check finds the registry
665
- # structurally, from its own position in the package, and that is why it
666
- # needs no path here to READ it -- but scope decides whether a changed
667
- # file makes this row run at all, and an empty scope matches nothing. The
668
- # gate that enforces phase disjointness across the registry was therefore
669
- # never selected by a change to the registry: the one edit that can break
670
- # it was the one edit that did not run it.
671
- scope:
672
- - <compliance>/policy/gate-registry.yaml
673
- grants: 0
674
- timeout_ms: 60000
675
-
676
638
  # ---- repository ----
677
639
  - id: REP-001
678
640
  name: license-declared
@@ -707,53 +669,32 @@ rows:
707
669
  - EC-A.5.21
708
670
  engine:
709
671
  scope:
710
- # The tree-derived DEFAULT: each half is exactly two entries under its own
711
- # tree. A repository whose manifests do not sit one level under its tree
712
- # (enact-combined: a brace-union `typescript` tree, manifests at the root and
713
- # under apps/*/) states the paths itself with `[controls.compliance.lockfiles]`
714
- # (`bun-manifests`/`bun-lockfiles`, `cargo-manifests`/`cargo-lockfiles`); a
715
- # declared half REPLACES that half's two entries, in the scope and in what the
716
- # check grades. See `LockfileIntegrity.declared_scope`.
717
- - <rust>/Cargo.toml
718
- - <rust>/Cargo.lock
719
- - <typescript>/package.json
720
- - <typescript>/bun.lock
672
+ # The REPOSITORY-ROOT pairs, graded automatically (Tarun, 2026-10-08,
673
+ # PBI 598): `Cargo.toml` -> `Cargo.lock` and `package.json` -> `bun.lock`.
674
+ # Every other lockfile is graded only because the repository declares it
675
+ # with `[controls.compliance.lockfiles]` (`bun-manifests`/`bun-lockfiles`,
676
+ # `cargo-manifests`/`cargo-lockfiles`); a declaration ADDS its manifests
677
+ # and lockfiles to this scope and to what the check grades. See
678
+ # `LockfileIntegrity.declared_scope`.
679
+ - Cargo.toml
680
+ - Cargo.lock
681
+ - package.json
682
+ - bun.lock
721
683
  grants: 0
722
684
  timeout_ms: 60000
723
685
  - id: REP-004
724
- name: no-banned-commands
686
+ name: no-legacy-search
725
687
  domain: repository
726
- title: Forbid banned command invocations in shell scripts and justfiles
688
+ title: Forbid standalone legacy search in shell scripts and justfiles
727
689
  severity: M
728
690
  controls:
729
691
  - EC-A.5.36
730
692
  engine:
731
693
  scope:
732
- # Both GIT-001 (no version-control invocation) and GRP-001 (no
733
- # standalone grep, use rg) are restricted to the compliance package --
734
- # a deliberate, explicit decision (both are compliance gates), not an
735
- # inherited default. Neither rule is about the rest of the repository,
736
- # so nothing here is expressed as an extension glob any more: the old
737
- # repository-wide `*.{sh,bash,...}` list existed only because GRP-001
738
- # used to run everywhere and needed to exclude non-shell files from a
739
- # much larger candidate set. Restricted to compliance/**, that ceiling
740
- # is gone -- check.sh's own shell/justfile filter is enough.
741
- - <compliance>/**
742
- # The scope contract itself. `discover_files` lists the tree through the
743
- # version-control plumbing; every other file in this package reaches it
744
- # through this one, which is why it is exempted here rather than at each
745
- # caller. Out of scope, not granted: the rule does not apply to the
746
- # implementation of the mechanism it exists to make optional everywhere
747
- # else.
748
- - '!<compliance>/lib/discovery.sh'
749
- # The same exemption, on the test side. `_corpus-set.sh` is the one
750
- # place a fixture enumerates its corpus, and it asks the corpus the
751
- # same question the runner asks the repository, through the same
752
- # plumbing -- deliberately, so the set a test hands over is the same
753
- # KIND of set production hands over. Every converted gate test reaches
754
- # it through this file, which is why it is exempted here rather than at
755
- # each caller.
756
- - '!<compliance>/checks/framework/_corpus-set.sh'
694
+ # Repo-wide: every file, narrowed by the check to the shell scripts
695
+ # and justfiles `core/scripts.py` selects (by suffix, name or
696
+ # shebang), the same selector REP-007 uses.
697
+ - '**'
757
698
  # EVERY gate's fixture corpus, not just this row's. A fixture is
758
699
  # deliberate violation material -- both halves of this row's own corpus
759
700
  # contain real invocations on purpose -- and graded as production
@@ -775,3 +716,56 @@ rows:
775
716
  - '**'
776
717
  grants: 0
777
718
  timeout_ms: 60000
719
+ # Split from REP-004 (Tarun 2026-10-08: PBI 605). Same repo-wide scope; a
720
+ # repository whose git hooks and release scripts must call the version-control
721
+ # tool leaves this gate out of `enabled` and keeps REP-004.
722
+ - id: REP-006
723
+ name: no-vcs-in-scripts
724
+ domain: repository
725
+ title: Forbid version-control calls in shell scripts and justfiles
726
+ severity: M
727
+ controls:
728
+ - EC-A.5.36
729
+ engine:
730
+ scope:
731
+ # Repo-wide: every file, narrowed by the check to the shell scripts
732
+ # and justfiles `core/scripts.py` selects (by suffix, name or
733
+ # shebang), the same selector REP-007 uses.
734
+ - '**'
735
+ # EVERY gate's fixture corpus, not just this row's. A fixture is
736
+ # deliberate violation material -- both halves of this row's own corpus
737
+ # contain real invocations on purpose -- and graded as production
738
+ # content it fails the gate it exists to prove. Declared here rather
739
+ # than skipped inside the check: path exclusions carry no default in
740
+ # this tree.
741
+ - '!**/fixtures/**'
742
+ # The managed projections adl rebuilds on every install (Tarun,
743
+ # 2026-10-08): their git hooks must call the version-control tool and
744
+ # the repository cannot edit them. Only this gate leaves them out.
745
+ - '!.workflows/**'
746
+ - '!.agents/**'
747
+ - '!.claude/**'
748
+ - '!.codex/**'
749
+ - '!.cursor/**'
750
+ - '!.kimi-code/**'
751
+ - '!.opencode/**'
752
+ grants: 0
753
+ timeout_ms: 60000
754
+ # Bug 602 (Tarun 2026-10-08): no multi-line comment in code; the explanation
755
+ # moves to docs/. Grades every code file by suffix (the check's own question,
756
+ # `scanner.is_code_file`), so the scope is the whole repository less every
757
+ # gate's fixture corpus. Exempt files are named by the repository's own
758
+ # register, `<compliance>/ratchets/REP-007-multiline-comments.yaml`.
759
+ - id: REP-007
760
+ name: no-multiline-comments
761
+ domain: repository
762
+ title: Forbid multi-line comments in code files
763
+ severity: M
764
+ controls:
765
+ - EC-A.8.28
766
+ engine:
767
+ scope:
768
+ - '**'
769
+ - '!**/fixtures/**'
770
+ grants: 0
771
+ timeout_ms: 60000