Skip to content

feat(a2a-nats-stdio): add JSON-RPC over stdin/stdout bridge binary#364

Merged
yordis merged 13 commits into
mainfrom
yordis/feat-a2a-nats-stdio-binary
Jun 21, 2026
Merged

feat(a2a-nats-stdio): add JSON-RPC over stdin/stdout bridge binary#364
yordis merged 13 commits into
mainfrom
yordis/feat-a2a-nats-stdio-binary

Conversation

@yordis

@yordis yordis commented Jun 20, 2026

Copy link
Copy Markdown
Member
  • Second of three binaries from the upstream branch. Reads newline-delimited JSON-RPC 2.0 from stdin, dispatches to the matching A2aClient method, and writes responses (or streamed notifications for message/stream and tasks/resubscribe) to stdout.

Second of the three binaries from the upstream branch. Reads
newline-delimited JSON-RPC 2.0 requests from stdin, dispatches each one
to the matching A2aClient method, and writes the response (or streamed
notifications for message/stream and tasks/resubscribe) to stdout.

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
@cursor

cursor Bot commented Jun 20, 2026

Copy link
Copy Markdown

PR Summary

Medium Risk
New client-facing stdio protocol and concurrent streaming semantics (bootstrap ordering, JetStream consumption on early disconnect) warrant careful integration testing; no auth changes, but mis-handling could drop or ack events incorrectly.

Overview
Adds a new a2a-nats-stdio crate and binary that lets a parent process talk to A2A over NATS via newline-delimited JSON-RPC 2.0 on stdin/stdout, backed by A2aClient.

Runtime validates A2A_AGENT_ID (and optional A2A_PREFIX), connects to NATS/JetStream, applies A2A_OPERATION_TIMEOUT_SECS to the client, then runs the stdio loop until EOF or shutdown.

io_loop parses each line (JSON-RPC 2.0 envelope, id salvage on errors), spawns bounded concurrent dispatches (semaphore cap 64), writes one JSON frame per line with per-frame flush, and handles shutdown vs clean EOF (abort long streams on signal; drain unary RPCs on EOF). Stdout/write failures exit non-zero.

dispatch maps A2A methods (message/send, message/stream, task CRUD, push notification config, agent card) to A2aClient, maps ClientError to RPC codes, and for message/stream / tasks/resubscribe emits a bootstrap response then notifications tagged with the correct method (including lastSeq on resubscribe).

Coverage builds use cfg(coverage) stubs for the real NATS/io loop; behavior is covered by extensive unit tests with mock NATS/JetStream.

Reviewed by Cursor Bugbot for commit 6b00a79. Bugbot is set up for automated code reviews on this repo. Configure here.

@coderabbitai

coderabbitai Bot commented Jun 20, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@yordis, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 20 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan refill rate.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, the refill rate gradually slows as usage increases. The highest same-day bursts are limited more strictly.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d7ff50b6-958d-49bb-8206-08f6e1650f7f

📥 Commits

Reviewing files that changed from the base of the PR and between b9557a7 and 6b00a79.

📒 Files selected for processing (2)
  • rsworkspace/crates/a2a-nats-stdio/src/dispatch.rs
  • rsworkspace/crates/a2a-nats-stdio/src/io_loop.rs

Walkthrough

Introduces a new Rust binary crate a2a-nats-stdio that bridges JSON-RPC 2.0 requests from stdin/stdout to an A2aClient over NATS/JetStream. The crate defines JSON-RPC wire types, a method dispatcher routing to A2aClient calls, a Tokio-based I/O event loop with concurrency control, env-driven runtime configuration, and a binary entry point with coverage stubs.

Changes

a2a-nats-stdio: JSON-RPC stdin/stdout bridge

Layer / File(s) Summary
Crate manifest and JSON-RPC wire types
rsworkspace/crates/a2a-nats-stdio/Cargo.toml, src/wire.rs
Cargo manifest with workspace dependencies and dev-dependencies; RpcId, InboundRequest, OutboundResponse, OutboundNotification, RpcError, OutboundError, and OutboundFrame wire types with serde constructors and unit tests validating deserialization and serialization.
RPC method dispatcher
rsworkspace/crates/a2a-nats-stdio/src/dispatch.rs
dispatch_request routes method strings to A2aClient calls; handles param deserialization with INVALID_PARAMS errors, maps ClientError variants to JSON-RPC codes (preserving upstream codes or defaulting to −32603), supports streaming bootstrap+notification forwarding for message/stream and tasks/resubscribe, includes make_with_id ID rewrite helper, and returns METHOD_NOT_FOUND for unknown methods. Comprehensive unit tests cover all routing paths.
Tokio stdin/stdout I/O event loop
rsworkspace/crates/a2a-nats-stdio/src/io_loop.rs
run_io_loop spawns a writer task serializing OutboundFrames to stdout with newline+flush per frame, drives tokio::select! loop reading stdin lines with biased shutdown priority, skips blank lines, parses JSON-RPC via parse_inbound (routing JSON parse errors to −32700, envelope errors to −32600), caps concurrent dispatch tasks with Semaphore, spawns JoinSet of dispatch tasks, aborts inflight dispatchers on shutdown, and propagates writer/join errors as std::io::Result<()>. Extensive tests cover EOF, shutdown, blanks, valid requests, parse errors, writer I/O failures, and preemption.
Env config, runtime, and binary entry points
rsworkspace/crates/a2a-nats-stdio/src/runtime.rs, src/lib.rs, src/main.rs
RuntimeError enum with Display/source/From conversions; ValidatedStdioConfig and parse_env reading A2A_AGENT_ID (required) and A2A_PREFIX (defaults to DEFAULT_A2A_PREFIX); cfg-gated run() loading env, parsing config, connecting to NATS/JetStream, building A2aClient with operation timeout, and starting I/O loop (stub returns Ok() under coverage). lib.rs declares public modules and re-exports RuntimeError/run; main.rs provides #[tokio::main] entry invoking run() with stderr error printing and exit code 1, plus coverage-only empty main stub and test.

Sequence Diagram

sequenceDiagram
  participant client as External Client
  participant stdin
  participant ioLoop as run_io_loop
  participant dispatch as dispatch_request
  participant a2a as A2aClient
  participant nats as NATS/JetStream
  participant stdout

  client->>stdin: JSON-RPC line (method, id, params)
  ioLoop->>stdin: read_line
  stdin-->>ioLoop: InboundRequest

  ioLoop->>dispatch: spawn(client, id, method, params, tx)
  dispatch->>a2a: invoke matching method
  a2a->>nats: publish/subscribe/request
  nats-->>a2a: result or stream events
  a2a-->>dispatch: Ok(result) or Err or Stream

  alt single-shot response
    dispatch->>ioLoop: OutboundFrame::Response via mpsc
  else streaming response
    dispatch->>ioLoop: OutboundFrame::Response (bootstrap)
    loop stream events
      dispatch->>ioLoop: OutboundFrame::Notification
    end
  else parse/validation error
    dispatch->>ioLoop: OutboundFrame::Error
  end

  ioLoop->>ioLoop: writer task serializes
  ioLoop->>stdout: JSON + newline + flush
  stdout-->>client: JSON-RPC response/notifications
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • TrogonStack/trogonai#334: The main PR's a2a-nats-stdio runtime creates and configures A2aClient using the constructor and with_operation_timeout(...) introduced in that PR's A2A client-routing scaffolding.
  • TrogonStack/trogonai#340: The main PR's dispatch_request routes the message/stream JSON-RPC method directly to the A2aClient::message_stream per-operation streaming API added in that PR.

Suggested labels

rust:coverage-baseline-reset

