Skip to content

Preserve transport truth and batch attributed requests - #749

Open
tony wants to merge 6 commits into
engine-ops-on-seamfrom
engine-ops-hardening
Open

Preserve transport truth and batch attributed requests#749
tony wants to merge 6 commits into
engine-ops-on-seamfrom
engine-ops-hardening

Conversation

@tony

@tony tony commented Aug 23, 2026

Copy link
Copy Markdown
Member

Summary

  • Fix four ways the engine transports could lie about what happened: misrouted commands, misattributed results, leaked child processes, and pane output left encoded.
  • Replace semicolon-folded command strings with ordered batches of distinct requests, so a control-mode reply can be matched to the operation that caused it.
  • Fix the MCP adapter closing engines it does not own, and make one close survive repeated cancellation.
  • Add session x window x pane matrix scenarios that verify their live postconditions rather than assuming them.
  • Fix a sync warmup that verified the full session set from inside the per-session build loop.

Changes by area

Transports

  • src/libtmux/_internal/tmux_argv.py, engines/connection.py: protect literal semicolons and reject incompatible engine connections.
  • experimental/engines/control_mode.py: correlate replies without treating guard-shaped output as protocol.
  • experimental/engines/async_control_mode.py, asyncio.py: drain and reap async children through cancellation and reader failures.
  • pane.py, experimental/mcp/events.py: expose decoded pane-output bytes to control-mode consumers.

Planner

  • experimental/ops/: ordered batches of distinct requests in place of folded command strings, with planner partitions, dependency boundaries, and result cardinality validated. In-flight plans and bindings are snapshotted across sync and async execution.
  • Borrowing tmux's server-global marked pane is gone; a plan no longer depends on process-wide state another client can move.

MCP lifespan

  • experimental/mcp/: model engine ownership and close only adapter-owned instances, shielding one close task through repeated cancellation with stable precedence.

Benchmark matrix

  • Report planner, request, engine-call, and process-model quantities separately, so a change that moves cost between them reads as movement rather than as a win.
  • Build every warmup session before topology verification, and clean the set only once it passes.

Design decisions

Batches, not folded strings. Folding several commands into one semicolon-separated string erases control-mode's reply boundaries: the transport returns output with no way to say which command produced which part, so a failure gets reported against the wrong operation. Ordered batches keep one request per result.

Close only what you own. An adapter handed an engine by its caller must not close it — the caller may still be using it. Ownership is now modelled explicitly rather than inferred from who happened to construct it.

Warmup completes before it is checked. Verifying the full expected topology from inside the per-session build loop asserts a postcondition that cannot hold until the loop finishes, so every multi-session scenario failed on its first build.

Test plan

  • uv run ruff check . — lint clean
  • uv run ruff format . — formatting clean, tree unchanged
  • uv run mypy — types clean
  • uv run pytest --reruns 0 — see the note below
  • just build-docs — docs build clean
  • Argv tests — literal semicolons survive rendering; incompatible connections are refused
  • Correlation tests — guard-shaped pane output is not mistaken for protocol
  • Async lifecycle and supervisor tests — children drain and reap under cancellation and reader failure
  • MCP settle tests — concurrent clients, borrowed engines, and close-error propagation
  • Matrix tests — the public CLI regression covers multi-session sync warmup end to end

tests/test_server.py::test_new_session_shell_env fails from a shell whose environment exceeds tmux's command-length limit; it is unrelated to this branch and is fixed higher in the stack.

@tony
tony force-pushed the engine-ops-hardening branch from d6347b9 to 1f7c749 Compare August 23, 2026 01:21
@codecov

codecov Bot commented Aug 23, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 90.38232% with 161 lines in your changes missing coverage. Please review.
✅ Project coverage is 80.52%. Comparing base (8095b7e) to head (8389250).

