@amsterdamdatalabs/adl-agent-control-linux-x64 0.1.12 → 0.1.28
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/git +16 -17
- package/bin/git-ado +25 -24
- package/bin/git-defaults +173 -0
- package/bin/health-check +8 -1
- package/bin/kimi-hooks +1 -1
- package/bin/lib/adl-package.sh +257 -0
- package/bin/lib/fleet-host.sh +8 -5
- package/bin/reconcile +482 -232
- package/bin/reconcile-host +30 -20
- package/bin/setup +20 -17
- package/bin/shell-path-policy +15 -5
- package/bin/sync-and-reconcile +62 -64
- package/bin/validate-manifest +33 -9
- package/package.json +2 -10
- package/packages/agent-hooks/README.md +14 -9
- package/packages/agent-hooks/assets/hooks.json +0 -20
- package/packages/agent-hooks/src/cli/args.ts +1 -1
- package/packages/agent-hooks/src/cli/doctor.ts +6 -58
- package/packages/agent-hooks/src/deploy/deploy.ts +12 -41
- package/packages/agent-hooks/src/deploy/doctor.ts +8 -11
- package/packages/agent-hooks/src/deploy/index.ts +14 -14
- package/packages/agent-hooks/src/deploy/json-merge.ts +7 -8
- package/packages/agent-hooks/src/deploy/legacy-lock.ts +2 -2
- package/packages/agent-hooks/src/deploy/list.ts +1 -1
- package/packages/agent-hooks/src/deploy/lock.ts +31 -12
- package/packages/agent-hooks/src/deploy/profile.ts +3 -4
- package/packages/agent-hooks/src/deploy/source.ts +1 -1
- package/packages/agent-hooks/src/gating/config.ts +12 -24
- package/packages/agent-hooks/src/gating/root.ts +3 -3
- package/packages/agent-hooks/src/hooks/briefing/handler.ts +2 -2
- package/packages/agent-hooks/src/hooks/briefing/index.ts +27 -287
- package/packages/agent-hooks/src/hooks/contract.ts +17 -17
- package/packages/agent-hooks/src/hooks/crg/background.ts +27 -0
- package/packages/agent-hooks/src/hooks/crg/index.ts +7 -6
- package/packages/agent-hooks/src/hooks/log.ts +8 -10
- package/packages/agent-hooks/src/hooks/user-prompt-submit/match.ts +1 -1
- package/packages/agent-hooks/src/hooks/user-prompt-submit/tokenizer.ts +1 -1
- package/packages/agent-hooks/src/hooks/user-prompt-submit/vector.ts +6 -5
- package/packages/agent-hooks/src/hosts/registry.ts +1 -1
- package/packages/agent-hooks/src/log/adl-dir.ts +44 -0
- package/packages/agent-hooks/src/log/writer.ts +16 -2
- package/packages/agent-hooks/src/main.ts +7 -41
- package/packages/agent-hooks/src/pre-tool-use/handler.ts +71 -82
- package/packages/agent-hooks/src/rules/engine.ts +13 -17
- package/packages/agent-hooks/src/rules/impl/adl-build-run-denied.ts +3 -3
- package/packages/agent-hooks/src/rules/impl/adl-git-credential-bypass.ts +12 -14
- package/packages/agent-hooks/src/rules/impl/adl-git-identity.ts +28 -28
- package/packages/agent-hooks/src/rules/impl/adl-git-push-policy.ts +8 -9
- package/packages/agent-hooks/src/rules/impl/adl-human-azdo-bypass.ts +56 -59
- package/packages/agent-hooks/src/rules/impl/adl-identity.ts +16 -23
- package/packages/agent-hooks/src/rules/impl/adl-mcp-cli.ts +19 -16
- package/packages/agent-hooks/src/rules/impl/adl-pr-complete-pending.ts +2 -2
- package/packages/agent-hooks/src/rules/impl/adl-pr-review-role.ts +9 -12
- package/packages/agent-hooks/src/rules/impl/adl-pr-role.ts +5 -7
- package/packages/agent-hooks/src/rules/impl/adl-run-required.ts +411 -0
- package/packages/agent-hooks/src/rules/impl/adl-token-minting-role.ts +4 -5
- package/packages/agent-hooks/src/rules/impl/adl-workitem-role.ts +6 -7
- package/packages/agent-hooks/src/rules/impl/agent-tamper-protection.ts +77 -70
- package/packages/agent-hooks/src/rules/impl/deny-allowlist.ts +131 -0
- package/packages/agent-hooks/src/rules/impl/git-helpers.ts +21 -23
- package/packages/agent-hooks/src/rules/impl/git-worktree.ts +14 -28
- package/packages/agent-hooks/src/rules/impl/mcp-tool.ts +3 -3
- package/packages/agent-hooks/src/rules/impl/messages.ts +1 -1
- package/packages/agent-hooks/src/rules/impl/pr-completion.ts +1 -1
- package/packages/agent-hooks/src/rules/impl/tool-azure-devops.ts +35 -46
- package/packages/agent-hooks/src/rules/impl/tool-find.ts +34 -7
- package/packages/agent-hooks/src/rules/impl/tool-grep.ts +33 -12
- package/packages/agent-hooks/src/rules/impl/tool-native-search.ts +52 -9
- package/packages/agent-hooks/src/rules/ports.ts +5 -7
- package/packages/agent-hooks/src/rules/registry.ts +4 -6
- package/packages/agent-hooks/src/rules/shell/git-identity.ts +86 -101
- package/packages/agent-hooks/src/rules/shell/git-internals.ts +1 -1
- package/packages/agent-hooks/src/rules/shell/invocation.ts +24 -118
- package/packages/agent-hooks/src/rules/shell/piped-script.ts +1 -1
- package/packages/agent-hooks/src/rules/shell/prefixes.ts +1 -1
- package/packages/agent-hooks/src/rules/shell/protected-carrier-writes.ts +11 -10
- package/packages/agent-hooks/src/rules/shell/protected-carriers.ts +26 -26
- package/packages/agent-hooks/src/rules/shell/substitution.ts +1 -1
- package/packages/agent-hooks/src/rules/shell/xargs.ts +2 -2
- package/packages/agent-hooks/src/rules/spec.ts +2 -2
- package/packages/agent-settings/README.md +287 -0
- package/packages/agent-settings/assets/GLOBAL-AGENTS.md +14 -16
- package/packages/agent-settings/assets/agents/architect.toml +2 -0
- package/packages/agent-settings/assets/agents/code-reviewer.toml +2 -0
- package/packages/agent-settings/assets/agents/executor.toml +2 -0
- package/packages/agent-settings/assets/agents/explore.toml +2 -0
- package/packages/agent-settings/assets/agents/planner.toml +2 -0
- package/packages/agent-settings/assets/mcp.json +0 -4
- package/packages/agent-settings/deploy-profile.json +139 -0
- package/packages/agent-settings/deploy-profile.schema.json +147 -0
- package/packages/agent-settings/managed/README.md +29 -30
- package/packages/agent-settings/managed/codex-requirements.toml +9 -9
- package/packages/agent-settings/package.json +20 -0
- package/packages/agent-settings/src/deploy/agent-render.ts +2 -2
- package/packages/agent-settings/src/deploy/agent-toml.ts +1 -1
- package/packages/agent-settings/src/deploy/agents-deploy.ts +17 -3
- package/packages/agent-settings/src/deploy/doctor.ts +3 -83
- package/packages/agent-settings/src/deploy/index.ts +6 -33
- package/packages/agent-settings/src/deploy/legacy-lock.ts +6 -6
- package/packages/agent-settings/src/deploy/list.ts +5 -19
- package/packages/agent-settings/src/deploy/lock.ts +8 -18
- package/packages/agent-settings/src/deploy/mcp-deploy.ts +10 -5
- package/packages/agent-settings/src/deploy/mcp-merge.ts +22 -3
- package/packages/agent-settings/src/deploy/mcp-source.ts +1 -1
- package/packages/agent-settings/src/deploy/profile.ts +11 -35
- package/packages/agent-settings/src/deploy/retire-lean-ctx.ts +184 -0
- package/packages/agent-settings/src/deploy/settings.ts +17 -22
- package/packages/agent-settings/src/global-surface-sweep.ts +0 -2
- package/packages/agent-settings/src/kimi-hooks.ts +339 -192
- package/packages/agent-settings/src/opencode-hooks.ts +1 -1
- package/packages/agent-settings/tsconfig.json +23 -0
- package/packages/agent-skills/assets/agent-search-tool-audit/SKILL.md +120 -0
- package/packages/agent-skills/assets/agent-search-tool-audit/scripts/audit.sh +276 -0
- package/packages/agent-skills/assets/debug-issue/SKILL.md +8 -7
- package/packages/agent-skills/assets/explore-codebase/SKILL.md +13 -13
- package/packages/agent-skills/assets/refactor-safely/SKILL.md +12 -11
- package/packages/agent-skills/assets/review-changes/SKILL.md +7 -7
- package/packages/agent-skills/assets/testing/references/e2e.md +37 -0
- package/packages/agent-skills/assets/testing/references/integration.md +37 -0
- package/packages/agent-skills/assets/testing/references/unit.md +32 -0
- package/packages/agent-skills/dist/deploy.d.ts +2 -0
- package/packages/agent-skills/dist/deploy.d.ts.map +1 -1
- package/packages/agent-skills/dist/deploy.js +27 -1
- package/packages/agent-skills/dist/deploy.js.map +1 -1
- package/packages/agent-skills/dist/doctor.d.ts +0 -2
- package/packages/agent-skills/dist/doctor.d.ts.map +1 -1
- package/packages/agent-skills/dist/doctor.js +1 -1
- package/packages/agent-skills/dist/doctor.js.map +1 -1
- package/packages/agent-skills/dist/fs-utils.d.ts +0 -1
- package/packages/agent-skills/dist/fs-utils.d.ts.map +1 -1
- package/packages/agent-skills/dist/fs-utils.js +1 -1
- package/packages/agent-skills/dist/fs-utils.js.map +1 -1
- package/packages/agent-skills/src/deploy.ts +29 -1
- package/packages/agent-skills/src/doctor.ts +1 -1
- package/packages/agent-skills/src/fs-utils.ts +1 -1
- package/packages/azdo/README.md +10 -9
- package/packages/azdo/package.json +1 -3
- package/packages/azdo/scripts/probe-ado-rules.ts +311 -0
- package/packages/azdo/src/azdo-pl.ts +2 -54
- package/packages/azdo/src/azdo-pr-review.ts +4 -4
- package/packages/azdo/src/azdo-repo-doctor.ts +101 -52
- package/packages/azdo/src/azdo-wit.ts +44 -2
- package/packages/azdo/src/lib/agent-identity.ts +12 -14
- package/packages/azdo/src/lib/agent-token.ts +2 -2
- package/packages/azdo/src/lib/client.ts +0 -5
- package/packages/azdo/src/lib/graph-identity.ts +4 -4
- package/packages/azdo/src/workflow-ladder.csv +241 -0
- package/packages/azdo/src/workflow-rules-matrix.csv +85 -0
- package/packages/azdo/src/workflow-rules.ts +194 -0
- package/packages/fleet/manifest.json +35 -11
- package/packages/fleet/manifest.schema.json +62 -10
- package/packages/fleet/src/default-agent-file.ts +3 -3
- package/packages/fleet/src/install-adl-package.ts +73 -15
- package/packages/fleet/src/install-embedding-model.ts +13 -13
- package/packages/fleet/src/managed-settings.ts +7 -7
- package/packages/fleet/src/repo-maintain.ts +91 -55
- package/packages/fleet/src/scratch-reap.ts +5 -5
- package/packages/fleet/src/vscode-settings.ts +5 -5
- package/packages/repo-controls/README.md +141 -43
- package/packages/repo-controls/assets/promote.ts +4 -4
- package/packages/repo-controls/assets/reconcile-guard.sh +10 -46
- package/packages/repo-controls/assets/version-bump.sh +31 -84
- package/packages/repo-controls/bunfig.toml +6 -7
- package/packages/repo-controls/package/adl-compliance/AGENTS.md +5 -6
- package/packages/repo-controls/package/adl-compliance/conftest.py +3 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/__init__.py +4 -16
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/adr_lifecycle/test_check.py +9 -2
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/closed_set/fixtures/docs/notes.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/closed_set/test_check.py +11 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/__init__.py +7 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/check.py +266 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/docs/guide/.drafts/c.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/docs/guide/.drafts/d.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/docs/guide/.hidden.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/docs/guide/a.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/docs/guide/b.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/docs/guide/data.csv +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/docs/guide/diagram.png +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/docs/guide/mock.png +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/docs/guide/sub/nested.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/docs.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/grants.yaml +4 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/plans/deep/p1.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/plans/deep/p2.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/plans/deep/p3.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/plans/deep/p4.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/plans/deep/p5.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-clean/docs/architecture/build.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-clean/docs/architecture/overview.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-clean/docs/guide/install.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-clean/docs/guide/start.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-clean/grants.yaml +4 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-decisions/docs/decisions/adr-001-tenancy.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-decisions/docs/decisions/adr-002-carrier.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-decisions/docs/decisions/adr-003-cli.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-decisions/docs/decisions/archive/adr-000-old.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-decisions/docs/decisions/archive/adr-000-older.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-decisions/docs/guide/a.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-decisions/docs/guide/b.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-decisions/docs/guide/c.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-decisions/grants.yaml +4 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-default-cap/docs/guide/page-01.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-default-cap/docs/guide/page-02.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-default-cap/docs/guide/page-03.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-default-cap/docs/guide/page-04.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-default-cap/docs/guide/page-05.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-default-cap/docs/guide/page-06.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-default-cap/docs/guide/page-07.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-default-cap/docs/guide/page-08.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-default-cap/docs/guide/page-09.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-default-cap/docs/guide/page-10.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-default-cap/docs/guide/page-11.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-default-cap/docs/guide/page-12.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-default-cap/docs/guide/page-13.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-default-cap/docs/guide/page-14.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-default-cap/docs/guide/page-15.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-default-cap/docs/guide/page-16.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-default-cap/grants.yaml +4 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-exempt/docs/guide/a.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-exempt/docs/guide/b.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-exempt/docs/guide/c.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-exempt/grants.yaml +4 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-grew/docs/guide/a.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-grew/docs/guide/b.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-grew/docs/guide/c.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-grew/grants.yaml +4 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-no-section/docs/guide/a.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-no-section/docs/guide/b.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-no-section/docs/guide/c.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-no-section/docs/guide/d.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-no-section/docs/guide/e.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-no-section/grants.yaml +4 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-over-cap/docs/guide/a.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-over-cap/docs/guide/b.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-over-cap/docs/guide/c.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-over-cap/docs/short/only.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-over-cap/grants.yaml +4 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-stale/docs/held/a.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-stale/docs/held/b.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-stale/docs/held/c.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-stale/docs/held/d.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-stale/docs/shrunk/a.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-stale/docs/shrunk/b.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-stale/grants.yaml +6 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-unusable/docs/guide/a.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-unusable/docs/guide/b.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-unusable/docs/guide/c.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-unusable/grants.yaml +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/test_check.py +345 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/english_only/check.py +18 -5
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/english_only/test_check.py +35 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/__init__.py +7 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/check.py +91 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/AGENTS.md +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/CLAUDE.md +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/architecture/-leading-hyphen.md +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/architecture/AGENTS.md +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/architecture/double--hyphen.md +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/architecture/getting started.md +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/architecture/nested/page-here.md +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/architecture/trailing-hyphen-.md +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/architecture/ui-contract.md +4 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/architecture/user_profile.md +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/assets/UI-CONTRACT.png +2 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/assets/diagram.png +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/index.md +4 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/notes.md +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/reference.html +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/research/2026-10-experiment.md +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/research/UI-CONTRACT.md +6 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs.md +5 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/test_check.py +194 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/indexes/check.py +14 -2
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/indexes/docs-knowledge-indexes.yaml +5 -5
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/indexes/fixtures/knowledge-indexes-shipped-register-legacy/docs/compliance/index.md +10 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/indexes/fixtures/knowledge-indexes-shipped-register-type/docs/compliance/index.md +10 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/indexes/test_check.py +58 -6
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/ledger/test_check.py +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/check.py +64 -17
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/docs-okf-profiles.yaml +60 -9
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-ledger-clean/docs/notes.md +17 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-ledger-no-lines/docs/notes.md +13 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-profile-clean/docs/architecture/demo.md +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-profile-clean/docs-okf-profiles.yaml +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-profile-untyped/docs/research/no-type.md +9 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-profile-untyped/docs/research/typed-experiment.md +10 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-profile-untyped/docs/research/typed-research.md +10 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-profile-untyped/docs-okf-profiles.yaml +5 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-profile-violation/docs/architecture/bad-status.md +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-profile-violation/docs-okf-profiles.yaml +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/experiment-ok.md +15 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/extra-key.md +15 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/extra-keys.md +16 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/missing-created.md +11 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/missing-description.md +11 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/missing-last-update.md +11 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/missing-sources.md +10 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/missing-status.md +11 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/missing-title.md +11 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/optional-keys.md +16 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/research-ok.md +14 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research-neighbours/docs/architecture/created-date.md +21 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research-neighbours/docs/architecture/research-shaped.md +19 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research-neighbours/docs/operations/runbook.md +26 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/test_check.py +228 -2
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/register.py +5 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/semantics/test_check.py +11 -2
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/__init__.py +5 -3
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/check.py +160 -44
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-clean/grants.yaml +0 -2
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-empty-register/frontend/packages/desktop/src/a.ts +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-empty-register/frontend/packages/desktop/src/b.ts +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-empty-register/grants.yaml +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/grants.yaml +0 -2
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-missing-tree/frontend/packages/desktop/src/renderer/solo/item.ts +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-missing-tree/grants.yaml +5 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-no-ceilings/frontend/packages/desktop/src/a.ts +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-no-ceilings/frontend/packages/desktop/src/b.ts +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-no-ceilings/frontend/packages/desktop/src/c.ts +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-no-ceilings/grants.yaml +4 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-stale-entry/frontend/packages/desktop/src/renderer/solo/item.ts +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-stale-entry/grants.yaml +5 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unbaselined/grants.yaml +0 -2
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unusable-register/frontend/packages/desktop/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/grants.yaml +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/register.py +127 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/test_check.py +265 -29
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/markdown_trees/check.py +75 -2
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/markdown_trees/test_check.py +194 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/open_work_cap/check.py +56 -10
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/open_work_cap/test_check.py +258 -2
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/placement/check.py +40 -12
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/placement/test_check.py +108 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/plan_metadata.py +9 -4
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/plans_layout/check.py +1 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/plans_layout/fixtures/plans-layout-clean/plans/features/az347-test-coverage/items/az351-restore-entrypoint.md +1 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/plans_layout/test_check.py +3 -3
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/references/check.py +2 -3
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/check.py +23 -6
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/test_check.py +76 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_markdown_allowlist/check.py +58 -17
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_markdown_allowlist/test_check.py +161 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/scripts_size_depth/check.py +35 -3
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/scripts_size_depth/test_check.py +108 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/check.py +281 -61
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/absolute-path.yaml +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/backslash-path.yaml +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/baseline-is-a-list.yaml +2 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/boolean-size.yaml +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/dot-segment.yaml +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/duplicate-path.yaml +4 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/empty-file.yaml +0 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/empty-segment.yaml +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/float-size.yaml +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/negative-size.yaml +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/no-over-limit-baseline.yaml +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/no-schema-version.yaml +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/non-string-path.yaml +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/not-yaml.yaml +2 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/null-size.yaml +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/parent-segment.yaml +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/string-size.yaml +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/top-level-is-a-list.yaml +2 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/trailing-slash.yaml +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/unknown-key.yaml +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/wrong-schema-version.yaml +2 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/zero-size.yaml +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/valid.yaml +4 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/test_check.py +758 -45
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/ignored_paths/check.py +4 -3
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/ignored_paths/test_check.py +2 -2
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/cargo_lock.py +490 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/check.py +368 -55
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/test_check.py +4 -2
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/test_declared_paths.py +523 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/test_stale_lock.py +1179 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/cli.py +122 -3
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/core/check.py +33 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/core/constants.py +0 -11
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/core/context.py +16 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/config.py +1 -2
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/docs_shape.py +12 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/gate-registry.alt.yaml +133 -147
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/gate-registry.yaml +133 -147
- 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 +52 -10
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/runner.py +23 -4
- package/packages/repo-controls/package.json +2 -9
- package/packages/repo-controls/scripts/hooks/post-merge +13 -0
- package/packages/repo-controls/scripts/hooks/pre-push +3 -3
- package/packages/repo-controls/src/azdo-push.ts +64 -36
- package/packages/repo-controls/src/azure-devops-governance.ts +7 -9
- package/packages/repo-controls/src/azure-devops-remote.ts +1 -1
- package/packages/repo-controls/src/cli.ts +29 -8
- package/packages/repo-controls/src/compliance-config.ts +410 -2
- package/packages/repo-controls/src/config.ts +133 -60
- package/packages/repo-controls/src/constants.ts +13 -27
- package/packages/repo-controls/src/coverage-ratchet.ts +4 -4
- package/packages/repo-controls/src/doctor.ts +46 -19
- package/packages/repo-controls/src/gitignore-block.ts +5 -29
- package/packages/repo-controls/src/hook-log.ts +1 -2
- package/packages/repo-controls/src/hook.ts +201 -45
- package/packages/repo-controls/src/install.ts +14 -8
- package/packages/repo-controls/src/integrity.ts +3 -3
- package/packages/repo-controls/src/lfs.ts +111 -0
- package/packages/repo-controls/src/promote.ts +8 -8
- package/packages/repo-controls/src/runtime.ts +9 -1
- package/packages/repo-controls/src/workflows-drift.ts +4 -5
- package/packages/repo-controls/src/worktree-guard.ts +3 -3
|
@@ -9,9 +9,13 @@ nothing to contribute.
|
|
|
9
9
|
Four rules, evaluated independently per path (a single path can trip more than
|
|
10
10
|
one):
|
|
11
11
|
|
|
12
|
-
1. root allowlist a file with no `/` must be on the
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
1. root allowlist a file with no `/` must be on the allowlist of files
|
|
13
|
+
legitimately committed at the repository root: the
|
|
14
|
+
central set in `policy/root_shape.py` plus whatever the
|
|
15
|
+
repository itself declares (`root-files`).
|
|
16
|
+
2. apps/ retired any path under the retired `apps/` tree -- unless the
|
|
17
|
+
repository declares `apps` among its root directories
|
|
18
|
+
(`root-dirs`), which says `apps/` is live there.
|
|
15
19
|
3. stray artifacts a throwaway extension (`.log`/`.tmp`/`.bak`/`.swp`,
|
|
16
20
|
checked STRICTLY, everywhere) or a screenshot/image
|
|
17
21
|
basename outside the enumerated asset directories.
|
|
@@ -45,7 +49,12 @@ from typing import ClassVar
|
|
|
45
49
|
from ....core.check import Check
|
|
46
50
|
from ....core.context import Context, FileSet
|
|
47
51
|
from ....core.finding import Report
|
|
48
|
-
from ....policy.root_shape import
|
|
52
|
+
from ....policy.root_shape import (
|
|
53
|
+
ALLOWED_ROOT_FILES,
|
|
54
|
+
ROOT_DIRS_DECLARATION,
|
|
55
|
+
allowed_root_files,
|
|
56
|
+
declared_root_names,
|
|
57
|
+
)
|
|
49
58
|
|
|
50
59
|
|
|
51
60
|
class Placement(Check):
|
|
@@ -62,6 +71,10 @@ class Placement(Check):
|
|
|
62
71
|
# `.attributes` and `.ignore`, which LAY-012 had long since corrected to
|
|
63
72
|
# `.gitattributes` and `.gitignore` — so the same file was permitted by one
|
|
64
73
|
# gate and reported by the other.
|
|
74
|
+
#
|
|
75
|
+
# This is the CENTRAL default only. What is actually graded is the effective
|
|
76
|
+
# set, `allowed_root_files(ctx.declarations)`: this plus the names the
|
|
77
|
+
# repository declares under `[controls.compliance.root] files`.
|
|
65
78
|
ROOT_ALLOWLIST: ClassVar[frozenset[str]] = ALLOWED_ROOT_FILES
|
|
66
79
|
|
|
67
80
|
THROWAWAY_SUFFIXES: ClassVar[tuple[str, ...]] = (
|
|
@@ -139,24 +152,34 @@ class Placement(Check):
|
|
|
139
152
|
)
|
|
140
153
|
|
|
141
154
|
def _md_src_trees(self, ctx: Context) -> tuple[str, ...]:
|
|
142
|
-
|
|
155
|
+
# Decision for a tree declared absent (`rust = ""`, which drops
|
|
156
|
+
# `rust_root` from the resolved inputs): the rust root only contributes
|
|
157
|
+
# an extra PREFIX to the trees whose `src/` Markdown is reported, so a
|
|
158
|
+
# repository with no Rust tree has nothing under it to report and
|
|
159
|
+
# contributes nothing. The literal `agent/` tree still governs. This read
|
|
160
|
+
# `ctx.inputs['rust_root']` unguarded -- a `KeyError` traceback (exit 1),
|
|
161
|
+
# not a verdict, on any `.md` path.
|
|
162
|
+
rust_root = ctx.inputs.get("rust_root")
|
|
163
|
+
if rust_root is None:
|
|
164
|
+
return self.MD_SRC_TREES_LITERAL
|
|
165
|
+
return self.MD_SRC_TREES_LITERAL + (f"{ctx.relative(rust_root)}/",)
|
|
143
166
|
|
|
144
167
|
def graded(self, ctx: Context, files: FileSet) -> Iterable[Report]:
|
|
145
168
|
# `LC_ALL=C sort` in the shell is a byte-order sort; Python's default
|
|
146
169
|
# string ordering matches it for the ASCII repository-relative paths
|
|
147
170
|
# this row ever sees.
|
|
148
171
|
for relative in sorted(files):
|
|
149
|
-
yield from self._root_allowlist(relative)
|
|
150
|
-
yield from self._apps_retired(relative)
|
|
172
|
+
yield from self._root_allowlist(ctx, relative)
|
|
173
|
+
yield from self._apps_retired(ctx, relative)
|
|
151
174
|
yield from self._stray_artifact(ctx, relative)
|
|
152
175
|
yield from self._md_sprawl(ctx, relative)
|
|
153
176
|
|
|
154
177
|
# -- Rule 1: root-level allowlist ---------------------------------------
|
|
155
178
|
|
|
156
|
-
def _root_allowlist(self, relative: str) -> Iterable[Report]:
|
|
179
|
+
def _root_allowlist(self, ctx: Context, relative: str) -> Iterable[Report]:
|
|
157
180
|
if "/" in relative:
|
|
158
181
|
return
|
|
159
|
-
if relative in
|
|
182
|
+
if relative in allowed_root_files(ctx.declarations):
|
|
160
183
|
return
|
|
161
184
|
# The allowlist is ~60 entries. Printing all of them per finding buries
|
|
162
185
|
# the one fact the line is reporting, and five findings produced three
|
|
@@ -164,13 +187,18 @@ class Placement(Check):
|
|
|
164
187
|
yield self.report(
|
|
165
188
|
relative,
|
|
166
189
|
f"root: '{relative}' is not on the root allowlist",
|
|
167
|
-
f"move '{relative}' into an owning subdirectory, or
|
|
168
|
-
"
|
|
190
|
+
f"move '{relative}' into an owning subdirectory, or declare it under "
|
|
191
|
+
"[controls.compliance.root] files in this repository's adl-config.toml "
|
|
192
|
+
"if it genuinely belongs at the root",
|
|
169
193
|
)
|
|
170
194
|
|
|
171
195
|
# -- Rule 2 (numbered 4 in check.sh): apps/ is retired ------------------
|
|
172
196
|
|
|
173
|
-
def _apps_retired(self, relative: str) -> Iterable[Report]:
|
|
197
|
+
def _apps_retired(self, ctx: Context, relative: str) -> Iterable[Report]:
|
|
198
|
+
# A repository that declares `apps` as a root directory has said `apps/`
|
|
199
|
+
# is live there; "apps is retired" would contradict its own declaration.
|
|
200
|
+
if "apps" in declared_root_names(ctx.declarations, ROOT_DIRS_DECLARATION):
|
|
201
|
+
return
|
|
174
202
|
if relative.startswith("apps/"):
|
|
175
203
|
yield self.report(
|
|
176
204
|
relative,
|
|
@@ -228,3 +228,111 @@ def test_a_redeclared_rust_root_still_catches_md_sprawl(tmp_path: pathlib.Path)
|
|
|
228
228
|
f"real markdown sprawl under a redeclared rust root went "
|
|
229
229
|
f"unreported: {findings}"
|
|
230
230
|
)
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
# ---------------------------------------------- per-repository root declarations
|
|
234
|
+
def graded_declaring(
|
|
235
|
+
declarations: dict[str, str], paths: tuple[str, ...], root: pathlib.Path = ALLOWED
|
|
236
|
+
) -> Verdict:
|
|
237
|
+
"""`graded_directly`, plus what the repository declared about its own root
|
|
238
|
+
(`[controls.compliance.root]` arrives as the `root-files` / `root-dirs`
|
|
239
|
+
declarations)."""
|
|
240
|
+
ctx = Context(
|
|
241
|
+
root=root, row=ROW, declarations=declarations,
|
|
242
|
+
inputs={
|
|
243
|
+
"docs_root": root / "docs",
|
|
244
|
+
"rust_root": root / "backend",
|
|
245
|
+
"frontend_root": root / "frontend",
|
|
246
|
+
"specs_root": root / ".specs",
|
|
247
|
+
},
|
|
248
|
+
)
|
|
249
|
+
findings = tuple(Placement().graded(ctx, FileSet(paths=paths)))
|
|
250
|
+
return decide(ROW, findings, 0, ())
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
def test_a_non_standard_root_file_is_reported_without_a_declaration() -> None:
|
|
254
|
+
"""STATUS.md is not on the central list any more: without the repository
|
|
255
|
+
declaring it, it is an undeclared root file."""
|
|
256
|
+
verdict = graded_declaring({}, ("STATUS.md",))
|
|
257
|
+
assert verdict.outcome is Outcome.FINDINGS, verdict.render()
|
|
258
|
+
assert [f.path for f in verdict.findings] == ["STATUS.md"]
|
|
259
|
+
assert "root allowlist" in verdict.findings[0].message
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
def test_a_declared_root_file_is_accepted() -> None:
|
|
263
|
+
verdict = graded_declaring({"root-files": "STATUS.md,DRIFT.md"}, ("STATUS.md", "DRIFT.md"))
|
|
264
|
+
assert verdict.outcome is Outcome.CLEAN, verdict.render()
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
def test_a_declaration_admits_only_the_names_it_lists() -> None:
|
|
268
|
+
"""Without this, the case above also passes against a gate that stops
|
|
269
|
+
grading the root as soon as any declaration is present."""
|
|
270
|
+
verdict = graded_declaring({"root-files": "STATUS.md"}, ("STATUS.md", "DRIFT.md"))
|
|
271
|
+
assert [f.path for f in verdict.findings] == ["DRIFT.md"], verdict.render()
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
def test_a_root_dirs_declaration_does_not_admit_a_root_file() -> None:
|
|
275
|
+
verdict = graded_declaring({"root-dirs": "STATUS.md"}, ("STATUS.md",))
|
|
276
|
+
assert [f.path for f in verdict.findings] == ["STATUS.md"], verdict.render()
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
def test_the_root_file_remedy_points_at_the_declaration_not_at_source() -> None:
|
|
280
|
+
"""The old remedy sent a reader to edit `policy/root_shape.py` in the shared
|
|
281
|
+
package. The repository owns the declaration, so the remedy names it."""
|
|
282
|
+
finding = graded_declaring({}, ("STATUS.md",)).findings[0]
|
|
283
|
+
assert "[controls.compliance.root]" in finding.fix, finding.fix
|
|
284
|
+
assert "adl-config.toml" in finding.fix, finding.fix
|
|
285
|
+
assert "root_shape.py" not in finding.fix, finding.fix
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
def test_apps_stays_retired_unless_the_repository_declares_it() -> None:
|
|
289
|
+
"""The retired-`apps/` rule is active by default, and declaring a DIFFERENT
|
|
290
|
+
directory does not switch it off."""
|
|
291
|
+
for declarations in ({}, {"root-dirs": "packaging"}, {"root-files": "apps"}):
|
|
292
|
+
verdict = graded_declaring(declarations, ("apps/legacy/file.ts",))
|
|
293
|
+
assert [f.path for f in verdict.findings] == ["apps/legacy/file.ts"], declarations
|
|
294
|
+
assert "apps-retired" in verdict.findings[0].message
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
def test_a_declared_apps_directory_is_not_retired() -> None:
|
|
298
|
+
"""A declared `apps/` contradicts "apps is retired", so the rule stands down."""
|
|
299
|
+
for declarations in ({"root-dirs": "apps"}, {"root-dirs": "packaging, apps"}):
|
|
300
|
+
verdict = graded_declaring(declarations, ("apps/legacy/file.ts", "apps/cli/src/main.ts"))
|
|
301
|
+
assert verdict.outcome is Outcome.CLEAN, (declarations, verdict.render())
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
def test_enact_config_is_a_built_in_root_file_beside_adl_config() -> None:
|
|
305
|
+
"""Owner decision (Tarun, 2026-10-01): an adl-controlled Enact repository
|
|
306
|
+
carries BOTH `adl-config.toml` and `enact-config.toml` at its root,
|
|
307
|
+
permanently. Neither is declared by hand under `[controls.compliance.root]`."""
|
|
308
|
+
verdict = graded_declaring({}, ("adl-config.toml", "enact-config.toml"))
|
|
309
|
+
assert verdict.outcome is Outcome.CLEAN, verdict.render()
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
def test_an_unknown_root_toml_still_fails_beside_enact_config() -> None:
|
|
313
|
+
"""Without this, the case above also passes against a gate that admits
|
|
314
|
+
every root `.toml`."""
|
|
315
|
+
verdict = graded_declaring({}, ("enact-config.toml", "random.toml"))
|
|
316
|
+
assert [f.path for f in verdict.findings] == ["random.toml"], verdict.render()
|
|
317
|
+
|
|
318
|
+
|
|
319
|
+
# ------------------------------------------------- a tree declared absent
|
|
320
|
+
def test_a_rust_tree_declared_absent_contributes_nothing_to_md_sprawl(
|
|
321
|
+
tmp_path: pathlib.Path,
|
|
322
|
+
) -> None:
|
|
323
|
+
"""`rust = ""` (the repository states it has no Rust tree) drops `rust_root`
|
|
324
|
+
from the resolved inputs. In `_md_src_trees` that input only ever ADDS a
|
|
325
|
+
prefix to the trees whose `src/` Markdown is reported, so absent it
|
|
326
|
+
contributes nothing and the literal `agent/` tree still governs. This was a
|
|
327
|
+
`KeyError: 'rust_root'` traceback (exit 1, not could-not-run) on any `.md`
|
|
328
|
+
path, measured against enact-combined with `--tree rust= --tree frontend=`.
|
|
329
|
+
The rule is not switched off: `agent/**/src/*.md` is still reported."""
|
|
330
|
+
ctx = Context(root=tmp_path, row=ROW, inputs={"docs_root": tmp_path / "docs"})
|
|
331
|
+
findings = tuple(
|
|
332
|
+
Placement().graded(
|
|
333
|
+
ctx,
|
|
334
|
+
FileSet(paths=("notes/overview.md", "backend/crates/x/src/n.md", "agent/crates/x/src/n.md")),
|
|
335
|
+
)
|
|
336
|
+
)
|
|
337
|
+
assert [f.path for f in findings] == ["agent/crates/x/src/n.md"], findings
|
|
338
|
+
assert "md-sprawl" in findings[0].message
|
|
@@ -11,15 +11,20 @@ class PlanMetadata:
|
|
|
11
11
|
|
|
12
12
|
WORK_ITEM_STATUSES: ClassVar[tuple[str, ...]] = (
|
|
13
13
|
"New",
|
|
14
|
+
"In Planning",
|
|
15
|
+
"Awaiting Approval",
|
|
14
16
|
"Approved",
|
|
15
|
-
"
|
|
16
|
-
"In
|
|
17
|
+
"Spec Validation",
|
|
18
|
+
"In Implementation",
|
|
17
19
|
"In Testing",
|
|
20
|
+
"In Review",
|
|
21
|
+
"Updating Docs",
|
|
18
22
|
"Done",
|
|
23
|
+
"Parked for Removal",
|
|
19
24
|
"Removed",
|
|
20
25
|
)
|
|
21
|
-
ACTIVE_STATUSES: ClassVar[frozenset[str]] = frozenset(WORK_ITEM_STATUSES[:
|
|
22
|
-
TERMINAL_STATUSES: ClassVar[frozenset[str]] = frozenset(WORK_ITEM_STATUSES[
|
|
26
|
+
ACTIVE_STATUSES: ClassVar[frozenset[str]] = frozenset(WORK_ITEM_STATUSES[:9])
|
|
27
|
+
TERMINAL_STATUSES: ClassVar[frozenset[str]] = frozenset(WORK_ITEM_STATUSES[9:])
|
|
23
28
|
|
|
24
29
|
STATUS_LINE: ClassVar[re.Pattern[str]] = re.compile(r"^status:\s*(.+)$")
|
|
25
30
|
WORK_ITEM_LINE: ClassVar[re.Pattern[str]] = re.compile(r"^work_item:\s*(.+)$")
|
|
@@ -67,7 +67,7 @@ class PlansLayout(Check):
|
|
|
67
67
|
# you can tell what a file is from its name, in every feature, without opening
|
|
68
68
|
# it. Adding a name here later is cheap; leaving the set open is how a tree
|
|
69
69
|
# ends up with HANDOVER.md, handover-v2.md and channels-notes.md side by side.
|
|
70
|
-
SUPPORTING: ClassVar[tuple[str, ...]] = ("handoff.md", "review.md")
|
|
70
|
+
SUPPORTING: ClassVar[tuple[str, ...]] = ("handoff.md", "intent.md", "review.md")
|
|
71
71
|
|
|
72
72
|
ROOT_DIRS: ClassVar[tuple[str, ...]] = ("features", "templates")
|
|
73
73
|
# `GAPS-AND-FINDINGS.md` sits here because its own rows say where they go:
|
|
@@ -14,7 +14,7 @@ from __future__ import annotations
|
|
|
14
14
|
|
|
15
15
|
import pathlib
|
|
16
16
|
|
|
17
|
-
from helpers import corpus
|
|
17
|
+
from helpers import corpus
|
|
18
18
|
|
|
19
19
|
from adl_compliance.checks.layout.plans_layout import PlansLayout
|
|
20
20
|
from adl_compliance.core.context import Context, FileSet
|
|
@@ -199,8 +199,8 @@ def test_an_extra_file_beside_spec_is_reported(tmp_path: pathlib.Path) -> None:
|
|
|
199
199
|
# The message ENUMERATES what is allowed, so whoever hits it can correct the
|
|
200
200
|
# file without opening the check. A bare "not allowed" sends the reader here.
|
|
201
201
|
finding = next(f for f in verdict.findings if "Feature directory holds" in f.message)
|
|
202
|
-
assert finding.message == "a Feature directory holds spec.md, handoff.md, review.md, items/ only"
|
|
203
|
-
assert "rename it to one of handoff.md, review.md" in finding.fix
|
|
202
|
+
assert finding.message == "a Feature directory holds spec.md, handoff.md, intent.md, review.md, items/ only"
|
|
203
|
+
assert "rename it to one of handoff.md, intent.md, review.md" in finding.fix
|
|
204
204
|
|
|
205
205
|
|
|
206
206
|
def test_supporting_documents_are_permitted_beside_spec(tmp_path: pathlib.Path) -> None:
|
|
@@ -62,9 +62,8 @@ class References(Check):
|
|
|
62
62
|
# Was "LAY-010" — the neighbouring gate's id, so every broken-link finding printed
|
|
63
63
|
# under `layout.profile-data` and sent a reader chasing a Rust migration-filename
|
|
64
64
|
# rule. Third instance of the defect 58866d2 fixed for LAY-008, and its test pinned
|
|
65
|
-
# it the same way. (
|
|
66
|
-
#
|
|
67
|
-
# test.sh asserts LAY-009. This one had no such justification anywhere in the file.)
|
|
65
|
+
# it the same way. (The gate that owned LAY-010, `layout.profile-data`, was retired
|
|
66
|
+
# 2026-10-01, so no gate answers to that id now.)
|
|
68
67
|
rule: ClassVar[str] = "LAY-011"
|
|
69
68
|
|
|
70
69
|
# This gate's own values, and no other module's business. Shared values are
|
|
@@ -23,8 +23,13 @@ line:
|
|
|
23
23
|
which skips it for the same reason (not restated there beyond
|
|
24
24
|
the `continue`).
|
|
25
25
|
|
|
26
|
-
ALLOWED_FILES and ALLOWED_DIRS are the closed set
|
|
27
|
-
not scope, and the list cannot grow with the tree.
|
|
26
|
+
ALLOWED_FILES and ALLOWED_DIRS are the CENTRAL closed set: named requirements,
|
|
27
|
+
not scope, and the list cannot grow with the tree. What is graded is the
|
|
28
|
+
effective set -- the central one plus the names the repository declares under
|
|
29
|
+
`[controls.compliance.root]` in its own adl-config.toml (`files`, `dirs`), which
|
|
30
|
+
reach this gate as `Context.declarations["root-files" | "root-dirs"]`. A
|
|
31
|
+
non-standard root entry is declared by the repository that has it, never added
|
|
32
|
+
here.
|
|
28
33
|
|
|
29
34
|
Ported from `compliance_new/checks/layout/root-closed-set/check.sh` with one
|
|
30
35
|
correction verified against that script's own fixture and against this
|
|
@@ -58,6 +63,8 @@ from ....policy.root_shape import (
|
|
|
58
63
|
ALLOWED_ROOT_DIRS,
|
|
59
64
|
ALLOWED_ROOT_FILES,
|
|
60
65
|
REQUIRED_ROOT_FILES,
|
|
66
|
+
allowed_root_dirs,
|
|
67
|
+
allowed_root_files,
|
|
61
68
|
)
|
|
62
69
|
|
|
63
70
|
|
|
@@ -86,12 +93,18 @@ class RootClosedSet(Check):
|
|
|
86
93
|
# config module states the principle these lists were breaking: "a path
|
|
87
94
|
# outside this package, written inside it, is a dependency on this
|
|
88
95
|
# particular checkout's shape."
|
|
96
|
+
#
|
|
97
|
+
# The CENTRAL default. The effective set is
|
|
98
|
+
# `allowed_root_files(ctx.declarations)`, computed at grade time.
|
|
89
99
|
ALLOWED_FILES: ClassVar[frozenset[str]] = ALLOWED_ROOT_FILES
|
|
90
100
|
|
|
91
101
|
# PERMITTED at the root, same as the files above: present is fine, absent
|
|
92
102
|
# is fine. Several entries here name trees no longer in use anywhere
|
|
93
103
|
# (`.code-review-graph_old`, `.plans`, `.specs`) and they cost nothing while
|
|
94
104
|
# they only permit; under the old manifest reading, each was a finding.
|
|
105
|
+
#
|
|
106
|
+
# The CENTRAL default. The effective set is
|
|
107
|
+
# `allowed_root_dirs(ctx.declarations)`, computed at grade time.
|
|
95
108
|
ALLOWED_DIRS: ClassVar[frozenset[str]] = ALLOWED_ROOT_DIRS
|
|
96
109
|
|
|
97
110
|
# What a repository must actually HAVE at its root, as opposed to what it
|
|
@@ -121,15 +134,19 @@ class RootClosedSet(Check):
|
|
|
121
134
|
else:
|
|
122
135
|
root_files.add(path)
|
|
123
136
|
|
|
137
|
+
allowed_dirs = allowed_root_dirs(ctx.declarations)
|
|
138
|
+
allowed_files = allowed_root_files(ctx.declarations)
|
|
124
139
|
for name in sorted(dirs):
|
|
125
|
-
if name not in
|
|
140
|
+
if name not in allowed_dirs:
|
|
126
141
|
yield self.report(
|
|
127
142
|
name, "undeclared top-level directory",
|
|
128
|
-
f"declare {name}
|
|
143
|
+
f"declare {name} under [controls.compliance.root] dirs in this "
|
|
144
|
+
"repository's adl-config.toml, or move it into an owning tree",
|
|
129
145
|
)
|
|
130
146
|
for name in sorted(root_files):
|
|
131
|
-
if name not in
|
|
147
|
+
if name not in allowed_files:
|
|
132
148
|
yield self.report(
|
|
133
149
|
name, "undeclared top-level file",
|
|
134
|
-
f"declare {name}
|
|
150
|
+
f"declare {name} under [controls.compliance.root] files in this "
|
|
151
|
+
"repository's adl-config.toml, or move it into an owning tree",
|
|
135
152
|
)
|
|
@@ -120,3 +120,79 @@ def test_the_structural_half_still_runs_on_an_empty_set() -> None:
|
|
|
120
120
|
still a clean verdict."""
|
|
121
121
|
verdict = verdict_for(())
|
|
122
122
|
assert verdict.outcome is Outcome.CLEAN, verdict.render()
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
# ---------------------------------------------- per-repository root declarations
|
|
126
|
+
def verdict_declaring(declarations: dict[str, str], given: tuple[str, ...]) -> Verdict:
|
|
127
|
+
"""`verdict_for`, plus what the repository declared about its own root
|
|
128
|
+
(`[controls.compliance.root]` arrives as the `root-files` / `root-dirs`
|
|
129
|
+
declarations)."""
|
|
130
|
+
ctx = Context(root=CORPUS, row=ROW, declarations=declarations)
|
|
131
|
+
findings = tuple(
|
|
132
|
+
r for r in RootClosedSet().run(ctx, FileSet(paths=given)) if isinstance(r, Finding)
|
|
133
|
+
)
|
|
134
|
+
return decide(ROW, findings, 0, ())
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def test_a_non_standard_root_directory_is_undeclared_without_a_declaration() -> None:
|
|
138
|
+
"""`apps/` and `packaging/` are not on the central list any more."""
|
|
139
|
+
for name in ("apps", "packaging"):
|
|
140
|
+
verdict = verdict_declaring({}, (f"{name}/cli/main.ts",))
|
|
141
|
+
assert verdict.outcome is Outcome.FINDINGS, verdict.render()
|
|
142
|
+
assert [f.path for f in verdict.findings] == [name], verdict.render()
|
|
143
|
+
assert f"{name}: undeclared top-level directory" in verdict.render()
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def test_a_declared_root_directory_is_accepted() -> None:
|
|
147
|
+
verdict = verdict_declaring(
|
|
148
|
+
{"root-dirs": "apps,packaging"}, ("apps/cli/main.ts", "packaging/npm/package.json"),
|
|
149
|
+
)
|
|
150
|
+
assert verdict.outcome is Outcome.CLEAN, verdict.render()
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def test_a_non_standard_root_file_is_undeclared_without_a_declaration() -> None:
|
|
154
|
+
"""STATUS.md and DRIFT.md are not on the central list any more."""
|
|
155
|
+
for name in ("STATUS.md", "DRIFT.md"):
|
|
156
|
+
verdict = verdict_declaring({}, (name,))
|
|
157
|
+
assert [f.path for f in verdict.findings] == [name], verdict.render()
|
|
158
|
+
assert f"{name}: undeclared top-level file" in verdict.render()
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def test_a_declared_root_file_is_accepted() -> None:
|
|
162
|
+
verdict = verdict_declaring({"root-files": "STATUS.md, DRIFT.md"}, ("STATUS.md", "DRIFT.md"))
|
|
163
|
+
assert verdict.outcome is Outcome.CLEAN, verdict.render()
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def test_a_declaration_does_not_silence_the_rest_of_the_root() -> None:
|
|
167
|
+
"""Without this, the accept cases above also pass against a gate that stops
|
|
168
|
+
grading the root once any declaration is present."""
|
|
169
|
+
verdict = verdict_declaring(
|
|
170
|
+
{"root-dirs": "apps", "root-files": "STATUS.md"},
|
|
171
|
+
("apps/cli/main.ts", "STATUS.md", "unapproved-root/x.md", "undeclared-root-file.txt"),
|
|
172
|
+
)
|
|
173
|
+
assert sorted(f.path for f in verdict.findings) == [
|
|
174
|
+
"unapproved-root", "undeclared-root-file.txt",
|
|
175
|
+
], verdict.render()
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def test_the_files_and_dirs_declarations_do_not_cross() -> None:
|
|
179
|
+
"""A name declared as a directory does not admit a file of that name, and
|
|
180
|
+
the other way round."""
|
|
181
|
+
dirs_only = verdict_declaring({"root-dirs": "thing"}, ("thing",))
|
|
182
|
+
assert [f.path for f in dirs_only.findings] == ["thing"], dirs_only.render()
|
|
183
|
+
files_only = verdict_declaring({"root-files": "thing"}, ("thing/x.ts",))
|
|
184
|
+
assert [f.path for f in files_only.findings] == ["thing"], files_only.render()
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def test_the_remedies_point_at_the_declaration_not_at_source() -> None:
|
|
188
|
+
"""The old remedies said "declare X in ALLOWED_DIRS/ALLOWED_FILES" -- a
|
|
189
|
+
constant in the shared package. The repository owns the declaration."""
|
|
190
|
+
by_path = {
|
|
191
|
+
f.path: f for f in verdict_declaring({}, ("apps/cli/main.ts", "STATUS.md")).findings
|
|
192
|
+
}
|
|
193
|
+
directory, file = by_path["apps"], by_path["STATUS.md"]
|
|
194
|
+
for finding, key in ((directory, "dirs"), (file, "files")):
|
|
195
|
+
assert "[controls.compliance.root]" in finding.fix, finding.fix
|
|
196
|
+
assert "adl-config.toml" in finding.fix, finding.fix
|
|
197
|
+
assert key in finding.fix, finding.fix
|
|
198
|
+
assert "ALLOWED_" not in finding.fix, finding.fix
|
|
@@ -32,7 +32,13 @@ from typing import ClassVar
|
|
|
32
32
|
from ....core.check import Check
|
|
33
33
|
from ....core.context import Context, FileSet
|
|
34
34
|
from ....core.finding import Report
|
|
35
|
-
from ....policy.root_shape import
|
|
35
|
+
from ....policy.root_shape import (
|
|
36
|
+
GOVERNANCE,
|
|
37
|
+
GUIDES,
|
|
38
|
+
REGISTERS,
|
|
39
|
+
ROOT_FILES_DECLARATION,
|
|
40
|
+
declared_root_names,
|
|
41
|
+
)
|
|
36
42
|
|
|
37
43
|
|
|
38
44
|
class RootMarkdownAllowlist(Check):
|
|
@@ -64,7 +70,12 @@ class RootMarkdownAllowlist(Check):
|
|
|
64
70
|
# that does exist at `plans/AGENTS.md` went unseen while a phantom one was
|
|
65
71
|
# demanded. The rule is about trees being documented, not about these exact
|
|
66
72
|
# paths being present.
|
|
67
|
-
|
|
73
|
+
#
|
|
74
|
+
# `.workflows/` is deliberately not listed (owner decision, 2026-10-01): it is
|
|
75
|
+
# a machine-managed tree, written wholesale by `adl-repo-controls install` and
|
|
76
|
+
# never hand-authored, so it does not need a guide of its own. A guide that
|
|
77
|
+
# does exist there is still admitted by `_allowed_markdown`.
|
|
78
|
+
GUIDED_TREES: ClassVar[tuple[str, ...]] = ("plans", "specs", "docs")
|
|
68
79
|
|
|
69
80
|
# Trees whose Markdown this repository does not author: vendored provider
|
|
70
81
|
# documentation, and archives kept for reference. Renaming a README inside
|
|
@@ -199,8 +210,10 @@ class RootMarkdownAllowlist(Check):
|
|
|
199
210
|
path,
|
|
200
211
|
"tracked Markdown is outside the root allowlist",
|
|
201
212
|
f"move {path} under an allowed tree (docs/, plans/, .specs/, "
|
|
202
|
-
".changeset/, etc.), or
|
|
203
|
-
"
|
|
213
|
+
".changeset/, etc.), or, if it is a root-level Markdown file "
|
|
214
|
+
"this repository genuinely carries, declare it under "
|
|
215
|
+
"[controls.compliance.root] files in this repository's "
|
|
216
|
+
"adl-config.toml",
|
|
204
217
|
)
|
|
205
218
|
|
|
206
219
|
def _allowed_markdown(self, ctx: Context, path: str) -> bool:
|
|
@@ -209,17 +222,27 @@ class RootMarkdownAllowlist(Check):
|
|
|
209
222
|
# ADR-095 admits this one root-relative verification contract by
|
|
210
223
|
# literal name.
|
|
211
224
|
#
|
|
212
|
-
# `policy/root_shape.py` is THE list of what may sit at
|
|
225
|
+
# `policy/root_shape.py` is THE list of what may sit at EVERY repository's
|
|
213
226
|
# root — GUIDES (AGENTS.md/CLAUDE.md/INVARIANTS.md/…), GOVERNANCE
|
|
214
227
|
# (CONTRIBUTING.md/SECURITY.md/…) and REGISTERS (GAPS-AND-FINDINGS.md,
|
|
215
|
-
# OPEN-ITEMS.md
|
|
216
|
-
#
|
|
217
|
-
# drifted apart once (STATUS.md/DRIFT.md were on neither copy). Import
|
|
228
|
+
# OPEN-ITEMS.md). This gate used to carry its own copy of that same set,
|
|
229
|
+
# hardcoded here, and the copies had already drifted apart once. Import
|
|
218
230
|
# rather than duplicate, exactly as `layout.markdown-trees` and
|
|
219
231
|
# `layout.placement` already do — one policy, not a fourth copy of it.
|
|
220
232
|
# (Tarun, 2026-09-27.)
|
|
233
|
+
#
|
|
234
|
+
# Root Markdown that is NOT standard (a repository's own STATUS.md,
|
|
235
|
+
# DRIFT.md) is not on that list: the repository declares it under
|
|
236
|
+
# `[controls.compliance.root] files`, and it arrives below as the
|
|
237
|
+
# `root-files` declaration. That lookup must stay AFTER this short-circuit —
|
|
238
|
+
# the central names are answered without a Context at all
|
|
239
|
+
# (tests/core/test_root_shape.py passes `ctx=None`).
|
|
221
240
|
if path in (GUIDES | GOVERNANCE | REGISTERS):
|
|
222
241
|
return True
|
|
242
|
+
if "/" not in path and path in declared_root_names(
|
|
243
|
+
ctx.declarations, ROOT_FILES_DECLARATION
|
|
244
|
+
):
|
|
245
|
+
return True
|
|
223
246
|
# Ported from check-markdown-placement.py: any AGENTS.md/CLAUDE.md
|
|
224
247
|
# guide file is allowed regardless of folder — the AGENTS.md/CLAUDE.md
|
|
225
248
|
# hierarchy is governed separately by layout.agents-layout.
|
|
@@ -260,11 +283,25 @@ class RootMarkdownAllowlist(Check):
|
|
|
260
283
|
# above).
|
|
261
284
|
if path in self.GOVERNANCE_FILES or path in self.RETAINED_MARKDOWN_FILES:
|
|
262
285
|
return True
|
|
263
|
-
|
|
264
|
-
frontend_root
|
|
265
|
-
|
|
286
|
+
# Decision for a tree declared absent (`rust = ""` / `frontend = ""`, which
|
|
287
|
+
# drops `rust_root` / `frontend_root` from the resolved inputs): both only
|
|
288
|
+
# ever ADD allowlist entries -- the governance suffixes and code-asset
|
|
289
|
+
# roots beneath the tree -- so a repository with no such tree has nothing
|
|
290
|
+
# there to admit and they contribute nothing. Strictly stricter, never a
|
|
291
|
+
# silent pass. These were read unguarded (`ctx.inputs["rust_root"]`): a
|
|
292
|
+
# stray root Markdown file, which every allowance above declines, reached
|
|
293
|
+
# them and raised `KeyError` -- a traceback with exit 1, not a verdict.
|
|
294
|
+
rust_input = ctx.inputs.get("rust_root")
|
|
295
|
+
rust_root = None if rust_input is None else ctx.relative(rust_input)
|
|
296
|
+
frontend_input = ctx.inputs.get("frontend_root")
|
|
297
|
+
frontend_root = None if frontend_input is None else ctx.relative(frontend_input)
|
|
298
|
+
if rust_root is not None and path in {
|
|
299
|
+
f"{rust_root}/{suffix}" for suffix in self.RUST_GOVERNANCE_SUFFIXES
|
|
300
|
+
}:
|
|
266
301
|
return True
|
|
267
|
-
if
|
|
302
|
+
if frontend_root is not None and path in {
|
|
303
|
+
f"{frontend_root}/{suffix}" for suffix in self.FRONTEND_GOVERNANCE_SUFFIXES
|
|
304
|
+
}:
|
|
268
305
|
return True
|
|
269
306
|
if path in {f"{workflows_root}/{suffix}" for suffix in self.WORKFLOWS_GOVERNANCE_SUFFIXES}:
|
|
270
307
|
return True
|
|
@@ -272,19 +309,23 @@ class RootMarkdownAllowlist(Check):
|
|
|
272
309
|
return True
|
|
273
310
|
if any(path.startswith(code_root) for code_root in self.CODE_ASSET_ROOTS):
|
|
274
311
|
return True
|
|
275
|
-
if any(
|
|
312
|
+
if rust_root is not None and any(
|
|
276
313
|
path.startswith(f"{rust_root}/{suffix}") for suffix in self.RUST_CODE_ASSET_SUFFIXES
|
|
277
314
|
):
|
|
278
315
|
return True
|
|
279
|
-
if any(
|
|
316
|
+
if frontend_root is not None and any(
|
|
280
317
|
path.startswith(f"{frontend_root}/{suffix}")
|
|
281
318
|
for suffix in self.FRONTEND_CODE_ASSET_SUFFIXES
|
|
282
319
|
):
|
|
283
320
|
return True
|
|
284
321
|
name = path.rsplit("/", 1)[-1]
|
|
285
|
-
if
|
|
286
|
-
|
|
287
|
-
|
|
322
|
+
if (
|
|
323
|
+
frontend_root is not None
|
|
324
|
+
and name in self.FRONTEND_LOCAL_DOC_NAMES
|
|
325
|
+
and any(
|
|
326
|
+
path.startswith(f"{frontend_root}/{suffix}")
|
|
327
|
+
for suffix in self.FRONTEND_LOCAL_DOC_SUFFIXES
|
|
328
|
+
)
|
|
288
329
|
):
|
|
289
330
|
return True
|
|
290
331
|
return False
|