Skip to content

Steer routine delivery through outbound targets - #4780

Merged
serrrfirat merged 6 commits into
mainfrom
codex/outbound-delivery-planner-hint
Jun 15, 2026
Merged

serrrfirat merged 6 commits into
mainfrom
codex/outbound-delivery-planner-hint

Conversation

@serrrfirat

Copy link
Copy Markdown
Collaborator

Summary

  • add model-visible guidance on builtin.trigger_create to select outbound delivery targets before creating routines/triggers
  • teach the local-dev system prompt and outbound delivery tool descriptions to use outbound target discovery before saying Slack or another delivery product is unavailable
  • update trigger delivery contract docs and regression assertions for the model-visible hints

Tests

  • cargo fmt -p ironclaw_host_runtime -p ironclaw_reborn_composition -- --check
  • git diff --check
  • CARGO_TARGET_DIR=/Users/firatsertgoz/.codex/worktrees/channel-manifest-surfaces/reborn-ironclaw/target cargo test -p ironclaw_host_runtime visible_surface_resolves_builtin_first_party_input_schema_refs -j1
  • CARGO_TARGET_DIR=/Users/firatsertgoz/.codex/worktrees/channel-manifest-surfaces/reborn-ironclaw/target cargo test -p ironclaw_reborn_composition local_dev_runtime_injects_default_system_prompt_into_model_request -j1
  • CARGO_TARGET_DIR=/Users/firatsertgoz/.codex/worktrees/channel-manifest-surfaces/reborn-ironclaw/target cargo test -p ironclaw_reborn_composition local_dev_outbound_delivery_capabilities_use_late_registered_targets -j1

Stacked on #4779.

@github-actions github-actions Bot added scope: docs Documentation size: S 10-49 changed lines risk: low Changes to docs, tests, or low-risk modules contributor: core 20+ merged PRs labels Jun 11, 2026

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request updates the system prompts, tool descriptions, tests, and documentation to guide the LLM to discover and select outbound delivery targets before creating triggers or routines. The reviewer noted that the tool description in outbound_delivery.rs incorrectly uses dot notation (builtin.trigger_create) instead of the double underscore convention (builtin__trigger_create) used for model-facing tools, which could confuse the LLM. Consequently, the corresponding test assertion in tests.rs should also be updated to prevent test failures.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +28 to +29
const OUTBOUND_DELIVERY_TARGETS_LIST_DESCRIPTION: &str = "List available outbound delivery targets for final replies and routine/trigger results, such as Slack DMs or Slack channels. When the user asks to send routine or trigger results through Slack or another product/channel, call this before builtin.trigger_create and before saying a delivery product is unavailable or asking the user to reconnect it.";
const OUTBOUND_DELIVERY_TARGET_SET_DESCRIPTION: &str = "Set the current user's final-reply delivery target to an id returned by builtin__outbound_delivery_targets_list. Use after the user asks to send replies or routine/trigger results through that product or channel, and before creating the routine or trigger.";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

high

The description for OUTBOUND_DELIVERY_TARGETS_LIST_DESCRIPTION refers to builtin.trigger_create using dot notation, whereas model-facing tool names in Reborn use double underscores (e.g., builtin__trigger_create), as seen in builtin__outbound_delivery_targets_list in the very next line. Referring to the tool with dot notation can confuse the LLM since it will only see builtin__trigger_create in its tool list. We should update this to builtin__trigger_create.

Suggested change
const OUTBOUND_DELIVERY_TARGETS_LIST_DESCRIPTION: &str = "List available outbound delivery targets for final replies and routine/trigger results, such as Slack DMs or Slack channels. When the user asks to send routine or trigger results through Slack or another product/channel, call this before builtin.trigger_create and before saying a delivery product is unavailable or asking the user to reconnect it.";
const OUTBOUND_DELIVERY_TARGET_SET_DESCRIPTION: &str = "Set the current user's final-reply delivery target to an id returned by builtin__outbound_delivery_targets_list. Use after the user asks to send replies or routine/trigger results through that product or channel, and before creating the routine or trigger.";
const OUTBOUND_DELIVERY_TARGETS_LIST_DESCRIPTION: &str = "List available outbound delivery targets for final replies and routine/trigger results, such as Slack DMs or Slack channels. When the user asks to send routine or trigger results through Slack or another product/channel, call this before builtin__trigger_create and before saying a delivery product is unavailable or asking the user to reconnect it.";
const OUTBOUND_DELIVERY_TARGET_SET_DESCRIPTION: &str = "Set the current user's final-reply delivery target to an id returned by builtin__outbound_delivery_targets_list. Use after the user asks to send replies or routine/trigger results through that product or channel, and before creating the routine or trigger.";
References
  1. Keep tool-specific guidance, such as parameter formats, in both the main system prompt for LLM planning and within the tool's own description (tool_info) to ensure it's exposed directly.

Comment on lines +1197 to +1202
assert!(
list_tool
.description
.contains("before builtin.trigger_create"),
"list tool description should steer delivery requests before trigger creation"
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

high

Since we should update builtin.trigger_create to builtin__trigger_create in the tool description to match the model-facing tool naming convention, this test assertion should be updated accordingly to prevent test failures.

Suggested change
assert!(
list_tool
.description
.contains("before builtin.trigger_create"),
"list tool description should steer delivery requests before trigger creation"
);
assert!(
list_tool
.description
.contains("before builtin__trigger_create"),
"list tool description should steer delivery requests before trigger creation"
);
References
  1. Keep tool-specific guidance, such as parameter formats, in both the main system prompt for LLM planning and within the tool's own description (tool_info) to ensure it's exposed directly.


When a tool result is partial, truncated, failed, or otherwise shows the requested work is unfinished, adapt and continue autonomously. Ask the user only when progress requires external information, approval, or a product decision.

## Delivery Targets

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I don't think we should add any system prompts for this.

@henrypark133 henrypark133 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Code Review (multi-agent)

Intent: Guide routine and trigger creation toward outbound delivery targets via model-visible tool guidance, prompts, docs, and regression coverage.

Stats: 1 finding (from 5 raw, 1 after dedup) across 1 file. Reviewers run: security, bugs, performance, tests, conventions, local-patterns, maintainability, approach. Reviewers failed: none. Body-only: 0.

Bugs

  1. Medium Delivery steering was added to the default system prompt (crates/ironclaw_reborn_composition/assets/prompts/default-system.md:13-16, confidence 75) — anchor: crates/ironclaw_reborn_composition/assets/prompts/default-system.md:13
    The new block moves delivery-target workflow steering into the seeded default system prompt even though this PR already exposes that guidance through tool/schema/runtime surfaces. That broadens the behavior into baseline assistant identity and creates drift risk with the capability-owned descriptions.


When a tool result is partial, truncated, failed, or otherwise shows the requested work is unfinished, adapt and continue autonomously. Ask the user only when progress requires external information, approval, or a product decision.

## Delivery Targets

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Medium — Delivery steering was added to the default system prompt.

This behavior should stay in tool/schema/runtime guidance rather than the seeded default system prompt. The new Delivery Targets block changes the baseline prompt for every new local-dev runtime, while the PR already adds the steering to the trigger schema/manifest and outbound delivery tool descriptions where it is scoped to the visible capability surface.

Fix: Remove this default-system.md section and the test assertion that requires the guidance in the system prompt; keep the guidance in the trigger_create description/schema plus the outbound delivery list/set tool descriptions.

Also flagged by: conventions/Medium, approach/Low, local-patterns/Medium, maintainability/Medium

@henrypark133 henrypark133 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Code Review (multi-agent)

Intent: Guide routine and trigger creation to discover and choose outbound delivery targets before declaring delivery products unavailable.
Stats: 2 findings (from 3 raw, 2 after dedup) across 2 files. Reviewers run: security, bugs, performance, tests, conventions, local-patterns, maintainability, approach. Reviewers failed: none. Body-only: 0

  1. Medium No integration test covers delivery target selection before triggers (crates/ironclaw_reborn_composition/assets/prompts/default-system.md:15-16, confidence 75) — anchor: crates/ironclaw_reborn_composition/assets/prompts/default-system.md:15
    The PR adds model-visible behavior requiring outbound delivery target discovery and selection before creating a routine or trigger, but the added tests only assert prompt/descriptor text and exercise outbound list/set separately. There is no integration or trace test for a user request to send trigger or routine results to Slack that verifies the ordered flow list targets -> set target -> trigger_create. Also flagged by: maintainability/Low.

  2. Low Model-visible description names the non-callable trigger id (crates/ironclaw_reborn_composition/src/runtime/local_dev/outbound_delivery.rs:28-28, confidence 75) — anchor: crates/ironclaw_reborn_composition/assets/prompts/default-system.md:15
    The outbound list tool description tells the model to call this before builtin.trigger_create, but local-dev model-facing instructions use provider tool names with double underscores. In the same PR, the default system prompt names builtin__outbound_delivery_targets_list and builtin__outbound_delivery_target_set; using the dotted capability id here introduces a second name for the model-visible trigger tool and can make the sequencing hint less actionable.


## Delivery Targets

- When visible outbound delivery target tools exist and the user asks to send final replies, routine results, or trigger results through a product or channel such as Slack, call `builtin__outbound_delivery_targets_list` first, then call `builtin__outbound_delivery_target_set` with a returned `target_id` before creating the routine or trigger.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Medium — No integration test covers delivery target selection before triggers.

The PR adds model-visible behavior requiring outbound delivery target discovery and selection before creating a routine or trigger, but the added tests only assert prompt/descriptor text and exercise outbound list/set separately. There is no integration or trace test for a user request to send trigger or routine results to Slack that verifies the ordered flow list targets -> set target -> trigger_create.

Fix: Add a caller-level integration/trace test for a user request to send routine or trigger results to Slack with an available outbound target, asserting outbound target list and set run before trigger_create.

Also flagged by: maintainability/Low

"builtin__outbound_delivery_target_set";
const OUTBOUND_DELIVERY_TARGETS_LIST_DESCRIPTION: &str = "List available outbound delivery targets for final replies and routine/trigger results, such as Slack DMs or Slack channels. Use before saying a delivery product is unavailable or asking the user to reconnect it.";
const OUTBOUND_DELIVERY_TARGET_SET_DESCRIPTION: &str = "Set the current user's final-reply delivery target to an id returned by builtin__outbound_delivery_targets_list. Use only after the user asks to send replies or routine/trigger results through that product or channel.";
const OUTBOUND_DELIVERY_TARGETS_LIST_DESCRIPTION: &str = "List available outbound delivery targets for final replies and routine/trigger results, such as Slack DMs or Slack channels. When the user asks to send routine or trigger results through Slack or another product/channel, call this before builtin.trigger_create and before saying a delivery product is unavailable or asking the user to reconnect it.";

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Low — Model-visible description names the non-callable trigger id.

The outbound list tool description tells the model to call this before builtin.trigger_create, but local-dev model-facing instructions use provider tool names with double underscores. In the same PR, the default system prompt names builtin__outbound_delivery_targets_list and builtin__outbound_delivery_target_set; using the dotted capability id here introduces a second name for the model-visible trigger tool and can make the sequencing hint less actionable.

Fix: Use the provider tool spelling for the model-facing trigger tool, or avoid naming it and match the set-tool wording: before creating the routine or trigger.

@coderabbitai

coderabbitai Bot commented Jun 13, 2026 •

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Summary by CodeRabbit

Release Notes

  • New Features

    • Added guidance so models must discover and select an outbound delivery target before calling builtin.trigger_create.
    • Enabled local-runtime support for outbound-delivery target listing/selection via a mutable target registry.
  • Documentation

    • Clarified the required outbound target discovery/selection → trigger creation sequence.
  • Bug Fixes

    • Improved Slack outbound delivery for long messages with multipart sending and safer retry behavior.
    • Enhanced Slack mrkdwn rendering (including links, lists, and tables) and added stricter outbound-target and prompt/schema validation.
  • Tests

    • Expanded contract and integration tests to enforce the updated tool-call order and guidance.

Walkthrough

Enforces a three-step sequencing contract for outbound delivery before trigger creation via extracted capability surface and updated capability descriptions; introduces thread-safe mutable provider registry with RwLock-backed map; wires registry into runtime with task-level accessors and communication context integration; refactors local-dev to use shared capability surface; Slack host-beta registers providers directly on runtime; webui and connectable-channel validate local-runtime presence; integration tests verify the enforced three-call sequence. Additionally, Slack multi-message rendering is introduced via new mrkdwn module for markdown-to-Slack conversion and long-message chunking paired with dedicated delivery module for HTTP egress and Slack JSON error handling; adapter refactored to dispatch chunked messages while tracking single delivery status.

Changes

Outbound Delivery Target Sequencing Before Trigger Create

Layer / File(s) Summary
Extracted capability surface: types, schemas, and functions
crates/ironclaw_reborn_composition/src/outbound_delivery_capability_surface.rs, crates/ironclaw_reborn_composition/src/lib.rs
Introduces shared module defining capability IDs, tool names, descriptions for list/set operations; adds input structs with target_id() accessor; adds structured error type; implements JSON schema generators rejecting unknown fields; implements parsing functions validating inputs; implements async model-facing functions delegating to OutboundPreferencesProductFacade; includes unit tests for parser validation.
Capability descriptions and contract documentation
crates/ironclaw_host_runtime/src/first_party_tools/schemas.rs, crates/ironclaw_host_runtime/src/first_party_tools/trigger_management.rs, docs/reborn/contracts/triggers.md
Expands trigger_create schema prompt description with outbound delivery routing guidance; extracts TRIGGER_CREATE_DESCRIPTION constant; updates triggers.md contract documenting mandatory target-discovery-before-create sequencing and that trigger records do not embed delivery targets.
Mutable outbound delivery target registry with thread-safe locking
crates/ironclaw_reborn_composition/src/outbound_preferences.rs
Adds BTreeMap/RwLock imports; introduces MutableOutboundDeliveryTargetRegistry storing providers in RwLock<BTreeMap>; implements register_provider with write lock returning Registered/Replaced outcomes; implements OutboundDeliveryTargetProvider by snapshotting under read lock; adds outbound_target_registry_error() helper mapping lock failures to non-retryable HTTP 500.
Runtime field, accessors, and communication context wiring
crates/ironclaw_reborn_composition/src/runtime.rs
Adds outbound_delivery_target_registry field and task-level outbound_delivery_target_provider() reader and register_outbound_delivery_target_provider() mutator to RebornRuntime; instantiates registry for local substrates; constructs RebornOutboundPreferencesFacade combining product facade with registry; threads facade into local-dev wiring and RuntimeCommunicationContextProvider; test cleanup clears registry; registers test module.
Local-dev outbound delivery refactoring to use shared capability surface
crates/ironclaw_reborn_composition/src/runtime/local_dev/outbound_delivery.rs, crates/ironclaw_reborn_composition/src/runtime/local_dev.rs
Updates imports to use outbound_delivery_capability_surface; refactors list handler to parse via shared function and delegate to list_outbound_delivery_targets_for_model; refactors set handler to parse input, update approval flow with parsed target id, and delegate to set_outbound_delivery_target_for_model; adds input_error adapter; updates unit tests for new shared parsing functions; updates test-only re-exports.
Slack host-beta: direct runtime registration instead of embedded field
crates/ironclaw_reborn_composition/src/slack_host_beta.rs
Marks SlackHostBetaMounts #[non_exhaustive] and removes outbound_delivery_target_provider field; adds OutboundDeliveryTargetRegistration error variant; refactors build to register provider directly on runtime, reject replacement attempts; test verifies runtime-accessible provider; adds regression test for replacement rejection.
Webui and connectable-channel validation guards
crates/ironclaw_reborn_composition/src/webui.rs, crates/ironclaw_reborn_composition/src/slack_connectable_channel.rs
Webui adds services.local_runtime.is_some() guard before collecting providers; slack connectable-channel returns InvalidConfig when mounts present but runtime lacks provider.
Integration test: three-step flow with mock gateway
crates/ironclaw_reborn_composition/src/runtime/tests/outbound_delivery.rs
Introduces OutboundDeliveryTriggerGateway enforcing strict list→set→create sequence; StaticOutboundDeliveryTargetProvider fixture; test builds runtime with gateway override and registered Slack provider, sends user message for Slack DM trigger, asserts completion, verifies exactly three persisted ToolResultReference entries with capability IDs in enforced sequence.
Unit and surface tests for capability descriptions
crates/ironclaw_host_runtime/tests/tool_surface_contract.rs, crates/ironclaw_reborn_composition/src/runtime/local_dev/tests.rs
Extends tool-surface test to assert builtin.trigger_create presence and description content; updates local-dev test to validate list and set tool definitions contain "before" ordering guidance.

Slack Multi-Message Rendering and Delivery

Layer / File(s) Summary
Slack mrkdwn module: markdown conversion and text chunking
crates/ironclaw_slack_v2_adapter/src/mrkdwn.rs
Implements render_slack_mrkdwn converting markdown headings/links/bold and pipe-table formats (including issue-table special form) into Slack bullet/list output with table cell/header normalization and issue reference rendering; implements slack_text_chunks to split long text into numbered "Part i/n" chunks respecting soft character limits; includes table parsing, issue-table validation, markdown link conversion with safe-URL filtering, and comprehensive unit tests.
Slack delivery module: HTTP egress and error classification
crates/ironclaw_slack_v2_adapter/src/delivery.rs
Introduces send_slack_post_message async function; validates HTTP 2xx, enforces response-body size limit, parses Slack JSON treating JSON failures as retryable; classifies failures into Retryable/Unauthorized/Permanent using egress error variants, HTTP status codes (including 408 as retryable), and Slack error strings; returns SlackPostMessageDeliveryError with delivery status and adapter error.
Slack render module: multi-message rendering support
crates/ironclaw_slack_v2_adapter/src/render.rs
Adds render_final_reply_messages chunking rendered Slack text into multiple EgressRequests; refactors render_text_message to delegate to render_text_messages helper building one ChatPostMessageRequest per chunk; maintains backward-compatible single-message API.
Slack adapter refactoring: multi-message dispatch and deferred handling
crates/ironclaw_slack_v2_adapter/src/adapter.rs
Refactors render_supported_payload to return RenderedSlackOutbound enum (Deferred or Messages(Vec<EgressRequest>)); updates render_outbound to handle deferred case, iterate message vectors calling send_slack_post_message, record single delivery status, suppress retries after partial delivery; removes inline HTTP/Slack JSON parsing delegating to delivery module; adds tests verifying multipart dispatch and failure handling.
Slack adapter lib.rs: module declarations and exports
crates/ironclaw_slack_v2_adapter/src/lib.rs
Extends crate documentation to include delivery and mrkdwn modules; adds internal module declarations with proper ordering.
Slack delivery driver: triggered-run wait-time defaults
crates/ironclaw_reborn_composition/src/slack_delivery.rs
Adds DEFAULT_TRIGGERED_RUN_DELIVERY_MAX_WAIT constant (30 minutes); updates driver to use explicit constant; includes unit test asserting driver's max_wait exceeds default reply wait.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant LocalDevRuntime
  participant OutboundDeliveryTriggerGateway
  participant ListTargets as list targets
  participant SetTarget as set target
  participant TriggerCreate as trigger_create

  User->>LocalDevRuntime: "create daily Slack DM trigger"
  LocalDevRuntime->>OutboundDeliveryTriggerGateway: stream_model_with_capabilities (call 1)
  OutboundDeliveryTriggerGateway-->>LocalDevRuntime: select list tool call
  LocalDevRuntime->>ListTargets: execute
  ListTargets-->>LocalDevRuntime: tool result 1

  LocalDevRuntime->>OutboundDeliveryTriggerGateway: stream_model_with_capabilities (call 2)
  OutboundDeliveryTriggerGateway-->>LocalDevRuntime: select set tool call
  LocalDevRuntime->>SetTarget: execute
  SetTarget-->>LocalDevRuntime: tool result 2

  LocalDevRuntime->>OutboundDeliveryTriggerGateway: stream_model_with_capabilities (call 3, assert 3 tool results present)
  OutboundDeliveryTriggerGateway-->>LocalDevRuntime: select trigger_create tool call
  LocalDevRuntime->>TriggerCreate: execute
  TriggerCreate-->>LocalDevRuntime: tool result 3
  LocalDevRuntime-->>User: run complete, 3 tool-result refs persisted with enforced capability IDs
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~68 minutes

Possibly related issues

Possibly related PRs

  • nearai/ironclaw#4779: Directly preceding PR introducing model-visible outbound-delivery list/set synthetic capabilities and Slack/connection integration—this PR enforces the sequencing contract and dynamic provider registration on that foundation.

  • nearai/ironclaw#4836: Extends runtime-context to render delivery state and run-origin alongside this PR's outbound-delivery registry + provider wiring into CommunicationContextProvider.

Suggested reviewers

  • henrypark133

Poem

🐇 Three tools in order, now set in stone:
List the targets—no skip, make known.
Set the choice before triggers ignite,
Slack splits big words into chunked-up parts tonight.
Registry locks keep providers thread-true,
Sequencing mandated—the contract shines through! 🔔

🚥 Pre-merge checks | ✅ 3 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive Title is vague/generic, lacking Conventional Commits structure and specific scope identifier required by repo guidelines. Use Conventional Commits format: type(scope): brief summary. Example: 'feat(outbound-delivery): steer trigger creation through target selection'.
✅ Passed checks (3 passed)
Check name Status Explanation
Description check ✅ Passed PR description is substantially complete with summary bullets, test validation, and stacking reference, but omits several required template sections.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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


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

@github-actions github-actions Bot added size: L 200-499 changed lines scope: dependencies Dependency updates and removed size: S 10-49 changed lines labels Jun 13, 2026
@serrrfirat
serrrfirat marked this pull request as ready for review June 15, 2026 08:06
@serrrfirat
serrrfirat force-pushed the codex/channel-manifest-surfaces branch 5 times, most recently from c334a1f to 6b4efab Compare June 15, 2026 11:20
@serrrfirat
serrrfirat force-pushed the codex/channel-manifest-surfaces branch from 6b4efab to 7b2f622 Compare June 15, 2026 11:42
Base automatically changed from codex/channel-manifest-surfaces to main June 15, 2026 13:38
@serrrfirat
serrrfirat force-pushed the codex/outbound-delivery-planner-hint branch from 8eea976 to d3c2fcd Compare June 15, 2026 13:58
@github-actions github-actions Bot added size: XL 500+ changed lines and removed size: L 200-499 changed lines labels Jun 15, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

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

Inline comments:
In `@crates/ironclaw_reborn_composition/src/slack_host_beta.rs`:
- Around line 469-486: The current code accepts replacement of the outbound
delivery target provider without ensuring the delivery hook is also atomically
replaced, which violates the first-writer-wins semantics. Modify the match
statement handling OutboundDeliveryTargetRegistrationOutcome::Replaced to
either: (1) return an error to fail closed on replacement attempts instead of
just logging and continuing, or (2) verify that the existing registration uses
the same Slack config before allowing replacement. This ensures target selection
and triggered delivery remain consistent and preserves the scope of outbound
records as per coding guidelines.
🪄 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 Plus

Run ID: ae8952d9-6489-4ba9-9c23-66e66f24a797

📥 Commits

Reviewing files that changed from the base of the PR and between 16ac998 and 236c08d.

📒 Files selected for processing (4)
  • crates/ironclaw_reborn_composition/src/outbound_preferences.rs
  • crates/ironclaw_reborn_composition/src/runtime.rs
  • crates/ironclaw_reborn_composition/src/runtime/tests/outbound_delivery.rs
  • crates/ironclaw_reborn_composition/src/slack_host_beta.rs

Comment thread crates/ironclaw_reborn_composition/src/slack_host_beta.rs
@github-actions github-actions Bot added size: XL 500+ changed lines and removed size: L 200-499 changed lines labels Jun 15, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

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

Inline comments:
In `@crates/ironclaw_slack_v2_adapter/src/adapter.rs`:
- Around line 190-196: The loop processing multiple requests fails fast
per-part, returning a retryable error if any part fails, even after previous
parts have succeeded. This causes the entire envelope to be eligible for replay,
reposting already-delivered parts and creating duplicates for non-idempotent
sends. Track whether any part has been successfully delivered before the error,
and if so, convert retryable errors from send_slack_post_message into
non-retryable errors rather than propagating them as-is. Apply this same logic
to both occurrences of this pattern (the one shown and the additional location
mentioned in the comment).

In `@crates/ironclaw_slack_v2_adapter/src/delivery.rs`:
- Around line 157-164: The from_http_status function currently classifies HTTP
408 (Request Timeout) as a permanent error in the else branch, but it should be
treated as a retryable transient error. Add 408 to the condition that returns
Self::Retryable alongside the existing checks for status >= 500 and status ==
429, so that timeout errors will be retried instead of being dropped.

In `@crates/ironclaw_slack_v2_adapter/src/mrkdwn.rs`:
- Around line 309-313: The code slices `&str` using character counts and byte
offsets without validation, which violates string safety invariants and can
panic on multi-byte UTF-8 characters. In the strip_heading_marker function, the
hash_count variable (a character count) is used directly as a byte offset in the
slice &trimmed[hash_count..], and in the convert_markdown_links function,
slicing is performed at computed offsets without confirming character
boundaries. Refactor both functions to iterate using char_indices() instead of
maintaining direct byte or character indices, ensuring each slice operation
respects UTF-8 character boundaries.
🪄 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 Plus

Run ID: 60567f66-ced7-4d90-89f2-30b74264ca00

📥 Commits

Reviewing files that changed from the base of the PR and between 236c08d and 77ab6e2.

📒 Files selected for processing (6)
  • crates/ironclaw_reborn_composition/src/slack_delivery.rs
  • crates/ironclaw_slack_v2_adapter/src/adapter.rs
  • crates/ironclaw_slack_v2_adapter/src/delivery.rs
  • crates/ironclaw_slack_v2_adapter/src/lib.rs
  • crates/ironclaw_slack_v2_adapter/src/mrkdwn.rs
  • crates/ironclaw_slack_v2_adapter/src/render.rs

Comment thread crates/ironclaw_slack_v2_adapter/src/adapter.rs
Comment thread crates/ironclaw_slack_v2_adapter/src/delivery.rs
Comment thread crates/ironclaw_slack_v2_adapter/src/mrkdwn.rs Outdated
@serrrfirat
serrrfirat force-pushed the codex/outbound-delivery-planner-hint branch from d36ddb5 to e2e33af Compare June 15, 2026 22:41

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

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

⚠️ Outside diff range comments (1)
crates/ironclaw_reborn_composition/src/runtime.rs (1)

1576-1585: 🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Update the shutdown contract for the trace flush worker.

shutdown() now stops trace_flush_worker, but the doc still only mentions the turn-runner and budget projection.

Suggested doc update
-    /// Stop the turn-runner worker and the budget-event projection.
-    /// Awaits both tasks before returning so background state is fully
-    /// drained when the runtime drops.
+    /// Stop runtime background workers, including the trigger poller, trace
+    /// flush worker, turn-runner, and budget-event projection.
+    /// Awaits shutdown before returning so background state is fully drained
+    /// when the runtime drops.

As per coding guidelines, “When you change behavior in a function, re-read its docstring and adjacent comments — update or delete them in the same change.”

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

In `@crates/ironclaw_reborn_composition/src/runtime.rs` around lines 1576 - 1585,
The docstring for the shutdown method in runtime.rs is outdated and does not
reflect the current implementation. The method now stops the trace_flush_worker
in addition to the turn-runner worker and budget-event projection. Update the
docstring (the documentation comment above the shutdown function) to include the
trace_flush_worker in the list of components that are stopped and awaited during
shutdown, ensuring the documentation accurately describes the behavior of the
implementation.

Source: Coding guidelines

♻️ Duplicate comments (1)
crates/ironclaw_reborn_composition/src/slack_host_beta.rs (1)

469-485: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Reject replacement before mutating the runtime registry.

Replaced is handled as a build error, but the registry operation has already replaced the provider by then. A second build can return Err while leaving runtime target discovery on the new Slack config and the first-writer trigger delivery hook on the old config. Make the registry insert-if-absent/non-mutating on existing keys, or prove same-config idempotency before replacing. Also extend the regression test to assert the runtime provider remains unchanged after the rejected second build.

As per coding guidelines, “Fail closed for auth, approvals, trust, filesystem containment, network policy, secret leases, runtime selection, and adapter identity”; the PR context says the registry inserts/replaces providers before returning Replaced.

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

In `@crates/ironclaw_reborn_composition/src/slack_host_beta.rs` around lines 469 -
485, The register_outbound_delivery_target_provider call mutates the runtime
registry before the OutboundDeliveryTargetRegistrationOutcome::Replaced case is
evaluated and rejected as an error, leaving the registry in an inconsistent
state. Either modify the registry operation to be non-mutating/atomic on
existing keys (check-then-insert semantics), or validate that a provider with
the same configuration already exists and fail before calling
register_outbound_delivery_target_provider with SLACK_V2_ADAPTER_ID.
Additionally, extend the regression test to assert that after a rejected second
build attempt, the runtime provider for SLACK_V2_ADAPTER_ID remains unchanged
from the first build.

Source: Coding guidelines

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

Inline comments:
In `@crates/ironclaw_reborn_composition/src/runtime.rs`:
- Around line 1094-1110: The provider_key parameter in
register_outbound_delivery_target_provider uses impl Into<String>, which allows
string typos to create duplicate registrations instead of triggering replacement
detection. Create a new newtype OutboundDeliveryTargetProviderKey to wrap the
provider identifier and replace the provider_key parameter type from impl
Into<String> to OutboundDeliveryTargetProviderKey. Update the
registry.register_provider call to pass the typed key, and ensure the underlying
registry method accepts this newtype rather than raw strings, following the
coding guideline to use newtypes for identifiers instead of raw String types.

In `@crates/ironclaw_reborn_composition/src/runtime/local_dev.rs`:
- Around line 542-545: The `tracing::warn!` macro call that logs the trajectory
observer on_capability_result panic is using the wrong log level and can corrupt
the REPL/TUI display. Change `tracing::warn!` to `tracing::debug!` for this
internal diagnostic call, keeping the same capability_id field and message
content, to ensure it does not interfere with the terminal UI while still
providing diagnostic information at the appropriate debug level.

---

Outside diff comments:
In `@crates/ironclaw_reborn_composition/src/runtime.rs`:
- Around line 1576-1585: The docstring for the shutdown method in runtime.rs is
outdated and does not reflect the current implementation. The method now stops
the trace_flush_worker in addition to the turn-runner worker and budget-event
projection. Update the docstring (the documentation comment above the shutdown
function) to include the trace_flush_worker in the list of components that are
stopped and awaited during shutdown, ensuring the documentation accurately
describes the behavior of the implementation.

---

Duplicate comments:
In `@crates/ironclaw_reborn_composition/src/slack_host_beta.rs`:
- Around line 469-485: The register_outbound_delivery_target_provider call
mutates the runtime registry before the
OutboundDeliveryTargetRegistrationOutcome::Replaced case is evaluated and
rejected as an error, leaving the registry in an inconsistent state. Either
modify the registry operation to be non-mutating/atomic on existing keys
(check-then-insert semantics), or validate that a provider with the same
configuration already exists and fail before calling
register_outbound_delivery_target_provider with SLACK_V2_ADAPTER_ID.
Additionally, extend the regression test to assert that after a rejected second
build attempt, the runtime provider for SLACK_V2_ADAPTER_ID remains unchanged
from the first build.
🪄 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 Plus

Run ID: 88b769b2-c340-4fa8-b2e1-cd34eb9c4f0f

📥 Commits

Reviewing files that changed from the base of the PR and between d36ddb5 and e2e33af.

📒 Files selected for processing (21)
  • crates/ironclaw_host_runtime/src/first_party_tools/schemas.rs
  • crates/ironclaw_host_runtime/src/first_party_tools/trigger_management.rs
  • crates/ironclaw_host_runtime/tests/tool_surface_contract.rs
  • crates/ironclaw_reborn_composition/src/lib.rs
  • crates/ironclaw_reborn_composition/src/outbound_delivery_capability_surface.rs
  • crates/ironclaw_reborn_composition/src/outbound_preferences.rs
  • crates/ironclaw_reborn_composition/src/runtime.rs
  • crates/ironclaw_reborn_composition/src/runtime/local_dev.rs
  • crates/ironclaw_reborn_composition/src/runtime/local_dev/outbound_delivery.rs
  • crates/ironclaw_reborn_composition/src/runtime/local_dev/tests.rs
  • crates/ironclaw_reborn_composition/src/runtime/tests/outbound_delivery.rs
  • crates/ironclaw_reborn_composition/src/slack_connectable_channel.rs
  • crates/ironclaw_reborn_composition/src/slack_delivery.rs
  • crates/ironclaw_reborn_composition/src/slack_host_beta.rs
  • crates/ironclaw_reborn_composition/src/webui.rs
  • crates/ironclaw_slack_v2_adapter/src/adapter.rs
  • crates/ironclaw_slack_v2_adapter/src/delivery.rs
  • crates/ironclaw_slack_v2_adapter/src/lib.rs
  • crates/ironclaw_slack_v2_adapter/src/mrkdwn.rs
  • crates/ironclaw_slack_v2_adapter/src/render.rs
  • docs/reborn/contracts/triggers.md
💤 Files with no reviewable changes (1)
  • docs/reborn/contracts/triggers.md

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 2

Caution

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

⚠️ Outside diff range comments (1)
crates/ironclaw_reborn_composition/src/runtime.rs (1)

1576-1585: 🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Update the shutdown contract for the trace flush worker.

shutdown() now stops trace_flush_worker, but the doc still only mentions the turn-runner and budget projection.

Suggested doc update
-    /// Stop the turn-runner worker and the budget-event projection.
-    /// Awaits both tasks before returning so background state is fully
-    /// drained when the runtime drops.
+    /// Stop runtime background workers, including the trigger poller, trace
+    /// flush worker, turn-runner, and budget-event projection.
+    /// Awaits shutdown before returning so background state is fully drained
+    /// when the runtime drops.

As per coding guidelines, “When you change behavior in a function, re-read its docstring and adjacent comments — update or delete them in the same change.”

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

In `@crates/ironclaw_reborn_composition/src/runtime.rs` around lines 1576 - 1585,
The docstring for the shutdown method in runtime.rs is outdated and does not
reflect the current implementation. The method now stops the trace_flush_worker
in addition to the turn-runner worker and budget-event projection. Update the
docstring (the documentation comment above the shutdown function) to include the
trace_flush_worker in the list of components that are stopped and awaited during
shutdown, ensuring the documentation accurately describes the behavior of the
implementation.

Source: Coding guidelines

♻️ Duplicate comments (1)
crates/ironclaw_reborn_composition/src/slack_host_beta.rs (1)

469-485: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Reject replacement before mutating the runtime registry.

Replaced is handled as a build error, but the registry operation has already replaced the provider by then. A second build can return Err while leaving runtime target discovery on the new Slack config and the first-writer trigger delivery hook on the old config. Make the registry insert-if-absent/non-mutating on existing keys, or prove same-config idempotency before replacing. Also extend the regression test to assert the runtime provider remains unchanged after the rejected second build.

As per coding guidelines, “Fail closed for auth, approvals, trust, filesystem containment, network policy, secret leases, runtime selection, and adapter identity”; the PR context says the registry inserts/replaces providers before returning Replaced.

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

In `@crates/ironclaw_reborn_composition/src/slack_host_beta.rs` around lines 469 -
485, The register_outbound_delivery_target_provider call mutates the runtime
registry before the OutboundDeliveryTargetRegistrationOutcome::Replaced case is
evaluated and rejected as an error, leaving the registry in an inconsistent
state. Either modify the registry operation to be non-mutating/atomic on
existing keys (check-then-insert semantics), or validate that a provider with
the same configuration already exists and fail before calling
register_outbound_delivery_target_provider with SLACK_V2_ADAPTER_ID.
Additionally, extend the regression test to assert that after a rejected second
build attempt, the runtime provider for SLACK_V2_ADAPTER_ID remains unchanged
from the first build.

Source: Coding guidelines

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

Inline comments:
In `@crates/ironclaw_reborn_composition/src/runtime.rs`:
- Around line 1094-1110: The provider_key parameter in
register_outbound_delivery_target_provider uses impl Into<String>, which allows
string typos to create duplicate registrations instead of triggering replacement
detection. Create a new newtype OutboundDeliveryTargetProviderKey to wrap the
provider identifier and replace the provider_key parameter type from impl
Into<String> to OutboundDeliveryTargetProviderKey. Update the
registry.register_provider call to pass the typed key, and ensure the underlying
registry method accepts this newtype rather than raw strings, following the
coding guideline to use newtypes for identifiers instead of raw String types.

In `@crates/ironclaw_reborn_composition/src/runtime/local_dev.rs`:
- Around line 542-545: The `tracing::warn!` macro call that logs the trajectory
observer on_capability_result panic is using the wrong log level and can corrupt
the REPL/TUI display. Change `tracing::warn!` to `tracing::debug!` for this
internal diagnostic call, keeping the same capability_id field and message
content, to ensure it does not interfere with the terminal UI while still
providing diagnostic information at the appropriate debug level.

---

Outside diff comments:
In `@crates/ironclaw_reborn_composition/src/runtime.rs`:
- Around line 1576-1585: The docstring for the shutdown method in runtime.rs is
outdated and does not reflect the current implementation. The method now stops
the trace_flush_worker in addition to the turn-runner worker and budget-event
projection. Update the docstring (the documentation comment above the shutdown
function) to include the trace_flush_worker in the list of components that are
stopped and awaited during shutdown, ensuring the documentation accurately
describes the behavior of the implementation.

---

Duplicate comments:
In `@crates/ironclaw_reborn_composition/src/slack_host_beta.rs`:
- Around line 469-485: The register_outbound_delivery_target_provider call
mutates the runtime registry before the
OutboundDeliveryTargetRegistrationOutcome::Replaced case is evaluated and
rejected as an error, leaving the registry in an inconsistent state. Either
modify the registry operation to be non-mutating/atomic on existing keys
(check-then-insert semantics), or validate that a provider with the same
configuration already exists and fail before calling
register_outbound_delivery_target_provider with SLACK_V2_ADAPTER_ID.
Additionally, extend the regression test to assert that after a rejected second
build attempt, the runtime provider for SLACK_V2_ADAPTER_ID remains unchanged
from the first build.
🪄 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 Plus

Run ID: 88b769b2-c340-4fa8-b2e1-cd34eb9c4f0f

📥 Commits

Reviewing files that changed from the base of the PR and between d36ddb5 and e2e33af.

📒 Files selected for processing (21)
  • crates/ironclaw_host_runtime/src/first_party_tools/schemas.rs
  • crates/ironclaw_host_runtime/src/first_party_tools/trigger_management.rs
  • crates/ironclaw_host_runtime/tests/tool_surface_contract.rs
  • crates/ironclaw_reborn_composition/src/lib.rs
  • crates/ironclaw_reborn_composition/src/outbound_delivery_capability_surface.rs
  • crates/ironclaw_reborn_composition/src/outbound_preferences.rs
  • crates/ironclaw_reborn_composition/src/runtime.rs
  • crates/ironclaw_reborn_composition/src/runtime/local_dev.rs
  • crates/ironclaw_reborn_composition/src/runtime/local_dev/outbound_delivery.rs
  • crates/ironclaw_reborn_composition/src/runtime/local_dev/tests.rs
  • crates/ironclaw_reborn_composition/src/runtime/tests/outbound_delivery.rs
  • crates/ironclaw_reborn_composition/src/slack_connectable_channel.rs
  • crates/ironclaw_reborn_composition/src/slack_delivery.rs
  • crates/ironclaw_reborn_composition/src/slack_host_beta.rs
  • crates/ironclaw_reborn_composition/src/webui.rs
  • crates/ironclaw_slack_v2_adapter/src/adapter.rs
  • crates/ironclaw_slack_v2_adapter/src/delivery.rs
  • crates/ironclaw_slack_v2_adapter/src/lib.rs
  • crates/ironclaw_slack_v2_adapter/src/mrkdwn.rs
  • crates/ironclaw_slack_v2_adapter/src/render.rs
  • docs/reborn/contracts/triggers.md
💤 Files with no reviewable changes (1)
  • docs/reborn/contracts/triggers.md
🛑 Comments failed to post (2)
crates/ironclaw_reborn_composition/src/runtime.rs (1)

1094-1110: 🛠️ Refactor suggestion | 🟠 Major | 🏗️ Heavy lift

Use a typed provider key at this registration seam.

provider_key: impl Into<String> is the cross-layer identity that drives Registered vs Replaced; a target-id/empty/string typo can register a second provider instead of tripping replacement detection. Introduce/use a validated OutboundDeliveryTargetProviderKey and have the registry/runtime/Slack caller pass that type.

As per coding guidelines, “Use newtypes for identifiers … instead of raw String, &str, or uuid::Uuid.”

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

In `@crates/ironclaw_reborn_composition/src/runtime.rs` around lines 1094 - 1110,
The provider_key parameter in register_outbound_delivery_target_provider uses
impl Into<String>, which allows string typos to create duplicate registrations
instead of triggering replacement detection. Create a new newtype
OutboundDeliveryTargetProviderKey to wrap the provider identifier and replace
the provider_key parameter type from impl Into<String> to
OutboundDeliveryTargetProviderKey. Update the registry.register_provider call to
pass the typed key, and ensure the underlying registry method accepts this
newtype rather than raw strings, following the coding guideline to use newtypes
for identifiers instead of raw String types.

Source: Coding guidelines

crates/ironclaw_reborn_composition/src/runtime/local_dev.rs (1)

542-545: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Use debug! for observer-panic diagnostics.

Line 542 emits an internal diagnostic with tracing::warn!; this can corrupt the REPL/TUI display. Keep capability staging best-effort, but log this at debug!.

Minimal fix
-                tracing::warn!(
+                tracing::debug!(
                     capability_id = capability_id.as_str(),
                     "trajectory observer on_capability_result panicked; dropping event"
                 );

As per coding guidelines, “REPL/TUI logging: info!/warn! corrupt the terminal UI — internal diagnostics use debug!”

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

In `@crates/ironclaw_reborn_composition/src/runtime/local_dev.rs` around lines 542
- 545, The `tracing::warn!` macro call that logs the trajectory observer
on_capability_result panic is using the wrong log level and can corrupt the
REPL/TUI display. Change `tracing::warn!` to `tracing::debug!` for this internal
diagnostic call, keeping the same capability_id field and message content, to
ensure it does not interfere with the terminal UI while still providing
diagnostic information at the appropriate debug level.

Source: Coding guidelines

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

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

⚠️ Outside diff range comments (1)
crates/ironclaw_reborn_composition/src/slack_host_beta.rs (1)

543-607: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Make hook/provider wiring atomic.

set_trigger_post_submit_hook mutates runtime state before provider registration can fail or report Replaced. If registration errors after Line 543, the runtime can be left with the Slack delivery hook wired but no matching runtime outbound-target provider; if Replaced means the registry already swapped the provider, returning Err at Line 604 does not undo the mutation. Use one runtime API that claims the hook and inserts the provider atomically, or make provider registration insert-only with rollback on any later hook conflict. Downstream WebUI target discovery consumes runtime.outbound_delivery_target_provider(), so partial wiring directly drifts the visible target surface. As per coding guidelines, “Fail closed for auth, approvals, trust, filesystem containment, network policy, secret leases, runtime selection, and adapter identity” and “Preserve tenant/user/agent/project/mission/thread scope on authority, state, memory, process, network, outbound, resource, and event records.”

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

In `@crates/ironclaw_reborn_composition/src/slack_host_beta.rs` around lines 543 -
607, The `set_trigger_post_submit_hook(hook)` call at line 543 mutates runtime
state independently from the subsequent
`register_outbound_delivery_target_provider()` call around line 595. If provider
registration fails or reports `Replaced`, the runtime is left in an inconsistent
state with the hook wired but no matching provider. Refactor to make these
operations atomic: either consolidate into a single runtime API that claims the
hook and registers the provider together, or implement rollback logic where if
`register_outbound_delivery_target_provider()` fails or returns
`OutboundDeliveryTargetRegistrationOutcome::Replaced`, undo the hook mutation to
restore consistency. This prevents partial state corruption that would be
visible to downstream consumers like
`runtime.outbound_delivery_target_provider()`.

Source: Coding guidelines

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

Inline comments:
In `@crates/ironclaw_reborn_composition/src/slack_host_beta.rs`:
- Line 37: The runtime state mutations for hook and provider registration must
be atomic to prevent leaving the runtime in an inconsistent state. In the code
block around lines 543–607, the calls to set_trigger_post_submit_hook() and
register_outbound_delivery_target_provider() are currently sequential and can
fail independently. Either wrap both mutations in a single transaction so they
succeed or fail together, or pre-validate that provider registration will
succeed before calling set_trigger_post_submit_hook(). This ensures adapter
identity and outbound delivery state remain synchronized per the runtime wiring
contract, preventing hook-set/provider-missing states that cause permanent build
failures.

---

Outside diff comments:
In `@crates/ironclaw_reborn_composition/src/slack_host_beta.rs`:
- Around line 543-607: The `set_trigger_post_submit_hook(hook)` call at line 543
mutates runtime state independently from the subsequent
`register_outbound_delivery_target_provider()` call around line 595. If provider
registration fails or reports `Replaced`, the runtime is left in an inconsistent
state with the hook wired but no matching provider. Refactor to make these
operations atomic: either consolidate into a single runtime API that claims the
hook and registers the provider together, or implement rollback logic where if
`register_outbound_delivery_target_provider()` fails or returns
`OutboundDeliveryTargetRegistrationOutcome::Replaced`, undo the hook mutation to
restore consistency. This prevents partial state corruption that would be
visible to downstream consumers like
`runtime.outbound_delivery_target_provider()`.
🪄 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 Plus

Run ID: 722af1d2-941d-4d4b-8d3b-51a67b1227f1

📥 Commits

Reviewing files that changed from the base of the PR and between e2e33af and 2877fac.

📒 Files selected for processing (3)
  • crates/ironclaw_reborn_composition/src/outbound_preferences.rs
  • crates/ironclaw_reborn_composition/src/runtime.rs
  • crates/ironclaw_reborn_composition/src/slack_host_beta.rs

WebhookAuth,
};
use secrecy::{ExposeSecret, SecretString};
use sha2::{Digest, Sha256};

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Verify `sha2` is available to production code in this crate.

set -euo pipefail

manifest="$(fd Cargo.toml crates/ironclaw_reborn_composition | head -n 1)"
test -n "$manifest"

echo "Manifest: $manifest"
rg -n -C 3 '^\s*sha2\s*=' "$manifest"

Repository: nearai/ironclaw

Length of output: 750


Hook and provider registration must be atomic.

Lines 543–607 mutate runtime state in two steps: set_trigger_post_submit_hook() succeeds, then register_outbound_delivery_target_provider() can fail or report Replaced. If the second call fails after the hook is set, the runtime is left with a dangling hook and no provider — future builds will see hook-set/provider-missing and fail closed permanently.

Wrap both mutations in a single transaction or pre-validate provider registration before setting the hook. This is a fail-loud/fail-closed invariant: adapter identity and outbound delivery state must not split (CLAUDE.md runtime wiring contract).

Note: sha2 is correctly declared in [dependencies] at line 161 of Cargo.toml; production import is valid.

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

In `@crates/ironclaw_reborn_composition/src/slack_host_beta.rs` at line 37, The
runtime state mutations for hook and provider registration must be atomic to
prevent leaving the runtime in an inconsistent state. In the code block around
lines 543–607, the calls to set_trigger_post_submit_hook() and
register_outbound_delivery_target_provider() are currently sequential and can
fail independently. Either wrap both mutations in a single transaction so they
succeed or fail together, or pre-validate that provider registration will
succeed before calling set_trigger_post_submit_hook(). This ensures adapter
identity and outbound delivery state remain synchronized per the runtime wiring
contract, preventing hook-set/provider-missing states that cause permanent build
failures.

@serrrfirat
serrrfirat merged commit a0e5fe0 into main Jun 15, 2026
67 checks passed
@serrrfirat
serrrfirat deleted the codex/outbound-delivery-planner-hint branch June 15, 2026 23:31
theredspoon pushed a commit to theredspoon/ironclaw that referenced this pull request Jun 21, 2026
* fix(reborn): steer routine delivery through outbound targets

* fix(reborn): address outbound delivery review feedback (nearai#4780)

* fix(reborn): fail loud on outbound target registration (nearai#4780)

* fix(slack): harden outbound delivery rendering

* fix(slack): address outbound delivery review feedback

* fix(slack): allow idempotent host remounts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

contributor: core 20+ merged PRs risk: low Changes to docs, tests, or low-risk modules scope: dependencies Dependency updates scope: docs Documentation size: XL 500+ changed lines

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants