@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
|
@@ -1,18 +1,41 @@
|
|
|
1
1
|
"""LAY-004 — ported from `compliance_new/checks/layout/directory-ratchet/test.sh`.
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
`directory-ratchet-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
3
|
+
Eight committed corpora, the first six same names and shapes as the shell
|
|
4
|
+
fixtures with their registers reworked to the 2026-10-02 generic-ratchet
|
|
5
|
+
principle (v3 for this gate): `directory-ratchet-clean` (one baselined
|
|
6
|
+
single-file directory, nothing else), `directory-ratchet-unbaselined` (an
|
|
7
|
+
unbaselined single-file directory, plus a control: eleven single-file
|
|
8
|
+
subdirectories of a parent that itself holds zero direct files),
|
|
9
|
+
`directory-ratchet-excluded` (the row's own `!` exclusions under test, run
|
|
10
|
+
twice against the same files through two Row variants that differ by exactly
|
|
11
|
+
those two patterns), `directory-ratchet-missing-tree` (a ceiling-configured
|
|
12
|
+
tree with no directory — advisory, not failure),
|
|
13
|
+
`directory-ratchet-stale-entry` (DIR-003's kept reach: a baseline entry under
|
|
14
|
+
a live tree whose directory was deleted), `directory-ratchet-unusable-register`
|
|
15
|
+
(a register that exists but is not valid YAML — could-not-run, the kept
|
|
16
|
+
exception in every ruling shape), and two added for the generic principle:
|
|
17
|
+
`directory-ratchet-no-ceilings` (three files in one directory against a
|
|
18
|
+
register that would exempt them — with NO ceilings declared the gate has
|
|
19
|
+
nothing to enforce and the register is never read, so it stays clean), and
|
|
20
|
+
`directory-ratchet-empty-register` (a register recording ZERO state — a load
|
|
21
|
+
failure, because zero state is no file).
|
|
22
|
+
|
|
23
|
+
V3 (owner ruling 2026-10-02, superseding this gate's earlier "ratchets sit
|
|
24
|
+
ON TOP" ruling; the same principle DOC-012 v2 shipped): the per-tree
|
|
25
|
+
CEILINGS are CONFIGURATION and live in `[controls.compliance.directory-
|
|
26
|
+
ratchet].max_children`, reaching the engine as the `directory-ceilings`
|
|
27
|
+
declaration. The register records STATE only — over-limit and single-file
|
|
28
|
+
baselines. An absent register records no state, so the ceilings are enforced
|
|
29
|
+
bare (strict — the widening input's normal contract). Two v1 tests were
|
|
30
|
+
reworked and say so in their docstrings. At zero recorded state the file is
|
|
31
|
+
deleted; a file that EXISTS recording zero state is a load failure.
|
|
10
32
|
|
|
11
33
|
Each fixture carries its own `grants.yaml` at its own root, passed as the
|
|
12
34
|
`register` input override — the same mechanism `DOC-006`'s test uses for its
|
|
13
35
|
packaged profile register, not a path nested to match `policy/config.toml`'s
|
|
14
36
|
tree mapping, which is exactly the coupling that broke this port once already
|
|
15
|
-
(P-14).
|
|
37
|
+
(P-14). The ceilings travel as the `directory-ceilings` declaration, the same
|
|
38
|
+
channel DOC-012's tests use for `docs-pages-per-directory`.
|
|
16
39
|
"""
|
|
17
40
|
|
|
18
41
|
from __future__ import annotations
|
|
@@ -38,24 +61,102 @@ def corpus_files(root: pathlib.Path) -> tuple[str, ...]:
|
|
|
38
61
|
)
|
|
39
62
|
|
|
40
63
|
|
|
41
|
-
def run(
|
|
64
|
+
def run(
|
|
65
|
+
case: str, *, scope: tuple[str, ...] | None = None, ceilings: str | None = None
|
|
66
|
+
) -> object:
|
|
42
67
|
directory = FIXTURES / case
|
|
43
68
|
row = ROW
|
|
44
69
|
if scope is not None:
|
|
45
70
|
row = row.model_copy(update={"engine": row.engine.model_copy(update={"scope": scope})})
|
|
71
|
+
declarations = {} if ceilings is None else {DirectoryRatchet.CEILINGS_DECLARATION: ceilings}
|
|
46
72
|
return runner.run(
|
|
47
73
|
row, directory, corpus_files(directory),
|
|
48
74
|
inputs={row.id: {"register": directory / "grants.yaml"}},
|
|
75
|
+
declarations=declarations,
|
|
49
76
|
)
|
|
50
77
|
|
|
51
78
|
|
|
79
|
+
# ------------------------------------------------------- the ceilings channel
|
|
80
|
+
|
|
81
|
+
|
|
52
82
|
def test_a_fully_baselined_tree_passes() -> None:
|
|
53
|
-
verdict = run("directory-ratchet-clean")
|
|
83
|
+
verdict = run("directory-ratchet-clean", ceilings="frontend/packages/desktop/src:10")
|
|
84
|
+
assert verdict.outcome is Outcome.CLEAN, verdict.render()
|
|
85
|
+
assert not verdict.findings
|
|
86
|
+
assert not verdict.advisories
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def test_no_ceilings_configured_means_nothing_to_enforce() -> None:
|
|
90
|
+
"""The generic principle's config half: no `[controls.compliance.directory-
|
|
91
|
+
ratchet]` table, no ceilings declared — the gate has NOTHING to enforce
|
|
92
|
+
and passes clean even with a three-file directory on disk whose register
|
|
93
|
+
would exempt it (proving the register is not even read: its entry could
|
|
94
|
+
only ever REMOVE findings)."""
|
|
95
|
+
verdict = run("directory-ratchet-no-ceilings")
|
|
96
|
+
assert verdict.outcome is Outcome.CLEAN, verdict.render()
|
|
97
|
+
assert not verdict.findings
|
|
98
|
+
assert not verdict.advisories
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def test_a_baseline_entry_exempts_its_directory_up_to_the_recorded_count() -> None:
|
|
102
|
+
"""The state half: the same three-file directory, now under a declared
|
|
103
|
+
ceiling of 2, is CLEAN because the register records its count of 3 — an
|
|
104
|
+
entry forgives the directory up to the count recorded (growing past it
|
|
105
|
+
is DIR-002, reported separately)."""
|
|
106
|
+
verdict = run(
|
|
107
|
+
"directory-ratchet-no-ceilings", ceilings="frontend/packages/desktop/src:2"
|
|
108
|
+
)
|
|
54
109
|
assert verdict.outcome is Outcome.CLEAN, verdict.render()
|
|
110
|
+
assert not verdict.findings
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def test_an_over_ceiling_directory_with_no_register_is_dir_001() -> None:
|
|
114
|
+
"""The same three-file corpus one more time, register pointed at a path
|
|
115
|
+
that does not exist: no recorded state means no exemptions allowed, so
|
|
116
|
+
the ceiling of 2 is enforced bare — DIR-001 names the directory."""
|
|
117
|
+
directory = FIXTURES / "directory-ratchet-no-ceilings"
|
|
118
|
+
verdict = runner.run(
|
|
119
|
+
ROW, directory, corpus_files(directory),
|
|
120
|
+
inputs={ROW.id: {"register": directory / "does-not-exist.yaml"}},
|
|
121
|
+
declarations={DirectoryRatchet.CEILINGS_DECLARATION: "frontend/packages/desktop/src:2"},
|
|
122
|
+
)
|
|
123
|
+
assert verdict.outcome is Outcome.FINDINGS
|
|
124
|
+
findings = [f for f in verdict.findings if f.rule == "DIR-001"]
|
|
125
|
+
assert len(findings) == 1, tuple(f.render() for f in verdict.findings)
|
|
126
|
+
assert findings[0].path == "frontend/packages/desktop/src"
|
|
127
|
+
assert findings[0].message == "3 direct children (max 2), no ratchet entry"
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def test_a_malformed_ceilings_declaration_is_could_not_run() -> None:
|
|
131
|
+
for bad in ("frontend/packages/desktop/src:banana", "frontend/packages/desktop/src:0"):
|
|
132
|
+
verdict = run("directory-ratchet-clean", ceilings=bad)
|
|
133
|
+
assert verdict.outcome is Outcome.COULD_NOT_RUN, bad
|
|
134
|
+
assert "directory-ratchet" in verdict.message
|
|
135
|
+
assert "frontend/packages/desktop/src" in verdict.message
|
|
136
|
+
# An entry with no ceiling half at all:
|
|
137
|
+
verdict = run("directory-ratchet-clean", ceilings="frontend/packages/desktop/src")
|
|
138
|
+
assert verdict.outcome is Outcome.COULD_NOT_RUN
|
|
139
|
+
assert "directory-ratchet" in verdict.message
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def test_a_register_recording_zero_state_is_a_load_failure() -> None:
|
|
143
|
+
"""The ruling's deletion half, enforced loudly: a register file that
|
|
144
|
+
EXISTS but records no state (no over-limit baseline, no single-file
|
|
145
|
+
baseline, no docs_pages section) is the shape the owner deletes — read
|
|
146
|
+
as a load failure, never as a silent empty pass."""
|
|
147
|
+
verdict = run(
|
|
148
|
+
"directory-ratchet-empty-register",
|
|
149
|
+
ceilings="frontend/packages/desktop/src:2",
|
|
150
|
+
)
|
|
151
|
+
assert verdict.outcome is Outcome.COULD_NOT_RUN
|
|
152
|
+
assert "a register grading nothing" in verdict.message
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
# ------------------------------------------------------- the original corpus
|
|
55
156
|
|
|
56
157
|
|
|
57
158
|
def test_an_unbaselined_single_file_directory_is_reported() -> None:
|
|
58
|
-
verdict = run("directory-ratchet-unbaselined")
|
|
159
|
+
verdict = run("directory-ratchet-unbaselined", ceilings="frontend/packages/desktop/src:10")
|
|
59
160
|
assert verdict.outcome is Outcome.FINDINGS
|
|
60
161
|
paths = {f.path for f in verdict.findings if f.rule == "DIR-001"}
|
|
61
162
|
assert "frontend/packages/desktop/src/renderer/fresh" in paths
|
|
@@ -66,14 +167,14 @@ def test_a_subdirectory_alone_never_trips_the_rule() -> None:
|
|
|
66
167
|
"""`many` holds eleven subdirectories and zero direct files of its own, so it
|
|
67
168
|
needs no baseline entry; each subdirectory holds exactly one file and IS
|
|
68
169
|
reported. Both halves matter, or this corpus is silent by accident."""
|
|
69
|
-
verdict = run("directory-ratchet-unbaselined")
|
|
170
|
+
verdict = run("directory-ratchet-unbaselined", ceilings="frontend/packages/desktop/src:10")
|
|
70
171
|
paths = {f.path for f in verdict.findings if f.rule == "DIR-001"}
|
|
71
172
|
assert "frontend/packages/desktop/src/renderer/many" not in paths
|
|
72
173
|
assert "frontend/packages/desktop/src/renderer/many/sub1" in paths
|
|
73
174
|
|
|
74
175
|
|
|
75
176
|
def test_the_row_exclusions_silence_locales_and_vendored_cargo() -> None:
|
|
76
|
-
verdict = run("directory-ratchet-excluded")
|
|
177
|
+
verdict = run("directory-ratchet-excluded", ceilings="frontend/packages/desktop/src:20")
|
|
77
178
|
assert verdict.outcome is Outcome.FINDINGS
|
|
78
179
|
paths = {f.path for f in verdict.findings}
|
|
79
180
|
assert not any("locales" in p for p in paths)
|
|
@@ -93,7 +194,7 @@ def test_falsifiability_without_the_row_exclusions() -> None:
|
|
|
93
194
|
)
|
|
94
195
|
assert len(unscoped) == len(ROW.engine.scope) - 2
|
|
95
196
|
|
|
96
|
-
verdict = run("directory-ratchet-excluded", scope=unscoped)
|
|
197
|
+
verdict = run("directory-ratchet-excluded", scope=unscoped, ceilings="frontend/packages/desktop/src:20")
|
|
97
198
|
assert verdict.outcome is Outcome.FINDINGS
|
|
98
199
|
paths = {f.path for f in verdict.findings if f.rule == "DIR-001"}
|
|
99
200
|
assert any("locales" in p for p in paths)
|
|
@@ -104,30 +205,86 @@ def test_the_ratchet_register_is_not_a_grant_catalogue() -> None:
|
|
|
104
205
|
"""`structural_grant = True` forces the allowance to 0 regardless of the
|
|
105
206
|
row's own `grants:` field. Passing the register's size as the allowance is
|
|
106
207
|
the trap: a failing gate would report green."""
|
|
107
|
-
verdict = run("directory-ratchet-unbaselined")
|
|
208
|
+
verdict = run("directory-ratchet-unbaselined", ceilings="frontend/packages/desktop/src:10")
|
|
108
209
|
assert verdict.granted == 0
|
|
109
210
|
assert verdict.outcome is Outcome.FINDINGS
|
|
110
211
|
|
|
111
212
|
|
|
112
|
-
def
|
|
113
|
-
"""
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
`registered tree directory is missing: backend/crates` on the first entry —
|
|
121
|
-
a gate reporting another repo's layout as this repo's defect.
|
|
122
|
-
"""
|
|
213
|
+
def test_an_absent_register_enforces_the_ceilings_bare() -> None:
|
|
214
|
+
"""REWORKED from v1's `test_an_absent_register_means_nothing_is_ratcheted`,
|
|
215
|
+
which asserted the opposite under the superseded "ratchets sit ON TOP"
|
|
216
|
+
ruling. Generic principle (2026-10-02): the register records STATE only,
|
|
217
|
+
so an absent register records no exemptions and the configured ceilings
|
|
218
|
+
are enforced bare — every single-file directory the clean corpus holds
|
|
219
|
+
reports DIR-001 (the corpus's `solo` is exempted only by its recorded
|
|
220
|
+
entry, which is gone)."""
|
|
123
221
|
directory = FIXTURES / "directory-ratchet-clean"
|
|
124
222
|
verdict = runner.run(
|
|
125
223
|
ROW, directory, corpus_files(directory),
|
|
126
224
|
inputs={ROW.id: {"register": directory / "does-not-exist.yaml"}},
|
|
225
|
+
declarations={DirectoryRatchet.CEILINGS_DECLARATION: "frontend/packages/desktop/src:10"},
|
|
226
|
+
)
|
|
227
|
+
assert verdict.outcome is Outcome.FINDINGS
|
|
228
|
+
findings = [f for f in verdict.findings if f.rule == "DIR-001"]
|
|
229
|
+
assert {f.path for f in findings} == {
|
|
230
|
+
"frontend/packages/desktop/src/renderer/solo",
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
def test_an_absent_register_with_an_empty_scope_is_still_the_runners_dead_scope() -> None:
|
|
235
|
+
"""The C1 guard is untouched: on an exhaustive run whose scope selects
|
|
236
|
+
nothing, the runner's dead-scope could-not-run stands. The widening-input
|
|
237
|
+
change only says the CHECK must not add its own register complaint on top
|
|
238
|
+
of that — and it cannot even run here."""
|
|
239
|
+
directory = FIXTURES / "directory-ratchet-clean"
|
|
240
|
+
verdict = runner.run(
|
|
241
|
+
ROW, directory, (),
|
|
242
|
+
exhaustive=True,
|
|
243
|
+
inputs={ROW.id: {"register": directory / "does-not-exist.yaml"}},
|
|
244
|
+
declarations={DirectoryRatchet.CEILINGS_DECLARATION: "frontend/packages/desktop/src:10"},
|
|
245
|
+
)
|
|
246
|
+
assert verdict.outcome is Outcome.COULD_NOT_RUN
|
|
247
|
+
assert "matches no file on disk" in verdict.message
|
|
248
|
+
assert "register" not in verdict.message
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
def test_a_register_that_exists_but_is_unusable_is_could_not_run() -> None:
|
|
252
|
+
"""The kept exception through every ruling shape: absent is bare
|
|
253
|
+
enforcement, UNUSABLE is not. A register that exists but cannot be parsed
|
|
254
|
+
may be mid-edit; grading it as "no baselines" would silently drop every
|
|
255
|
+
exemption it names."""
|
|
256
|
+
verdict = run("directory-ratchet-unusable-register", ceilings="frontend/packages/desktop/src:10")
|
|
257
|
+
assert verdict.outcome is Outcome.COULD_NOT_RUN
|
|
258
|
+
assert "unusable" in verdict.message
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
def test_a_configured_tree_that_is_gone_is_an_advisory_not_a_failure() -> None:
|
|
262
|
+
"""Generic principle, the cleanup half: a tree the CONFIGURATION names
|
|
263
|
+
but the repository no longer has is cleanup, not a defect. One advisory
|
|
264
|
+
names what is unaccounted; the remaining trees are graded normally."""
|
|
265
|
+
verdict = run(
|
|
266
|
+
"directory-ratchet-missing-tree",
|
|
267
|
+
ceilings="frontend/packages/desktop/src:10,infra:10",
|
|
127
268
|
)
|
|
128
|
-
assert verdict.outcome is Outcome.
|
|
129
|
-
assert
|
|
130
|
-
assert
|
|
269
|
+
assert verdict.outcome is Outcome.CLEAN, verdict.render()
|
|
270
|
+
assert not verdict.findings
|
|
271
|
+
assert len(verdict.advisories) == 1
|
|
272
|
+
advisory = verdict.advisories[0]
|
|
273
|
+
assert advisory.path == "infra"
|
|
274
|
+
assert "no longer accounted" in advisory.message
|
|
275
|
+
assert "remove its register entries or restore the tree" in advisory.message
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
def test_a_baseline_entry_for_a_deleted_directory_is_still_reported_stale() -> None:
|
|
279
|
+
"""The narrowing of WHO may report absence, not the register's own
|
|
280
|
+
hygiene: an entry under a tree that STILL exists, naming a directory the
|
|
281
|
+
repository deleted, is DIR-003 exactly as before. Cleanup of the CONTENT
|
|
282
|
+
is free; cleanup of the REGISTER is the owner's edit, and the gate still
|
|
283
|
+
says so."""
|
|
284
|
+
verdict = run("directory-ratchet-stale-entry", ceilings="frontend/packages/desktop/src:10")
|
|
285
|
+
assert verdict.outcome is Outcome.FINDINGS
|
|
286
|
+
stale = {f.path for f in verdict.findings if f.rule == "DIR-003"}
|
|
287
|
+
assert "frontend/packages/desktop/src/renderer/gone" in stale
|
|
131
288
|
|
|
132
289
|
|
|
133
290
|
def test_the_register_is_not_packaged_data() -> None:
|
|
@@ -136,3 +293,82 @@ def test_the_register_is_not_packaged_data() -> None:
|
|
|
136
293
|
assert "register" in DirectoryRatchet.inputs
|
|
137
294
|
assert "register" not in DirectoryRatchet.resources
|
|
138
295
|
assert DirectoryRatchet.inputs["register"].startswith("<")
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
# --------------------------------------------------------- the shared schema
|
|
299
|
+
# The register model dropped `max_children` in the same change (v3): ceilings
|
|
300
|
+
# are configuration now, and a register recording zero state is a load
|
|
301
|
+
# failure. These pin the schema change itself.
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
def test_a_baselines_only_register_is_valid() -> None:
|
|
305
|
+
"""The register's whole job after the rework: recorded state. Over-limit
|
|
306
|
+
and single-file baselines, no `docs_pages` section — LAY-004's reader."""
|
|
307
|
+
from adl_compliance.checks.layout.directory_ratchet.register import Ratchet
|
|
308
|
+
|
|
309
|
+
ratchet = Ratchet.model_validate(
|
|
310
|
+
{
|
|
311
|
+
"schema_version": 2,
|
|
312
|
+
"over_children_baseline": {"frontend/packages/desktop/src/renderer": 12},
|
|
313
|
+
"single_file_baseline": {
|
|
314
|
+
"frontend/packages/desktop/src/renderer/solo": "item.ts"
|
|
315
|
+
},
|
|
316
|
+
}
|
|
317
|
+
)
|
|
318
|
+
assert ratchet.docs_pages is None
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
def test_a_register_carrying_max_children_is_refused() -> None:
|
|
322
|
+
"""`max_children` was configuration; configuration moved to adl-config.toml
|
|
323
|
+
in the same change, so the key it lived in is `extra="forbid"`-refused —
|
|
324
|
+
a stale register fails loud instead of being silently read as state."""
|
|
325
|
+
import pytest
|
|
326
|
+
from pydantic import ValidationError
|
|
327
|
+
|
|
328
|
+
from adl_compliance.checks.layout.directory_ratchet.register import Ratchet
|
|
329
|
+
|
|
330
|
+
with pytest.raises(ValidationError, match="max_children"):
|
|
331
|
+
Ratchet.model_validate(
|
|
332
|
+
{
|
|
333
|
+
"schema_version": 2,
|
|
334
|
+
"max_children": {"frontend/packages/desktop/src": 10},
|
|
335
|
+
"over_children_baseline": {},
|
|
336
|
+
"single_file_baseline": {},
|
|
337
|
+
}
|
|
338
|
+
)
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
def test_a_docs_pages_only_register_is_valid() -> None:
|
|
342
|
+
"""DOC-012's exemption-only shape is untouched by this rework: a register
|
|
343
|
+
holding only `docs_pages.baseline` parses clean."""
|
|
344
|
+
from adl_compliance.checks.layout.directory_ratchet.register import DocsPages, Ratchet
|
|
345
|
+
|
|
346
|
+
ratchet = Ratchet.model_validate(
|
|
347
|
+
{"schema_version": 2, "docs_pages": {"baseline": {"docs/operations": 10}}}
|
|
348
|
+
)
|
|
349
|
+
assert ratchet.over_children_baseline == {}
|
|
350
|
+
assert ratchet.docs_pages == DocsPages(baseline={"docs/operations": 10})
|
|
351
|
+
|
|
352
|
+
|
|
353
|
+
def test_an_all_empty_register_is_a_load_failure() -> None:
|
|
354
|
+
"""Zero recorded state is no file — an existing file that records nothing
|
|
355
|
+
is either the wrong file or an emptied register mid-cleanup, and reading
|
|
356
|
+
it as "no baselines" would silently drop every exemption it used to
|
|
357
|
+
name. The cross-field validator keeps the v1 `min_length=1` intent in
|
|
358
|
+
the new shape: at least one of over/single/docs_pages.baseline."""
|
|
359
|
+
import pytest
|
|
360
|
+
from pydantic import ValidationError
|
|
361
|
+
|
|
362
|
+
from adl_compliance.checks.layout.directory_ratchet.register import Ratchet
|
|
363
|
+
|
|
364
|
+
with pytest.raises(ValidationError, match="a register grading nothing"):
|
|
365
|
+
Ratchet.model_validate({"schema_version": 2})
|
|
366
|
+
with pytest.raises(ValidationError, match="a register grading nothing"):
|
|
367
|
+
Ratchet.model_validate(
|
|
368
|
+
{
|
|
369
|
+
"schema_version": 2,
|
|
370
|
+
"over_children_baseline": {},
|
|
371
|
+
"single_file_baseline": {},
|
|
372
|
+
"docs_pages": {"baseline": {}},
|
|
373
|
+
}
|
|
374
|
+
)
|
|
@@ -9,6 +9,12 @@ The allowed roots are RESOLVED, not listed: `<docs>`, `<plans>`, `<compliance>`,
|
|
|
9
9
|
graded against its own spelling. The only literals left are `*/LEDGER.md` (a
|
|
10
10
|
register beside the tree it records) and the exclusion list below.
|
|
11
11
|
|
|
12
|
+
A repository can add further Markdown roots of its own under
|
|
13
|
+
`[controls.compliance.markdown] roots` (the `markdown-roots` declaration): a
|
|
14
|
+
directory whose Markdown is site or application content rather than
|
|
15
|
+
documentation. A declared root only ever WIDENS the allowlist, so declaring
|
|
16
|
+
nothing is the stricter grade.
|
|
17
|
+
|
|
12
18
|
This docstring used to read "docs/, .plans/, .specs/, or .changeset/" and three
|
|
13
19
|
of those four were wrong. `.specs` was deleted 2026-09-16 as a path that matched
|
|
14
20
|
nothing in this estate and never could; `.plans` became the resolvable `<plans>`
|
|
@@ -40,12 +46,20 @@ trees; anything in neither list is reported.
|
|
|
40
46
|
from __future__ import annotations
|
|
41
47
|
|
|
42
48
|
import fnmatch
|
|
49
|
+
import glob
|
|
43
50
|
from collections.abc import Iterable
|
|
44
51
|
from typing import ClassVar
|
|
45
52
|
|
|
46
|
-
from ....policy.root_shape import
|
|
53
|
+
from ....policy.root_shape import (
|
|
54
|
+
GOVERNANCE,
|
|
55
|
+
GUIDES,
|
|
56
|
+
REGISTERS,
|
|
57
|
+
ROOT_FILES_DECLARATION,
|
|
58
|
+
declared_root_names,
|
|
59
|
+
)
|
|
47
60
|
from ....core.check import Check
|
|
48
61
|
from ....core.context import Context, FileSet
|
|
62
|
+
from ....core.errors import CouldNotRun
|
|
49
63
|
from ....core.finding import Report
|
|
50
64
|
|
|
51
65
|
|
|
@@ -85,6 +99,9 @@ class MarkdownTrees(Check):
|
|
|
85
99
|
# of "what may sit at a repository's root". This gate asked the same question
|
|
86
100
|
# and was not brought in, so it flagged CONTRIBUTING.md and MAINTAINERS.md --
|
|
87
101
|
# exactly the files d841de1 ruled belong at the root, where a newcomer looks.
|
|
102
|
+
# Only the STANDARD ones: a repository's own root Markdown (a STATUS.md, a
|
|
103
|
+
# DRIFT.md) is declared under `[controls.compliance.root] files` and added by
|
|
104
|
+
# `_excluded`.
|
|
88
105
|
*sorted(GOVERNANCE | GUIDES | REGISTERS),
|
|
89
106
|
"AGENTS.md", "CLAUDE.md", "CHANGELOG.md", "RELEASE.md",
|
|
90
107
|
"INVARIANTS.md", "README.md", "CLAUDE-INVARIANTS.md",
|
|
@@ -176,8 +193,47 @@ class MarkdownTrees(Check):
|
|
|
176
193
|
# `<specs>` only ever ADDS allowlist entries here. enact-m5 has no specs
|
|
177
194
|
# tree; requiring one would push the owner to declare a directory that does
|
|
178
195
|
# not exist, and a false declaration is undetectable. Absent -> stricter.
|
|
196
|
+
#
|
|
197
|
+
# This input is reachable only by a caller that builds a Context by hand (the
|
|
198
|
+
# unit tests do): `cli.py` routes global inputs to batch rows alone, so no
|
|
199
|
+
# `adl-config.toml` key ever reached `specs_root`. A repository's own extra
|
|
200
|
+
# Markdown roots arrive through the `markdown-roots` declaration below.
|
|
179
201
|
widening_inputs: ClassVar[frozenset[str]] = frozenset({"specs_root"})
|
|
180
202
|
|
|
203
|
+
# `[controls.compliance.markdown].roots` -- directories a repository declares
|
|
204
|
+
# as homes for Markdown it authors outside every tree above, e.g. an Astro
|
|
205
|
+
# site's content-collection pages (`apps/marketing/src/content/**/*.md`),
|
|
206
|
+
# which are site content, not documentation and not movable into `docs/`
|
|
207
|
+
# without breaking the framework that loads them. Sent to the engine as one
|
|
208
|
+
# comma-separated `--declare markdown-roots=a,b`.
|
|
209
|
+
ROOTS_DECLARATION: ClassVar[str] = "markdown-roots"
|
|
210
|
+
|
|
211
|
+
def _declared_roots(self, ctx: Context) -> tuple[str, ...]:
|
|
212
|
+
"""The repository-relative directories declared under `markdown-roots`.
|
|
213
|
+
|
|
214
|
+
Normalised (a trailing `/` is dropped) and VALIDATED. A declared root can
|
|
215
|
+
only WIDEN the allowlist, so a malformed one -- absolute, or carrying a
|
|
216
|
+
`.`, `..` or empty segment -- is could-not-run rather than a pattern
|
|
217
|
+
that admits more than the repository meant. `adl` rejects the same set
|
|
218
|
+
when it reads `adl-config.toml`; this is the engine refusing it too,
|
|
219
|
+
because the engine is also run directly with `--declare`. Whether the
|
|
220
|
+
directory exists is not asked: this check cannot walk, and a root that
|
|
221
|
+
matches no file widens nothing.
|
|
222
|
+
"""
|
|
223
|
+
roots: list[str] = []
|
|
224
|
+
for name in sorted(declared_root_names(ctx.declarations, self.ROOTS_DECLARATION)):
|
|
225
|
+
root = name.rstrip("/")
|
|
226
|
+
if name.startswith("/") or any(part in ("", ".", "..") for part in root.split("/")):
|
|
227
|
+
raise CouldNotRun(
|
|
228
|
+
f"{self.id}: `{self.ROOTS_DECLARATION}` declares {name!r}, which is not a "
|
|
229
|
+
"repository-relative directory (it is absolute, or has a `.`, `..` or "
|
|
230
|
+
"empty path segment); fix [controls.compliance.markdown].roots in "
|
|
231
|
+
"adl-config.toml -- a malformed root could only widen the allowlist, "
|
|
232
|
+
"so the gate does not grade against it"
|
|
233
|
+
)
|
|
234
|
+
roots.append(root)
|
|
235
|
+
return tuple(roots)
|
|
236
|
+
|
|
181
237
|
def _allowed(self, ctx: Context) -> tuple[str, ...]:
|
|
182
238
|
allowed = self.ALLOWED
|
|
183
239
|
# Absent is the fixed list, never a crash. The runner always resolves a
|
|
@@ -198,6 +254,14 @@ class MarkdownTrees(Check):
|
|
|
198
254
|
specs_root = ctx.inputs.get("specs_root")
|
|
199
255
|
if specs_root is not None:
|
|
200
256
|
allowed = (*allowed, f"{ctx.relative(specs_root)}/*.md")
|
|
257
|
+
# A declared root admits both suffixes this gate grades, like `docs_root`
|
|
258
|
+
# -- admitting `.md` and reporting `.mdx` beside it would look like half
|
|
259
|
+
# the declaration was ignored. Escaped: `_matches_any` is `fnmatchcase`, so
|
|
260
|
+
# a name carrying `*`, `?` or `[` must be literal or it admits more than
|
|
261
|
+
# it names. Absent declaration = nothing added = stricter.
|
|
262
|
+
for root in self._declared_roots(ctx):
|
|
263
|
+
escaped = glob.escape(root)
|
|
264
|
+
allowed = (*allowed, f"{escaped}/*.md", f"{escaped}/*.mdx")
|
|
201
265
|
return allowed
|
|
202
266
|
|
|
203
267
|
def _excluded(self, ctx: Context) -> tuple[str, ...]:
|
|
@@ -206,7 +270,16 @@ class MarkdownTrees(Check):
|
|
|
206
270
|
root = ctx.inputs.get(input_name)
|
|
207
271
|
if root is not None:
|
|
208
272
|
excluded = (*excluded, f"{ctx.relative(root)}/{suffix}")
|
|
209
|
-
|
|
273
|
+
# Root Markdown the repository declared under `[controls.compliance.root]
|
|
274
|
+
# files` (the `root-files` declaration). Matched EXACTLY: `_matches_any`
|
|
275
|
+
# is `fnmatchcase`, so a declared name carrying `*`, `?` or `[` must be
|
|
276
|
+
# escaped or it would exclude more than it names. A root name has no `/`,
|
|
277
|
+
# so a nested file of the same name is not the declared one.
|
|
278
|
+
declared = sorted(
|
|
279
|
+
name for name in declared_root_names(ctx.declarations, ROOT_FILES_DECLARATION)
|
|
280
|
+
if "/" not in name and name.endswith(self.MARKDOWN_SUFFIXES)
|
|
281
|
+
)
|
|
282
|
+
return (*excluded, *(glob.escape(name) for name in declared))
|
|
210
283
|
|
|
211
284
|
def graded(self, ctx: Context, files: FileSet) -> Iterable[Report]:
|
|
212
285
|
allowed = self._allowed(ctx)
|