Files
sessions/tests/contracts
Myeongseon Choi 1488c92b1f
All checks were successful
Python Tests / detect-release-tag (push) Successful in 16s
Rust Tests / detect-release-tag (push) Successful in 16s
Python Tests / python-tests (push) Successful in 1m23s
Rust Tests / rust-tests (push) Successful in 1m25s
chore: release v0.3.6
Bump package, Rust workspace, bridge helper cache, and contract fixture versions together so the remote helper path and release metadata stay in sync for the v0.3.6 cut.

Made-with: Cursor
2026-04-22 18:28:42 +09:00
..

Protocol contract fixtures

This directory holds static JSON (and one multi-line text) fixtures for the Sessions wire contract between the local bridge (Rust local_bridge, driven by Python in sublime/sessions/ssh_file_transport.py) and the remote session helper (session_helper, Rust). They are intended for shared parsing tests and documentation; they are not wired into any test runner by themselves.

Transport

  • Framing is NDJSON: one UTF-8 line per logical message, each line a single JSON object.
  • Every helper-visible line uses the serde externally tagged shape: a top-level message_type field (handshake, request, response, error, cancel, shutdown in snake_case) with the remaining fields flattened from the inner struct (session_protocol::ProtocolMessage).

Two request shapes

  1. Python → bridge (stdin, persistent mode)
    One JSON object per line without message_type: id, method, params, timeout_ms, trace (string off | error | info | debug). This matches RequestEnvelope JSON as consumed by local_bridge when --persistent is used.

  2. Bridge → helper (remote stdio)
    The same logical request is wrapped as {"message_type":"request",...} via session_protocol::encode_message before it reaches the helper. Fixtures that describe helper traffic use this shape only where noted.

Fixtures named *.request.json use the Python → bridge envelope and follow ssh_file_transport._execute_rust_bridge_request: methods tree/list, file/read, file/stat, and file/write are sent as method: "channel/dispatch" with params.v = "sessions.channel.v1", channel: "file", kind: "request", and the real method in params.body. exec/once is sent with method: "exec/once" directly (no channel wrapper).

Responses and errors

  • Fixtures named *.response*.json and helper-side errors use message_type: "response" or message_type: "error" with flattened fields: response carries id and result; error carries optional id, code, message, retryable.
  • file_write.error.*.json are still response messages: structured write failures are carried in result as file/writes FileWriteResult (ok: false, error_code, error_message), which matches how session_helper reports most write failures instead of a top-level protocol error.

Bridge → Python (stdout)

The bridge prints one JSON object per line shaped as { "ok": bool, "id"?: string, "result"?: any, "error"?: { "id"?, "code", "message", "retryable" } } (local_bridge::BridgeCliOutput). Fixtures prefixed with bridge_stdout.* capture this envelope explicitly so both Python parser tests and Rust output-model tests can verify the contract independently.

File reference

File Role
handshake.valid.json Valid handshake line from the helper after startup.
handshake.missing_required_fields.json Invalid handshake JSON (omits protocol_version and remote_home) for negative decoding tests.
tree_list.request.json Python-style channel/dispatch wrapping tree/list.
tree_list.response.json Helper response with mixed TreeListEntry values (directory, regular_file, symlink + is_symlink_loop: true).
file_read.request.json Python-style dispatch for file/read.
file_read.response.regular_file.json Helper response; body_b64 is standard Base64 of hello\n (aGVsbG8K).
file_read.response.directory.json Helper response for a non-regular path: metadata.kind is directory and body_b64 is empty (matches session_helper today). Callers should treat this as “not readable as file bytes”.
file_stat.response.exists.json Helper response with exists: true and metadata.
file_stat.response.not_exists.json Helper response with exists: false (no metadata).
file_write.request.json Dispatch for file/write including expected_metadata.
file_write.response.success.json FileWriteResult success payload inside result.
file_write.error.permission_denied.json Structured failure with error_code: "permission_denied".
file_write.error.metadata_changed.json Structured failure with error_code: "remote_metadata_changed".
exec_once.request.json Direct exec/once Python-style request.
exec_once.response.success.json Successful ExecOnceResult.
exec_once.response.timeout.json Timed-out ExecOnceResult (timed_out: true, exit_code: 124, stderr suffix style from the helper).
error.session_scoped.json Protocol-level error with id: null (session-scoped).
protocol.malformed_stdout.txt Sample stdout with non-JSON noise lines mixed with valid NDJSON frames (decoder tolerance / diagnostics).
bridge_stdout.success.handshake.json Bridge CLI handshake output (persistent mode first line): ok: true, result.handshake with remote_home, arch, helper_version, etc.
bridge_stdout.success.file_read.json Bridge success envelope wrapping a file/read result (ok: true, id, result with metadata + body_b64).
bridge_stdout.success.tree_list.json Bridge success envelope wrapping a tree/list result.
bridge_stdout.error.permission_denied.json Bridge error envelope for a file/write permission-denied failure (ok: false, structured error).
bridge_stdout.error.session_scoped.json Bridge error envelope with id: null (session-scoped abort).
bridge_stdout.malformed.non_json.txt Mixed valid and non-JSON lines as they could appear on bridge stdout (tolerance test).
bridge_stdout.malformed.ok_missing.json JSON object missing the required ok field — Python must reject or handle gracefully.
bridge_stdout.malformed.result_missing.json ok: true but no result field — tests incomplete success envelope handling.
bridge_stdout.malformed.id_mismatch.json Valid bridge output with an id that does not match any pending request — tests response routing.

Shared vocabulary

  • RemoteFileKind (JSON string): regular_file, directory, symlink, other.
  • FileWriteErrorCode (JSON string, snake_case): permission_denied, path_is_directory, remote_file_missing, remote_metadata_changed, transport_error.
  • ShutdownNotice.reason: stdin_closed, ssh_disconnected, bridge_requested.

Base64

Example used in file_read.response.regular_file.json: plaintext hello\naGVsbG8K (standard Base64, RFC 4648).