Skip to content

[PRODUCTION CRATE — trait-object seam, zero behavior change] Real gate-dispatch harness convergence + triggered-delivery outcome proof - #5735

Merged
henrypark133 merged 5 commits into
mainfrom
w6-gate-dispatch
Jul 7, 2026
Merged

henrypark133 merged 5 commits into
mainfrom
w6-gate-dispatch

Conversation

@henrypark133

Copy link
Copy Markdown
Collaborator

Summary

Two harness enablers for the gate-dispatch coverage lane.

E1 — turn-state convergence (production crate change). crates/ironclaw_reborn_composition's LocalDevApprovalTurnRunLocator and LocalDevAuthInteractionReadModel hardcoded their turn-run locator to a concrete Arc<LocalDevTurnStateStore> field. tests/integration's RebornIntegrationGroup runs real turns against its own shared.turn_store (built via a separate build_default_planned_runtime composition) — a store those locators had zero visibility into. Driving a real submit_inbound(ApprovalResolution) through the harness's interaction-service test accessors therefore always failed with WorkflowRejected { kind: ScopeNotFound }, even though the approval request was found (the request store is correctly shared; only the turn run state locator was not).

Fix: added runtime/turn_run_snapshot.rs, a small private trait (TurnRunSnapshotSource) abstracting persistence_snapshot() over any turn-state store shape (blanket impl for FilesystemTurnStateStore<F>, one for InMemoryTurnStateStore). Both locators now hold Arc<dyn TurnRunSnapshotSource> instead of the concrete type. build_local_dev_approval_interaction_service / build_webui_auth_interaction_service became thin wrappers over new _with_turn_run_source variants that accept the store explicitly — production callers (build_reborn_runtime) still pass Arc::clone(&local_runtime.turn_state), unchanged behavior, now going through a trait-object cast instead of a concrete type. This also deleted two copies of duplicated #[cfg(...)]-gated snapshot-reading logic (one per locator), collapsing them into the one shared trait.

Two new test-support-gated methods on RebornServices (local_dev_{approval,auth}_interaction_service_with_turn_state_for_test) let a caller supply an alternate store. RebornIntegrationGroup gained an opt-in .with_real_gate_dispatch_services() flag; when set, RebornThreadBuilder::build() wires the harness's real interaction services over the group's own shared.turn_store into the thread's DefaultProductWorkflow — every other group's workflow keeps the default Rejecting*InteractionService stubs, byte-identical to today.

RebornTestIngress gained verified_approval_resolution_envelope/verified_auth_resolution_envelope (built directly — ApprovalResolution/AuthResolution have no wire format in the test adapter's JSON enum). RebornIntegrationHarness gained submit_approval_resolution/submit_auth_resolution, which build an envelope and call self.workflow.submit_inbound(envelope) — the literal dispatch arm a real adapter's "approve"/"deny" reply hits, as opposed to approve_gate/deny_gate's direct TurnCoordinator::resume_turn shortcut.

Proof test: group_approvals/scenario_submit_inbound_approval_resolution.rs (approve + deny arms), driven from a new approvals_group_real_gate_dispatch_e2e test in group_approvals/main.rs. Asserts at a seam beyond wait_for_status(Completed): assert_workspace_file_contains/assert_workspace_file_absent on the real filesystem effect of the (re-)dispatched capability.

Mutation-verified: I temporarily re-pointed the wiring at the pre-fix zero-arg accessors (which read the harness's own disjoint local_runtime.turn_state), re-ran the test, and confirmed it fails with the exact ScopeNotFound from the root-cause investigation, then reverted. Tail:

thread 'approvals_group_real_gate_dispatch_e2e' panicked at .../group.rs:1239:13:
2 scenario(s) failed:
  submit_inbound_approval_resolution_approve: workflow rejected request (ScopeNotFound, status 404): <redacted>
  submit_inbound_approval_resolution_deny: workflow rejected request (ScopeNotFound, status 404): <redacted>

After reverting to the fix, both scenarios pass.

Auth-side (submit_auth_resolution) plumbing is included and symmetric, but is not exercised end-to-end in this PR: driving a real AuthResolution needs a gate backed by a genuine AuthFlowRecord (an OAuth-style flow), which live_approvals's file-tool fixture doesn't raise — that's a materially different fixture than this PR's scope. Flagging as a natural follow-up once a live_auth_and_approval-shaped .with_real_gate_dispatch_services() scenario is written.

E2 decision — triggered-delivery outcome seam.

Per the roadmap's C-TRIGGERED-DELIVERY row, and per the standing instruction that a user-flow coverage gap at int tier is a real signal to close, not wave off: investigated whether a triggered-run Slack-delivery outcome (TriggeredRunDeliveryOutcomeKind) can be made observable at integration tier, today only covered at crate tier (ironclaw_reborn_composition::slack_delivery's #[cfg(test)] module).

Evidence:

  • The observation seam already exists in production, unmodified: build_triggered_run_delivery_hook(&runtime, &config, delivery_store: Arc<dyn TriggeredRunDeliveryStore>) (slack_host_beta.rs:518) takes the delivery store as a public, caller-supplied parameter. TriggeredRunDeliveryStore + public InMemoryTriggeredRunDeliveryStore live in ironclaw_outbound.
  • Crate tier already pins two "cheap" outcomes (Skipped via pending-queue exhaustion, Denied via project scope) by constructing TriggeredRunDeliveryDriver directly (::new) — never through the composition factory a real host binds.
  • tests/integration's RebornIntegrationGroup builds its own build_default_planned_runtime composition, not the RebornRuntime the Slack delivery hook needs (SlackHostBetaRuntimeParts::from_runtime) — the same "two disjoint runtime compositions" shape E1 above fixes for gate dispatch. A sibling test (slack_pairing_actor_resolution.rs) documents this exact gap for a related Slack feature and works around it by driving the real component directly rather than the full group harness.

Verdict: implemented, small and non-duplicate. tests/integration/triggered_delivery_outcome.rs builds a real local-dev RebornRuntime (the same recipe wiring_parity.rs's smoke test already uses), calls the unmodified public build_triggered_run_delivery_hook factory with an injected InMemoryTriggeredRunDeliveryStore, drives a project-scoped TriggerFire through the real PostSubmitDeliveryHook::on_trigger_submitted, and asserts Denied is recorded through the exact store this test supplied — proving the factory construction path over a real RebornRuntime, which crate tier's driver-direct tests do not cover. Needed one new dev-dependency (ironclaw_outbound, for the public in-memory store) and one new [[test]] entry, matching the project's existing one-file-per-concern integration test convention (trace_capture.rs, budget.rs, etc.).

Does not drive a live trigger-poller fire end-to-end (pairing + seeding a due TriggerRecord + polling for the poller to claim it) — that full path is already proven at crate tier (build_slack_host_beta_mounts_wires_trigger_delivery_hook_writes_record) and would require materially more int-tier harness build-out (real Slack egress fakes, poller wiring) for marginal additional value over this PR's factory-construction proof.

Mutation-verified: swapped in a fresh, unconnected InMemoryTriggeredRunDeliveryStore for the read (instead of the one actually injected into the factory) and confirmed the assertion fails to find a record, then reverted.

Quality gates

  • cargo fmt — clean
  • cargo clippy --all --benches --tests --examples --all-features — clean (0 warnings beyond a pre-existing, unrelated net.retries config-key notice)
  • cargo test -p ironclaw_reborn_composition --lib / --test runtime — all pass in isolation; a subset of unrelated pre-existing tests intermittently hit RunTimeout only under heavy parallel load (default cargo test thread-per-test concurrency against 1396+ tests each spinning up a real tokio runtime) — every such test passes cleanly alone or at --test-threads=1/4, confirming this is pre-existing environment flakiness, not a regression from this diff.
  • cargo test --test reborn_group_approvals --test reborn_integration_triggered_delivery_outcome --test reborn_group_extensions --test reborn_group_multiuser --test reborn_group_skills --features integration — all green, repeated runs.
  • Post-implementation thermo-nuclear-code-quality-review pass on the full diff: no structural regressions, no unjustified file growth, opt-in flag/wiring matches established sibling patterns in the same files (budget, trace_capture, tool_disclosure). One optional, non-blocking finding: build_local_dev_approval_interaction_service / build_webui_auth_interaction_service could be deleted entirely in favor of calling their _with_turn_run_source twins directly from build_reborn_runtime's two call sites — left as-is since it's a pure style choice with no behavior or maintainability cost either way.

Closes #5722.

🤖 Generated with Claude Code

…table

Issue #5722: RebornIntegrationGroup's real runs live in a turn-state store
disjoint from the harness's own local-dev composition, so the interaction
services built from local_dev_{approval,auth}_interaction_service_for_test
could never find the group's runs (WorkflowRejected{ScopeNotFound}). Adds
a TurnRunSnapshotSource seam so the turn-run locator can read from a
caller-supplied store instead of always deriving it from
local_runtime.turn_state; production callers are unaffected (same value,
now behind a trait object). Wires this into RebornIntegrationGroup via a
new opt-in with_real_gate_dispatch_services() flag, and adds
submit_approval_resolution/submit_auth_resolution so tests can drive the
literal submit_inbound dispatch arm instead of the harness's direct
TurnCoordinator::resume_turn shortcut.

Also adds an integration-tier proof that build_triggered_run_delivery_hook
assembles a working driver over a real local-dev RebornRuntime and records
outcomes through the caller-supplied TriggeredRunDeliveryStore — the
factory-construction path crate-tier tests don't cover (they construct the
driver directly).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 6, 2026 21:52
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

@ironloopai

ironloopai Bot commented Jul 6, 2026 •

Copy link
Copy Markdown
Contributor

✅ IronLoop Review Status

Head: c6c92c9b5d8f3bfddbc49bf78519a9fd303b27eb
Result: 1/1 reviewers completed without blocking findings.
Next: Ready for normal human review and CI checks.
Updated: 2026-07-07T01:02:39.390Z

Current reviewers:

Reviewer State Verdict Findings Last update
ironloop/common-reviewer (reviewer) Completed Approved 0 blocking findings / 0 notes 2026-07-07T01:02:38.291Z
Reviewer summaries
Reviewer Detail
ironloop/common-reviewer (reviewer) Approved; 0 blocking findings; No concrete blocking issues found in the PR. The changes are scoped to a shared turn-run snapshot abstraction plus test-support seams and integration coverage for real gate-dispat…
Recent activity
Time Reviewer State Detail
2026-07-07T00:59:21.274Z ironloop/common-reviewer (reviewer) Queued Accepted review request for head c6c92c9.
2026-07-07T00:59:21.274Z ironloop/common-reviewer (reviewer) Queued Waiting for this reviewer lane to become available.
2026-07-07T00:59:21.437Z ironloop/common-reviewer (reviewer) Queued Added to the local review work handoff.
2026-07-07T00:59:23.551Z ironloop/common-reviewer (reviewer) Started Reviewer worker started attempt 1.
2026-07-07T00:59:27.315Z ironloop/common-reviewer (reviewer) Workspace ready Prepared isolated checkout (merge_ref) at 16de24d.
2026-07-07T01:02:22.386Z ironloop/common-reviewer (reviewer) Running Codex is reviewing; process live; elapsed 2m 56s; timeout in 17m 4s; last heartbeat 2026-07-07T01:02:22.386Z. Activity (stderr): ...getGateStore>, pub(crate) broadcast_budget_event_sink: Arc, pub(crate) event_log: Arc<dyn ….
2026-07-07T01:02:38.291Z ironloop/common-reviewer (reviewer) Result captured Approved; 0 blocking findings.
2026-07-07T01:02:38.291Z ironloop/common-reviewer (reviewer) Completed Review completed and terminal status was persisted.
Available commands
  • @ironloop agents
  • @ironloop review
  • @ironloop review --agent <agent-id-or-alias>
  • @ironloop status
Run metadata

Admission: webhook accepted the request and IronLoop persisted review state before this projection.

Copilot AI 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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@railway-app
railway-app Bot temporarily deployed to ironclaw-ci-preview / ironclaw-pr-5735 July 6, 2026 21:52 Destroyed
@github-actions github-actions Bot added scope: dependencies Dependency updates size: L 200-499 changed lines risk: medium Business logic, config, or moderate-risk modules contributor: core 20+ merged PRs labels Jul 6, 2026
@coderabbitai

coderabbitai Bot commented Jul 6, 2026 •

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 30d331a8-c703-4d67-ad9f-e6a9519894f7

📥 Commits

Reviewing files that changed from the base of the PR and between 36b8db0 and df2fdc7.

📒 Files selected for processing (1)
  • crates/ironclaw_reborn_composition/src/runtime.rs

📝 Walkthrough

Summary by CodeRabbit

  • New Features
    • Added an option for integration tests to route approval/auth resolutions through production-like interaction services.
    • Expanded integration coverage with new scenarios for submit-inbound approval resolution and triggered-delivery outcome validation.
  • Bug Fixes
    • Improved reliability and consistency when reading turn-state snapshots across different runtime storage backends.
    • Fixed blocked approval processing so approved/denied outcomes correctly complete and update expected workspace results.
  • Tests
    • Added new integration test targets and helper utilities to submit and verify approval/auth resolutions end-to-end.

Walkthrough

Adds a shared turn-run snapshot seam, rewires approval/auth and active-run lookup consumers to use it, extends integration harness plumbing for real gate dispatch, and adds integration coverage for approval resolution and triggered-delivery outcome recording.

Changes

Turn-run snapshot seam and integration dispatch coverage

Layer / File(s) Summary
Turn-run snapshot abstraction
crates/ironclaw_reborn_composition/src/lib.rs, .../turn_run_snapshot.rs
Defines TurnRunSnapshotSource and implements it for filesystem-backed and in-memory turn-state stores.
Interaction services and trigger lookup use injected turn source
crates/ironclaw_reborn_composition/src/runtime.rs, .../runtime/auth_interaction.rs, .../trigger_poller.rs, .../trigger_poller/active_run_lookup.rs
Approval/auth interaction builders and SnapshotActiveRunLookup switch to Arc<dyn TurnRunSnapshotSource> and drop the local trigger snapshot-source abstraction.
Harness stores RebornServices for tests
tests/integration/support/harness/mod.rs, .../harness/profiles/*.rs
HostRuntimeCapabilityHarness retains RebornServices, adds a test accessor, and profile constructors initialize the new field to None.
Real gate-dispatch workflow wiring
tests/integration/support/group.rs, .../group_options.rs
Adds the real-gate-dispatch flag and builder setter, then conditionally wires approval/auth interaction services into DefaultProductWorkflow.
Inbound resolution helpers
tests/integration/support/test_adapter.rs, .../builder.rs
Adds verified approval/auth resolution envelope builders and harness methods that submit them through workflow.submit_inbound.
Real approval-resolution scenario
tests/integration/group_approvals/scenario_submit_inbound_approval_resolution.rs, .../main.rs
Adds the approval-resolution scenario module and the group test that runs approve/deny cases through the real dispatch path.
Triggered-delivery outcome test
Cargo.toml, tests/integration/triggered_delivery_outcome.rs
Registers a new integration test target and adds a test that injects an in-memory delivery store and asserts a denied outcome record.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant DefaultProductWorkflow
  participant ApprovalInteractionService
  participant LocalDevApprovalTurnRunLocator
  participant TurnRunSnapshotSource

  Client->>DefaultProductWorkflow: submit_inbound(ApprovalResolution)
  DefaultProductWorkflow->>ApprovalInteractionService: dispatch resolution
  ApprovalInteractionService->>LocalDevApprovalTurnRunLocator: find active run for gate
  LocalDevApprovalTurnRunLocator->>TurnRunSnapshotSource: turn_run_snapshot()
  TurnRunSnapshotSource-->>LocalDevApprovalTurnRunLocator: TurnPersistenceSnapshot
  LocalDevApprovalTurnRunLocator-->>ApprovalInteractionService: run reference
  ApprovalInteractionService-->>DefaultProductWorkflow: resume/reject
  DefaultProductWorkflow-->>Client: ProductInboundAck
Loading

Possibly related issues

Possibly related PRs

  • nearai/ironclaw#5486: Same-area snapshot acquisition changes in runtime/auth/trigger-poller components, but via feature-gated snapshot selection rather than a shared trait seam.
  • nearai/ironclaw#5654: Related local-dev approval/auth wiring and RebornServices test-support plumbing in the composition crate.

Suggested reviewers: ilblackdragon, think-in-universe

🚥 Pre-merge checks | ✅ 2 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description omits most required template sections, including Change Type, Validation, Security Impact, Blast Radius, Rollback Plan, and Review track. Fill in the repository template sections and add the missing checklist items, especially Validation, Security Impact, Blast Radius, Rollback Plan, and Review track.
Out of Scope Changes check ⚠️ Warning The triggered-delivery outcome proof, new test target, and related harness plumbing are not covered by #5722 and are additional scope in this PR. Move the triggered-delivery outcome work to a separate PR or link the matching issue, and keep this PR focused on the gate-dispatch seam.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title is clearly related to the main changes, covering real gate dispatch and triggered-delivery proof, though it is not Conventional Commits style.
Linked Issues check ✅ Passed The turn-state seam, test-support injection, and real submit_inbound gate-dispatch wiring address #5722 and remove the direct resume_turn bypass without changing production behavior.

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

❤️ Share

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

@ironloopai ironloopai 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.

✅ IronLoop Review: reviewer

Verdict: ✅ Approved
Findings: 0 blocking / 0 notes
Next: No reviewer action needed.
Head: 6b55d78360b52b223ccf11e9dae31f23d89cfc20

Run details

Status: Current
Needs human: no
Needs validation: no

**Inline candidates:** 0

Summary

No concrete correctness, security, or test-coverage issues found in the reviewed diff. The change adds test-support seams for gate-resolution integration coverage and new integration tests without changing production wiring paths beyond the trait abstraction wrappers.

Findings

None.

Developer follow-up

After fixing this feedback:

  1. Push the fix to this PR branch.
  2. Re-run this reviewer with @ironloop review --agent reviewer if you only changed this reviewer's findings.
  3. Re-run all reviewers with @ironloop review when the fix may affect multiple areas.
  4. Use @ironloop status to check queued/running/completed/stale/stalled state while reviewers run.

@ironloopai ironloopai 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.

✅ IronLoop Review: reviewer

Verdict: ✅ Approved
Findings: 0 blocking / 0 notes
Next: No reviewer action needed.
Head: 6b55d78360b52b223ccf11e9dae31f23d89cfc20

Run details

Status: Current
Needs human: no
Needs validation: no

**Inline candidates:** 0

Summary

No concrete correctness, security, or test-coverage issues found in the reviewed diff. The change adds test-support seams for gate-resolution integration coverage and new integration tests without changing production wiring paths beyond the trait abstraction wrappers.

Findings

None.

Developer follow-up

After fixing this feedback:

  1. Push the fix to this PR branch.
  2. Re-run this reviewer with @ironloop review --agent reviewer if you only changed this reviewer's findings.
  3. Re-run all reviewers with @ironloop review when the fix may affect multiple areas.
  4. Use @ironloop status to check queued/running/completed/stale/stalled state while reviewers run.

@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

🤖 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 `@tests/integration/support/builder.rs`:
- Around line 744-762: `submit_auth_resolution` is still taking a raw `&str` for
the auth request reference even though the auth-flow already works with
`GateRef`; update the `submit_auth_resolution` method signature in `builder.rs`
to accept `&GateRef` and pass that through directly from
`submit_turn_until_auth_blocked`. Keep the string conversion only at the
`verified_auth_resolution_envelope` boundary, and adjust any call sites in this
harness to pass the `GateRef` value instead of a string.

In `@tests/integration/support/test_adapter.rs`:
- Around line 326-381: The two envelope builders duplicate the same
`ProtocolAuthEvidence::test_verified` and
`TrustedInboundContext::from_verified_evidence` setup; extract that shared
construction into a private helper near `verified_approval_resolution_envelope`
and `verified_auth_resolution_envelope` that returns the trusted envelope from a
provided payload. Then have both public methods only build their specific
`ProductInboundPayload` variant (`ApprovalResolution` vs `AuthResolution`) and
delegate to the helper.
🪄 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: cc83f3bc-57fe-460a-b638-122c09f63ad9

📥 Commits

Reviewing files that changed from the base of the PR and between ca88418 and 6b55d78.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock, !**/Cargo.lock
📒 Files selected for processing (18)
  • Cargo.toml
  • crates/ironclaw_reborn_composition/src/runtime.rs
  • crates/ironclaw_reborn_composition/src/runtime/auth_interaction.rs
  • crates/ironclaw_reborn_composition/src/runtime/test_support.rs
  • crates/ironclaw_reborn_composition/src/runtime/turn_run_snapshot.rs
  • tests/integration/group_approvals/main.rs
  • tests/integration/group_approvals/scenario_submit_inbound_approval_resolution.rs
  • tests/integration/support/builder.rs
  • tests/integration/support/group.rs
  • tests/integration/support/group_options.rs
  • tests/integration/support/harness/mod.rs
  • tests/integration/support/harness/profiles/core_builtin.rs
  • tests/integration/support/harness/profiles/github.rs
  • tests/integration/support/harness/profiles/mock_mcp.rs
  • tests/integration/support/harness/profiles/qa_smoke.rs
  • tests/integration/support/harness/profiles/web_access.rs
  • tests/integration/support/test_adapter.rs
  • tests/integration/triggered_delivery_outcome.rs

Comment thread tests/integration/support/builder.rs
Comment thread tests/integration/support/test_adapter.rs Outdated
@railway-app

railway-app Bot commented Jul 6, 2026 •

Copy link
Copy Markdown

🚅 Deployed to the ironclaw-pr-5735 environment in ironclaw-ci-preview

Service Status Web Updated (UTC)
ironclaw ✅ Success (View Logs) Web Jul 7, 2026 at 1:08 am

@henrypark133 henrypark133 left a comment

Copy link
Copy Markdown
Collaborator Author

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: Add harness enablers for gate-dispatch coverage while preserving production behavior, plus a triggered-delivery outcome integration proof.

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

Tests

  1. Medium Auth gate-dispatch seam lacks caller-level coverage (tests/integration/support/group.rs:1159-1169, confidence 100) - anchor: AGENTS.md:101
    The opt-in workflow now wires both the approval and auth interaction services, and the PR adds submit_auth_resolution plus the verified AuthResolution envelope builder. The approval submit_inbound path has a real scenario, but the auth side is explicitly left unexercised, so a regression where AuthResolution cannot find the auth gate through LocalDevAuthInteractionReadModel would still pass.

Maintainability

  1. Medium Collapse the duplicate turn-snapshot source traits (crates/ironclaw_reborn_composition/src/runtime/turn_run_snapshot.rs:23-24, confidence 75) - anchor: crates/ironclaw_reborn_composition/src/trigger_poller/active_run_lookup.rs:113
    This adds TurnRunSnapshotSource for the approval/auth locators even though trigger_poller already has TriggerTurnSnapshotSource over the same TurnPersistenceSnapshot operation. Keeping two private traits plus two store impl sets means future store-shape or snapshot error changes must be mirrored in both places.

Local Patterns

  1. Low Module doc now misdescribes the approval scenarios (tests/integration/group_approvals/main.rs:99-105, confidence 75) - anchor: tests/integration/group_approvals/main.rs:99
    The file-level comment still says one sequential test drives every real-gate scenario through approve_gate/deny_gate, with only failure_category_demasked as an exception. This PR adds a second real_gate_dispatch test whose point is resolving through submit_inbound(ApprovalResolution), so the navigation docs now describe the file incorrectly.

.ok_or(
"local-dev approval interaction service unavailable (harness has no local runtime)",
)?;
let auth_interaction_service = reborn_services

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Medium - Auth gate-dispatch seam lacks caller-level coverage.

The opt-in workflow now wires both the approval and auth interaction services, and the PR adds submit_auth_resolution plus the verified AuthResolution envelope builder. The approval submit_inbound path has a real scenario, but the auth side is explicitly left unexercised, so a regression where AuthResolution cannot find the auth gate through LocalDevAuthInteractionReadModel would still pass.

Fix: Add a live_auth_and_approval-style integration scenario built with with_real_gate_dispatch_services that drives RebornIntegrationHarness::submit_auth_resolution through DefaultProductWorkflow, or leave the auth helper/wiring out until that fixture lands.

Also flagged by: conventions/Medium, maintainability/Low

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Confirmed and tracked in #5744: manual-token auth gates never create an AuthFlowRecord, so submit_inbound(AuthResolution) is structurally unreachable against every int-tier harness profile today (only OAuth-gated capabilities create one). Deferring the real-dispatch auth arm to #5744's OAuth-gated-capability profile enabler rather than building a scenario that fails for the wrong reason.

use ironclaw_turns::{TurnError, TurnPersistenceSnapshot};

#[async_trait]
pub(crate) trait TurnRunSnapshotSource: Send + Sync {

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Medium - Collapse the duplicate turn-snapshot source traits.

This adds TurnRunSnapshotSource for the approval/auth locators even though trigger_poller already has TriggerTurnSnapshotSource over the same TurnPersistenceSnapshot operation. Keeping two private traits plus two store impl sets means future store-shape or snapshot error changes must be mirrored in both places.

Fix: Move one generic turn snapshot source abstraction to a shared composition module and have trigger poller, approval, and auth call it, mapping domain-specific errors at their boundaries.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Collapsed: moved TurnRunSnapshotSource to a crate-root turn_run_snapshot module (sibling of runtime/trigger_poller, not nested under runtime) and switched trigger_poller's SnapshotActiveRunLookup to consume it directly, mapping TurnError -> TriggerError at its own boundary the same way the approval/auth locators already map to ProductWorkflowError. This also deleted the now-unnecessary LocalTriggerTurnSnapshotSource<S> wrapper struct and its two feature-gated blanket impls entirely — confirmed the cfg-gating on those was incidental copy-drift, not load-bearing (FilesystemTurnStateStore/InMemoryTurnStateStore are defined unconditionally in ironclaw_turns, same as this trait's own unconditional impls already proved). Net: one duplicate trait + one duplicate blanket-impl pair + one wrapper struct removed, single crate, all 6 trigger_poller unit tests plus the full composition-crate suite (908 tests) still pass.

report.assert_all_passed();
}

/// Proof-of-seam group — the harness mid-stack bypass that resolved

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Low - Module doc now misdescribes the approval scenarios.

The file-level comment still says one sequential test drives every real-gate scenario through approve_gate/deny_gate, with only failure_category_demasked as an exception. This PR adds a second real_gate_dispatch test whose point is resolving through submit_inbound(ApprovalResolution), so the navigation docs now describe the file incorrectly.

Fix: Update the module doc to scope the approve_gate/deny_gate description to approvals_group_e2e/libSQL and mention approvals_group_real_gate_dispatch_e2e as the submit_inbound proof.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Fixed — module doc now scopes the approve_gate/deny_gate description to approvals_group_e2e and documents approvals_group_real_gate_dispatch_e2e as the separate submit_inbound proof.

@railway-app
railway-app Bot temporarily deployed to ironclaw-ci-preview / ironclaw-pr-5735 July 6, 2026 23:10 Destroyed
@ironloopai

ironloopai Bot commented Jul 6, 2026 •

Copy link
Copy Markdown
Contributor

🗂️ Archived IronLoop Review: reviewer

This result is from an older PR head and is no longer the active review.

Field Value
Status Superseded
Verdict ✅ Approved
Findings 0 blocking / 0 notes
Reviewed head df2fdc7db719
Archived summary

No concrete blocking issues found in the reviewed diff. The production changes are narrowly scoped to sharing a turn-run snapshot abstraction across approval/auth interaction lookup and trigger active-run lookup, with added integration coverage for submit_inbound gate resolution and triggered delivery hook factory wiring.

@ironloopai ironloopai 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.

✅ IronLoop Review: reviewer

Verdict: ✅ Approved
Findings: 0 blocking / 0 notes
Next: No reviewer action needed.
Head: af256fb08b2175562309d14a33d5a3899d425a4b

Run details

Status: Current
Needs human: no
Needs validation: no

**Inline candidates:** 0

Summary

No concrete correctness, security, maintainability, or test-coverage issues found in the reviewed diff. The changes are scoped to test-support seams and integration coverage, with production behavior preserved through wrapper paths.

Findings

None.

Developer follow-up

After fixing this feedback:

  1. Push the fix to this PR branch.
  2. Re-run this reviewer with @ironloop review --agent reviewer if you only changed this reviewer's findings.
  3. Re-run all reviewers with @ironloop review when the fix may affect multiple areas.
  4. Use @ironloop status to check queued/running/completed/stale/stalled state while reviewers run.

@github-actions

github-actions Bot commented Jul 6, 2026 •

Copy link
Copy Markdown
Contributor

Coverage ratchet

Ratchet mode: ENFORCING

RATCHET PASS: global
  observed: 85.34% (273355 / 320308 lines)
  floor:    85.3% (tolerance 0.5pp -> effective floor 84.8%)
  denominator: 320308 lines now vs 320188 at floor capture (+120 lines, +0.04%) — not a material change

⚠️ 3 Reborn crate(s) have 0 int-tier coverage (target: 0) — ironclaw_prompt_envelope, ironclaw_scripts, ironclaw_skill_learning

Reborn integration-tier coverage

Line coverage (Reborn crates): 85.34% — 273355 / 320308 lines

Per-crate breakdown (65 crates, lowest-covered first)
Crate Line % Covered / Total
ironclaw_prompt_envelope 0% 0 / 88
ironclaw_scripts 0% 0 / 347
ironclaw_skill_learning 0% 0 / 61
ironclaw_wasm_sandbox_core 7.37% 7 / 95
ironclaw_runtime_policy 33.2% 80 / 241
ironclaw_event_projections 43.34% 673 / 1553
ironclaw_run_state 52.73% 222 / 421
ironclaw_authorization 53.54% 461 / 861
ironclaw_triggers 60.32% 1736 / 2878
ironclaw_observability 61.54% 16 / 26
ironclaw_reborn_cli 64.58% 3988 / 6175
ironclaw_webui_v2 65.47% 2391 / 3652
ironclaw_filesystem 65.86% 3212 / 4877
ironclaw_reborn_migration 67.01% 1172 / 1749
ironclaw_memory 67.12% 747 / 1113
ironclaw_dispatcher 67.15% 92 / 137
ironclaw_mcp 67.42% 569 / 844
ironclaw_trust 72.88% 661 / 907
ironclaw_reborn_event_store 73.27% 940 / 1283
ironclaw_capabilities 74.08% 1658 / 2238
ironclaw_wasm_limiter 74.6% 47 / 63
ironclaw_extractors 74.72% 538 / 720
ironclaw_first_party_extensions 77.62% 5410 / 6970
ironclaw_llm 77.67% 19044 / 24519
ironclaw_product_context 78.57% 11 / 14
ironclaw_network 79.82% 621 / 778
ironclaw_wasm_product_adapters 80.58% 1510 / 1874
ironclaw_process_sandbox 80.65% 671 / 832
ironclaw_reborn_openai_compat 80.95% 956 / 1181
ironclaw_memory_native 81.86% 3226 / 3941
ironclaw_secrets 82.33% 2716 / 3299
ironclaw_wasm 82.54% 950 / 1151
ironclaw_events 83.44% 1759 / 2108
ironclaw_processes 84.06% 965 / 1148
ironclaw_host_api 84.5% 3119 / 3691
ironclaw_threads 84.9% 3251 / 3829
ironclaw_turns 85.63% 9819 / 11467
ironclaw_projects 85.92% 659 / 767
ironclaw_product_workflow 86.3% 10662 / 12354
ironclaw_auth 86.32% 2727 / 3159
ironclaw_common 86.59% 1472 / 1700
ironclaw_slack_v2_adapter 86.79% 1806 / 2081
ironclaw_reborn_config 86.98% 1730 / 1989
ironclaw_product_adapters 87.16% 3170 / 3637
ironclaw_hooks 87.25% 9782 / 11211
ironclaw_reborn_traces 87.35% 10325 / 11820
ironclaw_skills 87.36% 4335 / 4962
ironclaw_product_adapter_registry 87.96% 526 / 598
ironclaw_extensions 88.26% 2631 / 2981
ironclaw_reborn_identity 88.43% 344 / 389
ironclaw_reborn_composition 89.04% 68524 / 76961
ironclaw_host_runtime 89.12% 17249 / 19355
ironclaw_conversations 90.11% 2924 / 3245
ironclaw_approvals 90.51% 1507 / 1665
ironclaw_reborn 91.17% 17238 / 18908
ironclaw_event_streams 91.48% 1009 / 1103
ironclaw_reborn_webui_ingress 91.68% 2094 / 2284
ironclaw_loop_support 92.34% 14093 / 15262
ironclaw_attachments 93.06% 630 / 677
ironclaw_telegram_v2_adapter 94.01% 2447 / 2603
ironclaw_resources 94.25% 3625 / 3846
ironclaw_agent_loop 94.49% 8290 / 8773
ironclaw_safety 94.78% 3668 / 3870
ironclaw_first_party_extension_ports 95% 3094 / 3257
ironclaw_outbound 95.59% 3556 / 3720

This table itself is informational and never gates the PR on its own — not the percentage, not the per-crate holes, not the 0-coverage callout. A separate coverage ratchet (dry-run until enforce=true; see tests/integration/coverage-floor.toml) can fail the build on specific configured floors.

Exemptions (4 entry/entries excluded from the accounting above)
Module / Crate Reason Issue
crate: ironclaw_embeddings v1-only: consumed only by root ironclaw (src/app.rs, src/tools/builtin/memory.rs, src/workspace/mod.rs, src/config/{mod,embeddings}.rs); no crates/* dependents. Covered by "Tests (Legacy)". #5657
crate: ironclaw_gateway v1-only: consumed only by root ironclaw (src/channels/web/platform/static_files.rs, src/channels/web/handlers/frontend.rs); no crates/* dependents. Covered by "Tests (Legacy)". #5657
crate: ironclaw_oauth v1-only: consumed only by root ironclaw (src/auth/oauth.rs); no crates/* dependents. Crate's own doc comment confirms v1-only. Covered by "Tests (Legacy)". #5657
crate: ironclaw_tui v1-only: consumed only by root ironclaw (src/main.rs, src/channels/tui.rs); no crates/* dependents. Crate's own doc comment confirms it bridges INTO v1, not Reborn. Covered by "Tests (Legacy)". #5657

- Collapse TurnRunSnapshotSource/TriggerTurnSnapshotSource into one
  shared trait at crate-root turn_run_snapshot module; trigger_poller's
  SnapshotActiveRunLookup now maps TurnError -> TriggerError at its own
  boundary instead of duplicating the trait + blanket impls + a wrapper
  struct that turned out unnecessary once both consumers share the type.
- submit_auth_resolution now takes &GateRef (matching
  submit_approval_resolution), converting to &str only at the envelope
  boundary.
- Extract a shared verified_resolution_envelope helper for the
  approval/auth submit_inbound envelope builders.
- Fix group_approvals module doc to describe both tests now present.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 6, 2026 23:58
@railway-app
railway-app Bot temporarily deployed to ironclaw-ci-preview / ironclaw-pr-5735 July 6, 2026 23:58 Destroyed

Copilot AI 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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@ironloopai ironloopai 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.

✅ IronLoop Review: reviewer

Verdict: ✅ Approved
Findings: 0 blocking / 0 notes
Next: No reviewer action needed.
Head: 36b8db02d03e14c5cc3433c280bb0fe47a50c945

Run details

Status: Current
Needs human: no
Needs validation: no

**Inline candidates:** 0

Summary

No concrete blocking issues found in the PR diff. The changes keep production wiring behavior scoped while adding test-support seams and integration coverage for real gate-resolution and triggered-delivery factory paths.

Findings

None.

Developer follow-up

After fixing this feedback:

  1. Push the fix to this PR branch.
  2. Re-run this reviewer with @ironloop review --agent reviewer if you only changed this reviewer's findings.
  3. Re-run all reviewers with @ironloop review when the fix may affect multiple areas.
  4. Use @ironloop status to check queued/running/completed/stale/stalled state while reviewers run.

@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/trigger_poller/active_run_lookup.rs (1)

46-59: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Batch path double-wraps the snapshot error.

trigger_backend_error(error) already yields a TriggerError::Backend; .to_string() on it then feeds that rendered backend string back into another TriggerError::Backend, so the reason carries the backend prefix twice. The single-item path (Line 34) wraps once via .map_err(trigger_backend_error)?. Use the raw error string here so both paths produce identical reasons.

The reason.contains("snapshot failed") assertion at Line 376 still passes, which is why this divergence isn't caught.

🐛 Wrap once
-                let reason = trigger_backend_error(error).to_string();
+                let reason = error.to_string();
🤖 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/trigger_poller/active_run_lookup.rs`
around lines 46 - 59, The batch error handling in
active_run_lookup::lookup_snapshot is double-wrapping the snapshot failure by
calling trigger_backend_error(error).to_string() and then embedding that
rendered backend message inside another TriggerError::Backend. Update the
Err(error) branch to use the raw snapshot error text directly, matching the
single-item path that uses .map_err(trigger_backend_error) so both paths produce
the same reason string.
🤖 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`:
- Line 117: The `TurnRunSnapshotSource` re-export in `runtime.rs` is
unnecessarily public within the crate and creates an extra import path with no
callers. Change the `pub(crate) use` for `TurnRunSnapshotSource` to a private
`use` in `runtime.rs`, keeping the symbol available internally while removing
the unused re-export path.

---

Outside diff comments:
In `@crates/ironclaw_reborn_composition/src/trigger_poller/active_run_lookup.rs`:
- Around line 46-59: The batch error handling in
active_run_lookup::lookup_snapshot is double-wrapping the snapshot failure by
calling trigger_backend_error(error).to_string() and then embedding that
rendered backend message inside another TriggerError::Backend. Update the
Err(error) branch to use the raw snapshot error text directly, matching the
single-item path that uses .map_err(trigger_backend_error) so both paths produce
the same reason string.
🪄 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: 8b82956b-c8cc-48c8-986d-fc746e11d8ac

📥 Commits

Reviewing files that changed from the base of the PR and between af256fb and 36b8db0.

📒 Files selected for processing (9)
  • crates/ironclaw_reborn_composition/src/lib.rs
  • crates/ironclaw_reborn_composition/src/runtime.rs
  • crates/ironclaw_reborn_composition/src/runtime/auth_interaction.rs
  • crates/ironclaw_reborn_composition/src/trigger_poller.rs
  • crates/ironclaw_reborn_composition/src/trigger_poller/active_run_lookup.rs
  • crates/ironclaw_reborn_composition/src/turn_run_snapshot.rs
  • tests/integration/group_approvals/main.rs
  • tests/integration/support/builder.rs
  • tests/integration/support/test_adapter.rs

Comment thread crates/ironclaw_reborn_composition/src/runtime.rs Outdated
No in-crate consumer imports it via the runtime module path; all of
them (trigger_poller, auth_interaction, test_support via super::*)
resolve it through crate::turn_run_snapshot directly.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@railway-app
railway-app Bot temporarily deployed to ironclaw-ci-preview / ironclaw-pr-5735 July 7, 2026 00:12 Destroyed

@ironloopai ironloopai 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.

✅ IronLoop Review: reviewer

Verdict: ✅ Approved
Findings: 0 blocking / 0 notes
Next: No reviewer action needed.
Head: df2fdc7db71911f9229d2ffa0155bf2db2c7772f

Run details

Status: Current
Needs human: no
Needs validation: no

**Inline candidates:** 0

Summary

No concrete blocking issues found in the reviewed diff. The production changes are narrowly scoped to sharing a turn-run snapshot abstraction across approval/auth interaction lookup and trigger active-run lookup, with added integration coverage for submit_inbound gate resolution and triggered delivery hook factory wiring.

Findings

None.

Developer follow-up

After fixing this feedback:

  1. Push the fix to this PR branch.
  2. Re-run this reviewer with @ironloop review --agent reviewer if you only changed this reviewer's findings.
  3. Re-run all reviewers with @ironloop review when the fix may affect multiple areas.
  4. Use @ironloop status to check queued/running/completed/stale/stalled state while reviewers run.

Copilot AI review requested due to automatic review settings July 7, 2026 00:59
@railway-app
railway-app Bot temporarily deployed to ironclaw-ci-preview / ironclaw-pr-5735 July 7, 2026 00:59 Destroyed

Copilot AI 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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@ironloopai ironloopai 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.

✅ IronLoop Review: reviewer

Verdict: ✅ Approved
Findings: 0 blocking / 0 notes
Next: No reviewer action needed.
Head: c6c92c9b5d8f3bfddbc49bf78519a9fd303b27eb

Run details

Status: Current
Needs human: no
Needs validation: no

**Inline candidates:** 0

Summary

No concrete blocking issues found in the PR. The changes are scoped to a shared turn-run snapshot abstraction plus test-support seams and integration coverage for real gate-dispatch and triggered-delivery outcome wiring.

Findings

None.

Developer follow-up

After fixing this feedback:

  1. Push the fix to this PR branch.
  2. Re-run this reviewer with @ironloop review --agent reviewer if you only changed this reviewer's findings.
  3. Re-run all reviewers with @ironloop review when the fix may affect multiple areas.
  4. Use @ironloop status to check queued/running/completed/stale/stalled state while reviewers run.

This branch was successfully deployed

No deployments
ironclaw-ci-preview / ironclaw-pr-5735 — c6c92c9b Deployed Jul 7, 2026 by railway-app[bot]
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: medium Business logic, config, or moderate-risk modules scope: dependencies Dependency updates size: L 200-499 changed lines

Projects

None yet

2 participants