Skip to content

v0.18.0

Choose a tag to compare

@rustyconover rustyconover released this 19 May 01:57
· 34 commits to main since this release

Application protocol_version enforcement

Introduces a per-Protocol surface version that vgi-rpc validates on every dispatched RPC. A Protocol that declares protocol_version: ClassVar[str] = "X.Y.Z" opts in; the framework emits vgi_rpc.protocol_version on every request batch's custom_metadata; the server enforces exact major+minor match (patch ignored) at the dispatch boundary on every transport (pipe / HTTP / unix / subprocess). Mismatches raise ProtocolVersionError with a directional message telling the reader which side to upgrade.

This is distinct from REQUEST_VERSION (wire framing, vgi-rpc's concern) and from per-catalog data-version semantics. It versions the method-and-schema contract between client and worker — the thing a C++ extension or Rust port has to keep in sync with the Python reference Protocol.

What's new

  • protocol_version ClassVar on Protocol subclasses. Read via vars() (not getattr) so subclasses that don't redeclare get None and opt out cleanly — no inheritance leaks. Validated at server / client construction; malformed semver raises ValueError at construction, not first RPC.
  • vgi_rpc.protocol_version request metadata key. Carried on every request batch from a vgi-rpc RpcClient bound to a Protocol that declares the version. Surfaced in __describe__ response metadata so mismatched clients can introspect the server's expected version.
  • ProtocolVersionError (subclass of VersionError, error_kind="protocol_version_mismatch") with four directional templates: client-too-old, server-too-old, malformed, missing.
  • Dispatch-boundary enforcement on every transport. RpcServer.serve_one for pipe / subprocess / unix; _run_unary_sync and _run_stream_init_sync for HTTP. __describe__ is exempt so version-mismatched clients can still introspect.
  • ConformanceService.protocol_version = "1.0.0" — cross-language ports (Go / TS / Java / Rust) must add the metadata key to claim conformance. Three new conformance tests: describe_protocol_version.surfaces_declared_version, describe_protocol_version.format, protocol_version.matched_dispatch_succeeds.

Breaking changes

  • Operator-supplied RpcServer(protocol_version="...") kwarg removed. This was a free-form access-log label with no enforcement and no observed consumers; the name is reused for the new strict-semver mechanism declared on the Protocol class. Pre-release, no deprecation shim. Operators relying on the access-log protocol_version field must remove it from parsers.
  • protocol_version field removed from access log JSON schema (vgi_rpc/access_log.schema.json, docs/access-log-spec.md). The new mechanism is enforced at the wire layer; access-log emission of the value is no longer load-bearing.

Cross-language source of truth

For ports that can't import vgi_rpc, the canonical version string for ConformanceService ships at https://github.com/Query-farm/vgi-rpc-python/blob/main/vgi_rpc/conformance/_protocol.py — and the Protocol class is the source of truth on the Python side. Bumping the version requires:

  1. Update protocol_version on the Protocol class.
  2. Cross-language ports re-read the metadata key on every request.
  3. Conformance suite enforces parity.

Known issues

  • http_externalize_always conformance variant is skipped on Windows for now. A pre-existing TCP race between waitress and httpx (WinError 10053) surfaces deterministically on Windows when the new metadata key shifts request-batch timing past a margin that v0.17.1 happened to clear by luck. Linux / macOS keep full coverage of this variant. The underlying race needs a framework-side fix (drain WSGI response body before close) and will be addressed in a follow-up.

Files

  • vgi_rpc/metadata.pyPROTOCOL_VERSION_KEY, parse_version, SEMVER_REGEX
  • vgi_rpc/rpc/_server.py_check_protocol_version, dispatch-boundary gate, ProtocolVersionError raise
  • vgi_rpc/rpc/_client.py, vgi_rpc/http/_client.py — request-time emission
  • vgi_rpc/http/server/_app_unary.py, _app_stream.py — HTTP dispatch-boundary gate
  • vgi_rpc/conformance/_protocol.pyprotocol_version = "1.0.0"
  • vgi_rpc/conformance/_runner.py — describe + matched-dispatch tests
  • tests/test_protocol_version.py — 45 unit tests covering pipe and HTTP, comparison matrix, inheritance, malformed, directional error messages