Skip to content

release(v2.2.0): Python surface re-exports — unblocks CIRISLens#18 §2 + #20 Reticulum-half - #92

Merged
emooreatx merged 2 commits into
mainfrom
edge-v2-2-0-python-surface
Jun 12, 2026
Merged

release(v2.2.0): Python surface re-exports — unblocks CIRISLens#18 §2 + #20 Reticulum-half#92
emooreatx merged 2 commits into
mainfrom
edge-v2-2-0-python-surface

Conversation

@emooreatx

Copy link
Copy Markdown
Contributor

The lens-core 1.0.1 cohabitation surface lands, but it can't construct Edge from Python because python/ciris_edge/__init__.py only re-exported SUPPORTED_SCHEMA_VERSIONS + __version__. The Rust crate + PyO3 bindings have been feature-complete since v2.1.0 (PyEdge + init_edge_runtime + transport_identity_pubkeys + engine all registered via #[pyclass] / #[pyfunction] in the pymodule), but the Python wrapper never surfaced them.

This is a pure Python-wrapper fix: re-export the symbols the cdylib already registers.

What ships

python/ciris_edge/__init__.py now re-exports the full Phase 1 lens-cutover surface:

from .ciris_edge import (
    SUPPORTED_SCHEMA_VERSIONS,
    DurableHandle,
    Edge,
    NetworkEventSubscription,
    ReplicationHandle,
    SubscriptionHandle,
    VerifiedFeedSubscription,
    __version__,
    init_edge_runtime,
)

Lens-core's CIRISLens#18 §2 + #20 Reticulum-half pattern works as documented:

import ciris_edge, ciris_persist as cp
engine = cp.Engine(dsn="postgres://lens:lens@localhost:5432/cirislens")
edge = ciris_edge.init_edge_runtime(engine=engine, ...)
pubkeys = edge.transport_identity_pubkeys()
install_relay(edge)  # lens-core 1.0.1's frozen hook

Naming consistency — PyReplicationHandle → ReplicationHandle

PyReplicationHandle shipped at v1.6.3 with no explicit #[pyclass(name = "...")] attribute, so its Python class name defaulted to the Rust struct name (PyReplicationHandle). The five other Edge-family pyclasses (Edge, DurableHandle, SubscriptionHandle, VerifiedFeedSubscription, NetworkEventSubscription) all carry #[pyclass(name = "X", module = "ciris_edge")] with the Py prefix stripped. ReplicationHandle joins the pattern.

Safe: PyReplicationHandle was never re-exported through __init__.py in any prior release, so no Python consumer can be referencing ciris_edge.PyReplicationHandle today. Rust struct name unchanged (internal callers + m.add_class::<PyReplicationHandle>() still work).

What's NOT in this cut