Files with missing lines Patch % Lines
src/libtmux/_internal/tmux_argv.py 60.22% 27 Missing and 8 partials ⚠️
...libtmux/experimental/engines/async_control_mode.py 77.53% 21 Missing and 10 partials ⚠️
src/libtmux/engines/connection.py 70.70% 22 Missing and 7 partials ⚠️
src/libtmux/experimental/engines/control_mode.py 74.46% 10 Missing and 2 partials ⚠️
src/libtmux/experimental/engines/asyncio.py 87.34% 5 Missing and 5 partials ⚠️
src/libtmux/experimental/mcp/_lifespan.py 83.01% 5 Missing and 4 partials ⚠️
src/libtmux/server.py 73.33% 6 Missing and 2 partials ⚠️
tests/experimental/contract/test_async_engine.py 93.22% 6 Missing and 2 partials ⚠️
tests/experimental/ops/test_plan.py 95.34% 3 Missing and 3 partials ⚠️
tests/experimental/ops/test_execute.py 78.57% 3 Missing ⚠️
... and 5 more
Additional details and impacted files
@@                  Coverage Diff                   @@
##           engine-ops-on-seam     #749      +/-   ##
======================================================
+ Coverage               79.60%   80.52%   +0.92%     
======================================================
  Files                     240      242       +2     
  Lines                   16511    17687    +1176     
  Branches                 2075     2164      +89     
======================================================
+ Hits                    13143    14243    +1100     
- Misses                   2652     2705      +53     
- Partials                  716      739      +23     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

tony added 6 commits August 23, 2026 08:30
why: Direct argv parsing, pinned server scope, control-mode correlation, and
async subprocess cleanup could misroute commands, misattribute results, leak
process resources, or leave pane output encoded.

what:
- Protect literal semicolons and reject incompatible engine connections
- Correlate control replies without treating guard-shaped output as protocol
- Drain and reap async children through cancellation and reader failures
- Expose decoded pane-output bytes to control-mode consumers
why: Semicolon folding erased control-mode reply boundaries, reported failures
against the wrong operations, and borrowed tmux's server-global marked pane.

what:
- Replace folded command strings with ordered batches of distinct requests
- Validate planner partitions, dependency boundaries, and result cardinality
- Snapshot in-flight plans and bindings across sync and async execution
- Make workspace, fluent, query, docs, and CLI surfaces use batching vocabulary
why: Adapter lifespans did not distinguish borrowed from owned engines, and a
second cancellation or close failure could strand resources or mask the body
exception.

what:
- Model engine ownership and close only adapter-owned instances
- Shield one close task through repeated cancellation with stable precedence
- Align plan preview and execution defaults on the batching planner
- Cover concurrent clients, borrowed engines, and close-error propagation
why: The earlier workload could not measure planner batching and conflated
planner steps, engine calls, tmux requests, and transport process models.

what:
- Add session x window x pane scenarios with verified live postconditions
- Report planner, request, engine-call, and process-model quantities separately
- Mark historical timings stale until regenerated with the current workload
- Add lossless source-scroll and bounded-overload async control demos
why: Sync warmup checked the full expected session set from inside the
per-session build loop, so it validated every requested name after building
only the first one. Every multi-session scenario aborted after its first
build, which took valid hierarchy benchmarks down with it.

what:
- Build every warmup session before topology verification, and clean the
  set only once it passes
- Cover it through the public matrix command, requiring a clean exit, so
  the regression is pinned at the surface a user actually invokes
why: The script carries a `uv run --script` shebang but shipped without the
executable bit, so the shebang was misleading: the one invocation it
advertises could not work. ruff's EXE001 catches exactly this, and CI runs on
Linux where the rule applies -- it is skipped on Windows and WSL, so a
developer working there cannot see it locally.

what:
- Record the file as mode 755, matching the other runnable scripts
@tony
tony force-pushed the engine-ops-hardening branch from 80c20ae to 8389250 Compare August 23, 2026 13:31
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