Skip to content

Commit 1342fd7

Browse files
authored
Merge pull request #57 from AI-agent-assembly/v0.0.1/AAASM-1219/test/verify_f112
[AAASM-1219] ✅ (test): Verify F112 platform wheel + Trusted Publisher acceptance
2 parents 594dbd9 + 034a663 commit 1342fd7

1 file changed

Lines changed: 134 additions & 0 deletions

File tree

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
# F112 — Python SDK platform wheel distribution
2+
3+
> Story: [AAASM-1202](https://lightning-dust-mite.atlassian.net/browse/AAASM-1202)
4+
> Epic: [AAASM-1199](https://lightning-dust-mite.atlassian.net/browse/AAASM-1199)
5+
> Verification sub-ticket: [AAASM-1219](https://lightning-dust-mite.atlassian.net/browse/AAASM-1219)
6+
> Verified on: 2026-05-23
7+
8+
## Sub-ticket map → PRs
9+
10+
| Sub-ticket | Scope | PR |
11+
| --- | --- | --- |
12+
| [AAASM-1215](https://lightning-dust-mite.atlassian.net/browse/AAASM-1215) | Configure maturin build backend | #53 |
13+
| [AAASM-1216](https://lightning-dust-mite.atlassian.net/browse/AAASM-1216) | Redesign pyproject.toml extras + dependency-groups | #54 |
14+
| [AAASM-1217](https://lightning-dust-mite.atlassian.net/browse/AAASM-1217) | Matrix wheel build + PyPI Trusted Publisher workflow | #55 |
15+
| [AAASM-1218](https://lightning-dust-mite.atlassian.net/browse/AAASM-1218) | `ensure_runtime()` fallback in `_install.py` | #56 |
16+
17+
Per-AC verification below.
18+
19+
## AC1 — maturin configured in python-sdk with correct build targets (AAASM-1215, PR #53)
20+
21+
**Status: ✅ Pass**
22+
23+
| Check | Result |
24+
| --- | --- |
25+
| `[build-system].build-backend == "maturin"` | ✅ Verified — `python -c "import tomllib; print(tomllib.loads(open('pyproject.toml').read())['build-system']['build-backend'])"` returns `maturin` |
26+
| `[build-system].requires` contains `maturin>=1.7,<2` ||
27+
| `[tool.maturin].manifest-path == "rust/aa-ffi-python/Cargo.toml"` | ✅ Points at the existing PyO3 binding crate |
28+
| `[tool.maturin].module-name == "agent_assembly._core"` | ✅ Matches `#[pyclass(module = "agent_assembly._core")]` in `rust/aa-ffi-python/src/lib.rs` |
29+
| `[tool.maturin].include` bundles `agent_assembly/bin/aasm` into wheel | ✅ With `format = "wheel"` so the file appears only in the platform wheel, not in sdist |
30+
| `[tool.hatch.build.targets.*]` removed | ✅ — no orphaned hatchling config |
31+
32+
**Caveats**
33+
34+
* End-to-end `maturin build --release` execution is deferred to CI (AAASM-1217) — local execution requires the upstream `aa-core` / `aa-proto` crates which the rust binding fetches from `AI-agent-assembly/agent-assembly`.
35+
* Per memory: pyo3 0.20 on a Python 3.13 venv needs `PYO3_USE_ABI3_FORWARD_COMPATIBILITY=1`; the CI matrix pins `${{ env.PYTHON_VERSION }} = '3.12'` to sidestep this.
36+
37+
## AC2 — pyproject extras + dependency-groups split (AAASM-1216, PR #54)
38+
39+
**Status: ✅ Pass**
40+
41+
| Check | Result |
42+
| --- | --- |
43+
| `[project.optional-dependencies].runtime == []` | ✅ Empty marker extra — selection happens by platform wheel tag, not deps |
44+
| `[project.optional-dependencies].all == ["agent-assembly[runtime]"]` | ✅ Self-reference aggregator |
45+
| `[dependency-groups].lint` contains ruff + mypy ||
46+
| `[dependency-groups].test` contains pytest + pytest-cov + pytest-rerunfailures + pytest-asyncio + pytest-benchmark ||
47+
| `[dependency-groups].dev` slimmed via `{include-group = "lint"}` + `{include-group = "test"}` | ✅ No duplication of literals |
48+
| `[dependency-groups].pre-commit-ci` sources mypy via `{include-group = "lint"}` ||
49+
| `uv lock --check` after restructure | ✅ 84 packages resolved, lock in sync |
50+
| `uv sync --group dev --dry-run` | ✅ resolves cleanly |
51+
| `uv sync --group lint --dry-run` | ✅ resolves cleanly |
52+
| `uv sync --group test --dry-run` | ✅ resolves cleanly |
53+
54+
**Caveats**
55+
56+
* Project name is `agent-assembly` (not `agent-assembly-python` as the Story description references); the `all` extra correctly uses the actual package name.
57+
58+
## AC3 — release-python.yml: matrix build + PyPI Trusted Publisher (AAASM-1217, PR #55)
59+
60+
**Status: ✅ Pass (structure) / ⏳ Deferred to CI (E2E execution)**
61+
62+
| Check | Result |
63+
| --- | --- |
64+
| Workflow triggers on `v*.*.*` tag push ||
65+
| Workflow has `workflow_dispatch` for dry-run | ✅ with `dry-run: true` default input |
66+
| Top-level `permissions: id-token: write` set | ✅ Required for PyPI Trusted Publisher OIDC |
67+
| 5 build jobs present |`build-sdist`, `build-linux-x86_64`, `build-linux-aarch64`, `build-macos-arm64`, `build-macos-x86_64` |
68+
| Per-job: download `aasm` binary before maturin build | ✅ Each platform job uses `gh release download` against `AI-agent-assembly/agent-assembly` |
69+
| Each platform job uses `PyO3/maturin-action@v1` with platform target ||
70+
| `publish` job has `needs:` listing all 5 build jobs | ✅ Verified via `assert set(d['jobs']['publish']['needs']) == {...}` |
71+
| `publish` job is gated `if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')` ||
72+
| `publish` step uses `pypa/gh-action-pypi-publish@release/v1` with no `password:` | ✅ Trusted Publisher OIDC, no stored token |
73+
| `publish.environment.name == 'pypi'` | ✅ For Trusted Publisher registration matching |
74+
| Untrusted-input safety: no `${{ github.event.* }}` interpolated into any `run:` shell | ✅ Repo name flows only via workflow-level `env:` |
75+
76+
**One-time setup required outside the PR** (documented in PR #55's body):
77+
78+
1. Register Trusted Publisher at https://pypi.org/manage/account/publishing/ for project `agent-assembly` referencing `AI-agent-assembly/python-sdk`, workflow `release-python.yml`, environment `pypi`.
79+
2. Create GitHub Environment `pypi` in the repo settings.
80+
81+
**CI-only verifications** (cannot run locally — owned by the CI matrix runners):
82+
83+
* Actual `maturin build --release` per platform with `aasm` binary staged.
84+
* Wheel platform tags inspected post-build (`manylinux_*`, `macosx_*`, not `none-any` except for sdist).
85+
* Trusted Publisher OIDC handshake on dry-run via `workflow_dispatch` once the PyPI registration is in place.
86+
87+
## AC4 — `ensure_runtime()` install-time fallback (AAASM-1218, PR #56)
88+
89+
**Status: ✅ Pass**
90+
91+
| Check | Result |
92+
| --- | --- |
93+
| Module `agent_assembly/_install.py` exists ||
94+
| `BINARY_NAME == "aasm"` ||
95+
| `WHEEL_BUNDLED_BIN` resolves to `agent_assembly/bin/aasm` | ✅ — `Path(__file__).resolve().parent / "bin" / BINARY_NAME` |
96+
| `INSTALL_HINT` lists pip [runtime], Homebrew tap, curl installer ||
97+
| `ensure_runtime()` returns `shutil.which` match when on PATH | ✅ Test `test_ensure_runtime_returns_path_match_first` |
98+
| `ensure_runtime()` returns `WHEEL_BUNDLED_BIN` when not on PATH but file present | ✅ Test `test_ensure_runtime_falls_back_to_wheel_bundled` |
99+
| `ensure_runtime()` raises `RuntimeError(INSTALL_HINT)` when neither found | ✅ Test `test_ensure_runtime_raises_with_install_hint` |
100+
| Lazy-imports compatibility (PEP 562 in `__init__.py`) preserved | ✅ Module is not added to `_LAZY_EXPORTS` — kept as direct-import `from agent_assembly._install import ensure_runtime` |
101+
| Full SDK pytest suite | ✅ 380 passed, 11 skipped (pre-existing env-conditional skips) |
102+
103+
**Caveats**
104+
105+
* `_install.ensure_runtime()` is distinct from `runtime.find_aasm_binary()` — the former is a synchronous presence check, the latter manages full lifecycle (port probe + subprocess spawn). Both observe the same `agent_assembly/bin/aasm` wheel-bundled location.
106+
* Known collision risk: `[project.scripts] aasm = "agent_assembly.cli.main:main"` creates a Python entry-point at `.venv/bin/aasm` that would shadow the Rust sidecar on PATH. Tracked as out-of-scope for F112; needs a follow-up to rename one of them (likely the Python CLI → `aasm-py`).
107+
108+
## CI-only smoke-test plan (post-merge)
109+
110+
These exercises run only after PRs #53..#56 land on master and the PyPI Trusted Publisher / GitHub Environment registration is in place.
111+
112+
1. **Dry-run `workflow_dispatch` on master** of `release-python.yml` with `dry-run: true`.
113+
- Confirm all 5 build jobs produce wheels (sdist `.tar.gz` + 4 platform `.whl`).
114+
- Confirm `publish` job is skipped (because `github.event_name == 'workflow_dispatch'`, not `push`).
115+
2. **Cut a pre-release tag** `v0.0.1-rc1` and push.
116+
- Confirm the `publish` job runs and the OIDC token exchange with PyPI succeeds.
117+
- Confirm wheels appear on PyPI (or TestPyPI if the workflow is wired to test index first).
118+
3. **Sample installations** on each target platform:
119+
- `pip install agent-assembly==0.0.1rc1` — SDK-only, no `agent_assembly/bin/aasm` in site-packages.
120+
- `pip install 'agent-assembly[runtime]'==0.0.1rc1` on Linux x86_64 — wheel includes Linux binary.
121+
- `pip install 'agent-assembly[runtime]'==0.0.1rc1` on macOS arm64 — wheel includes mac arm64 binary.
122+
4. **`ensure_runtime()` end-to-end** inside each install:
123+
- `python -c "from agent_assembly._install import ensure_runtime; print(ensure_runtime())"` returns the bundled binary path with the `[runtime]` install; raises `RuntimeError` with the install hint without it.
124+
125+
## Final F112 sign-off
126+
127+
| Sub-ticket | Static structural verification | E2E / smoke (deferred to CI) |
128+
| --- | --- | --- |
129+
| AAASM-1215 || Covered by step 1 above |
130+
| AAASM-1216 || Covered by steps 3–4 above |
131+
| AAASM-1217 || Covered by steps 1–2 above |
132+
| AAASM-1218 | ✅ (unit-tested) | Covered by step 4 above |
133+
134+
All acceptance criteria pass for the parts that can be verified statically and via local unit tests. The remaining smoke-test items are scoped to CI under the post-merge plan above.

0 commit comments

Comments
 (0)