The pyo3 0.28 → 0.29 lockstep + persist v5.5.3 → v6.0.0 currency (originally planned as v2.2.0) is deferred. The upstream pyo3 ecosystem isn't ready:

  • pyo3-async-runtimes latest is 0.28.0 (PyO3/pyo3-async-runtimes#85 open for 0.29 bump, not merged)
  • pyo3-stub-gen latest is 0.22.3 (no 0.29 work started upstream)

Edge depends on both; can't move to pyo3 0.29 alone. Persist's ceiling-firewall (ciris-persist<6 in our pyproject) keeps edge 2.x from accidentally pulling persist 6.0.0 in the meantime — lens-core, agent, and edge stay coherent on the persist 5.x line until edge is g2g for pyo3 0.29.

When the ecosystem catches up, the lockstep cuts as v3.0.0 (or v2.3.0 if minor is sufficient) with pyo3 0.29 + persist 6.0.0 together, per the persist team's coordinated-publish handoff.

Substrate pin currency

  • ciris-persist: unchanged at v5.5.3
  • ciris-verify family: unchanged at v5.1.0
  • leviculum: unchanged at ded96ee

Verification

  • 255 lib tests green
  • cargo clippy --all-targets -- -D warnings clean
  • cargo fmt --check clean

Test plan

  • cargo test --lib --features transport-http,transport-reticulum,pyo3 green (255 tests)
  • cargo clippy --all-targets -- -D warnings clean
  • cargo fmt --check clean
  • Full CI gauntlet green on PR — including python/ciris_edge/__init__.py re-exports surviving the wheel build + from ciris_edge import Edge, init_edge_runtime round-trip on the cohabitation conformance cells

🤖 Generated with Claude Code

#20 Reticulum-half

The lens-core 1.0.1 cohabitation surface lands, but it can't construct
Edge from Python because `python/ciris_edge/__init__.py` only
re-exported `SUPPORTED_SCHEMA_VERSIONS + __version__`. The Rust crate
+ PyO3 bindings have been feature-complete since v2.1.0 (PyEdge +
init_edge_runtime + transport_identity_pubkeys + engine all registered
via #[pyclass] / #[pyfunction] in the pymodule), but the Python wrapper
never surfaced them.

This is a pure Python-wrapper fix: re-export the symbols the cdylib
already registers.

## What ships

`python/ciris_edge/__init__.py` now re-exports the full Phase 1 lens-
cutover surface:

```python
from .ciris_edge import (
    SUPPORTED_SCHEMA_VERSIONS,
    DurableHandle,
    Edge,
    NetworkEventSubscription,
    ReplicationHandle,
    SubscriptionHandle,
    VerifiedFeedSubscription,
    __version__,
    init_edge_runtime,
)
```

Lens-core's `CIRISLens#18 §2 + #20` Reticulum-half pattern works as
documented:

```python
import ciris_edge, ciris_persist as cp
engine = cp.Engine(dsn="postgres://lens:lens@localhost:5432/cirislens")
edge = ciris_edge.init_edge_runtime(engine=engine, ...)
pubkeys = edge.transport_identity_pubkeys()
install_relay(edge)  # lens-core 1.0.1's frozen hook
```

The docstring is updated with the full call shape; `__all__` carries
the same eight names.

## Naming consistency — PyReplicationHandle → ReplicationHandle

`PyReplicationHandle` shipped at v1.6.3 with no explicit
`#[pyclass(name = "...")]` attribute, so its Python class name
defaulted to the Rust struct name (`PyReplicationHandle`). The five
other Edge-family pyclasses (Edge, DurableHandle, SubscriptionHandle,
VerifiedFeedSubscription, NetworkEventSubscription) all carry
`#[pyclass(name = "X", module = "ciris_edge")]` with the `Py` prefix
stripped. ReplicationHandle joins the pattern.

Safe: PyReplicationHandle was never re-exported through __init__.py
in any prior release, so no Python consumer can be referencing
`ciris_edge.PyReplicationHandle` today. Rust struct name unchanged
(internal callers + `m.add_class::<PyReplicationHandle>()` still
work).

## What's NOT in this cut

The pyo3 0.28 → 0.29 lockstep + persist v5.5.3 → v6.0.0 currency
(originally planned as v2.2.0) is deferred. The upstream pyo3
ecosystem isn't ready:

- `pyo3-async-runtimes` latest is 0.28.0 (PyO3/pyo3-async-runtimes#85
  open for 0.29 bump, not merged)
- `pyo3-stub-gen` latest is 0.22.3 (no 0.29 work started upstream)

Edge depends on both; can't move to pyo3 0.29 alone. Persist's
ceiling-firewall (`ciris-persist<6` in our pyproject) keeps edge 2.x
from accidentally pulling persist 6.0.0 in the meantime — Lens-core,
agent, and edge stay coherent on the persist 5.x line until edge is
g2g for pyo3 0.29.

When the ecosystem catches up, the lockstep cuts as v3.0.0 (or
v2.3.0 if minor is sufficient) with pyo3 0.29 + persist 6.0.0
together, per the persist team's coordinated-publish handoff doc.

## Substrate pin currency

- `ciris-persist`: unchanged at v5.5.3
- `ciris-verify` family: unchanged at v5.1.0
- `leviculum`: unchanged at `ded96ee`

## Verification

- 255 lib tests green
- `cargo clippy --all-targets -- -D warnings` clean
- `cargo fmt --check` clean

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

`time v0.3.48` published 2026-06-12 added a generic `Into<String>`
impl that conflicts with `rcgen`'s blanket
`impl<T: Into<String>> From<T> for OtherNameValue` / `DnValue`. Every
edge PR (and downstream consumer) hits:

```
error[E0119]: conflicting implementations of trait
  `From<format_description::parse::format_item::HourBase>` for type
  `<HourBase as ModifierValue>::Type`
  --> rcgen-0.13.2/src/lib.rs:188:1
```

Both rcgen 0.13.x and 0.14.x exhibit the same conflict — the fix has
to come from rcgen upstream. Until then, edge pins `time = ">=0.3,
<0.3.48"` as a direct dep to constrain transitive resolution. Edge
doesn't use the `time` API surface — this is pure resolution control.

Drop the constraint when rcgen ships a release that handles the new
`Into<String>` impl (track at https://github.com/rustls/rcgen).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@emooreatx
emooreatx merged commit fe3cf8e into main Jun 12, 2026
62 of 63 checks passed
@emooreatx
emooreatx deleted the edge-v2-2-0-python-surface branch June 12, 2026 15:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant