Commit Graph

8 Commits

Author SHA1 Message Date
maaz519 a933e2e3af feat(iios): idempotency ledger on outbound egress (409 on key reuse) (P9)
OutboundService.send is now opt-in idempotent: an explicit idempotencyKey routes
the send through IdempotencyService.run (Slice 6), so reusing a key with a
different target/payload returns a 409 conflict and a same-key/same-request retry
replays the cached command. The inner findUnique early-return stays as a backstop
so a FAILED-then-retried send never collides on the command's unique key. Keyless
sends keep the old behavior (no ledger row).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-03 18:44:22 +05:30
maaz519 2424739e3a feat(iios): projectors checkpoint the projection cursor (P9)
All 5 projectors (route/ai/inbox/calendar/raw-event) now advance their
IiosProjectionCursor after a freshly-claimed event is applied — split into
claim → apply → advance so a duplicate never double-counts and a throw leaves
the cursor untouched (event replays via the DLQ). Inbox's two topics get two
cursor rows. Proves KG-06 replay reproduction at the projection level.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-03 02:44:23 +05:30
maaz519 d3d557766e feat(iios): wire projectors + relay into DLQ (P9 chaos-safe)
Projectors register a replay handler and route bus errors to
dlq.onConsumerFailure (dead-letter + clear the claim-then-fail claim)
instead of swallowing them. Relay dead-letters an outbox event after
IIOS_OUTBOX_MAX_ATTEMPTS instead of retrying forever. Chaos test proves
poison → DLQ → replay resolves while sibling events keep flowing (KG-13/KG-06).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-03 01:43:57 +05:30
maaz519 063049b724 feat(p9): scope-ownership assert + fence routing approve/deny/listDecisions
Task T3.1: ActorResolver gains findScope (no-create) + assertOwns(principal,
resourceScopeId) → ForbiddenException on mismatch (KG-02). RouteService.approve/
deny now assertOwns on the decision's binding scope before mutating; listDecisions
is scoped to the caller. Fixes the critical cross-tenant mutation (tenant A could
approve tenant B's route). Also adds IiosScope.cellId + IiosOutboundCommand.scopeId
columns (migration tenant-isolation) + cell assignment on scope create. Test:
another tenant approving → Forbidden, decision unchanged, no scope created, empty list.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-02 21:46:40 +05:30
maaz519 28e517fc1b feat(p9): route OutboundService through the Capability Broker
Task 9.3: OutboundService now delegates the execute step to CapabilityBroker
(policy-gated + obligation-enforced) instead of calling a provider directly, while
keeping idempotency + rate-limit + the command/attempt ledger. BLOCKED obligations
→ command BLOCKED; a fail-closed throw marks the command FAILED then propagates.
AdaptersModule imports CapabilityModule; P4/P6/P8 egress now flows through the
broker unchanged. Updated 6 spec constructions; added a DENY_OUTBOUND test.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 20:04:11 +05:30
maaz519 095ea869aa feat(service): P6.4 RouteProjector — AUTOMATIC forwarding on interaction.normalized
Reacts to channel-bearing (ingested/adapter) interactions, not native DMs;
simulates per binding; AUTOMATIC+ALLOW executes to sandbox, MANUAL/REVIEW/DENY
stay pending; idempotent. 8 route tests; 63 total.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 14:43:24 +05:30
maaz519 968a90bdb9 feat(service): P6.3 route REST + approve/deny → execute to sandbox
RouteService (createBinding/listBindings/simulate/listDecisions/approve/deny/
execute/flushDigest); approve REVIEW→ALLOW + route.approved event → execute via
P5 OutboundService (sandbox, idempotent per decision); deny never executes.
7 route endpoints; PORTAL adapter registered. 5 route tests green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 14:40:08 +05:30
maaz519 7ed3c11891 feat(service): P6.2 RuleEngine + RouteSimulator (deterministic, preview-first)
Keyword moderation flags; deny-by-default for protected (CHILD) destinations,
REVIEW for other flags/requiresReview, ALLOW otherwise; versioned rulepack for
replay. Simulate renders per-format previews + persists decisions, NEVER sends.
BDD (party@9pm → children DENY / adult+seniors REVIEW / 0 sends) + replay green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 14:29:01 +05:30