| id | R.3 | ||
|---|---|---|---|
| title | Beads Python Bindings | ||
| status | complete | ||
| branch | sprint/r-3-beads-python-bindings | ||
| target | integrate/phase-r | ||
| depends_on |
|
Deliver a dedicated Maturin/PyO3 package so Python extensions call the same
sc-composer-beads operations, request validation, authorization guard, and
receipts as Rust and the CLI.
R.3 may be developed in parallel with R.2 after R.1, but it cannot close until R.2's CLI JSON contract is available for the required cross-surface conformance fixture.
Cargo.tomlbindings/sc-composer-beads-python/Cargo.tomlbindings/sc-composer-beads-python/pyproject.tomlbindings/sc-composer-beads-python/src/lib.rsbindings/sc-composer-beads-python/python/sc_composer_beads/{__init__.py,_native.pyi,py.typed}bindings/sc-composer-beads-python/tests/{test_smoke,test_contract}.pycrates/sc-composer-beads/tests/fixtures/beads/.github/workflows/ci.yml.github/scripts/release_artifacts.pyand its testsrelease/publish-artifacts.toml(including matchingcrates,python_packages, and[[python_distributions]]entries for the new package)release/sc-publish-install.json(including matchingcrates,python_packages, andpython_distributionsentries for the new package)
The distribution is sc-composer-beads; its import package is
sc_composer_beads. It offers a faithful, typed representation of the R.1
request/receipt contract plus the library operation and convenience methods:
def execute(request: BeadComposeRequest) -> BeadComposeReceipt: ...
def render(request: BeadComposeRequest) -> BeadComposeReceipt: ...
def validate(request: BeadComposeRequest) -> BeadComposeReceipt: ...
def preview_pour(request: BeadComposeRequest) -> BeadComposeReceipt: ...
def pour(request: BeadComposeRequest) -> BeadComposeReceipt: ...pour() requires the same explicit enum/sentinel in the request. The adapter
does not shell out to sc-compose, does not accept arbitrary commands, and
does not expose an authorization bypass. It releases the Python GIL while the
Rust crate waits for bd.
- Add the independent workspace/member package with
cdylibandrlib, PyO30.29, Maturin>=1.9.4,<2.0, Python>=3.11, typed package files, and a dependency only onsc-composer-beadsplus adapter dependencies. - Convert Python dictionaries/lists/scalars to and from the versioned Rust request/receipt types without reimplementing rendering or process logic. Conversion failures map to a crate-owned Python exception with the stable Rust error code and stage, never a raw Rust panic.
- Add installed-wheel smoke tests and contract tests. They load the canonical
crates/sc-composer-beads/tests/fixtures/beads/fixture directly and prove it yields equivalent Rust, CLI JSON, and Python receipts; normalize only documented absolute-path differences. R.1 owns updates to that fixture when the shared contract changes. - Extend CI to build and install wheels on Linux, macOS, and Windows, execute
the pinned-Beads integration fixture through the wheel, and run ordinary
workspace tests without requiring an extension-module feature for
cargo test. - Add this wheel as a separately named release artifact in both
release/publish-artifacts.tomlandrelease/sc-publish-install.json. Each manifest must contain acratesentry forsc-composer-beads, apython_packagesentry forsc-composer-beads-python, and a matching[[python_distributions]]/python_distributionsentry consumed by the release wheel and sdist matrices. The TOML entry must usename = "sc-composer-beads",source = "bindings/sc-composer-beads-python",cargo_manifest = "bindings/sc-composer-beads-python/Cargo.toml",module_path = "bindings/sc-composer-beads-python/python/sc_composer_beads",sdist = true, andwheels = ["ubuntu-latest", "macos-latest", "windows-latest"]; the JSON entry must carry the matching field values. Wire all three entries into the existing version verification path;verify-version-lockstepalone is not a substitute for matrix coverage. Package publication itself remains subject to the existing explicit release authorization workflow.
-
import sc_composer_beadsworks from an installed wheel on all three CI platforms, and.pyi/py.typedship in the wheel and sdist. - Python
validateandpreview_pourproduce the same stage outcomes and Beads argv evidence as the Rust library/CLI fixture, using theBeadStageReceipt,BeadOutcome, andBeadComposeErrordefinitions from ADR-0021 without Python-local variants. - Python cannot bypass
PourAuthorization::CreatePersistentBeads; tests prove refusal occurs before subprocess execution. - The binding package has no dependency on
sc-compose, the existingbindings/pythonpackage, ATM, or Beads source/database code. - Release metadata validates the new package's version lockstep without
changing the existing
sc-composePython package identity. The R.3 closeout must runverify-version-lockstepagainst the release manifest and workspace manifest. - Both release manifests contain a matching
[[python_distributions]]/python_distributionsentry namedsc-composer-beads; the Python wheel and sdist matrix commands each emit that distribution name.
cargo fmt --all --check
cargo clippy --workspace --all-targets --all-features -- -D warnings
cargo test --workspace
maturin build --manifest-path bindings/sc-composer-beads-python/Cargo.toml --out dist
python3 -m pytest -q bindings/sc-composer-beads-python/tests
python3 .github/scripts/release_artifacts.py validate-manifest --manifest release/publish-artifacts.toml --workspace-toml Cargo.toml
python3 .github/scripts/release_artifacts.py verify-version-lockstep --manifest release/publish-artifacts.toml --workspace-toml Cargo.toml
python3 .github/scripts/release_artifacts.py python-wheel-matrix --manifest release/publish-artifacts.toml | python3 -c 'import json,sys; names={entry["name"] for entry in json.load(sys.stdin)["include"]}; raise SystemExit("sc-composer-beads missing from wheel matrix") if "sc-composer-beads" not in names else None'
python3 .github/scripts/release_artifacts.py python-sdist-matrix --manifest release/publish-artifacts.toml | python3 -c 'import json,sys; names={entry["name"] for entry in json.load(sys.stdin)["include"]}; raise SystemExit("sc-composer-beads missing from sdist matrix") if "sc-composer-beads" not in names else None'
Also require git diff --check.
Validated on 2026-08-26 across the R.3 closing commit chain:
285c23cclosed the initial QA findings;0fc1d2brestored typed JSON conversion errors; and9e1bfa2completed the schema-valid boundary record.- CI run 32947283597
passed all 17 checks for
9e1bfa2, including the installed wheel matrix on Linux, macOS, and Windows. - Installed-wheel smoke and contract tests cover the canonical R.1/R.2
fixture, Python-to-CLI stage receipts, authorization refusal before process
execution, the pinned-
bdfixture, and wheel/sdist typing-marker contents. cargo fmt --all --check, workspace clippy, full workspace tests, Maturin wheel/sdist build/install tests, release-manifest validation, version lockstep, wheel and sdist matrix checks, andgit diff --checkpassed locally.
Combining this package with sc-compose, adding a Go binding, publishing a
wheel without the normal release gate, or a non-dry-run Beads creation test is
not part of R.3.