Skip to content

feat(scheduler): add create schedule command#192

Merged
yordis merged 19 commits into
mainfrom
yordis/chore-create-schedule
Jun 1, 2026
Merged

feat(scheduler): add create schedule command#192
yordis merged 19 commits into
mainfrom
yordis/chore-create-schedule

Conversation

@yordis

@yordis yordis commented May 29, 2026

Copy link
Copy Markdown
Member
  • Enable scheduler command handling to build on the state schemas already introduced upstream.
  • Keep this slice focused on creation so later lifecycle commands can land with separate review context.

@cursor

cursor Bot commented May 29, 2026

Copy link
Copy Markdown

PR Summary

Medium Risk
New scheduling domain with cron/RRULE/timezone validation and event-sourced create semantics; scope is mostly new code and tests, but incorrect validation or state rules could affect future schedule execution paths.

Overview
Introduces the trogon-scheduler crate with a CreateSchedule decider (stream-per-schedule-id, NoStream write precondition) that emits ScheduleCreated when state is missing, and rejects duplicates, deleted IDs, and bad protobuf state.

Adds a domain layer for schedule specs (at / every / cron / RRULE), NATS delivery routes, message content and headers (including reserved Nats-Schedule-* names), and strict ScheduleId parsing—wired to schedule protobuf via new trogonai-proto convert helpers (chrono feature) for timestamps and bounded durations.

trogonai-proto gains optional chrono and extends schedules to depend on it; lockfile picks up cron, rrule, chrono-tz, etc. acp-nats-server adds a test that HTTP posts log responses without a GET listener.

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

@coderabbitai

coderabbitai Bot commented May 29, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

This PR establishes the domain layer and command logic for schedule creation in the trogon-scheduler crate. It introduces validated domain types for messaging, scheduling specifications (one-time, interval, cron, recurrence-rule), delivery routing, and schedule identifiers; wires conversions to protobuf event types; implements state evolution logic; and provides a CreateScheduleCommand decider that gates creation on stream preconditions.

Changes

Scheduler domain and command implementation

Layer / File(s) Summary
Message domain types and validation
rsworkspace/crates/trogon-scheduler/src/commands/domain/message.rs
MessageHeadersError with InvalidName/InvalidValue; MessageHeaders ordered wrapper with validation; HeaderName/HeaderValue newtypes; MessageContent/MessageContentType helpers; MessageEnvelope; From<&MessageEnvelope> for v1::Message; unit tests and proptests.
ScheduleId validation and error reporting
rsworkspace/crates/trogon-scheduler/src/commands/domain/schedule_id.rs
ScheduleId newtype with parse enforcing non-empty, no surrounding whitespace, and max 256 chars; ScheduleIdViolation/ScheduleIdError; AsRef/FromStr/Display/Error; tests and proptests.
Job status, schedule, and delivery domain with validation
rsworkspace/crates/trogon-scheduler/src/commands/domain/schedule.rs
JobStatus (Enabled/Disabled); Schedule variants At/Every/Cron/RRule and constructors; validated newtypes EverySeconds, CronExpression, RRuleExpression, RRuleDateTime; timezone tokens; JobHeaders/JobMessage; DeliveryRoute/SamplingSubject/TtlSeconds; SamplingSource/Delivery; reserved header checks; conversion From impls and extensive tests/proptests.
Schedule event types with protobuf conversion
rsworkspace/crates/trogon-scheduler/src/commands/domain/schedule_event_*.rs
ScheduleEventStatus, ScheduleEventSchedule, ScheduleEventSamplingSource, ScheduleEventDelivery and From conversions to protobuf v1::* messages, including timezone/timestamp/duration mapping and tests.
Domain module exports and proto helper integration
rsworkspace/crates/trogon-scheduler/src/commands/domain/mod.rs, rsworkspace/crates/trogonai-proto/Cargo.toml, rsworkspace/crates/trogonai-proto/src/convert.rs, rsworkspace/crates/trogonai-proto/src/lib.rs
Domain pub use re-exports; trogonai-proto adds optional chrono feature and exposes convert behind it; convert implements timestamp_from_datetime and duration_from_seconds.
State evolution logic for schedule events
rsworkspace/crates/trogon-scheduler/src/commands/state.rs
EvolveError with Display/Error; initial_state() returning STATE_VALUE_MISSING; evolve(state,event) mapping ScheduleCreated/ScheduleRemoved to next protobuf State and validating unknown/missing enum values; tests cover transitions and errors.
CreateScheduleCommand decider
rsworkspace/crates/trogon-scheduler/src/commands/create_schedule.rs
CreateScheduleCommand struct; CreateScheduleDecideError variants and Display/Error; Decider impl with WritePrecondition::NoStream, persisting state_v1::State and emitting v1::ScheduleEvent::ScheduleCreated only when state is MISSING; tests verifying success, AlreadyExists, JobDeleted, and invalid-state error cases.
Commands module exports
rsworkspace/crates/trogon-scheduler/src/commands/mod.rs
Declares create_schedule and state submodules; exposes domain publicly; re-exports command/error types and EvolveError.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • TrogonStack/trogonai#191: Proto schema definitions for state_v1::State, StateValue, and v1::ScheduleEvent that the decider and state evolution logic depend on.
  • TrogonStack/trogonai#183: Protobuf message schemas for ScheduleCreated, Delivery, Message, Schedule, and ScheduleStatus targeted by the domain-to-protobuf conversions.

Suggested labels

rust:coverage-baseline-reset

Poem

🐰 I stitched schedules with careful care,
Headers in order, times set to spare,
IDs that refuse stray space,
State that moves in tidy grace,
A rabbit's hop — new jobs in the air!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 24.55% 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(scheduler): add create schedule command' directly and clearly summarizes the main change: introducing a new command for creating schedules in the scheduler module.
Description check ✅ Passed The description explains the purpose of enabling scheduler command handling and notes the scope constraint to keep the change focused on creation logic, which aligns with the changeset.
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/chore-create-schedule

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.

@yordis yordis force-pushed the yordis/chore-create-schedule branch from ce2f437 to 4bf191f Compare May 29, 2026 22:40
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
@yordis yordis force-pushed the yordis/chore-create-schedule branch from 4bf191f to 018fc2f Compare May 29, 2026 22:43

@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

🤖 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/trogon-scheduler/src/commands/domain/message.rs`:
- Around line 99-109: The domain type MessageContent currently accepts any
string but elsewhere conversion always sets "application/json", so make invalid
states unrepresentable by either (A) enforcing JSON validity in MessageContent:
change MessageContent::new and from_static to validate the input with
serde_json::from_str and return Result<MessageContent, Error> so only valid JSON
is constructed (update callers and conversions), or (B) make content-type
explicit by changing MessageContent to include a content_type field (e.g.,
MessageContent { body: String, content_type: String }) and update the conversion
logic that currently hardcodes "application/json" to read the content_type from
the instance; pick one approach and update all usages (constructors,
conversions, and serialization) accordingly so the domain invariant is
preserved.
- Around line 24-50: Replace the Vec<(String,String)> storage and combined
validation in MessageHeaders and MessageHeaders::new with domain value objects:
create HeaderName and HeaderValue newtypes that implement TryFrom<String> (or
TryFrom<&str>) and perform their respective validation (name rules and value
rules) inside their factories, then change MessageHeaders to contain
Vec<MessageHeader> or Vec<(HeaderName, HeaderValue)> and update
MessageHeaders::new to iterate the input, attempt to construct HeaderName and
HeaderValue for each pair (propagating the specific conversion errors), and push
the validated value objects into the collection rather than validating raw
strings in the aggregate constructor. Ensure unique error types map to
MessageHeadersError where appropriate and update any call sites that previously
expected (String,String) tuples to use the new types or to extract their inner
strings explicitly.

In
`@rsworkspace/crates/trogon-scheduler/src/commands/domain/schedule_event_sampling_source.rs`:
- Around line 4-6: Replace the primitive String in the
ScheduleEventSamplingSource enum with the validated domain value object
SamplingSubject: change the variant LatestFromSubject { subject: String } to use
subject: SamplingSubject, import/bring SamplingSubject into scope, and update
all creation sites, pattern matches, and serde/derive usages for
ScheduleEventSamplingSource (constructors, matches, and any
serialization/deserialization) to accept/produce SamplingSubject instances so
invalid subjects become unrepresentable.

In `@rsworkspace/crates/trogon-scheduler/src/commands/domain/schedule_id.rs`:
- Around line 80-83: The Display implementation for ScheduleIdError currently
prints "job id" which is misleading; update the message in impl fmt::Display for
ScheduleIdError so it says "schedule id '{}' is invalid: {}" instead, since this
error is emitted by ScheduleId::parse and serde failures; ensure any other
user-facing strings in the ScheduleIdError formatting remain consistent with
this rename.

In `@rsworkspace/crates/trogon-scheduler/src/commands/domain/schedule.rs`:
- Around line 377-380: ScheduleTimezone::new currently only
strips/control-validates tokens via validate_timezone_token and must
additionally reject non-existent cron timezone IDs; update ScheduleTimezone::new
to attempt resolving the token to a real timezone (e.g., parse/lookup using the
same timezone registry used by RRuleTimezone, such as chrono_tz::Tz::from_str or
your project's timezone resolver) and return ScheduleSpecError on failure,
mirroring RRuleTimezone's behavior; apply the same validation change to the
other factory area referenced (the second ScheduleTimezone construction block)
so all Schedule::Cron constructors guarantee the timezone is real at
construction.
- Around line 14-21: The Job struct is a domain aggregate but is currently
deriving Deserialize; stop exposing domain types to the wire by removing
Deserialize from Job and introduce a new boundary type (e.g., JobInput or
JobWire) that derives Deserialize and mirrors the JSON shape (fields:
id/ScheduleId, status/JobStatus, schedule/Schedule, delivery/Delivery,
message/JobMessage). Implement an explicit conversion (e.g., From<JobInput> for
Job or TryFrom<JobInput> for Job) that validates or maps any wire types into the
domain Job (referencing Job, JobInput/JobWire, and the
JobStatus/Schedule/Delivery/JobMessage types) and update all deserialization
sites to parse into JobInput and then convert once into Job. Ensure serde
annotations move to the new JobInput and that domain code and tests use Job only
after that single conversion.

In `@rsworkspace/crates/trogon-scheduler/src/commands/state.rs`:
- Line 15: The Display message for the enum variant Self::UnsupportedEvent is
misleading ("job event"); update the string to reference "schedule event"
instead so it accurately reflects the handled type—locate the Display/fmt
implementation that contains Self::UnsupportedEvent in commands/state.rs and
replace the message "protobuf job event is not supported by command state" with
a clear "protobuf schedule event is not supported by command state" (or
equivalent wording), and run tests or adjust any assertions that depended on the
old message.
🪄 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: bee14602-23fb-4509-81d0-9854d846539b

📥 Commits

Reviewing files that changed from the base of the PR and between 205df68 and ce2f437.

📒 Files selected for processing (13)
  • rsworkspace/crates/trogon-scheduler/src/commands/create_schedule.rs
  • rsworkspace/crates/trogon-scheduler/src/commands/domain/message.rs
  • rsworkspace/crates/trogon-scheduler/src/commands/domain/mod.rs
  • rsworkspace/crates/trogon-scheduler/src/commands/domain/schedule.rs
  • rsworkspace/crates/trogon-scheduler/src/commands/domain/schedule_details.rs
  • rsworkspace/crates/trogon-scheduler/src/commands/domain/schedule_event_delivery.rs
  • rsworkspace/crates/trogon-scheduler/src/commands/domain/schedule_event_sampling_source.rs
  • rsworkspace/crates/trogon-scheduler/src/commands/domain/schedule_event_schedule.rs
  • rsworkspace/crates/trogon-scheduler/src/commands/domain/schedule_event_status.rs
  • rsworkspace/crates/trogon-scheduler/src/commands/domain/schedule_id.rs
  • rsworkspace/crates/trogon-scheduler/src/commands/mod.rs
  • rsworkspace/crates/trogon-scheduler/src/commands/snapshot.rs
  • rsworkspace/crates/trogon-scheduler/src/commands/state.rs

Comment thread rsworkspace/crates/trogon-scheduler/src/commands/domain/message.rs Outdated
Comment thread rsworkspace/crates/trogon-scheduler/src/commands/domain/message.rs Outdated
Comment thread rsworkspace/crates/trogon-scheduler/src/commands/domain/schedule_id.rs Outdated
Comment thread rsworkspace/crates/trogon-scheduler/src/commands/domain/schedule.rs Outdated
Comment thread rsworkspace/crates/trogon-scheduler/src/commands/domain/schedule.rs Outdated
Comment thread rsworkspace/crates/trogon-scheduler/src/commands/state.rs Outdated
Schedule identity is a business concept; constraining it to NATS subject
grammar let a transport detail dictate what a valid identifier is. Subject
safety belongs at the subject-construction seam, not on the identity.

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
yordis added 2 commits May 29, 2026 19:35
Schedule event representations re-admitted invariants the domain already
proves (unbounded seconds, unvalidated subjects/expressions) by flattening
value objects back to primitives. Keeping the value objects through to the
proto boundary stops unvalidated values from being representable, and moves
the create-event factory beside the command that emits it.

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Domain-time to protobuf conversions were duplicated inside the scheduler;
hosting them in the proto crate behind a chrono feature lets any crate reuse
them without depending on scheduler internals.

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Comment thread rsworkspace/crates/trogon-scheduler/src/commands/domain/schedule.rs
Comment thread rsworkspace/crates/trogon-scheduler/src/commands/domain/message.rs

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

🤖 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/trogon-scheduler/src/commands/create_schedule.rs`:
- Around line 32-36: The current Display impl for CreateScheduleDecideError uses
Debug ("{self:?}") which leaks internals; replace the impl of std::fmt::Display
for CreateScheduleDecideError (the fn fmt) with a match on each enum variant and
return concise, user-facing messages for each case (including any inner error
messages where appropriate), e.g., map validation/permission/internal variants
to human-readable strings and include underlying error.display() when useful;
keep the Display implementation stable for logging and ensure the error type
still implements std::error::Error.
🪄 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: 06e87181-2a0f-4d3a-9577-a8af83c8a552

📥 Commits

Reviewing files that changed from the base of the PR and between ce2f437 and 958d94c.

📒 Files selected for processing (15)
  • rsworkspace/crates/trogon-scheduler/src/commands/create_schedule.rs
  • rsworkspace/crates/trogon-scheduler/src/commands/domain/message.rs
  • rsworkspace/crates/trogon-scheduler/src/commands/domain/mod.rs
  • rsworkspace/crates/trogon-scheduler/src/commands/domain/schedule.rs
  • rsworkspace/crates/trogon-scheduler/src/commands/domain/schedule_details.rs
  • rsworkspace/crates/trogon-scheduler/src/commands/domain/schedule_event_delivery.rs
  • rsworkspace/crates/trogon-scheduler/src/commands/domain/schedule_event_sampling_source.rs
  • rsworkspace/crates/trogon-scheduler/src/commands/domain/schedule_event_schedule.rs
  • rsworkspace/crates/trogon-scheduler/src/commands/domain/schedule_event_status.rs
  • rsworkspace/crates/trogon-scheduler/src/commands/domain/schedule_id.rs
  • rsworkspace/crates/trogon-scheduler/src/commands/mod.rs
  • rsworkspace/crates/trogon-scheduler/src/commands/state.rs
  • rsworkspace/crates/trogonai-proto/Cargo.toml
  • rsworkspace/crates/trogonai-proto/src/convert.rs
  • rsworkspace/crates/trogonai-proto/src/lib.rs
✅ Files skipped from review due to trivial changes (2)
  • rsworkspace/crates/trogonai-proto/src/lib.rs
  • rsworkspace/crates/trogon-scheduler/src/commands/mod.rs
🚧 Files skipped from review as they are similar to previous changes (9)
  • rsworkspace/crates/trogon-scheduler/src/commands/domain/schedule_details.rs
  • rsworkspace/crates/trogon-scheduler/src/commands/domain/schedule_event_status.rs
  • rsworkspace/crates/trogon-scheduler/src/commands/domain/schedule_event_sampling_source.rs
  • rsworkspace/crates/trogon-scheduler/src/commands/domain/schedule_event_delivery.rs
  • rsworkspace/crates/trogon-scheduler/src/commands/domain/mod.rs
  • rsworkspace/crates/trogon-scheduler/src/commands/state.rs
  • rsworkspace/crates/trogon-scheduler/src/commands/domain/schedule_event_schedule.rs
  • rsworkspace/crates/trogon-scheduler/src/commands/domain/message.rs
  • rsworkspace/crates/trogon-scheduler/src/commands/domain/schedule.rs

Comment thread rsworkspace/crates/trogon-scheduler/src/commands/create_schedule.rs
@yordis yordis force-pushed the yordis/chore-create-schedule branch from 483dade to f39e1c5 Compare June 1, 2026 04:13
Comment thread rsworkspace/crates/trogon-scheduler/src/commands/domain/schedule.rs
@yordis yordis force-pushed the yordis/chore-create-schedule branch from f39e1c5 to 01b4b90 Compare June 1, 2026 04:28
@github-actions

github-actions Bot commented Jun 1, 2026

Copy link
Copy Markdown

badge

Code Coverage Summary

Details
Filename                                                                              Stmts    Miss  Cover    Missing
----------------------------------------------------------------------------------  -------  ------  -------  ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
crates/trogon-service-config/src/lib.rs                                                  92       0  100.00%
crates/acp-nats/src/nats/subjects/commands/cancel.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/acp-nats/src/nats/subjects/commands/set_model.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/fork.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/trogon-gateway/src/source/sentry/server.rs                                       311       0  100.00%
crates/trogon-gateway/src/source/sentry/signature.rs                                     54       0  100.00%
crates/trogon-gateway/src/source/sentry/sentry_client_secret.rs                          17       0  100.00%
crates/mcp-nats/src/client.rs                                                            31       0  100.00%
crates/mcp-nats/src/mcp_prefix.rs                                                        36       0  100.00%
crates/mcp-nats/src/jsonrpc.rs                                                           22       0  100.00%
crates/mcp-nats/src/config.rs                                                           110       0  100.00%
crates/mcp-nats/src/mcp_peer_id.rs                                                       33       0  100.00%
crates/mcp-nats/src/server.rs                                                            31       0  100.00%
crates/mcp-nats/src/transport.rs                                                        722       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/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/list_prompts.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/get_task.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/ping.rs                                          9       0  100.00%
crates/mcp-nats/src/nats/subjects/server/read_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/list_tasks.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/get_prompt.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_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/cancel_task.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_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/subscribe_resource.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/get_task_result.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/elicitation_completed.rs                        12       0  100.00%
crates/trogon-gateway/src/source/telegram/config.rs                                     109       0  100.00%
crates/trogon-gateway/src/source/telegram/registration.rs                               327       0  100.00%
crates/trogon-gateway/src/source/telegram/server.rs                                     339       0  100.00%
crates/trogon-gateway/src/source/telegram/signature.rs                                   32       0  100.00%
crates/trogon-decider-runtime/src/execution.rs                                         1341       0  100.00%
crates/trogon-decider-runtime/src/stream/read_stream.rs                                  10       0  100.00%
crates/trogon-decider-runtime/src/stream/stream_position.rs                              29       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-gateway/src/source/standard_webhooks.rs                                   172       0  100.00%
crates/acp-nats/src/config.rs                                                           203       0  100.00%
crates/acp-nats/src/lib.rs                                                               69       0  100.00%
crates/acp-nats/src/acp_prefix.rs                                                        50       0  100.00%
crates/acp-nats/src/pending_prompt_waiters.rs                                           134       0  100.00%
crates/acp-nats/src/ext_method_name.rs                                                   68       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/in_flight_slot_guard.rs                                              32       0  100.00%
crates/acp-nats/src/error.rs                                                             82       0  100.00%
crates/acp-nats/src/jsonrpc.rs                                                            6       0  100.00%
crates/acp-nats/src/session_id.rs                                                        71       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/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/session_update.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_create.rs                          12       0  100.00%
crates/acp-nats/src/nats/subjects/client_ops/terminal_kill.rs                            12       0  100.00%
crates/acp-nats/src/nats/subjects/client_ops/fs_write_text_file.rs                       12       0  100.00%
crates/mcp-nats/src/telemetry/transport.rs                                                6       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/trogon-nats/src/jetstream/publish.rs                                              64       0  100.00%
crates/trogon-nats/src/jetstream/stream_max_age.rs                                       18       0  100.00%
crates/trogon-nats/src/jetstream/claim_check.rs                                         346       0  100.00%
crates/trogon-nats/src/jetstream/traits.rs                                               40      40  0.00%    181-251
crates/trogon-nats/src/jetstream/mocks.rs                                              1637       7  99.57%   450, 824-826, 1003-1005
crates/trogon-nats/src/jetstream/create_conflicts.rs                                     24       0  100.00%
crates/trogon-scheduler/src/commands/domain/message.rs                                  224       0  100.00%
crates/trogon-scheduler/src/commands/domain/schedule.rs                                 736       0  100.00%
crates/trogon-scheduler/src/commands/domain/schedule_event_delivery.rs                   25       0  100.00%
crates/trogon-scheduler/src/commands/domain/schedule_id.rs                               91       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_schedule.rs                   83       0  100.00%
crates/trogon-scheduler/src/commands/domain/schedule_event_status.rs                     10       0  100.00%
crates/mcp-nats-server/src/config.rs                                                    276       0  100.00%
crates/mcp-nats-server/src/allowed_host.rs                                               90       0  100.00%
crates/mcp-nats-server/src/main.rs                                                      357     127  64.43%   149-166, 202-204, 214, 220-221, 228-231, 255-257, 261-270, 292-305, 310-358, 489, 492, 500-542
crates/trogon-nats/src/lease/renew.rs                                                   246      19  92.28%   23-29, 48-59
crates/trogon-nats/src/lease/renew_interval.rs                                           61       0  100.00%
crates/trogon-nats/src/lease/acquire.rs                                                   5       5  0.00%    9-14
crates/trogon-nats/src/lease/nats_kv_lease_config.rs                                     26       0  100.00%
crates/trogon-nats/src/lease/provision.rs                                               187      10  94.65%   82-92
crates/trogon-nats/src/lease/release.rs                                                   5       5  0.00%    8-12
crates/trogon-nats/src/lease/lease_timing.rs                                             15       0  100.00%
crates/trogon-nats/src/lease/lease_bucket.rs                                             19       0  100.00%
crates/trogon-nats/src/lease/lease_config_error.rs                                       11       0  100.00%
crates/trogon-nats/src/lease/lease_key.rs                                                19       0  100.00%
crates/trogon-nats/src/lease/ttl.rs                                                      73       0  100.00%
crates/trogon-nats/src/lease/mod.rs                                                     561      13  97.68%   180-193
crates/trogon-std/src/args.rs                                                            19       9  52.63%   11-28
crates/trogon-std/src/secret_string.rs                                                   35       0  100.00%
crates/trogon-std/src/http.rs                                                            19       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/duration.rs                                                        45       0  100.00%
crates/trogon-std/src/uuid.rs                                                             7       0  100.00%
crates/trogon-gateway/src/source/discord/config.rs                                      108       0  100.00%
crates/trogon-gateway/src/source/discord/gateway.rs                                     426       1  99.77%   137
crates/trogon-decider-runtime/src/headers/header_map.rs                                  54       3  94.44%   20-22
crates/trogon-decider-runtime/src/headers/mod.rs                                         74       0  100.00%
crates/trogon-decider-runtime/src/headers/header_name.rs                                 33       0  100.00%
crates/trogon-decider-runtime/src/headers/from_entries_error.rs                          11       0  100.00%
crates/trogon-decider-runtime/src/headers/header_value.rs                                37       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/incidentio/config.rs                                    16       0  100.00%
crates/trogon-gateway/src/source/incidentio/incidentio_signing_secret.rs                 67       0  100.00%
crates/trogon-gateway/src/source/incidentio/incidentio_event_type.rs                     62       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-std/src/telemetry/http.rs                                                 217       0  100.00%
crates/trogonai-proto/src/codec.rs                                                       16       0  100.00%
crates/trogonai-proto/src/convert.rs                                                     51       0  100.00%
crates/acp-nats/src/telemetry/metrics.rs                                                 53       0  100.00%
crates/trogon-nats/src/telemetry/messaging.rs                                            82       0  100.00%
crates/acp-nats/src/client/terminal_kill.rs                                             290       0  100.00%
crates/acp-nats/src/client/terminal_create.rs                                           274       0  100.00%
crates/acp-nats/src/client/session_update.rs                                             55       0  100.00%
crates/acp-nats/src/client/terminal_output.rs                                           206       0  100.00%
crates/acp-nats/src/client/terminal_release.rs                                          347       0  100.00%
crates/acp-nats/src/client/rpc_reply.rs                                                  64       0  100.00%
crates/acp-nats/src/client/ext_session_prompt_response.rs                               135       0  100.00%
crates/acp-nats/src/client/fs_read_text_file.rs                                         356       0  100.00%
crates/acp-nats/src/client/terminal_wait_for_exit.rs                                    378       0  100.00%
crates/acp-nats/src/client/request_permission.rs                                        308       0  100.00%
crates/acp-nats/src/client/mod.rs                                                      2851       0  100.00%
crates/acp-nats/src/client/ext.rs                                                       308       8  97.40%   163-172, 189-198
crates/acp-nats/src/client/fs_write_text_file.rs                                        418       0  100.00%
crates/trogon-gateway/src/source/slack/server.rs                                        854       0  100.00%
crates/trogon-gateway/src/source/slack/config.rs                                         68       0  100.00%
crates/trogon-gateway/src/source/slack/signature.rs                                      77       0  100.00%
crates/trogon-gateway/src/source/slack/socket_mode.rs                                   731       0  100.00%
crates/mcp-nats-stdio/src/main.rs                                                       212       0  100.00%
crates/mcp-nats-stdio/src/config.rs                                                     160       0  100.00%
crates/trogon-gateway/src/source_status.rs                                               28       0  100.00%
crates/trogon-gateway/src/http.rs                                                       145       0  100.00%
crates/trogon-gateway/src/main.rs                                                       116       0  100.00%
crates/trogon-gateway/src/source_plugin.rs                                              269       3  98.88%   82, 141-142
crates/trogon-gateway/src/streams.rs                                                    129       0  100.00%
crates/trogon-gateway/src/source_integration_id.rs                                       61       3  95.08%   55, 57, 65
crates/trogon-gateway/src/config.rs                                                    2655      46  98.27%   105, 124, 342-343, 346, 744, 747, 907, 964, 1047, 1050, 1053, 1057, 1141-1148, 1225, 1228, 1231, 1236, 1294, 1297, 1300, 1379, 1382, 1385, 1389, 1453, 1456, 1459, 1522, 1525, 1528, 1533, 1608, 1611, 1614, 1619, 1677, 1680, 1683, 1896-1898
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_client.rs                             9       0  100.00%
crates/mcp-nats/src/nats/subjects/subscriptions/one_server.rs                             9       0  100.00%
crates/acp-nats/src/jetstream/provision.rs                                               53       0  100.00%
crates/acp-nats/src/jetstream/ext_policy.rs                                              26       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/mcp-nats/src/nats/subjects/client/progress.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/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/create_message.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/list_roots.rs                                   12       0  100.00%
crates/trogon-scheduler/src/commands/create_schedule.rs                                 195       0  100.00%
crates/trogon-scheduler/src/commands/state.rs                                           194       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-decider-nats/src/snapshot_store.rs                                        969     117  87.93%   64-179, 202-204, 218-227, 275-277, 315-317, 335, 352-358, 461-467, 549, 685, 690, 786-788, 794-796, 830-831, 841-842, 861, 889-890
crates/trogon-decider-nats/src/store.rs                                                 145      65  55.17%   33-191
crates/trogon-decider-nats/src/stream_store.rs                                          725      84  88.41%   70-213, 240-258, 301, 329-330, 333, 349-353, 519-520, 561, 574-578
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-telemetry/src/resource_attribute.rs                                        23       0  100.00%
crates/trogon-telemetry/src/lib.rs                                                      197      23  88.32%   94, 99, 104, 114-115, 121-139, 175, 178, 181, 187
crates/trogon-telemetry/src/trace.rs                                                     23       1  95.65%   22
crates/trogon-telemetry/src/log.rs                                                       68       1  98.53%   33
crates/trogon-telemetry/src/service_name.rs                                              44       0  100.00%
crates/trogon-telemetry/src/metric.rs                                                    26       1  96.15%   29
crates/trogonai-proto/src/scheduler/schedules/codec.rs                                  254       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                              78       0  100.00%
crates/acp-nats-agent/src/connection.rs                                                1270       1  99.92%   607
crates/trogon-decider/src/decision.rs                                                    37       0  100.00%
crates/trogon-decider/src/act.rs                                                         62       0  100.00%
crates/trogon-decider/src/testing.rs                                                    660       0  100.00%
crates/trogon-decider/src/lib.rs                                                        143       0  100.00%
crates/trogon-decider/src/events.rs                                                      49       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_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_session.rs                           12       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_client.rs                            15       0  100.00%
crates/acp-nats/src/nats/subjects/subscriptions/one_agent.rs                             15       0  100.00%
crates/trogon-gateway/src/source/notion/verification_token.rs                           240       0  100.00%
crates/trogon-gateway/src/source/notion/server.rs                                       318       8  97.48%   93-97, 130-131, 150-151
crates/trogon-gateway/src/source/notion/signature.rs                                     56       1  98.21%   32
crates/trogon-gateway/src/source/notion/notion_event_type.rs                             46       3  93.48%   47-49
crates/trogon-gateway/src/source/notion/notion_verification_token.rs                     17       0  100.00%
crates/acp-nats/src/agent/close_session.rs                                               63       0  100.00%
crates/acp-nats/src/agent/js_request.rs                                                 283       0  100.00%
crates/acp-nats/src/agent/prompt.rs                                                     471       0  100.00%
crates/acp-nats/src/agent/authenticate.rs                                                49       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/test_support.rs                                               267       0  100.00%
crates/acp-nats/src/agent/initialize.rs                                                  79       0  100.00%
crates/acp-nats/src/agent/logout.rs                                                      49       0  100.00%
crates/acp-nats/src/agent/ext_method.rs                                                  82       0  100.00%
crates/acp-nats/src/agent/set_session_model.rs                                           67       0  100.00%
crates/acp-nats/src/agent/cancel.rs                                                     101       0  100.00%
crates/acp-nats/src/agent/fork_session.rs                                                94       0  100.00%
crates/acp-nats/src/agent/list_sessions.rs                                               47       0  100.00%
crates/acp-nats/src/agent/new_session.rs                                                 82       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/set_session_mode.rs                                            67       0  100.00%
crates/acp-nats/src/agent/ext_notification.rs                                            82       0  100.00%
crates/acp-nats/src/agent/resume_session.rs                                              90       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-std/src/dirs/fixed.rs                                                      80       0  100.00%
crates/trogon-std/src/dirs/system.rs                                                     71       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%   65, 113-120, 126-128, 145, 174-193
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/authenticate.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_notify.rs                                    9       0  100.00%
crates/acp-nats/src/nats/subjects/global/initialize.rs                                    6       0  100.00%
crates/acp-nats/src/nats/subjects/global/ext.rs                                           9       0  100.00%
crates/acp-nats-server/src/transport.rs                                                1945     106  94.55%   277, 536, 554, 581, 635, 640, 659, 671, 790, 813-815, 867, 884-887, 982-985, 1059, 1062, 1065, 1074, 1078, 1081, 1084-1087, 1106, 1138-1141, 1149-1154, 1166-1170, 1174-1183, 1195-1196, 1214-1215, 1225, 1241-1245, 1273-1279, 1299-1301, 1306-1310, 1313-1318, 1335, 1337-1338, 1420-1421, 1433-1434, 1454-1455, 1507-1523, 2228, 2272, 2325, 2381, 2394
crates/acp-nats-server/src/acp_connection_id.rs                                          45       0  100.00%
crates/acp-nats-server/src/main.rs                                                      896      10  98.88%   100, 231-238, 437
crates/acp-nats-server/src/connection.rs                                                171      32  81.29%   76-83, 88-99, 115, 117-118, 123, 132-133, 138, 142, 146, 149, 157, 161, 164, 167-171, 207
crates/acp-nats-server/src/config.rs                                                    137       9  93.43%   41, 50-61
crates/mcp-nats/src/nats/subjects/mod.rs                                                 89       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/trogon-decider-runtime/src/event/event_identity.rs                                 3       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/nats/mod.rs                                                          99       0  100.00%
crates/mcp-nats/src/nats/parsing.rs                                                     191       0  100.00%
crates/trogon-gateway/src/source/twitter/signature.rs                                    69       0  100.00%
crates/trogon-gateway/src/source/twitter/config.rs                                       17       0  100.00%
crates/trogon-gateway/src/source/twitter/server.rs                                      525       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/prompt_response.rs                           27       0  100.00%
crates/acp-nats/src/nats/subjects/responses/update.rs                                    27       0  100.00%
crates/trogon-gateway/src/source/github/signature.rs                                     61       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/gitlab/signature.rs                                    165       0  100.00%
crates/trogon-gateway/src/source/gitlab/gitlab_signing_token.rs                          74       0  100.00%
crates/trogon-gateway/src/source/gitlab/server.rs                                       460       0  100.00%
crates/trogon-nats/src/messaging.rs                                                     561       2  99.64%   144, 154
crates/trogon-nats/src/token.rs                                                           6       0  100.00%
crates/trogon-nats/src/nats_token.rs                                                    157       0  100.00%
crates/trogon-nats/src/connect.rs                                                        94       9  90.43%   22-23, 33, 60-65
crates/trogon-nats/src/auth.rs                                                          114       0  100.00%
crates/trogon-nats/src/mocks.rs                                                         317       0  100.00%
crates/trogon-nats/src/client.rs                                                         22      22  0.00%    50-86
crates/trogon-nats/src/subject_token_violation.rs                                        17       0  100.00%
crates/trogon-decider-runtime/src/snapshot/codec/snapshot_envelope_encode_error.rs       20       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                65       0  100.00%
crates/trogon-decider-runtime/src/snapshot/codec/encoded_snapshot.rs                    120       0  100.00%
crates/trogon-decider-runtime/src/snapshot/codec/snapshot_encode_error.rs                49       0  100.00%
crates/trogon-decider-runtime/src/snapshot/codec/snapshot_envelope_decode_error.rs       38       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/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/mod.rs                                                          23       0  100.00%
TOTAL                                                                                 42604     851  98.00%

Diff against main

Filename                                                                         Stmts    Miss  Cover
-----------------------------------------------------------------------------  -------  ------  --------
crates/trogon-scheduler/src/commands/domain/message.rs                            +224       0  +100.00%
crates/trogon-scheduler/src/commands/domain/schedule.rs                           +736       0  +100.00%
crates/trogon-scheduler/src/commands/domain/schedule_event_delivery.rs             +25       0  +100.00%
crates/trogon-scheduler/src/commands/domain/schedule_id.rs                         +91       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_schedule.rs             +83       0  +100.00%
crates/trogon-scheduler/src/commands/domain/schedule_event_status.rs               +10       0  +100.00%
crates/trogonai-proto/src/convert.rs                                               +51       0  +100.00%
crates/trogon-scheduler/src/commands/create_schedule.rs                           +195       0  +100.00%
crates/trogon-scheduler/src/commands/state.rs                                     +194       0  +100.00%
crates/acp-nats-server/src/transport.rs                                            +88       0  +0.26%
TOTAL                                                                            +1717       0  +0.08%

Results for commit: 7de8e0d

Minimum allowed coverage is 95%

♻️ This comment has been updated with latest results

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
@yordis yordis force-pushed the yordis/chore-create-schedule branch from 01b4b90 to 271aba5 Compare June 1, 2026 05:03

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
rsworkspace/crates/trogon-scheduler/src/commands/domain/schedule.rs (1)

224-227: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Replace std::io::Error::other/format! in RRULE validation with a typed error source

ScheduleSpecError::InvalidRRule { source: Box<dyn std::error::Error> } is currently populated with std::io::Error::other(...) (and format!(...)) at lines 224-227, 251-254, 260-265, and 272-275, making the failure reasons opaque/stringly-typed. Use a dedicated RRuleValidationError enum (implements Display + Error) and box that into InvalidRRule.source for these branches.

🤖 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/trogon-scheduler/src/commands/domain/schedule.rs` around
lines 224 - 227, Replace the ad-hoc std::io::Error::other/format!-based sources
used when constructing ScheduleSpecError::InvalidRRule with a new typed
RRuleValidationError enum (implementing std::fmt::Display + std::error::Error)
and box that into InvalidRRule.source; add variants that match the four failing
cases (e.g., EmptyOrMultiLine, InvalidProperty(String), ParseError(String),
etc.), implement Display/Error for RRuleValidationError, and in the existing
places that return Err(ScheduleSpecError::InvalidRRule { rrule: raw, source:
Box::new(...) }) (the branches around the current returns) replace
Box::new(std::io::Error::other(...)) / Box::new(format!(...)) with
Box::new(RRuleValidationError::YourVariant(...)) so the error source is strongly
typed and descriptive.
rsworkspace/crates/trogon-scheduler/src/commands/domain/message.rs (1)

6-9: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Preserve typed header validation errors in MessageHeaders::new instead of flattening to strings.

MessageHeadersError stores InvalidName/InvalidValue as { name: String }, and MessageHeaders::new collapses HeaderNameError/HeaderValueError by extracting only source.name or discarding the source entirely—dropping the typed cause. The local HeaderNameError/HeaderValueError in this module also don’t implement Display/std::error::Error, so they can’t be chained per the error guidelines.

Update MessageHeadersError to wrap the source errors (and use HeaderName as the typed header-name field), implement Display + std::error::Error for HeaderNameError/HeaderValueError, and adjust MessageHeadersError’s Display plus the map_err calls accordingly.

🤖 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/trogon-scheduler/src/commands/domain/message.rs` around
lines 6 - 9, Change MessageHeadersError to carry the typed causes and
header-name type instead of plain strings: make its variants like InvalidName {
name: HeaderName, source: HeaderNameError } and InvalidValue { name: HeaderName,
source: HeaderValueError }, update MessageHeaders::new map_err calls to wrap the
original HeaderNameError/HeaderValueError (preserving them as source) and supply
the parsed HeaderName for name; implement Display and std::error::Error for the
local HeaderNameError and HeaderValueError types so they can be chained; and
update MessageHeadersError’s Display impl to render a message plus use
std::error::Error::source() to return the wrapped source so chained errors are
preserved.
rsworkspace/crates/trogon-scheduler/src/commands/state.rs (1)

48-58: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Reject ScheduleCreated events that omit status.

If inner.status or status.kind is missing, this branch currently materializes the schedule as STATE_VALUE_PRESENT_ENABLED. That silently turns a malformed wire event into a live schedule instead of surfacing bad input.

Proposed fix
         Some(ScheduleEventCase::ScheduleCreated(inner)) => {
+            let Some(kind) = inner.status.as_option().and_then(|status| status.kind.as_ref()) else {
+                return Err(EvolveError::UnsupportedEvent);
+            };
+
             if current_state == state_v1::StateValue::STATE_VALUE_DELETED {
                 state_v1::StateValue::STATE_VALUE_DELETED
-            } else if matches!(
-                inner.status.as_option().and_then(|status| status.kind.as_ref()),
-                Some(ScheduleStatusKind::Paused(_))
-            ) {
+            } else if matches!(kind, ScheduleStatusKind::Paused(_)) {
                 state_v1::StateValue::STATE_VALUE_PRESENT_DISABLED
             } else {
                 state_v1::StateValue::STATE_VALUE_PRESENT_ENABLED
             }
         }

As per coding guidelines, "Untrusted input must use distinct *Input / *Wire / *Request types. Convert those boundary types into domain types exactly once."

🤖 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/trogon-scheduler/src/commands/state.rs` around lines 48 -
58, The ScheduleCreated branch currently treats missing inner.status or
status.kind as STATE_VALUE_PRESENT_ENABLED; instead detect when
inner.status.as_option() is None or status.kind is None and reject the event
(return an error) rather than materializing it. Update the
ScheduleEventCase::ScheduleCreated handling to explicitly pattern-match
inner.status.as_option().and_then(|s| s.kind.as_ref()); if that yields None
return a domain-level error (e.g. Err(InvalidWireEvent(...)) from the function
that maps events to state) so malformed wire input is surfaced, and adjust
callers/signature (propagate Result) as needed.
🤖 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/trogonai-proto/src/convert.rs`:
- Around line 10-17: The function duration_from_seconds currently panics via
expect; change it to return Result<Duration, DurationConversionError> and add a
DurationConversionError enum (e.g., OutOfRange { seconds: u64 }) with Display
and std::error::Error impls, then replace the try_from/ok/filter chain with
ok_or to return DurationConversionError::OutOfRange when seconds is not
representable or exceeds PROTOBUF_DURATION_MAX_SECONDS, and finally return
Ok(Duration::from_secs(converted_seconds_i64)); alternatively, if callers
already validate (e.g., EverySeconds), document the precondition and keep the
function infallible.

---

Outside diff comments:
In `@rsworkspace/crates/trogon-scheduler/src/commands/domain/message.rs`:
- Around line 6-9: Change MessageHeadersError to carry the typed causes and
header-name type instead of plain strings: make its variants like InvalidName {
name: HeaderName, source: HeaderNameError } and InvalidValue { name: HeaderName,
source: HeaderValueError }, update MessageHeaders::new map_err calls to wrap the
original HeaderNameError/HeaderValueError (preserving them as source) and supply
the parsed HeaderName for name; implement Display and std::error::Error for the
local HeaderNameError and HeaderValueError types so they can be chained; and
update MessageHeadersError’s Display impl to render a message plus use
std::error::Error::source() to return the wrapped source so chained errors are
preserved.

In `@rsworkspace/crates/trogon-scheduler/src/commands/domain/schedule.rs`:
- Around line 224-227: Replace the ad-hoc std::io::Error::other/format!-based
sources used when constructing ScheduleSpecError::InvalidRRule with a new typed
RRuleValidationError enum (implementing std::fmt::Display + std::error::Error)
and box that into InvalidRRule.source; add variants that match the four failing
cases (e.g., EmptyOrMultiLine, InvalidProperty(String), ParseError(String),
etc.), implement Display/Error for RRuleValidationError, and in the existing
places that return Err(ScheduleSpecError::InvalidRRule { rrule: raw, source:
Box::new(...) }) (the branches around the current returns) replace
Box::new(std::io::Error::other(...)) / Box::new(format!(...)) with
Box::new(RRuleValidationError::YourVariant(...)) so the error source is strongly
typed and descriptive.

In `@rsworkspace/crates/trogon-scheduler/src/commands/state.rs`:
- Around line 48-58: The ScheduleCreated branch currently treats missing
inner.status or status.kind as STATE_VALUE_PRESENT_ENABLED; instead detect when
inner.status.as_option() is None or status.kind is None and reject the event
(return an error) rather than materializing it. Update the
ScheduleEventCase::ScheduleCreated handling to explicitly pattern-match
inner.status.as_option().and_then(|s| s.kind.as_ref()); if that yields None
return a domain-level error (e.g. Err(InvalidWireEvent(...)) from the function
that maps events to state) so malformed wire input is surfaced, and adjust
callers/signature (propagate Result) as needed.
🪄 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: 446a90db-706b-4aac-af5c-88236b52ef71

📥 Commits

Reviewing files that changed from the base of the PR and between 483dade and 271aba5.

⛔ Files ignored due to path filters (1)
  • rsworkspace/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (14)
  • rsworkspace/crates/trogon-scheduler/Cargo.toml
  • rsworkspace/crates/trogon-scheduler/src/commands/create_schedule.rs
  • rsworkspace/crates/trogon-scheduler/src/commands/domain/message.rs
  • rsworkspace/crates/trogon-scheduler/src/commands/domain/mod.rs
  • rsworkspace/crates/trogon-scheduler/src/commands/domain/schedule.rs
  • rsworkspace/crates/trogon-scheduler/src/commands/domain/schedule_event_sampling_source.rs
  • rsworkspace/crates/trogon-scheduler/src/commands/domain/schedule_event_schedule.rs
  • rsworkspace/crates/trogon-scheduler/src/commands/domain/schedule_event_status.rs
  • rsworkspace/crates/trogon-scheduler/src/commands/domain/schedule_id.rs
  • rsworkspace/crates/trogon-scheduler/src/commands/state.rs
  • rsworkspace/crates/trogon-scheduler/src/error.rs
  • rsworkspace/crates/trogon-scheduler/src/lib.rs
  • rsworkspace/crates/trogon-scheduler/tests/create_schedule_errors.rs
  • rsworkspace/crates/trogonai-proto/src/convert.rs
🚧 Files skipped from review as they are similar to previous changes (5)
  • rsworkspace/crates/trogon-scheduler/src/commands/domain/schedule_event_status.rs
  • rsworkspace/crates/trogon-scheduler/src/commands/domain/mod.rs
  • rsworkspace/crates/trogon-scheduler/src/commands/create_schedule.rs
  • rsworkspace/crates/trogon-scheduler/src/commands/domain/schedule_id.rs
  • rsworkspace/crates/trogon-scheduler/src/commands/domain/schedule_event_schedule.rs

Comment thread rsworkspace/crates/trogonai-proto/src/convert.rs Outdated
yordis added 9 commits June 1, 2026 02:40
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Align create-schedule command and domain naming with schedule terminology by replacing JobStatus, JobHeaders, and JobMessage with ScheduleEventStatus, ScheduleHeaders, and ScheduleMessage.

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
@yordis yordis force-pushed the yordis/chore-create-schedule branch from 2ce160a to 38a4fd5 Compare June 1, 2026 17:10
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
yordis added 2 commits June 1, 2026 13:34
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
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 and found 2 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 599c911. Configure here.

Comment thread rsworkspace/crates/trogon-scheduler/src/commands/state.rs
Comment thread rsworkspace/crates/trogon-scheduler/src/commands/domain/schedule.rs
yordis added 2 commits June 1, 2026 13:46
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
@yordis yordis merged commit d54ab6b into main Jun 1, 2026
7 checks passed
@yordis yordis deleted the yordis/chore-create-schedule branch June 1, 2026 18:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant