Skip to content

feat(python): add bounded control-stream reliability state - #38

Merged
austinchennn merged 1 commit into
EmergentExit:mainfrom
wangyeyu1129:feat/python-sequence-reliability
Oct 17, 2026
Merged

austinchennn merged 1 commit into
EmergentExit:mainfrom
wangyeyu1129:feat/python-sequence-reliability

Conversation

@wangyeyu1129

@wangyeyu1129 wangyeyu1129 commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor

Description:

Refs #18 — Python control-stream reliability foundation only; no issue closed.

Adds direction-local Python Outbox and Inbox state on top of the merged protocol codecs. They provide continuous control-message numbering, cumulative ACK deletion, bounded replay storage and receive deduplication. They do not implement sockets, session lifecycle, reconnect orchestration, tools or audio.

Behaviours Completed

  • Outbox(direction, limit=1024).stamp(message) validates an unenveloped message, snapshots its payload and assigns a continuous seq. Transients use 0 and do not consume counter/cache space. Caller-provided v/seq are rejected rather than allowed to overwrite the generated envelope.
  • Server error messages require an explicit sessionless=True/False choice. Binding is not inferred from earlier messages or guessed by this transport-independent helper.
  • Cumulative ACKs and oldest-first capacity eviction remove retained messages. The replay loss floor advances for both kinds of removal: resend_from(cursor) returns independent ordered snapshots, [] when current, or None when a complete requested replay is unavailable/a valid uint32 cursor is ahead.
  • UInt32 ahead ACKs discard only currently retained messages, following §4.2's sender-side behavior. They do not change the allocated counter or grant future ACK credit. Non-int/bool/out-of-range local cursor parameters are rejected without mutation.
  • Control seq exhaustion raises OverflowError without wrapping, consuming a number or evicting data. Transients/sessionless errors remain possible. Validation and snapshot-copy failures do not partially commit a stamp.
  • Inbox(direction).accept(message) validates full structure before updating its receive cursor. Seq 0 never advances/deduplicates; valid seq <= cursor is duplicate; larger seq advances per §4.3, including a gap. Integral JSON numeric values normalize to Python ints internally.
  • Input, stamped output and replay output have separate mutable ownership. Public cursor properties are read-only; no arbitrary cursor setter or durable restore API is introduced.

Files Changed

  • python/src/vrealtime/sequence.py: two small synchronous state objects, local replay-capacity policy and argument checks; standard library only.
  • python/src/vrealtime/protocol.py: exposes the existing immutable transient-type set as TRANSIENT_MESSAGE_TYPES so codecs and sequence state share classification; wire rules unchanged.
  • python/src/vrealtime/__init__.py: public reliability helpers/constants.
  • python/tests/test_sequence.py: independent message/state trajectories, ACK/eviction boundaries, ownership, atomic failure and uint32 exhaustion coverage.
  • python/tests/check_install.py: checks new exports/state behavior in default installed artifacts without extras.
  • python/README.md, python/pyproject.toml: API, normative/local policy distinctions, limitations, discrepancies, aggregate budget and package description.

Brief Explanation

Outgoing retention and incoming receipt have different responsibilities and remain separate. Existing structural validation is reused; no transport/provider/tool dependency or framework is introduced. An ordered dictionary provides FIFO eviction/pruning without shifting a list. Deep copies isolate caller mutations; their cost is proportional to control-message payload size and is documented rather than presented as zero-copy real-time performance.

The invariant is a contiguous retained suffix after the highest actually removed seq, with a monotonic allocated counter. This prevents reporting a partial replay as successful when an old cursor refers to already acknowledged/deleted messages. The TypeScript helper currently tracks only unacknowledged eviction and can miss this case; this PR neither copies that behavior nor changes TypeScript/spec files.

A uint32 ahead ACK is impossible for a conforming peer that obeys the receive bound, but §4.2 explicitly defines its sender-side effect. The local helper honors that tolerant effect without storing credit for future sends. Session-level peer-error policy remains outside this API. Gaps follow §4.3's accept/advance rule without claiming missing-message recovery.

Testing

  • Python 3.10.22 and 3.14.8: 461 passed on each, including 73 new reliability cases and all existing shared-vector/schema/codec checks.
  • New coverage includes transient interleaving, cumulative/stale/ahead ACKs, empty and unavailable replay, capacities 1/2/3, ACK-plus-eviction interaction, wrong directions/envelopes/fields, local numeric boundaries, explicit error context, copy ownership, instance isolation, and failed validation/snapshot atomicity.
  • UInt32 exhaustion uses private test-only consistent state injection, not an exposed production setter. A simulated second-copy failure verifies that the old replay entry and allocated seq remain intact.
  • Ruff lint and format checks passed; production syntax checked for Python 3.10. No standalone Python type checker is configured in the repository or claimed here.
  • Built wheel/sdist. Each installed into a separate clean Python 3.10/3.14 environment (four combinations), with codec and new state smoke checks run outside the checkout; no runtime dependencies, network library or audio library were installed/imported.
  • npm run check:spec: 23 schemas, 156 control vectors, 9 audio vectors passed. Shared schemas/vector expectations are unchanged. git diff --check: passed.
  • Python production core: 619 lines, up 149 from upstream's 470. TypeScript/runtime, workerd and network-conformance suites were not rerun: this diff is confined to Python and provides no network implementation. Existing Python CI already exercises both versions, package installation and the aggregate budget.

Unsure About

  • Only 181 lines remain under python: Thin Python client SDK (vrealtime on PyPI) #18's 800-line non-audio core budget. Whether the remaining connection/session/tools/cancellation implementation can fit has not been established. Full-SDK budget/design needs review; this PR does not compress code or move it outside the count.
  • Review the explicit sessionless error flag, local strict-Python-int cursor parameters, and ahead-ACK tolerance. Validated integral wire numeric values need normalization at a future session boundary; blindly coercing arbitrary peer values is not intended.
  • ACK deletion makes older replay requests unsatisfiable just like eviction under §5.4. The corresponding TypeScript behavior merits separate review; no cross-language behavior change is hidden here.
  • Capacity bounds message count, not total bytes; future transports need frame-byte/resource limits. Helpers are single-owner synchronous state with no cross-thread synchronization, durable snapshot restore, ACK scheduler, replay/new-send ordering barrier or automatic session close.
  • No full reconnect, exactly-once application effects, complete SDK or conformance: Black-box conformance suite for clients and servers #17 black-box conformance claim. No package published.

Implementation Order and Acceptance — #18 progress

This records verified merged substeps, not completion of the full issue. The upstream issue body is unchanged because this contributor has read-only repository access.

@austinchennn
austinchennn merged commit b8bf53e into EmergentExit:main Oct 17, 2026
7 checks passed
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.

2 participants