feat(agent-runtime): complete gateway webhook dispatcher parity#283
Conversation
|
Note Reviews pausedIt 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 Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughRoutes gateway /webhook through a dispatcher-backed Agent turn with a session-aware TurnContext, threads session_id into memory recall/store, surfaces structured AgentTurnResult/events, adds a feature-flagged dispatcher path and webhook dispatcher adapter, and updates tests/specs/docs to prove parity and env-test isolation. Changes
Sequence DiagramsequenceDiagram
participant Client
participant Gateway as Gateway Handler
participant Dispatcher as Webhook Dispatcher
participant Agent
participant Memory
participant Tools
Client->>Gateway: POST /webhook (with/without X-Session-Id)
Gateway->>Gateway: resolve_session_id() -> (session_id, source)
Gateway->>Gateway: check cfg.gateway.webhook_dispatcher_enabled
alt Dispatcher Enabled
Gateway->>Dispatcher: execute(WebhookTurnRequest {session_id, include_sse})
Dispatcher->>Agent: bootstrap Agent & call turn_with_context(TurnContext)
Agent->>Memory: load_context(user_message, session_id)
Memory-->>Agent: recalled_context
Agent->>Tools: dispatch/execute tools
Tools-->>Agent: tool_results
Agent->>Agent: detect approval_required -> set AgentTurnResult.approval_required?
Agent->>Memory: auto_save(assistant_response, session_id)
Agent-->>Dispatcher: AgentTurnResult (final_text, events, outcome)
Dispatcher->>Gateway: WebhookTurnResult (mapped outcome, response_text, event_frames)
Gateway->>Client: HTTP response (status + JSON / events_sse)
else Legacy Fallback
Gateway->>Gateway: pre_execution::evaluate()
Gateway->>Agent: Provider::simple_chat(...) (legacy path)
Agent-->>Gateway: response text
Gateway-->>Client: HTTP response (legacy mapping)
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
📝 Coding Plan
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. Comment |
…-canonical-agent-dispatcher
Deploying corvus with
|
| Latest commit: |
e094d61
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://6ea5e457.corvus-42x.pages.dev |
| Branch Preview URL: | https://feature-257-complete-gateway.corvus-42x.pages.dev |
✅ Contributor ReportUser: @yacosta738
Contributor Report evaluates based on public GitHub activity. Analysis period: 2025-03-20 to 2026-03-20 |
There was a problem hiding this comment.
Actionable comments posted: 18
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
clients/agent-runtime/src/agent/memory_loader.rs (2)
331-377:⚠️ Potential issue | 🟡 MinorAdd a Cerebro loader session-forwarding test to prevent regressions.
You added explicit session propagation coverage for
DefaultMemoryLoader, but not forCerebroMemoryLoader. Add one focused test that passesSome(session_id)and asserts recall sees that value (using endpoint-missing or egress-blocked path to avoid network calls).As per coding guidelines
**/*: Security first, performance second... Look for ... missing tests ....🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@clients/agent-runtime/src/agent/memory_loader.rs` around lines 331 - 377, Add a new async test mirroring the DefaultMemoryLoader session test but for CerebroMemoryLoader: instantiate a CerebroMemoryLoader (use the endpoint-missing path by calling CerebroMemoryLoader::new(MemoryCerebroConfig::default(), 5, 0.4) or the egress-blocked config), use a SessionTrackingMemory instance, call loader.load_context(&memory, "hello", Some("webhook-session-1")).await.unwrap(), and then assert that memory.recall_sessions.lock().unwrap().clone() equals vec![Some("webhook-session-1".to_string())]; reference CerebroMemoryLoader, MemoryCerebroConfig, load_context, and SessionTrackingMemory.recall_sessions to locate the code.
118-123:⚠️ Potential issue | 🟠 MajorAdd session scoping to Cerebro recall payload or document the behavioral difference.
CerebroMemoryLoaderacceptssession_idand passes it to local memory recall, but omits it entirely from the remote Cerebro MCP payload. While Cerebro'smem_searchschema doesn't currently supportsession_id, this creates a silent behavioral gap:DefaultMemoryLoaderrespects session boundaries, butCerebroMemoryLoadersilently ignores them for remote recall, risking cross-session memory leakage in webhook flows.Either:
- Extend Cerebro's
mem_searchinput schema to acceptsession_idand propagate it via the payload- Or add explicit documentation/test that
CerebroMemoryLoadercannot enforce session isolation and document the security implicationsCurrently, only
DefaultMemoryLoaderhas a regression test (default_loader_uses_explicit_session_scope), butCerebroMemoryLoaderis untested with non-None session_id.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@clients/agent-runtime/src/agent/memory_loader.rs` around lines 118 - 123, CerebroMemoryLoader builds a remote recall payload (the payload JSON near the json!({...}) block) but omits session_id, creating a behavioral gap versus DefaultMemoryLoader; either extend Cerebro's mem_search input schema to accept session_id and include session_id in the payload constructed by CerebroMemoryLoader, or explicitly document and test that CerebroMemoryLoader does not enforce session isolation. Update the payload construction in CerebroMemoryLoader to add "session_id": self.session_id (and propagate this change to the mem_search schema/handler), and add a regression test analogous to default_loader_uses_explicit_session_scope to validate non-None session_id behavior if you choose the schema approach; if not, add documentation and a test that asserts the lack of session scoping to make the security implications explicit.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@clients/agent-runtime/src/agent/agent.rs`:
- Around line 784-797: The function approval_denial_from_history currently scans
the entire history and may return stale "approval_required" results; change it
to only consider the most recent turn by scanning history in reverse and
returning the first ToolResults entry that contains a JSON with code ==
"approval_required". Specifically, update approval_denial_from_history to
iterate history.iter().rev(), find the first ConversationMessage::ToolResults
group, then search that group's results for the parsed JSON with code
"approval_required" (instead of searching every ToolResults across the whole
history).
- Around line 816-831: The code is calling turn_with_context(...,
TurnContext::default()) so code-mode turns aren't given the session_id; change
the TurnContext passed into self.turn_with_context to include the code-session
id when session_id.is_some() so the turn context and the CodeSessionResult use
the same session identifier. Locate the call to turn_with_context in agent.rs
and replace TurnContext::default() with a TurnContext constructed/populated with
the session_id (derived from session_id.as_deref()) before calling
record_code_session_result, ensuring the same session_id is used for both the
turn (turn_with_context) and the subsequent
CodeSessionResult/record_code_session_result paths.
In `@clients/agent-runtime/src/config/schema.rs`:
- Around line 2807-2811: The code now ingests CORVUS_GATEWAY_WEBHOOK_DISPATCHER
at config load via env_override_bool but the runtime helper
webhook_dispatcher_enabled() still re-reads the env var and ORs it in, causing
post-startup env changes to override config; remove the runtime env read and
make webhook_dispatcher_enabled() return the loaded config value
(gateway.webhook_dispatcher_enabled) only so the config value loaded at startup
is the single source of truth; locate and remove the getenv/OR logic in
webhook_dispatcher_enabled() (gateway/mod.rs) and ensure all callers use the
configured field rather than env::var at runtime.
In `@clients/agent-runtime/src/gateway/mod.rs`:
- Around line 1387-1389: The webhook_duplicate_response function currently logs
the raw idempotency_key; change this to never log the raw key and instead log a
redacted fingerprint (e.g., compute a short stable hash/fingerprint of
idempotency_key and log only the first N chars). Update
webhook_duplicate_response to compute the fingerprint (using a hashing utility
or a new helper like redact_idempotency_key/fingerprint_idempotency_key) and
replace the tracing::info call so it includes only the fingerprint (not the raw
key) in the message; ensure no other places in this function write the raw
idempotency_key to logs or responses.
In `@clients/agent-runtime/src/gateway/webhook_dispatch.rs`:
- Around line 333-346: The current handler recreates a fresh Agent for every
webhook (using BootstrapContext::for_gateway and
Agent::from_bootstrap_with_provider with SharedProvider) so same-session calls
lose prior conversation messages; persist and replay session transcript into the
Provider before calling Agent::turn_with_context. Concretely: use a
session-scoped store keyed by request.session (or attach to TurnContext) to
retrieve prior ConversationMessage history, and either (a) construct a
session-backed Provider implementation that wraps SharedProvider and replays the
stored ConversationMessage list into Provider::chat before delegating, or (b)
reuse a single Agent instance per session (cached by session id) instead of
rebuilding via Agent::from_bootstrap_with_provider; ensure turn_with_context
receives the replayed messages via the Provider or TurnContext so continuity is
preserved.
- Around line 318-330: The code treats BlockingOutcome::ApprovalRequired as if
it were non-blocking and continues processing, which can downgrade an
approval-gated request; update the blocking match in the webhook_dispatch path
(where evaluate and classify_blocking are called) to immediately return a
Blocking result for ApprovalRequired rather than falling through — i.e., when
classify_blocking(&canonical) yields BlockingOutcome::ApprovalRequired, call
map_canonical_result(&request, model,
CanonicalWebhookResult::Blocking(BlockingOutcome::ApprovalRequired { .. })) (or
equivalent) and return, similar to how other blocking outcomes are handled, so
no further agent/model work is performed after an approval decision.
In `@clients/agent-runtime/src/test_support.rs`:
- Around line 32-65: The current guard (GatewayWebhookDispatcherEnvGuard)
acquires gateway_webhook_dispatcher_env_mutex but only when callers use
set()/set_blocking(); direct env manipulation still bypasses the mutex. Add and
export a lock-only helper (e.g., acquire_gateway_webhook_dispatcher_lock and
acquire_gateway_webhook_dispatcher_lock_blocking) that returns a
tokio::sync::MutexGuard<'static, ()> (or a thin RAII wrapper) by calling
gateway_webhook_dispatcher_env_mutex().lock().await / .blocking_lock(), and
update tests to use this helper for baseline setup/cleanup when they need to
manipulate GATEWAY_WEBHOOK_DISPATCHER_ENV_VAR directly so all env mutations are
serialized by the same mutex.
In `@openspec/changes/archive/2026-03-20-gateway-dispatcher-parity/design.md`:
- Around line 216-222: Update the WebhookTerminalOutcome enum in the design doc
to match the implemented variant name: change the variant TimeoutAborted to
Timeout in the WebhookTerminalOutcome definition so it aligns with the
implementation used in gateway/webhook_dispatch.rs (see the variant at the
implementation site).
In
`@openspec/changes/archive/2026-03-20-gateway-dispatcher-parity/exploration.md`:
- Around line 3-10: Rename or prepend this section to clearly label it as a
historical "Pre-change snapshot" and update the prose to state that the
described behavior (gateway routes using Provider::simple_chat(), /webhook being
the exception, and /whatsapp lacking dispatcher/MCP parity) reflects the
pre-migration state; also add one sentence noting that dispatcher-backed webhook
specs and implementations have since been merged and reference the existing
symbols pre_execution::evaluate(...), Provider::simple_chat(), and the /webhook
and /whatsapp call paths so readers can correlate the snapshot with current
files.
In
`@openspec/changes/archive/2026-03-20-gateway-dispatcher-parity/verify-report.md`:
- Around line 142-147: Run the specific Rust test repeatedly to confirm the
`GatewayWebhookDispatcherEnvGuard::set_blocking("1")` usage in the
`config::schema::tests::env_override_gateway_webhook_dispatcher` test actually
stabilizes the intermittent failure: execute `cargo test --lib
config::schema::tests::env_override_gateway_webhook_dispatcher` several times
(e.g., 10+ runs) and verify no flakiness; if failures persist despite the guard,
collect failing traces and environment mutation points, then escalate for deeper
isolation fixes (investigate other tests mutating the same env, refactor to use
per-test guards or temp env APIs, or serialize via a test-level mutex). Ensure
the guard call is present in the test harness
(`GatewayWebhookDispatcherEnvGuard::set_blocking("1")`) and document the
verification results in the PR.
In
`@openspec/changes/archive/2026-03-20-gateway-webhook-dispatcher-env-flake/design.md`:
- Around line 81-84: The fenced Rust code block using ```rust around the
gateway_webhook_dispatcher_env_guard declaration must use the repository's
configured fence style to satisfy MD046; replace the triple backtick fence with
the repository-preferred fence (e.g., use triple tildes ~~~rust if that is the
configured style) for the block containing gateway_webhook_dispatcher_env_guard
so the markdown linter stops flagging it.
In
`@openspec/changes/archive/2026-03-20-gateway-webhook-dispatcher-env-flake/tasks.md`:
- Line 6: The checklist entry references the test_support path inconsistently
(one place uses the module file variant and another uses the flat file variant);
update the tasks.md checklist line that mentions the test_support file so it
matches the actual module path used in the repo (i.e., normalize the
test_support reference to the module-style path) and ensure the same normalized
reference is used for the CORVUS_GATEWAY_WEBHOOK_DISPATCHER seam mention so docs
and code stay aligned.
In `@openspec/changes/archive/2026-03-20-mcp-webhook-response-mapping/design.md`:
- Around line 35-37: Replace the inconsistent phrase "end to end" with the
hyphenated "end-to-end" in the design text; specifically update the bullet lines
that include "Prove everything only in
`clients/agent-runtime/src/gateway/webhook_dispatch.rs`" and "Broaden the change
into dispatcher or policy work so MCP can execute end to end", and also the
other occurrence later in the document (the standalone "end to end" usage) so
all instances use "end-to-end" consistently.
In
`@openspec/changes/archive/2026-03-20-webhook-generated-session-isolation/design.md`:
- Around line 110-115: The assertions use
tracking.recall_sessions.lock().clone() and
tracking.store_sessions.lock().clone(), which is invalid because Mutex::lock()
returns a Result; change both to unwrap (or expect) before cloning, e.g. call
tracking.recall_sessions.lock().unwrap().clone() and
tracking.store_sessions.lock().unwrap().clone() (or use expect with a clear
message) so the MutexGuard is unwrapped prior to clone.
In
`@openspec/changes/archive/2026-03-20-webhook-generated-session-isolation/exploration.md`:
- Around line 1-54: The markdown fails linting (MD041/MD022): change the first
line title "Exploration: webhook-generated-session-isolation" to an H1 (prefix
with "# "), and ensure all section headings (e.g., "### Current State", "###
Affected Areas", "### Approaches", "### Recommendation", "What this change
should include:", "What stays out of scope:", "Minimum spec delta likely
needed:", "### Risks", "### Ready for Proposal") are preceded and followed by a
single blank line so each heading is isolated; run a quick markdownlint check to
confirm MD041/MD022 are resolved.
In
`@openspec/changes/archive/2026-03-20-webhook-generated-session-isolation/tasks.md`:
- Around line 6-7: Update the task wording to remove the contradictory "RED"
label and describe it as a passing/regression test: change the checklist item
referencing the `/webhook` dispatcher-backed test in
clients/agent-runtime/src/gateway/mod.rs to read something like "Add a new
dispatcher-backed regression test for `/webhook` that omits `X-Session-Id`,
enables auto-save, captures the JSON `session_id`, and asserts the generated
`webhook-...` id matches all recorded recall/store session ids without reusing
any prior explicit session." Ensure "RED" is not used and the wording clearly
states it is a new regression test (or equivalent) that now passes.
In
`@openspec/changes/archive/2026-03-20-webhook-generated-session-isolation/verify-report.md`:
- Line 17: Update the stale tasks link in verify-report.md: replace the
reference to "openspec/changes/webhook-generated-session-isolation/tasks.md"
with the archived path
"openspec/changes/archive/2026-03-20-webhook-generated-session-isolation/tasks.md"
so the Assessment line points to the archived tasks file; edit the string in
verify-report.md where the Assessment paragraph references the tasks file to
ensure the audit trail is accurate.
---
Outside diff comments:
In `@clients/agent-runtime/src/agent/memory_loader.rs`:
- Around line 331-377: Add a new async test mirroring the DefaultMemoryLoader
session test but for CerebroMemoryLoader: instantiate a CerebroMemoryLoader (use
the endpoint-missing path by calling
CerebroMemoryLoader::new(MemoryCerebroConfig::default(), 5, 0.4) or the
egress-blocked config), use a SessionTrackingMemory instance, call
loader.load_context(&memory, "hello", Some("webhook-session-1")).await.unwrap(),
and then assert that memory.recall_sessions.lock().unwrap().clone() equals
vec![Some("webhook-session-1".to_string())]; reference CerebroMemoryLoader,
MemoryCerebroConfig, load_context, and SessionTrackingMemory.recall_sessions to
locate the code.
- Around line 118-123: CerebroMemoryLoader builds a remote recall payload (the
payload JSON near the json!({...}) block) but omits session_id, creating a
behavioral gap versus DefaultMemoryLoader; either extend Cerebro's mem_search
input schema to accept session_id and include session_id in the payload
constructed by CerebroMemoryLoader, or explicitly document and test that
CerebroMemoryLoader does not enforce session isolation. Update the payload
construction in CerebroMemoryLoader to add "session_id": self.session_id (and
propagate this change to the mem_search schema/handler), and add a regression
test analogous to default_loader_uses_explicit_session_scope to validate
non-None session_id behavior if you choose the schema approach; if not, add
documentation and a test that asserts the lack of session scoping to make the
security implications explicit.
🪄 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: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 8add987f-b54b-442d-812b-ed6fdea87cca
📒 Files selected for processing (39)
clients/agent-runtime/src/agent/agent.rsclients/agent-runtime/src/agent/memory_loader.rsclients/agent-runtime/src/agent/mod.rsclients/agent-runtime/src/agent/tests.rsclients/agent-runtime/src/bootstrap/mod.rsclients/agent-runtime/src/config/schema.rsclients/agent-runtime/src/gateway/mod.rsclients/agent-runtime/src/gateway/webhook_dispatch.rsclients/agent-runtime/src/test_support.rsclients/agent-runtime/tests/memory_backend_selection.rsopenspec/changes/archive/2026-03-20-gateway-dispatcher-parity/archive-report.mdopenspec/changes/archive/2026-03-20-gateway-dispatcher-parity/design.mdopenspec/changes/archive/2026-03-20-gateway-dispatcher-parity/exploration.mdopenspec/changes/archive/2026-03-20-gateway-dispatcher-parity/proposal.mdopenspec/changes/archive/2026-03-20-gateway-dispatcher-parity/specs/agent-loop/spec.mdopenspec/changes/archive/2026-03-20-gateway-dispatcher-parity/specs/mcp-runtime/spec.mdopenspec/changes/archive/2026-03-20-gateway-dispatcher-parity/tasks.mdopenspec/changes/archive/2026-03-20-gateway-dispatcher-parity/verify-report.mdopenspec/changes/archive/2026-03-20-gateway-webhook-dispatcher-env-flake/archive-report.mdopenspec/changes/archive/2026-03-20-gateway-webhook-dispatcher-env-flake/design.mdopenspec/changes/archive/2026-03-20-gateway-webhook-dispatcher-env-flake/exploration.mdopenspec/changes/archive/2026-03-20-gateway-webhook-dispatcher-env-flake/proposal.mdopenspec/changes/archive/2026-03-20-gateway-webhook-dispatcher-env-flake/tasks.mdopenspec/changes/archive/2026-03-20-gateway-webhook-dispatcher-env-flake/verify-report.mdopenspec/changes/archive/2026-03-20-mcp-webhook-response-mapping/archive-report.mdopenspec/changes/archive/2026-03-20-mcp-webhook-response-mapping/design.mdopenspec/changes/archive/2026-03-20-mcp-webhook-response-mapping/exploration.mdopenspec/changes/archive/2026-03-20-mcp-webhook-response-mapping/proposal.mdopenspec/changes/archive/2026-03-20-mcp-webhook-response-mapping/specs/mcp-runtime/spec.mdopenspec/changes/archive/2026-03-20-mcp-webhook-response-mapping/tasks.mdopenspec/changes/archive/2026-03-20-mcp-webhook-response-mapping/verify-report.mdopenspec/changes/archive/2026-03-20-webhook-generated-session-isolation/archive-report.mdopenspec/changes/archive/2026-03-20-webhook-generated-session-isolation/design.mdopenspec/changes/archive/2026-03-20-webhook-generated-session-isolation/exploration.mdopenspec/changes/archive/2026-03-20-webhook-generated-session-isolation/proposal.mdopenspec/changes/archive/2026-03-20-webhook-generated-session-isolation/tasks.mdopenspec/changes/archive/2026-03-20-webhook-generated-session-isolation/verify-report.mdopenspec/specs/agent-loop/spec.mdopenspec/specs/mcp-runtime/spec.md
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
- GitHub Check: pr-checks
- GitHub Check: Analyze (python)
- GitHub Check: pr-checks
- GitHub Check: core-checks
- GitHub Check: submit-gradle
- GitHub Check: Cloudflare Pages
🧰 Additional context used
📓 Path-based instructions (7)
clients/agent-runtime/**/*.rs
📄 CodeRabbit inference engine (clients/agent-runtime/AGENTS.md)
Run
cargo fmt --all -- --check,cargo clippy --all-targets -- -D warnings, andcargo testfor code validation, or document which checks were skipped and why
Files:
clients/agent-runtime/tests/memory_backend_selection.rsclients/agent-runtime/src/agent/mod.rsclients/agent-runtime/src/agent/memory_loader.rsclients/agent-runtime/src/agent/tests.rsclients/agent-runtime/src/test_support.rsclients/agent-runtime/src/gateway/webhook_dispatch.rsclients/agent-runtime/src/bootstrap/mod.rsclients/agent-runtime/src/config/schema.rsclients/agent-runtime/src/agent/agent.rsclients/agent-runtime/src/gateway/mod.rs
**/*.rs
⚙️ CodeRabbit configuration file
**/*.rs: Focus on Rust idioms, memory safety, and ownership/borrowing correctness.
Flag unnecessary clones, unchecked panics in production paths, and weak error context.
Prioritize unsafe blocks, FFI boundaries, concurrency races, and secret handling.
Files:
clients/agent-runtime/tests/memory_backend_selection.rsclients/agent-runtime/src/agent/mod.rsclients/agent-runtime/src/agent/memory_loader.rsclients/agent-runtime/src/agent/tests.rsclients/agent-runtime/src/test_support.rsclients/agent-runtime/src/gateway/webhook_dispatch.rsclients/agent-runtime/src/bootstrap/mod.rsclients/agent-runtime/src/config/schema.rsclients/agent-runtime/src/agent/agent.rsclients/agent-runtime/src/gateway/mod.rs
**/*
⚙️ CodeRabbit configuration file
**/*: Security first, performance second.
Validate input boundaries, auth/authz implications, and secret management.
Look for behavioral regressions, missing tests, and contract breaks across modules.
Files:
clients/agent-runtime/tests/memory_backend_selection.rsopenspec/changes/archive/2026-03-20-gateway-webhook-dispatcher-env-flake/proposal.mdclients/agent-runtime/src/agent/mod.rsopenspec/changes/archive/2026-03-20-mcp-webhook-response-mapping/proposal.mdopenspec/changes/archive/2026-03-20-webhook-generated-session-isolation/proposal.mdopenspec/changes/archive/2026-03-20-webhook-generated-session-isolation/tasks.mdopenspec/changes/archive/2026-03-20-webhook-generated-session-isolation/design.mdopenspec/changes/archive/2026-03-20-gateway-dispatcher-parity/archive-report.mdopenspec/changes/archive/2026-03-20-gateway-webhook-dispatcher-env-flake/tasks.mdopenspec/changes/archive/2026-03-20-gateway-webhook-dispatcher-env-flake/design.mdopenspec/changes/archive/2026-03-20-webhook-generated-session-isolation/archive-report.mdopenspec/changes/archive/2026-03-20-mcp-webhook-response-mapping/exploration.mdopenspec/changes/archive/2026-03-20-gateway-webhook-dispatcher-env-flake/archive-report.mdopenspec/changes/archive/2026-03-20-mcp-webhook-response-mapping/verify-report.mdopenspec/changes/archive/2026-03-20-gateway-webhook-dispatcher-env-flake/exploration.mdopenspec/changes/archive/2026-03-20-mcp-webhook-response-mapping/design.mdopenspec/changes/archive/2026-03-20-mcp-webhook-response-mapping/archive-report.mdopenspec/changes/archive/2026-03-20-gateway-dispatcher-parity/tasks.mdopenspec/changes/archive/2026-03-20-gateway-dispatcher-parity/exploration.mdclients/agent-runtime/src/agent/memory_loader.rsopenspec/changes/archive/2026-03-20-mcp-webhook-response-mapping/specs/mcp-runtime/spec.mdopenspec/specs/mcp-runtime/spec.mdopenspec/specs/agent-loop/spec.mdopenspec/changes/archive/2026-03-20-gateway-dispatcher-parity/proposal.mdopenspec/changes/archive/2026-03-20-gateway-dispatcher-parity/design.mdopenspec/changes/archive/2026-03-20-gateway-dispatcher-parity/specs/agent-loop/spec.mdopenspec/changes/archive/2026-03-20-webhook-generated-session-isolation/verify-report.mdopenspec/changes/archive/2026-03-20-gateway-dispatcher-parity/specs/mcp-runtime/spec.mdclients/agent-runtime/src/agent/tests.rsclients/agent-runtime/src/test_support.rsopenspec/changes/archive/2026-03-20-mcp-webhook-response-mapping/tasks.mdclients/agent-runtime/src/gateway/webhook_dispatch.rsopenspec/changes/archive/2026-03-20-gateway-webhook-dispatcher-env-flake/verify-report.mdopenspec/changes/archive/2026-03-20-webhook-generated-session-isolation/exploration.mdclients/agent-runtime/src/bootstrap/mod.rsclients/agent-runtime/src/config/schema.rsopenspec/changes/archive/2026-03-20-gateway-dispatcher-parity/verify-report.mdclients/agent-runtime/src/agent/agent.rsclients/agent-runtime/src/gateway/mod.rs
**/*.{md,mdx}
⚙️ CodeRabbit configuration file
**/*.{md,mdx}: Verify technical accuracy and that docs stay aligned with code changes.
For user-facing docs, check EN/ES parity or explicitly note pending translation gaps.
Files:
openspec/changes/archive/2026-03-20-gateway-webhook-dispatcher-env-flake/proposal.mdopenspec/changes/archive/2026-03-20-mcp-webhook-response-mapping/proposal.mdopenspec/changes/archive/2026-03-20-webhook-generated-session-isolation/proposal.mdopenspec/changes/archive/2026-03-20-webhook-generated-session-isolation/tasks.mdopenspec/changes/archive/2026-03-20-webhook-generated-session-isolation/design.mdopenspec/changes/archive/2026-03-20-gateway-dispatcher-parity/archive-report.mdopenspec/changes/archive/2026-03-20-gateway-webhook-dispatcher-env-flake/tasks.mdopenspec/changes/archive/2026-03-20-gateway-webhook-dispatcher-env-flake/design.mdopenspec/changes/archive/2026-03-20-webhook-generated-session-isolation/archive-report.mdopenspec/changes/archive/2026-03-20-mcp-webhook-response-mapping/exploration.mdopenspec/changes/archive/2026-03-20-gateway-webhook-dispatcher-env-flake/archive-report.mdopenspec/changes/archive/2026-03-20-mcp-webhook-response-mapping/verify-report.mdopenspec/changes/archive/2026-03-20-gateway-webhook-dispatcher-env-flake/exploration.mdopenspec/changes/archive/2026-03-20-mcp-webhook-response-mapping/design.mdopenspec/changes/archive/2026-03-20-mcp-webhook-response-mapping/archive-report.mdopenspec/changes/archive/2026-03-20-gateway-dispatcher-parity/tasks.mdopenspec/changes/archive/2026-03-20-gateway-dispatcher-parity/exploration.mdopenspec/changes/archive/2026-03-20-mcp-webhook-response-mapping/specs/mcp-runtime/spec.mdopenspec/specs/mcp-runtime/spec.mdopenspec/specs/agent-loop/spec.mdopenspec/changes/archive/2026-03-20-gateway-dispatcher-parity/proposal.mdopenspec/changes/archive/2026-03-20-gateway-dispatcher-parity/design.mdopenspec/changes/archive/2026-03-20-gateway-dispatcher-parity/specs/agent-loop/spec.mdopenspec/changes/archive/2026-03-20-webhook-generated-session-isolation/verify-report.mdopenspec/changes/archive/2026-03-20-gateway-dispatcher-parity/specs/mcp-runtime/spec.mdopenspec/changes/archive/2026-03-20-mcp-webhook-response-mapping/tasks.mdopenspec/changes/archive/2026-03-20-gateway-webhook-dispatcher-env-flake/verify-report.mdopenspec/changes/archive/2026-03-20-webhook-generated-session-isolation/exploration.mdopenspec/changes/archive/2026-03-20-gateway-dispatcher-parity/verify-report.md
clients/agent-runtime/src/**/*.rs
📄 CodeRabbit inference engine (clients/agent-runtime/AGENTS.md)
clients/agent-runtime/src/**/*.rs: Never log secrets, tokens, raw credentials, or sensitive payloads in any logging statements
Avoid unnecessary allocations, clones, and blocking operations to maintain performance and efficiency
Files:
clients/agent-runtime/src/agent/mod.rsclients/agent-runtime/src/agent/memory_loader.rsclients/agent-runtime/src/agent/tests.rsclients/agent-runtime/src/test_support.rsclients/agent-runtime/src/gateway/webhook_dispatch.rsclients/agent-runtime/src/bootstrap/mod.rsclients/agent-runtime/src/config/schema.rsclients/agent-runtime/src/agent/agent.rsclients/agent-runtime/src/gateway/mod.rs
clients/agent-runtime/src/{security,gateway,tools}/**/*.rs
📄 CodeRabbit inference engine (clients/agent-runtime/AGENTS.md)
Treat
src/security/,src/gateway/,src/tools/as high-risk surfaces and never broaden filesystem/network execution scope without explicit policy checks
Files:
clients/agent-runtime/src/gateway/webhook_dispatch.rsclients/agent-runtime/src/gateway/mod.rs
clients/agent-runtime/src/{security,gateway,tools,config}/**/*.rs
📄 CodeRabbit inference engine (clients/agent-runtime/AGENTS.md)
Do not silently weaken security policy or access constraints; keep default behavior secure-by-default with deny-by-default where applicable
Files:
clients/agent-runtime/src/gateway/webhook_dispatch.rsclients/agent-runtime/src/config/schema.rsclients/agent-runtime/src/gateway/mod.rs
🧠 Learnings (12)
📓 Common learnings
Learnt from: CR
Repo: dallay/corvus PR: 0
File: clients/agent-runtime/AGENTS.md:0-0
Timestamp: 2026-02-17T12:31:17.076Z
Learning: Applies to clients/agent-runtime/src/channels/**/*.rs : Implement `Channel` trait in `src/channels/` with consistent `send`, `listen`, and `health_check` semantics and cover auth/allowlist/health behavior with tests
📚 Learning: 2026-02-17T12:31:17.076Z
Learnt from: CR
Repo: dallay/corvus PR: 0
File: clients/agent-runtime/AGENTS.md:0-0
Timestamp: 2026-02-17T12:31:17.076Z
Learning: Applies to clients/agent-runtime/src/main.rs : Preserve CLI contract unless change is intentional and documented; prefer explicit errors over silent fallback for unsupported critical paths
Applied to files:
clients/agent-runtime/tests/memory_backend_selection.rsclients/agent-runtime/src/agent/mod.rsopenspec/changes/archive/2026-03-20-gateway-webhook-dispatcher-env-flake/exploration.mdclients/agent-runtime/src/agent/tests.rsclients/agent-runtime/src/test_support.rsclients/agent-runtime/src/gateway/webhook_dispatch.rsclients/agent-runtime/src/bootstrap/mod.rsclients/agent-runtime/src/agent/agent.rsclients/agent-runtime/src/gateway/mod.rs
📚 Learning: 2026-02-17T12:31:17.076Z
Learnt from: CR
Repo: dallay/corvus PR: 0
File: clients/agent-runtime/AGENTS.md:0-0
Timestamp: 2026-02-17T12:31:17.076Z
Learning: Include threat/risk notes and rollback strategy for security, runtime, and gateway changes; add or update tests for boundary checks and failure modes
Applied to files:
openspec/changes/archive/2026-03-20-gateway-webhook-dispatcher-env-flake/proposal.mdopenspec/changes/archive/2026-03-20-webhook-generated-session-isolation/tasks.mdopenspec/changes/archive/2026-03-20-gateway-webhook-dispatcher-env-flake/tasks.mdopenspec/changes/archive/2026-03-20-gateway-webhook-dispatcher-env-flake/design.mdopenspec/changes/archive/2026-03-20-mcp-webhook-response-mapping/verify-report.mdopenspec/changes/archive/2026-03-20-gateway-webhook-dispatcher-env-flake/exploration.mdopenspec/changes/archive/2026-03-20-gateway-dispatcher-parity/tasks.mdopenspec/changes/archive/2026-03-20-gateway-dispatcher-parity/exploration.mdopenspec/specs/mcp-runtime/spec.mdopenspec/changes/archive/2026-03-20-gateway-dispatcher-parity/proposal.mdopenspec/changes/archive/2026-03-20-gateway-webhook-dispatcher-env-flake/verify-report.mdopenspec/changes/archive/2026-03-20-gateway-dispatcher-parity/verify-report.md
📚 Learning: 2026-02-17T12:31:17.076Z
Learnt from: CR
Repo: dallay/corvus PR: 0
File: clients/agent-runtime/AGENTS.md:0-0
Timestamp: 2026-02-17T12:31:17.076Z
Learning: Applies to clients/agent-runtime/**/*.rs : Run `cargo fmt --all -- --check`, `cargo clippy --all-targets -- -D warnings`, and `cargo test` for code validation, or document which checks were skipped and why
Applied to files:
clients/agent-runtime/src/agent/mod.rsopenspec/changes/archive/2026-03-20-gateway-webhook-dispatcher-env-flake/tasks.mdclients/agent-runtime/src/agent/tests.rsclients/agent-runtime/src/test_support.rsclients/agent-runtime/src/gateway/webhook_dispatch.rsopenspec/changes/archive/2026-03-20-gateway-webhook-dispatcher-env-flake/verify-report.md
📚 Learning: 2026-02-17T12:31:17.076Z
Learnt from: CR
Repo: dallay/corvus PR: 0
File: clients/agent-runtime/AGENTS.md:0-0
Timestamp: 2026-02-17T12:31:17.076Z
Learning: Applies to clients/agent-runtime/**/Cargo.toml : Do not add heavy dependencies for minor convenience; justify new crate additions
Applied to files:
clients/agent-runtime/src/agent/mod.rs
📚 Learning: 2026-02-17T12:31:17.076Z
Learnt from: CR
Repo: dallay/corvus PR: 0
File: clients/agent-runtime/AGENTS.md:0-0
Timestamp: 2026-02-17T12:31:17.076Z
Learning: Applies to clients/agent-runtime/src/**/*.rs : Avoid unnecessary allocations, clones, and blocking operations to maintain performance and efficiency
Applied to files:
clients/agent-runtime/src/agent/mod.rs
📚 Learning: 2026-02-17T12:31:17.076Z
Learnt from: CR
Repo: dallay/corvus PR: 0
File: clients/agent-runtime/AGENTS.md:0-0
Timestamp: 2026-02-17T12:31:17.076Z
Learning: Applies to clients/agent-runtime/src/{security,gateway,tools,config}/**/*.rs : Do not silently weaken security policy or access constraints; keep default behavior secure-by-default with deny-by-default where applicable
Applied to files:
clients/agent-runtime/src/agent/mod.rsopenspec/changes/archive/2026-03-20-webhook-generated-session-isolation/design.mdopenspec/changes/archive/2026-03-20-gateway-webhook-dispatcher-env-flake/exploration.mdopenspec/changes/archive/2026-03-20-gateway-dispatcher-parity/tasks.mdopenspec/specs/mcp-runtime/spec.mdclients/agent-runtime/src/test_support.rsclients/agent-runtime/src/gateway/webhook_dispatch.rsclients/agent-runtime/src/bootstrap/mod.rsclients/agent-runtime/src/config/schema.rsclients/agent-runtime/src/gateway/mod.rs
📚 Learning: 2026-02-17T12:31:17.076Z
Learnt from: CR
Repo: dallay/corvus PR: 0
File: clients/agent-runtime/AGENTS.md:0-0
Timestamp: 2026-02-17T12:31:17.076Z
Learning: Applies to clients/agent-runtime/src/providers/**/*.rs : Implement `Provider` trait in `src/providers/` and register in `src/providers/mod.rs` factory when adding a new provider
Applied to files:
clients/agent-runtime/src/agent/mod.rsclients/agent-runtime/src/agent/agent.rsclients/agent-runtime/src/gateway/mod.rs
📚 Learning: 2026-02-17T12:31:17.076Z
Learnt from: CR
Repo: dallay/corvus PR: 0
File: clients/agent-runtime/AGENTS.md:0-0
Timestamp: 2026-02-17T12:31:17.076Z
Learning: Applies to clients/agent-runtime/src/main.rs : Keep startup path lean and avoid heavy initialization in command parsing flow
Applied to files:
clients/agent-runtime/src/agent/mod.rsclients/agent-runtime/src/agent/tests.rsclients/agent-runtime/src/bootstrap/mod.rsclients/agent-runtime/src/agent/agent.rs
📚 Learning: 2026-02-17T12:31:17.076Z
Learnt from: CR
Repo: dallay/corvus PR: 0
File: clients/agent-runtime/AGENTS.md:0-0
Timestamp: 2026-02-17T12:31:17.076Z
Learning: Applies to clients/agent-runtime/src/{security,gateway,tools}/**/*.rs : Treat `src/security/`, `src/gateway/`, `src/tools/` as high-risk surfaces and never broaden filesystem/network execution scope without explicit policy checks
Applied to files:
openspec/specs/mcp-runtime/spec.mdclients/agent-runtime/src/test_support.rsclients/agent-runtime/src/gateway/webhook_dispatch.rsclients/agent-runtime/src/gateway/mod.rs
📚 Learning: 2026-02-17T12:31:17.076Z
Learnt from: CR
Repo: dallay/corvus PR: 0
File: clients/agent-runtime/AGENTS.md:0-0
Timestamp: 2026-02-17T12:31:17.076Z
Learning: Applies to clients/agent-runtime/src/tools/**/*.rs : Implement `Tool` trait in `src/tools/` with strict parameter schema, validate and sanitize all inputs, and return structured `ToolResult` without panics in runtime path
Applied to files:
clients/agent-runtime/src/agent/tests.rsclients/agent-runtime/src/agent/agent.rs
📚 Learning: 2026-02-17T12:31:17.076Z
Learnt from: CR
Repo: dallay/corvus PR: 0
File: clients/agent-runtime/AGENTS.md:0-0
Timestamp: 2026-02-17T12:31:17.076Z
Learning: Applies to clients/agent-runtime/src/channels/**/*.rs : Implement `Channel` trait in `src/channels/` with consistent `send`, `listen`, and `health_check` semantics and cover auth/allowlist/health behavior with tests
Applied to files:
clients/agent-runtime/src/gateway/webhook_dispatch.rs
🪛 LanguageTool
openspec/changes/archive/2026-03-20-gateway-webhook-dispatcher-env-flake/proposal.md
[style] ~45-~45: As an alternative to the over-used intensifier ‘very’, consider replacing this phrase.
Context: ...default plan is test-only, with at most a very small supporting test-harness adjustment in `...
(EN_WEAK_ADJECTIVE)
[style] ~61-~61: To elevate your writing, try using a synonym here.
Context: ...----------|------------| | The flake is hard to reproduce deterministically | Medium...
(HARD_TO)
openspec/changes/archive/2026-03-20-webhook-generated-session-isolation/proposal.md
[grammar] ~1-~1: Use a hyphen to join words.
Context: # Proposal: Webhook Generated Session Isolation ## Intent ...
(QB_NEW_EN_HYPHEN)
openspec/changes/archive/2026-03-20-webhook-generated-session-isolation/tasks.md
[grammar] ~1-~1: Use a hyphen to join words.
Context: # Tasks: Webhook Generated Session Isolation ## Phase 1:...
(QB_NEW_EN_HYPHEN)
openspec/changes/archive/2026-03-20-webhook-generated-session-isolation/design.md
[grammar] ~1-~1: Use a hyphen to join words.
Context: # Design: Webhook Generated Session Isolation ## Technica...
(QB_NEW_EN_HYPHEN)
openspec/changes/archive/2026-03-20-gateway-webhook-dispatcher-env-flake/archive-report.md
[style] ~51-~51: To elevate your writing, try using an alternative expression here.
Context: ... ## Next Recommended - If auditability matters for a later follow-up, isolate unrelate...
(MATTERS_RELEVANT)
openspec/changes/archive/2026-03-20-gateway-webhook-dispatcher-env-flake/exploration.md
[style] ~40-~40: Using a “neither–nor” construction here can make your writing sound more fluent.
Context: ...therwise. The narrowest useful scope is not a broad config refactor and not a production behavior change; it is a small test-harness correction ...
(N_NOR)
openspec/changes/archive/2026-03-20-mcp-webhook-response-mapping/design.md
[grammar] ~37-~37: Use a hyphen to join words.
Context: ...er or policy work so MCP can execute end to end Rationale: `clients/agent-ru...
(QB_NEW_EN_HYPHEN)
[grammar] ~37-~37: Use a hyphen to join words.
Context: ...or policy work so MCP can execute end to end Rationale: `clients/agent-runti...
(QB_NEW_EN_HYPHEN)
[grammar] ~152-~152: Use a hyphen to join words.
Context: ...eachable MCP policy behavior remains end to end | Keep `webhook_dispatcher_blocks...
(QB_NEW_EN_HYPHEN)
[grammar] ~152-~152: Use a hyphen to join words.
Context: ...hable MCP policy behavior remains end to end | Keep `webhook_dispatcher_blocks_mc...
(QB_NEW_EN_HYPHEN)
openspec/changes/archive/2026-03-20-mcp-webhook-response-mapping/specs/mcp-runtime/spec.md
[grammar] ~28-~28: Use a hyphen to join words.
Context: ...ntime-reachable MCP denial is proven end to end - GIVEN a dispatcher-backed gate...
(QB_NEW_EN_HYPHEN)
[grammar] ~28-~28: Use a hyphen to join words.
Context: ...me-reachable MCP denial is proven end to end - GIVEN a dispatcher-backed gateway...
(QB_NEW_EN_HYPHEN)
openspec/specs/mcp-runtime/spec.md
[grammar] ~148-~148: Use a hyphen to join words.
Context: ...ntime-reachable MCP denial is proven end to end - GIVEN a dispatcher-backed gate...
(QB_NEW_EN_HYPHEN)
[grammar] ~148-~148: Use a hyphen to join words.
Context: ...me-reachable MCP denial is proven end to end - GIVEN a dispatcher-backed gateway...
(QB_NEW_EN_HYPHEN)
openspec/changes/archive/2026-03-20-gateway-dispatcher-parity/design.md
[uncategorized] ~177-~177: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ...- pairing enforcement - IP/header-aware rate limiting - idempotency policy - request parsing ...
(EN_COMPOUND_ADJECTIVE_INTERNAL)
[style] ~350-~350: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...ts. - No resumable approval protocol. - No broad channels/gateway shared-runtime r...
(ENGLISH_WORD_REPEAT_BEGINNING_RULE)
openspec/changes/archive/2026-03-20-webhook-generated-session-isolation/exploration.md
[style] ~46-~46: As an alternative to the over-used intensifier ‘very’, consider replacing this phrase.
Context: ...ta spec for the follow-up, it should be a very small agent-loop delta that restates this a...
(EN_WEAK_ADJECTIVE)
🪛 markdownlint-cli2 (0.21.0)
openspec/changes/archive/2026-03-20-gateway-webhook-dispatcher-env-flake/proposal.md
[warning] 14-14: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
[warning] 24-24: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
openspec/changes/archive/2026-03-20-webhook-generated-session-isolation/design.md
[warning] 12-12: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
[warning] 20-20: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
openspec/changes/archive/2026-03-20-gateway-webhook-dispatcher-env-flake/design.md
[warning] 81-81: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
openspec/changes/archive/2026-03-20-mcp-webhook-response-mapping/exploration.md
[warning] 13-13: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
[warning] 25-25: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
openspec/changes/archive/2026-03-20-gateway-webhook-dispatcher-env-flake/exploration.md
[warning] 1-1: First line in a file should be a top-level heading
(MD041, first-line-heading, first-line-h1)
[warning] 3-3: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
[warning] 15-15: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
[warning] 23-23: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
[warning] 39-39: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
[warning] 56-56: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
[warning] 62-62: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
openspec/changes/archive/2026-03-20-gateway-dispatcher-parity/exploration.md
[warning] 1-1: First line in a file should be a top-level heading
(MD041, first-line-heading, first-line-h1)
[warning] 3-3: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
[warning] 12-12: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
[warning] 21-21: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
[warning] 32-32: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
[warning] 41-41: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
[warning] 47-47: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
openspec/specs/agent-loop/spec.md
[warning] 18-18: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
[warning] 26-26: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
[warning] 33-33: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
[warning] 47-47: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
[warning] 62-62: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
[warning] 70-70: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
[warning] 85-85: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
[warning] 92-92: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
[warning] 106-106: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
[warning] 113-113: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
[warning] 127-127: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
[warning] 134-134: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
openspec/changes/archive/2026-03-20-gateway-dispatcher-parity/proposal.md
[warning] 81-81: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
openspec/changes/archive/2026-03-20-webhook-generated-session-isolation/exploration.md
[warning] 1-1: First line in a file should be a top-level heading
(MD041, first-line-heading, first-line-h1)
[warning] 3-3: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
[warning] 12-12: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
[warning] 20-20: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
[warning] 31-31: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
[warning] 48-48: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
[warning] 54-54: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
🔇 Additional comments (27)
openspec/changes/archive/2026-03-20-gateway-dispatcher-parity/proposal.md (1)
124-138: Risk and rollback coverage is clear and actionable.The proposal’s risk table and rollback path are explicit and scoped correctly for gateway/runtime migration work.
Based on learnings: "Include threat/risk notes and rollback strategy for security, runtime, and gateway changes; add or update tests for boundary checks and failure modes".
clients/agent-runtime/tests/memory_backend_selection.rs (1)
75-118: Signature migration is correctly applied in tests.Passing
Noneexplicitly at call sites keeps these tests aligned with the new session-awareMemoryLoadercontract.clients/agent-runtime/src/agent/mod.rs (1)
17-20: Public re-exports match the new turn-context API surface.This keeps downstream imports consistent with the session-aware agent runtime changes.
openspec/changes/archive/2026-03-20-mcp-webhook-response-mapping/archive-report.md (1)
30-55: Archive warning carry-forward is documented well.The warnings and next recommended actions are precise and maintain auditability of remaining proof gaps.
openspec/changes/archive/2026-03-20-gateway-webhook-dispatcher-env-flake/proposal.md (1)
57-69: Good scope control and rollback discipline for the flake fix.The proposal keeps runtime behavior stable unless a deterministic production defect is proven.
Based on learnings: "Include threat/risk notes and rollback strategy for security, runtime, and gateway changes; add or update tests for boundary checks and failure modes".
clients/agent-runtime/src/config/schema.rs (1)
666-673: Secure default is correctly fail-closed.
webhook_dispatcher_enableddefaults tofalse, which keeps legacy behavior unless explicitly enabled.As per coding guidelines "
clients/agent-runtime/src/{security,gateway,tools,config}/**/*.rs: ... keep default behavior secure-by-default with deny-by-default where applicable".Also applies to: 723-723
openspec/changes/archive/2026-03-20-webhook-generated-session-isolation/proposal.md (1)
29-35: Approach is appropriately proof-first and tightly scoped.This keeps the follow-up focused on validating session isolation without widening production change scope.
openspec/changes/archive/2026-03-20-webhook-generated-session-isolation/archive-report.md (1)
12-49: Looks good — archive rationale and artifact trail are clear and internally consistent.openspec/changes/archive/2026-03-20-gateway-webhook-dispatcher-env-flake/archive-report.md (1)
12-61: LGTM — warning carry-forward and audit trail are well documented for this test-only slice.openspec/changes/archive/2026-03-20-mcp-webhook-response-mapping/proposal.md (1)
13-97: Well-scoped proposal with clear proof-first boundaries and acceptance criteria.openspec/changes/archive/2026-03-20-gateway-dispatcher-parity/archive-report.md (1)
12-69: LGTM — archive summary, carry-forward warnings, and follow-up guidance are clear and consistent.clients/agent-runtime/src/agent/tests.rs (2)
219-279: Good targeted test double for session propagation.
TrackingMemoryat Line 219 cleanly capturesrecall/storesession IDs and keeps the assertions deterministic for async tests.
808-861: Great coverage for both session-present and session-absent paths.Lines 808-861 validate session threading end-to-end through recall/store and result metadata for both explicit and default
TurnContext.openspec/changes/archive/2026-03-20-mcp-webhook-response-mapping/tasks.md (1)
1-16: Scope control is clear and well constrained.The phased tasks keep this follow-up proof-oriented and avoid accidental runtime-scope expansion.
openspec/changes/archive/2026-03-20-mcp-webhook-response-mapping/verify-report.md (1)
53-74: Verification evidence is well-structured and traceable.The compliance and correctness sections clearly separate runtime-reachable proof from seam-only proof, which matches the scoped objective.
openspec/changes/archive/2026-03-20-gateway-webhook-dispatcher-env-flake/verify-report.md (1)
38-65: Strong flake-validation evidence.The repeated focused runs and per-file coverage details make the stabilization claim credible and auditable.
openspec/changes/archive/2026-03-20-gateway-webhook-dispatcher-env-flake/exploration.md (1)
1-63: Well-structured investigation with appropriate scope boundaries.The exploration correctly identifies the cross-module env-var race between
ENV_OVERRIDE_TEST_LOCKin config tests andGATEWAY_ENV_MUTEXin gateway tests. The recommendation to use a shared test-only env guard (approach 2) is the right call—it addresses the structural root cause without touching production code.openspec/changes/archive/2026-03-20-mcp-webhook-response-mapping/exploration.md (1)
1-63: Sound framing of proof-vs-reachability distinction.The exploration correctly distinguishes runtime-reachable outcomes (MCP denial) from policy-blocked outcomes (MCP success/timeout/error). The recommendation to use seam-level proof for blocked outcomes while requiring E2E proof for reachable outcomes is the right architectural stance—it avoids false confidence from tests that can't exercise real execution paths.
openspec/changes/archive/2026-03-20-gateway-dispatcher-parity/design.md (1)
1-361: Solid security-first design with appropriate rollout controls.The design correctly:
- Keeps transport/auth concerns at the gateway edge before dispatcher execution
- Enforces "Gateway MUST NOT bypass approval checks" as an explicit constraint
- Provides dedicated rollout flag with legacy fallback for safe migration
- Preserves idempotency semantics for non-terminal outcomes
This aligns with the coding guidelines for secure-by-default behavior. Based on learnings: "Include threat/risk notes and rollback strategy for security, runtime, and gateway changes."
clients/agent-runtime/src/bootstrap/mod.rs (3)
147-174: Clean delegation pattern with idiomatic option handling.The refactoring correctly extracts override-aware initialization while preserving the original API through delegation. The
unwrap_or_elsefor lazy observer creation and explicitif letfor memory are readable and avoid unnecessary allocations.
188-194: Appropriate visibility for gateway-only bootstrap path.
pub(crate)correctly limitsfor_gatewayto internal use, preventing external callers from bypassing the canonical bootstrap flow. This maintains the design constraint that gateway reuses canonical memory/observer instances.
572-588: Good feature-flag conditional test coverage.The test correctly validates MCP tool registry behavior under both feature states using
cfg!(feature = "mcp-runtime"). This ensures gateway bootstrap maintains parity with canonical MCP registration regardless of the feature flag.openspec/changes/archive/2026-03-20-gateway-dispatcher-parity/tasks.md (1)
1-38: Comprehensive task breakdown with clear phase boundaries.The task plan correctly sequences: contract tests (RED) → implementation → HTTP mapping → MCP parity → verification. The explicit
openspec/specs/mcp-runtime/spec.md (2)
93-130: Strong security boundary for MCP policy enforcement.The expanded requirement correctly:
- Extends approval gates to dispatcher-backed
/webhook- Explicitly disallows any canonical entry point from bypassing MCP approval
- Treats legacy fallback as "MCP parity inactive" rather than partially enforced
This prevents the security posture gap where gateway might accidentally weaken MCP policy. Based on learnings: "Do not silently weaken security policy or access constraints."
131-176: Well-defined proof semantics distinguish reachable vs blocked outcomes.The three-scenario structure is precise:
- Denial (E2E required): Runtime-reachable, must prove through full dispatcher path
- Non-denial blocked (seam OK): Policy prevents execution, seam-level proof acceptable with clear labeling
- Future reachable (E2E required): When policy changes, seam-only evidence becomes insufficient
This prevents false confidence from tests labeled "MCP" that only exercise generic outcome mapping.
openspec/changes/archive/2026-03-20-mcp-webhook-response-mapping/specs/mcp-runtime/spec.md (1)
1-55: Clear delta documentation with change tracking.The "Previously:" clause (Lines 22-26) provides good change history context, showing exactly what was added to the original capability parity requirement. The proof semantics mirror the main spec correctly.
openspec/changes/archive/2026-03-20-gateway-dispatcher-parity/verify-report.md (1)
1-162: Thorough verification with honest gap disclosure.The report correctly:
- Documents 14/16 compliant scenarios with 2 partial (not hidden)
- Provides actionable suggestions for each warning
- Acknowledges the
make testvscargo testcoverage gap- Maintains "PASS WITH WARNINGS" rather than overstating compliance
The partial scenarios (missing-session E2E and MCP non-denial mapping) are legitimate gaps tracked as follow-ups in the exploration docs.
…-canonical-agent-dispatcher
…-canonical-agent-dispatcher
There was a problem hiding this comment.
Actionable comments posted: 7
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
clients/agent-runtime/src/agent/memory_loader.rs (1)
117-125:⚠️ Potential issue | 🔴 CriticalDo not merge global Cerebro recall into session-scoped turns.
When
session_idis set, this still issues an unscoped remotemem_searchand appends those results to the prompt. That breaks the new session-isolation contract and can leak memories across webhook sessions whenever Cerebro is enabled. Until the remote API can filter by session, this path needs to fail closed for session-bound turns.As per coding guidelines `**/*`: Security first, performance second. Validate input boundaries, auth/authz implications, and secret management.Suggested fix
- let adapter = cerebro::cerebro_tool_adapter(&self.config, normalize::CEREBRO_TOOL_RECALL)?; - // Cerebro's current mem_search contract does not accept a session filter, so remote recall - // remains global even when the local memory fallback is session-scoped. + // Fail closed for session-scoped turns until Cerebro supports server-side session filters. + if session_id.is_some() { + if !added { + return Ok(String::new()); + } + context.push('\n'); + return Ok(context); + } + + let adapter = + cerebro::cerebro_tool_adapter(&self.config, normalize::CEREBRO_TOOL_RECALL)?;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@clients/agent-runtime/src/agent/memory_loader.rs` around lines 117 - 125, The remote Cerebro recall path currently builds a global mem_search payload and calls cerebro::cerebro_tool_adapter (normalize::CEREBRO_TOOL_RECALL) even when a session_id is present, which can leak memories across sessions; modify the code in the memory loading function so that if session_id (or the field representing session scope on self) is Some/exists you do not construct or call the remote mem_search (the payload and cerebro::cerebro_tool_adapter/ mem_search path) and instead fail closed — return an Err (or skip adding remote results) with a clear error indicating remote recall is disallowed for session-scoped turns; keep the existing global behavior only when session_id is None.clients/agent-runtime/src/gateway/mod.rs (1)
714-735:⚠️ Potential issue | 🟠 MajorReject malformed
X-Session-Idinstead of treating it as missing.A present-but-invalid header currently falls through to the generated-session path. That silently forks the caller into a new session and hides client bugs. Only the truly missing-header case should mint
webhook-<uuid>; malformed values should get a400.As per coding guidelines
**/*: "Validate input boundaries, auth/authz implications, and secret management."🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@clients/agent-runtime/src/gateway/mod.rs` around lines 714 - 735, Change resolve_session_id so that a present but syntactically invalid X-Session-Id causes an explicit client error instead of generating a new session: update the function signature to return a Result<(String, webhook_dispatch::WebhookSessionSource), E> (E can be the framework error type or an HttpResponse) and when headers.get("X-Session-Id") exists but fails the trim/len/char validation return Err(BadRequest) with a clear message; only when the header is absent return Ok((format!("webhook-{}", Uuid::new_v4()), webhook_dispatch::WebhookSessionSource::Generated)), and when the header is valid return Ok((session_id, webhook_dispatch::WebhookSessionSource::Explicit)).
♻️ Duplicate comments (4)
openspec/changes/archive/2026-03-20-gateway-webhook-dispatcher-env-flake/design.md (1)
79-84:⚠️ Potential issue | 🟡 MinorUse the repo’s configured code-block style here.
This fenced snippet still trips MD046, so doc lint will keep failing until it is converted to the configured indented style.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@openspec/changes/archive/2026-03-20-gateway-webhook-dispatcher-env-flake/design.md` around lines 79 - 84, The markdown snippet uses a fenced code block which violates the repo’s configured indented code-block style and triggers MD046; change the fenced Rust example for the test-only seam to the repo’s indented style and keep the same signature/name (gateway_webhook_dispatcher_env_guard), ensuring the block is prefixed by the required indentation so the linter accepts it and the snippet remains exactly the same content-wise except for formatting.openspec/changes/archive/2026-03-20-webhook-generated-session-isolation/exploration.md (1)
3-3:⚠️ Potential issue | 🟡 MinorUse H2 section headings under the H1.
The file still jumps from
#to###, so markdownlint's MD001 remains unresolved.Also applies to: 34-34, 49-49, 68-68, 74-74, 82-82, 89-89, 96-96, 107-107
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@openspec/changes/archive/2026-03-20-webhook-generated-session-isolation/exploration.md` at line 3, Replace all third-level headings (e.g., the "### Current State" heading and the other occurrences at the noted locations) with second-level headings under the top-level title so H2 (##) follows the H1; update every "### ..." instance in this file (including the instances referenced at lines 34, 49, 68, 74, 82, 89, 96, 107) to "## ..." to satisfy markdownlint MD001.clients/agent-runtime/src/gateway/mod.rs (1)
1613-1645:⚠️ Potential issue | 🔴 CriticalMake dispatcher idempotency reservation atomic.
This path still does a
contains()pre-check and a laterrecord(). Two concurrent requests with the same key can both pass Line 1616, both execute side effects, and only then record the key. Reserve withrecord_if_new()before dispatch andremove()it again whenpersist_idempotencyis false.As per coding guidelines `**/*`: "Security first, performance second. Validate input boundaries, auth/authz implications, and secret management. Look for behavioral regressions, missing tests, and contract breaks across modules."🔒 Minimal fix
- if let Some(idempotency_key) = webhook_idempotency_key(&headers) { - if state.idempotency_store.contains(idempotency_key) { - return webhook_duplicate_response(idempotency_key); - } - } + let idempotency_key = webhook_idempotency_key(&headers); + if let Some(key) = idempotency_key { + if !state.idempotency_store.record_if_new(key) { + return webhook_duplicate_response(key); + } + } @@ - if persist_idempotency { - if let Some(idempotency_key) = webhook_idempotency_key(&headers) { - state.idempotency_store.record(idempotency_key); - } - } + if !persist_idempotency { + if let Some(key) = idempotency_key { + state.idempotency_store.remove(key); + } + }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@clients/agent-runtime/src/gateway/mod.rs` around lines 1613 - 1645, Replace the separate contains() pre-check and later record() with an atomic reservation using record_if_new() before calling webhook_dispatch::execute: call webhook_idempotency_key(&headers) once, if Some(key) then if state.idempotency_store.record_if_new(key) returns false immediately return webhook_duplicate_response(key); proceed to call webhook_dispatch::execute; after computing (response, persist_idempotency) from webhook_response_from_dispatch_result, if persist_idempotency is false and an idempotency key was reserved earlier call state.idempotency_store.remove(key) to release the reservation; remove the original contains()/record() pair so reservations are atomic.clients/agent-runtime/src/agent/agent.rs (1)
784-799:⚠️ Potential issue | 🟠 MajorScope
approval_requireddetection to current turn only.The function iterates the entire history in reverse. If a previous turn ended with
approval_requiredbut the current turn completed with only a text response (no tool calls), the stale denial will still be returned inAgentTurnResult.approval_required.Track
history_startat the beginning ofturn_with_contextand pass only the relevant slice:Suggested fix
pub async fn turn_with_context( &mut self, user_message: &str, turn_context: TurnContext, ) -> Result<AgentTurnResult> { + let history_start = self.history.len(); let effective_model = self .prepare_turn_with_context(user_message, &turn_context) .await?; // ... later at line 858: - approval_required: Self::approval_denial_from_history(&self.history), + approval_required: Self::approval_denial_from_history( + &self.history[history_start..], + ),🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@clients/agent-runtime/src/agent/agent.rs` around lines 784 - 799, The code currently scans the entire conversation history in approval_denial_from_history, which can return stale "approval_required" results; change call sites (e.g., turn_with_context) to compute history_start at turn start and pass only the current-turn slice (e.g., &history[history_start..]) into approval_denial_from_history, and adjust the function signature to accept that slice (or an explicit start index) so detection is scoped to the current turn only; update any callers of approval_denial_from_history to pass the sliced history and run tests to confirm AgentTurnResult.approval_required only reflects the current turn.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@clients/agent-runtime/src/gateway/webhook_dispatch.rs`:
- Around line 189-203: The ApprovalRequired branch is setting a hardcoded
"approval_required" reason which loses the structured denial reason produced by
evaluate_tool_risk() / canonical_outcome_early_response(); update the pattern in
CanonicalWebhookResult::Blocking(BlockingOutcome::ApprovalRequired { tool }) to
capture the real denial reason (e.g. BlockingOutcome::ApprovalRequired { tool,
reason }) and use that reason string when constructing WebhookTurnResult (set
WebhookTerminalOutcome::ApprovalRequired.reason to the captured reason and pass
Some(&reason) to event_frames_for_blocking_result) so the dispatcher-backed
/webhook matches the legacy path.
In `@openspec/changes/archive/2026-03-20-gateway-dispatcher-parity/design.md`:
- Around line 30-31: Update the archived API snippet so it reflects the landed
turn contract: replace usages of Agent::turn and bool-based outcome fields with
the new turn_with_context function and the AgentTurnOutcome and AgentTurnEvent
types, mapping previous boolean flags to the appropriate AgentTurnOutcome
variants and emitting AgentTurnEvent values where the old sketch referenced turn
primitives; if you prefer to keep the old sketch, mark it explicitly as
pre-implementation pseudocode and add a short note calling out the actual
shipped APIs (turn_with_context, AgentTurnOutcome, AgentTurnEvent,
unified_loop/unified_entrypoint) so readers are not misled—apply the same change
to the other sketch region mentioned.
In
`@openspec/changes/archive/2026-03-20-gateway-dispatcher-parity/verify-report.md`:
- Around line 21-41: Update the verification report to explicitly state the
status of Rust formatting and lint checks for the changed
clients/agent-runtime/**/*.rs files: either run and record the results of `cargo
fmt --all -- --check`, `cargo clippy --all-targets -- -D warnings`, and `cargo
test` (include exit codes and any failing test names such as
config::schema::tests::env_override_gateway_webhook_dispatcher), or document
that each check was intentionally skipped with the reason; reference the
affected path pattern (clients/agent-runtime/**/*.rs) and include the exact
commands and outcomes (pass/fail and exit codes) in the report.
In
`@openspec/changes/archive/2026-03-20-gateway-webhook-dispatcher-env-flake/design.md`:
- Around line 67-74: Update the File Changes table to point to the actual helper
file `clients/agent-runtime/src/test_support.rs` (instead of the speculative
`test_support/mod.rs`), and adjust the descriptions for
`clients/agent-runtime/src/config/schema.rs` and
`clients/agent-runtime/src/gateway/mod.rs` to explicitly mention that they now
use the shared dispatcher env test lock/helper in `test_support.rs` and that the
flaky test restores `CORVUS_GATEWAY_WEBHOOK_DISPATCHER` deterministically;
reference the symbol CORVUS_GATEWAY_WEBHOOK_DISPATCHER and the shared test
helper in `test_support.rs` to make the doc match the implementation.
In `@openspec/changes/archive/2026-03-20-mcp-webhook-response-mapping/design.md`:
- Around line 99-105: Update the file-change table entry so the path points to
the archived document location: change
`openspec/changes/mcp-webhook-response-mapping/design.md` to
`openspec/changes/archive/2026-03-20-mcp-webhook-response-mapping/design.md`
(the record for the created design doc referenced in the table), ensuring the
table row for that file and the Description/Action columns remain unchanged and
that any other occurrences of the non-archived path in this document are updated
to the archived path as well.
In
`@openspec/changes/archive/2026-03-20-webhook-generated-session-isolation/exploration.md`:
- Around line 5-32: Replace all hard-coded line-number citations in the
exploration notes with symbol-and-file references (e.g., resolve_session_id in
clients/agent-runtime/src/gateway/mod.rs, WebhookSessionSource::Generated in
clients/agent-runtime/src/gateway/webhook_dispatch.rs, TurnContext::default()
and relevant tests in clients/agent-runtime/src/agent/tests.rs, and the gateway
`/webhook` handler locations in clients/agent-runtime/src/gateway/mod.rs) so the
text links to functions/structs/files rather than specific line numbers; update
each reference sentence to mention the symbol and file path only, remove the
numeric anchors, and verify the surrounding prose still accurately describes the
behavior (generated webhook-{uuid} session propagation and the missing-header
proof) after making the replacements.
In
`@openspec/changes/archive/2026-03-20-webhook-generated-session-isolation/verify-report.md`:
- Line 57: Update the verification report anchors to use symbol-based references
instead of stale line numbers: replace the hardcoded line anchors for the
"Gateway Webhook Session Scoping" entry and the test
`webhook_dispatcher_generates_isolated_session_when_header_missing` and the
`TrackingMemory` symbol with current symbol-based links (e.g., reference the
test function name
`webhook_dispatcher_generates_isolated_session_when_header_missing`, the type
`TrackingMemory`, and the module `gateway`), and refresh the other affected
verification rows mentioned in the comment so all proof links point to the
current symbols in the repository rather than fixed line numbers.
---
Outside diff comments:
In `@clients/agent-runtime/src/agent/memory_loader.rs`:
- Around line 117-125: The remote Cerebro recall path currently builds a global
mem_search payload and calls cerebro::cerebro_tool_adapter
(normalize::CEREBRO_TOOL_RECALL) even when a session_id is present, which can
leak memories across sessions; modify the code in the memory loading function so
that if session_id (or the field representing session scope on self) is
Some/exists you do not construct or call the remote mem_search (the payload and
cerebro::cerebro_tool_adapter/ mem_search path) and instead fail closed — return
an Err (or skip adding remote results) with a clear error indicating remote
recall is disallowed for session-scoped turns; keep the existing global behavior
only when session_id is None.
In `@clients/agent-runtime/src/gateway/mod.rs`:
- Around line 714-735: Change resolve_session_id so that a present but
syntactically invalid X-Session-Id causes an explicit client error instead of
generating a new session: update the function signature to return a
Result<(String, webhook_dispatch::WebhookSessionSource), E> (E can be the
framework error type or an HttpResponse) and when headers.get("X-Session-Id")
exists but fails the trim/len/char validation return Err(BadRequest) with a
clear message; only when the header is absent return Ok((format!("webhook-{}",
Uuid::new_v4()), webhook_dispatch::WebhookSessionSource::Generated)), and when
the header is valid return Ok((session_id,
webhook_dispatch::WebhookSessionSource::Explicit)).
---
Duplicate comments:
In `@clients/agent-runtime/src/agent/agent.rs`:
- Around line 784-799: The code currently scans the entire conversation history
in approval_denial_from_history, which can return stale "approval_required"
results; change call sites (e.g., turn_with_context) to compute history_start at
turn start and pass only the current-turn slice (e.g.,
&history[history_start..]) into approval_denial_from_history, and adjust the
function signature to accept that slice (or an explicit start index) so
detection is scoped to the current turn only; update any callers of
approval_denial_from_history to pass the sliced history and run tests to confirm
AgentTurnResult.approval_required only reflects the current turn.
In `@clients/agent-runtime/src/gateway/mod.rs`:
- Around line 1613-1645: Replace the separate contains() pre-check and later
record() with an atomic reservation using record_if_new() before calling
webhook_dispatch::execute: call webhook_idempotency_key(&headers) once, if
Some(key) then if state.idempotency_store.record_if_new(key) returns false
immediately return webhook_duplicate_response(key); proceed to call
webhook_dispatch::execute; after computing (response, persist_idempotency) from
webhook_response_from_dispatch_result, if persist_idempotency is false and an
idempotency key was reserved earlier call state.idempotency_store.remove(key) to
release the reservation; remove the original contains()/record() pair so
reservations are atomic.
In
`@openspec/changes/archive/2026-03-20-gateway-webhook-dispatcher-env-flake/design.md`:
- Around line 79-84: The markdown snippet uses a fenced code block which
violates the repo’s configured indented code-block style and triggers MD046;
change the fenced Rust example for the test-only seam to the repo’s indented
style and keep the same signature/name (gateway_webhook_dispatcher_env_guard),
ensuring the block is prefixed by the required indentation so the linter accepts
it and the snippet remains exactly the same content-wise except for formatting.
In
`@openspec/changes/archive/2026-03-20-webhook-generated-session-isolation/exploration.md`:
- Line 3: Replace all third-level headings (e.g., the "### Current State"
heading and the other occurrences at the noted locations) with second-level
headings under the top-level title so H2 (##) follows the H1; update every "###
..." instance in this file (including the instances referenced at lines 34, 49,
68, 74, 82, 89, 96, 107) to "## ..." to satisfy markdownlint MD001.
🪄 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: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 1fc9f002-0dab-4de5-8e67-14cb93c4af26
📒 Files selected for processing (17)
clients/agent-runtime/src/agent/agent.rsclients/agent-runtime/src/agent/memory_loader.rsclients/agent-runtime/src/config/schema.rsclients/agent-runtime/src/gateway/mod.rsclients/agent-runtime/src/gateway/webhook_dispatch.rsclients/agent-runtime/src/test_support.rsclients/agent-runtime/tests/memory_backend_selection.rsopenspec/changes/archive/2026-03-20-gateway-dispatcher-parity/design.mdopenspec/changes/archive/2026-03-20-gateway-dispatcher-parity/exploration.mdopenspec/changes/archive/2026-03-20-gateway-dispatcher-parity/verify-report.mdopenspec/changes/archive/2026-03-20-gateway-webhook-dispatcher-env-flake/design.mdopenspec/changes/archive/2026-03-20-gateway-webhook-dispatcher-env-flake/tasks.mdopenspec/changes/archive/2026-03-20-mcp-webhook-response-mapping/design.mdopenspec/changes/archive/2026-03-20-webhook-generated-session-isolation/design.mdopenspec/changes/archive/2026-03-20-webhook-generated-session-isolation/exploration.mdopenspec/changes/archive/2026-03-20-webhook-generated-session-isolation/tasks.mdopenspec/changes/archive/2026-03-20-webhook-generated-session-isolation/verify-report.md
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: pr-checks
- GitHub Check: Cloudflare Pages
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{md,mdx}
⚙️ CodeRabbit configuration file
**/*.{md,mdx}: Verify technical accuracy and that docs stay aligned with code changes.
For user-facing docs, check EN/ES parity or explicitly note pending translation gaps.
Files:
openspec/changes/archive/2026-03-20-gateway-webhook-dispatcher-env-flake/tasks.mdopenspec/changes/archive/2026-03-20-webhook-generated-session-isolation/tasks.mdopenspec/changes/archive/2026-03-20-webhook-generated-session-isolation/design.mdopenspec/changes/archive/2026-03-20-gateway-dispatcher-parity/design.mdopenspec/changes/archive/2026-03-20-mcp-webhook-response-mapping/design.mdopenspec/changes/archive/2026-03-20-gateway-dispatcher-parity/exploration.mdopenspec/changes/archive/2026-03-20-gateway-dispatcher-parity/verify-report.mdopenspec/changes/archive/2026-03-20-gateway-webhook-dispatcher-env-flake/design.mdopenspec/changes/archive/2026-03-20-webhook-generated-session-isolation/exploration.mdopenspec/changes/archive/2026-03-20-webhook-generated-session-isolation/verify-report.md
**/*
⚙️ CodeRabbit configuration file
**/*: Security first, performance second.
Validate input boundaries, auth/authz implications, and secret management.
Look for behavioral regressions, missing tests, and contract breaks across modules.
Files:
openspec/changes/archive/2026-03-20-gateway-webhook-dispatcher-env-flake/tasks.mdopenspec/changes/archive/2026-03-20-webhook-generated-session-isolation/tasks.mdopenspec/changes/archive/2026-03-20-webhook-generated-session-isolation/design.mdopenspec/changes/archive/2026-03-20-gateway-dispatcher-parity/design.mdclients/agent-runtime/tests/memory_backend_selection.rsopenspec/changes/archive/2026-03-20-mcp-webhook-response-mapping/design.mdopenspec/changes/archive/2026-03-20-gateway-dispatcher-parity/exploration.mdclients/agent-runtime/src/config/schema.rsopenspec/changes/archive/2026-03-20-gateway-dispatcher-parity/verify-report.mdopenspec/changes/archive/2026-03-20-gateway-webhook-dispatcher-env-flake/design.mdclients/agent-runtime/src/test_support.rsclients/agent-runtime/src/agent/memory_loader.rsopenspec/changes/archive/2026-03-20-webhook-generated-session-isolation/exploration.mdclients/agent-runtime/src/gateway/webhook_dispatch.rsopenspec/changes/archive/2026-03-20-webhook-generated-session-isolation/verify-report.mdclients/agent-runtime/src/agent/agent.rsclients/agent-runtime/src/gateway/mod.rs
clients/agent-runtime/**/*.rs
📄 CodeRabbit inference engine (clients/agent-runtime/AGENTS.md)
Run
cargo fmt --all -- --check,cargo clippy --all-targets -- -D warnings, andcargo testfor code validation, or document which checks were skipped and why
Files:
clients/agent-runtime/tests/memory_backend_selection.rsclients/agent-runtime/src/config/schema.rsclients/agent-runtime/src/test_support.rsclients/agent-runtime/src/agent/memory_loader.rsclients/agent-runtime/src/gateway/webhook_dispatch.rsclients/agent-runtime/src/agent/agent.rsclients/agent-runtime/src/gateway/mod.rs
**/*.rs
⚙️ CodeRabbit configuration file
**/*.rs: Focus on Rust idioms, memory safety, and ownership/borrowing correctness.
Flag unnecessary clones, unchecked panics in production paths, and weak error context.
Prioritize unsafe blocks, FFI boundaries, concurrency races, and secret handling.
Files:
clients/agent-runtime/tests/memory_backend_selection.rsclients/agent-runtime/src/config/schema.rsclients/agent-runtime/src/test_support.rsclients/agent-runtime/src/agent/memory_loader.rsclients/agent-runtime/src/gateway/webhook_dispatch.rsclients/agent-runtime/src/agent/agent.rsclients/agent-runtime/src/gateway/mod.rs
clients/agent-runtime/src/**/*.rs
📄 CodeRabbit inference engine (clients/agent-runtime/AGENTS.md)
clients/agent-runtime/src/**/*.rs: Never log secrets, tokens, raw credentials, or sensitive payloads in any logging statements
Avoid unnecessary allocations, clones, and blocking operations to maintain performance and efficiency
Files:
clients/agent-runtime/src/config/schema.rsclients/agent-runtime/src/test_support.rsclients/agent-runtime/src/agent/memory_loader.rsclients/agent-runtime/src/gateway/webhook_dispatch.rsclients/agent-runtime/src/agent/agent.rsclients/agent-runtime/src/gateway/mod.rs
clients/agent-runtime/src/{security,gateway,tools,config}/**/*.rs
📄 CodeRabbit inference engine (clients/agent-runtime/AGENTS.md)
Do not silently weaken security policy or access constraints; keep default behavior secure-by-default with deny-by-default where applicable
Files:
clients/agent-runtime/src/config/schema.rsclients/agent-runtime/src/gateway/webhook_dispatch.rsclients/agent-runtime/src/gateway/mod.rs
clients/agent-runtime/src/{security,gateway,tools}/**/*.rs
📄 CodeRabbit inference engine (clients/agent-runtime/AGENTS.md)
Treat
src/security/,src/gateway/,src/tools/as high-risk surfaces and never broaden filesystem/network execution scope without explicit policy checks
Files:
clients/agent-runtime/src/gateway/webhook_dispatch.rsclients/agent-runtime/src/gateway/mod.rs
🧠 Learnings (10)
📓 Common learnings
Learnt from: CR
Repo: dallay/corvus PR: 0
File: clients/agent-runtime/AGENTS.md:0-0
Timestamp: 2026-02-17T12:31:17.076Z
Learning: Applies to clients/agent-runtime/src/channels/**/*.rs : Implement `Channel` trait in `src/channels/` with consistent `send`, `listen`, and `health_check` semantics and cover auth/allowlist/health behavior with tests
📚 Learning: 2026-02-17T12:31:17.076Z
Learnt from: CR
Repo: dallay/corvus PR: 0
File: clients/agent-runtime/AGENTS.md:0-0
Timestamp: 2026-02-17T12:31:17.076Z
Learning: Include threat/risk notes and rollback strategy for security, runtime, and gateway changes; add or update tests for boundary checks and failure modes
Applied to files:
openspec/changes/archive/2026-03-20-gateway-webhook-dispatcher-env-flake/tasks.mdopenspec/changes/archive/2026-03-20-gateway-dispatcher-parity/exploration.mdopenspec/changes/archive/2026-03-20-gateway-dispatcher-parity/verify-report.mdopenspec/changes/archive/2026-03-20-gateway-webhook-dispatcher-env-flake/design.md
📚 Learning: 2026-02-17T12:31:17.076Z
Learnt from: CR
Repo: dallay/corvus PR: 0
File: clients/agent-runtime/AGENTS.md:0-0
Timestamp: 2026-02-17T12:31:17.076Z
Learning: Applies to clients/agent-runtime/**/*.rs : Run `cargo fmt --all -- --check`, `cargo clippy --all-targets -- -D warnings`, and `cargo test` for code validation, or document which checks were skipped and why
Applied to files:
openspec/changes/archive/2026-03-20-gateway-webhook-dispatcher-env-flake/tasks.mdopenspec/changes/archive/2026-03-20-gateway-dispatcher-parity/verify-report.mdopenspec/changes/archive/2026-03-20-gateway-webhook-dispatcher-env-flake/design.mdclients/agent-runtime/src/test_support.rs
📚 Learning: 2026-02-17T12:31:17.076Z
Learnt from: CR
Repo: dallay/corvus PR: 0
File: clients/agent-runtime/AGENTS.md:0-0
Timestamp: 2026-02-17T12:31:17.076Z
Learning: Applies to clients/agent-runtime/src/main.rs : Preserve CLI contract unless change is intentional and documented; prefer explicit errors over silent fallback for unsupported critical paths
Applied to files:
openspec/changes/archive/2026-03-20-gateway-webhook-dispatcher-env-flake/tasks.mdopenspec/changes/archive/2026-03-20-webhook-generated-session-isolation/design.mdopenspec/changes/archive/2026-03-20-gateway-dispatcher-parity/design.mdclients/agent-runtime/tests/memory_backend_selection.rsclients/agent-runtime/src/config/schema.rsopenspec/changes/archive/2026-03-20-gateway-dispatcher-parity/verify-report.mdclients/agent-runtime/src/test_support.rsclients/agent-runtime/src/gateway/webhook_dispatch.rsclients/agent-runtime/src/agent/agent.rsclients/agent-runtime/src/gateway/mod.rs
📚 Learning: 2026-02-17T12:31:17.076Z
Learnt from: CR
Repo: dallay/corvus PR: 0
File: clients/agent-runtime/AGENTS.md:0-0
Timestamp: 2026-02-17T12:31:17.076Z
Learning: Applies to clients/agent-runtime/src/{security,gateway,tools,config}/**/*.rs : Do not silently weaken security policy or access constraints; keep default behavior secure-by-default with deny-by-default where applicable
Applied to files:
clients/agent-runtime/src/config/schema.rsopenspec/changes/archive/2026-03-20-gateway-dispatcher-parity/verify-report.mdclients/agent-runtime/src/test_support.rsclients/agent-runtime/src/gateway/webhook_dispatch.rsclients/agent-runtime/src/gateway/mod.rs
📚 Learning: 2026-02-17T12:31:17.076Z
Learnt from: CR
Repo: dallay/corvus PR: 0
File: clients/agent-runtime/AGENTS.md:0-0
Timestamp: 2026-02-17T12:31:17.076Z
Learning: Applies to clients/agent-runtime/src/{security,gateway,tools}/**/*.rs : Treat `src/security/`, `src/gateway/`, `src/tools/` as high-risk surfaces and never broaden filesystem/network execution scope without explicit policy checks
Applied to files:
clients/agent-runtime/src/config/schema.rsclients/agent-runtime/src/test_support.rsclients/agent-runtime/src/gateway/webhook_dispatch.rs
📚 Learning: 2026-02-17T12:31:17.076Z
Learnt from: CR
Repo: dallay/corvus PR: 0
File: clients/agent-runtime/AGENTS.md:0-0
Timestamp: 2026-02-17T12:31:17.076Z
Learning: Applies to clients/agent-runtime/src/main.rs : Keep startup path lean and avoid heavy initialization in command parsing flow
Applied to files:
clients/agent-runtime/src/config/schema.rsclients/agent-runtime/src/agent/agent.rs
📚 Learning: 2026-02-17T12:31:17.076Z
Learnt from: CR
Repo: dallay/corvus PR: 0
File: clients/agent-runtime/AGENTS.md:0-0
Timestamp: 2026-02-17T12:31:17.076Z
Learning: Applies to clients/agent-runtime/src/channels/**/*.rs : Implement `Channel` trait in `src/channels/` with consistent `send`, `listen`, and `health_check` semantics and cover auth/allowlist/health behavior with tests
Applied to files:
clients/agent-runtime/src/test_support.rsclients/agent-runtime/src/gateway/mod.rs
📚 Learning: 2026-02-17T12:31:17.076Z
Learnt from: CR
Repo: dallay/corvus PR: 0
File: clients/agent-runtime/AGENTS.md:0-0
Timestamp: 2026-02-17T12:31:17.076Z
Learning: Applies to clients/agent-runtime/src/providers/**/*.rs : Implement `Provider` trait in `src/providers/` and register in `src/providers/mod.rs` factory when adding a new provider
Applied to files:
clients/agent-runtime/src/agent/agent.rsclients/agent-runtime/src/gateway/mod.rs
📚 Learning: 2026-02-17T12:31:17.076Z
Learnt from: CR
Repo: dallay/corvus PR: 0
File: clients/agent-runtime/AGENTS.md:0-0
Timestamp: 2026-02-17T12:31:17.076Z
Learning: Applies to clients/agent-runtime/src/**/*.rs : Never log secrets, tokens, raw credentials, or sensitive payloads in any logging statements
Applied to files:
clients/agent-runtime/src/gateway/mod.rs
🪛 LanguageTool
openspec/changes/archive/2026-03-20-webhook-generated-session-isolation/tasks.md
[grammar] ~1-~1: Use a hyphen to join words.
Context: # Tasks: Webhook Generated Session Isolation ## Phase 1:...
(QB_NEW_EN_HYPHEN)
openspec/changes/archive/2026-03-20-webhook-generated-session-isolation/design.md
[grammar] ~1-~1: Use a hyphen to join words.
Context: # Design: Webhook Generated Session Isolation ## Technica...
(QB_NEW_EN_HYPHEN)
openspec/changes/archive/2026-03-20-gateway-dispatcher-parity/design.md
[uncategorized] ~177-~177: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ...- pairing enforcement - IP/header-aware rate limiting - idempotency policy - request parsing ...
(EN_COMPOUND_ADJECTIVE_INTERNAL)
[style] ~350-~350: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...ts. - No resumable approval protocol. - No broad channels/gateway shared-runtime r...
(ENGLISH_WORD_REPEAT_BEGINNING_RULE)
openspec/changes/archive/2026-03-20-webhook-generated-session-isolation/exploration.md
[style] ~93-~93: As an alternative to the over-used intensifier ‘very’, consider replacing this phrase.
Context: ...ta spec for the follow-up, it should be a very small agent-loop delta that restates this a...
(EN_WEAK_ADJECTIVE)
🪛 markdownlint-cli2 (0.21.0)
openspec/changes/archive/2026-03-20-gateway-dispatcher-parity/exploration.md
[warning] 26-26: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
[warning] 35-35: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
[warning] 46-46: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
[warning] 55-55: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
[warning] 61-61: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
openspec/changes/archive/2026-03-20-gateway-dispatcher-parity/verify-report.md
[warning] 81-81: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
openspec/changes/archive/2026-03-20-gateway-webhook-dispatcher-env-flake/design.md
[warning] 81-81: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
openspec/changes/archive/2026-03-20-webhook-generated-session-isolation/exploration.md
[warning] 3-3: Heading levels should only increment by one level at a time
Expected: h2; Actual: h3
(MD001, heading-increment)
🔇 Additional comments (11)
clients/agent-runtime/src/config/schema.rs (1)
666-673: Defaulting this rollout flag off is the right security posture.
webhook_dispatcher_enabledstays opt-in, and theDefaultimpl matches the documented behavior, so/webhookremains on the legacy path unless operators explicitly enable dispatcher mode.As per coding guidelines
clients/agent-runtime/src/{security,gateway,tools,config}/**/*.rs: Do not silently weaken security policy or access constraints; keep default behavior secure-by-default with deny-by-default where applicable.Also applies to: 723-724
clients/agent-runtime/src/test_support.rs (1)
31-88: Nice shared env-guard extraction.This gives config and gateway tests one serialization point for
CORVUS_GATEWAY_WEBHOOK_DISPATCHERand restores the prior value on drop.clients/agent-runtime/src/gateway/mod.rs (1)
1388-1405: Good redaction on duplicate-idempotency logging.Fingerprinting the idempotency key here is a solid improvement over emitting the raw header value.
clients/agent-runtime/src/gateway/webhook_dispatch.rs (1)
318-337: Nice fail-closed handling for classified blocks.Returning immediately on pre-execution blocks keeps the dispatcher path deny-by-default before the agent ever runs.
Based on learnings
Applies to clients/agent-runtime/src/{security,gateway,tools,config}/**/*.rs : Do not silently weaken security policy or access constraints; keep default behavior secure-by-default with deny-by-default where applicableclients/agent-runtime/src/agent/agent.rs (7)
30-73: LGTM!Clean type definitions for the session-aware turn API. The
TurnContextdesign withwith_sessionconstructor andDefaultimpl provides ergonomic construction paths.
595-648: LGTM!Session ID correctly threaded through memory operations. The fallback on
load_contextfailure (log + empty string) is appropriate for resilience.
659-695: LGTM!Session ID properly passed to assistant response storage. Truncation before storage is a sensible memory hygiene practice.
811-836: LGTM!Session ID is now correctly propagated into
TurnContextfor code-mode turns, addressing the previous session/audit divergence concern.
838-868: LGTM!Clean structured return API with proper event logging. Session ID correctly propagated to result for downstream correlation.
1393-1445: LGTM!Clean refactor threading
turn_contextthrough the step pipeline. Mission policy enforcement and tool result handling remain intact.
382-386: LGTM!
pub(crate)visibility is appropriate for internal gateway/webhook dispatcher wiring without exposing to external consumers.
…-canonical-agent-dispatcher
…-canonical-agent-dispatcher
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
Actionable comments posted: 14
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@clients/agent-runtime/src/agent/agent.rs`:
- Around line 41-54: TurnContext exposes a public origin field but nothing reads
it, making the API misleading; either remove origin from the TurnContext struct
or thread it into the policy gating logic. To fix, choose one: (A) delete the
origin field and its uses (and update constructors like
TurnContext::with_session and any TurnContext::default) so callers cannot pass
an unused origin, or (B) update the execution/policy check paths (the functions
that use the "mission" flag and the entry points like turn_with_context and any
execution gating code) to consult TurnContext.origin (e.g., add a parameter or
access TurnContext.origin inside the policy decision function) so origin
actually influences behavior; pick one approach and apply consistently across
TurnContext, with_session, turn_with_context, and the mission gating logic.
- Around line 843-861: The code captures history_start before the turn mutates
self.history, then later computes approval_required from
&self.history[history_start..], which is invalid if trim_history() ran and
shifted/compacted history; instead, compute and track approval state in
turn-local state while processing the turn (e.g., set a local approval_required
flag when detecting approval/denial events during prepare_turn_with_context /
step_with_context) and return that flag into the AgentTurnResult rather than
slicing self.history by history_start; update uses of history_start,
approval_denial_from_history, and the return path that constructs
AgentTurnResult (including where AgentTurnEvent::Completed is pushed) to use the
new local approval_required value.
In `@clients/agent-runtime/src/agent/memory_loader.rs`:
- Around line 117-120: The code currently panics with anyhow::bail! when
session_id.is_some(), which prevents session-scoped turns from falling back to
local recall; instead, change the branch in the function that checks session_id
(the block containing session_id.is_some() and the call path to mem_search /
Cerebro remote recall) to not bail—log or warn the condition and skip remote
Cerebro recall, returning the safe local-only result (e.g., Ok(None) or the
already-found local memory) so session-aware turns continue without error;
ensure mem_search remains unchanged and only the remote-recall path is skipped
when session_id is present.
In `@clients/agent-runtime/src/gateway/mod.rs`:
- Around line 1629-1667: The branch currently reserves and conditionally
releases idempotency only when dispatcher_enabled (see dispatcher_enabled,
reserved_idempotency_key, webhook_idempotency_key,
state.idempotency_store.record_if_new), causing retryability differences versus
the legacy /webhook/simple_chat path; move the idempotency reservation logic so
the key is reserved before choosing between webhook_dispatch::execute and the
legacy/simple_chat flow, and ensure both paths call the same release policy (use
webhook_response_from_dispatch_result-like persist_idempotency handling and call
state.idempotency_store.remove when persist_idempotency is false) so provider
failures yield identical 500 retry behavior; also add a legacy 500-retry test
that posts with an idempotency key and verifies the key is consumed/released
consistently across dispatcher_enabled true/false.
In `@clients/agent-runtime/src/gateway/webhook_dispatch.rs`:
- Around line 284-295: render_sse_frame currently injects session_id verbatim
into the SSE "id:" field which allows CR/LF injection; sanitize or canonicalize
the session_id before formatting by normalizing it to a single line (e.g., strip
or replace '\r' and '\n' and trim whitespace or take only the first line) and
ensure empty/invalid ids are handled consistently, and update/add a
unit/regression test that passes a session_id containing newlines to
render_sse_frame to assert the output contains a single-line id and no extra SSE
fields; modify the render_sse_frame function's session_id usage (and any callers
if needed) to use the sanitized value.
- Around line 367-378: The code currently falls back to
CanonicalWebhookResult::Agent(result) when approval_denial_from_value() fails to
extract fields, silently downgrading an approval-required event; change the
branch that tests result.approval_required to always map to
CanonicalWebhookResult::ApprovalRequired when approval_required is Some(_) (or
surface an Error), and if approval_denial_from_value() returns a tool with
missing reason, derive the reason using approval_reason_for_tool(tool) instead
of the literal "approval_required"; update map_canonical_result usage
accordingly (referencing AgentTurnResult.approval_required,
approval_denial_from_value, CanonicalWebhookResult::ApprovalRequired,
approval_reason_for_tool and map_canonical_result) and add a regression test
that submits a payload with code == "approval_required" but missing fields to
assert the result is ApprovalRequired (or Error) rather than Completed.
- Around line 298-319: The helper approval_denial_from_history currently scans
history oldest-first while the runtime parser in agent::agent.rs uses
history.iter().rev(); fix this by making approval_denial_from_history iterate
newest-first (e.g., use history.iter().rev() on the outer iterator) so the
search order matches the runtime parser, ensuring the same approval_required
tool result is returned; alternatively, call or reuse the agent-side parser used
at agent::agent.rs lines ~784-799 to keep logic identical.
In `@openspec/changes/archive/2026-03-20-gateway-dispatcher-parity/design.md`:
- Around line 256-264: Update the `/webhook` response contract to account for
the adapter terminal outcomes: map WebhookTerminalOutcome::Fallback to `200 OK`
with the `response` shape plus `fallback: true`, and map
WebhookTerminalOutcome::Error to `500 Internal Server Error` with a structured
`error` payload (distinct from the transport-only 500 case described); keep
`403` for approval-required tool actions, `408` for canonical timeouts with
`aborted: true`, and ensure `session_id` is explicitly stated as echoed in all
terminal responses and that `events_sse` frames (when present) are derived from
the real canonical execution path.
In
`@openspec/changes/archive/2026-03-20-gateway-dispatcher-parity/verify-report.md`:
- Line 17: Update the checklist link in verify-report.md to point to the
archived tasks file instead of the live path: replace references to
"openspec/changes/gateway-dispatcher-parity/tasks.md" with
"openspec/changes/archive/2026-03-20-gateway-dispatcher-parity/tasks.md" so the
checklist stays correct in the archived report; edit the link in
verify-report.md (the file under
openspec/changes/archive/2026-03-20-gateway-dispatcher-parity/) to use the
archived tasks.md path.
In
`@openspec/changes/archive/2026-03-20-gateway-webhook-dispatcher-env-flake/design.md`:
- Around line 71-72: The planned gateway changes must also prevent unguarded
reads of CORVUS_GATEWAY_WEBHOOK_DISPATCHER in
clients/agent-runtime/src/gateway/mod.rs::temp_config(): update temp_config to
obtain the same shared test lock/helper from
clients/agent-runtime/src/test_support.rs (or otherwise remove the direct env
read) before reading CORVUS_GATEWAY_WEBHOOK_DISPATCHER so gateway tests cannot
observe another test's transient env value, and ensure temp_config restores or
derives the value deterministically under that lock.
In `@openspec/changes/archive/2026-03-20-mcp-webhook-response-mapping/design.md`:
- Around line 45-58: The decision text in design.md claims a single non-success
seam (Error) suffices, but webhook_response_from_dispatch_result(...) implements
both Timeout and Error paths with different transport contracts; update the
document to either require tests for both Timeout (408 + aborted) and Error (500
+ body) branches or explicitly narrow the decision to state that only the Error
branch is in-scope and justify why Timeout can remain unproven; reference
webhook_response_from_dispatch_result, the Timeout and Error branches, and
ensure the rationale aligns with the actual transport contracts described.
In
`@openspec/changes/archive/2026-03-20-webhook-generated-session-isolation/exploration.md`:
- Around line 16-26: Update the archive note in exploration.md to reflect
current code: change the phrasing that calls missing-header session isolation a
remaining gap to state that the gateway test
webhook_dispatcher_generates_isolated_session_when_header_missing (in
clients/agent-runtime/src/gateway/mod.rs) now provides end-to-end proof, or
explicitly mark the paragraph as historical context; also update the sentence
ranges noted (lines ~64-75) to avoid contradicting the implementation and ensure
the doc references the test by name and file so readers can locate the proof.
In
`@openspec/changes/archive/2026-03-20-webhook-generated-session-isolation/verify-report.md`:
- Around line 79-80: The documentation references two different test symbols for
the "missing-session" proof
(agent::tests::turn_with_context_keeps_missing_session_isolated vs
turn_with_context_omits_session_scope_when_context_missing) which causes an
audit mismatch; update the verify-report.md evidence bullet to use the exact
landed test symbol name (or, if both tests exist, add a one-line clarification
distinguishing their intent) so the doc matches the code; specifically ensure
the evidence bullet references either
turn_with_context_keeps_missing_session_isolated or
turn_with_context_omits_session_scope_when_context_missing (whichever is the
actual test in clients/agent-runtime/src/agent/tests.rs) and, if keeping both,
briefly state the difference relative to
turn_with_context_scopes_memory_recall_and_auto_save_to_session.
- Around line 21-47: The report omitted whether code style and lint checks were
run for the changed Rust surface (clients/agent-runtime/**/*.rs); run and record
the results of `cargo fmt --all -- --check` and `cargo clippy --all-targets --
-D warnings` against that directory (or explicitly document that you
intentionally skipped them and why), and update the verify-report.md to state
the exact commands executed and their pass/fail outputs for those files.
🪄 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: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 4dc40840-e6a1-40f5-87a6-6b3cbebc6461
📒 Files selected for processing (12)
clients/agent-runtime/src/agent/agent.rsclients/agent-runtime/src/agent/memory_loader.rsclients/agent-runtime/src/gateway/mod.rsclients/agent-runtime/src/gateway/webhook_dispatch.rsclients/agent-runtime/src/test_support.rsclients/agent-runtime/tests/memory_backend_selection.rsopenspec/changes/archive/2026-03-20-gateway-dispatcher-parity/design.mdopenspec/changes/archive/2026-03-20-gateway-dispatcher-parity/verify-report.mdopenspec/changes/archive/2026-03-20-gateway-webhook-dispatcher-env-flake/design.mdopenspec/changes/archive/2026-03-20-mcp-webhook-response-mapping/design.mdopenspec/changes/archive/2026-03-20-webhook-generated-session-isolation/exploration.mdopenspec/changes/archive/2026-03-20-webhook-generated-session-isolation/verify-report.md
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: pr-checks
- GitHub Check: sonar
- GitHub Check: pr-checks
- GitHub Check: Cloudflare Pages
🧰 Additional context used
📓 Path-based instructions (7)
clients/agent-runtime/**/*.rs
📄 CodeRabbit inference engine (clients/agent-runtime/AGENTS.md)
Run
cargo fmt --all -- --check,cargo clippy --all-targets -- -D warnings, andcargo testfor code validation, or document which checks were skipped and why
Files:
clients/agent-runtime/tests/memory_backend_selection.rsclients/agent-runtime/src/test_support.rsclients/agent-runtime/src/agent/memory_loader.rsclients/agent-runtime/src/agent/agent.rsclients/agent-runtime/src/gateway/webhook_dispatch.rsclients/agent-runtime/src/gateway/mod.rs
**/*.rs
⚙️ CodeRabbit configuration file
**/*.rs: Focus on Rust idioms, memory safety, and ownership/borrowing correctness.
Flag unnecessary clones, unchecked panics in production paths, and weak error context.
Prioritize unsafe blocks, FFI boundaries, concurrency races, and secret handling.
Files:
clients/agent-runtime/tests/memory_backend_selection.rsclients/agent-runtime/src/test_support.rsclients/agent-runtime/src/agent/memory_loader.rsclients/agent-runtime/src/agent/agent.rsclients/agent-runtime/src/gateway/webhook_dispatch.rsclients/agent-runtime/src/gateway/mod.rs
**/*
⚙️ CodeRabbit configuration file
**/*: Security first, performance second.
Validate input boundaries, auth/authz implications, and secret management.
Look for behavioral regressions, missing tests, and contract breaks across modules.
Files:
clients/agent-runtime/tests/memory_backend_selection.rsopenspec/changes/archive/2026-03-20-gateway-webhook-dispatcher-env-flake/design.mdopenspec/changes/archive/2026-03-20-webhook-generated-session-isolation/verify-report.mdclients/agent-runtime/src/test_support.rsopenspec/changes/archive/2026-03-20-webhook-generated-session-isolation/exploration.mdclients/agent-runtime/src/agent/memory_loader.rsopenspec/changes/archive/2026-03-20-gateway-dispatcher-parity/design.mdopenspec/changes/archive/2026-03-20-gateway-dispatcher-parity/verify-report.mdopenspec/changes/archive/2026-03-20-mcp-webhook-response-mapping/design.mdclients/agent-runtime/src/agent/agent.rsclients/agent-runtime/src/gateway/webhook_dispatch.rsclients/agent-runtime/src/gateway/mod.rs
**/*.{md,mdx}
⚙️ CodeRabbit configuration file
**/*.{md,mdx}: Verify technical accuracy and that docs stay aligned with code changes.
For user-facing docs, check EN/ES parity or explicitly note pending translation gaps.
Files:
openspec/changes/archive/2026-03-20-gateway-webhook-dispatcher-env-flake/design.mdopenspec/changes/archive/2026-03-20-webhook-generated-session-isolation/verify-report.mdopenspec/changes/archive/2026-03-20-webhook-generated-session-isolation/exploration.mdopenspec/changes/archive/2026-03-20-gateway-dispatcher-parity/design.mdopenspec/changes/archive/2026-03-20-gateway-dispatcher-parity/verify-report.mdopenspec/changes/archive/2026-03-20-mcp-webhook-response-mapping/design.md
clients/agent-runtime/src/**/*.rs
📄 CodeRabbit inference engine (clients/agent-runtime/AGENTS.md)
clients/agent-runtime/src/**/*.rs: Never log secrets, tokens, raw credentials, or sensitive payloads in any logging statements
Avoid unnecessary allocations, clones, and blocking operations to maintain performance and efficiency
Files:
clients/agent-runtime/src/test_support.rsclients/agent-runtime/src/agent/memory_loader.rsclients/agent-runtime/src/agent/agent.rsclients/agent-runtime/src/gateway/webhook_dispatch.rsclients/agent-runtime/src/gateway/mod.rs
clients/agent-runtime/src/{security,gateway,tools}/**/*.rs
📄 CodeRabbit inference engine (clients/agent-runtime/AGENTS.md)
Treat
src/security/,src/gateway/,src/tools/as high-risk surfaces and never broaden filesystem/network execution scope without explicit policy checks
Files:
clients/agent-runtime/src/gateway/webhook_dispatch.rsclients/agent-runtime/src/gateway/mod.rs
clients/agent-runtime/src/{security,gateway,tools,config}/**/*.rs
📄 CodeRabbit inference engine (clients/agent-runtime/AGENTS.md)
Do not silently weaken security policy or access constraints; keep default behavior secure-by-default with deny-by-default where applicable
Files:
clients/agent-runtime/src/gateway/webhook_dispatch.rsclients/agent-runtime/src/gateway/mod.rs
🧠 Learnings (14)
📓 Common learnings
Learnt from: CR
Repo: dallay/corvus PR: 0
File: clients/agent-runtime/AGENTS.md:0-0
Timestamp: 2026-02-17T12:31:17.076Z
Learning: Applies to clients/agent-runtime/src/channels/**/*.rs : Implement `Channel` trait in `src/channels/` with consistent `send`, `listen`, and `health_check` semantics and cover auth/allowlist/health behavior with tests
Learnt from: CR
Repo: dallay/corvus PR: 0
File: clients/agent-runtime/AGENTS.md:0-0
Timestamp: 2026-02-17T12:31:17.076Z
Learning: Applies to clients/agent-runtime/src/{security,gateway,tools,config}/**/*.rs : Do not silently weaken security policy or access constraints; keep default behavior secure-by-default with deny-by-default where applicable
Learnt from: CR
Repo: dallay/corvus PR: 0
File: clients/agent-runtime/AGENTS.md:0-0
Timestamp: 2026-02-17T12:31:17.076Z
Learning: Include threat/risk notes and rollback strategy for security, runtime, and gateway changes; add or update tests for boundary checks and failure modes
📚 Learning: 2026-02-17T12:31:17.076Z
Learnt from: CR
Repo: dallay/corvus PR: 0
File: clients/agent-runtime/AGENTS.md:0-0
Timestamp: 2026-02-17T12:31:17.076Z
Learning: Applies to clients/agent-runtime/src/main.rs : Preserve CLI contract unless change is intentional and documented; prefer explicit errors over silent fallback for unsupported critical paths
Applied to files:
clients/agent-runtime/tests/memory_backend_selection.rsopenspec/changes/archive/2026-03-20-gateway-webhook-dispatcher-env-flake/design.mdopenspec/changes/archive/2026-03-20-webhook-generated-session-isolation/exploration.mdclients/agent-runtime/src/agent/memory_loader.rsopenspec/changes/archive/2026-03-20-gateway-dispatcher-parity/design.mdopenspec/changes/archive/2026-03-20-gateway-dispatcher-parity/verify-report.mdclients/agent-runtime/src/agent/agent.rsclients/agent-runtime/src/gateway/webhook_dispatch.rs
📚 Learning: 2026-02-17T12:31:17.076Z
Learnt from: CR
Repo: dallay/corvus PR: 0
File: clients/agent-runtime/AGENTS.md:0-0
Timestamp: 2026-02-17T12:31:17.076Z
Learning: Include threat/risk notes and rollback strategy for security, runtime, and gateway changes; add or update tests for boundary checks and failure modes
Applied to files:
openspec/changes/archive/2026-03-20-gateway-webhook-dispatcher-env-flake/design.mdopenspec/changes/archive/2026-03-20-gateway-dispatcher-parity/verify-report.md
📚 Learning: 2026-02-17T12:31:17.076Z
Learnt from: CR
Repo: dallay/corvus PR: 0
File: clients/agent-runtime/AGENTS.md:0-0
Timestamp: 2026-02-17T12:31:17.076Z
Learning: Applies to clients/agent-runtime/**/*.rs : Run `cargo fmt --all -- --check`, `cargo clippy --all-targets -- -D warnings`, and `cargo test` for code validation, or document which checks were skipped and why
Applied to files:
openspec/changes/archive/2026-03-20-gateway-webhook-dispatcher-env-flake/design.mdopenspec/changes/archive/2026-03-20-webhook-generated-session-isolation/verify-report.mdclients/agent-runtime/src/test_support.rsopenspec/changes/archive/2026-03-20-webhook-generated-session-isolation/exploration.mdopenspec/changes/archive/2026-03-20-gateway-dispatcher-parity/verify-report.md
📚 Learning: 2026-02-17T12:31:17.076Z
Learnt from: CR
Repo: dallay/corvus PR: 0
File: clients/agent-runtime/AGENTS.md:0-0
Timestamp: 2026-02-17T12:31:17.076Z
Learning: Applies to clients/agent-runtime/src/{security,gateway,tools,config}/**/*.rs : Do not silently weaken security policy or access constraints; keep default behavior secure-by-default with deny-by-default where applicable
Applied to files:
openspec/changes/archive/2026-03-20-gateway-webhook-dispatcher-env-flake/design.mdopenspec/changes/archive/2026-03-20-webhook-generated-session-isolation/verify-report.mdclients/agent-runtime/src/test_support.rsopenspec/changes/archive/2026-03-20-webhook-generated-session-isolation/exploration.mdopenspec/changes/archive/2026-03-20-gateway-dispatcher-parity/verify-report.mdclients/agent-runtime/src/gateway/webhook_dispatch.rsclients/agent-runtime/src/gateway/mod.rs
📚 Learning: 2026-02-17T12:31:17.076Z
Learnt from: CR
Repo: dallay/corvus PR: 0
File: clients/agent-runtime/AGENTS.md:0-0
Timestamp: 2026-02-17T12:31:17.076Z
Learning: Applies to clients/agent-runtime/src/{security,gateway,tools}/**/*.rs : Treat `src/security/`, `src/gateway/`, `src/tools/` as high-risk surfaces and never broaden filesystem/network execution scope without explicit policy checks
Applied to files:
clients/agent-runtime/src/test_support.rsopenspec/changes/archive/2026-03-20-webhook-generated-session-isolation/exploration.mdopenspec/changes/archive/2026-03-20-gateway-dispatcher-parity/verify-report.mdclients/agent-runtime/src/gateway/webhook_dispatch.rs
📚 Learning: 2026-02-17T12:31:17.076Z
Learnt from: CR
Repo: dallay/corvus PR: 0
File: clients/agent-runtime/AGENTS.md:0-0
Timestamp: 2026-02-17T12:31:17.076Z
Learning: Applies to clients/agent-runtime/src/channels/**/*.rs : Implement `Channel` trait in `src/channels/` with consistent `send`, `listen`, and `health_check` semantics and cover auth/allowlist/health behavior with tests
Applied to files:
clients/agent-runtime/src/test_support.rsopenspec/changes/archive/2026-03-20-gateway-dispatcher-parity/verify-report.mdclients/agent-runtime/src/gateway/mod.rs
📚 Learning: 2026-02-17T12:31:17.076Z
Learnt from: CR
Repo: dallay/corvus PR: 0
File: clients/agent-runtime/AGENTS.md:0-0
Timestamp: 2026-02-17T12:31:17.076Z
Learning: Applies to clients/agent-runtime/src/tools/**/*.rs : Implement `Tool` trait in `src/tools/` with strict parameter schema, validate and sanitize all inputs, and return structured `ToolResult` without panics in runtime path
Applied to files:
openspec/changes/archive/2026-03-20-gateway-dispatcher-parity/verify-report.md
📚 Learning: 2026-02-17T12:31:17.076Z
Learnt from: CR
Repo: dallay/corvus PR: 0
File: clients/agent-runtime/AGENTS.md:0-0
Timestamp: 2026-02-17T12:31:17.076Z
Learning: Applies to clients/agent-runtime/**/Cargo.toml : Do not add heavy dependencies for minor convenience; justify new crate additions
Applied to files:
openspec/changes/archive/2026-03-20-gateway-dispatcher-parity/verify-report.md
📚 Learning: 2026-02-17T12:31:17.076Z
Learnt from: CR
Repo: dallay/corvus PR: 0
File: clients/agent-runtime/AGENTS.md:0-0
Timestamp: 2026-02-17T12:31:17.076Z
Learning: Applies to clients/agent-runtime/**/Cargo.toml : Preserve release-size profile assumptions in `Cargo.toml` and avoid adding heavy dependencies unless clearly justified
Applied to files:
openspec/changes/archive/2026-03-20-gateway-dispatcher-parity/verify-report.md
📚 Learning: 2026-02-17T12:31:17.076Z
Learnt from: CR
Repo: dallay/corvus PR: 0
File: clients/agent-runtime/AGENTS.md:0-0
Timestamp: 2026-02-17T12:31:17.076Z
Learning: Applies to clients/agent-runtime/src/**/*.rs : Avoid unnecessary allocations, clones, and blocking operations to maintain performance and efficiency
Applied to files:
openspec/changes/archive/2026-03-20-gateway-dispatcher-parity/verify-report.md
📚 Learning: 2026-02-17T12:31:17.076Z
Learnt from: CR
Repo: dallay/corvus PR: 0
File: clients/agent-runtime/AGENTS.md:0-0
Timestamp: 2026-02-17T12:31:17.076Z
Learning: Applies to clients/agent-runtime/.github/**/*.{yml,yaml} : For workflow/template-only changes, ensure YAML/template syntax validity
Applied to files:
openspec/changes/archive/2026-03-20-gateway-dispatcher-parity/verify-report.md
📚 Learning: 2026-02-17T12:31:17.076Z
Learnt from: CR
Repo: dallay/corvus PR: 0
File: clients/agent-runtime/AGENTS.md:0-0
Timestamp: 2026-02-17T12:31:17.076Z
Learning: Applies to clients/agent-runtime/src/providers/**/*.rs : Implement `Provider` trait in `src/providers/` and register in `src/providers/mod.rs` factory when adding a new provider
Applied to files:
clients/agent-runtime/src/agent/agent.rsclients/agent-runtime/src/gateway/mod.rs
📚 Learning: 2026-02-17T12:31:17.076Z
Learnt from: CR
Repo: dallay/corvus PR: 0
File: clients/agent-runtime/AGENTS.md:0-0
Timestamp: 2026-02-17T12:31:17.076Z
Learning: Applies to clients/agent-runtime/src/**/*.rs : Never log secrets, tokens, raw credentials, or sensitive payloads in any logging statements
Applied to files:
clients/agent-runtime/src/gateway/mod.rs
🪛 LanguageTool
openspec/changes/archive/2026-03-20-webhook-generated-session-isolation/verify-report.md
[style] ~81-~81: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...ayer. - turn_context_for_request(...) in `clients/agent-runtime/src/gateway/webh...
(ENGLISH_WORD_REPEAT_BEGINNING_RULE)
openspec/changes/archive/2026-03-20-webhook-generated-session-isolation/exploration.md
[style] ~87-~87: As an alternative to the over-used intensifier ‘very’, consider replacing this phrase.
Context: ...ta spec for the follow-up, it should be a very small agent-loop delta that restates this a...
(EN_WEAK_ADJECTIVE)
openspec/changes/archive/2026-03-20-gateway-dispatcher-parity/design.md
[uncategorized] ~178-~178: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ...- pairing enforcement - IP/header-aware rate limiting - idempotency policy - request parsing ...
(EN_COMPOUND_ADJECTIVE_INTERNAL)
[style] ~355-~355: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...ts. - No resumable approval protocol. - No broad channels/gateway shared-runtime r...
(ENGLISH_WORD_REPEAT_BEGINNING_RULE)
🔇 Additional comments (1)
clients/agent-runtime/src/gateway/webhook_dispatch.rs (1)
330-348: Early return on pre-execution blocks looks correct.This now short-circuits approval/timeout/fallback outcomes before any agent/model work, which preserves the canonical gate in the webhook path.
|



This pull request introduces support for session-scoped memory in the agent runtime, allowing agent turns and memory operations to be associated with an explicit session context. This enables more granular control over memory recall and storage, particularly useful for scenarios like multi-session conversations or webhook-based interactions. The changes include new types for turn context and results, updates to memory loader and agent APIs, and enhancements to tests for session-aware behavior.
Session Context and Turn Result Structures:
TurnContext,AgentTurnResult,AgentTurnOutcome, andAgentTurnEventto track session context and detailed outcomes for each agent turn. These types enable passing and recording session information and turn events throughout the agent workflow.Agent API and Internal Refactoring:
prepare_turn,step,turn_with_context) to accept aTurnContext, propagate session IDs, and return richer results (AgentTurnResult). This refactoring ensures that session information is consistently used during memory and provider interactions. [1] [2] [3] [4]from_bootstrap_with_providerpublic (within the crate) to facilitate agent construction with custom providers.Memory Loader and Memory Trait Changes:
MemoryLoadertrait and its implementations to accept an optionalsession_id, ensuring memory recall can be scoped to a session. Updated memory loader logic to pass this session context to the underlying memory. [1] [2] [3]Testing Enhancements:
SessionTrackingMemory,TrackingMemory) that track session IDs used in memory operations, and extended tests to verify that the correct session context is propagated during memory recall and storage. [1] [2] [3] [4]Public API Surface:
These changes collectively enable session-aware agent behavior and lay the groundwork for advanced conversational and multi-session use cases.
Closes: #257