Commit 1c960f3
authored
Preserve raw worker stdin at the server boundary (#72)
* Add Zod readline discard recovery test
Teach the standalone Zod worker to emit readline_discard for buffered stdin after an interrupt so stale active-turn input is accounted for before a follow-up tail runs.
Validation: cargo check; cargo build; python3 tests/run_integration_tests.py --binary target/debug/mcp-repl; cargo clippy --all-targets --all-features -- -D warnings; cargo test --quiet; cargo +nightly fmt.
* Validate protocol session_end reasons
Reject worker sideband session_end frames that carry unrecognized reasons, and validate optional session_end message_b64 payloads before accepting the frame as final.
Add a Zod test hook and MCP-level regression coverage so malformed protocol-worker session_end data fails fast instead of being treated as a clean session shutdown.
Validation: cargo test --quiet --test zod_protocol zod_worker_invalid_session_end_reason_is_protocol_error; cargo test --quiet --test zod_protocol; cargo check; cargo build; python3 tests/run_integration_tests.py --binary target/debug/mcp-repl; cargo clippy --all-targets --all-features -- -D warnings; cargo test --quiet; cargo +nightly fmt
* Add Zod shutdown conformance hooks
Add slow-shutdown and hang-shutdown commands to the standalone Zod worker so public protocol tests can exercise delayed graceful shutdown and pending shutdown states. Cover both through MCP-level tests and update the active protocol plan command list.
Validation:
- cargo test --quiet --test zod_protocol shutdown (red before fixture change)
- cargo test --quiet --test zod_protocol
- cargo check
- cargo build
- python3 tests/run_integration_tests.py --binary target/debug/mcp-repl
- cargo clippy --all-targets --all-features -- -D warnings
- cargo test --quiet
- cargo +nightly fmt
* Split Zod interrupt observations
Add an interrupt-report fixture command that records sideband interrupt
notifications separately from OS interrupt delivery. Cover it through the
public Zod protocol test and document the command in the active protocol plan.
Validation:
- cargo +nightly fmt
- cargo check
- cargo build
- cargo test --test zod_protocol zod_worker_reports_sideband_and_os_interrupt_facts -- --nocapture
- cargo test --test zod_protocol --quiet
- python3 tests/run_integration_tests.py --binary target/debug/mcp-repl
- cargo clippy --all-targets --all-features -- -D warnings
- cargo test --quiet
* Preserve control-tail newline bytes
Consume only the leading Ctrl-C/Ctrl-D byte when splitting control-prefixed input so an immediate newline remains part of the tail payload. Add a public Zod MCP regression that proves the worker observes that newline before the tail command.
Update existing tests that intend bare controls to send unterminated control bytes, and update transcript snapshots to show those bare inputs explicitly.
Validation:
- cargo check
- cargo build
- python3 tests/run_integration_tests.py --binary target/debug/mcp-repl
- cargo clippy --all-targets --all-features -- -D warnings
- cargo test --quiet
- cargo +nightly fmt
* Preserve protocol worker stdin bytes
Move CR/CRLF normalization out of the shared request path and keep it in the built-in R/Python drivers, so custom protocol workers receive the exact client stdin bytes plus the existing single appended LF rule.
Add public Zod MCP coverage for supplied CRLF bytes and a trailing bare carriage return. Update the protocol plan to state the byte-preservation contract.
Validation:
- cargo test --test zod_protocol zod_worker_preserves_crlf_stdin_and_appended_newline -- --exact
- cargo test --test write_stdin_edge_cases write_stdin_accepts_crlf_input -- --exact
- cargo check
- cargo build
- python3 tests/run_integration_tests.py --binary target/debug/mcp-repl
- cargo clippy --all-targets --all-features -- -D warnings
- cargo test --quiet
- cargo +nightly fmt
* Fix reset teardown output and Ctrl-C bundle reuse
Snapshot pending output before reset shutdown so teardown-only worker output
does not leak into the reset reply. Also classify Ctrl-C plus newline/CRLF
as follow-up input for timeout bundle reuse; only bare Ctrl-C reuses the
full timeout reply.
Validation:
- cargo check
- cargo build
- python3 tests/run_integration_tests.py --binary target/debug/mcp-repl
- cargo clippy --all-targets --all-features -- -D warnings
- cargo test --quiet
- cargo +nightly fmt
* Cover reset EOF for active Zod stdin
Add a Zod command that blocks on a second stdin read and verify repl_reset
closes the active stdin stream without sending interpreter shutdown text.
Validation:
- cargo check
- cargo build
- python3 tests/run_integration_tests.py --binary target/debug/mcp-repl
- cargo clippy --all-targets --all-features -- -D warnings
- cargo test --quiet
- cargo +nightly fmt
* Fix Unix Python CRLF stdin normalization
Normalize CRLF and bare CR input before the built-in Unix Python backend
writes request bytes to its PTY. Keep custom protocol worker payloads
byte-preserving by applying the normalization only when the protocol driver is
serving the built-in Python bridge.
Add a Unix public regression test that sends a CRLF-formatted multiline Python
block through the MCP repl tool and asserts it executes without an injected
blank line or IndentationError.
Review finding:
- [P2] Normalize CRLF before Unix Python PTY writes — /Users/tomasz/github/posit-dev/mcp-repl/src/worker_process.rs:2624-2624
On Unix, the built-in Python backend uses `ProtocolBackendDriver`, whose `prepare_input_payload` now preserves stdin bytes. Since the previous normalization was removed before this call, CRLF input is written to the PTY as `\r\n`; the terminal maps `\r` to another newline, so a block like `if True:\r\n print("A")` reaches Python with a blank line and raises `IndentationError`. Custom protocol workers can preserve bytes, but built-in Python still needs newline normalization before writing to the PTY.
Response:
- Added `python_crlf_multiline_block_executes` to cover CRLF multiline Python input through the public MCP tool path.
- Updated `ProtocolBackendDriver::prepare_input_payload` so only the built-in Unix Python bridge normalizes CRLF/CR before PTY writes; custom protocol workers still preserve stdin bytes.
Validation:
- cargo test --test python_backend python_crlf_multiline_block_executes -- --nocapture (failed before fix, passed after fix)
- cargo check
- cargo build
- python3 tests/run_integration_tests.py --binary target/debug/mcp-repl
- cargo clippy --all-targets --all-features -- -D warnings
- cargo test --quiet
- cargo +nightly fmt
* Fix Zod command fixture argument count
Move the shutdown-log path into CommandState so run_command stays within the clippy argument limit after the stdin-close reset coverage was adapted.
Validation:
- cargo test --test zod_protocol --quiet
- cargo test --test python_backend --quiet crlf
- cargo test --quiet timeout_bundle_reuse_treats_newline_ctrl_c_as_follow_up_input
- cargo check
- cargo build
- python3 tests/run_integration_tests.py --binary target/debug/mcp-repl
- cargo clippy --all-targets --all-features -- -D warnings
- cargo test --quiet
- cargo +nightly fmt
* Preserve worker stdin bytes at server boundary
Keep server-side input payload preparation limited to the MCP UTF-8 string
boundary and the explicit final-newline append rule. Backend/runtime-specific
CRLF interpretation belongs to the worker instead of the server.
This also removes the Unix Python CRLF multiline expectation, keeps CRLF
acceptance scoped to Windows, and rewords the Zod protocol regression around
raw client byte preservation.
Validation:
- cargo check
- cargo build
- python3 tests/run_integration_tests.py --binary target/debug/mcp-repl
- cargo clippy --all-targets --all-features -- -D warnings
- cargo test --quiet
- cargo +nightly fmt
* Fix CI stdin edge cases
Normalize CRLF input in the built-in R backend before writing bytes to R so
Windows requests do not leave carriage returns in R source. Keep protocol
worker byte preservation intact by leaving the protocol driver unchanged.
Make the files-mode timeout poll regression deterministic by replacing a
short sleep with an explicit file gate before releasing the request.
Validation:
- cargo check
- cargo build
- python3 tests/run_integration_tests.py --binary target/debug/mcp-repl
- cargo clippy --all-targets --all-features -- -D warnings
- cargo test --quiet
- cargo +nightly fmt1 parent 55c7209 commit 1c960f3
22 files changed
Lines changed: 797 additions & 104 deletions
File tree
- docs/plans/active
- src
- server
- tests
- common
- fixtures
- snapshots
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
664 | 664 | | |
665 | 665 | | |
666 | 666 | | |
667 | | - | |
| 667 | + | |
| 668 | + | |
| 669 | + | |
668 | 670 | | |
669 | 671 | | |
670 | 672 | | |
| |||
751 | 753 | | |
752 | 754 | | |
753 | 755 | | |
754 | | - | |
755 | | - | |
| 756 | + | |
| 757 | + | |
| 758 | + | |
| 759 | + | |
| 760 | + | |
| 761 | + | |
| 762 | + | |
| 763 | + | |
756 | 764 | | |
757 | 765 | | |
758 | 766 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
461 | 461 | | |
462 | 462 | | |
463 | 463 | | |
| 464 | + | |
| 465 | + | |
| 466 | + | |
| 467 | + | |
| 468 | + | |
| 469 | + | |
| 470 | + | |
| 471 | + | |
464 | 472 | | |
465 | 473 | | |
466 | 474 | | |
| |||
1907 | 1915 | | |
1908 | 1916 | | |
1909 | 1917 | | |
| 1918 | + | |
| 1919 | + | |
| 1920 | + | |
| 1921 | + | |
| 1922 | + | |
| 1923 | + | |
| 1924 | + | |
| 1925 | + | |
| 1926 | + | |
| 1927 | + | |
| 1928 | + | |
| 1929 | + | |
| 1930 | + | |
| 1931 | + | |
| 1932 | + | |
| 1933 | + | |
| 1934 | + | |
1910 | 1935 | | |
1911 | 1936 | | |
1912 | 1937 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
186 | 186 | | |
187 | 187 | | |
188 | 188 | | |
189 | | - | |
190 | | - | |
191 | | - | |
192 | | - | |
193 | | - | |
194 | | - | |
195 | | - | |
196 | | - | |
197 | | - | |
198 | 189 | | |
199 | 190 | | |
200 | 191 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
197 | 197 | | |
198 | 198 | | |
199 | 199 | | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
200 | 216 | | |
201 | 217 | | |
202 | 218 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
475 | 475 | | |
476 | 476 | | |
477 | 477 | | |
478 | | - | |
| 478 | + | |
| 479 | + | |
479 | 480 | | |
480 | 481 | | |
481 | 482 | | |
| |||
1234 | 1235 | | |
1235 | 1236 | | |
1236 | 1237 | | |
1237 | | - | |
1238 | | - | |
1239 | | - | |
1240 | | - | |
1241 | | - | |
1242 | | - | |
1243 | | - | |
1244 | | - | |
1245 | | - | |
1246 | | - | |
1247 | | - | |
| 1238 | + | |
1248 | 1239 | | |
1249 | 1240 | | |
1250 | 1241 | | |
| |||
2575 | 2566 | | |
2576 | 2567 | | |
2577 | 2568 | | |
2578 | | - | |
2579 | 2569 | | |
2580 | 2570 | | |
2581 | 2571 | | |
| |||
3480 | 3470 | | |
3481 | 3471 | | |
3482 | 3472 | | |
| 3473 | + | |
| 3474 | + | |
| 3475 | + | |
| 3476 | + | |
| 3477 | + | |
3483 | 3478 | | |
3484 | 3479 | | |
| 3480 | + | |
3485 | 3481 | | |
3486 | 3482 | | |
3487 | | - | |
3488 | 3483 | | |
3489 | | - | |
| 3484 | + | |
| 3485 | + | |
| 3486 | + | |
| 3487 | + | |
| 3488 | + | |
| 3489 | + | |
3490 | 3490 | | |
3491 | 3491 | | |
3492 | 3492 | | |
| |||
3653 | 3653 | | |
3654 | 3654 | | |
3655 | 3655 | | |
| 3656 | + | |
| 3657 | + | |
| 3658 | + | |
| 3659 | + | |
| 3660 | + | |
3656 | 3661 | | |
3657 | 3662 | | |
3658 | 3663 | | |
| 3664 | + | |
3659 | 3665 | | |
3660 | | - | |
3661 | 3666 | | |
3662 | 3667 | | |
3663 | | - | |
| 3668 | + | |
| 3669 | + | |
| 3670 | + | |
| 3671 | + | |
| 3672 | + | |
| 3673 | + | |
| 3674 | + | |
| 3675 | + | |
| 3676 | + | |
| 3677 | + | |
| 3678 | + | |
| 3679 | + | |
| 3680 | + | |
| 3681 | + | |
3664 | 3682 | | |
3665 | 3683 | | |
3666 | 3684 | | |
| |||
4586 | 4604 | | |
4587 | 4605 | | |
4588 | 4606 | | |
| 4607 | + | |
| 4608 | + | |
| 4609 | + | |
| 4610 | + | |
| 4611 | + | |
| 4612 | + | |
| 4613 | + | |
| 4614 | + | |
| 4615 | + | |
4589 | 4616 | | |
4590 | 4617 | | |
4591 | 4618 | | |
4592 | | - | |
| 4619 | + | |
4593 | 4620 | | |
4594 | 4621 | | |
4595 | 4622 | | |
| |||
4613 | 4640 | | |
4614 | 4641 | | |
4615 | 4642 | | |
| 4643 | + | |
| 4644 | + | |
| 4645 | + | |
| 4646 | + | |
| 4647 | + | |
| 4648 | + | |
| 4649 | + | |
| 4650 | + | |
| 4651 | + | |
4616 | 4652 | | |
4617 | 4653 | | |
4618 | 4654 | | |
| |||
7603 | 7639 | | |
7604 | 7640 | | |
7605 | 7641 | | |
7606 | | - | |
| 7642 | + | |
7607 | 7643 | | |
7608 | 7644 | | |
7609 | 7645 | | |
7610 | | - | |
| 7646 | + | |
7611 | 7647 | | |
7612 | 7648 | | |
7613 | 7649 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
25 | 25 | | |
26 | 26 | | |
27 | 27 | | |
28 | | - | |
| 28 | + | |
29 | 29 | | |
30 | 30 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
279 | 279 | | |
280 | 280 | | |
281 | 281 | | |
| 282 | + | |
| 283 | + | |
| 284 | + | |
| 285 | + | |
| 286 | + | |
| 287 | + | |
| 288 | + | |
| 289 | + | |
| 290 | + | |
| 291 | + | |
| 292 | + | |
| 293 | + | |
| 294 | + | |
| 295 | + | |
| 296 | + | |
282 | 297 | | |
283 | 298 | | |
284 | 299 | | |
| |||
440 | 455 | | |
441 | 456 | | |
442 | 457 | | |
443 | | - | |
| 458 | + | |
444 | 459 | | |
445 | 460 | | |
446 | 461 | | |
| |||
0 commit comments