diff --git a/.github/workflows/pr-title-lint.yml b/.github/workflows/pr-title-lint.yml index 5f63d4d9b..d2ba7b1ae 100644 --- a/.github/workflows/pr-title-lint.yml +++ b/.github/workflows/pr-title-lint.yml @@ -7,11 +7,16 @@ name: PR Title Lint # # The PR title is untrusted event data, so it is read from $GITHUB_EVENT_PATH # by the checker (never shell-interpolated), the token is read-only, and this -# uses `pull_request` (never `pull_request_target`). There is no exemption for -# PRs targeting `dev`. +# uses `pull_request` (never `pull_request_target`). +# +# Scoped to PRs targeting `dev` (feature PRs). On a squash-merged feature PR the +# conventional title becomes the commit release-please reads, so it is enforced +# there. `dev`->`main` promotion PRs are not squashed and their title never +# becomes a release commit, so linting them is noise (#684). on: pull_request: types: [opened, edited, synchronize, reopened] + branches: [dev] permissions: contents: read diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml index daf17a642..638c6e304 100644 --- a/.github/workflows/release-please.yml +++ b/.github/workflows/release-please.yml @@ -99,3 +99,35 @@ jobs: GH_TOKEN: ${{ github.token }} TAG: ${{ needs.release-please.outputs.tag_name }} run: gh release upload "${TAG}" dist/* --clobber + + # After a release is cut, the version bump + CHANGELOG land on `main`, so `dev` + # falls one release commit behind. Open a back-merge PR so `dev` is resynced. + # `main` is ahead of `dev` only by the release commit (a fast-forward). This + # job cannot auto-merge it: `dev` requires status checks that a bot-opened PR + # does not trigger, and repo auto-merge is off — merge it yourself (admin + # override; enforce_admins is false). + sync-dev: + needs: release-please + if: needs.release-please.outputs.release_created == 'true' + runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: write + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + fetch-depth: 0 + - name: Open the back-merge PR (main -> dev) + env: + GH_TOKEN: ${{ github.token }} + TAG: ${{ needs.release-please.outputs.tag_name }} + run: | + set -euo pipefail + existing="$(gh pr list --repo "${GITHUB_REPOSITORY}" --base dev --head main --state open --json number --jq '.[].number')" + if [ -n "${existing}" ]; then + echo "back-merge PR main->dev already open (#${existing}); nothing to do" + exit 0 + fi + gh pr create --repo "${GITHUB_REPOSITORY}" --base dev --head main \ + --title "chore: back-merge ${TAG} into dev" \ + --body "Automated back-merge of the ${TAG} release commit (version bump + CHANGELOG) from \`main\` into \`dev\`, so \`dev\` stays in sync. \`main\` is ahead of \`dev\` only by the release commit (fast-forward). \`dev\`'s required checks do not run on this bot-opened PR — merge it directly (admin)." diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 5e39b9417..19ee807a9 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.18.0" + ".": "0.19.0" } diff --git a/CHANGELOG.md b/CHANGELOG.md index e81b4858f..2e3f621c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,81 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 PRs do **not** edit this file directly. release-please maintains it from the Conventional Commit history on `main` (#684). +## [0.19.0](https://github.com/Brad-Edwards/aces/compare/v0.18.0...v0.19.0) (2026-07-06) + + +### Features + +* add ADR amendment policy and acceptance-content pin gate (GOV-941) ([8c58ab5](https://github.com/Brad-Edwards/aces/commit/8c58ab5d34129da32573845ff5a31d7569d20b00)) +* add authored evidence requirements ([b41584b](https://github.com/Brad-Edwards/aces/commit/b41584be704c3dea9062e10cdfe99275c8462cdf)) +* add behavior specifications to SDL ([039b019](https://github.com/Brad-Edwards/aces/commit/039b0197b896803fa4c4d70a49eaf650080148af)) +* add dns runtime inventory ([2f61056](https://github.com/Brad-Edwards/aces/commit/2f6105631e69444467d2aaa9dfd5aef0e4a47cb8)) +* add explicitness classifier semantics ([26a22da](https://github.com/Brad-Edwards/aces/commit/26a22da9c7ce9eaff571296ac1578f36c07adf11)) +* add libvirt participant runtime for the paper scenario ([554a139](https://github.com/Brad-Edwards/aces/commit/554a139fb62b4873ffea8141051520ef800df2cc)) +* add libvirt provisioning backend ([7da3293](https://github.com/Brad-Edwards/aces/commit/7da329364620a31f543fec77c8b2fdf62130d8dd)) +* add operational apparatus summary ([b26876c](https://github.com/Brad-Edwards/aces/commit/b26876c401667ec5ba96b4de5d72521a55989fa8)) +* add participant concurrency runtime contracts ([9827df8](https://github.com/Brad-Edwards/aces/commit/9827df8aad84c94c8d8f53825672e8a651adb421)) +* add repository-owned reference processor (RUN-313) ([106122b](https://github.com/Brad-Edwards/aces/commit/106122b7589f673ca57fa1d9bd35f51c65c23161)) +* add scenario-level forwarding agents ([a7467df](https://github.com/Brad-Edwards/aces/commit/a7467df3b2366c8d4d6f5f044ab7623c27830081)) +* add scenario-native observability coverage ([3e9f5db](https://github.com/Brad-Edwards/aces/commit/3e9f5dbbf65c70ad4ac88da8e6f852629c3fb4e4)) +* bind participant implementations to runtime actions ([d28d314](https://github.com/Brad-Edwards/aces/commit/d28d3140d78b9ce1115ed3e946f5eb81e0c0c3c4)) +* **corpus:** add paper demonstration corpus with cross-backend invariant ledger ([ce1bc07](https://github.com/Brad-Edwards/aces/commit/ce1bc07ab8bb80e7afaf6c304ac69f4a2e5dd8ec)) +* define SEM-216 boundary semantics for state, evidence, evaluation, analysis, and views ([2c72e7f](https://github.com/Brad-Edwards/aces/commit/2c72e7f600f7a20f205b45754747934c4f6de438)) +* **DSL-132,DSL-133:** add datastore_services and platform_applications spines ([aaef653](https://github.com/Brad-Edwards/aces/commit/aaef6530d56ae02e929ec98c275139b82a0ebf04)) +* **DSL-134,DSL-135:** add app_authorization and scheduled_jobs runtime families ([4d02197](https://github.com/Brad-Edwards/aces/commit/4d02197de616cc58fc50af44400b85551db79c7a)) +* **DSL-136,DSL-137:** add forwarding_agents and orchestration_authorities families ([b9f9f12](https://github.com/Brad-Edwards/aces/commit/b9f9f123318e8afe461195d0b11392871deb7dc1)) +* **DSL-138:** add typed runtime relationship subtypes + route upstream_target ([4e0f631](https://github.com/Brad-Edwards/aces/commit/4e0f631af89676c0212dcaa2d711c54bb27e04e7)) +* emit SEM-218 realization requirements and gate the planner on backend support ([38f925f](https://github.com/Brad-Edwards/aces/commit/38f925f2dde5cab96320139de7199e956d475321)) +* implement SEM-224 observability plane separation semantics ([eba8724](https://github.com/Brad-Edwards/aces/commit/eba87241b4c02bbc4b5a5c86f9b71010bccafa04)) +* **libvirt:** typed capability diagnostics for out-of-envelope plan terms ([7b298e9](https://github.com/Brad-Edwards/aces/commit/7b298e90e7a79a50bae34b42a2d2d0c318a29756)) +* **libvirt:** typed capability diagnostics for out-of-envelope plan terms ([1db2597](https://github.com/Brad-Edwards/aces/commit/1db2597c09494664aa656ab0a4be307b1ae9ca76)) +* realize plan resources on libvirt (domains, networks, placements) ([72b87e0](https://github.com/Brad-Edwards/aces/commit/72b87e07f2ac04fbd144110f0c3d13b9793fd7e9)) +* register API-406 backend carrier contracts ([59cfd43](https://github.com/Brad-Edwards/aces/commit/59cfd43a4275f4e41234f901a85895f522966c69)) +* **runtime:** add shared operational state snapshots ([29ca38c](https://github.com/Brad-Edwards/aces/commit/29ca38c70081b25b430717ea9984752c6987f848)) +* **runtime:** add shared operational state snapshots ([5ca2c2b](https://github.com/Brad-Edwards/aces/commit/5ca2c2b969812a0c38bc283a7f4d506591c99047)) +* ship contract corpus as package data and add a versioned release line ([8c0ddd8](https://github.com/Brad-Edwards/aces/commit/8c0ddd89809ac6332ff318fa7fd73c93ed46d209)) + + +### Bug Fixes + +* backfill schema-publication ledger entries to unblock dev->main ([27c2fb0](https://github.com/Brad-Edwards/aces/commit/27c2fb0c0b13d237f2d058b2afef62883bb4dedf)) +* clear SonarCloud new-code findings in the libvirt backend ([180715a](https://github.com/Brad-Edwards/aces/commit/180715a855c4e6c12c7fb5819d997db5a5050671)) +* consolidate runtime validation helpers ([bfab7e1](https://github.com/Brad-Edwards/aces/commit/bfab7e1e0709eda2b00318fc36564257a8de034a)) +* consolidate runtime validation helpers ([6958fed](https://github.com/Brad-Edwards/aces/commit/6958fed460067cd5a3b9c5dd6a4a2ca6cfd75aae)) +* **DSL-132:** tighten SCN-010 SDL validation closure ([d727d84](https://github.com/Brad-Edwards/aces/commit/d727d84a2b6f0365211cba6310044446e889cd98)) +* honor reconciliation and make libvirt backend teardown idempotent ([a2ccc81](https://github.com/Brad-Edwards/aces/commit/a2ccc8158b797f2181fc73bda5d85f7dc5429902)) +* preserve inventory target secrets ([26e5abb](https://github.com/Brad-Edwards/aces/commit/26e5abb2c80bdd10df1f4e2a4b7978380c633102)) +* **runtime:** clear shared-state sonar findings ([4d464c4](https://github.com/Brad-Edwards/aces/commit/4d464c466066e7eb8b579cb7577faee312c8e0dc)) +* **runtime:** simplify shared-state validators ([c19f282](https://github.com/Brad-Edwards/aces/commit/c19f282ff737a4c9b1292269e819c102a949cc45)) +* **sdl:** make local import lockfile resolved_source checkout-independent ([15b7121](https://github.com/Brad-Edwards/aces/commit/15b7121c7e6257b564e1c36ce0a9b723441c3899)) +* unify runtime service family registry ([ffe28e5](https://github.com/Brad-Edwards/aces/commit/ffe28e596840cc37d152f63880a889a7477a5911)) + + +### Documentation + +* accept participant ADR dependency chain ([cee0543](https://github.com/Brad-Edwards/aces/commit/cee05438a6c49295d5cfb7df81c7138817603f2c)) +* add CAGE-2 replication architecture ([7ad0276](https://github.com/Brad-Edwards/aces/commit/7ad0276003d88fc3673f3f4768d857580c124f16)) +* add participant runtime design ([bb087e9](https://github.com/Brad-Edwards/aces/commit/bb087e99dfb5d773e7a6f30f7d4db6c372ae5b85)) +* add proposed ADR-073 on scoring/reward language scope ([c8bbbad](https://github.com/Brad-Edwards/aces/commit/c8bbbad68c2d4bd8938918d9a70f98c7d62fe292)) +* add related-work comparison positioning ACES against precedent systems ([0fe9f1f](https://github.com/Brad-Edwards/aces/commit/0fe9f1fc39dce1ec8ec1c9478d96f7eb7ea49561)) +* add SDL module composition ADR ([22bbbdb](https://github.com/Brad-Edwards/aces/commit/22bbbdb5f76d4a5b09385ce428b7e420e209f899)) +* add validation admission profile design ([4df4e8e](https://github.com/Brad-Edwards/aces/commit/4df4e8e5c066bbbc1d2612b066fe1a8aff0393b1)) +* author the SDL prose specification under specs/sdl/ (CT-6) ([792c207](https://github.com/Brad-Edwards/aces/commit/792c207950211f25166139e7035a3509570b6f49)) +* define experiment replication and replay claims ([bed09cf](https://github.com/Brad-Edwards/aces/commit/bed09cf75b17bf52b19c8cdbcfaab3bd6db7bfb1)) +* document ACT-603 interaction guardrails ([0be0e79](https://github.com/Brad-Edwards/aces/commit/0be0e79c957a490e945cbe9fca09186d1a39140d)) +* document observability evidence plane separation ([9fd2b73](https://github.com/Brad-Edwards/aces/commit/9fd2b73f9a578b8270ac3921ca21cd87720fd7a9)) +* document realization envelope semantics ([bfe4515](https://github.com/Brad-Edwards/aces/commit/bfe4515b27ce6cf3bc09283be0c4a8e70f36a597)) +* **DSL-139:** backfill limitations.md family coverage + confirmation-folds doctrine ([eb49821](https://github.com/Brad-Edwards/aces/commit/eb49821b2546f56c9f8cd512ccd969624d1b55d5)) +* **experiment-core:** define replication and replay claims ([09d56df](https://github.com/Brad-Edwards/aces/commit/09d56dff861087cc74f87c46b49e3b25565faeeb)) +* reconcile asset inventory methodology closeout ([4a1fddb](https://github.com/Brad-Edwards/aces/commit/4a1fddbbbcaa0f3718f26363c3d011eaf8b97bba)) +* reconcile asset inventory methodology closeout ([ba18151](https://github.com/Brad-Edwards/aces/commit/ba18151b2a665bcc85eb4417915297ec7c6464f7)) +* record api-419 preflight guardrails ([b61eb02](https://github.com/Brad-Edwards/aces/commit/b61eb024a37be7114d3c5cce645ae9ce3c7ef1fb)) +* register gap remediation overlay ([ee74846](https://github.com/Brad-Edwards/aces/commit/ee74846a4210e3299f981b6c6bc54429b3ebf2b5)) +* **scn010:** add expressivity gap analysis and wire toctree ([0cdc927](https://github.com/Brad-Edwards/aces/commit/0cdc92791c40cd14c4bc3cdb97259f7fbf013ca6)) +* **security:** record 2026-07-01 commit authorship anomaly ([5eb8078](https://github.com/Brad-Edwards/aces/commit/5eb8078047a17890e819d8d5867c59acc79c8320)) +* **security:** record 2026-07-01 commit authorship anomaly ([b648c99](https://github.com/Brad-Edwards/aces/commit/b648c99e8716b634fa2b48ec3f0902734d0bd585)) +* tighten citation hygiene across SDL lineage and precedent docs ([0059d03](https://github.com/Brad-Edwards/aces/commit/0059d03af5c6280655eb41c07b8a094388b9f4e2)) + ## [0.18.0] - 2026-07-06 ### Security diff --git a/README.md b/README.md index a6a9aecee..8fd8bf04a 100644 --- a/README.md +++ b/README.md @@ -70,9 +70,9 @@ nodes: roles: {mail-admin: postfix} ``` -Complete examples live in [`examples/scenarios/`](examples/scenarios/). +Complete examples live in [`examples/scenarios/`](https://github.com/Brad-Edwards/aces/tree/main/examples/scenarios). Reusable non-normative templates and patterns are indexed by -[`examples/library/catalog.yaml`](examples/library/catalog.yaml). +[`examples/library/catalog.yaml`](https://github.com/Brad-Edwards/aces/blob/main/examples/library/catalog.yaml). ## Getting Started @@ -147,24 +147,24 @@ uv run aces-mcp For a dimension-by-dimension comparison against these systems — what ACES expresses that they do not, and where they still lead ACES — see -[Related-Work Comparison](docs/explain/sdl/related-work-comparison.md). +[Related-Work Comparison](https://github.com/Brad-Edwards/aces/blob/main/docs/explain/sdl/related-work-comparison.md). ## Documentation -The documentation source is under [`docs/`](docs/). Important entry points: - -- [`docs/index.md`](docs/index.md) - documentation index -- [`docs/explain/getting-started.md`](docs/explain/getting-started.md) - use-case and rigor-level entrypoint -- [`examples/README.md`](examples/README.md) - current worked example inventory -- [`examples/library/catalog.yaml`](examples/library/catalog.yaml) - template and pattern library catalog -- [`docs/explain/reference/canonical-reference-map.md`](docs/explain/reference/canonical-reference-map.md) - current reference map -- [`docs/explain/reference/documentation-style-guide.md`](docs/explain/reference/documentation-style-guide.md) - documentation style and citation rules -- [`docs/explain/reference/glossary.md`](docs/explain/reference/glossary.md) - current terminology -- [`docs/explain/sdl/index.md`](docs/explain/sdl/index.md) - SDL guide -- [`docs/explain/sdl/runtime-architecture.md`](docs/explain/sdl/runtime-architecture.md) - runtime architecture -- [`docs/explain/reference/backend-conformance.md`](docs/explain/reference/backend-conformance.md) - backend conformance model -- [`docs/decisions/adrs/README.md`](docs/decisions/adrs/README.md) - architecture decisions -- [`contracts/README.md`](contracts/README.md) - contract publication surface +The documentation source is under [`docs/`](https://github.com/Brad-Edwards/aces/tree/main/docs). Important entry points: + +- [`docs/index.md`](https://github.com/Brad-Edwards/aces/blob/main/docs/index.md) - documentation index +- [`docs/explain/getting-started.md`](https://github.com/Brad-Edwards/aces/blob/main/docs/explain/getting-started.md) - use-case and rigor-level entrypoint +- [`examples/README.md`](https://github.com/Brad-Edwards/aces/blob/main/examples/README.md) - current worked example inventory +- [`examples/library/catalog.yaml`](https://github.com/Brad-Edwards/aces/blob/main/examples/library/catalog.yaml) - template and pattern library catalog +- [`docs/explain/reference/canonical-reference-map.md`](https://github.com/Brad-Edwards/aces/blob/main/docs/explain/reference/canonical-reference-map.md) - current reference map +- [`docs/explain/reference/documentation-style-guide.md`](https://github.com/Brad-Edwards/aces/blob/main/docs/explain/reference/documentation-style-guide.md) - documentation style and citation rules +- [`docs/explain/reference/glossary.md`](https://github.com/Brad-Edwards/aces/blob/main/docs/explain/reference/glossary.md) - current terminology +- [`docs/explain/sdl/index.md`](https://github.com/Brad-Edwards/aces/blob/main/docs/explain/sdl/index.md) - SDL guide +- [`docs/explain/sdl/runtime-architecture.md`](https://github.com/Brad-Edwards/aces/blob/main/docs/explain/sdl/runtime-architecture.md) - runtime architecture +- [`docs/explain/reference/backend-conformance.md`](https://github.com/Brad-Edwards/aces/blob/main/docs/explain/reference/backend-conformance.md) - backend conformance model +- [`docs/decisions/adrs/README.md`](https://github.com/Brad-Edwards/aces/blob/main/docs/decisions/adrs/README.md) - architecture decisions +- [`contracts/README.md`](https://github.com/Brad-Edwards/aces/blob/main/contracts/README.md) - contract publication surface ## Verification @@ -183,7 +183,7 @@ including repository policy, generated artifact checks, tests, and docs. Contributions are welcome where they improve the language, reference implementation, contracts, tests, examples, or documentation. Start with -[CONTRIBUTING.md](CONTRIBUTING.md). +[CONTRIBUTING.md](https://github.com/Brad-Edwards/aces/blob/main/CONTRIBUTING.md). Language and contract changes should be discussed before implementation because small SDL changes can affect validation, generated schemas, backend @@ -192,9 +192,9 @@ conformance, and existing scenario examples. ## Versioning The Python package currently declares its version in -[`implementations/python/pyproject.toml`](implementations/python/pyproject.toml). +[`implementations/python/pyproject.toml`](https://github.com/Brad-Edwards/aces/blob/main/implementations/python/pyproject.toml). Release notes are collated from towncrier fragments in -[`changelog.d/`](changelog.d/). Do not hand-edit `CHANGELOG.md`. +[`changelog.d/`](https://github.com/Brad-Edwards/aces/tree/main/changelog.d). Do not hand-edit `CHANGELOG.md`. Published JSON Schemas use versioned contract identifiers such as `sdl-authoring-input-v1`, but the suffix is not the same as a stability promise. @@ -202,7 +202,7 @@ The authoritative schema publication manifest records each schema's `draft` or `stable` stability class and canonical content hash. Current checked-in schemas are draft until a maintainer explicitly promotes them; stable breaking changes must mint a new schema version as described in -[ADR-061](docs/decisions/adrs/adr-061-published-schema-evolution-policy.md). +[ADR-061](https://github.com/Brad-Edwards/aces/blob/main/docs/decisions/adrs/adr-061-published-schema-evolution-policy.md). ## Maintainers @@ -224,4 +224,4 @@ If you use ACES SDL in academic work, cite the repository: ## License -Released under the MIT License. See [LICENSE](LICENSE). +Released under the MIT License. See [LICENSE](https://github.com/Brad-Edwards/aces/blob/main/LICENSE). diff --git a/implementations/python/README.md b/implementations/python/README.md deleted file mode 100644 index ce85b4796..000000000 --- a/implementations/python/README.md +++ /dev/null @@ -1,17 +0,0 @@ -# Python Reference Implementation - -This directory contains the current Python reference implementation after the -monorepo reorganization. - -Current contents: - -- `packages/`: Python implementation packages split by concern -- `tests/`: Python implementation tests moved out of the repo root -- `pyproject.toml` and `uv.lock`: Python-local build and dependency files - -This directory is transitional. The code has been moved into the right buckets -first; imports, packaging, and other implementation details will be reconciled -in later passes. - -The intended order for that reconciliation work is captured in -[../../docs/decisions/adrs/adr-010-repository-realignment-order-and-compatibility-policy.md](../../docs/decisions/adrs/adr-010-repository-realignment-order-and-compatibility-policy.md). diff --git a/implementations/python/hatch_build.py b/implementations/python/hatch_build.py index 4c9a3301d..ac7499d33 100644 --- a/implementations/python/hatch_build.py +++ b/implementations/python/hatch_build.py @@ -1,23 +1,18 @@ -"""Hatchling build hook that bundles the published contract corpus (#537). - -The corpus is the ADR-009 normative authority at the repository-root -``contracts/`` tree, which lives *outside* this Python project directory. A -static ``force-include`` of ``../../contracts`` works when the wheel is built -directly from the source checkout, but breaks when the wheel is built from an -unpacked sdist — the ``../../contracts`` parent path is not present inside the -sdist, so ``uv build`` (which builds the wheel from the sdist) fails with -``Forced include not found``. - -This hook resolves the corpus from whichever layout is being built and -force-includes it into the wheel at ``aces_contracts/_corpus``: - -* **source checkout** — the corpus is the authority at ``/contracts``; -* **sdist** — the sdist target vendors the corpus at top-level ``_corpus/`` - (see ``[tool.hatch.build.targets.sdist.force-include]``), so a wheel built - from the sdist still finds it. - -The runtime resolver (``aces_contracts.corpus``) reads the bundled corpus via -``importlib.resources``; this hook only governs what lands in the wheel. +"""Hatchling hooks for the aces-sdl package (#537, #684). + +Two things this package needs live *outside* this Python project directory, at +the repository root, and are pulled in at build time: + +* the published contract corpus (``/contracts``) — bundled into the wheel + as package data by the build hook below; and +* the project ``README.md`` (``/README.md``) — injected as the PyPI long + description by the metadata hook below, so there is a single README source and + no duplicate copy under ``implementations/python``. + +Both reach ``../..`` in a source checkout and fall back to a copy vendored into +the sdist, so the ``uv build`` sdist→wheel path also resolves them: the sdist +force-includes ``../../contracts`` as ``_corpus/`` and ``../../README.md`` as +``README.md`` (see ``[tool.hatch.build.targets.sdist.force-include]``). """ from __future__ import annotations @@ -25,6 +20,7 @@ from pathlib import Path from hatchling.builders.hooks.plugin.interface import BuildHookInterface +from hatchling.metadata.plugin.interface import MetadataHookInterface _WHEEL_DESTINATION = "aces_contracts/_corpus" @@ -50,3 +46,37 @@ def initialize(self, version: str, build_data: dict) -> None: ) build_data.setdefault("force_include", {})[str(corpus)] = _WHEEL_DESTINATION + + +class ReadmeMetadataHook(MetadataHookInterface): + """Inject the repo-root README.md as the package's PyPI long description. + + The Python package lives in ``implementations/python`` but the canonical + README is at the repo root (the repo is spec-first; the root README covers + the whole project). Rather than maintain a duplicate package README, this + hook sets ``readme`` from the root README at build time; + ``[project] dynamic = ["readme"]`` delegates the field to it. + """ + + PLUGIN_NAME = "custom" + + def update(self, metadata: dict) -> None: + root = Path(self.root) + source_checkout_readme = (root.parent.parent / "README.md").resolve() + vendored_sdist_readme = (root / "README.md").resolve() + + if source_checkout_readme.is_file(): + readme = source_checkout_readme + elif vendored_sdist_readme.is_file(): + readme = vendored_sdist_readme + else: + raise FileNotFoundError( + "project README not found for packaging: looked for " + f"{source_checkout_readme} (source checkout) and " + f"{vendored_sdist_readme} (sdist)." + ) + + metadata["readme"] = { + "content-type": "text/markdown", + "text": readme.read_text(encoding="utf-8"), + } diff --git a/implementations/python/pyproject.toml b/implementations/python/pyproject.toml index 402c51eaf..15fb4117a 100644 --- a/implementations/python/pyproject.toml +++ b/implementations/python/pyproject.toml @@ -4,8 +4,9 @@ build-backend = "hatchling.build" [project] name = "aces-sdl" -version = "0.18.0" +version = "0.19.0" description = "Backend-agnostic cyber range scenario description language and runtime." +dynamic = ["readme"] requires-python = ">=3.11" dependencies = [ "typer>=0.12.0", @@ -45,6 +46,12 @@ aces-mcp = "aces_mcp.server:main" # truth, rewritten by release-please on each release. Hatchling reads it directly; # `aces.__version__` derives from the installed distribution metadata. +# The PyPI long description (`readme`) is injected from the repo-root README.md by +# a custom metadata hook (hatch_build.py), so there is a single README source and +# no duplicate copy under implementations/python. `[project] dynamic = ["readme"]`. +[tool.hatch.metadata.hooks.custom] +path = "hatch_build.py" + [tool.hatch.build.targets.wheel] packages = [ "src/aces", @@ -78,6 +85,7 @@ path = "hatch_build.py" [tool.hatch.build.targets.sdist.force-include] "../../contracts" = "_corpus" +"../../README.md" = "README.md" [tool.pytest.ini_options] testpaths = ["tests"]