Skip to content

refactor(contracts): extract ironclaw_extension_contracts and close the dual import paths (WS1.3) - #6977

Merged
BenKurrek merged 29 commits into
mainfrom
ws1/extension-contracts
Jul 31, 2026
Merged

BenKurrek merged 29 commits into
mainfrom
ws1/extension-contracts

Conversation

@BenKurrek

@BenKurrek BenKurrek commented Jul 31, 2026 •

Copy link
Copy Markdown
Collaborator

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_api into crates/ironclaw_extension_contracts, repoint every consumer, and close the dual import paths. Flat crate directory today; the contracts/ family directory arrives in Wave 5.

git mv moved eight modules with 96–100% similarity, so the diff reads as a move, not a rewrite:

Module Owns
channel ChannelDescriptor / ChannelIngressDescriptor / ChannelEgressDescriptor / ChannelPresentation + connection strategy, notices, validators
channel_identity ChannelConnectionScopeSource, ChannelIdentityPostBind(Factory), ChannelIdentityOverride
extension Extension, ExtensionContract, ExtensionRuntimeIdentity, ExtensionInstanceId, ExtensionHostAssemblyConfig
memory MemoryDescriptor, MemoryLifecycleHook (the [memory] manifest surface)
package_lifecycle the Lifecycle* projection set, ChannelConnectStrategy, ChannelConfigField
preference_target PreferenceTargetCodec + PreferenceTargetEncodeRequest (extracted from product_adapter::outbound)
recipe VendorAuthRecipe, OAuth2CodeRecipe, PkceMode, ingress-verification recipes, …
state InstallationState, LifecyclePublicState
surface CapabilitySurfaceKind

Five dispositions the lead sheet did not predict

1. ChannelAdapter, ToolAdapter, and RestrictedEgress did not move — and cannot until WS1.4. host_api::product_surface names both in ChannelInboundProductSurface::admit_channel_inbound_with_attachment_transfer(request, Arc<dyn ChannelAdapter>, Arc<dyn RestrictedEgress>), and that file also holds ProductSurface itself — unambiguously PROPOSAL §6.1.3 material that cannot come to this crate. ironclaw_host_api's dependency allowlist is "no ironclaw_*" (pinned in reborn_dependency_boundaries.rs), so a type leaving host_api while a type staying in host_api names it is mechanically impossible. The dependency runs one way only — §6.1.3 lets product_contracts depend on extension_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_lifecycle moved as a forced co-mover, and §6.1.3 may want it back. It is typed on InstallationState, LifecyclePublicState, ChannelPresentation, and CapabilitySurfaceKind — 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 in host_api. §6.1.3 assigns it to product_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's CLAUDE.md, not presented as a decision.

3. AuthAccountState is not in host_api::state. It is ironclaw_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 without AuthAccountLastError and project_auth_account_state splits a state machine from its projection, which is a domain call, not a contracts extraction. The row's "(today host_api::state)" is wrong for one of its three names.

4. ReplyTargetBindingRef was already home. It is a bounded_ref! in host_api::turn (turn.rs:280) — WS1.1's canonical turn vocabulary. Moving it here would undo that consolidation and force loop_host, product, and composition onto extension_contracts for turn vocabulary. §6.1.2's stated rationale for naming it — "the product/turns types that force telegram_extension's upward edges" — is satisfied without it (see below).

5. The dual import path was worse than "a re-export". PreferenceTargetCodec had three paths: host_api::product_adapter (Slack's), ironclaw_product (Telegram's, which carried a forbidden product dependency to reach it), and ironclaw_reborn_composition, which re-exported product's re-export. InstallationState had a second path through ironclaw_extension_host::state — a facade with no external consumer whose own crate then used crate::InstallationState internally. All are deleted, extension_host/src/state.rs with them.

What that bought

ironclaw_telegram_extension dropped ironclaw_product entirely — 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 forbade product), so the edge cannot come back. The dead [dev-dependencies] ironclaw_product entry beside it went too; its stated purpose (FakeProtocolHttpEgress, mark_shared_secret_header_verified) is served by the ironclaw_host_api dev-dep that actually owns them.

Also forced, and amended in place with evidence rather than waived: ironclaw_loop_contracts gained an ironclaw_extension_contracts dependency, because LoopRuntimeContext carries Option<ChannelPresentation> and render_presentation_hint reads 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_EXCEPTIONS was re-read against this branch's base. Not one is a host_api edge, so no contracts carve-out from host_api can 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* in ironclaw_extensions), which §6.1.2 explicitly forbids this crate from absorbing and which CHECKLIST WS3's mcp row owns. The count stays at 13.

What this PR does delete is a forbidden edge the layer matrix never saw: telegram_extension → product is legal by layer (both are products) and forbidden by §8.2's channel-package row. It is gone and now pinned.

New-crate rule inventory

  • §11.2.3 contracts purity — internal-dependency allowlist (ironclaw_host_api only; 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.
  • §11.2.4 port-location scan — new 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 may pub use one. 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 new ironclaw_telegram_extension rule described above.
  • Scan reach preserved: the crate joined untrusted_ingress_paths_cannot_submit_host_trusted_inbound's roots (which listed host_api/src, part of which moved) and the extension-specificity allowlist entry for surface.rs was repointed, so neither guard silently lost coverage over relocated code.
  • CI lane selectors: root members, [package.metadata.ironclaw] layer = "contracts", classify-test-scope.sh's shared arm, and reborn-crate-test-buckets.sh's extension-operator bucket (beside extension_host/extensions — the bucket groups by what a change to it can break, not by layer). Verified, not assumed: discover-reborn-package-crates.sh resolves it through the shipped-binary closure and needs no allowlist entry; test-classify-test-scope.sh and test-reborn-crate-test-buckets.sh both pass and the bash/python crate inventories agree at 65.
  • Visibility kit: #![warn(unreachable_pub)], a directory-of-modules lib.rs with no prelude and no cross-module re-export (same shape host_api took after de-wildcarding), and no sealed traits — deliberately. agent_loop::planner seals to close a strategy set; every trait here exists to be implemented outside the crate (PreferenceTargetCodec by 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.
  • Guidance: crate CLAUDE.md (admission test, module table, the interim placements above), a crates/AGENTS.md row, and the live docs/reborn/ references repointed (extension-runtime/checklist.md, extension-runtime/implementation.md, auth/recipe-parity-checklist.md, ironclaw_auth/CLAUDE.md). Dated docs/superpowers/plans/* records were left alone — they are historical artifacts, not live guidance.

One deliberate public-API widening

HostApiError::invalid_id went from pub(crate) to pub. package_lifecycle's
bounded_lifecycle_string! template constructs HostApiError through it, and a
contracts crate carved out of host_api keeps reporting its validation
failures as HostApiError — introducing a parallel error type for the same
contract 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_api 379 → 335 tests (−44); ironclaw_extension_contracts has 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 longer ironclaw_host_api::http:: path re-flows the line), the invalid_id visibility change above, and the codec extraction (−54 from outbound.rs, +67 in preference_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 -- --check clean.
  • Per-touched-crate cargo clippy --all-targets --all-features -- -D warnings over all 15 touched crates: zero warnings.
  • Per-touched-crate unfiltered cargo test -p <crate> --all-features: green.
  • Full ironclaw_architecture suite 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 carried pub 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-features clean, run last, after every pub use deletion — workspace-root tests/ targets are invisible to -p lanes.
  • cargo metadata --locked resolves. The crate's first lock entry pinned thiserror 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 --locked lanes resolve.
  • All 10 exact-test selectors in scripts/reborn-e2e-rust.sh executed, each matching exactly one test (grep -Fcx = 1), rather than eyeballed.
  • No cross-crate include_str! reaches into any file this PR moved code out of (checked against the moved modules, product_adapter/outbound.rs, and the deleted extension_host/src/state.rs).
  • The repo-wide gates a new crate or a moved file can silently break, all run locally and green: check_no_panics.py --reborn-baseline (1158 files, baseline matches — the moved files carried no baselined panic sites, so unusually for a git mv no baseline regeneration is owed), critical_mutation_gate.py --selection-only against 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, and check-reborn-branch-coverage-flags.py.

Known debt, recorded not hidden

  • A shadow type this scan cannot see. ironclaw_auth::ids declares its own LifecyclePackageRef (validated_string!, src/ids.rs:188) beside the one package_lifecycle declares (bounded_lifecycle_string!). Both are macro-generated, so neither is discoverable by a pub struct walk, 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.
  • Two as Reborn* aliases (RebornChannelConnectStrategy, RebornChannelConfigField in product::reborn_services) are a second name for extension-tier vocabulary, not just a second path. Retiring the Reborn* 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's Lifecycle* re-export is deliberately out of the one-import-path half: §6.1.3 assigns package_lifecycle to product_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 four pull_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 head 00c1d5cd4 (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 is pull_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.

BenKurrek and others added 19 commits July 31, 2026 11:59
…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>
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

@coderabbitai

coderabbitai Bot commented Jul 31, 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: 79cc8f51-db14-49b6-b6e1-0527479cddba

📥 Commits

Reviewing files that changed from the base of the PR and between 6c0cc6c and c71cf8b.

📒 Files selected for processing (3)
  • crates/ironclaw_extension_contracts/src/channel.rs
  • crates/ironclaw_extension_contracts/src/extension.rs
  • tests/integration/changed-coverage-exemptions.toml

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Added shared extension contracts for channels, memory, authentication, lifecycle, state, and preference targets.
    • Added memory lifecycle declarations, public lifecycle states, and preference-target encoding interfaces.
    • Added validation and architecture checks for contract ownership and dependency boundaries.
  • Refactor

    • Migrated extension integrations to the shared contracts package.
    • Removed obsolete contract exports and duplicate import paths.
    • Preserved existing validation and runtime behavior.
  • Documentation

    • Updated architecture guides, checklists, and crate documentation.

Walkthrough

The PR creates ironclaw_extension_contracts, moves shared extension vocabulary out of ironclaw_host_api, updates dependent crates and tests, removes legacy re-exports, and adds architecture and CI enforcement for contract ownership and dependency boundaries.

Changes

Extension contracts extraction

Layer / File(s) Summary
Contract crate and contract definitions
crates/ironclaw_extension_contracts/*, Cargo.toml
Adds module-qualified channel, extension, hosted MCP, memory, lifecycle, preference-target, recipe, state, and surface contracts.
Legacy ownership removal
crates/ironclaw_host_api/*, crates/ironclaw_extension_host/src/{lib.rs,state.rs}, crates/ironclaw_product/src/lib.rs
Removes relocated module exports, preference-target re-exports, and the extension-host state module.
Consumer migration
crates/ironclaw_auth/*, crates/ironclaw_extension_host/*, crates/ironclaw_extensions/*, crates/ironclaw_host_runtime/*, crates/ironclaw_product/*, crates/ironclaw_reborn_composition/*, crates/ironclaw_*_extension/*, crates/ironclaw_webui/*
Updates dependencies, public types, imports, hosted MCP flows, memory descriptors, recipes, egress descriptors, lifecycle states, and preference-target trait objects.
Architecture and CI enforcement
crates/ironclaw_architecture/tests/*, crates/AGENTS.md, crates/ironclaw_extension_contracts/CLAUDE.md, docs/reborn/*, scripts/ci/*
Registers the crate and enforces dependency, ownership, import-path, ingress, test-scope, and test-bucket rules.
Integration validation
tests/integration/*
Migrates memory and hosted MCP fixtures and assertions to the contract types.

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

Possibly related PRs

Suggested reviewers: ilblackdragon

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title follows Conventional Commits style and clearly describes the contract extraction and removal of duplicate import paths.
Description check ✅ Passed The detailed description covers the change scope, design decisions, validation evidence, risks, known debt, and linked stacked work.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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.

@railway-app

railway-app Bot commented Jul 31, 2026 •

Copy link
Copy Markdown

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

Service Status Web Updated (UTC)
ironclaw ✅ Success (View Logs) Web Jul 31, 2026 at 11:49 pm

@railway-app
railway-app Bot temporarily deployed to ironclaw-ci-preview / ironclaw-pr-6977 July 31, 2026 21:01 Destroyed
@github-actions github-actions Bot added scope: docs Documentation scope: dependencies Dependency updates size: XL 500+ changed lines risk: medium Business logic, config, or moderate-risk modules contributor: core 20+ merged PRs labels Jul 31, 2026
…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>
@railway-app
railway-app Bot temporarily deployed to ironclaw-ci-preview / ironclaw-pr-6977 July 31, 2026 21:04 Destroyed

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

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

Inline comments:
In
`@crates/ironclaw_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

📥 Commits

Reviewing files that changed from the base of the PR and between 9ae415a and f29a9aa.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock, !**/Cargo.lock
📒 Files selected for processing (144)
  • Cargo.toml
  • crates/AGENTS.md
  • crates/ironclaw_architecture/tests/reborn_dependency_boundaries.rs
  • crates/ironclaw_architecture/tests/reborn_extension_contract_location_scan.rs
  • crates/ironclaw_architecture/tests/reborn_extension_specificity.rs
  • crates/ironclaw_auth/CLAUDE.md
  • crates/ironclaw_auth/Cargo.toml
  • crates/ironclaw_auth/src/engine/admission.rs
  • crates/ironclaw_auth/src/engine/dcr.rs
  • crates/ironclaw_auth/src/engine/exchange.rs
  • crates/ironclaw_auth/src/engine/keepalive.rs
  • crates/ironclaw_auth/src/engine/mod.rs
  • crates/ironclaw_auth/src/product_auth/oauth/oauth_gate.rs
  • crates/ironclaw_auth/tests/auth_engine_contract.rs
  • crates/ironclaw_capabilities/Cargo.toml
  • crates/ironclaw_capabilities/src/registry.rs
  • crates/ironclaw_extension_contracts/CLAUDE.md
  • crates/ironclaw_extension_contracts/Cargo.toml
  • crates/ironclaw_extension_contracts/src/channel.rs
  • crates/ironclaw_extension_contracts/src/channel_identity.rs
  • crates/ironclaw_extension_contracts/src/extension.rs
  • crates/ironclaw_extension_contracts/src/hosted_mcp.rs
  • crates/ironclaw_extension_contracts/src/lib.rs
  • crates/ironclaw_extension_contracts/src/memory.rs
  • crates/ironclaw_extension_contracts/src/package_lifecycle.rs
  • crates/ironclaw_extension_contracts/src/preference_target.rs
  • crates/ironclaw_extension_contracts/src/recipe.rs
  • crates/ironclaw_extension_contracts/src/state.rs
  • crates/ironclaw_extension_contracts/src/surface.rs
  • crates/ironclaw_extension_host/Cargo.toml
  • crates/ironclaw_extension_host/src/active.rs
  • crates/ironclaw_extension_host/src/active_publication.rs
  • crates/ironclaw_extension_host/src/available_extensions.rs
  • crates/ironclaw_extension_host/src/channel_config.rs
  • crates/ironclaw_extension_host/src/channel_connection.rs
  • crates/ironclaw_extension_host/src/channel_dm_provisioning.rs
  • crates/ironclaw_extension_host/src/channel_host.rs
  • crates/ironclaw_extension_host/src/channel_host/e2e_tests.rs
  • crates/ironclaw_extension_host/src/channel_identity.rs
  • crates/ironclaw_extension_host/src/channel_identity_binding.rs
  • crates/ironclaw_extension_host/src/channel_outbound_targets.rs
  • crates/ironclaw_extension_host/src/channel_subject_routes.rs
  • crates/ironclaw_extension_host/src/channel_triggered_delivery.rs
  • crates/ironclaw_extension_host/src/egress.rs
  • crates/ironclaw_extension_host/src/extension_lifecycle_capabilities.rs
  • crates/ironclaw_extension_host/src/extension_lifecycle_command.rs
  • crates/ironclaw_extension_host/src/generic_host.rs
  • crates/ironclaw_extension_host/src/hosted_mcp_admission.rs
  • crates/ironclaw_extension_host/src/hosted_mcp_manifest.rs
  • crates/ironclaw_extension_host/src/hosted_mcp_preparation.rs
  • crates/ironclaw_extension_host/src/ingress/router.rs
  • crates/ironclaw_extension_host/src/ingress/verifier.rs
  • crates/ironclaw_extension_host/src/ironhub/service.rs
  • crates/ironclaw_extension_host/src/lib.rs
  • crates/ironclaw_extension_host/src/lifecycle.rs
  • crates/ironclaw_extension_host/src/lifecycle_product_service.rs
  • crates/ironclaw_extension_host/src/mcp_discovery.rs
  • crates/ironclaw_extension_host/src/product_lifecycle.rs
  • crates/ironclaw_extension_host/src/recipes.rs
  • crates/ironclaw_extension_host/src/state.rs
  • crates/ironclaw_extension_host/src/store.rs
  • crates/ironclaw_extension_host/src/test_support.rs
  • crates/ironclaw_extension_host/src/test_support/lifecycle.rs
  • crates/ironclaw_extension_host/tests/ingress_router_contract.rs
  • crates/ironclaw_extension_host/tests/lifecycle_contract.rs
  • crates/ironclaw_extensions/Cargo.toml
  • crates/ironclaw_extensions/src/package.rs
  • crates/ironclaw_extensions/src/resolved.rs
  • crates/ironclaw_extensions/src/v2.rs
  • crates/ironclaw_extensions/src/v3.rs
  • crates/ironclaw_extensions/tests/manifest_v2_contract.rs
  • crates/ironclaw_extensions/tests/manifest_v3_contract.rs
  • crates/ironclaw_host_api/src/error.rs
  • crates/ironclaw_host_api/src/lib.rs
  • crates/ironclaw_host_api/src/product_adapter/mod.rs
  • crates/ironclaw_host_api/src/product_adapter/outbound.rs
  • crates/ironclaw_host_runtime/Cargo.toml
  • crates/ironclaw_host_runtime/src/egress/sanitize.rs
  • crates/ironclaw_host_runtime/src/memory_context.rs
  • crates/ironclaw_host_runtime/src/memory_native_extension.rs
  • crates/ironclaw_host_runtime/tests/memory_prompt_context.rs
  • crates/ironclaw_loop_contracts/Cargo.toml
  • crates/ironclaw_loop_contracts/src/runtime_context.rs
  • crates/ironclaw_mcp/Cargo.toml
  • crates/ironclaw_mcp/src/lib.rs
  • crates/ironclaw_product/Cargo.toml
  • crates/ironclaw_product/src/adapter_registry.rs
  • crates/ironclaw_product/src/auth_prompt.rs
  • crates/ironclaw_product/src/commands.rs
  • crates/ironclaw_product/src/communication_context.rs
  • crates/ironclaw_product/src/lib.rs
  • crates/ironclaw_product/src/lifecycle.rs
  • crates/ironclaw_product/src/reborn_services.rs
  • crates/ironclaw_product/src/reborn_services/extension_onboarding.rs
  • crates/ironclaw_product/src/reborn_services/extensions.rs
  • crates/ironclaw_product/src/reborn_services/lifecycle_setup.rs
  • crates/ironclaw_product/src/reborn_services/product_capability_handlers.rs
  • crates/ironclaw_product/src/reborn_services/product_commands.rs
  • crates/ironclaw_product/src/reborn_services/types.rs
  • crates/ironclaw_product/src/run_delivery/triggered.rs
  • crates/ironclaw_product/tests/adapter_registry_manifest_ingestion.rs
  • crates/ironclaw_product/tests/reborn_services_contract.rs
  • crates/ironclaw_product/tests/run_delivery_contract.rs
  • crates/ironclaw_reborn_cli/Cargo.toml
  • crates/ironclaw_reborn_cli/src/commands/extension.rs
  • crates/ironclaw_reborn_composition/Cargo.toml
  • crates/ironclaw_reborn_composition/src/extension_host_assembly.rs
  • crates/ironclaw_reborn_composition/src/factory.rs
  • crates/ironclaw_reborn_composition/src/factory/auth_engine_assembly.rs
  • crates/ironclaw_reborn_composition/src/factory/auth_tests.rs
  • crates/ironclaw_reborn_composition/src/factory/tests.rs
  • crates/ironclaw_reborn_composition/src/input.rs
  • crates/ironclaw_reborn_composition/src/lib.rs
  • crates/ironclaw_reborn_composition/src/llm_admin/nearai_mcp.rs
  • crates/ironclaw_reborn_composition/src/memory_provider_factory.rs
  • crates/ironclaw_reborn_composition/src/runtime.rs
  • crates/ironclaw_reborn_composition/src/runtime/tests/core.rs
  • crates/ironclaw_reborn_composition/src/test_support/channel_connection.rs
  • crates/ironclaw_reborn_composition/src/test_support/oauth_product_auth.rs
  • crates/ironclaw_reborn_composition/tests/first_party_manifest_v3_parity.rs
  • crates/ironclaw_reborn_composition/tests/memory_mem0_swap.rs
  • crates/ironclaw_reborn_composition/tests/webui_v2_product_auth.rs
  • crates/ironclaw_reborn_composition/tests/webui_v2_serve.rs
  • crates/ironclaw_slack_extension/Cargo.toml
  • crates/ironclaw_slack_extension/src/preference_targets.rs
  • crates/ironclaw_telegram_extension/Cargo.toml
  • crates/ironclaw_telegram_extension/src/lib.rs
  • crates/ironclaw_telegram_extension/src/preference_targets.rs
  • crates/ironclaw_webui/Cargo.toml
  • crates/ironclaw_webui/src/product_auth/mod.rs
  • crates/ironclaw_webui/src/product_auth/oauth_start_tests.rs
  • crates/ironclaw_webui/src/webui_v2/handlers.rs
  • crates/ironclaw_webui/tests/webui_v2_handlers_contract.rs
  • docs/plans/composition-pubuse.snapshot
  • docs/reborn/auth/recipe-parity-checklist.md
  • docs/reborn/extension-runtime/checklist.md
  • docs/reborn/extension-runtime/implementation.md
  • docs/reborn/target-architecture/CHECKLIST.md
  • scripts/ci/classify-test-scope.sh
  • scripts/ci/reborn-crate-test-buckets.sh
  • tests/integration/group_memory/scenario_lifecycle_gates_host_memory_calls.rs
  • tests/integration/hosted_mcp_registration.rs
  • tests/integration/support/group.rs
  • tests/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

Comment thread crates/ironclaw_extension_contracts/CLAUDE.md Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

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

Actionable comments posted: 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

📥 Commits

Reviewing files that changed from the base of the PR and between 9ae415a and f29a9aa.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock, !**/Cargo.lock
📒 Files selected for processing (144)
  • Cargo.toml
  • crates/AGENTS.md
  • crates/ironclaw_architecture/tests/reborn_dependency_boundaries.rs
  • crates/ironclaw_architecture/tests/reborn_extension_contract_location_scan.rs
  • crates/ironclaw_architecture/tests/reborn_extension_specificity.rs
  • crates/ironclaw_auth/CLAUDE.md
  • crates/ironclaw_auth/Cargo.toml
  • crates/ironclaw_auth/src/engine/admission.rs
  • crates/ironclaw_auth/src/engine/dcr.rs
  • crates/ironclaw_auth/src/engine/exchange.rs
  • crates/ironclaw_auth/src/engine/keepalive.rs
  • crates/ironclaw_auth/src/engine/mod.rs
  • crates/ironclaw_auth/src/product_auth/oauth/oauth_gate.rs
  • crates/ironclaw_auth/tests/auth_engine_contract.rs
  • crates/ironclaw_capabilities/Cargo.toml
  • crates/ironclaw_capabilities/src/registry.rs
  • crates/ironclaw_extension_contracts/CLAUDE.md
  • crates/ironclaw_extension_contracts/Cargo.toml
  • crates/ironclaw_extension_contracts/src/channel.rs
  • crates/ironclaw_extension_contracts/src/channel_identity.rs
  • crates/ironclaw_extension_contracts/src/extension.rs
  • crates/ironclaw_extension_contracts/src/hosted_mcp.rs
  • crates/ironclaw_extension_contracts/src/lib.rs
  • crates/ironclaw_extension_contracts/src/memory.rs
  • crates/ironclaw_extension_contracts/src/package_lifecycle.rs
  • crates/ironclaw_extension_contracts/src/preference_target.rs
  • crates/ironclaw_extension_contracts/src/recipe.rs
  • crates/ironclaw_extension_contracts/src/state.rs
  • crates/ironclaw_extension_contracts/src/surface.rs
  • crates/ironclaw_extension_host/Cargo.toml
  • crates/ironclaw_extension_host/src/active.rs
  • crates/ironclaw_extension_host/src/active_publication.rs
  • crates/ironclaw_extension_host/src/available_extensions.rs
  • crates/ironclaw_extension_host/src/channel_config.rs
  • crates/ironclaw_extension_host/src/channel_connection.rs
  • crates/ironclaw_extension_host/src/channel_dm_provisioning.rs
  • crates/ironclaw_extension_host/src/channel_host.rs
  • crates/ironclaw_extension_host/src/channel_host/e2e_tests.rs
  • crates/ironclaw_extension_host/src/channel_identity.rs
  • crates/ironclaw_extension_host/src/channel_identity_binding.rs
  • crates/ironclaw_extension_host/src/channel_outbound_targets.rs
  • crates/ironclaw_extension_host/src/channel_subject_routes.rs
  • crates/ironclaw_extension_host/src/channel_triggered_delivery.rs
  • crates/ironclaw_extension_host/src/egress.rs
  • crates/ironclaw_extension_host/src/extension_lifecycle_capabilities.rs
  • crates/ironclaw_extension_host/src/extension_lifecycle_command.rs
  • crates/ironclaw_extension_host/src/generic_host.rs
  • crates/ironclaw_extension_host/src/hosted_mcp_admission.rs
  • crates/ironclaw_extension_host/src/hosted_mcp_manifest.rs
  • crates/ironclaw_extension_host/src/hosted_mcp_preparation.rs
  • crates/ironclaw_extension_host/src/ingress/router.rs
  • crates/ironclaw_extension_host/src/ingress/verifier.rs
  • crates/ironclaw_extension_host/src/ironhub/service.rs
  • crates/ironclaw_extension_host/src/lib.rs
  • crates/ironclaw_extension_host/src/lifecycle.rs
  • crates/ironclaw_extension_host/src/lifecycle_product_service.rs
  • crates/ironclaw_extension_host/src/mcp_discovery.rs
  • crates/ironclaw_extension_host/src/product_lifecycle.rs
  • crates/ironclaw_extension_host/src/recipes.rs
  • crates/ironclaw_extension_host/src/state.rs
  • crates/ironclaw_extension_host/src/store.rs
  • crates/ironclaw_extension_host/src/test_support.rs
  • crates/ironclaw_extension_host/src/test_support/lifecycle.rs
  • crates/ironclaw_extension_host/tests/ingress_router_contract.rs
  • crates/ironclaw_extension_host/tests/lifecycle_contract.rs
  • crates/ironclaw_extensions/Cargo.toml
  • crates/ironclaw_extensions/src/package.rs
  • crates/ironclaw_extensions/src/resolved.rs
  • crates/ironclaw_extensions/src/v2.rs
  • crates/ironclaw_extensions/src/v3.rs
  • crates/ironclaw_extensions/tests/manifest_v2_contract.rs
  • crates/ironclaw_extensions/tests/manifest_v3_contract.rs
  • crates/ironclaw_host_api/src/error.rs
  • crates/ironclaw_host_api/src/lib.rs
  • crates/ironclaw_host_api/src/product_adapter/mod.rs
  • crates/ironclaw_host_api/src/product_adapter/outbound.rs
  • crates/ironclaw_host_runtime/Cargo.toml
  • crates/ironclaw_host_runtime/src/egress/sanitize.rs
  • crates/ironclaw_host_runtime/src/memory_context.rs
  • crates/ironclaw_host_runtime/src/memory_native_extension.rs
  • crates/ironclaw_host_runtime/tests/memory_prompt_context.rs
  • crates/ironclaw_loop_contracts/Cargo.toml
  • crates/ironclaw_loop_contracts/src/runtime_context.rs
  • crates/ironclaw_mcp/Cargo.toml
  • crates/ironclaw_mcp/src/lib.rs
  • crates/ironclaw_product/Cargo.toml
  • crates/ironclaw_product/src/adapter_registry.rs
  • crates/ironclaw_product/src/auth_prompt.rs
  • crates/ironclaw_product/src/commands.rs
  • crates/ironclaw_product/src/communication_context.rs
  • crates/ironclaw_product/src/lib.rs
  • crates/ironclaw_product/src/lifecycle.rs
  • crates/ironclaw_product/src/reborn_services.rs
  • crates/ironclaw_product/src/reborn_services/extension_onboarding.rs
  • crates/ironclaw_product/src/reborn_services/extensions.rs
  • crates/ironclaw_product/src/reborn_services/lifecycle_setup.rs
  • crates/ironclaw_product/src/reborn_services/product_capability_handlers.rs
  • crates/ironclaw_product/src/reborn_services/product_commands.rs
  • crates/ironclaw_product/src/reborn_services/types.rs
  • crates/ironclaw_product/src/run_delivery/triggered.rs
  • crates/ironclaw_product/tests/adapter_registry_manifest_ingestion.rs
  • crates/ironclaw_product/tests/reborn_services_contract.rs
  • crates/ironclaw_product/tests/run_delivery_contract.rs
  • crates/ironclaw_reborn_cli/Cargo.toml
  • crates/ironclaw_reborn_cli/src/commands/extension.rs
  • crates/ironclaw_reborn_composition/Cargo.toml
  • crates/ironclaw_reborn_composition/src/extension_host_assembly.rs
  • crates/ironclaw_reborn_composition/src/factory.rs
  • crates/ironclaw_reborn_composition/src/factory/auth_engine_assembly.rs
  • crates/ironclaw_reborn_composition/src/factory/auth_tests.rs
  • crates/ironclaw_reborn_composition/src/factory/tests.rs
  • crates/ironclaw_reborn_composition/src/input.rs
  • crates/ironclaw_reborn_composition/src/lib.rs
  • crates/ironclaw_reborn_composition/src/llm_admin/nearai_mcp.rs
  • crates/ironclaw_reborn_composition/src/memory_provider_factory.rs
  • crates/ironclaw_reborn_composition/src/runtime.rs
  • crates/ironclaw_reborn_composition/src/runtime/tests/core.rs
  • crates/ironclaw_reborn_composition/src/test_support/channel_connection.rs
  • crates/ironclaw_reborn_composition/src/test_support/oauth_product_auth.rs
  • crates/ironclaw_reborn_composition/tests/first_party_manifest_v3_parity.rs
  • crates/ironclaw_reborn_composition/tests/memory_mem0_swap.rs
  • crates/ironclaw_reborn_composition/tests/webui_v2_product_auth.rs
  • crates/ironclaw_reborn_composition/tests/webui_v2_serve.rs
  • crates/ironclaw_slack_extension/Cargo.toml
  • crates/ironclaw_slack_extension/src/preference_targets.rs
  • crates/ironclaw_telegram_extension/Cargo.toml
  • crates/ironclaw_telegram_extension/src/lib.rs
  • crates/ironclaw_telegram_extension/src/preference_targets.rs
  • crates/ironclaw_webui/Cargo.toml
  • crates/ironclaw_webui/src/product_auth/mod.rs
  • crates/ironclaw_webui/src/product_auth/oauth_start_tests.rs
  • crates/ironclaw_webui/src/webui_v2/handlers.rs
  • crates/ironclaw_webui/tests/webui_v2_handlers_contract.rs
  • docs/plans/composition-pubuse.snapshot
  • docs/reborn/auth/recipe-parity-checklist.md
  • docs/reborn/extension-runtime/checklist.md
  • docs/reborn/extension-runtime/implementation.md
  • docs/reborn/target-architecture/CHECKLIST.md
  • scripts/ci/classify-test-scope.sh
  • scripts/ci/reborn-crate-test-buckets.sh
  • tests/integration/group_memory/scenario_lifecycle_gates_host_memory_calls.rs
  • tests/integration/hosted_mcp_registration.rs
  • tests/integration/support/group.rs
  • tests/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 InstallationState lives in ironclaw_host_api. This file now owns the type in ironclaw_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>
@railway-app
railway-app Bot temporarily deployed to ironclaw-ci-preview / ironclaw-pr-6977 July 31, 2026 23:06 Destroyed
@github-actions

github-actions Bot commented Jul 31, 2026 •

Copy link
Copy Markdown
Contributor

Coverage ratchet

Ratchet mode: ENFORCING

RATCHET PASS: global
  observed: 85.88% (323334 / 376497 lines)
  floor:    85.11% (tolerance 0.5pp -> effective floor 84.61%)
  denominator: 376497 lines now vs 375097 at floor capture (+1400 lines, +0.37%) — not a material change

RATCHET PASS: ironclaw_runner
  observed: 86% (15134 / 17597 lines)
  floor:    85.55% (tolerance 0.5pp -> effective floor 85.05%)
  floor_covered_lines: 14658 (tolerance 20 lines -> effective floor 14638)
  denominator: 17597 lines now vs 17133 at floor capture (+464 lines, +2.71%) — not a material change

RATCHET PASS: ironclaw_processes
  observed: 88.76% (5889 / 6635 lines)
  floor:    88.07% (tolerance 0.5pp -> effective floor 87.57%)
  floor_covered_lines: 5839 (tolerance 20 lines -> effective floor 5819)
  denominator: 6635 lines now vs 6630 at floor capture (+5 lines, +0.08%) — not a material change

RATCHET PASS: ironclaw_turns
  observed: 88.46% (3709 / 4193 lines)
  floor:    85.11% (tolerance 0.5pp -> effective floor 84.61%)

RATCHET PASS: ironclaw_authorization
  observed: 86.59% (723 / 835 lines)
  floor:    62.51% (tolerance 0.5pp -> effective floor 62.01%)
  floor_covered_lines: 612 (tolerance 20 lines -> effective floor 592)
  denominator: 835 lines now vs 979 at floor capture (-144 lines, -14.71%) — material change (>5%)

RATCHET PASS: ironclaw_approvals
  observed: 91.05% (1820 / 1999 lines)
  floor:    85.86% (tolerance 0.5pp -> effective floor 85.36%)
  floor_covered_lines: 1822 (tolerance 20 lines -> effective floor 1802)
  denominator: 1999 lines now vs 2122 at floor capture (-123 lines, -5.8%) — material change (>5%)

RATCHET PASS: ironclaw_secrets
  observed: 85.81% (2896 / 3375 lines)
  floor:    84.01% (tolerance 0.5pp -> effective floor 83.51%)
  floor_covered_lines: 2795 (tolerance 20 lines -> effective floor 2775)
  denominator: 3375 lines now vs 3327 at floor capture (+48 lines, +1.44%) — not a material change

RATCHET PASS: ironclaw_filesystem
  observed: 76.87% (5898 / 7673 lines)
  floor:    75.93% (tolerance 0.5pp -> effective floor 75.43%)
  floor_covered_lines: 5826 (tolerance 20 lines -> effective floor 5806)
  denominator: 7673 lines now vs 7673 at floor capture (+0 lines, +0%) — not a material change

RATCHET PASS: ironclaw_llm
  observed: 79.22% (20885 / 26364 lines)
  floor:    79.22% (tolerance 0.5pp -> effective floor 78.72%)
  floor_covered_lines: 20885 (tolerance 20 lines -> effective floor 20865)
  denominator: 26364 lines now vs 26364 at floor capture (+0 lines, +0%) — not a material change

RATCHET PASS: ironclaw_triggers
  observed: 94.88% (3092 / 3259 lines)
  floor:    86.04% (tolerance 0.5pp -> effective floor 85.54%)
  floor_covered_lines: 2804 (tolerance 20 lines -> effective floor 2784)
  denominator: 3259 lines now vs 3259 at floor capture (+0 lines, +0%) — not a material change

RATCHET PASS: ironclaw_product
  observed: 87.38% (22831 / 26129 lines)
  floor:    86.94% (tolerance 0.5pp -> effective floor 86.44%)
  floor_covered_lines: 21367 (tolerance 20 lines -> effective floor 21347)
  denominator: 26129 lines now vs 24576 at floor capture (+1553 lines, +6.32%) — material change (>5%)

RATCHET PASS: ironclaw_outbound
  observed: 94.68% (4271 / 4511 lines)
  floor:    93.49% (tolerance 0.5pp -> effective floor 92.99%)
  floor_covered_lines: 4105 (tolerance 20 lines -> effective floor 4085)
  denominator: 4511 lines now vs 4391 at floor capture (+120 lines, +2.73%) — not a material change

RATCHET PASS: ironclaw_extension_host
  observed: 84.99% (24339 / 28637 lines)
  floor:    83.82% (tolerance 0.5pp -> effective floor 83.32%)
  floor_covered_lines: 22271 (tolerance 20 lines -> effective floor 22251)
  denominator: 28637 lines now vs 26569 at floor capture (+2068 lines, +7.78%) — material change (>5%)

RATCHET PASS: ironclaw_events
  observed: 80.55% (1197 / 1486 lines)
  floor:    80.55% (tolerance 0.5pp -> effective floor 80.05%)
  floor_covered_lines: 1197 (tolerance 20 lines -> effective floor 1177)
  denominator: 1486 lines now vs 1486 at floor capture (+0 lines, +0%) — not a material change

RATCHET PASS: ironclaw_safety
  observed: 92.75% (4468 / 4817 lines)
  floor:    92.44% (tolerance 0.5pp -> effective floor 91.94%)
  floor_covered_lines: 3973 (tolerance 20 lines -> effective floor 3953)
  denominator: 4817 lines now vs 4298 at floor capture (+519 lines, +12.08%) — material change (>5%)

RATCHET PASS: ironclaw_host_runtime
  observed: 88.41% (21338 / 24135 lines)
  floor:    88.23% (tolerance 0.5pp -> effective floor 87.73%)
  floor_covered_lines: 20538 (tolerance 20 lines -> effective floor 20518)
  denominator: 24135 lines now vs 23277 at floor capture (+858 lines, +3.69%) — not a material change

Reborn integration-tier coverage

Line coverage (Reborn crates): 85.88% — 323334 / 376497 lines

Per-crate breakdown (62 crates, lowest-covered first)
Crate Line % Covered / Total
ironclaw_host_ingress 42.5% 17 / 40
ironclaw_memory 53.48% 630 / 1178
ironclaw_projects 72.36% 233 / 322
ironclaw_capabilities 74.59% 2876 / 3856
ironclaw_trust 75.79% 748 / 987
ironclaw_extractors 75.88% 538 / 709
ironclaw_reborn_cli 76.1% 11084 / 14566
ironclaw_observability 76.19% 32 / 42
ironclaw_filesystem 76.87% 5898 / 7673
ironclaw_wasm 78.84% 704 / 893
ironclaw_llm 79.22% 20885 / 26364
ironclaw_events 80.55% 1197 / 1486
ironclaw_loop_contracts 82.4% 5637 / 6841
ironclaw_first_party_extensions 82.57% 6784 / 8216
ironclaw_host_api 82.57% 8908 / 10788
ironclaw_memory_native 82.85% 2850 / 3440
ironclaw_libsql_runtime 83.3% 384 / 461
ironclaw_auth 83.95% 6699 / 7980
ironclaw_operator 84.47% 5309 / 6285
ironclaw_hooks 84.57% 9896 / 11702
ironclaw_event_projections 84.81% 854 / 1007
ironclaw_reborn_event_store 84.93% 1206 / 1420
ironclaw_extension_host 84.99% 24339 / 28637
ironclaw_reborn_config 85.29% 2110 / 2474
ironclaw_network 85.31% 894 / 1048
ironclaw_reborn_composition 85.51% 21794 / 25488
ironclaw_secrets 85.81% 2896 / 3375
ironclaw_runner 86% 15134 / 17597
ironclaw_authorization 86.59% 723 / 835
ironclaw_webui 86.95% 11935 / 13727
ironclaw_wasm_limiter 87.06% 74 / 85
ironclaw_common 87.33% 1641 / 1879
ironclaw_product 87.38% 22831 / 26129
ironclaw_reborn_traces 87.61% 11720 / 13377
ironclaw_extension_contracts 87.65% 1370 / 1563
ironclaw_scripts 87.87% 420 / 478
ironclaw_threads 88.14% 5189 / 5887
ironclaw_host_runtime 88.41% 21338 / 24135
ironclaw_turns 88.46% 3709 / 4193
ironclaw_telegram_extension 88.52% 586 / 662
ironclaw_skills 88.61% 2785 / 3143
ironclaw_process_sandbox 88.64% 281 / 317
ironclaw_processes 88.76% 5889 / 6635
ironclaw_reborn_openai_compat 89.4% 3644 / 4076
ironclaw_telegram_v2_adapter 89.43% 1573 / 1759
ironclaw_extensions 89.55% 6249 / 6978
ironclaw_loop_host 90.47% 18043 / 19944
ironclaw_resources 90.76% 4084 / 4500
ironclaw_approvals 91.05% 1820 / 1999
ironclaw_reborn_identity 91.3% 451 / 494
ironclaw_mcp 92% 1426 / 1550
ironclaw_conversations 92.08% 2383 / 2588
ironclaw_event_streams 92.5% 1048 / 1133
ironclaw_safety 92.75% 4468 / 4817
ironclaw_agent_loop 93.52% 10430 / 11153
ironclaw_slack_extension 93.94% 3689 / 3927
ironclaw_first_party_extension_ports 94.66% 3758 / 3970
ironclaw_outbound 94.68% 4271 / 4511
ironclaw_triggers 94.88% 3092 / 3259
ironclaw_prompt_envelope 97.46% 192 / 197
ironclaw_runtime_policy 97.6% 855 / 876
ironclaw_attachments 98.23% 831 / 846

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)
Module / Crate Reason Issue
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_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
crates/ironclaw_attachments/src/lib.rs Declarative crate facade: module declarations, constants, and re-exports only; executable attachment modules remain covered. #6524
crates/ironclaw_extension_host/src/ingress/mod.rs Declarative ingress module facade and documentation only; executable router modules remain covered. #6524
crates/ironclaw_host_api/src/lib.rs Declarative crate facade: module declarations and re-exports only; executable host API modules remain covered. #6524
crates/ironclaw_host_api/src/product_adapter/mod.rs Declarative product-adapter facade: module declarations and re-exports only; executable adapter modules remain covered. #6524
crates/ironclaw_llm/src/rig_adapter/tests/finish_reason_tests.rs Test-only module stored under src/ for private adapter access; cargo-llvm-cov omits test harness source from production LCOV while the exercised rig_adapter.rs production lines remain coverage-gated. #6284
crates/ironclaw_loop_contracts/src/lib.rs Declaration-only public facade with no executable Rust statements; rustc emits no LCOV source record. Executable loop-contract behavior remains covered in the owned implementation modules. #6524
crates/ironclaw_outbound/src/error.rs Declarative error vocabulary only; variants have no LLVM-instrumentable production statements. #6524
crates/ironclaw_outbound/src/lib.rs Declarative crate facade: module declarations and re-exports only; executable outbound modules remain covered. #6524
crates/ironclaw_product/src/lib.rs Declaration-only public facade with no executable Rust statements; rustc emits no LCOV source record. Executable product behavior remains covered in the owned implementation modules. #6524
crates/ironclaw_product/src/lib.rs Declarative crate facade: module declarations and re-exports only; executable product modules remain covered. #6524
crates/ironclaw_product/src/scoped_fs/mod.rs Declarative scoped-filesystem facade and documentation only; executable scoped filesystem modules remain covered. #6524
crates/ironclaw_reborn_composition/src/support/fs/mod.rs Declarative composition support facade: module declarations and re-exports only; executable filesystem adapters remain covered. #6524
crates/ironclaw_slack_extension/src/lib.rs Declarative Slack crate facade: module declarations and re-exports only; executable Slack modules remain covered. #6524
crates/ironclaw_telegram_extension/src/lib.rs Declarative Telegram crate facade: module declarations and re-exports only; executable Telegram modules remain covered. #6524
crates/ironclaw_threads/src/lib.rs Declaration-only public facade with no executable Rust statements; rustc emits no LCOV source record. Executable thread behavior remains covered in the owned implementation modules. #6524
crates/ironclaw_webui/src/webui_v2/mod.rs Declaration-only WebUI v2 facade with no executable Rust statements; rustc emits no LCOV source record. Executable route behavior remains covered in the owned implementation modules. #6524

…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>
@BenKurrek

Copy link
Copy Markdown
Collaborator Author

Coordinator sign-off (Wave 1 slot 3 — WS1.3 ironclaw_extension_contracts extraction).

Verified continuously across the slice's full lifecycle:

  • Zero exception delta, and that is the correct answer — re-verified per edge: none of the 13 survivors is a host_api edge; the extension-ish ones wait on WS3's registry DTOs by the checklist's own assignment. What did fall: a forbidden telegram_extension → product edge (normal + dev) the matrix had never seen, deleted and pinned by a new boundary rule.
  • The feat(extensions): register hosted MCP servers #6930 reconciliation was the slice's hardest work, done right: the invisible hosted_mcp ↔ package_lifecycle crate-cycle was caught by reconnaissance before it could compile-fail, resolved by relocating hosted_mcp on the merits (§6.1.2 wire types), all 16 consumers repointed, and the type frozen by name in the location scan so the cycle cannot silently return.
  • The collapse prevented a real regression: taking --ours on the checklist would have silently dropped all three of docs(target-architecture): reconcile with #6930 hosted-MCP registration #6979's merged additions — caught by line-diffing the merged commits rather than trusting a clean-looking file, and every line re-applied and verified.
  • Coverage gate closed honestly: of nine flagged sites, two were genuine holes in the new crate's own surface and got TESTS (proven 0→hits with llvm-cov), not exemptions; seven carry per-site evidence in three classes, including feat(extensions): register hosted MCP servers #6930's own untested arm correctly attributed to its owner. Replayed to 100% lines / 100% branches / exit 0 against CI's own artifact, re-verified at the final head.
  • Un-masking exact (host_api 379→335, new crate holds exactly the moved set + hosted_mcp's tests); both CodeRabbit findings verified real, fixed with measured evidence, and replied; five inventory corrections recorded where the docs had aged.

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.

@BenKurrek
BenKurrek merged commit dc333b1 into main Jul 31, 2026
60 checks passed
@BenKurrek
BenKurrek deleted the ws1/extension-contracts branch July 31, 2026 23:53
BenKurrek added a commit that referenced this pull request Aug 1, 2026
…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>
l3ocifer pushed a commit to l3ocifer/frick-ironclaw that referenced this pull request Sep 3, 2026
…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>
l3ocifer pushed a commit to l3ocifer/frick-ironclaw that referenced this pull request Sep 3, 2026
…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>

This branch was successfully deployed

No deployments
ironclaw-ci-preview / ironclaw-pr-6977 — c71cf8b3 Deployed Jul 31, 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 scope: docs Documentation size: XL 500+ changed lines

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant