Repository navigation
refactor(reborn): budget-gate store over RootFilesystem, delete InMemoryBudgetGateStore (§4.3) - #6210
Conversation
|
Caution The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased. |
🔎 IronLoop Review StatusHead: Current reviewers:
Reviewer summaries
Recent activity
Available commands
Run metadataAdmission: webhook accepted the request and IronLoop persisted reviewer state before this projection. |
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. 🗂️ Base branches to auto review (2)
Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
c35af94 to
2d69809
Compare
728e484 to
5bd5181
Compare
2d69809 to
e2dfea4
Compare
5bd5181 to
6c38630
Compare
e2dfea4 to
13f8a37
Compare
6c38630 to
529ede6
Compare
|
🚅 Deployed to the ironclaw-pr-6210 environment in ironclaw-ci-preview
|
13f8a37 to
7263297
Compare
529ede6 to
03bc985
Compare
…MemoryOutboundStateStore (§4.3)
Continues the arch-simplification §4.3 store consolidation: delete the
hand-written `InMemoryOutboundStateStore` (which implemented only
`CommunicationPreferenceRepository` + `OutboundStateStore`) and use the one
production `FilesystemOutboundStateStore` — which implements all four
outbound-store traits — over an in-memory backend.
Gap closed (strict improvement): the durable (libsql/postgres) composition
already shared one `FilesystemOutboundStateStore` across all four outbound
roles, while the no-durable path split `InMemoryOutboundStateStore` (prefs +
state) from separate `InMemory{DeliveredGateRoute,TriggeredRunDelivery}Store`
instances — a documented cross-store "gap". Both `local_dev_outbound_store`
cfg branches now collapse into one that shares a single
`FilesystemOutboundStateStore<CompositeRootFilesystem>` for every role
(`LocalDevRootFilesystem` is `CompositeRootFilesystem` in both builds), closing
the gap.
Changes:
- `ironclaw_outbound`: delete `memory.rs` (`InMemoryOutboundStateStore`, 264
lines, no other exports); add a `test-support` feature + `test_support.rs`
with `in_memory_backed_outbound_state_store()`. Own tests use
local/`crate::` helpers (run_state pattern).
- Composition factory: merge the two `local_dev_outbound_store` cfg branches;
make the `FilesystemOutboundStateStore` import unconditional (the
cfg-gated-import trap — A5 lesson) and ungate `local_dev_scoped_filesystem`.
- `projection.rs` (`build_reborn_projection_services`, PRODUCTION): the
EventStreamManager's throwaway `InMemoryOutboundStateStore::default()` becomes
a fresh `FilesystemOutboundStateStore::new(wrap_scoped(InMemoryBackend))`
(the budget-gate factory pattern — no `expect`, behavior-preserving). Store
stays constructed inside the fn, so its ~65 test callers are untouched.
- Downstream test doubles (event_streams, product_workflow, composition slack/
outbound/projection tests) repointed to the test-support helper; each
consumer crate enables `ironclaw_outbound/test-support` in dev-deps.
- `outbound_state_store_contract.rs`: delete the now-redundant `in_memory_*`
conformance test (the filesystem arm is a strict superset).
- R1 ratchet: drop `InMemoryOutboundStateStore` from the frozen allowlist.
Wire-safe: record schemas unchanged (the filesystem store reuses them).
Verified: outbound 110, event_streams 70, product_workflow 18, composition
projection 143 + slack 387 + outbound 76 tests pass; `cargo build -p
ironclaw_reborn_composition` (default + libsql) clean; clippy `-D warnings`
clean on all four crates; ratchet pass; fmt + pre-commit clean.
Stacked on #6210.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
7263297 to
50e47c6
Compare
03bc985 to
3e00ebf
Compare
…MemoryOutboundStateStore (§4.3)
Continues the arch-simplification §4.3 store consolidation: delete the
hand-written `InMemoryOutboundStateStore` (which implemented only
`CommunicationPreferenceRepository` + `OutboundStateStore`) and use the one
production `FilesystemOutboundStateStore` — which implements all four
outbound-store traits — over an in-memory backend.
Gap closed (strict improvement): the durable (libsql/postgres) composition
already shared one `FilesystemOutboundStateStore` across all four outbound
roles, while the no-durable path split `InMemoryOutboundStateStore` (prefs +
state) from separate `InMemory{DeliveredGateRoute,TriggeredRunDelivery}Store`
instances — a documented cross-store "gap". Both `local_dev_outbound_store`
cfg branches now collapse into one that shares a single
`FilesystemOutboundStateStore<CompositeRootFilesystem>` for every role
(`LocalDevRootFilesystem` is `CompositeRootFilesystem` in both builds), closing
the gap.
Changes:
- `ironclaw_outbound`: delete `memory.rs` (`InMemoryOutboundStateStore`, 264
lines, no other exports); add a `test-support` feature + `test_support.rs`
with `in_memory_backed_outbound_state_store()`. Own tests use
local/`crate::` helpers (run_state pattern).
- Composition factory: merge the two `local_dev_outbound_store` cfg branches;
make the `FilesystemOutboundStateStore` import unconditional (the
cfg-gated-import trap — A5 lesson) and ungate `local_dev_scoped_filesystem`.
- `projection.rs` (`build_reborn_projection_services`, PRODUCTION): the
EventStreamManager's throwaway `InMemoryOutboundStateStore::default()` becomes
a fresh `FilesystemOutboundStateStore::new(wrap_scoped(InMemoryBackend))`
(the budget-gate factory pattern — no `expect`, behavior-preserving). Store
stays constructed inside the fn, so its ~65 test callers are untouched.
- Downstream test doubles (event_streams, product_workflow, composition slack/
outbound/projection tests) repointed to the test-support helper; each
consumer crate enables `ironclaw_outbound/test-support` in dev-deps.
- `outbound_state_store_contract.rs`: delete the now-redundant `in_memory_*`
conformance test (the filesystem arm is a strict superset).
- R1 ratchet: drop `InMemoryOutboundStateStore` from the frozen allowlist.
Wire-safe: record schemas unchanged (the filesystem store reuses them).
Verified: outbound 110, event_streams 70, product_workflow 18, composition
projection 143 + slack 387 + outbound 76 tests pass; `cargo build -p
ironclaw_reborn_composition` (default + libsql) clean; clippy `-D warnings`
clean on all four crates; ratchet pass; fmt + pre-commit clean.
Stacked on #6210.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…et 2)
The on-disk `RootFilesystem` backend was named `LocalFilesystem`, which
read as a *deployment tier* ("local" dev vs. served) when it is simply the
disk storage medium — a peer of `InMemoryBackend`, `LibSqlRootFilesystem`,
and `PostgresRootFilesystem` that a `DeploymentConfig` may select. Renamed
to `DiskFilesystem` so the type name states the storage medium, per the
architecture-simplification note's §4.4 Bucket 2 (Local* deployment-mode
naming cleanup).
Mechanical, behavior-preserving word-boundary rename across 69 files:
`struct LocalFilesystem` -> `struct DiskFilesystem`, the `pub use` in
`ironclaw_filesystem/src/lib.rs`, and every reference. Wire-safe: the type
has no serde persistence tag keyed on its name; the only renamed strings
are test assertion messages. Verified:
- `cargo build --workspace` — Finished
- `cargo test -p ironclaw_filesystem` — 24 pass
- `cargo test --no-run -p ironclaw_reborn_composition -p ironclaw_webui` — rc=0
- `cargo fmt --check` clean; `scripts/pre-commit-safety.sh` clean
Nine >1500-line files carry a `// arch-exempt: large_file, mechanical
... plan #6168` annotation — the rename adds a handful of lines with no
logic change and nowhere else to land.
Stacked on the LocalTraceSubmission* rename (#6207).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…e mapping; refresh filesystem guidance Addresses the IronLoop finding on #6209 plus a semantic rebase conflict: - host_runtime_services_contract.rs:574 — the run-state/approval classification test landed on main (#6203 follow-up) after this branch was cut and still constructed `LocalFilesystem::new()`; repointed to `DiskFilesystem::new()` (compile fix). - reborn_localdev_typename_ratchet.rs — the §4.4 doc comment's rename example was over-renamed to `DiskFilesystem`→`DiskFilesystem`; restored the historical `LocalFilesystem`→`DiskFilesystem` mapping. - Live filesystem guidance now names the current backend: ironclaw_filesystem CLAUDE.md/AGENTS.md backend lists and the filesystem/live-vertical-slice contract docs. The arch-exempt annotations and the `local.rs` "renamed from" breadcrumb keep the old name deliberately (they describe the rename). [skip-regression-check] compile/doc fixes on a behavior-preserving rename. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
50e47c6 to
22a3c12
Compare
…oryBudgetGateStore (§4.3)
Continues the arch-simplification §4.3 store consolidation (after
approvals/authorization/processes/run-state): delete the hand-written
`InMemoryBudgetGateStore` parallel implementation and use the one
production `FilesystemBudgetGateStore` over an in-memory backend —
"in-memory" stops being a store and becomes a filesystem backend
(`InMemoryBackend`). The code already flagged this in a TODO
("Production composition can swap in a filesystem-backed store ...
deferred to a follow-up"); this is that follow-up.
Behavior change (strictly more correct): the deleted in-memory store
was a single global HashMap that *ignored* `ResourceScope`. The
filesystem store routes each gate under the caller's tenant/user mount
(the same `cas_update(scoped_fs, &scope, path)` mechanism the merged
capability-lease store #6197 uses), so budget gates are now properly
tenant-isolated in the no-durable path instead of globally shared. The
open→get gate lifecycle is preserved: both flow from the same user's
turn scope. All existing gate tests use a single scope, so none needed
reconciliation. `resolve()` has no production caller today; only
`open()` (budget accountant) and `get()` (`apply_resolved_budget_gate`)
are wired.
Changes:
- `ironclaw_resources`: delete `InMemoryBudgetGateStore` struct+impl and
its `pub use`; add a `test-support` feature + `test_support.rs` with
`in_memory_backed_budget_gate_store()` (retention disabled to match the
old retain-forever semantics for tests). Migrate the 7 gate.rs unit
tests onto the helper.
- Composition factory no-durable path: `FilesystemBudgetGateStore::new(
wrap_scoped(InMemoryBackend::new()))`, mirroring the capability-lease
wiring. Observability + integration (`tests/integration/support/group.rs`)
test doubles use the `test-support` helper.
- R1 ratchet (`reborn_inmemory_store_ratchet`): drop
`InMemoryBudgetGateStore` from the frozen allowlist (the ratchet forces
this trim in the same PR as the deletion).
Wire-safe: `BudgetApprovalGate`/`BudgetGateStatus` serde shapes unchanged
(the filesystem store reuses the same records). Verified:
- `cargo test -p ironclaw_resources --features test-support` — 64 pass
- `cargo test -p ironclaw_reborn_composition --lib observability::budget` — 5 pass
- `cargo test -p ironclaw_architecture --test reborn_inmemory_store_ratchet` — pass
- `cargo build -p ironclaw_reborn_composition` (default + libsql) — clean
- `cargo clippy -p ironclaw_resources -p ironclaw_reborn_composition --all-targets ... -D warnings` — clean
- `cargo test --features integration --no-run` — rc=0
- `cargo fmt --check` + `scripts/pre-commit-safety.sh` — clean
Stacked on #6209.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…t-in contract Same wording CodeRabbit corrected on #6203's run_state test-support: a production build can technically enable the feature, so describe the gate as disabled-by-default/opt-in for [dev-dependencies] rather than promising "never ships"/"zero bytes". Applies to the module doc and the Cargo.toml feature comment. [skip-regression-check] doc-comment wording only. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3e00ebf to
d5a657f
Compare
…MemoryOutboundStateStore (§4.3)
Continues the arch-simplification §4.3 store consolidation: delete the
hand-written `InMemoryOutboundStateStore` (which implemented only
`CommunicationPreferenceRepository` + `OutboundStateStore`) and use the one
production `FilesystemOutboundStateStore` — which implements all four
outbound-store traits — over an in-memory backend.
Gap closed (strict improvement): the durable (libsql/postgres) composition
already shared one `FilesystemOutboundStateStore` across all four outbound
roles, while the no-durable path split `InMemoryOutboundStateStore` (prefs +
state) from separate `InMemory{DeliveredGateRoute,TriggeredRunDelivery}Store`
instances — a documented cross-store "gap". Both `local_dev_outbound_store`
cfg branches now collapse into one that shares a single
`FilesystemOutboundStateStore<CompositeRootFilesystem>` for every role
(`LocalDevRootFilesystem` is `CompositeRootFilesystem` in both builds), closing
the gap.
Changes:
- `ironclaw_outbound`: delete `memory.rs` (`InMemoryOutboundStateStore`, 264
lines, no other exports); add a `test-support` feature + `test_support.rs`
with `in_memory_backed_outbound_state_store()`. Own tests use
local/`crate::` helpers (run_state pattern).
- Composition factory: merge the two `local_dev_outbound_store` cfg branches;
make the `FilesystemOutboundStateStore` import unconditional (the
cfg-gated-import trap — A5 lesson) and ungate `local_dev_scoped_filesystem`.
- `projection.rs` (`build_reborn_projection_services`, PRODUCTION): the
EventStreamManager's throwaway `InMemoryOutboundStateStore::default()` becomes
a fresh `FilesystemOutboundStateStore::new(wrap_scoped(InMemoryBackend))`
(the budget-gate factory pattern — no `expect`, behavior-preserving). Store
stays constructed inside the fn, so its ~65 test callers are untouched.
- Downstream test doubles (event_streams, product_workflow, composition slack/
outbound/projection tests) repointed to the test-support helper; each
consumer crate enables `ironclaw_outbound/test-support` in dev-deps.
- `outbound_state_store_contract.rs`: delete the now-redundant `in_memory_*`
conformance test (the filesystem arm is a strict superset).
- R1 ratchet: drop `InMemoryOutboundStateStore` from the frozen allowlist.
Wire-safe: record schemas unchanged (the filesystem store reuses them).
Verified: outbound 110, event_streams 70, product_workflow 18, composition
projection 143 + slack 387 + outbound 76 tests pass; `cargo build -p
ironclaw_reborn_composition` (default + libsql) clean; clippy `-D warnings`
clean on all four crates; ratchet pass; fmt + pre-commit clean.
Stacked on #6210.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
✅ Ready for mergeReviewed, CI fully green (20 pass / 0 fail) on head
🤖 Generated with Claude Code |
…MemoryOutboundStateStore (§4.3)
Continues the arch-simplification §4.3 store consolidation: delete the
hand-written `InMemoryOutboundStateStore` (which implemented only
`CommunicationPreferenceRepository` + `OutboundStateStore`) and use the one
production `FilesystemOutboundStateStore` — which implements all four
outbound-store traits — over an in-memory backend.
Gap closed (strict improvement): the durable (libsql/postgres) composition
already shared one `FilesystemOutboundStateStore` across all four outbound
roles, while the no-durable path split `InMemoryOutboundStateStore` (prefs +
state) from separate `InMemory{DeliveredGateRoute,TriggeredRunDelivery}Store`
instances — a documented cross-store "gap". Both `local_dev_outbound_store`
cfg branches now collapse into one that shares a single
`FilesystemOutboundStateStore<CompositeRootFilesystem>` for every role
(`LocalDevRootFilesystem` is `CompositeRootFilesystem` in both builds), closing
the gap.
Changes:
- `ironclaw_outbound`: delete `memory.rs` (`InMemoryOutboundStateStore`, 264
lines, no other exports); add a `test-support` feature + `test_support.rs`
with `in_memory_backed_outbound_state_store()`. Own tests use
local/`crate::` helpers (run_state pattern).
- Composition factory: merge the two `local_dev_outbound_store` cfg branches;
make the `FilesystemOutboundStateStore` import unconditional (the
cfg-gated-import trap — A5 lesson) and ungate `local_dev_scoped_filesystem`.
- `projection.rs` (`build_reborn_projection_services`, PRODUCTION): the
EventStreamManager's throwaway `InMemoryOutboundStateStore::default()` becomes
a fresh `FilesystemOutboundStateStore::new(wrap_scoped(InMemoryBackend))`
(the budget-gate factory pattern — no `expect`, behavior-preserving). Store
stays constructed inside the fn, so its ~65 test callers are untouched.
- Downstream test doubles (event_streams, product_workflow, composition slack/
outbound/projection tests) repointed to the test-support helper; each
consumer crate enables `ironclaw_outbound/test-support` in dev-deps.
- `outbound_state_store_contract.rs`: delete the now-redundant `in_memory_*`
conformance test (the filesystem arm is a strict superset).
- R1 ratchet: drop `InMemoryOutboundStateStore` from the frozen allowlist.
Wire-safe: record schemas unchanged (the filesystem store reuses them).
Verified: outbound 110, event_streams 70, product_workflow 18, composition
projection 143 + slack 387 + outbound 76 tests pass; `cargo build -p
ironclaw_reborn_composition` (default + libsql) clean; clippy `-D warnings`
clean on all four crates; ratchet pass; fmt + pre-commit clean.
Stacked on #6210.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…MemoryOutboundStateStore (§4.3)
Continues the arch-simplification §4.3 store consolidation: delete the
hand-written `InMemoryOutboundStateStore` (which implemented only
`CommunicationPreferenceRepository` + `OutboundStateStore`) and use the one
production `FilesystemOutboundStateStore` — which implements all four
outbound-store traits — over an in-memory backend.
Gap closed (strict improvement): the durable (libsql/postgres) composition
already shared one `FilesystemOutboundStateStore` across all four outbound
roles, while the no-durable path split `InMemoryOutboundStateStore` (prefs +
state) from separate `InMemory{DeliveredGateRoute,TriggeredRunDelivery}Store`
instances — a documented cross-store "gap". Both `local_dev_outbound_store`
cfg branches now collapse into one that shares a single
`FilesystemOutboundStateStore<CompositeRootFilesystem>` for every role
(`LocalDevRootFilesystem` is `CompositeRootFilesystem` in both builds), closing
the gap.
Changes:
- `ironclaw_outbound`: delete `memory.rs` (`InMemoryOutboundStateStore`, 264
lines, no other exports); add a `test-support` feature + `test_support.rs`
with `in_memory_backed_outbound_state_store()`. Own tests use
local/`crate::` helpers (run_state pattern).
- Composition factory: merge the two `local_dev_outbound_store` cfg branches;
make the `FilesystemOutboundStateStore` import unconditional (the
cfg-gated-import trap — A5 lesson) and ungate `local_dev_scoped_filesystem`.
- `projection.rs` (`build_reborn_projection_services`, PRODUCTION): the
EventStreamManager's throwaway `InMemoryOutboundStateStore::default()` becomes
a fresh `FilesystemOutboundStateStore::new(wrap_scoped(InMemoryBackend))`
(the budget-gate factory pattern — no `expect`, behavior-preserving). Store
stays constructed inside the fn, so its ~65 test callers are untouched.
- Downstream test doubles (event_streams, product_workflow, composition slack/
outbound/projection tests) repointed to the test-support helper; each
consumer crate enables `ironclaw_outbound/test-support` in dev-deps.
- `outbound_state_store_contract.rs`: delete the now-redundant `in_memory_*`
conformance test (the filesystem arm is a strict superset).
- R1 ratchet: drop `InMemoryOutboundStateStore` from the frozen allowlist.
Wire-safe: record schemas unchanged (the filesystem store reuses them).
Verified: outbound 110, event_streams 70, product_workflow 18, composition
projection 143 + slack 387 + outbound 76 tests pass; `cargo build -p
ironclaw_reborn_composition` (default + libsql) clean; clippy `-D warnings`
clean on all four crates; ratchet pass; fmt + pre-commit clean.
Stacked on #6210.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…MemoryOutboundStateStore (§4.3)
Continues the arch-simplification §4.3 store consolidation: delete the
hand-written `InMemoryOutboundStateStore` (which implemented only
`CommunicationPreferenceRepository` + `OutboundStateStore`) and use the one
production `FilesystemOutboundStateStore` — which implements all four
outbound-store traits — over an in-memory backend.
Gap closed (strict improvement): the durable (libsql/postgres) composition
already shared one `FilesystemOutboundStateStore` across all four outbound
roles, while the no-durable path split `InMemoryOutboundStateStore` (prefs +
state) from separate `InMemory{DeliveredGateRoute,TriggeredRunDelivery}Store`
instances — a documented cross-store "gap". Both `local_dev_outbound_store`
cfg branches now collapse into one that shares a single
`FilesystemOutboundStateStore<CompositeRootFilesystem>` for every role
(`LocalDevRootFilesystem` is `CompositeRootFilesystem` in both builds), closing
the gap.
Changes:
- `ironclaw_outbound`: delete `memory.rs` (`InMemoryOutboundStateStore`, 264
lines, no other exports); add a `test-support` feature + `test_support.rs`
with `in_memory_backed_outbound_state_store()`. Own tests use
local/`crate::` helpers (run_state pattern).
- Composition factory: merge the two `local_dev_outbound_store` cfg branches;
make the `FilesystemOutboundStateStore` import unconditional (the
cfg-gated-import trap — A5 lesson) and ungate `local_dev_scoped_filesystem`.
- `projection.rs` (`build_reborn_projection_services`, PRODUCTION): the
EventStreamManager's throwaway `InMemoryOutboundStateStore::default()` becomes
a fresh `FilesystemOutboundStateStore::new(wrap_scoped(InMemoryBackend))`
(the budget-gate factory pattern — no `expect`, behavior-preserving). Store
stays constructed inside the fn, so its ~65 test callers are untouched.
- Downstream test doubles (event_streams, product_workflow, composition slack/
outbound/projection tests) repointed to the test-support helper; each
consumer crate enables `ironclaw_outbound/test-support` in dev-deps.
- `outbound_state_store_contract.rs`: delete the now-redundant `in_memory_*`
conformance test (the filesystem arm is a strict superset).
- R1 ratchet: drop `InMemoryOutboundStateStore` from the frozen allowlist.
Wire-safe: record schemas unchanged (the filesystem store reuses them).
Verified: outbound 110, event_streams 70, product_workflow 18, composition
projection 143 + slack 387 + outbound 76 tests pass; `cargo build -p
ironclaw_reborn_composition` (default + libsql) clean; clippy `-D warnings`
clean on all four crates; ratchet pass; fmt + pre-commit clean.
Stacked on #6210.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…MemoryOutboundStateStore (§4.3) (#6212) Continues the arch-simplification §4.3 store consolidation: delete the hand-written `InMemoryOutboundStateStore` (which implemented only `CommunicationPreferenceRepository` + `OutboundStateStore`) and use the one production `FilesystemOutboundStateStore` — which implements all four outbound-store traits — over an in-memory backend. Gap closed (strict improvement): the durable (libsql/postgres) composition already shared one `FilesystemOutboundStateStore` across all four outbound roles, while the no-durable path split `InMemoryOutboundStateStore` (prefs + state) from separate `InMemory{DeliveredGateRoute,TriggeredRunDelivery}Store` instances — a documented cross-store "gap". Both `local_dev_outbound_store` cfg branches now collapse into one that shares a single `FilesystemOutboundStateStore<CompositeRootFilesystem>` for every role (`LocalDevRootFilesystem` is `CompositeRootFilesystem` in both builds), closing the gap. Changes: - `ironclaw_outbound`: delete `memory.rs` (`InMemoryOutboundStateStore`, 264 lines, no other exports); add a `test-support` feature + `test_support.rs` with `in_memory_backed_outbound_state_store()`. Own tests use local/`crate::` helpers (run_state pattern). - Composition factory: merge the two `local_dev_outbound_store` cfg branches; make the `FilesystemOutboundStateStore` import unconditional (the cfg-gated-import trap — A5 lesson) and ungate `local_dev_scoped_filesystem`. - `projection.rs` (`build_reborn_projection_services`, PRODUCTION): the EventStreamManager's throwaway `InMemoryOutboundStateStore::default()` becomes a fresh `FilesystemOutboundStateStore::new(wrap_scoped(InMemoryBackend))` (the budget-gate factory pattern — no `expect`, behavior-preserving). Store stays constructed inside the fn, so its ~65 test callers are untouched. - Downstream test doubles (event_streams, product_workflow, composition slack/ outbound/projection tests) repointed to the test-support helper; each consumer crate enables `ironclaw_outbound/test-support` in dev-deps. - `outbound_state_store_contract.rs`: delete the now-redundant `in_memory_*` conformance test (the filesystem arm is a strict superset). - R1 ratchet: drop `InMemoryOutboundStateStore` from the frozen allowlist. Wire-safe: record schemas unchanged (the filesystem store reuses them). Verified: outbound 110, event_streams 70, product_workflow 18, composition projection 143 + slack 387 + outbound 76 tests pass; `cargo build -p ironclaw_reborn_composition` (default + libsql) clean; clippy `-D warnings` clean on all four crates; ratchet pass; fmt + pre-commit clean. Stacked on #6210. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
What
Continues the arch-simplification §4.3 store consolidation (after approvals/authorization/processes/run-state): deletes the hand-written
InMemoryBudgetGateStoreand uses the one productionFilesystemBudgetGateStoreover an in-memory backend. The code already flagged this as a TODO ("Production composition can swap in a filesystem-backed store … deferred to a follow-up") — this is that follow-up.Behavior change — strictly more correct
The deleted in-memory store was a single global
HashMapthat ignoredResourceScope.FilesystemBudgetGateStoreroutes each gate under the caller's tenant/user mount via the samecas_update(scoped_fs, &scope, path)mechanism the merged capability-lease store (#6197) uses — so budget gates are now properly tenant-isolated in the no-durable path instead of globally shared.The
open → getgate lifecycle is preserved (both flow from the same user's turn scope). All existing gate tests use a single scope, so none needed A2-style reconciliation.resolve()has no production caller today; onlyopen()(budget accountant) andget()(apply_resolved_budget_gate) are wired.Changes
ironclaw_resources: deleteInMemoryBudgetGateStorestruct+impl and itspub use; add atest-supportfeature +test_support.rswithin_memory_backed_budget_gate_store()(terminal retention disabled to match the old retain-forever test semantics). Migrate the 7 gate.rs unit tests onto the helper.FilesystemBudgetGateStore::new(wrap_scoped(InMemoryBackend::new())), mirroring the capability-lease wiring. Observability + integration (tests/integration/support/group.rs) test doubles use thetest-supporthelper.reborn_inmemory_store_ratchet): dropInMemoryBudgetGateStorefrom the frozen allowlist (the ratchet forces this trim in the same PR as the deletion — shrinking toward the §10 empty-set goal).Wire-safe:
BudgetApprovalGate/BudgetGateStatusserde shapes unchanged (the filesystem store reuses the same records).Verification
cargo test -p ironclaw_resources --features test-support— 64 passcargo test -p ironclaw_reborn_composition --lib observability::budget— 5 passcargo test -p ironclaw_architecture --test reborn_inmemory_store_ratchet— passcargo build -p ironclaw_reborn_composition(default + libsql) — cleancargo clippy -p ironclaw_resources -p ironclaw_reborn_composition --all-targets --all-features -- -D warnings— cleancargo test --features integration --no-run— rc=0 (integration harness compiles)cargo fmt --check+scripts/pre-commit-safety.sh— cleanStack
Stacked on #6209. Part of the incremental arch-simplification refactor (
docs/reborn/2026-07-17-architecture-simplification-dto-dyn-local.md).🤖 Generated with Claude Code