refactor(contracts): extract ironclaw_extension_contracts and close the dual import paths (WS1.3) - #6977
Conversation
…ire the turns shims (WS1.1) `ironclaw_host_api::turn` becomes the complete canonical turn vocabulary: it absorbs `TurnStatus` (with the inseparable `GateKind`/`BlockedReason` gate correspondence), `EventCursor`, and `RunOriginAdapter`. The three `ironclaw_turns` re-export shims named by CHECKLIST WS1.1 are deleted — `src/ids.rs`, `src/scope.rs`, and the whole `src/product_adapter/` module, whose `fakes.rs` moves beside the traits it implements in `host_api::product_adapter::test_support`. `ids.rs` carried `pub type GateRef = TurnGateRef`: a second name for a host_api type that collided with the unrelated `ironclaw_host_api::ids::GateRef` (an opaque uuid GateRecord key, versus turns' bounded `gate:`-prefixed routing string). The alias is retired rather than relocated, so the workspace now has exactly one `GateRef`. The six vocabulary-only consumers — auth, event_streams, outbound, telegram_extension, triggers, event_projections — import from `ironclaw_host_api::turn` and drop their `ironclaw_turns` dependency entirely. Five `*→turns` LAYER_MATRIX_EXCEPTIONS are therefore not waived but obsolete: the edges no longer exist. The §11.2.2 ratchet baseline moves 20 → 15. No behavior change. `RunOriginAdapter`'s validation error becomes `Result<_, String>` (matching every other bounded ref in `host_api::turn`) with a byte-identical message pinned by a test, so both production `e.to_string()` call sites are unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
WS1.1's box is ticked with what the change actually landed, including the three lead-sheet corrections it turned up: the row named `TurnStatus` but not `EventCursor`/`RunOriginAdapter` (which the six consumers genuinely needed), `GateKind`/`BlockedReason` could not be left behind without duplicating the single `GateKind -> TurnStatus` match table, and deleting `ids.rs` forced retiring its `GateRef` alias rather than relocating it. Two decisions confirmed outside the doc and never recorded: - Strategy B (family dirs + focused crates) — confirmed 2026-07-31 by the owner, recorded retroactively; it was made in practice at program start. - The `tools/` row's `default-members` trim — resolved as no trim. Also surfaces #6963 on the WS0 blocking-prerequisite row's first line (it was already cited mid-paragraph) and records the §11.2.2 exception ratchet moving 20 -> 15. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…TurnGateRef contract CodeRabbit review round on #6967. Import repoints (accepted): every `use` line this PR already rewrote now names `ironclaw_host_api::turn` directly instead of routing through `ironclaw_turns`' prelude — 57 files across extension_host, product, composition, runner, loop_host, conversations, the integration harness, and the stress tool, plus three inside `ironclaw_turns` itself so the crate stops consuming its own facade. Import lines this PR did not touch are left for their consumer's own repoint slot. TurnGateRef contract pinned (refutation): two review comments claimed `TurnGateRef::new` only accepts `gate:approval-`/`gate:auth-` prefixes and that fixtures like "gate-alpha" and "stress-gate:{run_id}" fail construction. They do not — `TurnGateRef` is `bounded_ref!` (non-empty, <= 256 bytes, no control characters); `LoopGateRef` is the prefix- validated family via `loop_ref!(.., "gate:")`. The misreading traces to this PR's own AGENTS.md wording ("bounded `gate:`-prefixed routing string"), which stated a minting convention as if it were validation. That wording is corrected and the distinction is now pinned by a test. Also: drop a stale cross-file line reference in a product test comment. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The `tools/` row resolved the `default-members` trim as "no trim" but kept a trailing "The `tools/`/`default-members` half is still open." from before that decision, so the row asserted both states. Drop the stale sentence. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Finishes the remediation deferred last round, now that the settled run (job 91246493989) provides authoritative line numbers. Manifest-only — no .rs file changes, so the changed-line set the gate computes is unchanged and these numbers stay valid for the next run. Derived, not transcribed: the gate was replayed locally against its own merged lcov from that run, reproducing CI's failure byte-identically first (95.17%, 138/145, same 13 files, same 7 lines), then re-run after each entry. Final local result: 100.00% (138/138), branch 100% (4/4), exit 0. All 45 gate self-tests pass. Two classes, both verified rather than asserted: - 13 files x 20 lines - declaration lines (fn params, return types, struct fields) whose only edit is the type NAME: GateRef -> TurnGateRef, or ironclaw_turns::X -> ironclaw_host_api::turn::X. Declarations are not executable, so these files contribute a zero denominator and trip the fail-closed empty_denominator branch. - 7 lines x 3 files - executable, instrumented, and genuinely not exercised by the integration tier. Each checked against the base merged lcov (main @ 67088a4, the PR's own base sha): identical 0 hits before and after, so no coverage was lost. approval_prompt_ context_view is uncovered across its whole signature at base (lines 505-511); the background spawn-mode arm and the invalid-gate- ref error path likewise. This includes the two entries I refused to guess last round - turn_events.rs (three identical candidate lines by text; the settled run disambiguates it as 510) and await_edge/store.rs (no verbatim twin after the repoint; authoritatively 268-272). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…oop (WS1.2) Carve the loop tier's neutral contracts out of the turn kernel into a new contracts-layer crate per PROPOSAL 6.1.4, and repoint every consumer. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…new crate Enforcement, CI registration, and guidance for the WS1.2 extraction. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…he two crates The claim types moved to ironclaw_loop_contracts with WS1.2; the validator policy and the trusted applier stayed in the turn kernel. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The two HostManagedLoop*Port impls stayed in ironclaw_turns, so same-crate links to them no longer resolve; the TurnRunId link target became redundant when the import repoint fully qualified it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Removing the ironclaw_runner re-export (required by the new port-location scan) left two workspace-root test-support files importing the turn kernel's evidence types through it. They now import from ironclaw_turns::loop_exit directly, which is the single sanctioned path. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
#6967 landed as a squash, so this branch carries the parent's original commits while main carries their collapsed equivalent. Merging reconciles the two shapes; the result must be main plus exactly the WS1.2 delta. # Conflicts: # crates/ironclaw_architecture/tests/reborn_dependency_boundaries.rs # crates/ironclaw_host_api/src/turn.rs # crates/ironclaw_host_runtime/tests/memory_prompt_context.rs # crates/ironclaw_loop_contracts/src/host/checkpoint.rs # crates/ironclaw_loop_contracts/src/memory_context.rs # crates/ironclaw_loop_contracts/tests/memory_prompt_context_service.rs # crates/ironclaw_loop_host/src/subagent_spawn_port.rs # crates/ironclaw_product/src/communication_context.rs # crates/ironclaw_product/src/projection/tests.rs # crates/ironclaw_product/src/projection/turn_events.rs # crates/ironclaw_product/src/reborn_services/types.rs # crates/ironclaw_reborn_composition/src/llm_admin/openai_compat_serve.rs # crates/ironclaw_reborn_composition/src/runtime.rs # crates/ironclaw_reborn_composition/src/runtime/capability_host/tests.rs # crates/ironclaw_reborn_composition/src/runtime/tests/core.rs # crates/ironclaw_runner/src/loop_exit_applier/tests/mod.rs # crates/ironclaw_runner/src/loop_exit_applier/tests/support.rs # crates/ironclaw_runner/src/subagent/await_edge/resolver.rs # crates/ironclaw_turns/src/agent_turn_runtime.rs # crates/ironclaw_turns/src/coordinator.rs # crates/ironclaw_turns/src/lib.rs # crates/ironclaw_turns/src/loop_exit.rs # crates/ironclaw_turns/src/loop_exit/tests/mod.rs # crates/ironclaw_turns/src/origin.rs # crates/ironclaw_turns/src/process_projection/runtime.rs # crates/ironclaw_turns/src/process_projection/tests.rs # crates/ironclaw_turns/src/request.rs # crates/ironclaw_turns/src/status.rs # crates/ironclaw_turns/tests/agent_loop_host_contract.rs # docs/reborn/target-architecture/CHECKLIST.md # tests/integration/support/comm_context.rs # tests/integration/support/harness/mod.rs # tests/integration/support/harness/recorder.rs # tests/integration/support/triggered_submit.rs # tests/support/reborn_parity_qa/binary_e2e.rs # tools/ironclaw_stress/src/user_turn.rs
…scan Two artifacts of collapsing onto main: - Cargo.lock pinned thiserror 2.0.18 for the new ironclaw_loop_contracts entry while main's dependency bump moved the workspace to 2.0.19. The auto-merge kept the stale pin because the bump predates the crate, so --locked builds failed. - ironclaw_product's failure-summary test reaches into another crate's source with include_str! and scans it for 'impl LoopFailureKind'. WS1.2 moved that impl to ironclaw_loop_contracts, so the include still resolved and matched nothing. Repointed to follow the code. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…he dual import paths (WS1.3) Carve the extension tier's neutral contracts out of the host API into a new contracts-layer crate per PROPOSAL 6.1.2, repoint every consumer, and pin the boundary with the 11.2.3 purity allowlist and the 11.2.4 location scan. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
scripts/reborn-e2e-rust.sh pins exact test names for the deterministic gate. The capability-failure rehydration test moved from ironclaw_turns::run_profile::host::capability to ironclaw_loop_contracts::host::capability, so its selector matched zero tests and the gate failed closed. Swept all 10 pinned selectors in that script (4 lib + 6 integration target); this was the only stale one. Each now resolves to exactly one test, verified by running the selector. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The extension_contracts lock entry was generated before the parent branch collapsed against main, so it pinned thiserror 2.0.18 and toml 1.1.2 — versions that no longer have [[package]] blocks. --locked lanes would have failed to resolve. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Caution The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased. |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (3)
📝 WalkthroughSummary by CodeRabbit
WalkthroughThe PR creates ChangesExtension contracts extraction
Estimated code review effort: 4 (Complex) | ~60 minutes Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
🚅 Deployed to the ironclaw-pr-6977 environment in ironclaw-ci-preview
|
…merate deps The composition pub-use snapshot still carried product's PreferenceTargetCodec re-export, and the CLI's exact-dependency allowlist did not know the extension tier's contracts crate. Both are enumerating gates, so both failed loudly rather than passing vacuously. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
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_architecture/tests/reborn_extension_contract_location_scan.rs`:
- Around line 305-322: Update collect_rust_files to skip node_modules and other
generated or vendored directories during recursive traversal, alongside the
existing target exclusion. Keep Rust-file collection unchanged for directories
that are part of the source tree.
In `@crates/ironclaw_extension_contracts/CLAUDE.md`:
- Around line 16-29: Update the module count in the introductory sentence of
CLAUDE.md from nine to ten so it matches all modules listed in the table.
In `@crates/ironclaw_extension_contracts/src/state.rs`:
- Around line 4-10: Update the module documentation above InstallationState to
identify ironclaw_extension_contracts as the type’s owner, replacing the
obsolete ironclaw_host_api ownership and dependency-path explanation. Ensure
references to ExtensionHost, ironclaw_product, and the shared enum point
consumers to this contract module without retaining the removed host API import
path.
🪄 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: 50e3e926-01bc-4bee-bf83-43d8660b2bc8
⛔ Files ignored due to path filters (1)
Cargo.lockis excluded by!**/*.lock,!**/Cargo.lock
📒 Files selected for processing (144)
Cargo.tomlcrates/AGENTS.mdcrates/ironclaw_architecture/tests/reborn_dependency_boundaries.rscrates/ironclaw_architecture/tests/reborn_extension_contract_location_scan.rscrates/ironclaw_architecture/tests/reborn_extension_specificity.rscrates/ironclaw_auth/CLAUDE.mdcrates/ironclaw_auth/Cargo.tomlcrates/ironclaw_auth/src/engine/admission.rscrates/ironclaw_auth/src/engine/dcr.rscrates/ironclaw_auth/src/engine/exchange.rscrates/ironclaw_auth/src/engine/keepalive.rscrates/ironclaw_auth/src/engine/mod.rscrates/ironclaw_auth/src/product_auth/oauth/oauth_gate.rscrates/ironclaw_auth/tests/auth_engine_contract.rscrates/ironclaw_capabilities/Cargo.tomlcrates/ironclaw_capabilities/src/registry.rscrates/ironclaw_extension_contracts/CLAUDE.mdcrates/ironclaw_extension_contracts/Cargo.tomlcrates/ironclaw_extension_contracts/src/channel.rscrates/ironclaw_extension_contracts/src/channel_identity.rscrates/ironclaw_extension_contracts/src/extension.rscrates/ironclaw_extension_contracts/src/hosted_mcp.rscrates/ironclaw_extension_contracts/src/lib.rscrates/ironclaw_extension_contracts/src/memory.rscrates/ironclaw_extension_contracts/src/package_lifecycle.rscrates/ironclaw_extension_contracts/src/preference_target.rscrates/ironclaw_extension_contracts/src/recipe.rscrates/ironclaw_extension_contracts/src/state.rscrates/ironclaw_extension_contracts/src/surface.rscrates/ironclaw_extension_host/Cargo.tomlcrates/ironclaw_extension_host/src/active.rscrates/ironclaw_extension_host/src/active_publication.rscrates/ironclaw_extension_host/src/available_extensions.rscrates/ironclaw_extension_host/src/channel_config.rscrates/ironclaw_extension_host/src/channel_connection.rscrates/ironclaw_extension_host/src/channel_dm_provisioning.rscrates/ironclaw_extension_host/src/channel_host.rscrates/ironclaw_extension_host/src/channel_host/e2e_tests.rscrates/ironclaw_extension_host/src/channel_identity.rscrates/ironclaw_extension_host/src/channel_identity_binding.rscrates/ironclaw_extension_host/src/channel_outbound_targets.rscrates/ironclaw_extension_host/src/channel_subject_routes.rscrates/ironclaw_extension_host/src/channel_triggered_delivery.rscrates/ironclaw_extension_host/src/egress.rscrates/ironclaw_extension_host/src/extension_lifecycle_capabilities.rscrates/ironclaw_extension_host/src/extension_lifecycle_command.rscrates/ironclaw_extension_host/src/generic_host.rscrates/ironclaw_extension_host/src/hosted_mcp_admission.rscrates/ironclaw_extension_host/src/hosted_mcp_manifest.rscrates/ironclaw_extension_host/src/hosted_mcp_preparation.rscrates/ironclaw_extension_host/src/ingress/router.rscrates/ironclaw_extension_host/src/ingress/verifier.rscrates/ironclaw_extension_host/src/ironhub/service.rscrates/ironclaw_extension_host/src/lib.rscrates/ironclaw_extension_host/src/lifecycle.rscrates/ironclaw_extension_host/src/lifecycle_product_service.rscrates/ironclaw_extension_host/src/mcp_discovery.rscrates/ironclaw_extension_host/src/product_lifecycle.rscrates/ironclaw_extension_host/src/recipes.rscrates/ironclaw_extension_host/src/state.rscrates/ironclaw_extension_host/src/store.rscrates/ironclaw_extension_host/src/test_support.rscrates/ironclaw_extension_host/src/test_support/lifecycle.rscrates/ironclaw_extension_host/tests/ingress_router_contract.rscrates/ironclaw_extension_host/tests/lifecycle_contract.rscrates/ironclaw_extensions/Cargo.tomlcrates/ironclaw_extensions/src/package.rscrates/ironclaw_extensions/src/resolved.rscrates/ironclaw_extensions/src/v2.rscrates/ironclaw_extensions/src/v3.rscrates/ironclaw_extensions/tests/manifest_v2_contract.rscrates/ironclaw_extensions/tests/manifest_v3_contract.rscrates/ironclaw_host_api/src/error.rscrates/ironclaw_host_api/src/lib.rscrates/ironclaw_host_api/src/product_adapter/mod.rscrates/ironclaw_host_api/src/product_adapter/outbound.rscrates/ironclaw_host_runtime/Cargo.tomlcrates/ironclaw_host_runtime/src/egress/sanitize.rscrates/ironclaw_host_runtime/src/memory_context.rscrates/ironclaw_host_runtime/src/memory_native_extension.rscrates/ironclaw_host_runtime/tests/memory_prompt_context.rscrates/ironclaw_loop_contracts/Cargo.tomlcrates/ironclaw_loop_contracts/src/runtime_context.rscrates/ironclaw_mcp/Cargo.tomlcrates/ironclaw_mcp/src/lib.rscrates/ironclaw_product/Cargo.tomlcrates/ironclaw_product/src/adapter_registry.rscrates/ironclaw_product/src/auth_prompt.rscrates/ironclaw_product/src/commands.rscrates/ironclaw_product/src/communication_context.rscrates/ironclaw_product/src/lib.rscrates/ironclaw_product/src/lifecycle.rscrates/ironclaw_product/src/reborn_services.rscrates/ironclaw_product/src/reborn_services/extension_onboarding.rscrates/ironclaw_product/src/reborn_services/extensions.rscrates/ironclaw_product/src/reborn_services/lifecycle_setup.rscrates/ironclaw_product/src/reborn_services/product_capability_handlers.rscrates/ironclaw_product/src/reborn_services/product_commands.rscrates/ironclaw_product/src/reborn_services/types.rscrates/ironclaw_product/src/run_delivery/triggered.rscrates/ironclaw_product/tests/adapter_registry_manifest_ingestion.rscrates/ironclaw_product/tests/reborn_services_contract.rscrates/ironclaw_product/tests/run_delivery_contract.rscrates/ironclaw_reborn_cli/Cargo.tomlcrates/ironclaw_reborn_cli/src/commands/extension.rscrates/ironclaw_reborn_composition/Cargo.tomlcrates/ironclaw_reborn_composition/src/extension_host_assembly.rscrates/ironclaw_reborn_composition/src/factory.rscrates/ironclaw_reborn_composition/src/factory/auth_engine_assembly.rscrates/ironclaw_reborn_composition/src/factory/auth_tests.rscrates/ironclaw_reborn_composition/src/factory/tests.rscrates/ironclaw_reborn_composition/src/input.rscrates/ironclaw_reborn_composition/src/lib.rscrates/ironclaw_reborn_composition/src/llm_admin/nearai_mcp.rscrates/ironclaw_reborn_composition/src/memory_provider_factory.rscrates/ironclaw_reborn_composition/src/runtime.rscrates/ironclaw_reborn_composition/src/runtime/tests/core.rscrates/ironclaw_reborn_composition/src/test_support/channel_connection.rscrates/ironclaw_reborn_composition/src/test_support/oauth_product_auth.rscrates/ironclaw_reborn_composition/tests/first_party_manifest_v3_parity.rscrates/ironclaw_reborn_composition/tests/memory_mem0_swap.rscrates/ironclaw_reborn_composition/tests/webui_v2_product_auth.rscrates/ironclaw_reborn_composition/tests/webui_v2_serve.rscrates/ironclaw_slack_extension/Cargo.tomlcrates/ironclaw_slack_extension/src/preference_targets.rscrates/ironclaw_telegram_extension/Cargo.tomlcrates/ironclaw_telegram_extension/src/lib.rscrates/ironclaw_telegram_extension/src/preference_targets.rscrates/ironclaw_webui/Cargo.tomlcrates/ironclaw_webui/src/product_auth/mod.rscrates/ironclaw_webui/src/product_auth/oauth_start_tests.rscrates/ironclaw_webui/src/webui_v2/handlers.rscrates/ironclaw_webui/tests/webui_v2_handlers_contract.rsdocs/plans/composition-pubuse.snapshotdocs/reborn/auth/recipe-parity-checklist.mddocs/reborn/extension-runtime/checklist.mddocs/reborn/extension-runtime/implementation.mddocs/reborn/target-architecture/CHECKLIST.mdscripts/ci/classify-test-scope.shscripts/ci/reborn-crate-test-buckets.shtests/integration/group_memory/scenario_lifecycle_gates_host_memory_calls.rstests/integration/hosted_mcp_registration.rstests/integration/support/group.rstests/integration/support/group_options.rs
💤 Files with no reviewable changes (6)
- docs/plans/composition-pubuse.snapshot
- crates/ironclaw_host_api/src/product_adapter/outbound.rs
- crates/ironclaw_extension_host/src/lib.rs
- crates/ironclaw_reborn_composition/src/lib.rs
- crates/ironclaw_extension_host/src/state.rs
- crates/ironclaw_host_api/src/lib.rs
There was a problem hiding this comment.
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: 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_architecture/tests/reborn_extension_contract_location_scan.rs`:
- Around line 305-322: Update collect_rust_files to skip node_modules and other
generated or vendored directories during recursive traversal, alongside the
existing target exclusion. Keep Rust-file collection unchanged for directories
that are part of the source tree.
In `@crates/ironclaw_extension_contracts/CLAUDE.md`:
- Around line 16-29: Update the module count in the introductory sentence of
CLAUDE.md from nine to ten so it matches all modules listed in the table.
In `@crates/ironclaw_extension_contracts/src/state.rs`:
- Around line 4-10: Update the module documentation above InstallationState to
identify ironclaw_extension_contracts as the type’s owner, replacing the
obsolete ironclaw_host_api ownership and dependency-path explanation. Ensure
references to ExtensionHost, ironclaw_product, and the shared enum point
consumers to this contract module without retaining the removed host API import
path.
🪄 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: 50e3e926-01bc-4bee-bf83-43d8660b2bc8
⛔ Files ignored due to path filters (1)
Cargo.lockis excluded by!**/*.lock,!**/Cargo.lock
📒 Files selected for processing (144)
Cargo.tomlcrates/AGENTS.mdcrates/ironclaw_architecture/tests/reborn_dependency_boundaries.rscrates/ironclaw_architecture/tests/reborn_extension_contract_location_scan.rscrates/ironclaw_architecture/tests/reborn_extension_specificity.rscrates/ironclaw_auth/CLAUDE.mdcrates/ironclaw_auth/Cargo.tomlcrates/ironclaw_auth/src/engine/admission.rscrates/ironclaw_auth/src/engine/dcr.rscrates/ironclaw_auth/src/engine/exchange.rscrates/ironclaw_auth/src/engine/keepalive.rscrates/ironclaw_auth/src/engine/mod.rscrates/ironclaw_auth/src/product_auth/oauth/oauth_gate.rscrates/ironclaw_auth/tests/auth_engine_contract.rscrates/ironclaw_capabilities/Cargo.tomlcrates/ironclaw_capabilities/src/registry.rscrates/ironclaw_extension_contracts/CLAUDE.mdcrates/ironclaw_extension_contracts/Cargo.tomlcrates/ironclaw_extension_contracts/src/channel.rscrates/ironclaw_extension_contracts/src/channel_identity.rscrates/ironclaw_extension_contracts/src/extension.rscrates/ironclaw_extension_contracts/src/hosted_mcp.rscrates/ironclaw_extension_contracts/src/lib.rscrates/ironclaw_extension_contracts/src/memory.rscrates/ironclaw_extension_contracts/src/package_lifecycle.rscrates/ironclaw_extension_contracts/src/preference_target.rscrates/ironclaw_extension_contracts/src/recipe.rscrates/ironclaw_extension_contracts/src/state.rscrates/ironclaw_extension_contracts/src/surface.rscrates/ironclaw_extension_host/Cargo.tomlcrates/ironclaw_extension_host/src/active.rscrates/ironclaw_extension_host/src/active_publication.rscrates/ironclaw_extension_host/src/available_extensions.rscrates/ironclaw_extension_host/src/channel_config.rscrates/ironclaw_extension_host/src/channel_connection.rscrates/ironclaw_extension_host/src/channel_dm_provisioning.rscrates/ironclaw_extension_host/src/channel_host.rscrates/ironclaw_extension_host/src/channel_host/e2e_tests.rscrates/ironclaw_extension_host/src/channel_identity.rscrates/ironclaw_extension_host/src/channel_identity_binding.rscrates/ironclaw_extension_host/src/channel_outbound_targets.rscrates/ironclaw_extension_host/src/channel_subject_routes.rscrates/ironclaw_extension_host/src/channel_triggered_delivery.rscrates/ironclaw_extension_host/src/egress.rscrates/ironclaw_extension_host/src/extension_lifecycle_capabilities.rscrates/ironclaw_extension_host/src/extension_lifecycle_command.rscrates/ironclaw_extension_host/src/generic_host.rscrates/ironclaw_extension_host/src/hosted_mcp_admission.rscrates/ironclaw_extension_host/src/hosted_mcp_manifest.rscrates/ironclaw_extension_host/src/hosted_mcp_preparation.rscrates/ironclaw_extension_host/src/ingress/router.rscrates/ironclaw_extension_host/src/ingress/verifier.rscrates/ironclaw_extension_host/src/ironhub/service.rscrates/ironclaw_extension_host/src/lib.rscrates/ironclaw_extension_host/src/lifecycle.rscrates/ironclaw_extension_host/src/lifecycle_product_service.rscrates/ironclaw_extension_host/src/mcp_discovery.rscrates/ironclaw_extension_host/src/product_lifecycle.rscrates/ironclaw_extension_host/src/recipes.rscrates/ironclaw_extension_host/src/state.rscrates/ironclaw_extension_host/src/store.rscrates/ironclaw_extension_host/src/test_support.rscrates/ironclaw_extension_host/src/test_support/lifecycle.rscrates/ironclaw_extension_host/tests/ingress_router_contract.rscrates/ironclaw_extension_host/tests/lifecycle_contract.rscrates/ironclaw_extensions/Cargo.tomlcrates/ironclaw_extensions/src/package.rscrates/ironclaw_extensions/src/resolved.rscrates/ironclaw_extensions/src/v2.rscrates/ironclaw_extensions/src/v3.rscrates/ironclaw_extensions/tests/manifest_v2_contract.rscrates/ironclaw_extensions/tests/manifest_v3_contract.rscrates/ironclaw_host_api/src/error.rscrates/ironclaw_host_api/src/lib.rscrates/ironclaw_host_api/src/product_adapter/mod.rscrates/ironclaw_host_api/src/product_adapter/outbound.rscrates/ironclaw_host_runtime/Cargo.tomlcrates/ironclaw_host_runtime/src/egress/sanitize.rscrates/ironclaw_host_runtime/src/memory_context.rscrates/ironclaw_host_runtime/src/memory_native_extension.rscrates/ironclaw_host_runtime/tests/memory_prompt_context.rscrates/ironclaw_loop_contracts/Cargo.tomlcrates/ironclaw_loop_contracts/src/runtime_context.rscrates/ironclaw_mcp/Cargo.tomlcrates/ironclaw_mcp/src/lib.rscrates/ironclaw_product/Cargo.tomlcrates/ironclaw_product/src/adapter_registry.rscrates/ironclaw_product/src/auth_prompt.rscrates/ironclaw_product/src/commands.rscrates/ironclaw_product/src/communication_context.rscrates/ironclaw_product/src/lib.rscrates/ironclaw_product/src/lifecycle.rscrates/ironclaw_product/src/reborn_services.rscrates/ironclaw_product/src/reborn_services/extension_onboarding.rscrates/ironclaw_product/src/reborn_services/extensions.rscrates/ironclaw_product/src/reborn_services/lifecycle_setup.rscrates/ironclaw_product/src/reborn_services/product_capability_handlers.rscrates/ironclaw_product/src/reborn_services/product_commands.rscrates/ironclaw_product/src/reborn_services/types.rscrates/ironclaw_product/src/run_delivery/triggered.rscrates/ironclaw_product/tests/adapter_registry_manifest_ingestion.rscrates/ironclaw_product/tests/reborn_services_contract.rscrates/ironclaw_product/tests/run_delivery_contract.rscrates/ironclaw_reborn_cli/Cargo.tomlcrates/ironclaw_reborn_cli/src/commands/extension.rscrates/ironclaw_reborn_composition/Cargo.tomlcrates/ironclaw_reborn_composition/src/extension_host_assembly.rscrates/ironclaw_reborn_composition/src/factory.rscrates/ironclaw_reborn_composition/src/factory/auth_engine_assembly.rscrates/ironclaw_reborn_composition/src/factory/auth_tests.rscrates/ironclaw_reborn_composition/src/factory/tests.rscrates/ironclaw_reborn_composition/src/input.rscrates/ironclaw_reborn_composition/src/lib.rscrates/ironclaw_reborn_composition/src/llm_admin/nearai_mcp.rscrates/ironclaw_reborn_composition/src/memory_provider_factory.rscrates/ironclaw_reborn_composition/src/runtime.rscrates/ironclaw_reborn_composition/src/runtime/tests/core.rscrates/ironclaw_reborn_composition/src/test_support/channel_connection.rscrates/ironclaw_reborn_composition/src/test_support/oauth_product_auth.rscrates/ironclaw_reborn_composition/tests/first_party_manifest_v3_parity.rscrates/ironclaw_reborn_composition/tests/memory_mem0_swap.rscrates/ironclaw_reborn_composition/tests/webui_v2_product_auth.rscrates/ironclaw_reborn_composition/tests/webui_v2_serve.rscrates/ironclaw_slack_extension/Cargo.tomlcrates/ironclaw_slack_extension/src/preference_targets.rscrates/ironclaw_telegram_extension/Cargo.tomlcrates/ironclaw_telegram_extension/src/lib.rscrates/ironclaw_telegram_extension/src/preference_targets.rscrates/ironclaw_webui/Cargo.tomlcrates/ironclaw_webui/src/product_auth/mod.rscrates/ironclaw_webui/src/product_auth/oauth_start_tests.rscrates/ironclaw_webui/src/webui_v2/handlers.rscrates/ironclaw_webui/tests/webui_v2_handlers_contract.rsdocs/plans/composition-pubuse.snapshotdocs/reborn/auth/recipe-parity-checklist.mddocs/reborn/extension-runtime/checklist.mddocs/reborn/extension-runtime/implementation.mddocs/reborn/target-architecture/CHECKLIST.mdscripts/ci/classify-test-scope.shscripts/ci/reborn-crate-test-buckets.shtests/integration/group_memory/scenario_lifecycle_gates_host_memory_calls.rstests/integration/hosted_mcp_registration.rstests/integration/support/group.rstests/integration/support/group_options.rs
💤 Files with no reviewable changes (6)
- docs/plans/composition-pubuse.snapshot
- crates/ironclaw_host_api/src/product_adapter/outbound.rs
- crates/ironclaw_extension_host/src/lib.rs
- crates/ironclaw_reborn_composition/src/lib.rs
- crates/ironclaw_extension_host/src/state.rs
- crates/ironclaw_host_api/src/lib.rs
🛑 Comments failed to post (1)
crates/ironclaw_extension_contracts/src/state.rs (1)
4-10: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Correct the documented owner of
InstallationState.These lines state that
InstallationStatelives inironclaw_host_api. This file now owns the type inironclaw_extension_contracts. Update the owner and dependency-path explanation so consumers do not retain the removed host API import path.As per path instructions, module specifications win ties. As per coding guidelines, update the owning contract or documentation whenever behavior changes.
🤖 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_extension_contracts/src/state.rs` around lines 4 - 10, Update the module documentation above InstallationState to identify ironclaw_extension_contracts as the type’s owner, replacing the obsolete ironclaw_host_api ownership and dependency-path explanation. Ensure references to ExtensionHost, ironclaw_product, and the shared enum point consumers to this contract module without retaining the removed host API import path.Sources: Coding guidelines, Path instructions
Both CodeRabbit findings verified against the tree and real: the crate guide still said nine modules after hosted_mcp joined on the merge-down (lib.rs declares ten), and crates/ironclaw_webui/frontend/node_modules really is present -- 2,506 directories the location scan descended on every run. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Coverage ratchetReborn integration-tier coverageLine coverage (Reborn crates): 85.88% — 323334 / 376497 lines Per-crate breakdown (62 crates, lowest-covered first)
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 (18 entry/entries excluded from the accounting above)
|
…empt the rest The gate flagged nine sites. Two were genuine gaps in this crate's own contract surface and are now tested rather than exempted: the body_json_pointer egress injection arm (the existing shape test grew the rejecting and accepting cases) and ExtensionContract::capability. The remaining seven are declaration-only lines, or a type path inside a body that was already fully uncovered, and are exempted with their per-site evidence. Every line number was derived by replaying the failing run's own merged lcov against the gate until it reproduced byte-identically -- none was guessed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Coordinator sign-off (Wave 1 slot 3 — WS1.3 Verified continuously across the slice's full lifecycle:
Ready to merge on settle (four routine lanes finishing at time of writing, zero failures). Stack note: #6980 auto-retargets to this branch's place on merge; its collapse and full validation follow. |
…n record with shipped reality (#6995) * docs(target-architecture): Wave 1 truth audit — reconcile the decision record with shipped reality Wave 1 merged as seven PRs (#6967, #6975, #6977, #6979, #6980, #6981, #6982). This audits the north-star docs against merged `main` at `a50ad0638` and closes every gap where the decision record no longer matches what shipped. Docs-only: five `.md` files under `docs/reborn/target-architecture/`. House style throughout — dated ✎ amendments, prior text quoted where a clause is corrected, no silent rewrites (`git diff --word-diff` removes nothing but the words each amendment quotes back). Highlights: - §8.3's exception-dissolution proof corrected: `conversations → turns` is turn admission authority, not vocabulary; the wave's "20 → 12" milestone was wrong by construction and the true end-state is 13. - §6.1.1–§6.1.4 gain as-built module inventories; the #6930 amendment placing `hosted_mcp` in `host_api` is superseded by #6977's relocation. - §12.1a records the evidence-mint finding: the `host-auth-mint` feature seal was vacuous, replaced by witness grants — plus two residuals, one from the slice and one this audit verified against the ratchet source. - The coverage-governance gap (~14k lines now ungated by the floor file's opt-in design) moves from a sign-off comment onto the ratchet row. - Duplicate-type findings, the `llm_costs`/`ModelCostTable` deferral, the surviving `product → loop_host` sites, and issues #6945/#6978 all gain owning rows. Verification: docs-only diff; `cargo test -p ironclaw_architecture` green. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * docs(target-architecture): tighten the Wave 1 audit where review found it overstated Six review findings triaged against the built tree; four were real. - `families/contracts.md` landing marker claimed "everything else in this file was built as written". Three `ironclaw_loop_contracts` divergences contradict it and are now named at the marker and marked at the entry: the manifest holds `ironclaw_extension_contracts` and holds neither `ironclaw_common` nor `ironclaw_prompt_envelope`; the `tokio` carve-out; the embedded prompt asset. - The evidence-mint guarantee said "compile-time impossibility" and "enforced by constructor visibility plus a workspace string-scan pin" in one breath. Split: the compiler enforces no-mint-without-a-grant (so nothing outside a workspace crate can mint at all); an architecture test — a line-oriented substring scan with two named evasions — decides which workspace crate may hold one. - That deferral had no home. §12.1a said "hardening the scan is WS10 work, listed there"; it was not listed. Added to the WS10 guardrail row with both evasions and the call-site census that backstops them. - CHECKLIST WS8's `common/src/event.rs` row still closed with "stays in `common` as a deletion candidate" under an "executed by #6982" header. The file is deleted; the tail now says so. Plus two clarity fixes where a reader could reach a wrong number: the `(66)`/`(64)` figures in §9/§13 are that table's 2026-07-30 measurement and now say so beside the live 67, and the row-1 edge count now states that six of row 1's seven fell while the register moved by seven, because `auth → turns` is row 9. Dated amendments only; every replaced phrase is quoted in place. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
…he dual import paths (WS1.3) (nearai#6977) * refactor(contracts): complete the turn vocabulary in host_api and retire the turns shims (WS1.1) `ironclaw_host_api::turn` becomes the complete canonical turn vocabulary: it absorbs `TurnStatus` (with the inseparable `GateKind`/`BlockedReason` gate correspondence), `EventCursor`, and `RunOriginAdapter`. The three `ironclaw_turns` re-export shims named by CHECKLIST WS1.1 are deleted — `src/ids.rs`, `src/scope.rs`, and the whole `src/product_adapter/` module, whose `fakes.rs` moves beside the traits it implements in `host_api::product_adapter::test_support`. `ids.rs` carried `pub type GateRef = TurnGateRef`: a second name for a host_api type that collided with the unrelated `ironclaw_host_api::ids::GateRef` (an opaque uuid GateRecord key, versus turns' bounded `gate:`-prefixed routing string). The alias is retired rather than relocated, so the workspace now has exactly one `GateRef`. The six vocabulary-only consumers — auth, event_streams, outbound, telegram_extension, triggers, event_projections — import from `ironclaw_host_api::turn` and drop their `ironclaw_turns` dependency entirely. Five `*→turns` LAYER_MATRIX_EXCEPTIONS are therefore not waived but obsolete: the edges no longer exist. The §11.2.2 ratchet baseline moves 20 → 15. No behavior change. `RunOriginAdapter`'s validation error becomes `Result<_, String>` (matching every other bounded ref in `host_api::turn`) with a byte-identical message pinned by a test, so both production `e.to_string()` call sites are unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs(target-architecture): tick WS1.1 and close PLAN decision round #1 WS1.1's box is ticked with what the change actually landed, including the three lead-sheet corrections it turned up: the row named `TurnStatus` but not `EventCursor`/`RunOriginAdapter` (which the six consumers genuinely needed), `GateKind`/`BlockedReason` could not be left behind without duplicating the single `GateKind -> TurnStatus` match table, and deleting `ids.rs` forced retiring its `GateRef` alias rather than relocating it. Two decisions confirmed outside the doc and never recorded: - Strategy B (family dirs + focused crates) — confirmed 2026-07-31 by the owner, recorded retroactively; it was made in practice at program start. - The `tools/` row's `default-members` trim — resolved as no trim. Also surfaces nearai#6963 on the WS0 blocking-prerequisite row's first line (it was already cited mid-paragraph) and records the §11.2.2 exception ratchet moving 20 -> 15. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * refactor(contracts): repoint touched imports to host_api and pin the TurnGateRef contract CodeRabbit review round on nearai#6967. Import repoints (accepted): every `use` line this PR already rewrote now names `ironclaw_host_api::turn` directly instead of routing through `ironclaw_turns`' prelude — 57 files across extension_host, product, composition, runner, loop_host, conversations, the integration harness, and the stress tool, plus three inside `ironclaw_turns` itself so the crate stops consuming its own facade. Import lines this PR did not touch are left for their consumer's own repoint slot. TurnGateRef contract pinned (refutation): two review comments claimed `TurnGateRef::new` only accepts `gate:approval-`/`gate:auth-` prefixes and that fixtures like "gate-alpha" and "stress-gate:{run_id}" fail construction. They do not — `TurnGateRef` is `bounded_ref!` (non-empty, <= 256 bytes, no control characters); `LoopGateRef` is the prefix- validated family via `loop_ref!(.., "gate:")`. The misreading traces to this PR's own AGENTS.md wording ("bounded `gate:`-prefixed routing string"), which stated a minting convention as if it were validation. That wording is corrected and the distinction is now pinned by a test. Also: drop a stale cross-file line reference in a product test comment. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs(target-architecture): remove the row-97 self-contradiction The `tools/` row resolved the `default-members` trim as "no trim" but kept a trailing "The `tools/`/`default-members` half is still open." from before that decision, so the row asserted both states. Drop the stale sentence. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * ci(coverage): complete the WS1.1 changed-coverage exemptions Finishes the remediation deferred last round, now that the settled run (job 91246493989) provides authoritative line numbers. Manifest-only — no .rs file changes, so the changed-line set the gate computes is unchanged and these numbers stay valid for the next run. Derived, not transcribed: the gate was replayed locally against its own merged lcov from that run, reproducing CI's failure byte-identically first (95.17%, 138/145, same 13 files, same 7 lines), then re-run after each entry. Final local result: 100.00% (138/138), branch 100% (4/4), exit 0. All 45 gate self-tests pass. Two classes, both verified rather than asserted: - 13 files x 20 lines - declaration lines (fn params, return types, struct fields) whose only edit is the type NAME: GateRef -> TurnGateRef, or ironclaw_turns::X -> ironclaw_host_api::turn::X. Declarations are not executable, so these files contribute a zero denominator and trip the fail-closed empty_denominator branch. - 7 lines x 3 files - executable, instrumented, and genuinely not exercised by the integration tier. Each checked against the base merged lcov (main @ 67088a4, the PR's own base sha): identical 0 hits before and after, so no coverage was lost. approval_prompt_ context_view is uncovered across its whole signature at base (lines 505-511); the background spawn-mode arm and the invalid-gate- ref error path likewise. This includes the two entries I refused to guess last round - turn_events.rs (three identical candidate lines by text; the settled run disambiguates it as 510) and await_edge/store.rs (no verbatim twin after the repoint; authoritatively 268-272). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * refactor(contracts): extract ironclaw_loop_contracts and flip agent_loop (WS1.2) Carve the loop tier's neutral contracts out of the turn kernel into a new contracts-layer crate per PROPOSAL 6.1.4, and repoint every consumer. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * refactor(contracts): pin the loop-contract boundary and register the new crate Enforcement, CI registration, and guidance for the WS1.2 extraction. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs(reborn): split the loop-exit contract's ownership claim across the two crates The claim types moved to ironclaw_loop_contracts with WS1.2; the validator policy and the trusted applier stayed in the turn kernel. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs(contracts): repoint the three intra-doc links the crate split broke The two HostManagedLoop*Port impls stayed in ironclaw_turns, so same-crate links to them no longer resolve; the TurnRunId link target became redundant when the import repoint fully qualified it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(tests): repoint the loop-exit evidence imports the port rule moved Removing the ironclaw_runner re-export (required by the new port-location scan) left two workspace-root test-support files importing the turn kernel's evidence types through it. They now import from ironclaw_turns::loop_exit directly, which is the single sanctioned path. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(collapse): reconcile the lock pin and the moved failure-category scan Two artifacts of collapsing onto main: - Cargo.lock pinned thiserror 2.0.18 for the new ironclaw_loop_contracts entry while main's dependency bump moved the workspace to 2.0.19. The auto-merge kept the stale pin because the bump predates the crate, so --locked builds failed. - ironclaw_product's failure-summary test reaches into another crate's source with include_str! and scans it for 'impl LoopFailureKind'. WS1.2 moved that impl to ironclaw_loop_contracts, so the include still resolved and matched nothing. Repointed to follow the code. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * refactor(contracts): extract ironclaw_extension_contracts and close the dual import paths (WS1.3) Carve the extension tier's neutral contracts out of the host API into a new contracts-layer crate per PROPOSAL 6.1.2, repoint every consumer, and pin the boundary with the 11.2.3 purity allowlist and the 11.2.4 location scan. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(ci): repoint the exact-test selector WS1.2 moved scripts/reborn-e2e-rust.sh pins exact test names for the deterministic gate. The capability-failure rehydration test moved from ironclaw_turns::run_profile::host::capability to ironclaw_loop_contracts::host::capability, so its selector matched zero tests and the gate failed closed. Swept all 10 pinned selectors in that script (4 lib + 6 integration target); this was the only stale one. Each now resolves to exactly one test, verified by running the selector. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(collapse): reconcile the new crate's lock pins with main's dep bumps The extension_contracts lock entry was generated before the parent branch collapsed against main, so it pinned thiserror 2.0.18 and toml 1.1.2 — versions that no longer have [[package]] blocks. --locked lanes would have failed to resolve. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(arch): register the new contracts crate in the two gates that enumerate deps The composition pub-use snapshot still carried product's PreferenceTargetCodec re-export, and the CLI's exact-dependency allowlist did not know the extension tier's contracts crate. Both are enumerating gates, so both failed loudly rather than passing vacuously. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs(contracts): record why the extension tier's traits are not sealed The visibility kit's sealed-strategy template exists to close a strategy set; every trait here exists to be implemented outside the crate. State that, so the absence reads as a decision rather than an omission. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(coverage): drop the exemption WS1.2 made stale The changed-coverage manifest carried a WS1.1 exemption for crates/ironclaw_turns/src/run_profile/runtime_context.rs:575-576. WS1.2 moved that file into ironclaw_loop_contracts, so the gate's fail-closed path validator rejected the manifest before reaching its line-level verdict. Deleted rather than repointed: WS1.1 merged, so those lines are baseline on main, and this PR's diff pairs the file as a 99%-similarity rename whose only changed lines are imports. Repointing would re-exempt lines the gate no longer flags. All 19 remaining entries verified to resolve. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(coverage): merge main and derive the WS1.2 changed-coverage exemptions Merge brings in tests/e2e/scenarios/test_reborn_webui_v2_custom_mcp.py, added on main after the last merge-down; the WebUI-smoke and E2E roll-up reds were purely the missing file. Exemptions derived by replaying scripts/ci/reborn_changed_coverage.py against this PR's own merged lcov artifact until it exits 0 (100% line 244/244, 100% branch 8/8) - never estimated. Three classes: - type-path repoints on declaration/expression fragments; - verbatim-moved bodies in the new crate. Explicitly NOT counter-attribution: those files are instrumented in this lcov and partially hit (loop_exit 195/109, model 86/52, checkpoint_payload 32/16), which proves the crate is measured. The same bodies were equally unexercised by the integration tier before the move, when they sat in ironclaw_turns and simply were not changed lines; - one crate-root inner attribute the uninstrumentable-line classifier does not recognise on a declaration-only facade. Also adds the nearai#6524 declaration-only facade entry for the new crate's lib.rs to the informational per-crate coverage summary. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(collapse): drop the import the squash-collapse duplicated Both sides independently rewrote the same ironclaw_turns::run_profile import into ironclaw_loop_contracts, so the textual merge kept both copies. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * review: correct the module count and bound the scan walk Both CodeRabbit findings verified against the tree and real: the crate guide still said nine modules after hosted_mcp joined on the merge-down (lib.rs declares ten), and crates/ironclaw_webui/frontend/node_modules really is present -- 2,506 directories the location scan descended on every run. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * test(contracts): cover two arms the changed-coverage gate exposed, exempt the rest The gate flagged nine sites. Two were genuine gaps in this crate's own contract surface and are now tested rather than exempted: the body_json_pointer egress injection arm (the existing shape test grew the rejecting and accepting cases) and ExtensionContract::capability. The remaining seven are declaration-only lines, or a type path inside a body that was already fully uncovered, and are exempted with their per-site evidence. Every line number was derived by replaying the failing run's own merged lcov against the gate until it reproduced byte-identically -- none was guessed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…n record with shipped reality (nearai#6995) * docs(target-architecture): Wave 1 truth audit — reconcile the decision record with shipped reality Wave 1 merged as seven PRs (nearai#6967, nearai#6975, nearai#6977, nearai#6979, nearai#6980, nearai#6981, nearai#6982). This audits the north-star docs against merged `main` at `a50ad0638` and closes every gap where the decision record no longer matches what shipped. Docs-only: five `.md` files under `docs/reborn/target-architecture/`. House style throughout — dated ✎ amendments, prior text quoted where a clause is corrected, no silent rewrites (`git diff --word-diff` removes nothing but the words each amendment quotes back). Highlights: - §8.3's exception-dissolution proof corrected: `conversations → turns` is turn admission authority, not vocabulary; the wave's "20 → 12" milestone was wrong by construction and the true end-state is 13. - §6.1.1–§6.1.4 gain as-built module inventories; the nearai#6930 amendment placing `hosted_mcp` in `host_api` is superseded by nearai#6977's relocation. - §12.1a records the evidence-mint finding: the `host-auth-mint` feature seal was vacuous, replaced by witness grants — plus two residuals, one from the slice and one this audit verified against the ratchet source. - The coverage-governance gap (~14k lines now ungated by the floor file's opt-in design) moves from a sign-off comment onto the ratchet row. - Duplicate-type findings, the `llm_costs`/`ModelCostTable` deferral, the surviving `product → loop_host` sites, and issues nearai#6945/nearai#6978 all gain owning rows. Verification: docs-only diff; `cargo test -p ironclaw_architecture` green. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * docs(target-architecture): tighten the Wave 1 audit where review found it overstated Six review findings triaged against the built tree; four were real. - `families/contracts.md` landing marker claimed "everything else in this file was built as written". Three `ironclaw_loop_contracts` divergences contradict it and are now named at the marker and marked at the entry: the manifest holds `ironclaw_extension_contracts` and holds neither `ironclaw_common` nor `ironclaw_prompt_envelope`; the `tokio` carve-out; the embedded prompt asset. - The evidence-mint guarantee said "compile-time impossibility" and "enforced by constructor visibility plus a workspace string-scan pin" in one breath. Split: the compiler enforces no-mint-without-a-grant (so nothing outside a workspace crate can mint at all); an architecture test — a line-oriented substring scan with two named evasions — decides which workspace crate may hold one. - That deferral had no home. §12.1a said "hardening the scan is WS10 work, listed there"; it was not listed. Added to the WS10 guardrail row with both evasions and the call-site census that backstops them. - CHECKLIST WS8's `common/src/event.rs` row still closed with "stays in `common` as a deletion candidate" under an "executed by nearai#6982" header. The file is deleted; the tail now says so. Plus two clarity fixes where a reader could reach a wrong number: the `(66)`/`(64)` figures in §9/§13 are that table's 2026-07-30 measurement and now say so beside the live 67, and the row-1 edge count now states that six of row 1's seven fell while the register moved by seven, because `auth → turns` is row 9. Dated amendments only; every replaced phrase is quoted in place. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Stacked on #6975 (→ #6967) — merges after them; diff shown is against that branch.
WS1.3 of the target architecture: carve the extension tier's neutral contracts out of
ironclaw_host_apiintocrates/ironclaw_extension_contracts, repoint every consumer, and close the dual import paths. Flat crate directory today; thecontracts/family directory arrives in Wave 5.git mvmoved eight modules with 96–100% similarity, so the diff reads as a move, not a rewrite:channelChannelDescriptor/ChannelIngressDescriptor/ChannelEgressDescriptor/ChannelPresentation+ connection strategy, notices, validatorschannel_identityChannelConnectionScopeSource,ChannelIdentityPostBind(Factory),ChannelIdentityOverrideextensionExtension,ExtensionContract,ExtensionRuntimeIdentity,ExtensionInstanceId,ExtensionHostAssemblyConfigmemoryMemoryDescriptor,MemoryLifecycleHook(the[memory]manifest surface)package_lifecycleLifecycle*projection set,ChannelConnectStrategy,ChannelConfigFieldpreference_targetPreferenceTargetCodec+PreferenceTargetEncodeRequest(extracted fromproduct_adapter::outbound)recipeVendorAuthRecipe,OAuth2CodeRecipe,PkceMode, ingress-verification recipes, …stateInstallationState,LifecyclePublicStatesurfaceCapabilitySurfaceKindFive dispositions the lead sheet did not predict
1.
ChannelAdapter,ToolAdapter, andRestrictedEgressdid not move — and cannot until WS1.4.host_api::product_surfacenames both inChannelInboundProductSurface::admit_channel_inbound_with_attachment_transfer(request, Arc<dyn ChannelAdapter>, Arc<dyn RestrictedEgress>), and that file also holdsProductSurfaceitself — unambiguously PROPOSAL §6.1.3 material that cannot come to this crate.ironclaw_host_api's dependency allowlist is "noironclaw_*" (pinned inreborn_dependency_boundaries.rs), so a type leavinghost_apiwhile a type staying inhost_apinames it is mechanically impossible. The dependency runs one way only — §6.1.3 letsproduct_contractsdepend onextension_contracts— so WS1.4 unblocks the adapters, not the reverse. This is an ordering finding of the §12.1c class, not a scope cut; the channel-adapter conformance suite (§11.2.10) waits with them.2.
package_lifecyclemoved as a forced co-mover, and §6.1.3 may want it back. It is typed onInstallationState,LifecyclePublicState,ChannelPresentation, andCapabilitySurfaceKind— four §6.1.2 types, three named in the WS1.3 row — so the same allowlist that blocks the adapters would have blocked those three had it stayed inhost_api. §6.1.3 assigns it toproduct_contracts; since that crate may depend on this one, re-homing it in WS1.4 costs nothing and nothing here depends on it staying. Recorded as an interim placement in the crate'sCLAUDE.md, not presented as a decision.3.
AuthAccountStateis not inhost_api::state. It isironclaw_auth::account_state, and its module doc places it there deliberately ("the definition lives here with the engine that drives it"). It stayed: moving the enum withoutAuthAccountLastErrorandproject_auth_account_statesplits a state machine from its projection, which is a domain call, not a contracts extraction. The row's "(todayhost_api::state)" is wrong for one of its three names.4.
ReplyTargetBindingRefwas already home. It is abounded_ref!inhost_api::turn(turn.rs:280) — WS1.1's canonical turn vocabulary. Moving it here would undo that consolidation and forceloop_host,product, andcompositionontoextension_contractsfor turn vocabulary. §6.1.2's stated rationale for naming it — "the product/turns types that forcetelegram_extension's upward edges" — is satisfied without it (see below).5. The dual import path was worse than "a re-export".
PreferenceTargetCodechad three paths:host_api::product_adapter(Slack's),ironclaw_product(Telegram's, which carried a forbiddenproductdependency to reach it), andironclaw_reborn_composition, which re-exported product's re-export.InstallationStatehad a second path throughironclaw_extension_host::state— a facade with no external consumer whose own crate then usedcrate::InstallationStateinternally. All are deleted,extension_host/src/state.rswith them.What that bought
ironclaw_telegram_extensiondroppedironclaw_productentirely — normal and dev dependency — which is what §6.1.2 promised the codec re-home would buy, and what §8.2's channel-package row requires. It gained the boundary rule it never had (its Slack sibling, same shape, same surfaces, already forbadeproduct), so the edge cannot come back. The dead[dev-dependencies] ironclaw_productentry beside it went too; its stated purpose (FakeProtocolHttpEgress,mark_shared_secret_header_verified) is served by theironclaw_host_apidev-dep that actually owns them.Also forced, and amended in place with evidence rather than waived:
ironclaw_loop_contractsgained anironclaw_extension_contractsdependency, becauseLoopRuntimeContextcarriesOption<ChannelPresentation>andrender_presentation_hintreads it. §8.2's contracts row sanctions it ("others: host_api/common ± extension_contracts"); §6.1.4's list predates the extension tier existing.Exception delta: zero, by design and re-verified
Every one of the 13
LAYER_MATRIX_EXCEPTIONSwas re-read against this branch's base. Not one is ahost_apiedge, so no contracts carve-out fromhost_apican dissolve any of them. The five lane exceptions that sound like this slice —mcp → extensions,scripts → extensions("remove when extension runtime descriptors move to a neutral contract") — wait on the registry DTOs (ExtensionPackage,ExtensionRuntime,HostedMcpDiscoveredTool*inironclaw_extensions), which §6.1.2 explicitly forbids this crate from absorbing and which CHECKLIST WS3'smcprow owns. The count stays at 13.What this PR does delete is a forbidden edge the layer matrix never saw:
telegram_extension → productis legal by layer (both areproducts) and forbidden by §8.2's channel-package row. It is gone and now pinned.New-crate rule inventory
ironclaw_host_apionly; an allowlist, not a blocklist, so a future kernel/domain edge cannot slip past a list of today's offenders), plus the crate added to the shared framework/driver deny test the parent branch introduced across contracts crates.reborn_extension_contract_location_scan.rs, six tests. One home: every type the crate defines, discovered rather than enumerated, must be defined nowhere else — passes with zero exemptions. One import path: the crate's traits (discovered, so a new port inherits the rule) plus the value types the WS1.3 row names — no crate maypub useone. Ships with positive and negative fixtures per WS10, including the three real traps this PR deleted, and both halves assert they measured something before asserting anything else.boundary_rules()entry for the new crate, naming the edges whose appearance would be most damaging (ironclaw_extensions,ironclaw_extension_host,ironclaw_product) so the failure message says which invariant broke — plus the newironclaw_telegram_extensionrule described above.untrusted_ingress_paths_cannot_submit_host_trusted_inbound's roots (which listedhost_api/src, part of which moved) and the extension-specificity allowlist entry forsurface.rswas repointed, so neither guard silently lost coverage over relocated code.members,[package.metadata.ironclaw] layer = "contracts",classify-test-scope.sh's shared arm, andreborn-crate-test-buckets.sh'sextension-operatorbucket (besideextension_host/extensions— the bucket groups by what a change to it can break, not by layer). Verified, not assumed:discover-reborn-package-crates.shresolves it through the shipped-binary closure and needs no allowlist entry;test-classify-test-scope.shandtest-reborn-crate-test-buckets.shboth pass and the bash/python crate inventories agree at 65.#![warn(unreachable_pub)], a directory-of-moduleslib.rswith no prelude and no cross-module re-export (same shapehost_apitook after de-wildcarding), and no sealed traits — deliberately.agent_loop::plannerseals to close a strategy set; every trait here exists to be implemented outside the crate (PreferenceTargetCodecby the channel packages,Extension/ChannelIdentity*by extension implementations and their hosts), so sealing would forbid the extensibility the unified extension model is built on. The crate guide records that so the absence reads as a decision.CLAUDE.md(admission test, module table, the interim placements above), acrates/AGENTS.mdrow, and the livedocs/reborn/references repointed (extension-runtime/checklist.md,extension-runtime/implementation.md,auth/recipe-parity-checklist.md,ironclaw_auth/CLAUDE.md). Dateddocs/superpowers/plans/*records were left alone — they are historical artifacts, not live guidance.One deliberate public-API widening
HostApiError::invalid_idwent frompub(crate)topub.package_lifecycle'sbounded_lifecycle_string!template constructsHostApiErrorthrough it, and acontracts crate carved out of
host_apikeeps reporting its validationfailures as
HostApiError— introducing a parallel error type for the samecontract failures, or re-inlining the variant at every future carve-out, is how
the message text drifts apart. The variant itself was already public; this is
its canonical constructor, and the reason is in the code beside it.
Un-masking
ironclaw_host_api379 → 335 tests (−44);ironclaw_extension_contractshas exactly 44, and set-differencing the two rosters leaves zero unaccounted names in either direction.No test was edited for content — shown, not asserted. A rename-aware content diff over the moved modules leaves exactly three non-import deltas in the whole move: rustfmt re-wrapping two match arms in
channel.rs(the longerironclaw_host_api::http::path re-flows the line), theinvalid_idvisibility change above, and the codec extraction (−54 fromoutbound.rs, +67 inpreference_target.rs— body byte-identical, the delta is its new module doc).Verification
Lean gauntlet, all local (see the CI note below):
cargo fmt --all -- --checkclean.cargo clippy --all-targets --all-features -- -D warningsover all 15 touched crates: zero warnings.cargo test -p <crate> --all-features: green.ironclaw_architecturesuite green (33 boundary tests + every sibling ratchet), including the two new scans. Two enumerating gates failed first and were fixed rather than relaxed — the composition pub-use snapshot still carriedpub use ironclaw_product::PreferenceTargetCodec;, and the CLI's exact-dependency allowlist did not know the new crate. Both failed loudly because they compare an explicit list; that is the property this PR's own scans were built with.cargo check --workspace --all-targets --all-featuresclean, run last, after everypub usedeletion — workspace-roottests/targets are invisible to-planes.cargo metadata --lockedresolves. The crate's first lock entry pinnedthiserror 2.0.18/toml 1.1.2, versions with no[[package]]block after the parent's collapse against main; reconciled in its own commit so--lockedlanes resolve.scripts/reborn-e2e-rust.shexecuted, each matching exactly one test (grep -Fcx= 1), rather than eyeballed.include_str!reaches into any file this PR moved code out of (checked against the moved modules,product_adapter/outbound.rs, and the deletedextension_host/src/state.rs).check_no_panics.py --reborn-baseline(1158 files, baseline matches — the moved files carried no baselined panic sites, so unusually for agit mvno baseline regeneration is owed),critical_mutation_gate.py --selection-onlyagainst this diff (resolves; its manifest names no moved file),check-composition-budget.sh(the new crate shifts the denominator; 840/1122 dispatch, inside),check-include-str-paths.sh, andcheck-reborn-branch-coverage-flags.py.Known debt, recorded not hidden
ironclaw_auth::idsdeclares its ownLifecyclePackageRef(validated_string!,src/ids.rs:188) beside the onepackage_lifecycledeclares (bounded_lifecycle_string!). Both are macro-generated, so neither is discoverable by apub structwalk, and the workspace carries two same-named types for one concept. Recorded in the scanner's module doc rather than silently passed; unifying them is a domain change, not a contracts extraction.as Reborn*aliases (RebornChannelConnectStrategy,RebornChannelConfigFieldinproduct::reborn_services) are a second name for extension-tier vocabulary, not just a second path. Retiring theReborn*prefix is CHECKLIST WS10's type-name row across ~20 call sites, and is not smuggled in here; the scan's scope note says so explicitly.ironclaw_product'sLifecycle*re-export is deliberately out of the one-import-path half: §6.1.3 assignspackage_lifecycletoproduct_contracts, so that re-export points toward the type's target home. WS1.4 settles it.CI note
While this PR targets
ws1/loop-contracts, the fourpull_request: branches: [main]-gated workflows (reborn-tests,reborn-e2e,platform-and-compat,history-check) do not attach. The evidence above is local. Full Reborn workflow dispatched against this branch: https://github.com/nearai/ironclaw/actions/runs/30665278857 at head00c1d5cd4(matching this PR's HEAD exactly). It is not a PR status — it is the evidence backing the architecture, crate-bucket, and root/group lanes while stacked. Coverage-floor recapture and any changed-coverage exemption are deliberately not pre-written: the exemption step ispull_request/merge_group-gated and produces no artifact under dispatch, so entries would be guesses. Both obligations are executed in steward mode once real gate output exists.