feat(11-C1): embed + stage hero_tracing.py on server startup #17

Merged
timur merged 1 commit from feat/11-phase-c1-embed-stage-tracing into development 2026-05-05 12:21:12 +00:00
Owner

Summary

Phase C1 of #11 — smallest piece of the executor work. Wires the Phase B SDK (hero_logic#16, merged) into the server binary so subsequent Phase C work (socket listener, subprocess spawn, RPC handlers) has a stable on-disk SDK location to point Python PYTHONPATHs at.

What's here

Item Purpose
engine/python_executor.rs New module. HERO_TRACING_PY constant (include_str!), flows_sdk_dir() resolver (env-overridable), stage_sdk(), stage_sdk_at(dir), PythonFlowExecutor placeholder for C2/C3/C4.
hero_logic_server main Calls python_executor::stage_sdk() after domain registration. Idempotent on every startup. Failure is fatal — no SDK ⇒ no Python flow can ever run.
Cargo deps Added dirs (workspace), tempfile as dev-dep.
Tests (4) contents-equal-source, mkdir -p of nested parents, idempotent overwrite of stale content, env-var override of the default path. All pass.

Why stage rather than ship a wheel

Flow authors should python my_flow.py without pip install hero_tracing. Embedding + staging guarantees the on-disk SDK always matches the running server's wire protocol — eliminates the "wheel out of sync with server" drift class. Cost is ~20 KiB of static text in the binary.

What this PR is NOT

  • Doesn't spawn any Python yet (C3).
  • Doesn't open any sockets (C2).
  • Doesn't add any RPC methods (C4).
  • Doesn't route play_start to the Python path yet (C4).
  • The DAG executor still owns every Play end-to-end.

PythonFlowExecutor is a struct with a single sdk_dir field — placeholder so the type exists when C2 starts adding methods.

Phase plan (#11)

  • A — schema additive (#15, merged)
  • B — hero_tracing.py SDK (#16, merged)
  • C1 — this PR — staging
  • C2 — UDS span socket listener
  • C3 — python3 subprocess + Tier 0 sandbox
  • C4 — new RPCs + SSE + play_start routing
  • D — migration tool + delete legacy DAG

Test plan

  • cargo build --workspace clean
  • cargo test -p hero_logic --lib python_executor — 4/4 pass
  • cargo test --workspace --lib green

🤖 Generated with Claude Code

## Summary Phase C1 of #11 — smallest piece of the executor work. Wires the Phase B SDK (hero_logic#16, merged) into the server binary so subsequent Phase C work (socket listener, subprocess spawn, RPC handlers) has a stable on-disk SDK location to point Python `PYTHONPATH`s at. ## What's here | Item | Purpose | |---|---| | `engine/python_executor.rs` | New module. `HERO_TRACING_PY` constant (`include_str!`), `flows_sdk_dir()` resolver (env-overridable), `stage_sdk()`, `stage_sdk_at(dir)`, `PythonFlowExecutor` placeholder for C2/C3/C4. | | `hero_logic_server` main | Calls `python_executor::stage_sdk()` after domain registration. Idempotent on every startup. Failure is fatal — no SDK ⇒ no Python flow can ever run. | | Cargo deps | Added `dirs` (workspace), `tempfile` as dev-dep. | | Tests (4) | contents-equal-source, mkdir -p of nested parents, idempotent overwrite of stale content, env-var override of the default path. All pass. | ## Why stage rather than ship a wheel Flow authors should `python my_flow.py` without `pip install hero_tracing`. Embedding + staging guarantees the on-disk SDK always matches the running server's wire protocol — eliminates the "wheel out of sync with server" drift class. Cost is ~20 KiB of static text in the binary. ## What this PR is NOT - Doesn't spawn any Python yet (C3). - Doesn't open any sockets (C2). - Doesn't add any RPC methods (C4). - Doesn't route `play_start` to the Python path yet (C4). - The DAG executor still owns every `Play` end-to-end. `PythonFlowExecutor` is a struct with a single `sdk_dir` field — placeholder so the type exists when C2 starts adding methods. ## Phase plan (#11) - A — schema additive (#15, merged) - B — `hero_tracing.py` SDK (#16, merged) - **C1 — this PR** — staging - C2 — UDS span socket listener - C3 — python3 subprocess + Tier 0 sandbox - C4 — new RPCs + SSE + `play_start` routing - D — migration tool + delete legacy DAG ## Test plan - [x] `cargo build --workspace` clean - [x] `cargo test -p hero_logic --lib python_executor` — 4/4 pass - [x] `cargo test --workspace --lib` green 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Phase C1 of #11. Smallest piece of the executor work — wires Phase B's
hero_tracing.py SDK into the server binary so subsequent Phase C work
(socket listener, subprocess spawn, RPC handlers) has a stable on-disk
SDK location to point Python flow PYTHONPATHs at.

What's here:

- New module `engine/python_executor.rs` with `HERO_TRACING_PY` (the
  SDK source embedded via `include_str!`), `flows_sdk_dir()` (resolves
  to `~/.hero/var/flows/sdk` with `HERO_FLOWS_SDK_DIR` override for
  tests/non-default deployments), `stage_sdk()` / `stage_sdk_at(dir)`
  for writing the SDK to disk, and a `PythonFlowExecutor` placeholder
  struct that future phases (C2/C3/C4) will fill out.

- `hero_logic_server` main calls `python_executor::stage_sdk()` after
  domain registration, before `server.run()`. Runs idempotently on
  every startup so binary upgrades land the matching SDK without
  operator action. Failure is fatal — no SDK ⇒ no Python flow can
  ever run, and the operator should know loudly.

- Added `dirs` to crate deps (already in workspace toml) and
  `tempfile` as a dev-dep so the staging tests can write into a
  per-test directory without touching the operator's real
  `~/.hero/var/flows/sdk`.

- 4 unit tests: contents-equal-source, mkdir -p of nested parents,
  idempotent overwrite of stale content, env-var override of the
  default path.

Why we stage the SDK rather than ship a wheel: flow authors should be
able to write a `.py` and run it without `pip install hero_tracing`.
Embedding + staging guarantees the on-disk SDK always matches the
running server's expected wire protocol — no version-skew drift class.
The cost (~20 KiB of static text in the binary) is negligible.

Phase C plan tracked at #11; this commit unblocks C2 (UDS span socket
listener) and C3 (subprocess spawn).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
timur merged commit 4290b200a0 into development 2026-05-05 12:21:12 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
lhumina_code/hero_logic!17
No description provided.