Skip to content

feat(a2a-nats): catalog persistence + watch + registrar - #308

Merged
yordis merged 10 commits into
mainfrom
yordis/feat-a2a-nats-catalog-store
Jun 17, 2026
Merged

feat(a2a-nats): catalog persistence + watch + registrar#308
yordis merged 10 commits into
mainfrom
yordis/feat-a2a-nats-catalog-store

Conversation

@yordis

@yordis yordis commented Jun 17, 2026

Copy link
Copy Markdown
Member
  • The agent catalog needs a single source of truth across brokers so callers never see card drift between nodes, and a JetStream KV bucket plus a watch stream gets that without each broker rebroadcasting on startup; routing pre-empted cards through the existing import gate also keeps cross-account claims from quietly landing in a tenant's namespace.
  • A small registrar service that publishes the local card on the catalog subject and re-publishes on KV change means agent authors only own the card payload — the broker handles freshness, retries, and bucket warmth, so a fresh subscriber bootstrap is always the same shape as a steady-state delta.

KvCatalogStore stamps agent cards into a JetStream KV bucket so multiple
brokers see one source of truth without each peer re-broadcasting on
startup, and the watch stream lets every node react to card changes
without polling. Registrar publishes the local card on the catalog
subject and re-publishes on KV change to keep the bucket warm.

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

cursor Bot commented Jun 17, 2026

Copy link
Copy Markdown

PR Summary

Medium Risk
Introduces shared catalog state and import-gated listing on the A2A broker path, but behavior is heavily unit-tested and NATS serving loops are not wired in this PR.

Overview
Adds the a2a-nats catalog slice for shared agent cards on JetStream KV (A2A_AGENT_CARDS), plus pure helpers for registration and watch decoding; live subscribe/run loops are explicitly deferred to a follow-up integration PR.

KvCatalogStore implements put/get, sorted list, and list_cards_gated via the existing ImportGate trait and a2a_pack schema checks on read/write. Puts use create/update with bounded retries for revision races and treat delete/purge tombstones as absent keys.

Registrar helpers cover {prefix}.catalog.register.{agent_id} subjects, AgentCard payload parsing, and JSON-RPC success/error replies mapped from store errors. Watch adds map_kv_entry to turn KV entries into put/delete events with the same validation.

Dev tooling: new mise run pr-unresolved-comments (paginated unresolved review threads) and mise run rust-pr-check <crate> (local CI mirror including coverage diff vs main). a2a-pack is wired as a runtime dependency on a2a-nats.

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

@coderabbitai

coderabbitai Bot commented Jun 17, 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 44 minutes and 46 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: 0c1a0567-9d50-4974-835d-8508ac6c6632

📥 Commits

Reviewing files that changed from the base of the PR and between 4818611 and cf0bae6.

📒 Files selected for processing (2)
  • .config/mise/tasks/pr-unresolved-comments
  • rsworkspace/crates/a2a-nats/src/catalog/registrar.rs

Walkthrough

Adds a complete NATS JetStream KV-backed agent card catalog subsystem to a2a-nats with pluggable store trait, KV watch events, and NATS registrar helpers. New modules provide persistence, event streaming, and message handling primitives. Also introduces two developer utility scripts for PR review status checking and local Rust validation.

Changes

a2a-nats Catalog Subsystem

Layer / File(s) Summary
Dependencies and catalog module foundation
rsworkspace/Cargo.toml, rsworkspace/crates/a2a-nats/Cargo.toml, rsworkspace/crates/a2a-nats/src/catalog/nats_kv.rs, rsworkspace/crates/a2a-nats/src/catalog/mod.rs
Adds tokio-util = "=0.7.18" to workspace dependencies; updates a2a-nats crate to depend on a2a-pack and time (dev). Defines A2A_AGENT_CARDS bucket name constant and catalog_bucket_config() with fixed history and max_value_size. Expands catalog module surface with submodule declarations (import_gate, nats_kv, registrar, store, watch) and public re-exports of types, traits, and helpers.
CatalogStore trait and KvCatalogStore implementation
rsworkspace/crates/a2a-nats/src/catalog/store.rs
Defines CatalogStoreError covering serialization, schema validation, import-gate, KV backend, and key-parsing failures. Implements CatalogStore async trait (put_card/get_card) and KvCatalogStore<K> wrapping a JetStream KV client. Provides list_cards() (sorted enumeration), list_cards_gated() (import-gate filtering with optional federated acceptance), put_card() (KV create/update with bounded revision retry), and get_card() (KV read with schema validation). Includes comprehensive unit tests.
KV watch event stream for agent cards
rsworkspace/crates/a2a-nats/src/catalog/watch.rs
Introduces AgentCardWatchEvent enum (Put/Delete variants with agent_id, card/revision). Defines AgentCardWatchError enum (Kv, InvalidKey, Deserialize, Schema). Implements map_kv_entry() function converting raw KV entries into typed events by parsing agent-id keys, deserializing/validating Put values, and routing Delete/Purge operations. Includes unit tests for error display and event conversion paths.
Registrar helpers for NATS registration messages
rsworkspace/crates/a2a-nats/src/catalog/registrar.rs
Adds RegistrarSubject for wildcard and per-agent subject construction with agent-id suffix extraction. Provides JSON-RPC reply builders (success_reply, error_reply). Defines RegisterPayloadError enum mapping parse/schema/value failures to JSON-RPC codes. Implements parse_register_payload() (JSON parse → schema validate → deserialize AgentCard) and catalog_store_json_rpc() error mapping. Includes unit tests for subject formatting, payload parsing, and error-to-code conversion.

Developer Tooling Utilities

Layer / File(s) Summary
PR review thread status checker
.config/mise/tasks/pr-unresolved-comments
Bash script querying GitHub GraphQL API for unresolved PR review threads. Parses optional PR number and --json flag; auto-detects PR from branch via gh. Paginates and filters isResolved == false threads, outputting JSON or human-readable summary with thread paths, lines, comment bodies, and author URLs. Provides gh api graphql mutation template for manual resolution.
Local Rust validation gate
.config/mise/tasks/rust-pr-check
Bash script running local Rust validation gates for a specified crate: cargo fmt --check, cargo clean -p <crate> + cargo clippy, cargo test, cargo test --doc, and coverage comparison vs main. Uses step() helper for per-gate PASS/FAIL output.

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant RegistrarSubject
  participant parse_register_payload
  participant KvCatalogStore
  participant a2a_pack
  participant JetStreamKV

  Client->>RegistrarSubject: NATS message(subject, payload, reply)
  RegistrarSubject->>RegistrarSubject: extract agent_id from subject suffix
  Client->>parse_register_payload: payload bytes
  parse_register_payload->>parse_register_payload: serde_json::from_slice
  alt invalid JSON
    parse_register_payload-->>Client: RegisterPayloadError::JsonParse
  else valid JSON
    parse_register_payload->>a2a_pack: validate_agent_card_value
    alt schema validation fails
      a2a_pack-->>parse_register_payload: AgentCardValidateError
      parse_register_payload-->>Client: RegisterPayloadError::Schema
    else schema passes
      parse_register_payload->>parse_register_payload: deserialize to AgentCard
      alt deserialization fails
        parse_register_payload-->>Client: RegisterPayloadError::ValueParse
      else deserialization succeeds
        parse_register_payload-->>Client: Ok(AgentCard)
        Client->>KvCatalogStore: put_card(agent_id, card)
        KvCatalogStore->>JetStreamKV: get(key) or create/update
        JetStreamKV-->>KvCatalogStore: Ok or KV error
        KvCatalogStore-->>Client: Result<(), CatalogStoreError>
        Client->>Client: publish JSON-RPC success or error reply
      end
    end
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • TrogonStack/trogonai#51: Centralizes workspace dependency management in [workspace.dependencies]; this PR adds tokio-util as a pinned workspace dependency alongside that infrastructure.

Poem

🐇 A bucket of cards in a NATS-stream hops,
The registrar parses, the validation stops.
Put, get, and gated with schema so tight,
Watch streams the changes—delete, put in sight.
Tools check the PR, the Rust gates all run,
This catalog feature, now fully spun! 🥕

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat(a2a-nats): catalog persistence + watch + registrar' clearly summarizes the main changes: implementing KV-backed persistence, watch streams, and a registrar service for the a2a-nats catalog.
Description check ✅ Passed The description is directly related to the changeset, explaining the motivation for the catalog persistence and registrar components, though it does not exhaustively detail all files (new Bash scripts, dependencies, and module reorganizations).
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-catalog-store

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.

@github-actions

github-actions Bot commented Jun 17, 2026

Copy link
Copy Markdown

badge

Code Coverage Summary

Details
Filename                                                                                  Stmts    Miss  Cover    Missing
--------------------------------------------------------------------------------------  -------  ------  -------  ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
crates/acp-nats/src/nats/subjects/responses/prompt_response.rs                               27       0  100.00%
crates/acp-nats/src/nats/subjects/responses/cancelled.rs                                     15       0  100.00%
crates/acp-nats/src/nats/subjects/responses/response.rs                                      20       0  100.00%
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/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/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-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/trogon-gateway/src/source/slack/signature.rs                                          66       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/socket_mode.rs                                       716       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/mcp_prefix.rs                                                            34       0  100.00%
crates/mcp-nats/src/server.rs                                                                31       0  100.00%
crates/mcp-nats/src/transport.rs                                                            698       0  100.00%
crates/mcp-nats/src/config.rs                                                               110       0  100.00%
crates/mcp-nats/src/jsonrpc.rs                                                               22       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-nats/src/lease/lease_bucket.rs                                                 19       0  100.00%
crates/trogon-nats/src/lease/provision.rs                                                   187      10  94.65%   82-92
crates/trogon-nats/src/lease/acquire.rs                                                       5       5  0.00%    9-14
crates/trogon-nats/src/lease/release.rs                                                       5       5  0.00%    8-12
crates/trogon-nats/src/lease/ttl.rs                                                          68       0  100.00%
crates/trogon-nats/src/lease/nats_kv_lease_config.rs                                         26       0  100.00%
crates/trogon-nats/src/lease/lease_timing.rs                                                 15       0  100.00%
crates/trogon-nats/src/lease/mod.rs                                                         523      13  97.51%   113-126
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/trogon-nats/src/lease/renew_interval.rs                                               57       0  100.00%
crates/trogon-decider-runtime/src/headers/header_value.rs                                    34       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/trogonai-proto/src/codec.rs                                                           16       0  100.00%
crates/trogonai-proto/src/convert.rs                                                        120       0  100.00%
crates/trogon-gateway/src/source/incidentio/config.rs                                        16       0  100.00%
crates/trogon-gateway/src/source/incidentio/server.rs                                       343       0  100.00%
crates/trogon-gateway/src/source/incidentio/incidentio_event_type.rs                         62       0  100.00%
crates/trogon-gateway/src/source/incidentio/incidentio_signing_secret.rs                     56       0  100.00%
crates/trogon-gateway/src/source/incidentio/signature.rs                                    206       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/acp-nats/src/nats/extensions.rs                                                        3       0  100.00%
crates/acp-nats/src/nats/subjects/global/session_new.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/logout.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/authenticate.rs                                      6       0  100.00%
crates/acp-nats/src/nats/subjects/global/initialize.rs                                        6       0  100.00%
crates/acp-nats-agent/src/connection.rs                                                    1260       1  99.92%   590
crates/trogon-scheduler/src/commands/domain/schedule_id.rs                                   81       0  100.00%
crates/trogon-scheduler/src/commands/domain/schedule.rs                                     638       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-scheduler/src/commands/domain/schedule_event_status.rs                         10       0  100.00%
crates/trogon-scheduler/src/commands/domain/message.rs                                      219       0  100.00%
crates/trogon-scheduler/src/commands/domain/schedule_event_delivery.rs                       25       0  100.00%
crates/trogon-scheduler/src/commands/domain/schedule_event_schedule.rs                       83       0  100.00%
crates/trogon-scheduler/src/commands/domain/recurrence.rs                                   179       1  99.44%   99
crates/trogon-std/src/time/system.rs                                                         31       0  100.00%
crates/trogon-std/src/time/mock.rs                                                          125       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                         36       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/events.rs                                                          49       0  100.00%
crates/trogon-decider/src/act.rs                                                             62       0  100.00%
crates/trogon-decider/src/decision.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/trogonai-proto/src/scheduler/schedules/codec.rs                                      377       0  100.00%
crates/mcp-nats/src/nats/subjects/subscriptions/one_client.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/mcp-nats/src/nats/subjects/subscriptions/one_server.rs                                 9       0  100.00%
crates/trogon-std/src/dirs/fixed.rs                                                          80       0  100.00%
crates/trogon-std/src/dirs/system.rs                                                         71       0  100.00%
crates/acp-nats/src/agent/ext_method.rs                                                      82       0  100.00%
crates/acp-nats/src/agent/set_session_mode.rs                                                67       0  100.00%
crates/acp-nats/src/agent/authenticate.rs                                                    49       0  100.00%
crates/acp-nats/src/agent/cancel.rs                                                         101       0  100.00%
crates/acp-nats/src/agent/ext_notification.rs                                                82       0  100.00%
crates/acp-nats/src/agent/js_request.rs                                                     283       0  100.00%
crates/acp-nats/src/agent/logout.rs                                                          49       0  100.00%
crates/acp-nats/src/agent/prompt.rs                                                         471       0  100.00%
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/mod.rs                                                             65       0  100.00%
crates/acp-nats/src/agent/resume_session.rs                                                  90       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/test_support.rs                                                   267       0  100.00%
crates/acp-nats/src/agent/list_sessions.rs                                                   47       0  100.00%
crates/acp-nats/src/agent/fork_session.rs                                                    94       0  100.00%
crates/acp-nats/src/agent/initialize.rs                                                      79       0  100.00%
crates/acp-nats/src/agent/set_session_config_option.rs                                       67       0  100.00%
crates/acp-nats/src/agent/set_session_model.rs                                               67       0  100.00%
crates/acp-nats/src/nats/subjects/mod.rs                                                    362       0  100.00%
crates/acp-nats/src/nats/subjects/stream.rs                                                  56       0  100.00%
crates/trogon-decider-runtime/src/execution.rs                                             1432       0  100.00%
crates/trogon-decider-nats/src/store.rs                                                     127      47  62.99%   35-160
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-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-runtime/src/snapshot/codec/snapshot_envelope_encode_error.rs           14       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_encode_error.rs                    36       0  100.00%
crates/trogon-decider-runtime/src/snapshot/codec/snapshot_envelope_decode_error.rs           28       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_decode_error.rs                    49       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/event_identity.rs                                     3       0  100.00%
crates/trogon-decider-runtime/src/event/mod.rs                                              170       0  100.00%
crates/trogon-scheduler/src/processor/execution/wakeup.rs                                   353       7  98.02%   83-85, 127, 400, 416, 585
crates/trogon-std/src/telemetry/http.rs                                                     217       0  100.00%
crates/acp-nats/src/telemetry/metrics.rs                                                     53       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/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/mcp-nats-stdio/src/main.rs                                                           204       0  100.00%
crates/mcp-nats-stdio/src/config.rs                                                         149       0  100.00%
crates/mcp-nats/src/nats/subjects/server/unsubscribe_resource.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/progress.rs                                         12       0  100.00%
crates/mcp-nats/src/nats/subjects/server/resource_list_changed.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/logging_message.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/prompt_list_changed.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/resource_updated.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/list_tasks.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/call_tool.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/initialize.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/elicitation_completed.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/set_logging_level.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/subscribe_resource.rs                               12       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/list_prompts.rs                                     12       0  100.00%
crates/trogon-std/src/duration.rs                                                            42       0  100.00%
crates/trogon-std/src/signal.rs                                                              26      12  53.85%   6-11, 18-25, 34
crates/trogon-std/src/secret_string.rs                                                       32       0  100.00%
crates/trogon-std/src/http.rs                                                                19       0  100.00%
crates/trogon-std/src/uuid.rs                                                                 7       0  100.00%
crates/trogon-std/src/args.rs                                                                19       9  52.63%   11-28
crates/trogon-std/src/json.rs                                                                30       0  100.00%
crates/a2a-nats/src/gateway_ingress.rs                                                      256       0  100.00%
crates/a2a-nats/src/constants.rs                                                             36       0  100.00%
crates/a2a-nats/src/context_id.rs                                                            54       0  100.00%
crates/a2a-nats/src/task_id.rs                                                               57       0  100.00%
crates/a2a-nats/src/agent_id.rs                                                              62       0  100.00%
crates/a2a-nats/src/error.rs                                                                 32       0  100.00%
crates/a2a-nats/src/req_id.rs                                                                41       0  100.00%
crates/a2a-nats/src/a2a_prefix.rs                                                            47       0  100.00%
crates/a2a-nats/src/jsonrpc.rs                                                               49       0  100.00%
crates/trogon-gateway/src/streams.rs                                                        129       0  100.00%
crates/trogon-gateway/src/source_status.rs                                                   24       0  100.00%
crates/trogon-gateway/src/main.rs                                                           111       0  100.00%
crates/trogon-gateway/src/source_plugin.rs                                                  268       3  98.88%   82, 139-140
crates/trogon-gateway/src/source_integration_id.rs                                           55       2  96.36%   58, 60
crates/trogon-gateway/src/config.rs                                                        2591      42  98.38%   84, 668, 671, 831, 888, 971, 974, 977, 981, 1065-1072, 1149, 1152, 1155, 1160, 1218, 1221, 1224, 1303, 1306, 1309, 1313, 1377, 1380, 1383, 1446, 1449, 1452, 1457, 1532, 1535, 1538, 1543, 1601, 1604, 1607, 1820-1822
crates/trogon-gateway/src/http.rs                                                           145       0  100.00%
crates/trogon-gateway/src/source/sentry/server.rs                                           308       0  100.00%
crates/trogon-gateway/src/source/sentry/signature.rs                                         42       0  100.00%
crates/trogon-gateway/src/source/sentry/sentry_client_secret.rs                              17       0  100.00%
crates/acp-nats/src/jetstream/streams.rs                                                    163       4  97.55%   206-208, 218
crates/acp-nats/src/jetstream/consumers.rs                                                   91       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/nats/subjects/subscriptions/one_session.rs                               12       0  100.00%
crates/acp-nats/src/nats/subjects/subscriptions/all_agent.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_client.rs                                15       0  100.00%
crates/acp-nats/src/nats/subjects/subscriptions/prompt_wildcard.rs                            9       0  100.00%
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_client.rs                                 9       0  100.00%
crates/acp-nats/src/nats/subjects/subscriptions/one_agent.rs                                 15       0  100.00%
crates/mcp-nats/src/nats/subjects/mod.rs                                                     89       0  100.00%
crates/trogon-nats/src/telemetry/messaging.rs                                                82       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                                             13       0  100.00%
crates/a2a-nats/src/catalog/import_gate/principal.rs                                         14       0  100.00%
crates/mcp-nats/src/nats/mod.rs                                                              99       0  100.00%
crates/mcp-nats/src/nats/parsing.rs                                                         191       0  100.00%
crates/trogon-scheduler/src/commands/create_schedule.rs                                     199       0  100.00%
crates/trogon-scheduler/src/commands/pause_schedule.rs                                      174       0  100.00%
crates/trogon-scheduler/src/commands/remove_schedule.rs                                     171       0  100.00%
crates/trogon-scheduler/src/commands/record_schedule_occurrence.rs                          348       1  99.71%   182
crates/trogon-scheduler/src/commands/schedule_next_occurrence.rs                            355       0  100.00%
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/resume_schedule.rs                                     207       0  100.00%
crates/acp-nats/src/client/mod.rs                                                          2851       0  100.00%
crates/acp-nats/src/client/terminal_create.rs                                               264       0  100.00%
crates/acp-nats/src/client/ext.rs                                                           296       8  97.30%   146-155, 172-181
crates/acp-nats/src/client/terminal_release.rs                                              335       0  100.00%
crates/acp-nats/src/client/terminal_output.rs                                               206       0  100.00%
crates/acp-nats/src/client/ext_session_prompt_response.rs                                   135       0  100.00%
crates/acp-nats/src/client/session_update.rs                                                 55       0  100.00%
crates/acp-nats/src/client/rpc_reply.rs                                                      64       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/request_permission.rs                                            298       0  100.00%
crates/acp-nats/src/client/fs_write_text_file.rs                                            408       0  100.00%
crates/acp-nats/src/client/fs_read_text_file.rs                                             346       0  100.00%
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/a2a-identity-types/src/principal.rs                                                   40       0  100.00%
crates/a2a-identity-types/src/error.rs                                                       33       0  100.00%
crates/a2a-identity-types/src/caller.rs                                                      61       0  100.00%
crates/a2a-identity-types/src/jwt.rs                                                        156       0  100.00%
crates/trogon-gateway/src/source/github/server.rs                                           328       0  100.00%
crates/trogon-gateway/src/source/github/config.rs                                            17       0  100.00%
crates/trogon-gateway/src/source/github/signature.rs                                         50       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_wait_for_exit.rs                       12       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/terminal_create.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/fs_write_text_file.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_kill.rs                                12       0  100.00%
crates/trogon-service-config/src/lib.rs                                                      92       0  100.00%
crates/trogon-gateway/src/source/gitlab/server.rs                                           460       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/a2a-nats/src/client/handle.rs                                                         43       0  100.00%
crates/a2a-nats/src/client/error.rs                                                         185       2  98.92%   153, 162
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/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-server/src/config.rs                                                        126       3  97.62%   41-43
crates/acp-nats-server/src/acp_connection_id.rs                                              37       0  100.00%
crates/acp-nats-server/src/main.rs                                                          900      10  98.89%   109, 243-250, 450
crates/a2a-nats/src/catalog/store.rs                                                        399       0  100.00%
crates/a2a-nats/src/catalog/watch.rs                                                        106       0  100.00%
crates/a2a-nats/src/catalog/registrar.rs                                                    233       0  100.00%
crates/a2a-nats/src/catalog/nats_kv.rs                                                       19       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/acp-nats/src/acp_prefix.rs                                                            46       0  100.00%
crates/acp-nats/src/in_flight_slot_guard.rs                                                  32       0  100.00%
crates/acp-nats/src/lib.rs                                                                   69       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/jsonrpc.rs                                                                6       0  100.00%
crates/acp-nats/src/pending_prompt_waiters.rs                                               131       0  100.00%
crates/acp-nats/src/ext_method_name.rs                                                       65       0  100.00%
crates/acp-nats/src/config.rs                                                               203       0  100.00%
crates/acp-nats/src/client_proxy.rs                                                         181       0  100.00%
crates/acp-nats/src/error.rs                                                                 82       0  100.00%
crates/trogon-gateway/src/source/linear/config.rs                                            17       0  100.00%
crates/trogon-gateway/src/source/linear/signature.rs                                         54       1  98.15%   16
crates/trogon-gateway/src/source/linear/server.rs                                           386       0  100.00%
crates/mcp-nats/src/telemetry/transport.rs                                                    6       0  100.00%
crates/trogon-gateway/src/source/standard_webhooks.rs                                       138       0  100.00%
crates/trogon-telemetry/src/resource_attribute.rs                                            23       0  100.00%
crates/trogon-telemetry/src/service_name.rs                                                  44       0  100.00%
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/metric.rs                                                        26       1  96.15%   30
crates/trogon-telemetry/src/log.rs                                                           70       1  98.57%   35
crates/trogon-scheduler/src/processor/execution/worker/dispatcher.rs                       1027       6  99.42%   186-187, 247, 432-434
crates/trogon-scheduler/src/processor/execution/worker/testkit.rs                           330       4  98.79%   459, 490-491, 496
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/acp-nats/src/nats/subjects/commands/prompt.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/cancel.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/resume.rs                                         15       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/set_config_option.rs                              15       0  100.00%
crates/acp-nats/src/nats/subjects/commands/load.rs                                           15       0  100.00%
crates/trogon-nats/src/jetstream/claim_check.rs                                             405      10  97.53%   45-47, 116-122
crates/trogon-nats/src/jetstream/publish.rs                                                  64       0  100.00%
crates/trogon-nats/src/jetstream/mocks.rs                                                  1686       1  99.94%   505
crates/trogon-nats/src/jetstream/stream_max_age.rs                                           18       0  100.00%
crates/trogon-nats/src/jetstream/traits.rs                                                   46      40  13.04%   181-251
crates/trogon-nats/src/jetstream/create_conflicts.rs                                         24       0  100.00%
crates/trogon-nats/src/connect.rs                                                            82       6  92.68%   41-46
crates/trogon-nats/src/subject_token_violation.rs                                            11       0  100.00%
crates/trogon-nats/src/mocks.rs                                                             314       0  100.00%
crates/trogon-nats/src/auth.rs                                                              114       0  100.00%
crates/trogon-nats/src/nats_token.rs                                                        157       0  100.00%
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/client.rs                                                             22      22  0.00%    50-86
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/mcp-nats-server/src/allowed_host.rs                                                   88       0  100.00%
crates/mcp-nats-server/src/config.rs                                                        257       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/reconcile.rs                 808      13  98.39%   251-260, 325-327
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/rrule_wakeup_payload.rs       35       0  100.00%
crates/trogon-scheduler/src/processor/execution/reconciliation/schedule_key.rs               67       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/go_duration.rs                59       0  100.00%
crates/trogon-gateway/src/source/telegram/registration.rs                                   313       0  100.00%
crates/trogon-gateway/src/source/telegram/config.rs                                          89       0  100.00%
crates/trogon-gateway/src/source/telegram/signature.rs                                       27       0  100.00%
crates/trogon-gateway/src/source/telegram/server.rs                                         339       0  100.00%
crates/mcp-nats/src/nats/subjects/client/create_message.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/initialized.rs                                      12       0  100.00%
crates/mcp-nats/src/nats/subjects/client/roots_list_changed.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/progress.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/create_elicitation.rs                               12       0  100.00%
crates/trogon-std/src/env/in_memory.rs                                                       73       0  100.00%
crates/trogon-std/src/env/system.rs                                                          17       0  100.00%
crates/acp-nats-stdio/src/config.rs                                                          66       0  100.00%
crates/acp-nats-stdio/src/main.rs                                                           135      25  81.48%   67, 115-122, 128-130, 147, 176-195
crates/a2a-nats/src/server/handler.rs                                                        73       0  100.00%
crates/a2a-nats/src/server/wire.rs                                                          115       0  100.00%
crates/trogon-gateway/src/source/twitter/server.rs                                          524       0  100.00%
crates/trogon-gateway/src/source/twitter/signature.rs                                        58       0  100.00%
crates/trogon-gateway/src/source/twitter/config.rs                                           17       0  100.00%
crates/a2a-pack/src/agent_card_schema.rs                                                     84       0  100.00%
crates/a2a-pack/src/agent_card_read.rs                                                       66       0  100.00%
crates/trogon-scheduler/src/processor/execution/execution_schedules/mod.rs                  270       0  100.00%
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/server.rs                                           310       4  98.71%   115-116, 135-136
crates/trogon-gateway/src/source/notion/signature.rs                                         45       0  100.00%
crates/trogon-gateway/src/source/notion/notion_event_type.rs                                 46       3  93.48%   50-52
TOTAL                                                                                     53401     819  98.47%

Diff against main

Filename                                                                Stmts    Miss  Cover
--------------------------------------------------------------------  -------  ------  --------
crates/a2a-nats/src/catalog/store.rs                                     +399       0  +100.00%
crates/a2a-nats/src/catalog/watch.rs                                     +106       0  +100.00%
crates/a2a-nats/src/catalog/registrar.rs                                 +233       0  +100.00%
crates/a2a-nats/src/catalog/nats_kv.rs                                    +19       0  +100.00%
crates/trogon-scheduler/src/processor/execution/worker/dispatcher.rs        0      +3  -0.29%
TOTAL                                                                    +757      +3  +0.02%

Results for commit: cf0bae6

Minimum allowed coverage is 95%

♻️ This comment has been updated with latest results

@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: 7

🧹 Nitpick comments (1)
rsworkspace/crates/a2a-nats/src/catalog/store.rs (1)

113-145: ⚖️ Poor tradeoff

Consider caching original JSON to avoid round-trip serialization.

Line 135 serializes the card back to JSON for accept_agent_card_on_read, but the card was just deserialized from JSON in get_card (line 105). This round-trip serialization adds overhead for each gated card.

If list_cards_gated is called frequently or with large card sets, consider either:

  1. Extending get_card to optionally return the original JSON alongside the parsed card
  2. Caching the JSON representation in the AgentCard wrapper
  3. Refactoring accept_agent_card_on_read to accept the structured card instead of JSON
🤖 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/src/catalog/store.rs` around lines 113 - 145, The
list_cards_gated method unnecessarily serializes the card to JSON for the
accept_agent_card_on_read check on line 135, but this card was already
deserialized from JSON earlier through the list_cards and get_card flow. To
eliminate this round-trip serialization overhead, either modify get_card to
return both the original JSON value and the deserialized AgentCard so
list_cards_gated can reuse the cached JSON, or refactor
accept_agent_card_on_read to accept the structured AgentCard type directly
instead of requiring JSON serialization. Choose the approach that minimizes
changes to the existing codebase while preserving the validation logic of
accept_agent_card_on_read.
🤖 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/src/catalog/registrar.rs`:
- Around line 61-76: The RegisterPayloadError enum is missing implementations
for the Display and std::error::Error traits, which are required by coding
guidelines for all error types. Add a Display trait implementation to
RegisterPayloadError that formats error messages appropriately for each variant
(JsonParse, Schema, ValueParse), and also implement the std::error::Error trait
for RegisterPayloadError to ensure it follows standard error handling patterns
in Rust. These implementations will make the error type more consistent with
Rust conventions and enable broader usage patterns if the type is used elsewhere
in the codebase.
- Around line 214-227: The Subscribe variant in CatalogRegistrarServiceError is
currently storing a String, which loses error context. Replace the String field
with Box<dyn std::error::Error + Send + Sync> to preserve the full error chain.
Update the Display implementation for Subscribe to format the boxed error
appropriately. Add a #[source] attribute to the Subscribe field to properly
expose the underlying error in the error chain. At line 117 where the error is
constructed, instead of converting the error to a String, pass the error
directly as a boxed trait object using Box::new or similar. Consider using the
thiserror crate with #[error] and #[source] derive attributes to simplify the
implementation, following the pattern used elsewhere in the codebase like
acp-nats-agent/src/connection.rs.

In `@rsworkspace/crates/a2a-nats/src/catalog/store.rs`:
- Around line 88-110: In the list_cards method, remove the .to_string() calls
from the error mapping expressions where errors are converted to
CatalogStoreError::Kv. Instead of using .map_err(|e|
CatalogStoreError::Kv(e.to_string())), change it to .map_err(|e|
CatalogStoreError::Kv(e)) to preserve the typed error rather than converting it
to a string. This same change needs to be applied to other methods in the file
(mentioned as lines 152-182 and 184-200) where similar error conversions exist.
- Around line 14-22: The Kv(String) variant in the CatalogStoreError enum
discards the underlying error type and breaks the error source chain. Replace
the Kv(String) variant with a typed error field that wraps the actual error type
returned by async-nats KV operations (which implements std::error::Error). Then
update the Display and source trait implementations for CatalogStoreError to
properly expose the wrapped error as the source, and finally locate all sites
where Kv errors are created and update them to wrap the source error instead of
converting it to a string.

In `@rsworkspace/crates/a2a-nats/src/catalog/watch.rs`:
- Around line 53-63: The error conversion in the subscribe_agent function on
line 61 is converting the typed error to a string using e.to_string(), but the
Kv variant of AgentCardWatchError now holds typed errors directly instead of
strings. Replace the `.map_err(|e| AgentCardWatchError::Kv(e.to_string()))?`
call with `.map_err(|e| AgentCardWatchError::Kv(e))?` to pass the typed error
directly. Apply the same fix to the similar error conversion in the other watch
subscription function in the 66-81 range that also converts errors to strings.
- Around line 30-41: The std::error::Error implementation for
AgentCardWatchError is missing the source() method, which prevents error chain
preservation and makes underlying errors inaccessible to error handlers.
Implement the source() method in the std::error::Error impl block for
AgentCardWatchError to return an Option containing a reference to the underlying
error. For each variant (Kv, InvalidKey, Deserialize, Schema), return Some
reference to the contained error, except for Kv which should return None until
it is changed to hold typed errors.
- Around line 22-28: The Kv variant in the AgentCardWatchError enum is storing
the KV error as a String, which discards the underlying error type and violates
the coding guideline that errors must never be converted to strings. Replace the
Kv(String) variant with Kv(Box<dyn std::error::Error + Send + Sync>) or wrap the
actual typed KV error from the NATS client library (e.g., the concrete error
type returned by NATS KV operations) to preserve the source error information
instead of converting it to a string.

---

Nitpick comments:
In `@rsworkspace/crates/a2a-nats/src/catalog/store.rs`:
- Around line 113-145: The list_cards_gated method unnecessarily serializes the
card to JSON for the accept_agent_card_on_read check on line 135, but this card
was already deserialized from JSON earlier through the list_cards and get_card
flow. To eliminate this round-trip serialization overhead, either modify
get_card to return both the original JSON value and the deserialized AgentCard
so list_cards_gated can reuse the cached JSON, or refactor
accept_agent_card_on_read to accept the structured AgentCard type directly
instead of requiring JSON serialization. Choose the approach that minimizes
changes to the existing codebase while preserving the validation logic of
accept_agent_card_on_read.
🪄 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: abab9fd3-d549-4a6d-81de-2374b93372bd

📥 Commits

Reviewing files that changed from the base of the PR and between 273e593 and 58c1b87.

⛔ Files ignored due to path filters (1)
  • rsworkspace/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (7)
  • rsworkspace/Cargo.toml
  • rsworkspace/crates/a2a-nats/Cargo.toml
  • rsworkspace/crates/a2a-nats/src/catalog/mod.rs
  • rsworkspace/crates/a2a-nats/src/catalog/nats_kv.rs
  • rsworkspace/crates/a2a-nats/src/catalog/registrar.rs
  • rsworkspace/crates/a2a-nats/src/catalog/store.rs
  • rsworkspace/crates/a2a-nats/src/catalog/watch.rs

Comment thread rsworkspace/crates/a2a-nats/src/catalog/registrar.rs
Comment thread rsworkspace/crates/a2a-nats/src/catalog/registrar.rs Outdated
Comment thread rsworkspace/crates/a2a-nats/src/catalog/store.rs
Comment thread rsworkspace/crates/a2a-nats/src/catalog/store.rs
Comment thread rsworkspace/crates/a2a-nats/src/catalog/watch.rs
Comment thread rsworkspace/crates/a2a-nats/src/catalog/watch.rs
Comment thread rsworkspace/crates/a2a-nats/src/catalog/watch.rs Outdated
yordis added 3 commits June 17, 2026 15:57
Without a single source of truth, fmt + clippy + coverage all run in
slightly different cwds and silently miss steps when invoked ad-hoc.
The script gates each step the same way CI does so a green run locally
means a green run in CI.

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Previous commit (1548dec) intended to add this but the local checkout
had .trogonai/ symlinked to a private artefact dir, so 'git add' fell
behind the symlink and the script never made it into the tree. Land
it under rsworkspace/scripts/ so future agents (and humans) can run
the same CI mirror without depending on a personal symlink.

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Strip the un-test-harnessable run loop and live JetStream watch wrapper
into a follow-up integration PR so this slice ships only the pure
helpers + KV-backed store + decoder it can exercise locally. Every
remaining production line is now hit by a unit test, so the coverage
gate sees no new uncovered statements.

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Comment thread rsworkspace/scripts/pr-check.sh Outdated
The previous run flagged +2 uncovered lines in
trogon-scheduler/dispatcher.rs unrelated to this PR (main run had 3
uncovered there, this branch had 5). Empty commit to retrigger and
confirm the flap is on lines this PR doesn't touch.

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Comment thread rsworkspace/crates/a2a-nats/src/catalog/store.rs
yordis added 3 commits June 17, 2026 16:18
Move the rsworkspace PR gate script under .config/mise/tasks so it's
discoverable via 'mise tasks' alongside rust-coverage-check and
rust-coverage-gate, and reuse rust-coverage-check for the coverage
comparison instead of duplicating that logic.

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Surface every unresolved review thread + its thread ID so addressing
review feedback doesn't depend on remembering which threads have been
seen vs resolved already.

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

CatalogStoreError::Kv now wraps the underlying KV error as a boxed
source so callers keep std::error::Error chaining (and can downcast)
instead of pattern-matching on a stringified message. Split out an
InvalidKey variant for the catalog-key validation failure that used
to be hidden inside Kv(String).

put_card also stops calling JetStream KV update against a delete or
purge tombstone — the latest entry's revision is still returned for
removed keys, and update against that revision fails where create
would have restored the card, so re-registration after a delete now
works cleanly.

RegisterPayloadError gains Display + Error impls + a source() chain
to align with the workspace error-shape guidelines.

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 3 potential issues.

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 415de7a. Configure here.

Comment thread .config/mise/tasks/pr-unresolved-comments
Comment thread .config/mise/tasks/pr-unresolved-comments Outdated
Comment thread rsworkspace/crates/a2a-nats/src/catalog/store.rs
…-comments script

put_card now retries up to three attempts when the JetStream KV write
loses a revision race (WrongLastRevision against a stale revision or
AlreadyExists against a key recreated underneath us). Non-conflict
errors still propagate immediately so a backend failure can't get
masked as a race.

pr-unresolved-comments switches to set -euo pipefail and paginates
through reviewThreads via pageInfo so a flaky GraphQL response can't
make the script lie about a clean PR, and PRs with more than 100
threads can't silently hide unresolved comments past the first page.

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 17, 2026

@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

♻️ Duplicate comments (1)
rsworkspace/crates/a2a-nats/src/catalog/watch.rs (1)

25-31: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Restore typed error chaining in AgentCardWatchError instead of stringifying context.

Line 27/28 and Line 48 currently convert error context into String (Kv(String), InvalidKey(String), format!(...)), and Line 44 omits source(). This drops structured causes and regresses diagnosability.

Suggested direction
 pub enum AgentCardWatchError {
-    Kv(String),
-    InvalidKey(String),
+    Kv(Box<dyn std::error::Error + Send + Sync>),
+    InvalidKey(A2aAgentIdParseError), // or your concrete parse error type
     Deserialize(serde_json::Error),
     Schema(a2a_pack::AgentCardValidateError),
 }

-impl std::error::Error for AgentCardWatchError {}
+impl std::error::Error for AgentCardWatchError {
+    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
+        match self {
+            Self::Kv(e) => Some(e.as_ref()),
+            Self::InvalidKey(e) => Some(e),
+            Self::Deserialize(e) => Some(e),
+            Self::Schema(e) => Some(e),
+        }
+    }
+}
- let agent_id = A2aAgentId::new(entry.key.as_str()).map_err(|_| {
-     AgentCardWatchError::InvalidKey(format!("catalog KV key `{}` is not a valid agent id", entry.key))
- })?;
+ let agent_id =
+     A2aAgentId::new(entry.key.as_str()).map_err(AgentCardWatchError::InvalidKey)?;

As per coding guidelines, “Errors must be typed—use structs or enums, never String or format!()… Never discard error context by converting a typed error into a string; wrap the source error as a field or variant instead.”

Also applies to: 44-49

🤖 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/src/catalog/watch.rs` around lines 25 - 31, The
AgentCardWatchError enum currently uses String variants for Kv and InvalidKey
instead of storing typed errors, which drops structured error context. Replace
the Kv(String) and InvalidKey(String) variants with typed error fields that wrap
the actual underlying error types (likely a Box<dyn Error> or the specific error
type that caused these variants). Additionally, ensure that the Error trait
implementation for AgentCardWatchError includes a proper source() method
implementation that returns the underlying error, and verify that error
conversions around lines 44-49 propagate the typed errors instead of converting
them to formatted strings.

Source: Coding guidelines

🤖 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 @.config/mise/tasks/pr-unresolved-comments:
- Around line 35-37: The gh repo view command on line 35 can fail due to
authentication, network, or API errors, causing the script to exit via set -e
before reaching your controlled exit 2 path, resulting in inconsistent exit
codes and lost diagnostic messages. Add explicit error handling around the
REPO_NWO assignment to check if the gh command succeeds; if it fails, explicitly
exit with code 2 and include a clear diagnostic message. Apply the same explicit
error handling pattern to the similar gh commands around lines 67-70 to ensure
all gh command failures are caught and handled consistently with your diagnostic
exit contract.
- Around line 16-25: The argument parsing loop in the for loop currently uses a
catch-all pattern that accepts any unknown argument as the PR value, which
silently accepts typos like --jsno. Replace the catch-all case pattern with
explicit validation that rejects unknown arguments with a clear error message
and exit code 2. Additionally, after the loop completes, add numeric validation
on the PR variable to ensure it contains only digits, and if validation fails,
output an error message and exit with code 2. This ensures the script fails fast
with helpful feedback rather than silently accepting invalid input.

In `@rsworkspace/crates/a2a-nats/src/catalog/registrar.rs`:
- Around line 39-45: The functions `register_subject_prefix` and
`agent_id_suffix` expose raw primitives (`&str`, `usize`, and `Option<&str>`)
instead of domain value objects, allowing unvalidated subject data to flow
downstream. Modify `register_subject_prefix` to accept `&A2aPrefix` instead of
raw `&str`, and update `agent_id_suffix` to return a validated `A2aAgentId`
instead of `Option<&str>` (or an appropriate typed parse error), ensuring domain
boundaries are enforced and invalid subjects are rejected at the boundary rather
than propagating downstream.

---

Duplicate comments:
In `@rsworkspace/crates/a2a-nats/src/catalog/watch.rs`:
- Around line 25-31: The AgentCardWatchError enum currently uses String variants
for Kv and InvalidKey instead of storing typed errors, which drops structured
error context. Replace the Kv(String) and InvalidKey(String) variants with typed
error fields that wrap the actual underlying error types (likely a Box<dyn
Error> or the specific error type that caused these variants). Additionally,
ensure that the Error trait implementation for AgentCardWatchError includes a
proper source() method implementation that returns the underlying error, and
verify that error conversions around lines 44-49 propagate the typed errors
instead of converting them to formatted strings.
🪄 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: cf4b4935-beba-481c-99b7-6594a48b17d8

📥 Commits

Reviewing files that changed from the base of the PR and between 58c1b87 and 4818611.

⛔ Files ignored due to path filters (1)
  • rsworkspace/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (7)
  • .config/mise/tasks/pr-unresolved-comments
  • .config/mise/tasks/rust-pr-check
  • rsworkspace/crates/a2a-nats/Cargo.toml
  • rsworkspace/crates/a2a-nats/src/catalog/mod.rs
  • rsworkspace/crates/a2a-nats/src/catalog/registrar.rs
  • rsworkspace/crates/a2a-nats/src/catalog/store.rs
  • rsworkspace/crates/a2a-nats/src/catalog/watch.rs
💤 Files with no reviewable changes (1)
  • rsworkspace/crates/a2a-nats/Cargo.toml
✅ Files skipped from review due to trivial changes (1)
  • .config/mise/tasks/rust-pr-check
🚧 Files skipped from review as they are similar to previous changes (1)
  • rsworkspace/crates/a2a-nats/src/catalog/store.rs

Comment thread .config/mise/tasks/pr-unresolved-comments
Comment thread .config/mise/tasks/pr-unresolved-comments Outdated
Comment thread rsworkspace/crates/a2a-nats/src/catalog/registrar.rs Outdated
…r-comments arg parsing

agent_id_from_subject(prefix, subject) returns a validated A2aAgentId
plus a typed AgentSuffixError instead of leaking Option<&str>/usize
through the registrar API surface. register_subject_prefix takes
&A2aPrefix instead of &str so the boundary type conversion happens
exactly once.

pr-unresolved-comments rejects unknown flags + non-numeric PR
arguments early, and treats every gh failure as its own exit 2 path
so set -euo pipefail can't silently override the script's diagnostic
contract.

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
@yordis
yordis merged commit 164b920 into main Jun 17, 2026
7 checks passed
@yordis
yordis deleted the yordis/feat-a2a-nats-catalog-store branch June 17, 2026 21:31
yordis added a commit that referenced this pull request Jun 18, 2026
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
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