@amsterdamdatalabs/adl-agent-control-linux-x64 0.1.29 → 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.
- 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/cli/args.ts +2 -2
- package/packages/agent-hooks/src/cli/doctor.ts +2 -1
- package/packages/agent-hooks/src/cli/rules.ts +2 -1
- package/packages/agent-hooks/src/deploy/opencode-template.ts +5 -3
- package/packages/agent-hooks/src/gating/config.ts +11 -0
- package/packages/agent-hooks/src/gating/running-adl.ts +24 -0
- 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/hooks/user-prompt-submit/handler.ts +2 -2
- package/packages/agent-hooks/src/log/writer.ts +170 -24
- package/packages/agent-hooks/src/main.ts +11 -4
- package/packages/agent-hooks/src/pre-tool-use/handler.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-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/azdo-wit.ts +8 -2
- package/packages/azdo/src/mcp-server.ts +1 -1
- package/packages/fleet/manifest.json +2 -1
- package/packages/fleet/src/repo-maintain.ts +5 -2
- package/packages/repo-controls/AGENTS.md +7 -4
- package/packages/repo-controls/README.md +346 -56
- 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/pre-commit +12 -2
- package/packages/repo-controls/scripts/hooks/pre-push +38 -20
- 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 +55 -46
- 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/package/adl-compliance/src/adl_compliance/policy/gate-registry.yaml
CHANGED
|
@@ -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
|
-
#
|
|
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
|
-
# (
|
|
84
|
-
#
|
|
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
|
-
#
|
|
89
|
-
#
|
|
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
|
-
#
|
|
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
|
-
-
|
|
414
|
-
-
|
|
415
|
-
-
|
|
416
|
-
-
|
|
417
|
-
|
|
418
|
-
#
|
|
419
|
-
#
|
|
420
|
-
|
|
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:
|
|
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:
|
|
500
|
-
#
|
|
501
|
-
#
|
|
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
|
|
711
|
-
#
|
|
712
|
-
#
|
|
713
|
-
#
|
|
714
|
-
#
|
|
715
|
-
#
|
|
716
|
-
#
|
|
717
|
-
-
|
|
718
|
-
-
|
|
719
|
-
-
|
|
720
|
-
-
|
|
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-
|
|
686
|
+
name: no-legacy-search
|
|
725
687
|
domain: repository
|
|
726
|
-
title: Forbid
|
|
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
|
-
#
|
|
733
|
-
#
|
|
734
|
-
#
|
|
735
|
-
|
|
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
|
|
@@ -69,7 +69,7 @@ class EngineSpec(StrictModel):
|
|
|
69
69
|
"""Ordered list, last match wins, '!' excludes. Not a grant: it carries no
|
|
70
70
|
signature and there is nothing to shrink.
|
|
71
71
|
|
|
72
|
-
Stored EXPANDED: `<
|
|
72
|
+
Stored EXPANDED: `<docs>/guides/**` is `documentation/guides/**` by the time
|
|
73
73
|
anything reads this. Nothing downstream knows placeholders exist, which is
|
|
74
74
|
the point — one mechanism resolves the consumer's layout, at load, and the
|
|
75
75
|
matcher sees ordinary repository-relative globs."""
|
package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/root_shape.py
CHANGED
|
@@ -57,9 +57,7 @@ VCS_AND_META: frozenset[str] = frozenset({
|
|
|
57
57
|
|
|
58
58
|
GUIDES: frozenset[str] = frozenset({
|
|
59
59
|
"AGENTS.md",
|
|
60
|
-
"CLAUDE-INVARIANTS.md",
|
|
61
60
|
"CLAUDE.md",
|
|
62
|
-
"INDEPENDENT-VERIFICATION.md",
|
|
63
61
|
"INVARIANTS.md",
|
|
64
62
|
"README.md",
|
|
65
63
|
})
|
|
@@ -93,33 +91,18 @@ NODE_TOOLCHAIN: frozenset[str] = frozenset({
|
|
|
93
91
|
".nvmrc",
|
|
94
92
|
".prettierrc",
|
|
95
93
|
".prettierignore",
|
|
96
|
-
#
|
|
97
|
-
# already has to Docker in `VCS_AND_META` — a paired root-required ignore
|
|
98
|
-
# file, not a look-alike added on resemblance. Deliberately NOT extended
|
|
99
|
-
# to `.markdownlint.json`/`.markdownlintignore`/`.yamllint.yml`: grepped
|
|
100
|
-
# for real in the one consumer repository that carries all three
|
|
101
|
-
# (enact-extensions) — zero hits in `package.json`, `bun.lock`, any
|
|
102
|
-
# `scripts/` file, or `azure-pipelines.yml`. Nothing in that repository's
|
|
103
|
-
# own tooling invokes markdownlint or yamllint; they read as editor-only
|
|
104
|
-
# preference files there, not a root file some build step requires to
|
|
105
|
-
# find, so they stay off this list until a consumer shows otherwise.
|
|
94
|
+
# Paired root-required ignore file like `.dockerignore`; markdownlint/yamllint files are declared by the repository.
|
|
106
95
|
"biome.json",
|
|
107
96
|
"bun.lock",
|
|
108
97
|
"bunfig.toml",
|
|
109
98
|
"eslint.config.js",
|
|
110
|
-
"index.html",
|
|
111
|
-
"knip.json",
|
|
112
99
|
"opencode.json",
|
|
113
100
|
"opencode.jsonc",
|
|
114
101
|
"package-lock.json",
|
|
115
102
|
"package.json",
|
|
116
|
-
"playwright.config.ts",
|
|
117
103
|
"pnpm-lock.yaml",
|
|
118
|
-
"svelte.config.js",
|
|
119
104
|
"tsconfig.json",
|
|
120
105
|
"tsconfig.base.json",
|
|
121
|
-
"vite.config.ts",
|
|
122
|
-
"vitest.config.ts",
|
|
123
106
|
"yarn.lock",
|
|
124
107
|
})
|
|
125
108
|
|
|
@@ -147,18 +130,10 @@ PROJECT_CONFIG: frozenset[str] = frozenset({
|
|
|
147
130
|
# `azure-pipelines.yml` at their root, and `layout.placement`/
|
|
148
131
|
# `layout.root-closed-set` both reported it as undeclared, a false
|
|
149
132
|
# failure on every Azure-DevOps-driven consumer this package can
|
|
150
|
-
# plausibly serve.
|
|
151
|
-
#
|
|
133
|
+
# plausibly serve. A build/deploy
|
|
134
|
+
# pipeline definition naming THIS repository's own stages,
|
|
152
135
|
# not a language-specific toolchain file.
|
|
153
|
-
"coverage-floor.json",
|
|
154
|
-
"ctx_overlays.json",
|
|
155
|
-
"docker-compose.yml",
|
|
156
|
-
"drizzle.config.ts",
|
|
157
136
|
"adl-config.toml",
|
|
158
|
-
# An adl-controlled Enact repository carries BOTH config files at its root,
|
|
159
|
-
# permanently (Tarun, 2026-10-01: "there will be both"). Built in here so no
|
|
160
|
-
# repository declares it by hand under `[controls.compliance.root] files`.
|
|
161
|
-
"enact-config.toml",
|
|
162
137
|
"justfile",
|
|
163
138
|
})
|
|
164
139
|
|
|
@@ -195,37 +170,21 @@ AGENT_TREES: frozenset[str] = frozenset({
|
|
|
195
170
|
})
|
|
196
171
|
|
|
197
172
|
KNOWLEDGE_TREES: frozenset[str] = frozenset({
|
|
198
|
-
".changeset",
|
|
199
|
-
".docs",
|
|
200
|
-
".donors",
|
|
201
173
|
"docs",
|
|
202
174
|
"plans",
|
|
203
|
-
"specs",
|
|
204
175
|
})
|
|
205
176
|
|
|
206
|
-
# Only
|
|
207
|
-
# repository that has them declares them under `[controls.compliance.root] dirs`.
|
|
208
|
-
# (Tarun, 2026-10-01 — reverses the 2026-09-27 central listing.)
|
|
177
|
+
# Only adl's own or language-neutral trees (PBI 601); any other layout is declared under `[controls.compliance.root] dirs`.
|
|
209
178
|
SOURCE_TREES: frozenset[str] = frozenset({
|
|
210
|
-
"backend",
|
|
211
|
-
"compliance",
|
|
212
|
-
"docker",
|
|
213
179
|
"bin",
|
|
214
|
-
"
|
|
215
|
-
"frontend",
|
|
216
|
-
"infra",
|
|
217
|
-
"live-probes",
|
|
180
|
+
"compliance",
|
|
218
181
|
"packages",
|
|
219
182
|
"scripts",
|
|
220
|
-
"server",
|
|
221
|
-
"shared",
|
|
222
183
|
"src",
|
|
223
|
-
"src-tauri",
|
|
224
|
-
"static",
|
|
225
184
|
"tests",
|
|
226
185
|
# The CI tree: pipelines, pipeline-templates, scripts, tools. Distinct from
|
|
227
186
|
# `.workflows/`, which is adl-repo-controls' managed hook stubs and lock, and
|
|
228
|
-
# both are live
|
|
187
|
+
# both are live -- one is what Azure runs, the other is what git runs. A repository
|
|
229
188
|
# carrying both is not mid-migration, and LAY-012 calling this one undeclared said
|
|
230
189
|
# it was. (Owner decision, 2026-09-15.)
|
|
231
190
|
"workflows",
|
|
@@ -27,6 +27,12 @@ from .policy.grants import granted
|
|
|
27
27
|
from .policy.registry import Row
|
|
28
28
|
|
|
29
29
|
|
|
30
|
+
def _names_unknown_tree(relative: str, trees: Mapping[str, str] | None) -> bool:
|
|
31
|
+
"""Does `relative` name a `<tree>` the effective map has no entry for at all?"""
|
|
32
|
+
known = trees or {}
|
|
33
|
+
return any(match.group(1) not in known for match in PLACEHOLDER.finditer(relative))
|
|
34
|
+
|
|
35
|
+
|
|
30
36
|
def resolve_inputs(
|
|
31
37
|
check: type[Check],
|
|
32
38
|
root: Path,
|
|
@@ -34,6 +40,7 @@ def resolve_inputs(
|
|
|
34
40
|
stack: ExitStack,
|
|
35
41
|
trees: Mapping[str, str] | None = None,
|
|
36
42
|
declared_trees: Mapping[str, str] | None = None,
|
|
43
|
+
dropped: dict[str, str] | None = None,
|
|
37
44
|
) -> dict[str, Path]:
|
|
38
45
|
"""Declared logical names -> absolute paths. The only place inputs are joined.
|
|
39
46
|
|
|
@@ -80,6 +87,8 @@ def resolve_inputs(
|
|
|
80
87
|
# Declared-absent behaves like undeclared here; which of the two it
|
|
81
88
|
# was decides below whether that is fatal or merely narrowing.
|
|
82
89
|
if not absent(relative, trees)
|
|
90
|
+
# A WIDENING input (register of grants) with an unknown tree is "no register", never an error (PBI 599).
|
|
91
|
+
and not (name in check.widening_inputs and _names_unknown_tree(relative, trees))
|
|
83
92
|
}
|
|
84
93
|
except TreeMapError as exc:
|
|
85
94
|
raise CouldNotRun(f"{check.id} declares an input naming an unknown tree: {exc}") from exc
|
|
@@ -99,6 +108,9 @@ def resolve_inputs(
|
|
|
99
108
|
# only produce MORE findings. The check reads it with
|
|
100
109
|
# `.get()` and must never assume it is present.
|
|
101
110
|
resolved.pop(name, None)
|
|
111
|
+
if dropped is not None and name not in check.widening_inputs:
|
|
112
|
+
# Bug 597: a non-widening input dropped because its tree is declared ""; `run` turns a subscript of it into could-not-run.
|
|
113
|
+
dropped[name] = tree
|
|
102
114
|
break
|
|
103
115
|
raise CouldNotRun(
|
|
104
116
|
f"{check.id} requires `{name}`; declare "
|
|
@@ -116,7 +128,7 @@ def resolve_inputs(
|
|
|
116
128
|
# Overrides are keyed BY GATE ID. A flat map was handed to every selected
|
|
117
129
|
# row, and the unknown-name guard below then failed every check that did not
|
|
118
130
|
# happen to declare that name -- so declaring the one input `LAY-004` needs
|
|
119
|
-
# took
|
|
131
|
+
# took a managed repository from 14 PASS to 18 ERROR / 1 FAIL / 0 PASS. The channel was
|
|
120
132
|
# unusable the moment anyone used it, which is why no repository in the
|
|
121
133
|
# fleet had ever declared an input.
|
|
122
134
|
mine = override.get(check.id) if override else None
|
|
@@ -168,7 +180,7 @@ def applicable_files(
|
|
|
168
180
|
|
|
169
181
|
given_paths = tuple(given)
|
|
170
182
|
narrowed = FileSet(paths=scope.intersect(patterns, given_paths))
|
|
171
|
-
if not narrowed and exhaustive:
|
|
183
|
+
if not narrowed and exhaustive and not (check.empty_scope_is_clean and restated is None):
|
|
172
184
|
raise CouldNotRun(
|
|
173
185
|
f"engine.scope matches no file on disk ({' | '.join(patterns)}); "
|
|
174
186
|
"a scope selecting nothing is could-not-run, never a clean pass"
|
|
@@ -236,6 +248,9 @@ def prepare_batches(
|
|
|
236
248
|
except CouldNotRun as exc:
|
|
237
249
|
results[row.id] = BatchResult(error=str(exc))
|
|
238
250
|
continue
|
|
251
|
+
except Exception as exc:
|
|
252
|
+
results[row.id] = BatchResult(error=_crashed(check, exc))
|
|
253
|
+
continue
|
|
239
254
|
if not files:
|
|
240
255
|
results[row.id] = BatchResult()
|
|
241
256
|
continue
|
|
@@ -259,13 +274,17 @@ def prepare_batches(
|
|
|
259
274
|
)
|
|
260
275
|
try:
|
|
261
276
|
produced = provider.run(request)
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
277
|
+
if not isinstance(produced, Mapping):
|
|
278
|
+
raise TypeError(
|
|
279
|
+
f"batch provider {key!r} returned {type(produced).__name__}, "
|
|
280
|
+
"not a mapping of gate id to BatchResult"
|
|
281
|
+
)
|
|
282
|
+
extra = sorted(set(produced) - set(files_by_gate))
|
|
283
|
+
except Exception as exc:
|
|
284
|
+
results.update({gate: BatchResult(error=f"{gate} crashed: {type(exc).__name__}: {exc}") for gate in files_by_gate})
|
|
265
285
|
continue
|
|
266
286
|
|
|
267
287
|
expected = set(files_by_gate)
|
|
268
|
-
extra = sorted(set(produced) - expected)
|
|
269
288
|
if extra:
|
|
270
289
|
reason = (
|
|
271
290
|
f"batch provider {key!r} returned unrequested gate result(s): "
|
|
@@ -288,6 +307,10 @@ def prepare_batches(
|
|
|
288
307
|
return results
|
|
289
308
|
|
|
290
309
|
|
|
310
|
+
def _crashed(check_class: type[Check], exc: Exception) -> str:
|
|
311
|
+
return f"{check_class.id} crashed: {type(exc).__name__}: {exc}"
|
|
312
|
+
|
|
313
|
+
|
|
291
314
|
def run(
|
|
292
315
|
row: Row,
|
|
293
316
|
root: Path,
|
|
@@ -338,8 +361,10 @@ def run(
|
|
|
338
361
|
)
|
|
339
362
|
except CouldNotRun as exc:
|
|
340
363
|
return could_not_run(row, str(exc))
|
|
364
|
+
except Exception as exc:
|
|
365
|
+
return could_not_run(row, _crashed(check_class, exc))
|
|
341
366
|
|
|
342
|
-
if (check_class.whole_scope or restated is not None) and not narrowed:
|
|
367
|
+
if (check_class.whole_scope or check_class.empty_scope_is_clean or restated is not None) and not narrowed:
|
|
343
368
|
return decide(row, (), (), ())
|
|
344
369
|
|
|
345
370
|
missing = [tool for tool in check_class.requires if shutil.which(tool) is None]
|
|
@@ -352,6 +377,7 @@ def run(
|
|
|
352
377
|
if batch is None:
|
|
353
378
|
batch = BatchResult(error=f"no batch result was prepared for {row.id}")
|
|
354
379
|
|
|
380
|
+
dropped: dict[str, str] = {}
|
|
355
381
|
try:
|
|
356
382
|
with ExitStack() as stack:
|
|
357
383
|
# A structural grant is already spent by the time the findings
|
|
@@ -363,7 +389,9 @@ def run(
|
|
|
363
389
|
allowance = granted(row.resolved_grants(trees, declared_trees), root)
|
|
364
390
|
context = Context(
|
|
365
391
|
root=root, row=row,
|
|
366
|
-
inputs=resolve_inputs(
|
|
392
|
+
inputs=resolve_inputs(
|
|
393
|
+
check_class, root, inputs, stack, trees, declared_trees, dropped
|
|
394
|
+
),
|
|
367
395
|
declarations=dict(declarations or {}),
|
|
368
396
|
committed_sizes=dict(committed_sizes or {}),
|
|
369
397
|
batch_reports=batch.reports if batch is not None else None,
|
|
@@ -373,11 +401,29 @@ def run(
|
|
|
373
401
|
# valid while `as_file` holds it, and a lazy generator would read it
|
|
374
402
|
# after the stack closed.
|
|
375
403
|
reported = tuple(check_class().run(context, narrowed))
|
|
404
|
+
for item in reported:
|
|
405
|
+
if not isinstance(item, (Finding, Advisory)):
|
|
406
|
+
raise TypeError(f"produced {type(item).__name__}, not a Finding or Advisory")
|
|
376
407
|
except CouldNotRun as exc:
|
|
377
408
|
return could_not_run(row, str(exc))
|
|
378
409
|
except OSError as exc:
|
|
379
410
|
# An unreadable input is a tool failure, not a violation (F-05).
|
|
380
411
|
return could_not_run(row, f"{type(exc).__name__}: {exc}")
|
|
412
|
+
except KeyError as exc:
|
|
413
|
+
# Bug 597: an input dropped for a tree declared "" is could-not-run, never clean; any other KeyError is a crash (below).
|
|
414
|
+
name = exc.args[0] if exc.args else None
|
|
415
|
+
if isinstance(name, str) and name in dropped:
|
|
416
|
+
return could_not_run(
|
|
417
|
+
row,
|
|
418
|
+
f"{check_class.id} requires input `{name}` from tree <{dropped[name]}>, "
|
|
419
|
+
f"which adl-config.toml declares absent ([controls.compliance.trees]."
|
|
420
|
+
f"{dropped[name]} = \"\"); nothing to grade, and a gate that graded "
|
|
421
|
+
"nothing is could-not-run, never a clean pass",
|
|
422
|
+
)
|
|
423
|
+
return could_not_run(row, _crashed(check_class, exc))
|
|
424
|
+
except Exception as exc:
|
|
425
|
+
# Bug 597: one check's unexpected exception is that row's could-not-run, not every row's.
|
|
426
|
+
return could_not_run(row, _crashed(check_class, exc))
|
|
381
427
|
|
|
382
428
|
# Partitioned by TYPE, not by a flag on one record. An advisory that could be
|
|
383
429
|
# mistaken for a finding eventually is one, and then it moves a verdict.
|
|
@@ -19,11 +19,21 @@ scratchpad_allowlisted() {
|
|
|
19
19
|
# `scripts/hooks/pre-commit` is where it LIVES in adl-repo-controls. Both
|
|
20
20
|
# are this same policy naming the thing it polices, which is what this
|
|
21
21
|
# allowlist is for.
|
|
22
|
-
.gitignore | .dockerignore | AGENTS.md | .workflows/hooks/pre-commit | scripts/hooks/pre-commit | src/integrity.ts | workflows/scripts/tests/hooks/*) return 0 ;;
|
|
22
|
+
.gitignore | .dockerignore | AGENTS.md | .workflows/hooks/pre-commit | scripts/hooks/pre-commit | packages/repo-controls/scripts/hooks/pre-commit | src/integrity.ts | workflows/scripts/tests/hooks/*) return 0 ;;
|
|
23
23
|
esac
|
|
24
24
|
return 1
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
added_lines_mention_scratchpad() {
|
|
28
|
+
local diff line
|
|
29
|
+
diff="$(git diff --cached -- "$1")"
|
|
30
|
+
[[ "$diff" == *.scratchpad* ]] || return 1
|
|
31
|
+
while IFS= read -r line; do
|
|
32
|
+
[[ "$line" == +* && "$line" != +++* && "$line" == *.scratchpad* ]] && return 0
|
|
33
|
+
done <<<"$diff"
|
|
34
|
+
return 1
|
|
35
|
+
}
|
|
36
|
+
|
|
27
37
|
staged_files=()
|
|
28
38
|
scratchpad_paths=()
|
|
29
39
|
while IFS= read -r -d '' file; do
|
|
@@ -43,7 +53,7 @@ fi
|
|
|
43
53
|
offenders=()
|
|
44
54
|
for file in "${staged_files[@]}"; do
|
|
45
55
|
scratchpad_allowlisted "$file" && continue
|
|
46
|
-
if
|
|
56
|
+
if added_lines_mention_scratchpad "$file"; then
|
|
47
57
|
offenders+=("$file")
|
|
48
58
|
fi
|
|
49
59
|
done
|