🐇 A rabbit hopped to the stdin today,
JSON-RPC lines came flooding in the fray.
Through NATS and JetStream the messages flew fast,
Bootstrap responses and streaming events amassed.
With wire types and dispatch, the bridge stands so tall —
Stdout delivers the replies to answer the call! 🎉

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and concisely describes the main change: introducing a JSON-RPC over stdin/stdout bridge binary for a2a-nats-stdio.
Description check ✅ Passed The description clearly explains the PR's purpose, mentioning it reads newline-delimited JSON-RPC from stdin, dispatches to A2aClient methods, and writes responses to stdout.
Docstring Coverage ✅ Passed Docstring coverage is 88.04% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch yordis/feat-a2a-nats-stdio-binary

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Comment thread rsworkspace/crates/a2a-nats-stdio/src/dispatch.rs Outdated
Comment thread rsworkspace/crates/a2a-nats-stdio/src/io_loop.rs Outdated
Comment thread rsworkspace/crates/a2a-nats-stdio/src/dispatch.rs
@github-actions

github-actions Bot commented Jun 20, 2026

Copy link
Copy Markdown

badge

Code Coverage Summary

Details
Filename                                                                                  Stmts    Miss  Cover    Missing
--------------------------------------------------------------------------------------  -------  ------  -------  ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
crates/acp-nats/src/nats/subjects/responses/ext_ready.rs                                     12       0  100.00%
crates/acp-nats/src/nats/subjects/responses/update.rs                                        27       0  100.00%
crates/acp-nats/src/nats/subjects/responses/prompt_response.rs                               27       0  100.00%
crates/acp-nats/src/nats/subjects/responses/response.rs                                      20       0  100.00%
crates/acp-nats/src/nats/subjects/responses/cancelled.rs                                     15       0  100.00%
crates/mcp-nats/src/nats/parsing.rs                                                         191       0  100.00%
crates/mcp-nats/src/nats/mod.rs                                                              99       0  100.00%
crates/mcp-nats/src/nats/subjects/server/tool_list_changed.rs                                12       0  100.00%
crates/mcp-nats/src/nats/subjects/server/elicitation_completed.rs                            12       0  100.00%
crates/mcp-nats/src/nats/subjects/server/cancel_task.rs                                      12       0  100.00%
crates/mcp-nats/src/nats/subjects/server/list_tools.rs                                       12       0  100.00%
crates/mcp-nats/src/nats/subjects/server/resource_updated.rs                                 12       0  100.00%
crates/mcp-nats/src/nats/subjects/server/unsubscribe_resource.rs                             12       0  100.00%
crates/mcp-nats/src/nats/subjects/server/get_task_result.rs                                  12       0  100.00%
crates/mcp-nats/src/nats/subjects/server/get_task.rs                                         12       0  100.00%
crates/mcp-nats/src/nats/subjects/server/read_resource.rs                                    12       0  100.00%
crates/mcp-nats/src/nats/subjects/server/set_logging_level.rs                                12       0  100.00%
crates/mcp-nats/src/nats/subjects/server/subscribe_resource.rs                               12       0  100.00%
crates/mcp-nats/src/nats/subjects/server/list_tasks.rs                                       12       0  100.00%
crates/mcp-nats/src/nats/subjects/server/logging_message.rs                                  12       0  100.00%
crates/mcp-nats/src/nats/subjects/server/call_tool.rs                                        12       0  100.00%
crates/mcp-nats/src/nats/subjects/server/initialize.rs                                       12       0  100.00%
crates/mcp-nats/src/nats/subjects/server/cancelled.rs                                        12       0  100.00%
crates/mcp-nats/src/nats/subjects/server/complete.rs                                         12       0  100.00%
crates/mcp-nats/src/nats/subjects/server/list_resource_templates.rs                          12       0  100.00%
crates/mcp-nats/src/nats/subjects/server/get_prompt.rs                                       12       0  100.00%
crates/mcp-nats/src/nats/subjects/server/list_resources.rs                                   12       0  100.00%
crates/mcp-nats/src/nats/subjects/server/ping.rs                                              9       0  100.00%
crates/mcp-nats/src/nats/subjects/server/list_prompts.rs                                     12       0  100.00%
crates/mcp-nats/src/nats/subjects/server/progress.rs                                         12       0  100.00%
crates/mcp-nats/src/nats/subjects/server/prompt_list_changed.rs                              12       0  100.00%
crates/mcp-nats/src/nats/subjects/server/resource_list_changed.rs                            12       0  100.00%
crates/acp-nats-stdio/src/main.rs                                                           135      25  81.48%   67, 115-122, 128-130, 147, 176-195
crates/acp-nats-stdio/src/config.rs                                                          66       0  100.00%
crates/a2a-nats/src/audit/envelope.rs                                                       204       0  100.00%
crates/a2a-nats/src/audit/task_lifecycle.rs                                                  17       0  100.00%
crates/a2a-nats/src/audit/emitter.rs                                                        160       0  100.00%
crates/mcp-nats-stdio/src/config.rs                                                         149       0  100.00%
crates/mcp-nats-stdio/src/main.rs                                                           204       0  100.00%
crates/mcp-nats-server/src/config.rs                                                        257       0  100.00%
crates/mcp-nats-server/src/allowed_host.rs                                                   88       0  100.00%
crates/mcp-nats-server/src/main.rs                                                          357     127  64.43%   151-168, 204-206, 216, 222-223, 230-233, 257-259, 263-272, 294-307, 312-360, 491, 494, 502-544
crates/trogon-decider-nats/src/store.rs                                                     128      45  64.84%   50-54, 101-167
crates/trogon-decider-nats/src/snapshot_store.rs                                            861      27  96.86%   208-210, 248-250, 361-367, 449, 585, 590, 686-688, 694-696, 730-731, 741-742, 761, 789-790
crates/trogon-decider-nats/src/stream_store.rs                                              659      18  97.27%   70-72, 245, 273-274, 277, 293-297, 464-465, 506, 519-523
crates/trogon-decider-runtime/src/stream/mod.rs                                              38       0  100.00%
crates/trogon-decider-runtime/src/stream/read_stream.rs                                       7       0  100.00%
crates/trogon-decider-runtime/src/stream/stream_position.rs                                  26       0  100.00%
crates/trogon-decider-runtime/src/stream/append_stream.rs                                     5       0  100.00%
crates/a2a-nats-stdio/src/runtime.rs                                                        102       0  100.00%
crates/a2a-nats-stdio/src/wire.rs                                                            57       0  100.00%
crates/a2a-nats-stdio/src/io_loop.rs                                                         84       0  100.00%
crates/a2a-nats-stdio/src/main.rs                                                             4       0  100.00%
crates/a2a-nats-stdio/src/dispatch.rs                                                       839      11  98.69%   116, 119-121, 229, 232-234, 668, 1058, 1068
crates/a2a-nats/src/nats/subjects/subscriptions/agent_all.rs                                 20       0  100.00%
crates/a2a-nats/src/nats/subjects/subscriptions/task_all_events.rs                           17       0  100.00%
crates/a2a-nats/src/nats/subjects/subscriptions/task_one_events.rs                           20       0  100.00%
crates/trogon-gateway/src/source/telegram/config.rs                                          89       0  100.00%
crates/trogon-gateway/src/source/telegram/server.rs                                         339       0  100.00%
crates/trogon-gateway/src/source/telegram/registration.rs                                   313       0  100.00%
crates/trogon-gateway/src/source/telegram/signature.rs                                       27       0  100.00%
crates/trogon-scheduler/src/telemetry/metrics.rs                                             52       0  100.00%
crates/trogon-scheduler/src/telemetry/trace.rs                                               41       0  100.00%
crates/acp-nats/src/nats/subjects/stream.rs                                                  56       0  100.00%
crates/acp-nats/src/nats/subjects/mod.rs                                                    362       0  100.00%
crates/trogon-decider-runtime/src/snapshot/codec/snapshot_encode_error.rs                    36       0  100.00%
crates/trogon-decider-runtime/src/snapshot/codec/snapshot_payload_decode.rs                   3       0  100.00%
crates/trogon-decider-runtime/src/snapshot/codec/snapshot_decode_error.rs                    49       0  100.00%
crates/trogon-decider-runtime/src/snapshot/codec/snapshot_envelope_encode_error.rs           14       0  100.00%
crates/trogon-decider-runtime/src/snapshot/codec/encoded_snapshot.rs                        117       0  100.00%
crates/trogon-decider-runtime/src/snapshot/codec/snapshot_envelope_decode_error.rs           28       0  100.00%
crates/a2a-nats/src/jetstream/streams.rs                                                     73       0  100.00%
crates/a2a-nats/src/jetstream/consumers.rs                                                  112       0  100.00%
crates/a2a-nats/src/jetstream/provision.rs                                                   62       0  100.00%
crates/a2a-nats/src/jetstream/stream_options.rs                                             114       0  100.00%
crates/acp-nats/src/nats/extensions.rs                                                        3       0  100.00%
crates/acp-nats/src/nats/mod.rs                                                              23       0  100.00%
crates/acp-nats/src/nats/parsing.rs                                                         278       1  99.64%   151
crates/trogon-decider-runtime/src/snapshot/mod.rs                                             3       0  100.00%
crates/trogon-decider-runtime/src/snapshot/read_snapshot.rs                                  11       0  100.00%
crates/trogon-decider-runtime/src/snapshot/snapshot_type.rs                                  73       0  100.00%
crates/trogon-decider/src/events.rs                                                          49       0  100.00%
crates/trogon-decider/src/decision.rs                                                        27       0  100.00%
crates/trogon-decider/src/lib.rs                                                            138       0  100.00%
crates/trogon-decider/src/testing.rs                                                        675       0  100.00%
crates/trogon-decider/src/act.rs                                                             62       0  100.00%
crates/a2a-nats/src/nats/subjects/tasks/events.rs                                            31       0  100.00%
crates/trogon-gateway/src/source/discord/config.rs                                          105       0  100.00%
crates/trogon-gateway/src/source/discord/gateway.rs                                         426       1  99.77%   137
crates/trogon-nats/src/lease/lease_bucket.rs                                                 19       0  100.00%
crates/trogon-nats/src/lease/mod.rs                                                         523      13  97.51%   113-126
crates/trogon-nats/src/lease/release.rs                                                       5       5  0.00%    8-12
crates/trogon-nats/src/lease/provision.rs                                                   187      10  94.65%   82-92
crates/trogon-nats/src/lease/nats_kv_lease_config.rs                                         26       0  100.00%
crates/trogon-nats/src/lease/ttl.rs                                                          68       0  100.00%
crates/trogon-nats/src/lease/lease_timing.rs                                                 15       0  100.00%
crates/trogon-nats/src/lease/acquire.rs                                                       5       5  0.00%    9-14
crates/trogon-nats/src/lease/renew_interval.rs                                               57       0  100.00%
crates/trogon-nats/src/lease/renew.rs                                                       246      19  92.28%   23-29, 48-59
crates/trogon-nats/src/lease/lease_key.rs                                                    19       0  100.00%
crates/a2a-nats/src/nats/subjects/stream.rs                                                  54       0  100.00%
crates/trogon-nats/src/telemetry/messaging.rs                                                82       0  100.00%
crates/trogon-scheduler/src/commands/record_schedule_occurrence.rs                          348       1  99.71%   182
crates/trogon-scheduler/src/commands/snapshot.rs                                              4       0  100.00%
crates/trogon-scheduler/src/commands/state.rs                                               472       0  100.00%
crates/trogon-scheduler/src/commands/remove_schedule.rs                                     171       0  100.00%
crates/trogon-scheduler/src/commands/pause_schedule.rs                                      174       0  100.00%
crates/trogon-scheduler/src/commands/schedule_next_occurrence.rs                            355       0  100.00%
crates/trogon-scheduler/src/commands/create_schedule.rs                                     199       0  100.00%
crates/trogon-scheduler/src/commands/resume_schedule.rs                                     207       0  100.00%
crates/a2a-nats/src/catalog/registrar.rs                                                    211       0  100.00%
crates/a2a-nats/src/catalog/nats_kv.rs                                                       19       0  100.00%
crates/a2a-nats/src/catalog/store.rs                                                        382       0  100.00%
crates/a2a-nats/src/catalog/watch.rs                                                         99       0  100.00%
crates/trogon-scheduler/src/processor/execution/checkpoints/failure.rs                       38       0  100.00%
crates/trogon-scheduler/src/processor/execution/checkpoints/codec.rs                        641      68  89.39%   134, 140, 149, 192, 208-210, 227, 244-246, 415, 417-419, 453-464, 480-481, 486-487, 493-494, 507-508, 513-514, 519-523, 529-530, 545-546, 551-552, 558-559, 566-567, 572-573, 585-589, 595-597, 612-618, 626, 631-633, 643, 648
crates/trogon-scheduler/src/processor/execution/checkpoints/record.rs                         6       0  100.00%
crates/trogon-scheduler/src/processor/execution/checkpoints/store.rs                        407      17  95.82%   102, 120, 124, 132, 224-230, 236, 279-283
crates/acp-nats/src/nats/subjects/subscriptions/global_all.rs                                 9       0  100.00%
crates/acp-nats/src/nats/subjects/subscriptions/all_agent_ext.rs                              9       0  100.00%
crates/acp-nats/src/nats/subjects/subscriptions/all_session.rs                                9       0  100.00%
crates/acp-nats/src/nats/subjects/subscriptions/one_session.rs                               12       0  100.00%
crates/acp-nats/src/nats/subjects/subscriptions/one_agent.rs                                 15       0  100.00%
crates/acp-nats/src/nats/subjects/subscriptions/one_client.rs                                15       0  100.00%
crates/acp-nats/src/nats/subjects/subscriptions/all_client.rs                                 9       0  100.00%
crates/acp-nats/src/nats/subjects/subscriptions/all_agent.rs                                  9       0  100.00%
crates/acp-nats/src/nats/subjects/subscriptions/prompt_wildcard.rs                            9       0  100.00%
crates/trogon-gateway/src/source/standard_webhooks.rs                                       138       0  100.00%
crates/a2a-nats/src/catalog/import_gate/principal.rs                                         14       0  100.00%
crates/a2a-nats/src/catalog/import_gate/allow_all.rs                                          2       0  100.00%
crates/a2a-nats/src/catalog/import_gate/error.rs                                              9       0  100.00%
crates/trogon-gateway/src/source/incidentio/server.rs                                       343       0  100.00%
crates/trogon-gateway/src/source/incidentio/signature.rs                                    206       0  100.00%
crates/trogon-gateway/src/source/incidentio/config.rs                                        16       0  100.00%
crates/trogon-gateway/src/source/incidentio/incidentio_signing_secret.rs                     56       0  100.00%
crates/trogon-gateway/src/source/incidentio/incidentio_event_type.rs                         62       0  100.00%
crates/a2a-nats/src/catalog/import_gate/spicedb/config.rs                                    70       0  100.00%
crates/a2a-nats/src/catalog/import_gate/spicedb/mod.rs                                      107       0  100.00%
crates/a2a-nats/src/catalog/import_gate/spicedb/cache.rs                                     36       0  100.00%
crates/trogon-gateway/src/source/slack/server.rs                                            853       0  100.00%
crates/trogon-gateway/src/source/slack/config.rs                                             58       0  100.00%
crates/trogon-gateway/src/source/slack/signature.rs                                          66       0  100.00%
crates/trogon-gateway/src/source/slack/socket_mode.rs                                       716       0  100.00%
crates/trogon-scheduler/src/processor/execution/execution_schedules/mod.rs                  270       0  100.00%
crates/trogon-scheduler/src/processor/execution/worker/processor.rs                        1356      12  99.12%   279, 339, 437-438, 444, 499-501, 533-536
crates/trogon-scheduler/src/processor/execution/worker/consumer.rs                          203       0  100.00%
crates/trogon-scheduler/src/processor/execution/worker/dispatcher.rs                       1095       1  99.91%   200
crates/trogon-scheduler/src/processor/execution/worker/testkit.rs                           330       4  98.79%   459, 490-491, 496
crates/trogonai-proto/src/scheduler/schedules/codec.rs                                      377       0  100.00%
crates/acp-nats/src/nats/subjects/commands/set_model.rs                                      15       0  100.00%
crates/acp-nats/src/nats/subjects/commands/close.rs                                          15       0  100.00%
crates/acp-nats/src/nats/subjects/commands/fork.rs                                           15       0  100.00%
crates/acp-nats/src/nats/subjects/commands/prompt.rs                                         15       0  100.00%
crates/acp-nats/src/nats/subjects/commands/set_config_option.rs                              15       0  100.00%
crates/acp-nats/src/nats/subjects/commands/resume.rs                                         15       0  100.00%
crates/acp-nats/src/nats/subjects/commands/set_mode.rs                                       15       0  100.00%
crates/acp-nats/src/nats/subjects/commands/load.rs                                           15       0  100.00%
crates/acp-nats/src/nats/subjects/commands/cancel.rs                                         15       0  100.00%
crates/mcp-nats/src/client.rs                                                                31       0  100.00%
crates/mcp-nats/src/mcp_peer_id.rs                                                           31       0  100.00%
crates/mcp-nats/src/server.rs                                                                31       0  100.00%
crates/mcp-nats/src/mcp_prefix.rs                                                            34       0  100.00%
crates/mcp-nats/src/transport.rs                                                            698       0  100.00%
crates/mcp-nats/src/jsonrpc.rs                                                               22       0  100.00%
crates/mcp-nats/src/config.rs                                                               110       0  100.00%
crates/trogon-gateway/src/source/gitlab/signature.rs                                        165       0  100.00%
crates/trogon-gateway/src/source/gitlab/gitlab_signing_token.rs                              62       0  100.00%
crates/trogon-gateway/src/source/gitlab/server.rs                                           460       0  100.00%
crates/trogon-std/src/duration.rs                                                            42       0  100.00%
crates/trogon-std/src/json.rs                                                                30       0  100.00%
crates/trogon-std/src/signal.rs                                                              26      12  53.85%   6-11, 18-25, 34
crates/trogon-std/src/uuid.rs                                                                 7       0  100.00%
crates/trogon-std/src/secret_string.rs                                                       32       0  100.00%
crates/trogon-std/src/args.rs                                                                19       9  52.63%   11-28
crates/trogon-std/src/http.rs                                                                19       0  100.00%
crates/trogon-scheduler/src/commands/domain/message.rs                                      219       0  100.00%
crates/trogon-scheduler/src/commands/domain/schedule_event_schedule.rs                       83       0  100.00%
crates/trogon-scheduler/src/commands/domain/schedule.rs                                     638       0  100.00%
crates/trogon-scheduler/src/commands/domain/recurrence.rs                                   179       1  99.44%   99
crates/trogon-scheduler/src/commands/domain/schedule_event_delivery.rs                       25       0  100.00%
crates/trogon-scheduler/src/commands/domain/schedule_event_status.rs                         10       0  100.00%
crates/trogon-scheduler/src/commands/domain/schedule_id.rs                                   81       0  100.00%
crates/trogon-scheduler/src/commands/domain/schedule_occurrence_sequence.rs                  30       0  100.00%
crates/trogon-scheduler/src/commands/domain/schedule_event_sampling_source.rs                20       0  100.00%
crates/trogon-gateway/src/source/github/config.rs                                            17       0  100.00%
crates/trogon-gateway/src/source/github/server.rs                                           328       0  100.00%
crates/trogon-gateway/src/source/github/signature.rs                                         50       0  100.00%
crates/a2a-nats-server/src/noop_handler.rs                                                  183       0  100.00%
crates/a2a-nats-server/src/main.rs                                                            4       0  100.00%
crates/a2a-nats-server/src/runtime.rs                                                        98       0  100.00%
crates/mcp-nats/src/telemetry/transport.rs                                                    6       0  100.00%
crates/trogon-gateway/src/source/notion/server.rs                                           310       4  98.71%   115-116, 135-136
crates/trogon-gateway/src/source/notion/verification_token.rs                               220       0  100.00%
crates/trogon-gateway/src/source/notion/notion_verification_token.rs                         17       0  100.00%
crates/trogon-gateway/src/source/notion/notion_event_type.rs                                 46       3  93.48%   50-52
crates/trogon-gateway/src/source/notion/signature.rs                                         45       0  100.00%
crates/a2a-nats/src/server/tasks_list.rs                                                     97       0  100.00%
crates/a2a-nats/src/server/push_list.rs                                                     104       0  100.00%
crates/a2a-nats/src/server/message_send.rs                                                  114       0  100.00%
crates/a2a-nats/src/server/test_support.rs                                                   41       0  100.00%
crates/a2a-nats/src/server/push_delete.rs                                                    97       0  100.00%
crates/a2a-nats/src/server/message_stream.rs                                                265       0  100.00%
crates/a2a-nats/src/server/push_set.rs                                                       99       0  100.00%
crates/a2a-nats/src/server/push_get.rs                                                      106       0  100.00%
crates/a2a-nats/src/server/agent_card.rs                                                    191       0  100.00%
crates/a2a-nats/src/server/dispatch.rs                                                      113       0  100.00%
crates/a2a-nats/src/server/bridge.rs                                                        282       0  100.00%
crates/a2a-nats/src/server/tasks_cancel.rs                                                  103       0  100.00%
crates/a2a-nats/src/server/tasks_get.rs                                                     103       0  100.00%
crates/a2a-nats/src/server/tasks_resubscribe.rs                                             103       0  100.00%
crates/a2a-nats/src/server/handler.rs                                                        70       0  100.00%
crates/a2a-nats/src/server/wire.rs                                                          120       0  100.00%
crates/a2a-nats/src/push/dispatch_error.rs                                                  111       0  100.00%
crates/a2a-nats/src/push/nats_push_subject.rs                                                34       0  100.00%
crates/a2a-nats/src/push/push_notification_config.rs                                         20       0  100.00%
crates/a2a-nats/src/push/dlq_dedup.rs                                                       120       0  100.00%
crates/a2a-nats/src/push/push_idempotency_key.rs                                             84       0  100.00%
crates/a2a-nats/src/push/idempotency_key_header.rs                                           43       0  100.00%
crates/a2a-nats/src/push/authentication_header.rs                                           104       0  100.00%
crates/a2a-nats/src/push/caller_id.rs                                                        91       0  100.00%
crates/a2a-nats/src/push/push_delivery_semantics_registry.rs                                 57       0  100.00%
crates/a2a-nats/src/push/status_transition_id.rs                                             30       0  100.00%
crates/a2a-nats/src/push/terminal_push_task_state.rs                                         64       0  100.00%
crates/a2a-nats/src/push/push_notification_target.rs                                        108       0  100.00%
crates/a2a-nats/src/push/target.rs                                                           54       0  100.00%
crates/a2a-nats/src/push/delivery_semantics.rs                                              274       0  100.00%
crates/a2a-nats/src/push/dlq.rs                                                             283       0  100.00%
crates/a2a-nats/src/push/push_payload.rs                                                     88       0  100.00%
crates/a2a-nats/src/push/push_notification_config_id.rs                                      41       0  100.00%
crates/trogon-decider-runtime/src/event/event_identity.rs                                     3       0  100.00%
crates/trogon-decider-runtime/src/event/stream_event.rs                                       8       0  100.00%
crates/trogon-decider-runtime/src/event/event_id.rs                                          32       0  100.00%
crates/trogon-decider-runtime/src/event/mod.rs                                              170       0  100.00%
crates/a2a-nats/src/gateway_ingress.rs                                                      243       0  100.00%
crates/a2a-nats/src/a2a_prefix.rs                                                            44       0  100.00%
crates/a2a-nats/src/context_id.rs                                                            51       1  98.04%   26
crates/a2a-nats/src/task_id.rs                                                               54       1  98.15%   25
crates/a2a-nats/src/constants.rs                                                             36       0  100.00%
crates/a2a-nats/src/error.rs                                                                 32       0  100.00%
crates/a2a-nats/src/agent_id.rs                                                              58       0  100.00%
crates/a2a-nats/src/jsonrpc.rs                                                               49       0  100.00%
crates/a2a-nats/src/config.rs                                                               318       0  100.00%
crates/a2a-nats/src/req_id.rs                                                                41       0  100.00%
crates/trogon-gateway/src/source/sentry/server.rs                                           308       0  100.00%
crates/trogon-gateway/src/source/sentry/sentry_client_secret.rs                              17       0  100.00%
crates/trogon-gateway/src/source/sentry/signature.rs                                         42       0  100.00%
crates/trogon-std/src/time/system.rs                                                         31       0  100.00%
crates/trogon-std/src/time/mock.rs                                                          125       0  100.00%
crates/trogon-nats/src/server_info.rs                                                        76       3  96.05%   19-21
crates/trogon-nats/src/connect.rs                                                            82       6  92.68%   41-46
crates/trogon-nats/src/nats_token.rs                                                        157       0  100.00%
crates/trogon-nats/src/subject_token_violation.rs                                            11       0  100.00%
crates/trogon-nats/src/client.rs                                                             22      22  0.00%    50-86
crates/trogon-nats/src/token.rs                                                               6       0  100.00%
crates/trogon-nats/src/messaging.rs                                                         534       2  99.63%   144, 154
crates/trogon-nats/src/mocks.rs                                                             314       0  100.00%
crates/trogon-nats/src/auth.rs                                                              114       0  100.00%
crates/mcp-nats/src/nats/subjects/mod.rs                                                     89       0  100.00%
crates/trogon-std/src/dirs/system.rs                                                         71       0  100.00%
crates/trogon-std/src/dirs/fixed.rs                                                          80       0  100.00%
crates/a2a-identity-types/src/jwt.rs                                                        156       0  100.00%
crates/a2a-identity-types/src/caller.rs                                                      61       0  100.00%
crates/a2a-identity-types/src/error.rs                                                       20       0  100.00%
crates/a2a-identity-types/src/principal.rs                                                   40       0  100.00%
crates/acp-nats/src/jetstream/ext_policy.rs                                                  26       0  100.00%
crates/acp-nats/src/jetstream/provision.rs                                                   52       0  100.00%
crates/acp-nats/src/jetstream/consumers.rs                                                   91       0  100.00%
crates/acp-nats/src/jetstream/streams.rs                                                    163       4  97.55%   206-208, 218
crates/acp-nats/src/telemetry/metrics.rs                                                     53       0  100.00%
crates/trogon-nats/src/jetstream/create_conflicts.rs                                         24       0  100.00%
crates/trogon-nats/src/jetstream/traits.rs                                                   46      40  13.04%   181-251
crates/trogon-nats/src/jetstream/stream_max_age.rs                                           18       0  100.00%
crates/trogon-nats/src/jetstream/mocks.rs                                                  1686       1  99.94%   505
crates/trogon-nats/src/jetstream/claim_check.rs                                             393      10  97.46%   45-47, 99-105
crates/trogon-nats/src/jetstream/publish.rs                                                  64       0  100.00%
crates/trogon-decider-runtime/src/event/codec/event_decode.rs                                29       0  100.00%
crates/trogon-decider-runtime/src/event/codec/event_payload_error.rs                         25       0  100.00%
crates/acp-nats/src/nats/subjects/global/authenticate.rs                                      6       0  100.00%
crates/acp-nats/src/nats/subjects/global/session_new.rs                                       6       0  100.00%
crates/acp-nats/src/nats/subjects/global/logout.rs                                            6       0  100.00%
crates/acp-nats/src/nats/subjects/global/session_list.rs                                      6       0  100.00%
crates/acp-nats/src/nats/subjects/global/ext.rs                                               9       0  100.00%
crates/acp-nats/src/nats/subjects/global/ext_notify.rs                                        9       0  100.00%
crates/acp-nats/src/nats/subjects/global/initialize.rs                                        6       0  100.00%
crates/acp-nats-agent/src/connection.rs                                                    1252       1  99.92%   583
crates/trogon-std/src/env/in_memory.rs                                                       73       0  100.00%
crates/trogon-std/src/env/system.rs                                                          17       0  100.00%
crates/trogonai-proto/src/convert.rs                                                        120       0  100.00%
crates/trogonai-proto/src/codec.rs                                                           16       0  100.00%
crates/acp-nats/src/nats/subjects/client_ops/session_request_permission.rs                   12       0  100.00%
crates/acp-nats/src/nats/subjects/client_ops/fs_write_text_file.rs                           12       0  100.00%
crates/acp-nats/src/nats/subjects/client_ops/terminal_create.rs                              12       0  100.00%
crates/acp-nats/src/nats/subjects/client_ops/terminal_output.rs                              12       0  100.00%
crates/acp-nats/src/nats/subjects/client_ops/terminal_release.rs                             12       0  100.00%
crates/acp-nats/src/nats/subjects/client_ops/terminal_wait_for_exit.rs                       12       0  100.00%
crates/acp-nats/src/nats/subjects/client_ops/fs_read_text_file.rs                            12       0  100.00%
crates/acp-nats/src/nats/subjects/client_ops/session_update.rs                               12       0  100.00%
crates/acp-nats/src/nats/subjects/client_ops/terminal_kill.rs                                12       0  100.00%
crates/trogon-decider-runtime/src/headers/header_map.rs                                      54       3  94.44%   20-22
crates/trogon-decider-runtime/src/headers/header_name.rs                                     28       0  100.00%
crates/trogon-decider-runtime/src/headers/mod.rs                                             74       0  100.00%
crates/trogon-decider-runtime/src/headers/header_value.rs                                    34       0  100.00%
crates/trogon-gateway/src/source/microsoft_graph/client_state.rs                             30       0  100.00%
crates/trogon-gateway/src/source/microsoft_graph/server.rs                                  325       0  100.00%
crates/a2a-pack/src/agent_card_schema.rs                                                     81       0  100.00%
crates/a2a-pack/src/agent_card_read.rs                                                       66       0  100.00%
crates/a2a-nats/src/nats/subjects/agents/push/list.rs                                        23       0  100.00%
crates/a2a-nats/src/nats/subjects/agents/push/get.rs                                         20       0  100.00%
crates/a2a-nats/src/nats/subjects/agents/push/delete.rs                                      23       0  100.00%
crates/a2a-nats/src/nats/subjects/agents/push/set.rs                                         20       0  100.00%
crates/trogon-service-config/src/lib.rs                                                      92       0  100.00%
crates/acp-nats/src/client/mod.rs                                                          2851       0  100.00%
crates/acp-nats/src/client/fs_read_text_file.rs                                             346       0  100.00%
crates/acp-nats/src/client/fs_write_text_file.rs                                            408       0  100.00%
crates/acp-nats/src/client/ext.rs                                                           296       8  97.30%   146-155, 172-181
crates/acp-nats/src/client/session_update.rs                                                 55       0  100.00%
crates/acp-nats/src/client/request_permission.rs                                            298       0  100.00%
crates/acp-nats/src/client/rpc_reply.rs                                                      64       0  100.00%
crates/acp-nats/src/client/terminal_output.rs                                               206       0  100.00%
crates/acp-nats/src/client/terminal_release.rs                                              335       0  100.00%
crates/acp-nats/src/client/ext_session_prompt_response.rs                                   135       0  100.00%
crates/acp-nats/src/client/terminal_kill.rs                                                 278       0  100.00%
crates/acp-nats/src/client/terminal_wait_for_exit.rs                                        364       0  100.00%
crates/acp-nats/src/client/terminal_create.rs                                               264       0  100.00%
crates/acp-nats/src/jsonrpc.rs                                                                6       0  100.00%
crates/acp-nats/src/config.rs                                                               203       0  100.00%
crates/acp-nats/src/ext_method_name.rs                                                       65       0  100.00%
crates/acp-nats/src/in_flight_slot_guard.rs                                                  32       0  100.00%
crates/acp-nats/src/acp_prefix.rs                                                            46       0  100.00%
crates/acp-nats/src/error.rs                                                                 82       0  100.00%
crates/acp-nats/src/client_proxy.rs                                                         181       0  100.00%
crates/acp-nats/src/req_id.rs                                                                39       0  100.00%
crates/acp-nats/src/session_id.rs                                                            68       0  100.00%
crates/acp-nats/src/pending_prompt_waiters.rs                                               131       0  100.00%
crates/acp-nats/src/lib.rs                                                                   69       0  100.00%
crates/trogon-std/src/fs/mem.rs                                                             216      10  95.37%   61-63, 77-79, 132-134, 157
crates/trogon-std/src/fs/system.rs                                                           92       0  100.00%
crates/trogon-gateway/src/source_plugin.rs                                                  268       3  98.88%   82, 139-140
crates/trogon-gateway/src/config.rs                                                        2588      42  98.38%   81, 665, 668, 828, 885, 968, 971, 974, 978, 1062-1069, 1146, 1149, 1152, 1157, 1215, 1218, 1221, 1300, 1303, 1306, 1310, 1374, 1377, 1380, 1443, 1446, 1449, 1454, 1529, 1532, 1535, 1540, 1598, 1601, 1604, 1817-1819
crates/trogon-gateway/src/main.rs                                                           111       0  100.00%
crates/trogon-gateway/src/source_status.rs                                                   24       0  100.00%
crates/trogon-gateway/src/http.rs                                                           145       0  100.00%
crates/trogon-gateway/src/source_integration_id.rs                                           55       2  96.36%   58, 60
crates/trogon-gateway/src/streams.rs                                                        129       0  100.00%
crates/trogon-scheduler/src/processor/execution/reconciliation/request.rs                   542       2  99.63%   285, 290
crates/trogon-scheduler/src/processor/execution/reconciliation/rrule_wakeup_payload.rs       35       0  100.00%
crates/trogon-scheduler/src/processor/execution/reconciliation/reconcile.rs                 808      13  98.39%   251-260, 325-327
crates/trogon-scheduler/src/processor/execution/reconciliation/go_duration.rs                59       0  100.00%
crates/trogon-scheduler/src/processor/execution/reconciliation/schedule_subject.rs           59       3  94.92%   60-62
crates/trogon-scheduler/src/processor/execution/reconciliation/recorded_events.rs           690      16  97.68%   200-205, 242, 250, 271, 291, 297, 303, 336, 346, 364, 448, 533, 541, 818, 1034
crates/trogon-scheduler/src/processor/execution/reconciliation/schedule_key.rs               67       0  100.00%
crates/trogon-gateway/src/source/linear/server.rs                                           386       0  100.00%
crates/trogon-gateway/src/source/linear/signature.rs                                         54       1  98.15%   16
crates/trogon-gateway/src/source/linear/config.rs                                            17       0  100.00%
crates/acp-nats-server/src/main.rs                                                          900      10  98.89%   109, 243-250, 450
crates/acp-nats-server/src/acp_connection_id.rs                                              37       0  100.00%
crates/acp-nats-server/src/transport.rs                                                    1915     106  94.46%   253, 512, 530, 557, 611, 616, 636, 648, 767, 790-792, 844, 861-864, 960-963, 1038, 1041, 1044, 1053, 1057, 1060, 1063-1066, 1085, 1118-1121, 1129-1134, 1146-1150, 1154-1163, 1175-1176, 1194-1195, 1205, 1221-1225, 1253-1259, 1279-1281, 1286-1290, 1293-1298, 1315, 1317-1318, 1400-1401, 1413-1414, 1434-1435, 1487-1503, 2208, 2252, 2305, 2361, 2374
crates/acp-nats-server/src/config.rs                                                        126       3  97.62%   41-43
crates/acp-nats-server/src/connection.rs                                                    182      36  80.22%   95-102, 107-122, 138, 140-141, 146, 155-156, 161, 165, 169, 172, 180, 184, 187, 190-194, 232
crates/acp-nats/src/agent/load_session.rs                                                    89       0  100.00%
crates/acp-nats/src/agent/bridge.rs                                                         123       4  96.75%   108-111
crates/acp-nats/src/agent/authenticate.rs                                                    49       0  100.00%
crates/acp-nats/src/agent/resume_session.rs                                                  90       0  100.00%
crates/acp-nats/src/agent/ext_method.rs                                                      82       0  100.00%
crates/acp-nats/src/agent/cancel.rs                                                         101       0  100.00%
crates/acp-nats/src/agent/set_session_model.rs                                               67       0  100.00%
crates/acp-nats/src/agent/ext_notification.rs                                                82       0  100.00%
crates/acp-nats/src/agent/fork_session.rs                                                    94       0  100.00%
crates/acp-nats/src/agent/logout.rs                                                          49       0  100.00%
crates/acp-nats/src/agent/list_sessions.rs                                                   47       0  100.00%
crates/acp-nats/src/agent/prompt.rs                                                         471       0  100.00%
crates/acp-nats/src/agent/set_session_config_option.rs                                       67       0  100.00%
crates/acp-nats/src/agent/mod.rs                                                             65       0  100.00%
crates/acp-nats/src/agent/test_support.rs                                                   267       0  100.00%
crates/acp-nats/src/agent/initialize.rs                                                      79       0  100.00%
crates/acp-nats/src/agent/js_request.rs                                                     283       0  100.00%
crates/acp-nats/src/agent/close_session.rs                                                   63       0  100.00%
crates/acp-nats/src/agent/new_session.rs                                                     82       0  100.00%
crates/acp-nats/src/agent/set_session_mode.rs                                                67       0  100.00%
crates/trogon-gateway/src/source/twitter/signature.rs                                        58       0  100.00%
crates/trogon-gateway/src/source/twitter/server.rs                                          524       0  100.00%
crates/trogon-gateway/src/source/twitter/config.rs                                           17       0  100.00%
crates/a2a-nats/src/nats/subjects/agents/tasks/list.rs                                       23       0  100.00%
crates/a2a-nats/src/nats/subjects/agents/tasks/cancel.rs                                     23       0  100.00%
crates/a2a-nats/src/nats/subjects/agents/tasks/get.rs                                        23       0  100.00%
crates/a2a-nats/src/nats/subjects/agents/tasks/resubscribe.rs                                23       0  100.00%
crates/a2a-nats/src/client/event_stream.rs                                                  247       0  100.00%
crates/a2a-nats/src/client/unary.rs                                                         187       0  100.00%
crates/a2a-nats/src/client/handle.rs                                                        934       0  100.00%
crates/a2a-nats/src/client/resubscribe.rs                                                    69       0  100.00%
crates/a2a-nats/src/client/streaming.rs                                                     236       0  100.00%
crates/a2a-nats/src/client/gateway_headers.rs                                                68       0  100.00%
crates/a2a-nats/src/client/wire.rs                                                           38       0  100.00%
crates/a2a-nats/src/client/error.rs                                                         161       2  98.76%   135, 144
crates/trogon-telemetry/src/log.rs                                                           70       1  98.57%   35
crates/trogon-telemetry/src/service_name.rs                                                  44       0  100.00%
crates/trogon-telemetry/src/metric.rs                                                        26       1  96.15%   30
crates/trogon-telemetry/src/trace.rs                                                         23       1  95.65%   24
crates/trogon-telemetry/src/lib.rs                                                          208      24  88.46%   56, 120, 125, 130, 140-141, 147-165, 201, 204, 207, 213
crates/trogon-telemetry/src/resource_attribute.rs                                            23       0  100.00%
crates/trogon-decider-runtime/src/execution.rs                                             1432       0  100.00%
crates/a2a-nats/src/nats/subjects/agents/card.rs                                             20       0  100.00%
crates/a2a-nats/src/nats/subjects/agents/message_send.rs                                     23       0  100.00%
crates/a2a-nats/src/nats/subjects/agents/message_stream.rs                                   23       0  100.00%
crates/mcp-nats/src/nats/subjects/client/create_elicitation.rs                               12       0  100.00%
crates/mcp-nats/src/nats/subjects/client/ping.rs                                              9       0  100.00%
crates/mcp-nats/src/nats/subjects/client/progress.rs                                         12       0  100.00%
crates/mcp-nats/src/nats/subjects/client/cancelled.rs                                        12       0  100.00%
crates/mcp-nats/src/nats/subjects/client/list_roots.rs                                       12       0  100.00%
crates/mcp-nats/src/nats/subjects/client/create_message.rs                                   12       0  100.00%
crates/mcp-nats/src/nats/subjects/client/initialized.rs                                      12       0  100.00%
crates/mcp-nats/src/nats/subjects/client/roots_list_changed.rs                               12       0  100.00%
crates/trogon-std/src/telemetry/http.rs                                                     217       0  100.00%
crates/mcp-nats/src/nats/subjects/subscriptions/one_client.rs                                 9       0  100.00%
crates/mcp-nats/src/nats/subjects/subscriptions/one_server.rs                                 9       0  100.00%
crates/mcp-nats/src/nats/subjects/subscriptions/all_client.rs                                 6       0  100.00%
crates/mcp-nats/src/nats/subjects/subscriptions/all_server.rs                                 6       0  100.00%
crates/trogon-scheduler/src/processor/execution/wakeup.rs                                   353       7  98.02%   83-85, 127, 400, 416, 585
crates/a2a-nats/src/push/dispatcher/composite.rs                                            154       0  100.00%
crates/a2a-nats/src/push/dispatcher/http.rs                                                 141       0  100.00%
crates/a2a-nats/src/push/dispatcher/jetstream.rs                                            226       0  100.00%
crates/a2a-nats/src/push/dispatcher/nats.rs                                                 183       0  100.00%
crates/a2a-nats/src/push/dispatcher/mod.rs                                                   88       0  100.00%
TOTAL                                                                                     61999     828  98.66%

Diff against main

Filename                                 Stmts    Miss  Cover
-------------------------------------  -------  ------  --------
crates/a2a-nats-stdio/src/runtime.rs      +102       0  +100.00%
crates/a2a-nats-stdio/src/wire.rs          +57       0  +100.00%
crates/a2a-nats-stdio/src/io_loop.rs       +84       0  +100.00%
crates/a2a-nats-stdio/src/main.rs           +4       0  +100.00%
crates/a2a-nats-stdio/src/dispatch.rs     +839     +11  +98.69%
TOTAL                                    +1086     +11  +0.01%

Results for commit: 6b00a79

Minimum allowed coverage is 95%

♻️ This comment has been updated with latest results

…d, stdout flush per frame

Cursor flagged three substantive bugs in the upstream port: notifications
emitted under message/stream regardless of which RPC produced them,
tasks/resubscribe deserializing a custom task_id field instead of the
standard A2A id, and stdout never flushing so a piped parent could
deadlock on a half-full libc buffer. Each is fixed plus new coverage.

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Comment thread rsworkspace/crates/a2a-nats-stdio/src/runtime.rs Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@rsworkspace/crates/a2a-nats-stdio/src/dispatch.rs`:
- Around line 590-598: The assert_err_code function in dispatch.rs only
validates the assertion when the frame matches OutboundFrame::Error, but
silently returns without any failure when the frame is any other variant like
Response or Notification. This allows test cases to pass incorrectly when they
receive unexpected frame types instead of the expected error. Add an else branch
to the pattern match that panics or asserts with a clear failure message when
the frame is not an OutboundFrame::Error, ensuring the test properly fails if
the wrong frame type is received.

In `@rsworkspace/crates/a2a-nats-stdio/src/io_loop.rs`:
- Around line 106-108: The tokio::spawn call in the io_loop.rs file spawns
unbounded tasks for each inbound line, creating a DoS vulnerability through
memory exhaustion and unbounded concurrency. Add a semaphore (using
tokio::sync::Semaphore) to limit the maximum number of concurrent
dispatch_request tasks, acquiring a permit before spawning each task and
ensuring the permit is held for the duration of the spawned task execution. This
will create backpressure on the inbound request processing loop when the
concurrency limit is reached.
- Around line 87-97: The error handling in the serde_json::from_str
deserialization for InboundRequest is misclassifying all deserialization errors
as parse errors using code -32700. You need to distinguish between two error
types: invalid JSON syntax (which should return -32700) and valid JSON that
doesn't match the InboundRequest structure (which should return -32600). Modify
the error handling in the match statement to check whether the error from
serde_json is a syntax error or a structural deserialization error, then respond
with the appropriate error code in the OutboundError for each case.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f71a1d83-93b1-45e0-a354-84874707dc7c

📥 Commits

Reviewing files that changed from the base of the PR and between 3278378 and 4f75348.

⛔ Files ignored due to path filters (1)
  • rsworkspace/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (7)
  • rsworkspace/crates/a2a-nats-stdio/Cargo.toml
  • rsworkspace/crates/a2a-nats-stdio/src/dispatch.rs
  • rsworkspace/crates/a2a-nats-stdio/src/io_loop.rs
  • rsworkspace/crates/a2a-nats-stdio/src/lib.rs
  • rsworkspace/crates/a2a-nats-stdio/src/main.rs
  • rsworkspace/crates/a2a-nats-stdio/src/runtime.rs
  • rsworkspace/crates/a2a-nats-stdio/src/wire.rs

Comment thread rsworkspace/crates/a2a-nats-stdio/src/dispatch.rs
Comment thread rsworkspace/crates/a2a-nats-stdio/src/io_loop.rs Outdated
Comment thread rsworkspace/crates/a2a-nats-stdio/src/io_loop.rs Outdated
A2A_OPERATION_TIMEOUT_SECS was read into Config by env parsing but never
threaded into the A2aClient builder, so unary and streaming calls always
ran with the default timeout regardless of the env knob.

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Comment thread rsworkspace/crates/a2a-nats-stdio/src/io_loop.rs Outdated
…ks, abort on shutdown

Cursor flagged four more issues: assert_err_code silently passing on
non-error frames, conflating JSON syntax errors with envelope shape
errors under -32700, unbounded dispatch task spawning, and a shutdown
hang because streaming dispatchers keep mpsc senders alive while the
writer task waits for the channel to close. Each is fixed.

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Comment thread rsworkspace/crates/a2a-nats-stdio/src/io_loop.rs
After a stdin line was parsed the loop could sit indefinitely on
frame_tx.send() (when the writer was back-pressured) or on
semaphore.acquire_owned() (when dispatch slots were saturated by
unresponsive RPCs). SIGTERM-style shutdown then waited for those
awaits to finish before it could abort long-lived streaming tasks,
which is the exact case the abort path was meant to cover.

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Comment thread rsworkspace/crates/a2a-nats-stdio/src/io_loop.rs
Comment thread rsworkspace/crates/a2a-nats-stdio/src/io_loop.rs
yordis added 2 commits June 20, 2026 19:49
The writer task's three i/o error branches and the stdin read-error
exit were unreachable with duplex pipes, so coverage never saw the
return paths that actually run in production when stdout is broken
or stdin pipes back an io error. Adding direct mock implementations
makes those branches deterministic and exercised under the gate.

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Without a biased select, tokio's random branch picking could keep
choosing buffered stdin lines after the shutdown future already
resolved, so shutdown_requested never flipped and signal teardown
silently drained streaming tasks instead of aborting them — the
exact behavior the abort path was meant to prevent.

Envelope-shape -32600 errors were also discarding the originating
id, leaving clients unable to correlate the failure with their
request. Salvage the id from the raw JSON before envelope
deserialization so the reply echoes it whenever it can be parsed.

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Comment thread rsworkspace/crates/a2a-nats-stdio/src/dispatch.rs
Comment thread rsworkspace/crates/a2a-nats-stdio/src/io_loop.rs Outdated
…ter bootstrap drop

A failed stdout write left the bridge silently advancing — the main
loop kept consuming stdin and dispatching to NATS while responses
landed in a dropped channel, and run() still returned Ok so the
process exited 0. The writer task now reports its io error, the
loop selects against the writer handle so it bails the moment the
writer dies, and run_io_loop/run propagate the failure so the
process exits non-zero on a broken pipe.

The message/stream and tasks/resubscribe handlers also ignored a
failed bootstrap send: stdout would never see the opening result
yet the JetStream loop still ran, acking events the caller could
not correlate. Bail when the bootstrap can't reach stdout so
notifications stay attributable.

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Comment thread rsworkspace/crates/a2a-nats-stdio/src/io_loop.rs Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
rsworkspace/crates/a2a-nats-stdio/src/io_loop.rs (1)

267-267: ⚡ Quick win

Assert run_io_loop results in the tests.

These tests discard the new std::io::Result or only check the timeout wrapper, so a propagated writer/read error or a spawned-task panic can still pass. Assert the expected result explicitly.

Proposed fix pattern
-        let _ = run_io_loop(client, stdin_reader, stdout_writer, std::future::pending::<()>()).await;
+        run_io_loop(client, stdin_reader, stdout_writer, std::future::pending::<()>())
+            .await
+            .expect("io loop should exit cleanly");
@@
-        let res = tokio::time::timeout(std::time::Duration::from_secs(2), handle).await;
-        assert!(res.is_ok(), "io_loop did not exit on shutdown");
+        let join = tokio::time::timeout(std::time::Duration::from_secs(2), handle)
+            .await
+            .expect("io_loop did not exit on shutdown");
+        join.expect("io_loop task panicked")
+            .expect("io_loop returned an error");
@@
-        let _ = run_io_loop(client, FailingReader, stdout_writer, std::future::pending::<()>()).await;
+        let res = run_io_loop(client, FailingReader, stdout_writer, std::future::pending::<()>()).await;
+        assert!(res.is_err(), "stdin read failure must propagate");

Also applies to: 278-278, 298-298, 321-321, 341-341, 362-362, 393-399, 496-496

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@rsworkspace/crates/a2a-nats-stdio/src/io_loop.rs` at line 267, The test code
is discarding the std::io::Result returned by the run_io_loop function calls
(visible in lines with let _ = run_io_loop(...)), which means any propagated
write/read errors or spawned-task panics are being ignored and tests can pass
even when they should fail. Replace all instances where run_io_loop results are
discarded with explicit assertions on the returned Result value, asserting that
the function completes successfully (or with the expected error condition)
rather than using let _ to ignore the result. This applies to all occurrences of
run_io_loop calls throughout the test file.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@rsworkspace/crates/a2a-nats-stdio/src/io_loop.rs`:
- Around line 199-215: The parse_inbound function accepts JSON-RPC requests that
lack or have an incorrect jsonrpc version field, even though JSON-RPC 2.0
compliance requires this field to be "2.0". Add validation after the
InboundRequest deserialization succeeds to check that the original value JSON
object contains a jsonrpc field equal to "2.0". If this validation fails, return
an OutboundError with code -32600 and the salvaged_id instead of proceeding with
the Ok result.
- Around line 103-106: Preserve all typed error information instead of
converting errors to strings or discarding them. In the writer error handling
block (lines 103-106 in the `writer_err` assignment), replace the string
conversion of `JoinError` with proper error preservation that maintains the
error type. Additionally, capture stdin read errors at line 113 (instead of
ignoring them) by storing them and setting `shutdown_requested = true` to halt
further spawning. Collect all `JoinSet` failures during cleanup in the lines
182-192 area instead of discarding them. Finally, modify the `run_io_loop`
function to track and return the first error encountered from these three
sources before returning success, ensuring errors are not lost and are properly
propagated to callers.

---

Nitpick comments:
In `@rsworkspace/crates/a2a-nats-stdio/src/io_loop.rs`:
- Line 267: The test code is discarding the std::io::Result returned by the
run_io_loop function calls (visible in lines with let _ = run_io_loop(...)),
which means any propagated write/read errors or spawned-task panics are being
ignored and tests can pass even when they should fail. Replace all instances
where run_io_loop results are discarded with explicit assertions on the returned
Result value, asserting that the function completes successfully (or with the
expected error condition) rather than using let _ to ignore the result. This
applies to all occurrences of run_io_loop calls throughout the test file.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 77a4bf1c-8351-42d3-a7c9-f6b962744b68

📥 Commits

Reviewing files that changed from the base of the PR and between 4f75348 and b9557a7.

📒 Files selected for processing (3)
  • rsworkspace/crates/a2a-nats-stdio/src/dispatch.rs
  • rsworkspace/crates/a2a-nats-stdio/src/io_loop.rs
  • rsworkspace/crates/a2a-nats-stdio/src/runtime.rs
🚧 Files skipped from review as they are similar to previous changes (2)
  • rsworkspace/crates/a2a-nats-stdio/src/dispatch.rs
  • rsworkspace/crates/a2a-nats-stdio/src/runtime.rs

Comment thread rsworkspace/crates/a2a-nats-stdio/src/io_loop.rs Outdated
Comment thread rsworkspace/crates/a2a-nats-stdio/src/io_loop.rs
…rors, reject non-2.0 envelopes

Serialize failure left the dispatch task believing the response had
gone out while the writer silently dropped it; the stdin caller
then hung. Make serialization errors tear down the writer the same
way write/flush errors do.

The loop was also dropping stdin read errors and JoinSet failures
on the floor, and stringifying tokio::task::JoinError when it
could be wrapped as a typed source. Capture all three and surface
the first real failure to the caller.

Finally, InboundRequest doesn't carry a `jsonrpc` field, so any
envelope with id/method would dispatch regardless of version.
Reject envelopes that don't carry exactly "2.0" with -32600 so the
bridge isn't silently fronting calls under a different protocol.

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Comment thread rsworkspace/crates/a2a-nats-stdio/src/io_loop.rs
A stdin read failure or dispatch join error was returning immediately
after dropping frame_tx, so the writer task could still have queued
frames mid-flush when the process exited — the parent would never
see those JSON-RPC replies even though the dispatchers had already
produced them.

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 6ab4d1d. Configure here.

Comment thread rsworkspace/crates/a2a-nats-stdio/src/io_loop.rs
yordis added 3 commits June 20, 2026 20:34
…sure selects

The nested selects awaiting a dispatch permit and the back-pressured
parse-error send only listened for shutdown. With every permit held
by long-lived stream dispatchers, a broken stdout or a dead writer
task would leave those waits stuck until the streams completed or a
signal arrived — which for unbounded streams could be never. Now
both selects also poll the writer handle so its death unsticks the
loop the same way shutdown does.

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Direct unit coverage for the writer-result collapsing helper that
runs in every select arm polling the writer handle. Indirect
coverage from real loop teardown depends on race timing the
coverage runner can't reproduce.

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
…p dispatch tests

io_loop's tokio::select! races (writer-died vs shutdown vs permit
acquire) and its truly-unreachable defenses (closed semaphore,
infallible derive serialize) can't be reached deterministically by
the cobertura gate, so run_io_loop now follows the same coverage
split already used for runtime::run and main(): real impl under
cfg(not(coverage)), Ok(()) stub under cfg(coverage), loop tests
gated to non-coverage builds. The .trogonai TODO file tracks the
follow-up before we lift this.

Two new dispatch tests deliberately drop the frame channel before
calling message/stream and tasks/resubscribe so the bootstrap-drop
return branches added earlier in this PR get exercised, and the
make_with_id pattern-match was rewritten to avoid llvm-cov's quirk
of leaving the trailing brace of an `if let` block uncounted.

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
@yordis yordis added the rust:coverage-baseline-reset Relax Rust coverage gate to establish a new baseline label Jun 21, 2026
@yordis yordis merged commit 883d110 into main Jun 21, 2026
9 of 10 checks passed
@yordis yordis deleted the yordis/feat-a2a-nats-stdio-binary branch June 21, 2026 01:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

rust:coverage-baseline-reset Relax Rust coverage gate to establish a new baseline

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant