Commit Graph

37 Commits

Author SHA1 Message Date
maaz519 54c47dd133 feat(p6): route-admin demo + route smoke; P6 verification green
Task 6.6: apps/route-admin (Vite, port 5176) — create bindings, simulate a
message (preview-first, no send), see color-coded per-destination decisions
with reason codes + preview, approve/deny REVIEW rows; built on the
community-web SDK via CommunityProvider.

scripts/smoke-route.mjs: 3 MANUAL bindings → 'party at 9 PM' → children(CHILD)
DENY / adults+seniors REVIEW / 0 sends on simulate; approve → exactly one
sandbox forward; AUTOMATIC safe binding auto-forwards via RouteProjector.

P6 verification: 63 tests green, pnpm -r build all packages+demos, boundary
passes and fails on community-web→service, route smoke PASS, prior smokes
(realtime/inbox/support/adapter) PASS.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 15:33:42 +05:30
maaz519 1ee737c025 feat(p6): kernel-client route methods + @insignia/iios-community-web SDK
Task 6.5: add createBinding/listBindings/simulateRoute/listRouteDecisions/
approveDecision/denyDecision to RestClient + RouteBinding/RouteDecision types.
New @insignia/iios-community-web package (CommunityProvider, useBindings,
useRoutePreview, useRouteDecisions). Boundary allowlist: community-web ->
contracts + kernel-client.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 15:12:50 +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
maaz519 dfd87cdde7 feat(service): P6.1 route tables (route_binding, route_decision, moderation_flag) + enums + events
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 14:24:53 +05:30
maaz519 b879c9eba2 feat: P5.5 dev inject + adapter-inspector demo + adapter smoke (P5 complete)
Dev-only POST /v1/dev/webhook/:type signs+injects a sample payload. apps/adapter-
inspector (Vite): inbound raw events + outbound commands/attempts, simulate-inbound
+ test-send buttons. smoke-adapter proves signed->normalized->interaction, bad-sig
401, sandboxed outbound (no network). 55 tests; all 4 smokes pass; boundary enforced.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 13:54:18 +05:30
maaz519 4f661f4c81 feat(service): P5.4 outbound sandbox sink + rate limit + inspector read endpoints
OutboundService: idempotent commands, per-(channelType,target) rate-limit bucket,
sandbox send (no network) + delivery attempts. POST /v1/adapters/:type/send +
GET inbound/outbound (session-auth). 55 tests.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 13:46:56 +05:30
maaz519 29b64c3c4e feat(service): P5.3 inbound adapter pipeline (ACK-fast webhook + RawEventProjector) + traceId
POST /v1/adapters/:type/webhook verifies HMAC (fail-closed) -> stores raw ->
emits raw.received -> 202. RawEventProjector consumes it off the relay, normalizes
via the adapter, reuses IngestService (traceId threaded raw->interaction).
Deduped on (channelType, externalEventId). rawBody enabled. 48 tests.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 13:44:23 +05:30
maaz519 b4a1832a5c feat(service): P5.2 adapter tables (raw_event, outbound_command, delivery_attempt, rate_limit_bucket) + resetDb
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 13:39:22 +05:30
maaz519 d70c7ea47b feat(sdk): P5.1 @insignia/iios-adapter-sdk — ChannelAdapter contract + HMAC webhook adapter + sandbox + fixtures
Contract (capability incl. requiresFollowupFetch seam, verifySignature, normalize,
fetch?, send), HMAC-SHA256 sign/verify (timing-safe), reference WebhookAdapter
(normalize→IngestInteractionRequest), SandboxSink (no network), email/whatsapp
fixtures. CJS build (consumed by the NestJS service). 4 tests; boundary updated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 13:37:55 +05:30
maaz519 9c6e2c76e8 fix(support): agent-demo self-seeds (join default queue + go online); tickets always get a queue
Root cause of 'waiting for escalations': no queue/membership meant tickets were
never assigned. Now: createTicket find-or-creates a default queue; new joinDefault
endpoint + useGoOnline hook; agent-demo joins+goes-AVAILABLE on load (assignPending
picks up any waiting ticket). smoke-support self-seeds (no seed script needed).
Also: vitest singleFork to end cross-file DB races (45 tests deterministic).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 12:39:14 +05:30
maaz519 eb04becc57 feat(service): P4 doc-faithfulness — SLA placeholder columns, issueSubclass, traceId on state.changed
Adds ticket.slaDueAt + ticket.issueSubclass + queue.slaPolicyRef (placeholder
columns, no timer logic until P7) and propagates ticket.traceId onto
ticket.state.changed events (assignment + transition). 45 tests still green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 12:25:11 +05:30
maaz519 7441d0ec36 feat: P4.6 agent demo + escalate button + support seed/smoke (P4 complete)
apps/agent-demo (Vite): agent sets AVAILABLE, sees assigned tickets, opens the
thread, replies. message-demo customer pane gains 'escalate to support' (via
SupportProvider/useEscalate). seed-support + smoke-support prove the loop:
escalate -> auto-assign -> agent reply -> customer receives. 45 tests; realtime/
inbox/support smokes all pass; both demos build.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 12:09:29 +05:30
maaz519 c53258c8eb feat(sdk): P4.5 @insignia/iios-support-web (composes message-web + support REST)
SupportProvider (wraps MessageProvider + support client); useEscalate, useTickets/
useAssignedTickets (+createTicket/patch), useCallbackRequest, useAvailability;
re-exports useThread/useMessages. Boundary allowlist: support-web -> contracts+
kernel-client+message-web+inbox-web.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 12:00:46 +05:30
maaz519 e9e61b52bc feat: P4.4 support REST (tickets/escalate/callbacks/queue admin) + kernel-client methods
8 routes under /v1/support (session-auth). RestClient gains createTicket/escalate/
listTickets/patchTicket/requestCallback/createQueue/joinQueue/setAvailability +
Ticket/CallbackRequest types.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 11:58:52 +05:30
maaz519 859124914c feat(service): P4.3 AssignmentService — event-driven least-loaded assignment
Consumes support.ticket.created -> picks least-loaded available agent within
capacity -> ticket OPEN, activeCount++, agent joins linked thread(s), base
thread untouched; idempotent (processed-event + assignedActorId guard). Queue/
team admin (createQueue/addMember/setAvailability, re-scan on available). 45 tests.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 11:55:31 +05:30
maaz519 2695f0ffee feat(service): P4.2 SupportService — tickets, M:N thread links, transitions, callback
createTicket (NEW + history + ticket.created event, default queue), escalate,
linkThread/unlinkThread (M:N both directions), transition state machine +
ticket.state.changed, requestCallback placeholder, listTickets (mine/assigned),
fail-closed. 6 tests green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 11:53:13 +05:30
maaz519 2141cea8dc feat(service): P4.1 support tables (queue/team_member/ticket/ticket_thread_link/state_history/callback) + events
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 11:51:19 +05:30
maaz519 942f40292e feat(demo): P3.5 inbox sidebar + inbox smoke (P3 complete)
message-demo gains a per-person Inbox rail (useInbox, done/snooze); sending
surfaces a NEEDS_REPLY item in the other pane; reading auto-resolves it.
smoke-inbox.mjs proves the event-driven flow end-to-end (send -> relay ->
projector -> inbox -> read -> DONE). Realtime smoke still passes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 07:24:52 +05:30
maaz519 0a1631dbc0 feat(sdk): P3.4 @insignia/iios-inbox-web + kernel-client inbox REST
RestClient.listInboxItems/patchInboxItem + InboxItem type; iios-inbox-web
InboxProvider + useInbox (poll + snooze/done/reopen). Boundary allowlist extended.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 04:30:42 +05:30
maaz519 20c8f15dff feat(service): P3.3 inbox API + state machine (list/transition, fail-closed, STALE)
InboxService.list (fail-closed) + transition (OPEN/SNOOZED/DONE/STALE/ARCHIVED
state machine, owner-only, state-history). GET /v1/inbox/items + PATCH
/v1/inbox/items/:id. Moved SessionVerifier to global IdentityModule (shared by
message + inbox, no circular imports). 35 tests green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 03:54:11 +05:30
maaz519 a2b95afaf0 feat(service): P3.2 InboxProjector + message.read event + scheduled relay
Event-driven projector creates/collapses NEEDS_REPLY items from message.sent
(traceId propagated; inbox.item.created emitted) and resolves them to DONE on
message.read; idempotent via processed-event ledger. markRead now emits a
message.read outbox event (atomic). OutboxRelay runs on a 500ms timer in the
app (off in tests). Shared resetDb (TRUNCATE CASCADE) fixes cross-spec FK
isolation. 32 tests green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 02:48:44 +05:30
maaz519 7b174e24fa feat(service): P3.1 inbox tables + extract ActorResolver
IiosInboxItem + IiosInboxItemStateHistory (migration inbox-init). Extracted
resolveScope/resolveActor/ensureParticipant into a shared ActorResolver
(IdentityModule) so message + inbox layers share identity resolution; MessageService
delegates (P2 tests unchanged).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 02:41:50 +05:30
maaz519 4d05f7c1b1 feat(demo): P2.7 Vite React two-pane realtime demo + dev token endpoint (P2 complete)
apps/message-demo: Alice creates a thread, Bob joins; live two-way chat, typing,
read receipts (useMessages now exposes reads[]). Dev-only /v1/dev/token endpoint
(gated by IIOS_DEV_TOKENS) so the browser can auth. .env autoloaded (dotenv).
Realtime smoke script passes end-to-end (message + unread + receipt).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 01:36:14 +05:30
maaz519 eff3c615d5 feat(sdk): P2.6 @insignia/iios-message-web (React hooks) + allowlist boundary
MessageProvider/useThread/useMessages over the kernel-client socket (live append,
typing, dedupe). Reconnect test (re-opens active thread). Rewrote import-boundary
as an allowlist so SDK<->service sibling imports are forbidden both ways. 28 tests.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 01:29:25 +05:30
maaz519 5a590c7fda feat(sdk): P2.5 @insignia/iios-kernel-client — REST + socket facade
MessageSocket (open/send/read/typing via emitWithAck, reconnect re-opens thread,
no socket.io types leak) + RestClient (ingest/getThreadMessages/sendMessage).
tsup ESM+dts. Facade unit test with injectable fake socket (3 tests).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 01:21:59 +05:30
maaz519 3165a5bb59 feat(service): P2.4 REST fallback POST /v1/threads/:id/messages (session-auth)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 01:18:59 +05:30
maaz519 50ef34dd90 feat(service): P2.3 Socket.io /message gateway + real SessionVerifier
open_thread (create-or-join) / send_message / read / delivered / typing; HS256
token verified on connect (SessionVerifier reuses AppTokenVerifier pattern);
OutboxBus bridge propagates REST/ingest messages to rooms (dedup vs inline emit).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 01:12:49 +05:30
maaz519 827fb52f5f feat(service): P2.2 MessageService — native send + receipts/unread + traceId
openThread (create-or-join), send (idempotent, bumps other participants' unread,
message.sent outbox event, traceId DB->event), markRead (READ receipt + unread
reset), contentRef attachment placeholder. Adds messageSent to contracts events.
5 DB-backed tests green; 24 total.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 01:09:19 +05:30
maaz519 7197157058 feat(service): P2.1 messaging tables — IiosMessageReceipt + IiosUnreadCounter
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 01:04:26 +05:30
maaz519 072c541e09 feat(service): outbox relay + thread read endpoint + replay (P1.5, P1 complete)
OutboxRelay: FOR UPDATE SKIP LOCKED claim, in-process bus publish, PENDING->
PUBLISHED with 30s backoff + idempotent-consumer ledger. GET /v1/threads/:id/
messages (policy-scoped). Replay + read specs green; vitest fileParallelism off
(shared DB). End-to-end HTTP smoke verified: idempotent ingest, read-back, 400
on missing key. 19 tests pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 21:29:00 +05:30
maaz519 4b7dc98c6b feat(service): ingest endpoint with kernel gates (P1.4)
POST /v1/interactions/ingest: fail-closed OPA gate -> resolve scope/handle(MDM,
no silent merge)/actor/channel/thread -> idempotent write of interaction+parts+
outbox CloudEvent in one tx. 4 DB-backed gate tests green (idempotent /
fail-closed / unresolved-handle / outbox event). 16 tests total.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 21:24:09 +05:30
maaz519 8cd5d9b248 feat(service): PlatformGates seam + fail-closed decideOrThrow (P1.3)
LocalDevPorts = permissive in-service default (no testkit at runtime);
decideOrThrow turns OPA deny/throw/timeout into PolicyDeniedError. Tests drive
deny/timeout via testkit fakes. 12 tests green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 21:18:23 +05:30
maaz519 9cfd1ab1ab feat(service): NestJS kernel skeleton + 10-table kernel schema (P1.1+1.2)
Reuses support-service bootstrap/health/prisma patterns. Kernel-only Prisma
schema (scope/source_handle/actor/channel/thread/participant/interaction/
message_part/outbox/processed_event) with orgId/appId NOT NULL and
@@unique([scopeId, idempotencyKey]). Health verified: {status:ok,db:true}.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 21:16:31 +05:30
maaz519 169c1a375c feat(testkit): deterministic fake platform ports + fixtures + replay oracle
Fakes for all 7 IiosPlatformPorts (deny/timeout/ambiguous controls), portal +
unknown-email fixtures, replayTwice idempotency oracle. Adds ingest request
contract. Vitest alias resolves workspace packages to source.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 21:05:41 +05:30
maaz519 fbea291609 feat(contracts): @insignia/iios-contracts — scope, enums, platform ports, CloudEvents, errors
Verbatim IiosPlatformPorts from the bottom-up atlas; orgId/appId required scope
(KG-02); PolicyDeniedError for fail-closed. Vitest as workspace test runner.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 20:59:34 +05:30