@amsterdamdatalabs/adl-agent-control-linux-x64 0.1.46 → 0.1.48
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 +1 -1
- package/bin/reconcile +7 -2
- package/package.json +1 -1
- package/packages/agent-hooks/src/rules/impl/git-branch.ts +1 -1
- package/packages/agent-skills/assets/write-feature/SKILL.md +13 -15
- package/bin/lean-ctx-observe-strip +0 -434
- package/bin/lib/lean-ctx-observe-hooks.sh +0 -634
- package/bin/update-azure-agent-pool +0 -29
- package/packages/agent-hooks/src/hooks/lean-ctx/handler.ts +0 -22
- package/packages/agent-hooks/src/hooks/lean-ctx/index.ts +0 -173
- package/packages/agent-hooks/src/hooks/lean-ctx/mapping.ts +0 -121
- package/packages/agent-hooks/src/hooks/lean-ctx/scope-rewrite.ts +0 -207
- package/packages/agent-hooks/src/lean-ctx/env.ts +0 -123
- package/packages/agent-hooks/src/lean-ctx/mcp.ts +0 -142
- package/packages/agent-hooks/src/rules/impl/adl-build-run-denied.ts +0 -51
- package/packages/agent-hooks/src/rules/impl/adl-session-required.ts +0 -403
- package/packages/agent-hooks/src/rules/impl/tool-lean-ctx-global.ts +0 -594
- package/packages/agent-settings/assets/GLOBAL-AGENTS.md +0 -112
- package/packages/agent-settings/assets/lean-ctx/config.toml +0 -42
- package/packages/agent-settings/assets/lean-ctx/gitignore +0 -10
- package/packages/agent-settings/assets/lean-ctx/layout.toml +0 -7
- package/packages/agent-settings/src/deploy/lean-ctx-deploy.ts +0 -230
- package/packages/agent-settings/src/deploy/lean-ctx-merge.ts +0 -580
- package/packages/agent-skills/assets/adl-mechanics/SKILL.md +0 -38
- package/packages/agent-skills/assets/codebase-design/SKILL.md +0 -98
- package/packages/agent-skills/assets/codebase-design/references/DEEPENING.md +0 -37
- package/packages/agent-skills/assets/codebase-design/references/DESIGN-IT-TWICE.md +0 -44
- package/packages/agent-skills/assets/codebase-design/references/TESTABILITY.md +0 -29
- package/packages/agent-skills/assets/debug-issue/SKILL.md +0 -41
- package/packages/agent-skills/assets/domain-modeling/SKILL.md +0 -86
- package/packages/agent-skills/assets/domain-modeling/references/ADR-FORMAT.md +0 -47
- package/packages/agent-skills/assets/domain-modeling/references/CONTEXT-FORMAT.md +0 -60
- package/packages/agent-skills/assets/implement/SKILL.md +0 -28
- package/packages/agent-skills/assets/review-changes/SKILL.md +0 -45
- package/packages/agent-skills/assets/tdd/SKILL.md +0 -49
- package/packages/agent-skills/assets/tdd/references/mocking.md +0 -59
- package/packages/agent-skills/assets/tdd/references/tests.md +0 -77
- package/packages/agent-skills/assets/testing/SKILL.md +0 -54
- package/packages/agent-skills/assets/testing/references/e2e.md +0 -37
- package/packages/agent-skills/assets/testing/references/integration.md +0 -37
- package/packages/agent-skills/assets/testing/references/unit.md +0 -32
- package/packages/agent-skills/assets/to-feature/SKILL.md +0 -91
- package/packages/agent-skills/assets/to-feature/references/FEATURE-SPEC-TEMPLATE.md +0 -88
- package/packages/agent-skills/assets/to-workitems/SKILL.md +0 -90
- package/packages/agent-skills/assets/to-workitems/references/AZURE-DEVOPS-HIERARCHY.md +0 -121
- package/packages/agent-skills/assets/to-workitems/references/TICKET-TEMPLATES.md +0 -70
- package/packages/azdo/src/workflow-rules-matrix.csv +0 -85
- package/packages/fleet/src/launch-agents.ts +0 -649
- package/packages/repo-controls/assets/GLOBAL-INVARIANTS.md +0 -21
- package/packages/repo-controls/assets/enable-integration-auto-complete.mjs +0 -79
- package/packages/repo-controls/assets/scaffold/docs/notes.md +0 -20
- package/packages/repo-controls/assets/scaffold/plans/GAPS-AND-FINDINGS.md +0 -12
- package/packages/repo-controls/azure-pipelines.yml +0 -274
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/closed_set/fixtures/docs/notes.md +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/english_only/fixtures/excluded/frontend/mobile/src/i18n/locales/zh-CN/strings.ts +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-ledger-clean/docs/notes.md +0 -17
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-ledger-no-lines/docs/notes.md +0 -13
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/semantics/fixtures/semantics-violations/docs/architecture/product/stable-delivery.md +0 -10
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/semantics/fixtures/semantics-violations/docs/architecture/product/stable-recommendation.md +0 -12
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/semantics/fixtures/semantics-violations/docs/architecture/product/target-narration.md +0 -10
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-clean/frontend/packages/desktop/src/renderer/solo/item.ts +0 -1
- 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 +0 -1
- 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 +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/frontend/packages/desktop/src/renderer/fresh/fresh.ts +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/frontend/packages/desktop/src/renderer/many/sub1/only.ts +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/frontend/packages/desktop/src/renderer/many/sub10/only.ts +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/frontend/packages/desktop/src/renderer/many/sub11/only.ts +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/frontend/packages/desktop/src/renderer/many/sub2/only.ts +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/frontend/packages/desktop/src/renderer/many/sub3/only.ts +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/frontend/packages/desktop/src/renderer/many/sub4/only.ts +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/frontend/packages/desktop/src/renderer/many/sub5/only.ts +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/frontend/packages/desktop/src/renderer/many/sub6/only.ts +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/frontend/packages/desktop/src/renderer/many/sub7/only.ts +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/frontend/packages/desktop/src/renderer/many/sub8/only.ts +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/frontend/packages/desktop/src/renderer/many/sub9/only.ts +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/frontend/packages/desktop/src/renderer/services/i18n/locales/de/common.json +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/frontend/packages/desktop/src/renderer/solo/item.ts +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/frontend/packages/desktop/src/vendored-crate/Cargo.toml +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 +0 -1
- 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 +0 -1
- 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 +0 -1
- 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 +0 -1
- 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 +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unbaselined/frontend/packages/desktop/src/renderer/fresh/fresh.ts +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unbaselined/frontend/packages/desktop/src/renderer/many/sub1/only.ts +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unbaselined/frontend/packages/desktop/src/renderer/many/sub10/only.ts +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unbaselined/frontend/packages/desktop/src/renderer/many/sub11/only.ts +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unbaselined/frontend/packages/desktop/src/renderer/many/sub2/only.ts +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unbaselined/frontend/packages/desktop/src/renderer/many/sub3/only.ts +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unbaselined/frontend/packages/desktop/src/renderer/many/sub4/only.ts +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unbaselined/frontend/packages/desktop/src/renderer/many/sub5/only.ts +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unbaselined/frontend/packages/desktop/src/renderer/many/sub6/only.ts +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unbaselined/frontend/packages/desktop/src/renderer/many/sub7/only.ts +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unbaselined/frontend/packages/desktop/src/renderer/many/sub8/only.ts +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unbaselined/frontend/packages/desktop/src/renderer/many/sub9/only.ts +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unbaselined/frontend/packages/desktop/src/renderer/solo/item.ts +0 -1
- 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 +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/open_work_cap/fixtures/open-work-cap-clean/plans/GAPS-AND-FINDINGS.md +0 -5
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/open_work_cap/fixtures/open-work-cap-clean/plans/features/az601-clean/spec.md +0 -10
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/placement/fixtures/placement-allowed/agent/crates/enact-providers/src/snapshots/README.md +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/placement/fixtures/placement-allowed/backend/crates/enact-app/assets/builtin-assistants/avatars/assistant.jpg +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/placement/fixtures/placement-allowed/backend/crates/enact-assets/assets/logos/tools/coding/tool.png +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/placement/fixtures/placement-allowed/backend/crates/enact-session/src/backend/codex_init_prompt.md +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/placement/fixtures/placement-allowed/frontend/mobile/assets/images/icon.png +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/placement/fixtures/placement-allowed/frontend/packages/desktop/src/renderer/assets/logos/brand/app.png +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/placement/fixtures/placement-allowed/frontend/packages/desktop/src/renderer/assets/themes/default-theme.png +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/placement/fixtures/placement-allowed/frontend/public/pwa/icon-192.png +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/placement/fixtures/placement-allowed/frontend/resources/product.png +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/placement/fixtures/placement-stray/backend/crates/enact-session/src/backend/README.md +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/plans_layout/fixtures/plans-layout-clean/plans/features/az347-test-coverage/spec.md +0 -12
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/plans_layout/fixtures/plans-layout-violation/plans/features/az347-test-coverage/spec.md +0 -12
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/profile_data/__init__.py +0 -11
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/profile_data/check.py +0 -62
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/profile_data/fixtures/migration-filenames/backend/crates/demo/NotAMigration.sql +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/profile_data/fixtures/migration-filenames/backend/crates/demo/migrations/0001_long_prefix.sql +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/profile_data/fixtures/migration-filenames/backend/crates/demo/migrations/001_init.sql +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/profile_data/fixtures/migration-filenames/backend/crates/demo/migrations/002_add_index.sql +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/profile_data/fixtures/migration-filenames/backend/crates/demo/migrations/003-dashed-slug.sql +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/profile_data/fixtures/migration-filenames/backend/crates/demo/migrations/004_MixedCase.sql +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/profile_data/fixtures/migration-filenames/backend/crates/demo/migrations/005_trailing space.sql +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/profile_data/fixtures/migration-filenames/backend/crates/demo/migrations/01_short_prefix.sql +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/profile_data/fixtures/migration-filenames/backend/crates/demo/migrations/not-a-migration.sql +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/profile_data/test_check.py +0 -116
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/references/fixtures/link-targets-broken/docs/architecture/product/links.md +0 -20
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/references/fixtures/link-targets-broken/docs/architecture/product/route-target.md +0 -8
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/references/fixtures/link-targets-clean/docs/architecture/product/links.md +0 -20
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/references/fixtures/link-targets-clean/docs/architecture/product/route-target.md +0 -8
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/.changeset/declared.txt +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_markdown_allowlist/fixtures/root-markdown-clean/INDEPENDENT-VERIFICATION.md +0 -3
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/attribute-without-conversion/.gitattributes +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/attribute-without-conversion/large file.bin +0 -3
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/clean/.gitattributes +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/clean/large file.bin +0 -3
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/clean/small.txt +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/missing-filter/large file.bin +0 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/unmatched-extension/.gitattributes +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/unmatched-extension/payload.dat +0 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/pipeline/__init__.py +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/pipeline/phase_disjoint/__init__.py +0 -12
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/pipeline/phase_disjoint/check.py +0 -129
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/pipeline/phase_disjoint/fixtures/disjoint/gate-registry.yaml +0 -13
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/pipeline/phase_disjoint/fixtures/empty/gate-registry.yaml +0 -7
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/pipeline/phase_disjoint/fixtures/overlapping/gate-registry.yaml +0 -13
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/pipeline/phase_disjoint/test_check.py +0 -109
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/release/__init__.py +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/release/changeset_plan/__init__.py +0 -11
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/release/changeset_plan/check.py +0 -149
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/release/changeset_plan/fixtures/clean/docs/readme.md +0 -4
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/release/changeset_plan/fixtures/relevant/VERSION +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/release/changeset_plan/test_check.py +0 -151
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/release/version_release/__init__.py +0 -11
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/release/version_release/check.py +0 -202
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/release/version_release/fixtures/aligned/.workflows/changesets/package.json +0 -5
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/release/version_release/fixtures/aligned/.workflows/package.json +0 -5
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/release/version_release/fixtures/aligned/CHANGELOG.md +0 -5
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/release/version_release/fixtures/aligned/VERSION +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/release/version_release/fixtures/mismatched/.workflows/changesets/package.json +0 -5
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/release/version_release/fixtures/mismatched/.workflows/package.json +0 -5
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/release/version_release/fixtures/mismatched/CHANGELOG.md +0 -5
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/release/version_release/fixtures/mismatched/VERSION +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/release/version_release/test_check.py +0 -162
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/banned_commands/check.py +0 -103
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/fixtures/clean/backend/Cargo.lock +0 -7
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/fixtures/clean/backend/Cargo.toml +0 -4
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/fixtures/clean/backend/rust-toolchain.toml +0 -3
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/fixtures/clean/backend/src/main.rs +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/fixtures/clean/frontend/bun.lock +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/fixtures/empty-bun-lock/backend/Cargo.lock +0 -7
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/fixtures/empty-bun-lock/backend/Cargo.toml +0 -4
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/fixtures/empty-bun-lock/backend/rust-toolchain.toml +0 -3
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/fixtures/empty-bun-lock/backend/src/main.rs +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/fixtures/empty-bun-lock/frontend/bun.lock +0 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/grants-registry.yaml +0 -112
- package/packages/repo-controls/workflows/scripts/release/verify-npm-artifact.ts +0 -119
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
"""PIP-004 — ported from
|
|
2
|
-
`compliance_new/checks/pipeline/phase-disjoint/test.sh`.
|
|
3
|
-
|
|
4
|
-
Same three named corpora as the shell fixtures, ported byte-for-byte
|
|
5
|
-
(`overlapping`, `disjoint`, `empty`), minus the `policy/` wrapper directory
|
|
6
|
-
the shell version needed to reassemble a whole package around the copied
|
|
7
|
-
gate script — the Python check reads its named input directly, so the
|
|
8
|
-
committed fixture is just the one document each case is about.
|
|
9
|
-
|
|
10
|
-
This wave's checks are wired into `checks/__init__.py` in a later, single
|
|
11
|
-
pass, so `PhaseDisjoint` is not yet registered under `checks.lookup`. Rather
|
|
12
|
-
than call `runner.run()` — which would resolve `PIP-004` to "no check
|
|
13
|
-
implements it" and report `COULD_NOT_RUN` for the wrong reason, a
|
|
14
|
-
coincidental pass — `run_check` below builds the `Context` directly (with the
|
|
15
|
-
one named input this gate declares) and drives the check the same way
|
|
16
|
-
`runner.run` would, so the real row (`policy/gate-registry.yaml`'s `PIP-004`)
|
|
17
|
-
and the real check class are exercised without depending on the registry
|
|
18
|
-
wiring. This is the same bypass `contracts.transport-boundaries`'s test uses
|
|
19
|
-
for an unwired, entirely-structural gate.
|
|
20
|
-
|
|
21
|
-
The shell `test.sh` also asserts two cases this port does not reproduce:
|
|
22
|
-
|
|
23
|
-
* "no set given is could-not-run" — a scope guard `check.sh` itself enforced
|
|
24
|
-
by hand (`ADL_CHANGED_FILES` unset). Here scope resolution belongs to
|
|
25
|
-
`runner.run`/the CLI, never to a check (K-29..K-31), and this gate reads no
|
|
26
|
-
member of the given file set at all (`graded` is unimplemented), so there
|
|
27
|
-
is no equivalent guard inside `PhaseDisjoint` for a test to exercise.
|
|
28
|
-
* the exact registry source LINE each finding points at (`yq '.id | line'`).
|
|
29
|
-
`yaml.safe_load` does not carry line numbers back into the parsed model,
|
|
30
|
-
and no other YAML-register gate ported so far (`layout.directory-ratchet`,
|
|
31
|
-
`contracts.transport-boundaries`) attaches one either; this port follows
|
|
32
|
-
that precedent and reports the registry's path without a line.
|
|
33
|
-
|
|
34
|
-
See `check.py`'s docstring for why neither the currently shipped shell
|
|
35
|
-
registry nor this package's own carries a single row with `phases:` today —
|
|
36
|
-
the scheduling model MET-001 grades was already retired in favour of
|
|
37
|
-
`engine.scope`-based triggering before this row was ported. Ported here
|
|
38
|
-
faithfully anyway, against the same three corpora `check.sh` was proven
|
|
39
|
-
against.
|
|
40
|
-
"""
|
|
41
|
-
|
|
42
|
-
from __future__ import annotations
|
|
43
|
-
|
|
44
|
-
import pathlib
|
|
45
|
-
|
|
46
|
-
from adl_compliance.checks.pipeline.phase_disjoint import PhaseDisjoint
|
|
47
|
-
from adl_compliance.core.context import Context, FileSet
|
|
48
|
-
from adl_compliance.core.errors import CouldNotRun
|
|
49
|
-
from adl_compliance.core.verdict import Outcome, Verdict, could_not_run, decide
|
|
50
|
-
from adl_compliance.policy.registry import load
|
|
51
|
-
|
|
52
|
-
FIXTURES = pathlib.Path(__file__).parent / "fixtures"
|
|
53
|
-
OVERLAPPING = FIXTURES / "overlapping" / "gate-registry.yaml"
|
|
54
|
-
DISJOINT = FIXTURES / "disjoint" / "gate-registry.yaml"
|
|
55
|
-
EMPTY = FIXTURES / "empty" / "gate-registry.yaml"
|
|
56
|
-
NOT_COMMITTED = FIXTURES / "gone.yaml"
|
|
57
|
-
|
|
58
|
-
ROW = load().by_id("PIP-004")
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
def run_check(registry: pathlib.Path) -> Verdict:
|
|
62
|
-
"""`runner.run`'s grade-then-decide, against this check directly — the
|
|
63
|
-
same bypass `contracts.transport-boundaries`'s test uses for an unwired
|
|
64
|
-
check."""
|
|
65
|
-
ctx = Context(root=FIXTURES, row=ROW, inputs={"registry": registry})
|
|
66
|
-
try:
|
|
67
|
-
findings = tuple(PhaseDisjoint().run(ctx, FileSet()))
|
|
68
|
-
except CouldNotRun as exc:
|
|
69
|
-
return could_not_run(ROW, str(exc))
|
|
70
|
-
return decide(ROW, findings, 0, ())
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
# ------------------------------------------------------------- both overlaps
|
|
74
|
-
|
|
75
|
-
def test_both_overlaps_are_reported_and_the_clean_row_is_not() -> None:
|
|
76
|
-
verdict = run_check(OVERLAPPING)
|
|
77
|
-
assert verdict.outcome is Outcome.FINDINGS, verdict.render()
|
|
78
|
-
assert verdict.rules == ["MET-001", "MET-001"]
|
|
79
|
-
|
|
80
|
-
messages = [f.message for f in verdict.findings]
|
|
81
|
-
assert any("BAD-01 runs at both pre-commit and pre-push" in m for m in messages)
|
|
82
|
-
assert any("BAD-02 runs at both pr_validation and qua_deploy" in m for m in messages)
|
|
83
|
-
assert not any("OK-01" in m for m in messages)
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
# --------------------------------------------------------- every row disjoint
|
|
87
|
-
|
|
88
|
-
def test_a_disjoint_registry_reports_nothing() -> None:
|
|
89
|
-
verdict = run_check(DISJOINT)
|
|
90
|
-
assert verdict.outcome is Outcome.CLEAN, verdict.render()
|
|
91
|
-
assert verdict.findings == ()
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
# ------------------------------------------------- zero rows is could-not-run
|
|
95
|
-
|
|
96
|
-
def test_a_registry_that_decodes_to_zero_rows_is_could_not_run() -> None:
|
|
97
|
-
"""A decode that yields nothing must not read as a clean estate — the
|
|
98
|
-
assertion that separates "every row passed" from "the gate read nothing"."""
|
|
99
|
-
verdict = run_check(EMPTY)
|
|
100
|
-
assert verdict.outcome is Outcome.COULD_NOT_RUN, verdict.render()
|
|
101
|
-
assert "decoded zero rows" in verdict.message
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
# --------------------------------------------------------- a missing registry
|
|
105
|
-
|
|
106
|
-
def test_a_missing_registry_is_could_not_run_not_a_pass() -> None:
|
|
107
|
-
verdict = run_check(NOT_COMMITTED)
|
|
108
|
-
assert verdict.outcome is Outcome.COULD_NOT_RUN, verdict.render()
|
|
109
|
-
assert "missing input" in verdict.message
|
package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/release/__init__.py
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
"""release."""
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
"""The `release.changeset-plan` gate.
|
|
2
|
-
|
|
3
|
-
A folder rather than a module because this gate's fixture corpora — a clean
|
|
4
|
-
one and a release-relevant one — belong beside the check that reads them.
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
|
-
from __future__ import annotations
|
|
8
|
-
|
|
9
|
-
from .check import ChangesetPlan
|
|
10
|
-
|
|
11
|
-
__all__ = ["ChangesetPlan"]
|
|
@@ -1,149 +0,0 @@
|
|
|
1
|
-
"""REL-001 — ported from
|
|
2
|
-
`compliance_new/checks/release/changeset-plan/check.sh`.
|
|
3
|
-
|
|
4
|
-
Entirely `graded`: the rule is "does the given set contain a release-relevant
|
|
5
|
-
path", and there is no named path this gate probes unconditionally — an empty
|
|
6
|
-
or irrelevant set is a silent pass, exactly as the shell script's own
|
|
7
|
-
`needs_changeset` guard makes it.
|
|
8
|
-
|
|
9
|
-
**The shell script's own case list, carried over untranslated.** `check.sh`'s
|
|
10
|
-
`case "$path" in .workflows/changesets/package.json | ... | .changeset/*)`
|
|
11
|
-
matches with bash's `case` pattern semantics, where `*` matches any string
|
|
12
|
-
INCLUDING one containing `/` (case patterns are not restricted to filesystem
|
|
13
|
-
pathname semantics the way `for f in *` is). `.changeset/*` therefore matches
|
|
14
|
-
`.changeset/plan.md` and `.changeset/nested/plan.md` alike — the same reach as
|
|
15
|
-
the registry row's own `.changeset/**` scope entry, not a narrower one.
|
|
16
|
-
`fnmatch.fnmatchcase` has the identical property (a straight `*` -> `.*` regex
|
|
17
|
-
translation, no path-separator special-casing) and, unlike plain `fnmatch`,
|
|
18
|
-
no host-dependent case folding either, so it reproduces the shell patterns
|
|
19
|
-
verbatim rather than approximating them with a hand-rolled prefix test.
|
|
20
|
-
|
|
21
|
-
**Linear, not accumulating**, like the shell version: `fail()` there reports
|
|
22
|
-
one finding and exits immediately, so at most one REL-001 finding ever comes
|
|
23
|
-
out of a single run. Each branch below yields once and returns.
|
|
24
|
-
|
|
25
|
-
**The jq-optional schema check does not survive.** `check.sh` skips its
|
|
26
|
-
"changeset status output is not a JSON object" check entirely when `jq` is not
|
|
27
|
-
on the host (`echo "... jq not installed for schema check"; exit 0`) — jq was
|
|
28
|
-
an EXTERNAL tool the shell script had no other way to parse JSON with. This
|
|
29
|
-
port has `json.loads` unconditionally, so the schema check always runs; there
|
|
30
|
-
is no equivalent "jq missing" skip because there is nothing here that can be
|
|
31
|
-
missing. This is a deliberate behavioural difference, not an oversight: it
|
|
32
|
-
makes the gate strictly stricter (it now catches a malformed JSON object on
|
|
33
|
-
every host, not only the ones with jq installed), never looser.
|
|
34
|
-
|
|
35
|
-
**`release/changeset-tooling.sh` is not a registered tree.** It is invoked as
|
|
36
|
-
a literal repository-relative path, exactly as `check.sh` invoked it — never
|
|
37
|
-
through a `<tree>` placeholder, because no `release` entry exists in
|
|
38
|
-
`policy/trees.toml` (K-42 governs a NAMED tree; this is one specific script
|
|
39
|
-
this one gate drives, declared as a plain `inputs` path like any other
|
|
40
|
-
consumer-owned file). Declared via `requires = ("bash",)` because that is the
|
|
41
|
-
interpreter the shell tool was always invoked through and is exactly what
|
|
42
|
-
`Check.requires` exists to verify before this code runs at all.
|
|
43
|
-
|
|
44
|
-
**A real limit, inherited rather than introduced.** `release/` does not exist
|
|
45
|
-
in this checkout (nor, per `git log`, has it ever been committed at any
|
|
46
|
-
reachable ref), so the "changeset status succeeded and its JSON was graded"
|
|
47
|
-
branch has never been exercised by anything this port can run — the shell
|
|
48
|
-
test's own docstring says the same thing about its own fixture. This port
|
|
49
|
-
proves exactly what the shell test proved: a release-relevant path in the
|
|
50
|
-
given set reaches the tool invocation, and the tool's failure becomes a
|
|
51
|
-
REL-001 finding rather than a crash or a silent pass.
|
|
52
|
-
"""
|
|
53
|
-
|
|
54
|
-
from __future__ import annotations
|
|
55
|
-
|
|
56
|
-
import fnmatch
|
|
57
|
-
import json
|
|
58
|
-
import subprocess
|
|
59
|
-
import tempfile
|
|
60
|
-
from collections.abc import Iterable
|
|
61
|
-
from pathlib import Path
|
|
62
|
-
from typing import ClassVar
|
|
63
|
-
|
|
64
|
-
from ....core.check import Check
|
|
65
|
-
from ....core.context import Context, FileSet
|
|
66
|
-
from ....core.finding import Report
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
class ChangesetPlan(Check):
|
|
70
|
-
id: ClassVar[str] = "REL-001"
|
|
71
|
-
rule: ClassVar[str] = "REL-001"
|
|
72
|
-
requires: ClassVar[tuple[str, ...]] = ("bash",)
|
|
73
|
-
|
|
74
|
-
# check.sh's own `case "$path" in ...)` alternatives. `VERSION`,
|
|
75
|
-
# `CHANGELOG.md`, and `.changeset/*` are root-relative subject matter the
|
|
76
|
-
# gate owns outright, never a consumer's tree choice; the two
|
|
77
|
-
# `.workflows`-rooted ones are fixed 2026-09-15 (K-42 sweep) — they used
|
|
78
|
-
# to be hardcoded literals FILTERING the given set (`_is_release_relevant`
|
|
79
|
-
# below), so a repository declaring `workflows` away from its packaged
|
|
80
|
-
# default had every real release-relevant change silently excluded and
|
|
81
|
-
# this gate went quiet over content it never read — the CON-002 shape.
|
|
82
|
-
ROOT_RELEVANT: ClassVar[tuple[str, ...]] = ("VERSION", "CHANGELOG.md", ".changeset/*")
|
|
83
|
-
|
|
84
|
-
inputs: ClassVar[dict[str, str]] = {
|
|
85
|
-
# A literal repository-relative path, not a `<tree>` placeholder: no
|
|
86
|
-
# `release` tree is registered in `policy/trees.toml`, and this is the
|
|
87
|
-
# one script this one gate drives, not a named consumer tree.
|
|
88
|
-
"changeset_tool": "release/changeset-tooling.sh",
|
|
89
|
-
"workflows_package": "<workflows>/package.json",
|
|
90
|
-
"changesets_package": "<workflows>/changesets/package.json",
|
|
91
|
-
"changesets_lock": "<workflows>/changesets/bun.lock",
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
def graded(self, ctx: Context, files: FileSet) -> Iterable[Report]:
|
|
95
|
-
release_relevant = self.ROOT_RELEVANT + (
|
|
96
|
-
ctx.relative(ctx.inputs["workflows_package"]),
|
|
97
|
-
ctx.relative(ctx.inputs["changesets_package"]),
|
|
98
|
-
ctx.relative(ctx.inputs["changesets_lock"]),
|
|
99
|
-
)
|
|
100
|
-
if not any(self._is_release_relevant(path, release_relevant) for path in files):
|
|
101
|
-
return
|
|
102
|
-
|
|
103
|
-
with tempfile.TemporaryDirectory(prefix="changeset-status.") as work:
|
|
104
|
-
status_file = Path(work) / "status.json"
|
|
105
|
-
completed = subprocess.run(
|
|
106
|
-
(
|
|
107
|
-
"bash", str(ctx.inputs["changeset_tool"]),
|
|
108
|
-
"changeset", "status", "--output", str(status_file),
|
|
109
|
-
),
|
|
110
|
-
cwd=ctx.root, capture_output=True, text=True, check=False,
|
|
111
|
-
)
|
|
112
|
-
if completed.returncode != 0:
|
|
113
|
-
yield self.report(
|
|
114
|
-
".changeset",
|
|
115
|
-
"changeset status could not be computed for a release-relevant change",
|
|
116
|
-
"add a .changeset/*.md plan for the release-relevant change, or fix "
|
|
117
|
-
"the failing 'release/changeset-tooling.sh changeset status' invocation",
|
|
118
|
-
)
|
|
119
|
-
return
|
|
120
|
-
|
|
121
|
-
if not status_file.is_file():
|
|
122
|
-
yield self.report(
|
|
123
|
-
".changeset",
|
|
124
|
-
"changeset status did not write its output file",
|
|
125
|
-
"investigate why 'release/changeset-tooling.sh changeset status "
|
|
126
|
-
"--output <file>' did not create the file",
|
|
127
|
-
)
|
|
128
|
-
return
|
|
129
|
-
|
|
130
|
-
body = status_file.read_text(encoding="utf-8", errors="replace")
|
|
131
|
-
try:
|
|
132
|
-
parsed = json.loads(body)
|
|
133
|
-
except json.JSONDecodeError:
|
|
134
|
-
parsed = None
|
|
135
|
-
if not isinstance(parsed, dict):
|
|
136
|
-
yield self.report(
|
|
137
|
-
"release/changeset-tooling.sh",
|
|
138
|
-
"changeset status output is not a JSON object",
|
|
139
|
-
"fix release/changeset-tooling.sh's 'changeset status --output' to "
|
|
140
|
-
"emit a JSON object",
|
|
141
|
-
)
|
|
142
|
-
|
|
143
|
-
@staticmethod
|
|
144
|
-
def _is_release_relevant(path: str, patterns: tuple[str, ...]) -> bool:
|
|
145
|
-
# `fnmatchcase`, not `fnmatch`: the shell `case` statement this ports
|
|
146
|
-
# is byte-for-byte case-sensitive, and plain `fnmatch` normalises case
|
|
147
|
-
# through `os.path.normcase` — a no-op on POSIX but not on Windows, so
|
|
148
|
-
# this would silently diverge from the shell semantics on that host.
|
|
149
|
-
return any(fnmatch.fnmatchcase(path, pattern) for pattern in patterns)
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
0.0.1
|
|
@@ -1,151 +0,0 @@
|
|
|
1
|
-
"""REL-001 — ported from
|
|
2
|
-
`compliance_new/checks/release/changeset-plan/test.sh`.
|
|
3
|
-
|
|
4
|
-
Two committed fixtures, copied byte-for-byte from the shell tree's corpora:
|
|
5
|
-
`fixtures/clean/docs/readme.md` (no release-relevant path) and
|
|
6
|
-
`fixtures/relevant/VERSION` (release-relevant, and the corpus deliberately
|
|
7
|
-
carries no `release/` tree so `bash release/changeset-tooling.sh` fails for
|
|
8
|
-
the same reason every time — see `check.py`'s module docstring for why that
|
|
9
|
-
is this gate's real, inherited limit as a fixture subject, not a gap this port
|
|
10
|
-
introduced).
|
|
11
|
-
|
|
12
|
-
This check is intentionally NOT wired into `checks/__init__.py` yet (a
|
|
13
|
-
separate step wires this whole wave's checks into the registry in one shot),
|
|
14
|
-
so these tests call `ChangesetPlan.graded` directly against a hand-built
|
|
15
|
-
`Context`/`FileSet` — the same bypass `docs/markdown_ast/test_check.py` and
|
|
16
|
-
`pipeline/parser_tool_range/test_check.py` use for an unwired check, not a
|
|
17
|
-
shortcut around row-scope narrowing.
|
|
18
|
-
|
|
19
|
-
`test.sh`'s three cases map onto the three tests below exactly: a set with no
|
|
20
|
-
release-relevant path exits 0 and reports nothing; a set naming `VERSION`
|
|
21
|
-
reaches the tool invocation and turns its failure into exactly one REL-001
|
|
22
|
-
finding on `.changeset`; an empty set grades nothing at all.
|
|
23
|
-
"""
|
|
24
|
-
|
|
25
|
-
from __future__ import annotations
|
|
26
|
-
|
|
27
|
-
import pathlib
|
|
28
|
-
import shutil
|
|
29
|
-
|
|
30
|
-
import pytest
|
|
31
|
-
|
|
32
|
-
from adl_compliance.checks.release.changeset_plan import ChangesetPlan
|
|
33
|
-
from adl_compliance.core.context import Context, FileSet
|
|
34
|
-
from adl_compliance.core.verdict import Outcome, decide
|
|
35
|
-
from adl_compliance.policy.registry import load
|
|
36
|
-
|
|
37
|
-
FIXTURES = pathlib.Path(__file__).parent / "fixtures"
|
|
38
|
-
CLEAN = FIXTURES / "clean"
|
|
39
|
-
RELEVANT = FIXTURES / "relevant"
|
|
40
|
-
|
|
41
|
-
ROW = load().by_id("REL-001")
|
|
42
|
-
|
|
43
|
-
pytestmark = pytest.mark.skipif(
|
|
44
|
-
shutil.which("bash") is None, reason="release.changeset-plan drives bash"
|
|
45
|
-
)
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
def corpus_files(root: pathlib.Path) -> tuple[str, ...]:
|
|
49
|
-
"""Every file in the corpus, relative to it — the same shape
|
|
50
|
-
`_corpus-set.sh`'s `corpus_set` produced for the shell test."""
|
|
51
|
-
return tuple(
|
|
52
|
-
sorted(
|
|
53
|
-
str(path.relative_to(root))
|
|
54
|
-
for path in root.rglob("*")
|
|
55
|
-
if path.is_file()
|
|
56
|
-
)
|
|
57
|
-
)
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
def graded(root: pathlib.Path, given: tuple[str, ...]):
|
|
61
|
-
ctx = Context(
|
|
62
|
-
root=root, row=ROW,
|
|
63
|
-
inputs={
|
|
64
|
-
"changeset_tool": root / "release" / "changeset-tooling.sh",
|
|
65
|
-
"workflows_package": root / ".workflows" / "package.json",
|
|
66
|
-
"changesets_package": root / ".workflows" / "changesets" / "package.json",
|
|
67
|
-
"changesets_lock": root / ".workflows" / "changesets" / "bun.lock",
|
|
68
|
-
},
|
|
69
|
-
)
|
|
70
|
-
findings = tuple(ChangesetPlan().graded(ctx, FileSet(paths=given)))
|
|
71
|
-
return decide(ROW, findings, 0, ())
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
def test_the_row_declares_the_gate_this_check_ports() -> None:
|
|
75
|
-
assert ROW.domain == "release"
|
|
76
|
-
assert ROW.name == "changeset-plan"
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
def test_the_fixture_premise_holds() -> None:
|
|
80
|
-
"""A mistyped fixture path would leave every assertion below vacuous."""
|
|
81
|
-
assert (CLEAN / "docs" / "readme.md").is_file()
|
|
82
|
-
assert (RELEVANT / "VERSION").is_file()
|
|
83
|
-
assert not (RELEVANT / "release").exists()
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
def test_no_release_relevant_path_is_a_clean_no_op() -> None:
|
|
87
|
-
verdict = graded(CLEAN, corpus_files(CLEAN))
|
|
88
|
-
assert verdict.outcome is Outcome.CLEAN, verdict.render()
|
|
89
|
-
assert verdict.findings == ()
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
def test_a_release_relevant_path_reaches_the_tool_and_reports_its_failure() -> None:
|
|
93
|
-
verdict = graded(RELEVANT, corpus_files(RELEVANT))
|
|
94
|
-
assert verdict.outcome is Outcome.FINDINGS, verdict.render()
|
|
95
|
-
assert len(verdict.findings) == 1
|
|
96
|
-
finding = verdict.findings[0]
|
|
97
|
-
assert finding.rule == "REL-001"
|
|
98
|
-
assert finding.path == ".changeset"
|
|
99
|
-
assert finding.message == (
|
|
100
|
-
"changeset status could not be computed for a release-relevant change"
|
|
101
|
-
)
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
def test_an_empty_set_grades_nothing() -> None:
|
|
105
|
-
verdict = graded(CLEAN, ())
|
|
106
|
-
assert verdict.outcome is Outcome.CLEAN, verdict.render()
|
|
107
|
-
assert verdict.findings == ()
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
def test_changeset_star_matches_a_nested_path_like_the_shell_case_pattern() -> None:
|
|
111
|
-
"""bash `case` patterns are not restricted to filesystem pathname
|
|
112
|
-
semantics: `.changeset/*` matches a path with more than one segment
|
|
113
|
-
beneath it, the same reach as the row's own `.changeset/**` scope."""
|
|
114
|
-
patterns = ChangesetPlan.ROOT_RELEVANT + (".workflows/package.json",)
|
|
115
|
-
assert ChangesetPlan._is_release_relevant(".changeset/nested/plan.md", patterns)
|
|
116
|
-
assert ChangesetPlan._is_release_relevant(".changeset/plan.md", patterns)
|
|
117
|
-
assert not ChangesetPlan._is_release_relevant("docs/readme.md", patterns)
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
def test_a_redeclared_workflows_tree_is_honoured() -> None:
|
|
121
|
-
"""FIXED 2026-09-15 (K-42 sweep): the bug this pins is SILENT — the old
|
|
122
|
-
`RELEASE_RELEVANT` tuple hardcoded `.workflows/...`, and `_is_release_
|
|
123
|
-
relevant` filtered the given set against it directly. A repository
|
|
124
|
-
declaring `workflows = "my-workflows"` with a real, changed `my-workflows
|
|
125
|
-
/package.json` in the given set would have that file match NOTHING,
|
|
126
|
-
`graded` would return on its very first line, and this gate would go
|
|
127
|
-
quiet over a release-relevant change it never read — never an error,
|
|
128
|
-
never a finding, a clean pass over unread content. This drives the real
|
|
129
|
-
`<workflows>` resolution (not the manual `inputs` override every other
|
|
130
|
-
test in this file uses) via `runner.resolve_inputs`/`effective_trees`,
|
|
131
|
-
and a given set containing ONLY the redeclared-tree path (nothing under
|
|
132
|
-
`.workflows/` at all) — proving the match comes from the resolved tree,
|
|
133
|
-
not a coincidental literal overlap."""
|
|
134
|
-
from contextlib import ExitStack
|
|
135
|
-
|
|
136
|
-
from adl_compliance import runner
|
|
137
|
-
from adl_compliance.policy.registry import effective_trees
|
|
138
|
-
|
|
139
|
-
tool = RELEVANT / "release" / "changeset-tooling.sh"
|
|
140
|
-
with ExitStack() as stack:
|
|
141
|
-
inputs = runner.resolve_inputs(
|
|
142
|
-
ChangesetPlan, RELEVANT, {ChangesetPlan.id: {"changeset_tool": tool}}, stack,
|
|
143
|
-
effective_trees({"workflows": "my-workflows"}),
|
|
144
|
-
)
|
|
145
|
-
ctx = Context(root=RELEVANT, row=ROW, inputs=inputs)
|
|
146
|
-
findings = tuple(
|
|
147
|
-
ChangesetPlan().graded(ctx, FileSet(paths=("my-workflows/package.json",)))
|
|
148
|
-
)
|
|
149
|
-
verdict = decide(ROW, findings, 0, ())
|
|
150
|
-
assert verdict.outcome is Outcome.FINDINGS, verdict.render()
|
|
151
|
-
assert verdict.findings[0].rule == "REL-001"
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
"""The `release.version-release` gate.
|
|
2
|
-
|
|
3
|
-
A folder rather than a module because this gate's fixture corpora — an
|
|
4
|
-
aligned checkout and a drifted one — belong beside the check that reads them.
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
|
-
from __future__ import annotations
|
|
8
|
-
|
|
9
|
-
from .check import VersionRelease
|
|
10
|
-
|
|
11
|
-
__all__ = ["VersionRelease"]
|
|
@@ -1,202 +0,0 @@
|
|
|
1
|
-
"""REL-004 — VERSION, CHANGELOG.md, and the two workflow manifests, aligned.
|
|
2
|
-
|
|
3
|
-
Ported from `compliance_new/checks/release/version-release/check.sh`. Entirely
|
|
4
|
-
`structural`: every file this gate reads — VERSION, CHANGELOG.md, and the two
|
|
5
|
-
entries in the shell's `versioned_files` array — is a FIXED, named path, never
|
|
6
|
-
a member of the given set. That script's own comment says the same thing:
|
|
7
|
-
"This gate reads no file set: the manifests it aligns are a FIXED list, named
|
|
8
|
-
in the row's `engine.scope` so the runner selects it when one of them
|
|
9
|
-
changes." There is no `graded` override for the same reason `COV-003` and
|
|
10
|
-
`PIP-001` have none: nothing here is answered by iterating the given set.
|
|
11
|
-
|
|
12
|
-
Two tiers, ported as two distinct behaviours because the shell script itself
|
|
13
|
-
keeps them apart:
|
|
14
|
-
|
|
15
|
-
VERREL-INPUT the shell's own bare `fail()` calls — VERSION missing, empty,
|
|
16
|
-
or not `x.y.z`; CHANGELOG.md missing or carrying no readable
|
|
17
|
-
latest-release heading; a versioned manifest missing or
|
|
18
|
-
carrying no readable version field. Each is a HARD STOP in
|
|
19
|
-
`check.sh`: it calls `fail`, which prints to stderr and does
|
|
20
|
-
`exit 1` directly, WITHOUT ever calling `report_finding` —
|
|
21
|
-
so at most one such condition is ever surfaced per run, and
|
|
22
|
-
the script never reaches the alignment checks below it once
|
|
23
|
-
one has fired. This port matches that: every branch below
|
|
24
|
-
yields at most one `VERREL-INPUT` finding and returns. No
|
|
25
|
-
shell rule id exists for this tier; `VERREL-INPUT` is invented
|
|
26
|
-
here the same way `COV-003`'s port invented `COVBASE-INPUT`
|
|
27
|
-
and `PIP-001`'s invented `PIPTR-INPUT`, both for shell scripts
|
|
28
|
-
that only ever wrote ad hoc prose to stderr on this same kind
|
|
29
|
-
of precondition failure.
|
|
30
|
-
|
|
31
|
-
VER-001 the shell's own `report_finding VER-001 ...` calls — a
|
|
32
|
-
manifest's or CHANGELOG.md's version does not match VERSION's.
|
|
33
|
-
ACCUMULATING, exactly as the shell script's `for` loop and
|
|
34
|
-
trailing CHANGELOG.md comparison never stop after the first
|
|
35
|
-
mismatch: every versioned file is graded independently, and
|
|
36
|
-
the CHANGELOG.md comparison always runs afterward regardless
|
|
37
|
-
of what the loop found.
|
|
38
|
-
|
|
39
|
-
`read_toml_version`'s case-statement arm (`check.sh`'s `case "$file" in
|
|
40
|
-
*.json) ...;; *) toml;; esac`) is ported as `_TOML_VERSION` even though both of
|
|
41
|
-
today's `VERSIONED_FILES` entries are `.json` and never reach it — the shell
|
|
42
|
-
dispatches on each entry's own suffix, not on a fixed list of json-only names,
|
|
43
|
-
so a future `.toml` entry would already be handled correctly by this port too.
|
|
44
|
-
"""
|
|
45
|
-
|
|
46
|
-
from __future__ import annotations
|
|
47
|
-
|
|
48
|
-
import re
|
|
49
|
-
from collections.abc import Iterable
|
|
50
|
-
from typing import ClassVar
|
|
51
|
-
|
|
52
|
-
from ....core.check import Check
|
|
53
|
-
from ....core.context import Context
|
|
54
|
-
from ....core.finding import Report
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
class VersionRelease(Check):
|
|
58
|
-
id: ClassVar[str] = "REL-004"
|
|
59
|
-
rule: ClassVar[str] = "VER-001"
|
|
60
|
-
|
|
61
|
-
INPUT: ClassVar[str] = "VERREL-INPUT"
|
|
62
|
-
|
|
63
|
-
# check.sh's own `versioned_files` array, verbatim order: changesets
|
|
64
|
-
# first, then the workflow root manifest. Fixed 2026-09-15 (K-42 sweep):
|
|
65
|
-
# these were hardcoded `.workflows/...` literals read directly via
|
|
66
|
-
# `self.text(ctx, relative)`, bypassing `ctx.inputs`/tree resolution
|
|
67
|
-
# entirely — a repository declaring `workflows` away from its packaged
|
|
68
|
-
# default got both manifests reported as flatly missing (LOUD, but
|
|
69
|
-
# against the wrong path).
|
|
70
|
-
inputs: ClassVar[dict[str, str]] = {
|
|
71
|
-
"changesets_package": "<workflows>/changesets/package.json",
|
|
72
|
-
"workflows_package": "<workflows>/package.json",
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
_SEMVER: ClassVar[re.Pattern[str]] = re.compile(r"^[0-9]+\.[0-9]+\.[0-9]+$")
|
|
76
|
-
# `read_json_version`'s sed: leading whitespace tolerated before the key.
|
|
77
|
-
_JSON_VERSION: ClassVar[re.Pattern[str]] = re.compile(r'^\s*"version"\s*:\s*"([^"]*)".*$')
|
|
78
|
-
# `read_toml_version`'s sed: no leading whitespace tolerated at all.
|
|
79
|
-
_TOML_VERSION: ClassVar[re.Pattern[str]] = re.compile(r'^version = "([^"]*)".*$')
|
|
80
|
-
# `tr -d '[:space:]'`'s POSIX class, spelled out rather than Python's wider
|
|
81
|
-
# (Unicode-including) `\s`.
|
|
82
|
-
_POSIX_SPACE: ClassVar[re.Pattern[str]] = re.compile(r"[ \t\n\r\v\f]")
|
|
83
|
-
_UNRELEASED_BRACKET: ClassVar[re.Pattern[str]] = re.compile(r"^## \[Unreleased\]")
|
|
84
|
-
|
|
85
|
-
def structural(self, ctx: Context) -> Iterable[Report]:
|
|
86
|
-
version_body = self.text(ctx, "VERSION")
|
|
87
|
-
if version_body is None:
|
|
88
|
-
yield self._input(
|
|
89
|
-
"VERSION", "VERSION is missing",
|
|
90
|
-
"create a VERSION file at the repository root holding the "
|
|
91
|
-
"canonical semantic version",
|
|
92
|
-
)
|
|
93
|
-
return
|
|
94
|
-
|
|
95
|
-
canonical_version = self._POSIX_SPACE.sub("", version_body)
|
|
96
|
-
if not canonical_version:
|
|
97
|
-
yield self._input(
|
|
98
|
-
"VERSION", "VERSION is empty",
|
|
99
|
-
"write the canonical semantic version into VERSION",
|
|
100
|
-
)
|
|
101
|
-
return
|
|
102
|
-
if not self._SEMVER.match(canonical_version):
|
|
103
|
-
yield self._input(
|
|
104
|
-
"VERSION", f"VERSION is not semantic x.y.z: {canonical_version}",
|
|
105
|
-
f"rewrite VERSION to hold a semantic x.y.z version instead of "
|
|
106
|
-
f"'{canonical_version}'",
|
|
107
|
-
)
|
|
108
|
-
return
|
|
109
|
-
|
|
110
|
-
changelog_body = self.text(ctx, "CHANGELOG.md")
|
|
111
|
-
if changelog_body is None:
|
|
112
|
-
yield self._input(
|
|
113
|
-
"CHANGELOG.md", "CHANGELOG.md is missing",
|
|
114
|
-
"create CHANGELOG.md recording the release history",
|
|
115
|
-
)
|
|
116
|
-
return
|
|
117
|
-
|
|
118
|
-
changelog_version = self._latest_changelog_version(changelog_body)
|
|
119
|
-
if not changelog_version:
|
|
120
|
-
yield self._input(
|
|
121
|
-
"CHANGELOG.md",
|
|
122
|
-
"unable to read latest CHANGELOG.md release version",
|
|
123
|
-
"add a release heading to CHANGELOG.md (## x.y.z or "
|
|
124
|
-
"## [x.y.z]) naming the current release",
|
|
125
|
-
)
|
|
126
|
-
return
|
|
127
|
-
|
|
128
|
-
for name in ("changesets_package", "workflows_package"):
|
|
129
|
-
path = ctx.inputs[name]
|
|
130
|
-
relative = ctx.relative(path)
|
|
131
|
-
body = self.text(ctx, path)
|
|
132
|
-
if body is None:
|
|
133
|
-
yield self._input(
|
|
134
|
-
relative, f"{relative} is missing",
|
|
135
|
-
f"create {relative} declaring a version field",
|
|
136
|
-
)
|
|
137
|
-
return
|
|
138
|
-
file_version = self._file_version(relative, body)
|
|
139
|
-
if not file_version:
|
|
140
|
-
yield self._input(
|
|
141
|
-
relative, f"unable to read version from {relative}",
|
|
142
|
-
f"add a version field to {relative}",
|
|
143
|
-
)
|
|
144
|
-
return
|
|
145
|
-
if file_version != canonical_version:
|
|
146
|
-
yield self.report(
|
|
147
|
-
relative,
|
|
148
|
-
f"{relative} has version {file_version}, expected "
|
|
149
|
-
f"{canonical_version} (from VERSION)",
|
|
150
|
-
f"update {relative}'s version field to {canonical_version}",
|
|
151
|
-
)
|
|
152
|
-
|
|
153
|
-
if changelog_version != canonical_version:
|
|
154
|
-
yield self.report(
|
|
155
|
-
"CHANGELOG.md",
|
|
156
|
-
f"CHANGELOG.md's latest release heading is {changelog_version}, "
|
|
157
|
-
f"expected {canonical_version} (from VERSION)",
|
|
158
|
-
f"add or rename CHANGELOG.md's latest release heading to "
|
|
159
|
-
f"## {canonical_version}",
|
|
160
|
-
)
|
|
161
|
-
|
|
162
|
-
# ------------------------------------------------------------- hard stops
|
|
163
|
-
|
|
164
|
-
def _input(self, path: str, message: str, fix: str) -> Report:
|
|
165
|
-
return self.report(path, message, fix, rule=self.INPUT)
|
|
166
|
-
|
|
167
|
-
# ------------------------------------------------------------- reading
|
|
168
|
-
|
|
169
|
-
def _file_version(self, relative: str, body: str) -> str | None:
|
|
170
|
-
pattern = self._JSON_VERSION if relative.endswith(".json") else self._TOML_VERSION
|
|
171
|
-
for line in body.splitlines():
|
|
172
|
-
match = pattern.match(line)
|
|
173
|
-
if match is not None:
|
|
174
|
-
return match.group(1)
|
|
175
|
-
return None
|
|
176
|
-
|
|
177
|
-
def _latest_changelog_version(self, body: str) -> str | None:
|
|
178
|
-
"""awk's one-pass scan: the FIRST `## ` heading that is not the
|
|
179
|
-
Unreleased section, stripped of its `## [`/`]…`/`## ` wrapping —
|
|
180
|
-
in that fixed order, so a bracketed and a bare heading both resolve to
|
|
181
|
-
the bare version text."""
|
|
182
|
-
for line in body.splitlines():
|
|
183
|
-
if not line.startswith("## "):
|
|
184
|
-
continue
|
|
185
|
-
if self._UNRELEASED_BRACKET.match(line):
|
|
186
|
-
continue
|
|
187
|
-
if line == "## Unreleased":
|
|
188
|
-
continue
|
|
189
|
-
return self._strip_heading(line)
|
|
190
|
-
return None
|
|
191
|
-
|
|
192
|
-
@staticmethod
|
|
193
|
-
def _strip_heading(line: str) -> str:
|
|
194
|
-
text = line
|
|
195
|
-
if text.startswith("## ["):
|
|
196
|
-
text = text[4:]
|
|
197
|
-
end = text.find("]")
|
|
198
|
-
if end != -1:
|
|
199
|
-
text = text[:end]
|
|
200
|
-
if text.startswith("## "):
|
|
201
|
-
text = text[3:]
|
|
202
|
-
return text
|