Skip to content

EMRY-034: Sidecar Python socket client - #72

Merged
vxfemboy merged 2 commits into
mainfrom
emry-034-sidecar-client
Jun 25, 2026
Merged

EMRY-034: Sidecar Python socket client#72
vxfemboy merged 2 commits into
mainfrom
emry-034-sidecar-client

Conversation

@vxfemboy

Copy link
Copy Markdown
Member

Closes #25 (EMRY-034). Branched off main. Pure Python.

What

  • emry.wire[u32 LE len][msgpack Event] encoder matching emry-ingest::wire (adjacently-tagged, structs-as-maps, values as [[id, val]]).
  • emry.socket_backend.SocketBackend — streams PhaseChange/MetricsBatch/RunFinished frames to a running emry engine over its Unix socket.
  • run() sidecar mode uses it (via EMRY_SOCKET), falling back to JSONL — with a warning — when no engine is reachable.
  • msgpack is an optional dep (emry[socket]), imported lazily; import emry and file/embedded runs don't need it.

Verification

  • pytest green: 59 passed, 1 skipped, 95.38% coverage. socketpair-based test decodes the exact frames sent.
  • Cross-language verified locally: a Python run(mode="sidecar") streamed 10 metric batches + a phase change + finish into the real emry engine, producing the expected events.jsonl. (This caught a real bug — the Rust Uuid msgpack form is a byte array, not a string — resolved by not sending RunStarted from the client, which is correct anyway: the engine owns run identity.)

Review-driven fixes

  • Send the initial PhaseChange (observers read phase from PhaseChange, not the batch field, so a run starting in EVAL would otherwise read as TRAIN).
  • Warn (don't silently file-fall-back) when mode="sidecar" is explicit but the engine is unreachable / EMRY_SOCKET unset.

Scope

Engine-side metrics.jsonl from socket events needs a name-table protocol (ids only over the wire) — a documented follow-up.

vxfemboy added 2 commits June 25, 2026 12:36
emry.wire: [u32 LE len][msgpack Event] encoder matching emry-ingest::wire
(adjacently-tagged, structs-as-maps). emry.socket_backend.SocketBackend streams
MetricsBatch/PhaseChange/RunFinished frames to a running 'emry engine' over its
Unix socket. run()'s sidecar mode uses it via EMRY_SOCKET, falling back to the
JSONL backend when no engine is listening. msgpack is an optional dep
(emry[socket]), imported lazily. Verified cross-language: a Python sidecar run
streamed 10 batches + a phase change + finish into the Rust engine's
events.jsonl. The client does NOT send RunStarted — the engine owns run
identity (and the Rust Uuid msgpack form is bytes, not a string).
- SocketBackend emits a PhaseChange on the first emit too (observers track phase
  from PhaseChange events, not the MetricsBatch field, so the initial phase must
  be sent or it reads as the default).
- run() warns when sidecar mode is explicitly requested but the engine is
  unreachable or EMRY_SOCKET is unset, before falling back to JSONL — a silent
  file fallback could mask a misconfigured sidecar.
@vxfemboy
vxfemboy merged commit 940876c into main Jun 25, 2026
3 checks passed
@vxfemboy
vxfemboy deleted the emry-034-sidecar-client branch July 2, 2026 23:34
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.

EMRY-034: Sidecar Python client

1 participant