@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.
- package/bin/adl +2 -2
- package/bin/health-check +2 -2
- package/bin/reconcile +41 -21
- package/bin/setup +2 -1
- package/package.json +1 -1
- package/packages/agent-hooks/README.md +77 -8
- package/packages/agent-hooks/assets/opencode-plugin.template.ts +2 -6
- package/packages/agent-hooks/src/deploy/opencode-template.ts +5 -3
- package/packages/agent-hooks/src/hooks/crg/background.ts +7 -4
- package/packages/agent-hooks/src/hooks/log.ts +12 -12
- package/packages/agent-hooks/src/log/writer.ts +170 -24
- package/packages/agent-hooks/src/main.ts +1 -1
- package/packages/agent-hooks/src/rules/impl/adl-git-push-policy.ts +5 -4
- package/packages/agent-hooks/src/rules/impl/mcp-tool.ts +1 -1
- package/packages/agent-hooks/src/rules/shell/invocation.ts +2 -1
- package/packages/agent-hooks/src/rules/shell/protected-carriers.ts +19 -5
- package/packages/agent-settings/assets/GLOBAL-AGENTS.md +1 -1
- package/packages/agent-skills/assets/agent-search-tool-audit/SKILL.md +24 -2
- package/packages/agent-skills/assets/agent-search-tool-audit/scripts/audit.sh +19 -45
- package/packages/agent-skills/assets/diagnosing-bugs/SKILL.md +9 -0
- package/packages/agent-skills/assets/diagnosing-bugs/scripts/hitl-loop.template.sh +1 -12
- package/packages/azdo/src/lib/commit-types.ts +8 -0
- package/packages/azdo/src/lib/validate-pr-metadata.ts +4 -1
- package/packages/fleet/manifest.json +2 -1
- package/packages/fleet/src/repo-maintain.ts +5 -2
- package/packages/repo-controls/AGENTS.md +8 -5
- package/packages/repo-controls/README.md +348 -58
- package/packages/repo-controls/assets/GLOBAL-INVARIANTS.md +21 -0
- package/packages/repo-controls/assets/promote.ts +7 -85
- package/packages/repo-controls/assets/reconcile-guard.sh +1 -14
- package/packages/repo-controls/assets/scaffold/docs/AGENTS.md +25 -0
- package/packages/repo-controls/assets/scaffold/docs/CLAUDE.md +1 -0
- package/packages/repo-controls/assets/scaffold/docs/decisions/index.md +17 -0
- package/packages/repo-controls/assets/scaffold/docs/notes.md +20 -0
- package/packages/repo-controls/assets/scaffold/plans/AGENTS.md +28 -0
- package/packages/repo-controls/assets/scaffold/plans/CLAUDE.md +1 -0
- package/packages/repo-controls/assets/scaffold/plans/GAPS-AND-FINDINGS.md +12 -0
- package/packages/repo-controls/assets/scaffold/plans/LEDGER.md +8 -0
- package/packages/repo-controls/assets/scaffold/plans/features/.gitkeep +0 -0
- package/packages/repo-controls/assets/scaffold/root/AGENTS.md +22 -0
- package/packages/repo-controls/assets/scaffold/root/CLAUDE.md +1 -0
- package/packages/repo-controls/assets/scaffold/workflows/AGENTS.md +16 -0
- package/packages/repo-controls/assets/scaffold/workflows/CLAUDE.md +1 -0
- package/packages/repo-controls/assets/scaffold/workflows/pipelines/.gitkeep +0 -0
- package/packages/repo-controls/assets/scaffold/workflows/scripts/.gitkeep +0 -0
- package/packages/repo-controls/assets/version-bump.sh +7 -48
- package/packages/repo-controls/package/adl-compliance/AGENTS.md +25 -7
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/__init__.py +6 -4
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/adr_lifecycle/check.py +1 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/adr_lifecycle/test_check.py +1 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/english_only/check.py +7 -42
- 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
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/english_only/test_check.py +10 -44
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/architecture/ui-contract.md +1 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/research/UI-CONTRACT.md +1 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/test_check.py +1 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/index_updated/check.py +1 -7
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/index_updated/test_check.py +12 -3
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/indexes/check.py +15 -23
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/indexes/docs-knowledge-indexes.yaml +0 -136
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/indexes/test_check.py +18 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/docs-okf-profiles.yaml +2 -2
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/register.py +0 -7
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/semantics/check.py +2 -4
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/semantics/fixtures/semantics-violations/docs/architecture/guides/stable-delivery.md +10 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/semantics/fixtures/semantics-violations/docs/architecture/guides/stable-recommendation.md +12 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/semantics/fixtures/semantics-violations/docs/architecture/guides/target-narration.md +10 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/semantics/test_check.py +6 -7
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/ci_paths/test_check.py +3 -3
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/check.py +10 -12
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-clean/grants.yaml +1 -1
- 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
- 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
- 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
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/grants.yaml +1 -1
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-missing-tree/grants.yaml +1 -1
- 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
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-no-ceilings/grants.yaml +1 -1
- 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
- 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
- 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
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-stale-entry/grants.yaml +2 -2
- 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
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unbaselined/grants.yaml +1 -1
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/test_check.py +46 -54
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/markdown_trees/check.py +16 -76
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/markdown_trees/test_check.py +35 -32
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/placement/check.py +46 -213
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/placement/fixtures/placement-allowed/README.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/placement/test_check.py +76 -194
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/plans_layout/check.py +18 -2
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/plans_layout/test_check.py +49 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/references/check.py +1 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/references/fixtures/link-targets-broken/docs/architecture/guides/links.md +20 -0
- 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
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/references/fixtures/link-targets-clean/docs/architecture/guides/links.md +20 -0
- 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
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/references/test_check.py +4 -4
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/check.py +3 -3
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/.notes/declared.txt +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/test_check.py +8 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_markdown_allowlist/check.py +15 -135
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_markdown_allowlist/test_check.py +98 -50
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/scripts_size_depth/check.py +1 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/scripts_size_depth/test_check.py +1 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/check.py +1 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/test_check.py +14 -10
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/banned_commands/__init__.py +3 -10
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/banned_commands/base.py +42 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/banned_commands/test_check.py +82 -49
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/banned_commands/test_scope.py +71 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/legacy_search/__init__.py +7 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/legacy_search/check.py +15 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/legacy_search/test_check.py +32 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/cargo_lock.py +1 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/check.py +56 -124
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/fixtures/clean/Cargo.lock +7 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/fixtures/clean/Cargo.toml +4 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/fixtures/clean/bun.lock +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/fixtures/clean/package.json +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/fixtures/clean/rust-toolchain.toml +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/fixtures/clean/src/main.rs +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/fixtures/empty-bun-lock/Cargo.lock +7 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/fixtures/empty-bun-lock/Cargo.toml +4 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/fixtures/empty-bun-lock/bun.lock +0 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/fixtures/empty-bun-lock/package.json +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/fixtures/empty-bun-lock/rust-toolchain.toml +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/fixtures/empty-bun-lock/src/main.rs +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/test_check.py +8 -37
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/test_declared_paths.py +95 -130
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/test_root_lockfiles.py +101 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/test_stale_lock.py +25 -13
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/no_multiline_comments/__init__.py +7 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/no_multiline_comments/check.py +124 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/no_multiline_comments/fixtures/valid-register.yaml +4 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/no_multiline_comments/scanner.py +217 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/no_multiline_comments/test_check.py +391 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/vcs_in_scripts/__init__.py +7 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/vcs_in_scripts/check.py +16 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/vcs_in_scripts/test_check.py +32 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/cli.py +12 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/core/ast_grep.py +2 -3
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/core/check.py +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/core/constants.py +1 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/core/declarations.py +24 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/core/receipt.py +2 -2
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/core/scripts.py +120 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/config.py +1 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/config.toml +4 -4
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/gate-registry.alt.yaml +93 -99
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/gate-registry.yaml +93 -99
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/registry.py +1 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/root_shape.py +6 -47
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/runner.py +54 -8
- package/packages/repo-controls/scripts/hooks/commit-msg +1 -1
- package/packages/repo-controls/scripts/hooks/pre-commit +12 -2
- package/packages/repo-controls/scripts/hooks/pre-push +27 -19
- package/packages/repo-controls/src/cli.ts +22 -3
- package/packages/repo-controls/src/compliance-config.ts +132 -65
- package/packages/repo-controls/src/config.ts +62 -52
- package/packages/repo-controls/src/constants.ts +9 -0
- package/packages/repo-controls/src/coverage-ratchet.ts +19 -4
- package/packages/repo-controls/src/doctor.ts +20 -30
- package/packages/repo-controls/src/findings-ratchet.ts +14 -0
- package/packages/repo-controls/src/gitignore-block.ts +3 -13
- package/packages/repo-controls/src/hook-log.ts +7 -10
- package/packages/repo-controls/src/hook.ts +127 -83
- package/packages/repo-controls/src/install-compliance.ts +112 -0
- package/packages/repo-controls/src/install.ts +133 -30
- package/packages/repo-controls/src/integrity.ts +5 -18
|
@@ -328,8 +328,8 @@ export function maintainRepositories(options: MaintainOptions): MaintainResult {
|
|
|
328
328
|
if (maxAgeDays !== undefined) pruneStale(repo, name, current, maxAgeDays)
|
|
329
329
|
|
|
330
330
|
// 5. the per-repo enrolment.
|
|
331
|
-
const argv = [...options.install.leadingArgs, 'install', '--repo', repo]
|
|
332
|
-
const shown = `adl install --repo ${repo}`
|
|
331
|
+
const argv = [...options.install.leadingArgs, 'install', '--repo', repo, '--rewire']
|
|
332
|
+
const shown = `adl install --repo ${repo} --rewire`
|
|
333
333
|
if (dry) {
|
|
334
334
|
info(`${name}: [dry] would run ${shown}`)
|
|
335
335
|
return
|
|
@@ -341,6 +341,9 @@ export function maintainRepositories(options: MaintainOptions): MaintainResult {
|
|
|
341
341
|
fail(`${name}: ${shown} exited ${result.status}: ${(result.stderr ?? '').trim()}`, repo)
|
|
342
342
|
} else {
|
|
343
343
|
info(`${name}: ${shown}: ok`)
|
|
344
|
+
for (const line of `${result.stdout}${result.stderr}`.split('\n')) {
|
|
345
|
+
if (/WARNING|FAIL|COULD-NOT-RUN/.test(line)) warn(`${name}: ${line.trim()}`)
|
|
346
|
+
}
|
|
344
347
|
}
|
|
345
348
|
}
|
|
346
349
|
|
|
@@ -44,19 +44,22 @@ connection to `enact-vps`.
|
|
|
44
44
|
**This repo's own layout versus what it writes.** Package-owned hook sources
|
|
45
45
|
live under `scripts/hooks/`; commit `20ec790` removed the former
|
|
46
46
|
`scripts/verbatim/` mirror and its manifest when mechanism moved into the
|
|
47
|
-
package. The `.workflows/hooks/` stubs, the `.adl/logs/{
|
|
48
|
-
|
|
47
|
+
package. The `.workflows/hooks/` stubs, the `.adl/logs/git-hooks/{activity,
|
|
48
|
+
deny}.log` JSON-Lines streams (written via `adl-repo-controls log`,
|
|
49
49
|
`src/hook-log.ts` — `.enact/logs/` is a 2026-09-27 hard cut, no longer
|
|
50
50
|
written) and the `core.hooksPath` setting are what `install --repo` wires in
|
|
51
51
|
**target** repos.
|
|
52
52
|
|
|
53
53
|
**Rule values are defaults, not universals.** The bundled defaults are enact-m5's:
|
|
54
|
-
branch prefixes `
|
|
54
|
+
branch prefixes fixed to the commit types minus `release` (`packages/azdo/src/lib/commit-types.ts`), protected `main` and `integration`,
|
|
55
55
|
lowercase kebab-case descriptions, lowercase commit subject with an 80-character
|
|
56
56
|
limit and a fixed type list, plus the coverage ratchet and the behind-origin push
|
|
57
57
|
check. Per-repo values are config-driven, in `adl-config.toml`'s `[controls]`
|
|
58
|
-
table. Installing seeds `branches` and `pre_push.remote`
|
|
59
|
-
every other
|
|
58
|
+
table. Installing seeds `branches` and `pre_push.remote` for `[controls]` and arms no
|
|
59
|
+
push or commit gate there; every other `[controls]` key is absent and therefore off
|
|
60
|
+
until someone adds it. `[controls.compliance]` is the opposite: install seeds the standard
|
|
61
|
+
trees and arms the strict gate set (see
|
|
62
|
+
`docs/architecture/compliance-controls.md#strict-activation-and-switching-a-gate-off`).
|
|
60
63
|
|
|
61
64
|
**`doctor --repo` must detect a dangling `core.hooksPath`.** If the directory it
|
|
62
65
|
points at is missing, git silently runs no hooks and does not error. That is the
|
|
@@ -33,12 +33,10 @@ local .git/config: core.hooksPath = .workflows/hooks
|
|
|
33
33
|
They originated in enact-m5; commit `20ec790` removed the former byte-copy
|
|
34
34
|
tree and manifest when mechanism moved into this package. Their current
|
|
35
35
|
behaviour is exercised by `tests/hooks-e2e.test.ts` and focused unit tests.
|
|
36
|
-
- **Logs** (gitignored): `.adl/logs/
|
|
37
|
-
for every hook invocation; `.adl/logs/hooks
|
|
38
|
-
rows
|
|
39
|
-
|
|
40
|
-
Written via `adl repo controls log` (`src/hook-log.ts`), the same shared
|
|
41
|
-
`writeLogEntry` format every `.adl/logs/*.log` file uses
|
|
36
|
+
- **Logs** (gitignored): `.adl/logs/git-hooks/activity.log` gets a JSON-Lines row
|
|
37
|
+
for every hook invocation; `.adl/logs/git-hooks/deny.log` gets only `FAIL`
|
|
38
|
+
rows. Written via `adl repo controls log` (`src/hook-log.ts`), the same shared
|
|
39
|
+
`writeLogEntry` format every `.adl/logs/<owner>/*.log` file uses
|
|
42
40
|
(docs/architecture/cli-design.md §5a). `.enact/logs/` is a hard cut: nothing writes
|
|
43
41
|
there any more; pre-existing evidence is left in place, never migrated.
|
|
44
42
|
|
|
@@ -186,9 +184,9 @@ or a `Task`/`Agent` launch with `isolation: "worktree"`) — see
|
|
|
186
184
|
`docs/operations/agent-vault-environment.md` for the host-side broker
|
|
187
185
|
contract underneath `adl-agent-id`/`agent-vault` itself.
|
|
188
186
|
- **uv** — only if `[controls.compliance].enabled` is non-empty; see below.
|
|
189
|
-
- **ast-grep** —
|
|
190
|
-
|
|
191
|
-
|
|
187
|
+
- **ast-grep** and **shfmt** — only REP-007 (`no_multiline_comments`) requires
|
|
188
|
+
them (`requires` in `package/adl-compliance/src/adl_compliance/checks/repository/no_multiline_comments/check.py`).
|
|
189
|
+
`doctor` warns, never fails, on a missing `ast-grep`.
|
|
192
190
|
|
|
193
191
|
### Why bun (and not node)
|
|
194
192
|
|
|
@@ -251,8 +249,9 @@ reading those mtimes) — a path whose content is already byte- and
|
|
|
251
249
|
mode-identical is left alone untouched, and anything else (missing,
|
|
252
250
|
altered, or retired) is still deleted or repaired. It then appends its
|
|
253
251
|
`[controls]` table only when that table is missing. It appends the single
|
|
254
|
-
|
|
255
|
-
|
|
252
|
+
one marker-bounded block to `.gitignore` (`/.adl/`, the agent scratch folder,
|
|
253
|
+
`/.coverage-cache/` and the retired log roots kept as quarantine; the list is
|
|
254
|
+
`src/gitignore-block.ts`), writes the lock, and sets `core.hooksPath=.workflows/hooks` with
|
|
256
255
|
`git config --local`.
|
|
257
256
|
- Re-running is a true no-op: the rebuilt root is byte-identical AND no
|
|
258
257
|
managed file's mtime changes when nothing needed correcting.
|
|
@@ -276,15 +275,14 @@ merge into `integration`) runs.
|
|
|
276
275
|
|
|
277
276
|
**doctor** is read-only and exits 1 on any failure: bash >= 4, bun, binary on
|
|
278
277
|
PATH, the bundled compliance package present at its packaged path, repository
|
|
279
|
-
root, `[controls]` config validity, (
|
|
280
|
-
exists whenever `pre_push.coverage_ratchet` is enabled (
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
`[controls.
|
|
284
|
-
doctor names it first), `[controls.compliance]` config validity, `uv` on PATH
|
|
278
|
+
root, `[controls]` config validity, (fail) `coverage/coverage-summary.json`
|
|
279
|
+
exists whenever `pre_push.coverage_ratchet` is enabled, (fail)
|
|
280
|
+
`pre_push.coverage_produce` enabled with no `[controls.coverage].produce_push`
|
|
281
|
+
declared, (fail) the findings floor and counters whenever `pre_push.findings_ratchet`
|
|
282
|
+
is enabled (see "No silent skips" below), `[controls.compliance]` config validity, `uv` on PATH
|
|
285
283
|
(only checked once `[controls.compliance].enabled` is non-empty; otherwise
|
|
286
284
|
reported ok unconditionally, same on-by-default posture as the coverage-summary
|
|
287
|
-
check), (
|
|
285
|
+
check), (fail, same conditioning) `ast-grep` on PATH, lock, each stub
|
|
288
286
|
(present, unedited, executable), `core.hooksPath`, `.gitignore` lines, and
|
|
289
287
|
(warning) lock version skew. When `[controls.release]` is declared, it also
|
|
290
288
|
derives the configured `origin` remote, loads the validated canonical Agent
|
|
@@ -350,12 +348,24 @@ comments) is opaque and is never inspected, reordered, or dropped.
|
|
|
350
348
|
running `install` may effectively create that marker even if `adl hook` itself
|
|
351
349
|
is not installed there. `adl-config.toml` itself is never deleted by uninstall.
|
|
352
350
|
|
|
353
|
-
### Install wires the hooks
|
|
354
|
-
|
|
355
|
-
`install` seeds
|
|
356
|
-
`pre_push.remote`
|
|
357
|
-
`
|
|
358
|
-
|
|
351
|
+
### Install wires the hooks, then arms the strict compliance set
|
|
352
|
+
|
|
353
|
+
`install` seeds the `[controls]` vocabulary (`version`, `branches`,
|
|
354
|
+
`pre_push.remote`) and arms **no push or commit gate** of its own: the
|
|
355
|
+
`[controls]` gates below are absent until somebody adds them. Compliance is the
|
|
356
|
+
opposite. `install` seeds `[controls.compliance]` strict: the standard trees, the
|
|
357
|
+
strict `enabled` set, the folder skeleton, the root entry files and printed
|
|
358
|
+
guidance (see [Compliance seeding](#compliance-seeding) below). The decisions
|
|
359
|
+
and the gate list live in
|
|
360
|
+
[`docs/architecture/compliance-controls.md`](../../docs/architecture/compliance-controls.md#strict-activation-and-switching-a-gate-off).
|
|
361
|
+
`install --rewire` (what fleet reconcile runs on every enrolled repo) seeds nothing,
|
|
362
|
+
scaffolds nothing and does not grade: it only re-deploys the hook stubs, `.workflows`
|
|
363
|
+
and the lock, and leaves adl-config.toml byte-identical. Without `uv`, the `adl install`
|
|
364
|
+
wrapper prints a one-line warning that grading is skipped, finishes deploying and exits 0;
|
|
365
|
+
pre-commit still fails loudly without `uv`. See
|
|
366
|
+
[`docs/architecture/compliance-controls.md`](../../docs/architecture/compliance-controls.md#install-and-re-wire).
|
|
367
|
+
|
|
368
|
+
`branches` and `pre_push.remote` are seeded rather than omitted because they are not gates but the
|
|
359
369
|
vocabulary gates are phrased in, and because `pre-push` reads their env vars with
|
|
360
370
|
`${VAR:?}`, which aborts on an empty value: "no branch policy" cannot be spelled as
|
|
361
371
|
an empty list.
|
|
@@ -367,24 +377,23 @@ disarm or restyle one you set. Granularity is the top-level key inside `[control
|
|
|
367
377
|
an inline table is one attribute, because editing inside one means rewriting bytes
|
|
368
378
|
you own. Nothing is parsed and re-serialized; text is spliced into the table's span.
|
|
369
379
|
|
|
370
|
-
`[controls]` is strictly validated: unknown keys
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
wrapper is ON but whose configuration is missing is a no-op at hook time and a
|
|
374
|
-
*warning* at `doctor` time — informational, never blocking.
|
|
380
|
+
`[controls]` is strictly validated: unknown keys, wrong types and missing gate keys are
|
|
381
|
+
errors. A gate key has no default: an absent one fails config load naming the key, and a
|
|
382
|
+
gate is switched off by an explicit `false`. See "No silent skips" below.
|
|
375
383
|
|
|
376
|
-
| Key | Seeded by install |
|
|
384
|
+
| Key | Seeded by install | When absent | enact-m5 | Effect |
|
|
377
385
|
|---|---|---|---|---|
|
|
378
386
|
| `branches.protected` | yes | *required* | `["main", "integration"]` | pre-push refuses while on these branches |
|
|
379
|
-
| `branches.prefixes` |
|
|
387
|
+
| `branches.prefixes` | removed | a config error naming the key | n/a | not configurable: branch prefixes are the commit types minus `release` (`packages/azdo/src/lib/commit-types.ts`); pre-push / azdo-push enforce `<prefix>/<kebab>`; delete the key |
|
|
380
388
|
| `pre_push.remote` | yes | *required* | `"origin"` | remote azdo-push pushes to and reads status from |
|
|
381
|
-
| `pre_commit.staged_coverage` |
|
|
382
|
-
| `pre_commit.doc_freshness` |
|
|
383
|
-
| `pre_commit.compliance` |
|
|
384
|
-
| `pre_push.coverage_ratchet` |
|
|
385
|
-
| `pre_push.coverage_produce` |
|
|
386
|
-
| `pre_push.findings_ratchet` |
|
|
389
|
+
| `pre_commit.staged_coverage` | yes (`true`) | config error | `true` | enact-m5-only staged coverage measurement (fails when `[controls.coverage].produce` is not declared) |
|
|
390
|
+
| `pre_commit.doc_freshness` | yes (`true`) | config error | opt in | a staged `docs/` or `plans/` `.md` carries a `last_update` stamped within 5h (nothing to grade when no docs are staged) |
|
|
391
|
+
| `pre_commit.compliance` | yes (`true`) | config error | `true` | staged adl-compliance gates (fails when `[controls.compliance].enabled`, read from the staged config, is empty) |
|
|
392
|
+
| `pre_push.coverage_ratchet` | yes (`true`) | config error | `true` | per outgoing commit, `coverage/coverage-summary.json` must exist and not regress (fails when missing) |
|
|
393
|
+
| `pre_push.coverage_produce` | yes (`false`) | config error | opt in | run the coverage MEASUREMENT at push via `[controls.coverage].produce_push` (fails the push when armed with no command declared) |
|
|
394
|
+
| `pre_push.findings_ratchet` | yes (`true`) | config error | opt in | per outgoing commit, every declared static-analysis counter's findings must not exceed the committed floor (fails when the floor file or counters are missing) |
|
|
387
395
|
| `pre_push.static_checks` | no | `[]` | tsc, knip, svelte-check | `{ label, run }` commands run on an export of HEAD, pass cached per tree OID |
|
|
396
|
+
| `release` | yes (`false`) | promotion governance fails at pre-push | `[controls.release]` table | `release = false` opts out of promotion governance; a `[controls.release]` table declares it |
|
|
388
397
|
| `release.source` | no | `""` | `"integration"` | source branch for the managed promotion PR; no branch pair is guessed |
|
|
389
398
|
| `release.target` | no | `""` | `"main"` | target branch for the managed promotion PR |
|
|
390
399
|
| `release.merge_strategy` | no | `"squash"` | `"no-fast-forward"` | one of `squash`, `rebase`, `rebase-merge`, or `no-fast-forward` — sent to Azure DevOps as the matching wire value (`squash`, `rebase`, `rebaseMerge`, `noFastForward`) |
|
|
@@ -508,12 +517,123 @@ runs no build; the approval is the only gate). Pre-commit calls the same read-on
|
|
|
508
517
|
doctor report and never repairs or stages the managed surface: run
|
|
509
518
|
`adl repo controls install --repo .` explicitly to repair it.
|
|
510
519
|
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
520
|
+
#### Compliance seeding
|
|
521
|
+
|
|
522
|
+
`[controls.compliance]` follows the same per-attribute rule. Install seeds:
|
|
523
|
+
|
|
524
|
+
- `[controls.compliance.trees]` with the four adl standard trees `docs`, `plans`,
|
|
525
|
+
`workflows` and `compliance` (default paths `docs/`, `plans/`, `workflows/`,
|
|
526
|
+
`compliance/`); `""` declares "this repository has no such tree". Never a
|
|
527
|
+
deleted tree such as `rust`, `frontend`, `typescript`, `infra` or `dev`. What each tree
|
|
528
|
+
is: [`#standard-trees`](../../docs/architecture/compliance-controls.md#standard-trees),
|
|
529
|
+
and `compliance` as the register folder:
|
|
530
|
+
[`#register-folder-and-ratchets`](../../docs/architecture/compliance-controls.md#register-folder-and-ratchets).
|
|
531
|
+
- `enabled` with **every gate in the engine registry**, one `domain.name` address per
|
|
532
|
+
line, `STRICT_ENABLED_GATES` in `src/compliance-config.ts` (Tarun, 2026-10-08). That
|
|
533
|
+
includes `repository.no-vcs-in-scripts` (GIT-001), `repository.license-declared`,
|
|
534
|
+
`repository.lockfile-integrity`, `docs.adr-lifecycle` and
|
|
535
|
+
`repository.no-multiline-comments`. `tests/strict-gates-registry.test.ts` fails when
|
|
536
|
+
the registry gains a gate the seed lacks, so the two cannot drift; the gates and why
|
|
537
|
+
each is on: [`#gate-catalogue`](../../docs/architecture/compliance-controls.md#gate-catalogue).
|
|
538
|
+
Armed from the first commit with NO ratchet baseline for existing violations, so an
|
|
539
|
+
existing repository reports its violations as guidance. Measured on a fresh install
|
|
540
|
+
(see "Fresh-install result" below), the one gate this package's own install leaves
|
|
541
|
+
failing is `repository.license-declared` (REP-001: no `license` declared). An existing `enabled` key, even `[]`, is never rewritten, and
|
|
542
|
+
switching a gate off is the repository's own decision, made by removing its one line
|
|
543
|
+
from `enabled`
|
|
544
|
+
([`#strict-activation-and-switching-a-gate-off`](../../docs/architecture/compliance-controls.md#strict-activation-and-switching-a-gate-off)).
|
|
545
|
+
`registry` has a working default and is not written.
|
|
546
|
+
- `[controls] integrity = { watched = ["<compliance tree>/**"] }`, the declared
|
|
547
|
+
compliance register folder, so the protection is visible in the file (see
|
|
548
|
+
[Managed dot paths and protected controls](#managed-dot-paths-and-protected-controls)).
|
|
549
|
+
Not written when the tree is declared `""`; an existing `integrity` is never rewritten.
|
|
550
|
+
|
|
551
|
+
An existing `[controls.compliance]` with no `trees` table gets it appended; one
|
|
552
|
+
that already has a `trees` table (any keys) is left byte-identical.
|
|
553
|
+
|
|
554
|
+
Install also scaffolds the repository entry files `AGENTS.md` and `CLAUDE.md`
|
|
555
|
+
(`@AGENTS.md`) at the root when absent (never overwritten) — `SCAFFOLD_ROOT_FILES` in
|
|
556
|
+
`src/constants.ts` is the list. `INVARIANTS.md` is deployed from
|
|
557
|
+
`assets/GLOBAL-INVARIANTS.md`, the invariants that apply to ALL repositories, only when
|
|
558
|
+
the target has none (never overwritten); the engine's root gate still requires
|
|
559
|
+
`INVARIANTS.md`. See Scaffolding below
|
|
560
|
+
for which folders it creates.
|
|
561
|
+
|
|
562
|
+
#### Grading
|
|
563
|
+
|
|
564
|
+
`install` run with `grade: { env }` (what `adl repo controls install` passes) grades
|
|
565
|
+
the repository once its own wiring is written and returns `compliance`:
|
|
566
|
+
`{ ok, enabled, failing[], guidance[] }`. Each failing gate carries its `id`,
|
|
567
|
+
`address`, `status` (`FAIL`, or `ERROR` = could not run, never a pass), summary and
|
|
568
|
+
findings, each with the engine's `fix`. `guidance` is the printable form:
|
|
569
|
+
"This repository now enforces N compliance gates; K failing. Fix the findings below
|
|
570
|
+
before committing." then one block per gate, then the line "To switch a gate off, remove it
|
|
571
|
+
from [controls.compliance] enabled in adl-config.toml — that is this repository's decision,
|
|
572
|
+
and adl-config.toml is a protected file landed by the owner." The engine runs through
|
|
573
|
+
`runTool` (the way `compliance run` and the hooks run it, trees and declarations included)
|
|
574
|
+
with its own `--log-dir`; the `failures.log` there is the structured channel `install`
|
|
575
|
+
parses. `RunContext.quietEngine` discards the engine's stdout rows, because Install prints
|
|
576
|
+
its own guidance and the engine's row listing would otherwise land in the caller's stdout
|
|
577
|
+
and corrupt `install --json`. `ok` is `true` only when every enabled gate passed. Install
|
|
578
|
+
still completes its wiring when gates fail (exit 0, `ok: false`); a missing `uv` is a loud
|
|
579
|
+
error naming `uv` and the real command to re-run (`adl repo controls compliance run --repo .`),
|
|
580
|
+
raised after the wiring is written, and an empty `enabled` reports "nothing is enforced". A
|
|
581
|
+
`--dry-run` never grades.
|
|
582
|
+
|
|
583
|
+
`adl install` (the all-in-one command) is not one repo-controls call: it runs repo-controls
|
|
584
|
+
install with `--no-grade`, then hooks, skills, settings and doctor, and only then grades
|
|
585
|
+
through the `grade` command (`adl repo controls grade --repo <path>`, which prints the
|
|
586
|
+
verdict as JSON and exits 0 whatever the verdict). Grading inside the repo-controls step
|
|
587
|
+
would run before the hooks, skills and settings deploy, so it would under-report what the
|
|
588
|
+
finished install contains. `adl install` prints one report at the end, its top-level `ok`
|
|
589
|
+
means the wiring succeeded (exit 0 when gates fail), and `compliance.ok` stays separate and
|
|
590
|
+
truthful. A `uv`-less machine errors out of the grade step, after everything is wired.
|
|
591
|
+
|
|
592
|
+
#### Scaffolding
|
|
593
|
+
|
|
594
|
+
Install bootstraps the minimal skeleton of `docs`, `plans` and `workflows` from the
|
|
595
|
+
package's `assets/scaffold/<tree>/` (Bug 570, Tarun 2026-10-08):
|
|
596
|
+
`docs/{AGENTS.md,CLAUDE.md,notes.md,decisions/index.md}`,
|
|
597
|
+
`plans/{AGENTS.md,CLAUDE.md,GAPS-AND-FINDINGS.md,LEDGER.md,features/.gitkeep}`, and
|
|
598
|
+
`workflows/{AGENTS.md,CLAUDE.md,pipelines/.gitkeep,scripts/.gitkeep}`. Rules:
|
|
599
|
+
|
|
600
|
+
- **An existing tree folder is ignored entirely** (Tarun, 2026-10-08). If `docs/`,
|
|
601
|
+
`plans/` or `workflows/` (or wherever the tree is declared) already exists at the
|
|
602
|
+
target, empty or not, install adds NOTHING inside it: no missing file, no
|
|
603
|
+
`.gitkeep`. Only a missing folder gets the whole skeleton, so
|
|
604
|
+
`plans/features/.gitkeep` appears only when `plans/` itself is created fresh. Other
|
|
605
|
+
trees are still scaffolded independently. A non-directory in the way of the tree path
|
|
606
|
+
(or a parent) fails the install loudly.
|
|
607
|
+
- The root entry files (`AGENTS.md`, `CLAUDE.md`, `INVARIANTS.md`) are created one by one
|
|
608
|
+
only when absent, never overwritten.
|
|
609
|
+
- `docs/decisions/index.md` makes `docs/decisions/` exist, which `docs.adr-lifecycle`
|
|
610
|
+
(DOC-001) requires; the gate only grades `adr-*.md` files, so the index passes and the
|
|
611
|
+
gate runs on a fresh repository instead of reporting could-not-run.
|
|
612
|
+
- **A tree pointed elsewhere is scaffolded there, never duplicated.** The paths
|
|
613
|
+
come from the effective `[controls.compliance.trees]` after the config step: with
|
|
614
|
+
`docs = "documentation"` the skeleton lands in `documentation/` and no `docs/`
|
|
615
|
+
is created; a tree declared `""`, or not declared, is not scaffolded at all. A
|
|
616
|
+
path that is not repository-relative is refused.
|
|
617
|
+
- **The skeleton is user-owned**: unlike `.workflows/` it is not recorded in the
|
|
618
|
+
lock, uninstall never removes it, and an edited scaffold file is never drift.
|
|
619
|
+
- `compliance` is seeded as a tree but its folder is **not** scaffolded here: it is the
|
|
620
|
+
register folder (ratchets, exemptions) and appears when the first register is
|
|
621
|
+
written. An absent register means "no grants" to the gates that read it.
|
|
622
|
+
- `--dry-run` lists every scaffold file as `create` and writes nothing.
|
|
623
|
+
|
|
624
|
+
#### Fresh-install result
|
|
625
|
+
|
|
626
|
+
The scaffold gates (DOC-001, DOC-002, DOC-004 to DOC-012, LAY-002, LAY-004, LAY-009,
|
|
627
|
+
LAY-011, LAY-014, LAY-016, LFS-001) pass on a fresh install
|
|
628
|
+
(`tests/install-scaffold.test.ts`). Of the 29 enabled gates, the package-level result of a
|
|
629
|
+
fresh install is exactly one failing gate, REP-001 `repository.license-declared`
|
|
630
|
+
(`tests/install-strict.test.ts`). `adl install` also deploys skills, hooks and plugins into
|
|
631
|
+
the repository, and any of their files with consecutive comment lines fail REP-007
|
|
632
|
+
`repository.no-multiline-comments`; that is a defect of the deployed assets, not an expected
|
|
633
|
+
result.
|
|
514
634
|
|
|
515
635
|
Fixed conventions (enact-m5, not configurable): commit subject
|
|
516
|
-
`^(
|
|
636
|
+
`^(<commit type>)(\([a-z0-9][a-z0-9-]*\))?: .+` (types `feat|fix|docs|refactor|perf|chore|release`, defined once in `packages/azdo/src/lib/commit-types.ts` and handed to the hook as `ADL_REPO_CONTROLS_COMMIT_TYPES`; `release` is the pipeline's only), at most 80
|
|
517
637
|
characters, lowercase description without trailing period; `Merge `, `Revert "`
|
|
518
638
|
and `X.Y.Z` subjects exempt; no staged `.scratchpad` paths or new references;
|
|
519
639
|
`git diff --cached --check`; git environment scrubbed before push checks.
|
|
@@ -529,14 +649,18 @@ The pre-commit gate has two deliberately different outcomes:
|
|
|
529
649
|
|
|
530
650
|
- A changed or untracked **top-level** dot path is **commit-required**.
|
|
531
651
|
When it is omitted from the index, the hook names it and tells the author to
|
|
532
|
-
stage it. Once staged, it can be committed normally. This covers
|
|
533
|
-
|
|
534
|
-
`.
|
|
652
|
+
stage it. Once staged, it can be committed normally. This covers top-level dot
|
|
653
|
+
paths that are not protected, such as `.mcp.json`, `.workflows/` and the agent surface roots
|
|
654
|
+
(`.agents/`, `.claude/`, `.codex/`, `.cursor/`, `.kimi-code/`, `.opencode/`): those hold a
|
|
655
|
+
repository's own hooks and skills, so they are not protected as a whole (Bug 644). Nested paths such as
|
|
535
656
|
`tools/.claude/**` are ordinary repository content. The designated ephemeral
|
|
536
657
|
scratch storage is never committable.
|
|
537
658
|
- A **protected control** requires human approval even when staged: every path
|
|
538
|
-
under `compliance/` or `workflows/`, `adl-config.toml`,
|
|
539
|
-
|
|
659
|
+
under `compliance/` or `workflows/`, `adl-config.toml`, the folder declared as `[controls.compliance.trees].compliance`
|
|
660
|
+
(in addition to the fixed `compliance/` root, so a relocated register folder stays
|
|
661
|
+
protected: `integrityWatched` in `src/hook.ts`), and the repository's explicit
|
|
662
|
+
`[controls.integrity].watched` patterns (`PROTECTED_ROOTS` and `WIRING` in `src/integrity.ts`). A repository protects any dot path it chooses through `watched`. The full definition and the
|
|
663
|
+
owner override: [`#protected-paths-and-owner-override`](../../docs/architecture/compliance-controls.md#protected-paths-and-owner-override). The same controls cannot be
|
|
540
664
|
left dirty while committing other work.
|
|
541
665
|
|
|
542
666
|
Git cannot make a pre-commit hook run for `git commit --no-verify`. That is the
|
|
@@ -581,6 +705,8 @@ human makes in the same commit as the fix, the same discipline
|
|
|
581
705
|
|
|
582
706
|
## Configuration — `adl-config.toml` `[controls.compliance]`
|
|
583
707
|
|
|
708
|
+
**Root declarations.** `[controls.compliance.root]` `dirs` are bare names directly under the repository root. `files` may also be relative paths with `/` (for example `.donors/MANIFEST.md`); install refuses an absolute path, a `.`, `..` or empty segment, a glob character, `,` and `=`. The list travels as one comma-separated `--declare root-files=a,b` value, so `,` and `=` would corrupt it, and `dirs` keep the stricter rule because a directory name is matched as a single entry.
|
|
709
|
+
|
|
584
710
|
`install` also appends a `[controls.compliance]` table to the same shared
|
|
585
711
|
`adl-config.toml`, independently of `[controls]` (each table is its own
|
|
586
712
|
append-once/user-owned-afterwards span; installing, editing, or uninstalling one
|
|
@@ -604,24 +730,22 @@ non-empty string.
|
|
|
604
730
|
| Key | Default | Effect |
|
|
605
731
|
|---|---|---|
|
|
606
732
|
| `version` | `1` | config schema version |
|
|
607
|
-
| `enabled` |
|
|
733
|
+
| `enabled` | the strict standard set (see above) | gate ids (ids such as `DOC-001`) or `domain.name` addresses (`layout.references`) to grade; empty = installed, nothing runs |
|
|
608
734
|
| `registry` | `"default"` | forward-compatible; today both values point at the same packaged registry YAML |
|
|
609
|
-
| `[controls.compliance.trees]` |
|
|
735
|
+
| `[controls.compliance.trees]` | the four standard trees (seeded) | per-key path overrides; the bundled engine ships NO tree defaults (`policy/config.toml` `[trees]` is empty), so a tree a gate reads that the repository has not declared is could-not-run naming what to add. See [`#standard-trees`](../../docs/architecture/compliance-controls.md#standard-trees) |
|
|
610
736
|
| `[controls.compliance.limits]` | absent (engine defaults) | per-repository engine limits, strictly validated. `scripts_direct_files` (positive integer) replaces LAY-014's default of 15 direct files per scripts directory and reaches the engine as `--declare scripts-direct-files=N`; a value the engine cannot read as a positive integer is could-not-run, never a fall back to 15. The depth limit is not configurable. `open_gaps` and `open_plans` (each a positive integer) replace LAY-016's default cap of 10 open gaps and 10 open plans, independently, and reach the engine as `--declare open-gaps=N` / `--declare open-plans=N`; the same could-not-run rule applies to each, and a finding names the effective cap as `N open gaps, cap is M`. The engine default stays 10: a repository declares today's measured count and ratchets it down |
|
|
611
737
|
| `[controls.compliance.markdown]` | absent (no extra Markdown roots) | extra Markdown roots for LAY-006 (`layout.markdown-trees`), strictly validated. `roots` is an array of repository-relative directories whose Markdown is site or application content rather than documentation (an Astro site's `src/content/**/*.md`); LAY-006 admits `.md` and `.mdx` beneath each, in addition to the docs trees, so a declared root only ever widens the allowlist and absent is the stricter grade. Reaches the engine as one `--declare markdown-roots=a,b`. An entry that is empty, absolute, contains `,` or `=`, or has a `.`, `..` or empty path segment is rejected when the config loads (a trailing `/` is dropped); the engine refuses the same values as could-not-run (exit 2) |
|
|
612
|
-
| `[controls.compliance.
|
|
738
|
+
| `[controls.compliance.placement]` | absent (LAY-008 uses its built-in asset directories) | extra asset directories for LAY-008 (`layout.placement`), strictly validated. `asset_dirs` is an array of repository-relative directories; reaches the engine as one `--declare asset-dirs=a,b` (omitted when empty). An entry that is empty, absolute, contains `,` or `=`, or has a `.`, `..` or empty path segment is rejected when the config loads (a trailing `/` is dropped); an unknown key is an error |
|
|
739
|
+
| `[controls.compliance.lockfiles]` | absent (REP-002 grades only the repository-root pairs) | exactly which manifest and lockfile paths REP-002 (`repository.lockfile-integrity`) scans and grades, strictly validated. Four arrays: `bun_manifests` / `bun_lockfiles` and `cargo_manifests` / `cargo_lockfiles`. A manifest entry is a repository-relative path or glob ending in `package.json` (`Cargo.toml`), such as `package.json` or `apps/*/package.json`; a lockfile entry is a literal path (a missing one is reported by name). REP-002 always grades the repository-root pairs itself (`package.json` -> `bun.lock`, `Cargo.toml` -> `Cargo.lock`); every other lockfile is graded only when declared here, because the engine does not guess where a repository keeps its workspaces. An ecosystem is declared as a pair. Reaches the engine as `--declare bun-manifests=a,b`, `bun-lockfiles=`, `cargo-manifests=`, `cargo-lockfiles=` (a list is omitted when empty); a declared manifest that matches no file is could-not-run naming it. An entry that is empty, absolute, duplicated, contains `,` `=` `\` `<` `>` `{` `}`, starts with `!`, has a `.`, `..` or empty path segment, ends in the wrong file name, or (for a lockfile) is a glob, an ecosystem with only one of its two lists, and a `REP-002:bun_lock` / `cargo_lock` / `cargo_manifest` / `workspace` input beside the pair it supersedes are all rejected when the config loads; the engine refuses the same values as could-not-run (exit 2) |
|
|
613
740
|
|
|
614
741
|
### Registry curation
|
|
615
742
|
|
|
616
|
-
The
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
package does **not** ship a pre-vetted "safe for any repo" subset; enabling a
|
|
623
|
-
row without pointing its trees at the right paths will simply grade the wrong
|
|
624
|
-
(or nonexistent) files.
|
|
743
|
+
The bundled registry (29 rows, counted from `gate-registry.yaml` and
|
|
744
|
+
`len(CHECKS)`) always ships and loads — `enabled` is what decides which row is
|
|
745
|
+
ever graded, not what is present. The engine ships no tree defaults: a repository
|
|
746
|
+
declares its own in `[controls.compliance.trees]`, and a gate whose tree is
|
|
747
|
+
undeclared is could-not-run, never a pass. The catalogue of gates is
|
|
748
|
+
[`#gate-catalogue`](../../docs/architecture/compliance-controls.md#gate-catalogue).
|
|
625
749
|
|
|
626
750
|
## Development
|
|
627
751
|
|
|
@@ -634,3 +758,169 @@ bun test --coverage # 100% lines + functions gate (bunfig.toml)
|
|
|
634
758
|
Tests run real git in temporary repositories under `.scratchpad/test-tmp/`
|
|
635
759
|
(gitignored), exercising the installed stubs end to end. CI runs them through
|
|
636
760
|
the repository's root pipelines under `workflows/pipelines/`.
|
|
761
|
+
|
|
762
|
+
## Managed workflow scripts
|
|
763
|
+
|
|
764
|
+
Rationale moved out of the scripts that `install` deploys into `.workflows/`, so the
|
|
765
|
+
deployed copies stay free of multi-line comments (REP-007).
|
|
766
|
+
|
|
767
|
+
### `promote.ts`
|
|
768
|
+
|
|
769
|
+
- Managed by adl-repo-controls; do not edit. Regenerate with `adl-repo-controls install --repo .`.
|
|
770
|
+
- Vendored into `.workflows/` byte-for-byte so CI depends on nothing: no adl-repo-controls on PATH,
|
|
771
|
+
no MCP client, no package install. A pipeline agent is a cold environment, and a promotion that
|
|
772
|
+
needs a global npm binary fails there for reasons that have nothing to do with the promotion.
|
|
773
|
+
- Byte-identical in every repository, deliberately. Refs come from the environment, never baked in;
|
|
774
|
+
otherwise each consumer's copy would hash differently and one published hash could not verify any
|
|
775
|
+
of them.
|
|
776
|
+
- No reviewer is named on the promotion PR, deliberately (Tarun, 2026-09-27). Naming one, typically
|
|
777
|
+
the person who pushed to `integration`, is a self-approval risk and contradicts "agent-reviewer is
|
|
778
|
+
optional, never required". The gate is the target branch's own minimum-reviewer policy (verified
|
|
779
|
+
earlier in the script), which excludes the author's own vote.
|
|
780
|
+
|
|
781
|
+
### `reconcile-guard.sh`
|
|
782
|
+
|
|
783
|
+
- Stage 1 of the CI pipeline for pull requests into `integration` (stage 2 runs the tests). It forces
|
|
784
|
+
the PR author, usually an agent, to reconcile with integration before anything merges.
|
|
785
|
+
- The only check: the PR source branch contains integration's tip. The version bump is not a PR
|
|
786
|
+
concern any more; the integration-merge pipeline bumps after the merge (Tarun, 2026-10-01).
|
|
787
|
+
- Read-only: it only fetches and reads. It never pushes, and the only refs it writes are the two
|
|
788
|
+
remote-tracking refs it fetches.
|
|
789
|
+
- CI never carries an agent identity: the script unsets `ADL_AGENT_ID_AGENT` and never inherits one
|
|
790
|
+
from the caller.
|
|
791
|
+
|
|
792
|
+
Further `promote.ts` rationale (moved from its doc comments):
|
|
793
|
+
|
|
794
|
+
- Standard, not repo-local: every repository in this estate is on Azure DevOps, and promoting a
|
|
795
|
+
branch to its trunk is find-or-reuse a PR, then set auto-complete. Ported from enact-m5's
|
|
796
|
+
`workflows/scripts/release/promote-main.ts`, where the mechanism was already injectable (fetch,
|
|
797
|
+
collection, project, repository and token were all parameters); only three module-scoped literals
|
|
798
|
+
made it that repository's: `SOURCE_REF = 'refs/heads/integration'`, `TARGET_REF =
|
|
799
|
+
'refs/heads/main'`, and `title = 'release: promote integration to main'`.
|
|
800
|
+
- The refs are declared as `[controls.release].source` / `.target`. The title is DERIVED from them
|
|
801
|
+
rather than being a third key: a title that can disagree with the refs it describes is a bug
|
|
802
|
+
waiting for someone to change one and forget the other, and the derived form satisfies this
|
|
803
|
+
package's own commit-msg grammar for any pair.
|
|
804
|
+
- The target branch's gate is Tarun's approval alone (Tarun, 2026-09-30): the promotion PR gets NO
|
|
805
|
+
build validation and CD runs after the merge into the target. The pre-flight proves the
|
|
806
|
+
minimum-reviewer policy (>=1 approver, resetOnSourcePush=true) and does not require a build
|
|
807
|
+
policy. `build` is still reported so a caller can show one that happens to be present, but
|
|
808
|
+
nothing demands it.
|
|
809
|
+
- There is no default pair. Defaulting to integration -> main would put one repository's branch
|
|
810
|
+
names back into the package by the back door.
|
|
811
|
+
- Merge strategy: Azure's `GitPullRequestCompletionOptions.mergeStrategy` is sent by name. The REST
|
|
812
|
+
wire values are the camelCase strings; sending the numeric `GitPullRequestMergeStrategy` enum
|
|
813
|
+
ordinal is silently accepted by the type system but is not what the API expects (PR 1477,
|
|
814
|
+
2026-09-27, armed auto-complete with `rebase` although "no-fast-forward" was intended). `squash`
|
|
815
|
+
is the standard, matching the MCP server's PR tool, which admits `enum: ['Squash']` only. A
|
|
816
|
+
repository wanting something else declares it, so the deviation is visible.
|
|
817
|
+
- Policy contract: one contract is used by both promotion and doctor. A configuration only counts
|
|
818
|
+
when it is enabled, blocking, and scoped exactly to the target branch; a project-wide or
|
|
819
|
+
path-filtered lookalike cannot guard a promotion.
|
|
820
|
+
- No named-reviewer policy is checked (Tarun, 2026-09-27): the two-branch standard's `main` gate is
|
|
821
|
+
"exactly one human reviewer, author's vote excluded" via the minimum-reviewer policy, never a
|
|
822
|
+
specific named individual. A required-reviewer-by-identity policy on `main` was PR 1477's second
|
|
823
|
+
live bug: it named the person who pushed to `integration` as a mandatory approver, which both
|
|
824
|
+
self-approves (that person is usually the change's author) and contradicts "agent-reviewer is
|
|
825
|
+
optional, never required".
|
|
826
|
+
- Standalone entry point: reads the refs from the ENVIRONMENT, not from config. The file is vendored
|
|
827
|
+
into `.workflows/` byte-for-byte, so its content must be identical in every repository or a single
|
|
828
|
+
published hash cannot verify any of them; the pipeline supplies repository-specific values through
|
|
829
|
+
environment variables.
|
|
830
|
+
|
|
831
|
+
### `version-bump.sh`
|
|
832
|
+
|
|
833
|
+
- Stage 1 of the promote pipeline (push to `integration`): the integration-merge build owns package
|
|
834
|
+
version allocation (Tarun, 2026-10-01). A PR's build-validation policy ignores `[skip ci]`, so a
|
|
835
|
+
bump pushed from PR CI re-queued itself; a push to a branch honours it. After a merge lands on
|
|
836
|
+
`integration` the script sets the manifest to that commit's version + patch 1:
|
|
837
|
+
`version-bump.sh --file package.json --integration --push`.
|
|
838
|
+
- The Azure Pipelines build checks out the detached triggering commit with persisted credentials, so
|
|
839
|
+
`git push` authenticates as the project build service (needs Contribute and "Bypass policies when
|
|
840
|
+
pushing" on `integration`). The bump commit is created on that checkout, carries `[skip ci]` so the
|
|
841
|
+
push does not trigger this pipeline again, and is pushed as a plain fast-forward, never forced. If
|
|
842
|
+
integration moved since the checkout the push is rejected and the script fails loud; the newer
|
|
843
|
+
merge's own run bumps. No npm query, no PR.
|
|
844
|
+
- CI never carries an agent identity: the push authenticates as the build service through the
|
|
845
|
+
checkout's persisted `System.AccessToken`. The script unsets `ADL_AGENT_ID_AGENT` and never
|
|
846
|
+
inherits one.
|
|
847
|
+
- `[controls.release].pre_bump` (`adl-config.toml`, repo root): ordered, repository-relative scripts a
|
|
848
|
+
multi-language repo runs before the bump commit, for example a Go version constant that nothing in
|
|
849
|
+
`package.json` can reach. No file, or no `pre_bump` key: no scripts, and the resulting commit is
|
|
850
|
+
byte-identical to the behaviour before the feature existed
|
|
851
|
+
(`tests/version-bump-integration-pre-bump.test.ts`).
|
|
852
|
+
- Declared scripts are all validated before any runs, so a bad declaration fails clearly instead of
|
|
853
|
+
leaving the repo half-way through a partial run.
|
|
854
|
+
- Every variable whose name ends `_TOKEN`, `_PAT`, `_SECRET` or `_PASSWORD` (any case), plus
|
|
855
|
+
`SYSTEM_ACCESSTOKEN` and the Azure DevOps credentials by exact name, is stripped from each script's
|
|
856
|
+
environment: a pre_bump script is repo-authored, unreviewed by this package, and has no business
|
|
857
|
+
seeing the pipeline's push credentials. The match is plain bash (no search tool, no `${var^^}`)
|
|
858
|
+
because Azure Pipelines agents do not guarantee ripgrep and macOS ships bash 3.2.
|
|
859
|
+
- A pre_bump script that edits `.git` directly (hooks, config, refs) never shows in `git status`, so
|
|
860
|
+
it is checked separately and the bump refuses. There is no equivalent check for a script writing
|
|
861
|
+
to an absolute path outside the repository: a plain shell script has no sandbox, so only `.git`
|
|
862
|
+
tampering is refused, honestly. Every add is scoped to `$repo_root`, so nothing outside it is staged.
|
|
863
|
+
- `[skip ci]` (Azure DevOps: a push whose commits contain it does not trigger CI pipelines) keeps the
|
|
864
|
+
push from re-running the promote pipeline that made it.
|
|
865
|
+
|
|
866
|
+
## Log folders
|
|
867
|
+
|
|
868
|
+
Bug 600 (Tarun, 2026-10-08): `.adl/logs/` has one folder per owner and no file
|
|
869
|
+
is written by two owners. The git hooks write `git-hooks/activity.log` (every
|
|
870
|
+
invocation) and `git-hooks/deny.log` (FAIL rows only); they no longer share a
|
|
871
|
+
deny file with agent-hooks (`agent-hooks/deny.log`). The old top-level
|
|
872
|
+
`repo-controls.log` and `hooks-deny.log` are left where they are, never
|
|
873
|
+
migrated. A git-hook row has `host: git` and is written by the same writer as
|
|
874
|
+
agent-hook rows (`packages/agent-hooks/src/log/writer.ts`).
|
|
875
|
+
|
|
876
|
+
`.enact/logs/` is pre-hard-cut evidence only: nothing writes there, and the
|
|
877
|
+
managed `.gitignore` block keeps ignoring it alongside the two legacy hook-log
|
|
878
|
+
roots. Hook and session logs live under `.adl/logs/<owner>/` (`agent-hooks/`,
|
|
879
|
+
`git-hooks/`, `agents/`), covered by the block's `/.adl/` line.
|
|
880
|
+
|
|
881
|
+
A log write that fails never changes a git hook's exit code; `hook-log.ts`
|
|
882
|
+
prints one `adl repo controls: could not write log row: ...` line to stderr.
|
|
883
|
+
|
|
884
|
+
## No silent skips
|
|
885
|
+
|
|
886
|
+
Tarun, 2026-10-09: an armed gate whose input is missing fails loud; switching a gate off is an
|
|
887
|
+
explicit `false` in `adl-config.toml`, an owner decision.
|
|
888
|
+
|
|
889
|
+
- Install seeds every gate key under `[controls]` (`pre_commit.*`, `pre_push.coverage_ratchet`,
|
|
890
|
+
`coverage_produce`, `findings_ratchet`) and `release = false`. A consumer config missing a gate key
|
|
891
|
+
fails to load, naming the key. `release` is the exception: an absent `[controls.release]` loads, and
|
|
892
|
+
fails the pre-push promotion check instead, telling the owner to declare source/target or set
|
|
893
|
+
`release = false`.
|
|
894
|
+
- Coverage ratchet: with the gate on, a summary missing from both HEAD and the work tree fails, and so does
|
|
895
|
+
a missing HEAD~1 baseline unless the summary is added in HEAD (a loud first-baseline note). A file with
|
|
896
|
+
no baseline entry is reported as "new, now baselined"; a file dropped from the summary while it still
|
|
897
|
+
exists on disk fails.
|
|
898
|
+
- Findings ratchet: a missing floor file fails, and so does a floor entry for a counter not declared in
|
|
899
|
+
`[controls.findings.counters]`.
|
|
900
|
+
- Staged coverage with an empty `[controls.coverage].produce` fails at commit.
|
|
901
|
+
- Compliance: the flag and `enabled` are both read from the staged `adl-config.toml`; flag true with
|
|
902
|
+
`enabled` empty fails.
|
|
903
|
+
- `doctor` reports these prerequisites as `fail` (not `warn`) while the governing gate is on, and the
|
|
904
|
+
pre-commit doctor gate prints them.
|
|
905
|
+
- `ADL_SKIP_STAGED_COVERAGE` was a dead export (nothing read it) and is removed.
|
|
906
|
+
|
|
907
|
+
## No silent skips
|
|
908
|
+
|
|
909
|
+
Tarun, 2026-10-09: an armed gate with a missing input fails loudly; it never
|
|
910
|
+
degrades to a pass.
|
|
911
|
+
|
|
912
|
+
- The pre-push static-check pass marker is keyed by the HEAD tree OID plus a
|
|
913
|
+
hash of the declared `static_checks` (label and command) and the
|
|
914
|
+
`export_links` list, so editing a check invalidates a cached pass. No marker
|
|
915
|
+
is written when zero static checks ran.
|
|
916
|
+
- A declared `export_links` entry whose target is missing in the checkout fails
|
|
917
|
+
the push instead of being skipped.
|
|
918
|
+
- A static check with an empty label or an empty command fails the push. The
|
|
919
|
+
entry is split on its first tab by hand because `read` with a tab `IFS`
|
|
920
|
+
collapses a leading tab and would shift the command into the label.
|
|
921
|
+
- In `workflows/scripts/coverage`, a full or `--merge-only` run with no
|
|
922
|
+
committed baseline at `HEAD:coverage/coverage-summary.json` fails unless
|
|
923
|
+
`--first-baseline` is passed; `--only` legs still never grade. The ratchet
|
|
924
|
+
reports a measured file with no baseline entry as "new file, baselined", the
|
|
925
|
+
sanitize step says when HEAD has no summary, and auto-publish no longer
|
|
926
|
+
falls back to the working summary or the candidate as its own baseline.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Invariants
|
|
2
|
+
|
|
3
|
+
The things this repository must never regress. These apply to every repository
|
|
4
|
+
adl manages; add this repository's own below, one bullet each, stating the rule
|
|
5
|
+
and how it is verified.
|
|
6
|
+
|
|
7
|
+
- The compliance gates enabled in `adl-config.toml` pass before every commit
|
|
8
|
+
(verified by `adl repo controls` pre-commit and CI). A gate is switched off by
|
|
9
|
+
removing it from `[controls.compliance] enabled`, which is the owner's decision.
|
|
10
|
+
- Protected paths (`adl-config.toml`, `.workflows/`, the agent surface folders,
|
|
11
|
+
`workflows/` and the declared compliance register folder) are landed only by the
|
|
12
|
+
owner. An agent leaves them uncommitted and asks (verified by the pre-commit
|
|
13
|
+
integrity gate).
|
|
14
|
+
- Ratchets only shrink. A register names the specific files granted, and a grant
|
|
15
|
+
is removed once its file is clean, never added to (verified by the gate that reads
|
|
16
|
+
the register).
|
|
17
|
+
- No multi-line comments in code. The explanation lives in `docs/`, and the code
|
|
18
|
+
keeps at most a one-line pointer (verified by `repository.no-multiline-comments`).
|
|
19
|
+
- The standard trees `docs`, `plans`, `workflows` and `compliance` are declared in
|
|
20
|
+
`[controls.compliance.trees]`, and layout rules follow those declarations
|
|
21
|
+
(verified by the layout and docs gates).
|