@pattern-stack/codegen 0.27.1 → 0.27.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (28) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/dist/{chunk-E5FJWOMP.js → chunk-3AM722ZH.js} +15 -6
  3. package/dist/chunk-3AM722ZH.js.map +1 -0
  4. package/dist/{chunk-DKKFTHHI.js → chunk-CZQUOIDY.js} +4 -4
  5. package/dist/{chunk-Z7YFYK6H.js → chunk-EGXFEZ2N.js} +4 -4
  6. package/dist/{chunk-KS4BZHIA.js → chunk-XW4XKN3F.js} +7 -7
  7. package/dist/{chunk-36NRG2EP.js → chunk-YQA5PMOD.js} +3 -3
  8. package/dist/runtime/base-classes/index.js +17 -17
  9. package/dist/runtime/subsystems/analytics/analytics.module.js +2 -2
  10. package/dist/runtime/subsystems/analytics/index.js +4 -4
  11. package/dist/runtime/subsystems/auth/auth.module.js +1 -1
  12. package/dist/runtime/subsystems/auth/index.js +3 -3
  13. package/dist/runtime/subsystems/bridge/bridge-outbox-drain-hook.js +1 -1
  14. package/dist/runtime/subsystems/bridge/bridge.module.js +7 -7
  15. package/dist/runtime/subsystems/bridge/bridge.protocol.d.ts +20 -14
  16. package/dist/runtime/subsystems/bridge/index.js +7 -7
  17. package/dist/runtime/subsystems/index.js +24 -24
  18. package/dist/runtime/subsystems/jobs/index.js +13 -13
  19. package/dist/runtime/subsystems/jobs/job-worker.module.js +5 -5
  20. package/dist/runtime/subsystems/jobs/jobs-domain.module.js +3 -3
  21. package/package.json +1 -1
  22. package/runtime/subsystems/bridge/bridge-outbox-drain-hook.ts +34 -11
  23. package/runtime/subsystems/bridge/bridge.protocol.ts +20 -14
  24. package/dist/chunk-E5FJWOMP.js.map +0 -1
  25. /package/dist/{chunk-DKKFTHHI.js.map → chunk-CZQUOIDY.js.map} +0 -0
  26. /package/dist/{chunk-Z7YFYK6H.js.map → chunk-EGXFEZ2N.js.map} +0 -0
  27. /package/dist/{chunk-KS4BZHIA.js.map → chunk-XW4XKN3F.js.map} +0 -0
  28. /package/dist/{chunk-36NRG2EP.js.map → chunk-YQA5PMOD.js.map} +0 -0
package/CHANGELOG.md CHANGED
@@ -2,6 +2,29 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## [0.27.2] — 2026-06-08
6
+
7
+ ### Fixed
8
+
9
+ - **Bridge audit-tier guard no longer emits a false-positive WARN on every
10
+ audit event (#535).** `BridgeOutboxDrainHook.processEvent` ran its audit-tier
11
+ guard *before* the trigger lookup, so it fired — and logged a WARN — for every
12
+ `tier:audit` event, while asserting "a `bridge_trigger` row exists out-of-band"
13
+ (a registry/runtime-drift claim it never actually checked). Audit-tier
14
+ lifecycle events (`connection.created`, `connection.field_changed`, …) share
15
+ the outbox with domain events and carry no triggers, so the warning fired on
16
+ ordinary, correct operation. Dogfood discovery from swe-brain. Fix: look up
17
+ triggers first, then branch — `tier:audit` **with** a registered trigger is
18
+ genuine drift (WARN, now naming the offending trigger id, + `auditBlocked:1`,
19
+ no fanout); `tier:audit` with **no** trigger is the benign shared-outbox case
20
+ (returns zeros, silent). The SELECT-level `tier='audit'` filter was rejected:
21
+ audit events still need the normal drain (`processed_at` stamp + subscriber
22
+ dispatch); only bridge fanout skips them. Revises the original AUDIT-4
23
+ top-of-method guard (`ai-docs/specs/issue-242/plan.md` §AUDIT-4 revision note).
24
+ To make a workflow react to a lifecycle moment, emit a typed domain
25
+ change-fact — do not make the audit event bridge-eligible (new bridge skill
26
+ rule).
27
+
5
28
  ## [0.27.1] — 2026-06-07
6
29
 
7
30
  ### Fixed
@@ -42,16 +42,24 @@ var BridgeOutboxDrainHook = class {
42
42
  warnedNullDirection = false;
43
43
  warnedAuditTypes = /* @__PURE__ */ new Set();
44
44
  async processEvent(event, tx) {
45
+ const triggers = this.lookupTriggers(event.type);
45
46
  if (event.metadata?.["tier"] === "audit") {
46
- this.warnAuditBlockedOnce(event);
47
+ if (triggers.length > 0) {
48
+ this.warnAuditBlockedOnce(event, triggers);
49
+ return {
50
+ delivered: 0,
51
+ dedupSkips: 0,
52
+ triggerCount: 0,
53
+ auditBlocked: 1
54
+ };
55
+ }
47
56
  return {
48
57
  delivered: 0,
49
58
  dedupSkips: 0,
50
59
  triggerCount: 0,
51
- auditBlocked: 1
60
+ auditBlocked: 0
52
61
  };
53
62
  }
54
- const triggers = this.lookupTriggers(event.type);
55
63
  if (triggers.length === 0) {
56
64
  return {
57
65
  delivered: 0,
@@ -128,11 +136,12 @@ var BridgeOutboxDrainHook = class {
128
136
  auditBlocked: 0
129
137
  };
130
138
  }
131
- warnAuditBlockedOnce(event) {
139
+ warnAuditBlockedOnce(event, triggers) {
132
140
  if (this.warnedAuditTypes.has(event.type)) return;
133
141
  this.warnedAuditTypes.add(event.type);
142
+ const triggerIds = triggers.map((t) => t.triggerId).join(", ");
134
143
  this.logger.warn(
135
- `Bridge guard blocked audit-tier event '${event.type}' (event.id=${event.id}). Registry says this event is not bridge-eligible; a bridge_trigger row exists out-of-band. Investigate registry/runtime drift.`
144
+ `Bridge guard blocked audit-tier event '${event.type}' (event.id=${event.id}). Audit events are not bridge-eligible, yet the registry has trigger(s) registered against this type [${triggerIds}] \u2014 an out-of-band bridge_trigger row or version skew. Investigate registry/runtime drift.`
136
145
  );
137
146
  }
138
147
  lookupTriggers(eventType) {
@@ -151,4 +160,4 @@ BridgeOutboxDrainHook = __decorateClass([
151
160
  export {
152
161
  BridgeOutboxDrainHook
153
162
  };
154
- //# sourceMappingURL=chunk-E5FJWOMP.js.map
163
+ //# sourceMappingURL=chunk-3AM722ZH.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../runtime/subsystems/bridge/bridge-outbox-drain-hook.ts"],"sourcesContent":["/**\n * BridgeOutboxDrainHook — drains-time bridge fanout writer (BRIDGE-4,\n * ADR-023 Phase 2).\n *\n * Implements `IBridgeOutboxDrainHook`. Called by `DrizzleEventBus`'s\n * modified `processBatch` once per drained event, INSIDE the per-event\n * transaction. For every trigger registered against the event's type in\n * the codegen-emitted `bridgeRegistry`, writes:\n *\n * 1. `bridge_delivery` ledger row — `INSERT … ON CONFLICT (event_id,\n * trigger_id) DO NOTHING RETURNING id`. Empty result ⇒ Case B\n * facade-eager pre-write OR drain-replay collision; skip wrapper\n * insert for that trigger; sibling triggers still fire.\n * 2. `job_run` wrapper row — `type='@framework/bridge_delivery'`,\n * `pool='events_<direction>'`, `input={ deliveryId }`,\n * `trigger_source='event'`, `trigger_ref=event.id`. The wrapper is\n * what the framework `BridgeDeliveryHandler` (BRIDGE-5) eventually\n * claims via the worker that polls the corresponding reserved pool.\n *\n * Null `event.metadata.direction` is tolerated: the hook logs a one-line\n * warning per event and returns zeros without writing rows. The drain's\n * `processed_at` stamp + subscriber dispatch still fire normally.\n * Direction is null only for events published via the legacy\n * `IEventBus.publish(...)` path (`TypedEventBus.publish` always sets it);\n * such events are out of scope for bridge fanout.\n *\n * The wrapper insert generates its own `id` via Drizzle's `defaultRandom`\n * — we don't `RETURNING id` because nobody needs it at drain time;\n * `BridgeDeliveryHandler` later looks up the wrapper via the\n * `bridge_delivery.wrapper_run_id` link if needed. This keeps the drain\n * one-round-trip-per-trigger.\n */\nimport { Inject, Injectable, Logger, Optional } from '@nestjs/common';\nimport { randomUUID } from 'node:crypto';\nimport { eq } from 'drizzle-orm';\n\nimport type { DomainEvent, DrizzleTransaction } from '../events/event-bus.protocol';\nimport { bridgeDelivery } from './bridge-delivery.schema';\nimport { jobRuns } from '../jobs/job-orchestration.schema';\n\nimport { BRIDGE_REGISTRY } from './bridge.tokens';\nimport type {\n BridgeOutboxDrainResult,\n BridgeRegistry,\n BridgeTriggerEntry,\n IBridgeOutboxDrainHook,\n} from './bridge.protocol';\nimport { BRIDGE_DELIVERY_JOB_TYPE } from './bridge-delivery-handler';\nimport type { EventTypeName } from '../events/event-registry';\nimport { JOBS_LISTEN_NOTIFY } from '../jobs/jobs-domain.tokens';\nimport { JOBS_WAKE_CHANNEL, pgNotify } from '../jobs/pg-notify';\n\n/** Reserved pools the wrapper rows route into; ADR-022 / ADR-024. */\nconst POOL_BY_DIRECTION: Record<string, string> = {\n inbound: 'events_inbound',\n change: 'events_change',\n outbound: 'events_outbound',\n};\n\n@Injectable()\nexport class BridgeOutboxDrainHook implements IBridgeOutboxDrainHook {\n private readonly logger = new Logger(BridgeOutboxDrainHook.name);\n private warnedNullDirection = false;\n private readonly warnedAuditTypes = new Set<string>();\n\n constructor(\n @Optional()\n @Inject(BRIDGE_REGISTRY)\n private readonly registry: BridgeRegistry = {},\n // LISTEN-NOTIFY-1 — when true, the wrapper `job_run` insert below emits an\n // in-tx `pg_notify(codegen_jobs_wake, <wrapperPool>)` so the reserved-pool\n // worker wakes the instant the per-event drain tx commits — otherwise the\n // bridge hop alone would still cost a full poll interval. `@Optional()`\n // defaulting false so the hook keeps working when jobs isn't installed\n // (bridge can drive non-jobs consumers) or in vendored/test wiring.\n @Optional()\n @Inject(JOBS_LISTEN_NOTIFY)\n private readonly listenNotify: boolean = false,\n ) {}\n\n async processEvent(\n event: DomainEvent,\n tx: DrizzleTransaction,\n ): Promise<BridgeOutboxDrainResult> {\n const triggers = this.lookupTriggers(event.type);\n\n // Audit-tier guard (defense-in-depth — AUDIT-4). Audit events are\n // bridge-inert by design: the codegen-side validator (AUDIT-2) blocks the\n // registry from listing them as triggers, so an audit event should never\n // have a matched trigger. The guard runs AFTER the lookup so it can tell\n // apart the two cases that share `tier === 'audit'`:\n // - triggers present → genuine registry/runtime drift (an out-of-band\n // `bridge_trigger` insert, or version skew during deploy). Refuse\n // fanout and surface the drift via WARN — now a verified claim, not a\n // guess. (Revises the original top-of-method guard, which warned for\n // every audit event: audit-tier lifecycle events like\n // `connection.created` routinely share the outbox with domain events,\n // so the unconditional warning was a false positive. See\n // ai-docs/specs/issue-242/plan.md §AUDIT-4 revision note.)\n // - no triggers → the common, benign case. Stay silent; auditBlocked: 0.\n if (event.metadata?.['tier'] === 'audit') {\n if (triggers.length > 0) {\n this.warnAuditBlockedOnce(event, triggers);\n return {\n delivered: 0,\n dedupSkips: 0,\n triggerCount: 0,\n auditBlocked: 1,\n };\n }\n return {\n delivered: 0,\n dedupSkips: 0,\n triggerCount: 0,\n auditBlocked: 0,\n };\n }\n\n if (triggers.length === 0) {\n return {\n delivered: 0,\n dedupSkips: 0,\n triggerCount: 0,\n auditBlocked: 0,\n };\n }\n\n const direction =\n (event.metadata?.['direction'] as string | undefined) ?? null;\n const tenantId =\n (event.metadata?.['tenantId'] as string | null | undefined) ?? null;\n const wrapperPool = direction ? POOL_BY_DIRECTION[direction] : undefined;\n\n if (!wrapperPool) {\n // Null direction (or an unrecognised one — defensive). Bridge\n // fanout requires a routed wrapper pool; without one we can't\n // spawn. Log once per process so misconfiguration surfaces.\n if (!this.warnedNullDirection) {\n this.warnedNullDirection = true;\n this.logger.warn(\n `Skipping bridge fanout for events with null/unknown direction. ` +\n `event.id=${event.id} event.type=${event.type} ` +\n `direction=${String(direction)}. The wrapper pool is derived ` +\n `from direction (events_<direction>); publishers must use ` +\n `TypedEventBus.publish() so direction is stamped on the ` +\n `outbox row.`,\n );\n }\n return {\n delivered: 0,\n dedupSkips: 0,\n triggerCount: triggers.length,\n auditBlocked: 0,\n };\n }\n\n let delivered = 0;\n let dedupSkips = 0;\n const client = tx as unknown as {\n insert: (table: unknown) => {\n values: (v: unknown) => {\n onConflictDoNothing: (opts: unknown) => {\n returning: (cols: unknown) => Promise<{ id: string }[]>;\n };\n } & {\n // wrapper insert path — no ON CONFLICT\n // (typed loosely via the same helper return shape)\n };\n };\n };\n\n for (const trigger of triggers) {\n const deliveryId = randomUUID();\n const wrapperRunId = randomUUID();\n\n // FK ORDER (BRIDGE / 0.15.2): `bridge_delivery.wrapper_run_id` REFERENCES\n // `job_run(id)` is a plain (non-deferrable) FK, so the referenced\n // wrapper `job_run` MUST exist before the delivery row that points at it\n // is inserted — otherwise Postgres rejects the delivery insert\n // immediately. (The codegen unit tests mock `tx`, so they never\n // exercised this ordering against a real FK; package-mode bridge\n // deliveries are the first to do so.) We therefore insert the wrapper\n // run FIRST, then the delivery. Idempotency is unchanged: the delivery\n // keeps its `ON CONFLICT (event_id, trigger_id) DO NOTHING RETURNING`,\n // and when the delivery conflicts (outbox replay or facade-eager Case B)\n // we DELETE the just-inserted orphan wrapper run in the same tx, so a\n // skipped delivery leaves no stray `job_run` for a worker to claim.\n\n // 1. Wrapper job_run insert. We carry the deliveryId into the wrapper\n // input so BridgeDeliveryHandler.run(ctx) can locate the row via\n // repo.findDeliveryById(ctx.input.deliveryId).\n await (tx as unknown as { insert: typeof client.insert })\n .insert(jobRuns)\n .values({\n id: wrapperRunId,\n jobType: BRIDGE_DELIVERY_JOB_TYPE,\n jobVersion: 1,\n rootRunId: wrapperRunId,\n pool: wrapperPool,\n status: 'pending',\n input: { deliveryId },\n triggerSource: 'event',\n triggerRef: event.id,\n tenantId,\n });\n\n // 2. bridge_delivery insert with ON CONFLICT DO NOTHING + RETURNING.\n const inserted = await (tx as unknown as {\n insert: typeof client.insert;\n })\n .insert(bridgeDelivery)\n .values({\n id: deliveryId,\n eventId: event.id,\n triggerId: trigger.triggerId,\n wrapperRunId,\n status: 'pending',\n tenantId,\n })\n .onConflictDoNothing({\n target: [bridgeDelivery.eventId, bridgeDelivery.triggerId],\n })\n .returning({ id: bridgeDelivery.id });\n\n if (inserted.length === 0) {\n // Case B (facade pre-wrote `delivered`) or drain replay — the delivery\n // already exists, so this trigger is a no-op. Remove the orphan wrapper\n // run we speculatively inserted above so no worker claims it. Sibling\n // triggers still fire.\n await (tx as unknown as {\n delete: (table: unknown) => {\n where: (cond: unknown) => Promise<unknown>;\n };\n })\n .delete(jobRuns)\n .where(eq(jobRuns.id, wrapperRunId));\n dedupSkips++;\n continue;\n }\n\n // LISTEN-NOTIFY-1 — the wrapper run is real and claimable; wake its\n // reserved-pool worker on commit (D7). Same `tx` as the inserts above, so\n // delivery is gated on the per-event drain tx committing. Best-effort: a\n // notify failure is non-fatal (the reserved-pool worker still polls).\n if (this.listenNotify) {\n try {\n await pgNotify(tx, JOBS_WAKE_CHANNEL, wrapperPool);\n } catch (err) {\n this.logger.warn(\n `pg_notify(${JOBS_WAKE_CHANNEL}, ${wrapperPool}) failed for ` +\n `wrapper run ${wrapperRunId}: ${(err as Error).message} ` +\n `(non-fatal — the reserved-pool worker still polls).`,\n );\n }\n }\n\n delivered++;\n }\n\n return {\n delivered,\n dedupSkips,\n triggerCount: triggers.length,\n auditBlocked: 0,\n };\n }\n\n private warnAuditBlockedOnce(\n event: DomainEvent,\n triggers: BridgeTriggerEntry[],\n ): void {\n if (this.warnedAuditTypes.has(event.type)) return;\n this.warnedAuditTypes.add(event.type);\n const triggerIds = triggers.map((t) => t.triggerId).join(', ');\n this.logger.warn(\n `Bridge guard blocked audit-tier event '${event.type}' (event.id=${event.id}). ` +\n `Audit events are not bridge-eligible, yet the registry has trigger(s) ` +\n `registered against this type [${triggerIds}] — an out-of-band bridge_trigger ` +\n `row or version skew. Investigate registry/runtime drift.`,\n );\n }\n\n private lookupTriggers(\n eventType: string,\n ): BridgeTriggerEntry[] {\n const candidates = this.registry[eventType as EventTypeName];\n return (candidates ?? []) as BridgeTriggerEntry[];\n }\n}\n"],"mappings":"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","names":[]}
@@ -1,6 +1,3 @@
1
- import {
2
- NoopAnalyticsBackend
3
- } from "./chunk-J37YWU7Y.js";
4
1
  import {
5
2
  CubeAnalyticsBackend
6
3
  } from "./chunk-7B3RYX45.js";
@@ -9,6 +6,9 @@ import {
9
6
  CUBE_API_SECRET,
10
7
  CUBE_API_URL
11
8
  } from "./chunk-6I7ULIN6.js";
9
+ import {
10
+ NoopAnalyticsBackend
11
+ } from "./chunk-J37YWU7Y.js";
12
12
  import {
13
13
  __decorateClass
14
14
  } from "./chunk-2E224ZSN.js";
@@ -50,4 +50,4 @@ AnalyticsModule = __decorateClass([
50
50
  export {
51
51
  AnalyticsModule
52
52
  };
53
- //# sourceMappingURL=chunk-DKKFTHHI.js.map
53
+ //# sourceMappingURL=chunk-CZQUOIDY.js.map
@@ -1,9 +1,9 @@
1
- import {
2
- JobsDomainModule
3
- } from "./chunk-KS4BZHIA.js";
4
1
  import {
5
2
  JobWorker
6
3
  } from "./chunk-7B7MMDOJ.js";
4
+ import {
5
+ JobsDomainModule
6
+ } from "./chunk-XW4XKN3F.js";
7
7
  import {
8
8
  BootValidationError,
9
9
  ReservedPoolViolationError
@@ -295,4 +295,4 @@ export {
295
295
  JobWorkerOrchestrator,
296
296
  JobWorkerModule
297
297
  };
298
- //# sourceMappingURL=chunk-Z7YFYK6H.js.map
298
+ //# sourceMappingURL=chunk-EGXFEZ2N.js.map
@@ -1,6 +1,3 @@
1
- import {
2
- MemoryJobRunService
3
- } from "./chunk-BHZP6LOV.js";
4
1
  import {
5
2
  DrizzleJobStepService
6
3
  } from "./chunk-DV4RV2DC.js";
@@ -13,12 +10,15 @@ import {
13
10
  import {
14
11
  MemoryJobStepService
15
12
  } from "./chunk-PNZSGAB2.js";
16
- import {
17
- MemoryJobStore
18
- } from "./chunk-SNQ3TOWP.js";
19
13
  import {
20
14
  DrizzleJobRunService
21
15
  } from "./chunk-VNBC3VXM.js";
16
+ import {
17
+ MemoryJobRunService
18
+ } from "./chunk-BHZP6LOV.js";
19
+ import {
20
+ MemoryJobStore
21
+ } from "./chunk-SNQ3TOWP.js";
22
22
  import {
23
23
  BULLMQ_CONNECTION,
24
24
  BULLMQ_RESOLVED_CONFIG,
@@ -114,4 +114,4 @@ JobsDomainModule = __decorateClass([
114
114
  export {
115
115
  JobsDomainModule
116
116
  };
117
- //# sourceMappingURL=chunk-KS4BZHIA.js.map
117
+ //# sourceMappingURL=chunk-XW4XKN3F.js.map
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-5A432NZJ.js";
4
4
  import {
5
5
  BridgeOutboxDrainHook
6
- } from "./chunk-E5FJWOMP.js";
6
+ } from "./chunk-3AM722ZH.js";
7
7
  import {
8
8
  EventFlowService
9
9
  } from "./chunk-7OVCARTQ.js";
@@ -24,7 +24,7 @@ import {
24
24
  } from "./chunk-NXXDZ6ZF.js";
25
25
  import {
26
26
  JOB_WORKER_MODULE_OPTIONS
27
- } from "./chunk-Z7YFYK6H.js";
27
+ } from "./chunk-EGXFEZ2N.js";
28
28
  import {
29
29
  BRIDGE_DELIVERY_REPO,
30
30
  BRIDGE_MODULE_OPTIONS,
@@ -119,4 +119,4 @@ BridgeModule = __decorateClass([
119
119
  export {
120
120
  BridgeModule
121
121
  };
122
- //# sourceMappingURL=chunk-36NRG2EP.js.map
122
+ //# sourceMappingURL=chunk-YQA5PMOD.js.map
@@ -1,8 +1,3 @@
1
- import {
2
- JunctionIntegrationRepository,
3
- buildCompositeExternalId,
4
- parseCompositeExternalId
5
- } from "../../chunk-2FTZLDBP.js";
6
1
  import {
7
2
  KnowledgeEntityRepository
8
3
  } from "../../chunk-NN7XZEGF.js";
@@ -18,9 +13,6 @@ import {
18
13
  import {
19
14
  WithAnalytics
20
15
  } from "../../chunk-IBGER4YK.js";
21
- import {
22
- ActivityEntityService
23
- } from "../../chunk-SJGEBMJT.js";
24
16
  import {
25
17
  BaseFindByIdUseCase,
26
18
  BaseListUseCase
@@ -32,15 +24,10 @@ import {
32
24
  IntegratedEntityService
33
25
  } from "../../chunk-5AAA4LTE.js";
34
26
  import {
35
- BaseService
36
- } from "../../chunk-BPYZCEHS.js";
37
- import {
38
- buildChangeEvents,
39
- buildLifecycleEvent,
40
- diffSnapshots,
41
- emitSafely,
42
- entitySnapshot
43
- } from "../../chunk-DAHWN63L.js";
27
+ JunctionIntegrationRepository,
28
+ buildCompositeExternalId,
29
+ parseCompositeExternalId
30
+ } from "../../chunk-2FTZLDBP.js";
44
31
  import {
45
32
  ActivityEntityRepository
46
33
  } from "../../chunk-MKWQKKK7.js";
@@ -56,6 +43,19 @@ import {
56
43
  withSuperuserScope,
57
44
  withUserScope
58
45
  } from "../../chunk-ZUKFQL6E.js";
46
+ import {
47
+ ActivityEntityService
48
+ } from "../../chunk-SJGEBMJT.js";
49
+ import {
50
+ BaseService
51
+ } from "../../chunk-BPYZCEHS.js";
52
+ import {
53
+ buildChangeEvents,
54
+ buildLifecycleEvent,
55
+ diffSnapshots,
56
+ emitSafely,
57
+ entitySnapshot
58
+ } from "../../chunk-DAHWN63L.js";
59
59
  import "../../chunk-2E224ZSN.js";
60
60
  export {
61
61
  ActivityEntityRepository,
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  AnalyticsModule
3
- } from "../../../chunk-DKKFTHHI.js";
4
- import "../../../chunk-J37YWU7Y.js";
3
+ } from "../../../chunk-CZQUOIDY.js";
5
4
  import "../../../chunk-7B3RYX45.js";
6
5
  import "../../../chunk-6I7ULIN6.js";
6
+ import "../../../chunk-J37YWU7Y.js";
7
7
  import "../../../chunk-GYGNEQSC.js";
8
8
  import "../../../chunk-2E224ZSN.js";
9
9
  export {
@@ -1,9 +1,6 @@
1
1
  import {
2
2
  AnalyticsModule
3
- } from "../../../chunk-DKKFTHHI.js";
4
- import {
5
- NoopAnalyticsBackend
6
- } from "../../../chunk-J37YWU7Y.js";
3
+ } from "../../../chunk-CZQUOIDY.js";
7
4
  import {
8
5
  CubeAnalyticsBackend
9
6
  } from "../../../chunk-7B3RYX45.js";
@@ -12,6 +9,9 @@ import {
12
9
  CUBE_API_SECRET,
13
10
  CUBE_API_URL
14
11
  } from "../../../chunk-6I7ULIN6.js";
12
+ import {
13
+ NoopAnalyticsBackend
14
+ } from "../../../chunk-J37YWU7Y.js";
15
15
  import "../../../chunk-GYGNEQSC.js";
16
16
  import "../../../chunk-2E224ZSN.js";
17
17
  export {
@@ -6,8 +6,8 @@ import "../../../chunk-N5OTOWTP.js";
6
6
  import "../../../chunk-QLTJSCE6.js";
7
7
  import "../../../chunk-BPARRK6F.js";
8
8
  import "../../../chunk-SZVPIHWE.js";
9
- import "../../../chunk-NPFPZ2HO.js";
10
9
  import "../../../chunk-6XY6ZMMD.js";
10
+ import "../../../chunk-NPFPZ2HO.js";
11
11
  import "../../../chunk-GYGNEQSC.js";
12
12
  import "../../../chunk-U64T4YZE.js";
13
13
  import "../../../chunk-2E224ZSN.js";
@@ -35,9 +35,6 @@ import {
35
35
  import {
36
36
  AuthController
37
37
  } from "../../../chunk-SZVPIHWE.js";
38
- import {
39
- authOAuthState
40
- } from "../../../chunk-NPFPZ2HO.js";
41
38
  import {
42
39
  AUTH_CONNECTION_GRANT_SINK,
43
40
  AUTH_CONNECTION_READER,
@@ -48,6 +45,9 @@ import {
48
45
  OAUTH_STATE_STORE,
49
46
  STRATEGY_REGISTRY
50
47
  } from "../../../chunk-6XY6ZMMD.js";
48
+ import {
49
+ authOAuthState
50
+ } from "../../../chunk-NPFPZ2HO.js";
51
51
  import "../../../chunk-GYGNEQSC.js";
52
52
  import "../../../chunk-U64T4YZE.js";
53
53
  import "../../../chunk-ZUKFQL6E.js";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  BridgeOutboxDrainHook
3
- } from "../../../chunk-E5FJWOMP.js";
3
+ } from "../../../chunk-3AM722ZH.js";
4
4
  import "../../../chunk-R6F6KFIL.js";
5
5
  import "../../../chunk-6DWFJNIK.js";
6
6
  import "../../../chunk-BORNCTH3.js";
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  BridgeModule
3
- } from "../../../chunk-36NRG2EP.js";
3
+ } from "../../../chunk-YQA5PMOD.js";
4
4
  import "../../../chunk-5A432NZJ.js";
5
- import "../../../chunk-E5FJWOMP.js";
5
+ import "../../../chunk-3AM722ZH.js";
6
6
  import "../../../chunk-7OVCARTQ.js";
7
7
  import "../../../chunk-EDKJU5BO.js";
8
8
  import "../../../chunk-R6F6KFIL.js";
@@ -11,16 +11,16 @@ import "../../../chunk-6DWFJNIK.js";
11
11
  import "../../../chunk-4DOJBQTP.js";
12
12
  import "../../../chunk-BORNCTH3.js";
13
13
  import "../../../chunk-NXXDZ6ZF.js";
14
- import "../../../chunk-Z7YFYK6H.js";
15
- import "../../../chunk-KS4BZHIA.js";
16
- import "../../../chunk-BHZP6LOV.js";
17
- import "../../../chunk-DV4RV2DC.js";
14
+ import "../../../chunk-EGXFEZ2N.js";
18
15
  import "../../../chunk-7B7MMDOJ.js";
16
+ import "../../../chunk-XW4XKN3F.js";
17
+ import "../../../chunk-DV4RV2DC.js";
19
18
  import "../../../chunk-E6PLM6QG.js";
20
19
  import "../../../chunk-VQOAATIG.js";
21
20
  import "../../../chunk-PNZSGAB2.js";
22
- import "../../../chunk-SNQ3TOWP.js";
23
21
  import "../../../chunk-VNBC3VXM.js";
22
+ import "../../../chunk-BHZP6LOV.js";
23
+ import "../../../chunk-SNQ3TOWP.js";
24
24
  import "../../../chunk-T4BIIU5E.js";
25
25
  import "../../../chunk-L3LZWWSX.js";
26
26
  import "../../../chunk-I6MVCB5A.js";
@@ -266,14 +266,16 @@ type BridgeRegistry = {
266
266
  * `triggerCount`: total triggers matched in the registry for this event;
267
267
  * `triggerCount === delivered + dedupSkips`.
268
268
  *
269
- * `auditBlocked`: number of events the dispatcher refused to fan out
270
- * because their `metadata.tier === 'audit'`. Audit-tier events are not
271
- * bridge-eligible; codegen errors block the registry from listing them
272
- * as triggers, so a non-zero value here indicates registry/runtime drift
273
- * (an out-of-band `bridge_trigger` insert, version skew during deploy).
274
- * Per-event: `0` when the guard does not fire, `1` when it does. Add it
275
- * to per-batch logging if your drain caller aggregates results. See
276
- * ai-docs/specs/issue-242/plan.md §AUDIT-4.
269
+ * `auditBlocked`: number of audit-tier events the dispatcher refused to fan
270
+ * out *because they had a trigger registered against them*. Audit-tier events
271
+ * are not bridge-eligible; codegen errors block the registry from listing them
272
+ * as triggers, so a non-zero value here indicates genuine registry/runtime
273
+ * drift (an out-of-band `bridge_trigger` insert, version skew during deploy).
274
+ * A benign audit-tier event one with no matched trigger, the common case for
275
+ * lifecycle events sharing the outbox returns `0` and produces no log.
276
+ * Per-event: `0` when the guard does not fire (including benign audit events),
277
+ * `1` when it fires on drift. Add it to per-batch logging if your drain caller
278
+ * aggregates results. See ai-docs/specs/issue-242/plan.md §AUDIT-4.
277
279
  */
278
280
  interface BridgeOutboxDrainResult {
279
281
  delivered: number;
@@ -307,13 +309,17 @@ interface IBridgeOutboxDrainHook {
307
309
  * job_run` row pairs for every matched trigger via the supplied `tx`.
308
310
  *
309
311
  * Behaviour:
310
- * 0. **Audit-tier guard (defense-in-depth).** If
311
- * `event.metadata.tier === 'audit'`, returns
312
+ * 0. **Audit-tier guard (defense-in-depth).** Runs *after* the registry
313
+ * lookup (step 1). If `event.metadata.tier === 'audit'` AND a trigger
314
+ * is registered against the type (genuine drift — AUDIT-2 should have
315
+ * prevented it), returns
312
316
  * `{ delivered: 0, dedupSkips: 0, triggerCount: 0, auditBlocked: 1 }`
313
- * immediately and logs a per-`(event_type, process)` WARN. The
314
- * codegen-side validator (AUDIT-2) is the primary enforcement;
315
- * this guard catches out-of-band `bridge_trigger` inserts and
316
- * version skew during deploy. See
317
+ * and logs a per-`(event_type, process)` WARN naming the offending
318
+ * trigger id(s). If the audit event has *no* matched trigger (the
319
+ * common, benign case lifecycle events sharing the outbox), returns
320
+ * all zeros (`auditBlocked: 0`) silently. The codegen-side validator
321
+ * (AUDIT-2) is the primary enforcement; this guard catches out-of-band
322
+ * `bridge_trigger` inserts and version skew. See
317
323
  * ai-docs/specs/issue-242/plan.md §AUDIT-4.
318
324
  * 1. Looks up `bridgeRegistry[event.type]`. No matches → returns
319
325
  * `{ delivered: 0, dedupSkips: 0, triggerCount: 0, auditBlocked: 0 }`;
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  BridgeModule
3
- } from "../../../chunk-36NRG2EP.js";
3
+ } from "../../../chunk-YQA5PMOD.js";
4
4
  import "../../../chunk-5A432NZJ.js";
5
5
  import {
6
6
  BridgeOutboxDrainHook
7
- } from "../../../chunk-E5FJWOMP.js";
7
+ } from "../../../chunk-3AM722ZH.js";
8
8
  import {
9
9
  EventFlowService
10
10
  } from "../../../chunk-7OVCARTQ.js";
@@ -33,16 +33,16 @@ import {
33
33
  MissingTenantIdError,
34
34
  UniqueConstraintError
35
35
  } from "../../../chunk-NXXDZ6ZF.js";
36
- import "../../../chunk-Z7YFYK6H.js";
37
- import "../../../chunk-KS4BZHIA.js";
38
- import "../../../chunk-BHZP6LOV.js";
39
- import "../../../chunk-DV4RV2DC.js";
36
+ import "../../../chunk-EGXFEZ2N.js";
40
37
  import "../../../chunk-7B7MMDOJ.js";
38
+ import "../../../chunk-XW4XKN3F.js";
39
+ import "../../../chunk-DV4RV2DC.js";
41
40
  import "../../../chunk-E6PLM6QG.js";
42
41
  import "../../../chunk-VQOAATIG.js";
43
42
  import "../../../chunk-PNZSGAB2.js";
44
- import "../../../chunk-SNQ3TOWP.js";
45
43
  import "../../../chunk-VNBC3VXM.js";
44
+ import "../../../chunk-BHZP6LOV.js";
45
+ import "../../../chunk-SNQ3TOWP.js";
46
46
  import "../../../chunk-T4BIIU5E.js";
47
47
  import "../../../chunk-L3LZWWSX.js";
48
48
  import "../../../chunk-I6MVCB5A.js";
@@ -12,6 +12,7 @@ import {
12
12
  MemoryStorageBackend
13
13
  } from "../../chunk-3SZFUTXE.js";
14
14
  import "../../chunk-J6MN42LG.js";
15
+ import "../../chunk-W4HOHZVF.js";
15
16
  import "../../chunk-FI34KYZ5.js";
16
17
  import "../../chunk-L4SDDEEU.js";
17
18
  import {
@@ -26,7 +27,6 @@ import {
26
27
  import {
27
28
  ObservabilityError
28
29
  } from "../../chunk-EWYCWP4H.js";
29
- import "../../chunk-W4HOHZVF.js";
30
30
  import "../../chunk-SYVZ4MD2.js";
31
31
  import {
32
32
  EventsModule
@@ -50,16 +50,16 @@ import {
50
50
  DrizzleEventBus
51
51
  } from "../../chunk-Y6UZMYGX.js";
52
52
  import "../../chunk-UQ5EHOH2.js";
53
- import "../../chunk-Z7YFYK6H.js";
54
- import "../../chunk-KS4BZHIA.js";
55
- import "../../chunk-BHZP6LOV.js";
56
- import "../../chunk-DV4RV2DC.js";
53
+ import "../../chunk-EGXFEZ2N.js";
57
54
  import "../../chunk-7B7MMDOJ.js";
55
+ import "../../chunk-XW4XKN3F.js";
56
+ import "../../chunk-DV4RV2DC.js";
58
57
  import "../../chunk-E6PLM6QG.js";
59
58
  import "../../chunk-VQOAATIG.js";
60
59
  import "../../chunk-PNZSGAB2.js";
61
- import "../../chunk-SNQ3TOWP.js";
62
60
  import "../../chunk-VNBC3VXM.js";
61
+ import "../../chunk-BHZP6LOV.js";
62
+ import "../../chunk-SNQ3TOWP.js";
63
63
  import "../../chunk-T4BIIU5E.js";
64
64
  import "../../chunk-L3LZWWSX.js";
65
65
  import "../../chunk-I6MVCB5A.js";
@@ -72,6 +72,21 @@ import "../../chunk-FASRXRX5.js";
72
72
  import {
73
73
  CACHE
74
74
  } from "../../chunk-L6FTY45T.js";
75
+ import "../../chunk-7C3FOSDI.js";
76
+ import {
77
+ withAuthRetry
78
+ } from "../../chunk-WL67FZGF.js";
79
+ import {
80
+ OAuth2RefreshStrategy
81
+ } from "../../chunk-M6QLSLPO.js";
82
+ import {
83
+ ConnectionBrokenError
84
+ } from "../../chunk-2N4UG4VD.js";
85
+ import {
86
+ SessionExpiredError,
87
+ isSessionExpiredError
88
+ } from "../../chunk-7RELQJIN.js";
89
+ import "../../chunk-OSQRXVG2.js";
75
90
  import "../../chunk-7P5ODGLA.js";
76
91
  import "../../chunk-ZPL74UQN.js";
77
92
  import {
@@ -93,21 +108,6 @@ import {
93
108
  waitKindEnum
94
109
  } from "../../chunk-OKXZ63IA.js";
95
110
  import "../../chunk-E2BRT5IB.js";
96
- import "../../chunk-7C3FOSDI.js";
97
- import {
98
- withAuthRetry
99
- } from "../../chunk-WL67FZGF.js";
100
- import {
101
- OAuth2RefreshStrategy
102
- } from "../../chunk-M6QLSLPO.js";
103
- import {
104
- ConnectionBrokenError
105
- } from "../../chunk-2N4UG4VD.js";
106
- import {
107
- SessionExpiredError,
108
- isSessionExpiredError
109
- } from "../../chunk-7RELQJIN.js";
110
- import "../../chunk-OSQRXVG2.js";
111
111
  import {
112
112
  AuthModule
113
113
  } from "../../chunk-7LKAMLV4.js";
@@ -126,9 +126,6 @@ import {
126
126
  import {
127
127
  AuthController
128
128
  } from "../../chunk-SZVPIHWE.js";
129
- import {
130
- authOAuthState
131
- } from "../../chunk-NPFPZ2HO.js";
132
129
  import {
133
130
  AUTH_CONNECTION_GRANT_SINK,
134
131
  AUTH_CONNECTION_READER,
@@ -139,6 +136,9 @@ import {
139
136
  OAUTH_STATE_STORE,
140
137
  STRATEGY_REGISTRY
141
138
  } from "../../chunk-6XY6ZMMD.js";
139
+ import {
140
+ authOAuthState
141
+ } from "../../chunk-NPFPZ2HO.js";
142
142
  import "../../chunk-GYGNEQSC.js";
143
143
  import "../../chunk-KVOWSC5S.js";
144
144
  import "../../chunk-VCXOPBYY.js";
@@ -2,16 +2,7 @@ import "../../../chunk-W4HOHZVF.js";
2
2
  import {
3
3
  JobWorkerModule,
4
4
  JobWorkerOrchestrator
5
- } from "../../../chunk-Z7YFYK6H.js";
6
- import {
7
- JobsDomainModule
8
- } from "../../../chunk-KS4BZHIA.js";
9
- import {
10
- MemoryJobRunService
11
- } from "../../../chunk-BHZP6LOV.js";
12
- import {
13
- DrizzleJobStepService
14
- } from "../../../chunk-DV4RV2DC.js";
5
+ } from "../../../chunk-EGXFEZ2N.js";
15
6
  import {
16
7
  JOB_WORKER_OPTIONS,
17
8
  JobWorker,
@@ -20,6 +11,12 @@ import {
20
11
  classifyError,
21
12
  computeBackoff
22
13
  } from "../../../chunk-7B7MMDOJ.js";
14
+ import {
15
+ JobsDomainModule
16
+ } from "../../../chunk-XW4XKN3F.js";
17
+ import {
18
+ DrizzleJobStepService
19
+ } from "../../../chunk-DV4RV2DC.js";
23
20
  import {
24
21
  DrizzleJobOrchestrator
25
22
  } from "../../../chunk-E6PLM6QG.js";
@@ -29,12 +26,15 @@ import {
29
26
  import {
30
27
  MemoryJobStepService
31
28
  } from "../../../chunk-PNZSGAB2.js";
32
- import {
33
- MemoryJobStore
34
- } from "../../../chunk-SNQ3TOWP.js";
35
29
  import {
36
30
  DrizzleJobRunService
37
31
  } from "../../../chunk-VNBC3VXM.js";
32
+ import {
33
+ MemoryJobRunService
34
+ } from "../../../chunk-BHZP6LOV.js";
35
+ import {
36
+ MemoryJobStore
37
+ } from "../../../chunk-SNQ3TOWP.js";
38
38
  import {
39
39
  BootValidationError,
40
40
  JobCollisionError,
@@ -2,16 +2,16 @@ import {
2
2
  JOB_WORKER_MODULE_OPTIONS,
3
3
  JobWorkerModule,
4
4
  JobWorkerOrchestrator
5
- } from "../../../chunk-Z7YFYK6H.js";
6
- import "../../../chunk-KS4BZHIA.js";
7
- import "../../../chunk-BHZP6LOV.js";
8
- import "../../../chunk-DV4RV2DC.js";
5
+ } from "../../../chunk-EGXFEZ2N.js";
9
6
  import "../../../chunk-7B7MMDOJ.js";
7
+ import "../../../chunk-XW4XKN3F.js";
8
+ import "../../../chunk-DV4RV2DC.js";
10
9
  import "../../../chunk-E6PLM6QG.js";
11
10
  import "../../../chunk-VQOAATIG.js";
12
11
  import "../../../chunk-PNZSGAB2.js";
13
- import "../../../chunk-SNQ3TOWP.js";
14
12
  import "../../../chunk-VNBC3VXM.js";
13
+ import "../../../chunk-BHZP6LOV.js";
14
+ import "../../../chunk-SNQ3TOWP.js";
15
15
  import "../../../chunk-T4BIIU5E.js";
16
16
  import "../../../chunk-L3LZWWSX.js";
17
17
  import "../../../chunk-I6MVCB5A.js";
@@ -1,13 +1,13 @@
1
1
  import {
2
2
  JobsDomainModule
3
- } from "../../../chunk-KS4BZHIA.js";
4
- import "../../../chunk-BHZP6LOV.js";
3
+ } from "../../../chunk-XW4XKN3F.js";
5
4
  import "../../../chunk-DV4RV2DC.js";
6
5
  import "../../../chunk-E6PLM6QG.js";
7
6
  import "../../../chunk-VQOAATIG.js";
8
7
  import "../../../chunk-PNZSGAB2.js";
9
- import "../../../chunk-SNQ3TOWP.js";
10
8
  import "../../../chunk-VNBC3VXM.js";
9
+ import "../../../chunk-BHZP6LOV.js";
10
+ import "../../../chunk-SNQ3TOWP.js";
11
11
  import "../../../chunk-T4BIIU5E.js";
12
12
  import "../../../chunk-L3LZWWSX.js";
13
13
  import "../../../chunk-I6MVCB5A.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pattern-stack/codegen",
3
- "version": "0.27.1",
3
+ "version": "0.27.2",
4
4
  "description": "Entity-driven code generation for full-stack TypeScript applications",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -82,22 +82,40 @@ export class BridgeOutboxDrainHook implements IBridgeOutboxDrainHook {
82
82
  event: DomainEvent,
83
83
  tx: DrizzleTransaction,
84
84
  ): Promise<BridgeOutboxDrainResult> {
85
- // Audit-tier guard (defense-in-depth — AUDIT-4). Audit events are not
86
- // bridge-eligible: the codegen-side validator (AUDIT-2) blocks the
87
- // registry from listing them as triggers. Reaching this branch means
88
- // registry/runtime drift an out-of-band `bridge_trigger` insert, or
89
- // version skew during deploy. Refuse fanout, surface drift via WARN.
85
+ const triggers = this.lookupTriggers(event.type);
86
+
87
+ // Audit-tier guard (defense-in-depth AUDIT-4). Audit events are
88
+ // bridge-inert by design: the codegen-side validator (AUDIT-2) blocks the
89
+ // registry from listing them as triggers, so an audit event should never
90
+ // have a matched trigger. The guard runs AFTER the lookup so it can tell
91
+ // apart the two cases that share `tier === 'audit'`:
92
+ // - triggers present → genuine registry/runtime drift (an out-of-band
93
+ // `bridge_trigger` insert, or version skew during deploy). Refuse
94
+ // fanout and surface the drift via WARN — now a verified claim, not a
95
+ // guess. (Revises the original top-of-method guard, which warned for
96
+ // every audit event: audit-tier lifecycle events like
97
+ // `connection.created` routinely share the outbox with domain events,
98
+ // so the unconditional warning was a false positive. See
99
+ // ai-docs/specs/issue-242/plan.md §AUDIT-4 revision note.)
100
+ // - no triggers → the common, benign case. Stay silent; auditBlocked: 0.
90
101
  if (event.metadata?.['tier'] === 'audit') {
91
- this.warnAuditBlockedOnce(event);
102
+ if (triggers.length > 0) {
103
+ this.warnAuditBlockedOnce(event, triggers);
104
+ return {
105
+ delivered: 0,
106
+ dedupSkips: 0,
107
+ triggerCount: 0,
108
+ auditBlocked: 1,
109
+ };
110
+ }
92
111
  return {
93
112
  delivered: 0,
94
113
  dedupSkips: 0,
95
114
  triggerCount: 0,
96
- auditBlocked: 1,
115
+ auditBlocked: 0,
97
116
  };
98
117
  }
99
118
 
100
- const triggers = this.lookupTriggers(event.type);
101
119
  if (triggers.length === 0) {
102
120
  return {
103
121
  delivered: 0,
@@ -247,13 +265,18 @@ export class BridgeOutboxDrainHook implements IBridgeOutboxDrainHook {
247
265
  };
248
266
  }
249
267
 
250
- private warnAuditBlockedOnce(event: DomainEvent): void {
268
+ private warnAuditBlockedOnce(
269
+ event: DomainEvent,
270
+ triggers: BridgeTriggerEntry[],
271
+ ): void {
251
272
  if (this.warnedAuditTypes.has(event.type)) return;
252
273
  this.warnedAuditTypes.add(event.type);
274
+ const triggerIds = triggers.map((t) => t.triggerId).join(', ');
253
275
  this.logger.warn(
254
276
  `Bridge guard blocked audit-tier event '${event.type}' (event.id=${event.id}). ` +
255
- `Registry says this event is not bridge-eligible; a bridge_trigger row exists ` +
256
- `out-of-band. Investigate registry/runtime drift.`,
277
+ `Audit events are not bridge-eligible, yet the registry has trigger(s) ` +
278
+ `registered against this type [${triggerIds}] — an out-of-band bridge_trigger ` +
279
+ `row or version skew. Investigate registry/runtime drift.`,
257
280
  );
258
281
  }
259
282
 
@@ -334,14 +334,16 @@ export type BridgeRegistry = {
334
334
  * `triggerCount`: total triggers matched in the registry for this event;
335
335
  * `triggerCount === delivered + dedupSkips`.
336
336
  *
337
- * `auditBlocked`: number of events the dispatcher refused to fan out
338
- * because their `metadata.tier === 'audit'`. Audit-tier events are not
339
- * bridge-eligible; codegen errors block the registry from listing them
340
- * as triggers, so a non-zero value here indicates registry/runtime drift
341
- * (an out-of-band `bridge_trigger` insert, version skew during deploy).
342
- * Per-event: `0` when the guard does not fire, `1` when it does. Add it
343
- * to per-batch logging if your drain caller aggregates results. See
344
- * ai-docs/specs/issue-242/plan.md §AUDIT-4.
337
+ * `auditBlocked`: number of audit-tier events the dispatcher refused to fan
338
+ * out *because they had a trigger registered against them*. Audit-tier events
339
+ * are not bridge-eligible; codegen errors block the registry from listing them
340
+ * as triggers, so a non-zero value here indicates genuine registry/runtime
341
+ * drift (an out-of-band `bridge_trigger` insert, version skew during deploy).
342
+ * A benign audit-tier event one with no matched trigger, the common case for
343
+ * lifecycle events sharing the outbox returns `0` and produces no log.
344
+ * Per-event: `0` when the guard does not fire (including benign audit events),
345
+ * `1` when it fires on drift. Add it to per-batch logging if your drain caller
346
+ * aggregates results. See ai-docs/specs/issue-242/plan.md §AUDIT-4.
345
347
  */
346
348
  export interface BridgeOutboxDrainResult {
347
349
  delivered: number;
@@ -376,13 +378,17 @@ export interface IBridgeOutboxDrainHook {
376
378
  * job_run` row pairs for every matched trigger via the supplied `tx`.
377
379
  *
378
380
  * Behaviour:
379
- * 0. **Audit-tier guard (defense-in-depth).** If
380
- * `event.metadata.tier === 'audit'`, returns
381
+ * 0. **Audit-tier guard (defense-in-depth).** Runs *after* the registry
382
+ * lookup (step 1). If `event.metadata.tier === 'audit'` AND a trigger
383
+ * is registered against the type (genuine drift — AUDIT-2 should have
384
+ * prevented it), returns
381
385
  * `{ delivered: 0, dedupSkips: 0, triggerCount: 0, auditBlocked: 1 }`
382
- * immediately and logs a per-`(event_type, process)` WARN. The
383
- * codegen-side validator (AUDIT-2) is the primary enforcement;
384
- * this guard catches out-of-band `bridge_trigger` inserts and
385
- * version skew during deploy. See
386
+ * and logs a per-`(event_type, process)` WARN naming the offending
387
+ * trigger id(s). If the audit event has *no* matched trigger (the
388
+ * common, benign case lifecycle events sharing the outbox), returns
389
+ * all zeros (`auditBlocked: 0`) silently. The codegen-side validator
390
+ * (AUDIT-2) is the primary enforcement; this guard catches out-of-band
391
+ * `bridge_trigger` inserts and version skew. See
386
392
  * ai-docs/specs/issue-242/plan.md §AUDIT-4.
387
393
  * 1. Looks up `bridgeRegistry[event.type]`. No matches → returns
388
394
  * `{ delivered: 0, dedupSkips: 0, triggerCount: 0, auditBlocked: 0 }`;
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../runtime/subsystems/bridge/bridge-outbox-drain-hook.ts"],"sourcesContent":["/**\n * BridgeOutboxDrainHook — drains-time bridge fanout writer (BRIDGE-4,\n * ADR-023 Phase 2).\n *\n * Implements `IBridgeOutboxDrainHook`. Called by `DrizzleEventBus`'s\n * modified `processBatch` once per drained event, INSIDE the per-event\n * transaction. For every trigger registered against the event's type in\n * the codegen-emitted `bridgeRegistry`, writes:\n *\n * 1. `bridge_delivery` ledger row — `INSERT … ON CONFLICT (event_id,\n * trigger_id) DO NOTHING RETURNING id`. Empty result ⇒ Case B\n * facade-eager pre-write OR drain-replay collision; skip wrapper\n * insert for that trigger; sibling triggers still fire.\n * 2. `job_run` wrapper row — `type='@framework/bridge_delivery'`,\n * `pool='events_<direction>'`, `input={ deliveryId }`,\n * `trigger_source='event'`, `trigger_ref=event.id`. The wrapper is\n * what the framework `BridgeDeliveryHandler` (BRIDGE-5) eventually\n * claims via the worker that polls the corresponding reserved pool.\n *\n * Null `event.metadata.direction` is tolerated: the hook logs a one-line\n * warning per event and returns zeros without writing rows. The drain's\n * `processed_at` stamp + subscriber dispatch still fire normally.\n * Direction is null only for events published via the legacy\n * `IEventBus.publish(...)` path (`TypedEventBus.publish` always sets it);\n * such events are out of scope for bridge fanout.\n *\n * The wrapper insert generates its own `id` via Drizzle's `defaultRandom`\n * — we don't `RETURNING id` because nobody needs it at drain time;\n * `BridgeDeliveryHandler` later looks up the wrapper via the\n * `bridge_delivery.wrapper_run_id` link if needed. This keeps the drain\n * one-round-trip-per-trigger.\n */\nimport { Inject, Injectable, Logger, Optional } from '@nestjs/common';\nimport { randomUUID } from 'node:crypto';\nimport { eq } from 'drizzle-orm';\n\nimport type { DomainEvent, DrizzleTransaction } from '../events/event-bus.protocol';\nimport { bridgeDelivery } from './bridge-delivery.schema';\nimport { jobRuns } from '../jobs/job-orchestration.schema';\n\nimport { BRIDGE_REGISTRY } from './bridge.tokens';\nimport type {\n BridgeOutboxDrainResult,\n BridgeRegistry,\n BridgeTriggerEntry,\n IBridgeOutboxDrainHook,\n} from './bridge.protocol';\nimport { BRIDGE_DELIVERY_JOB_TYPE } from './bridge-delivery-handler';\nimport type { EventTypeName } from '../events/event-registry';\nimport { JOBS_LISTEN_NOTIFY } from '../jobs/jobs-domain.tokens';\nimport { JOBS_WAKE_CHANNEL, pgNotify } from '../jobs/pg-notify';\n\n/** Reserved pools the wrapper rows route into; ADR-022 / ADR-024. */\nconst POOL_BY_DIRECTION: Record<string, string> = {\n inbound: 'events_inbound',\n change: 'events_change',\n outbound: 'events_outbound',\n};\n\n@Injectable()\nexport class BridgeOutboxDrainHook implements IBridgeOutboxDrainHook {\n private readonly logger = new Logger(BridgeOutboxDrainHook.name);\n private warnedNullDirection = false;\n private readonly warnedAuditTypes = new Set<string>();\n\n constructor(\n @Optional()\n @Inject(BRIDGE_REGISTRY)\n private readonly registry: BridgeRegistry = {},\n // LISTEN-NOTIFY-1 — when true, the wrapper `job_run` insert below emits an\n // in-tx `pg_notify(codegen_jobs_wake, <wrapperPool>)` so the reserved-pool\n // worker wakes the instant the per-event drain tx commits — otherwise the\n // bridge hop alone would still cost a full poll interval. `@Optional()`\n // defaulting false so the hook keeps working when jobs isn't installed\n // (bridge can drive non-jobs consumers) or in vendored/test wiring.\n @Optional()\n @Inject(JOBS_LISTEN_NOTIFY)\n private readonly listenNotify: boolean = false,\n ) {}\n\n async processEvent(\n event: DomainEvent,\n tx: DrizzleTransaction,\n ): Promise<BridgeOutboxDrainResult> {\n // Audit-tier guard (defense-in-depth — AUDIT-4). Audit events are not\n // bridge-eligible: the codegen-side validator (AUDIT-2) blocks the\n // registry from listing them as triggers. Reaching this branch means\n // registry/runtime drift — an out-of-band `bridge_trigger` insert, or\n // version skew during deploy. Refuse fanout, surface drift via WARN.\n if (event.metadata?.['tier'] === 'audit') {\n this.warnAuditBlockedOnce(event);\n return {\n delivered: 0,\n dedupSkips: 0,\n triggerCount: 0,\n auditBlocked: 1,\n };\n }\n\n const triggers = this.lookupTriggers(event.type);\n if (triggers.length === 0) {\n return {\n delivered: 0,\n dedupSkips: 0,\n triggerCount: 0,\n auditBlocked: 0,\n };\n }\n\n const direction =\n (event.metadata?.['direction'] as string | undefined) ?? null;\n const tenantId =\n (event.metadata?.['tenantId'] as string | null | undefined) ?? null;\n const wrapperPool = direction ? POOL_BY_DIRECTION[direction] : undefined;\n\n if (!wrapperPool) {\n // Null direction (or an unrecognised one — defensive). Bridge\n // fanout requires a routed wrapper pool; without one we can't\n // spawn. Log once per process so misconfiguration surfaces.\n if (!this.warnedNullDirection) {\n this.warnedNullDirection = true;\n this.logger.warn(\n `Skipping bridge fanout for events with null/unknown direction. ` +\n `event.id=${event.id} event.type=${event.type} ` +\n `direction=${String(direction)}. The wrapper pool is derived ` +\n `from direction (events_<direction>); publishers must use ` +\n `TypedEventBus.publish() so direction is stamped on the ` +\n `outbox row.`,\n );\n }\n return {\n delivered: 0,\n dedupSkips: 0,\n triggerCount: triggers.length,\n auditBlocked: 0,\n };\n }\n\n let delivered = 0;\n let dedupSkips = 0;\n const client = tx as unknown as {\n insert: (table: unknown) => {\n values: (v: unknown) => {\n onConflictDoNothing: (opts: unknown) => {\n returning: (cols: unknown) => Promise<{ id: string }[]>;\n };\n } & {\n // wrapper insert path — no ON CONFLICT\n // (typed loosely via the same helper return shape)\n };\n };\n };\n\n for (const trigger of triggers) {\n const deliveryId = randomUUID();\n const wrapperRunId = randomUUID();\n\n // FK ORDER (BRIDGE / 0.15.2): `bridge_delivery.wrapper_run_id` REFERENCES\n // `job_run(id)` is a plain (non-deferrable) FK, so the referenced\n // wrapper `job_run` MUST exist before the delivery row that points at it\n // is inserted — otherwise Postgres rejects the delivery insert\n // immediately. (The codegen unit tests mock `tx`, so they never\n // exercised this ordering against a real FK; package-mode bridge\n // deliveries are the first to do so.) We therefore insert the wrapper\n // run FIRST, then the delivery. Idempotency is unchanged: the delivery\n // keeps its `ON CONFLICT (event_id, trigger_id) DO NOTHING RETURNING`,\n // and when the delivery conflicts (outbox replay or facade-eager Case B)\n // we DELETE the just-inserted orphan wrapper run in the same tx, so a\n // skipped delivery leaves no stray `job_run` for a worker to claim.\n\n // 1. Wrapper job_run insert. We carry the deliveryId into the wrapper\n // input so BridgeDeliveryHandler.run(ctx) can locate the row via\n // repo.findDeliveryById(ctx.input.deliveryId).\n await (tx as unknown as { insert: typeof client.insert })\n .insert(jobRuns)\n .values({\n id: wrapperRunId,\n jobType: BRIDGE_DELIVERY_JOB_TYPE,\n jobVersion: 1,\n rootRunId: wrapperRunId,\n pool: wrapperPool,\n status: 'pending',\n input: { deliveryId },\n triggerSource: 'event',\n triggerRef: event.id,\n tenantId,\n });\n\n // 2. bridge_delivery insert with ON CONFLICT DO NOTHING + RETURNING.\n const inserted = await (tx as unknown as {\n insert: typeof client.insert;\n })\n .insert(bridgeDelivery)\n .values({\n id: deliveryId,\n eventId: event.id,\n triggerId: trigger.triggerId,\n wrapperRunId,\n status: 'pending',\n tenantId,\n })\n .onConflictDoNothing({\n target: [bridgeDelivery.eventId, bridgeDelivery.triggerId],\n })\n .returning({ id: bridgeDelivery.id });\n\n if (inserted.length === 0) {\n // Case B (facade pre-wrote `delivered`) or drain replay — the delivery\n // already exists, so this trigger is a no-op. Remove the orphan wrapper\n // run we speculatively inserted above so no worker claims it. Sibling\n // triggers still fire.\n await (tx as unknown as {\n delete: (table: unknown) => {\n where: (cond: unknown) => Promise<unknown>;\n };\n })\n .delete(jobRuns)\n .where(eq(jobRuns.id, wrapperRunId));\n dedupSkips++;\n continue;\n }\n\n // LISTEN-NOTIFY-1 — the wrapper run is real and claimable; wake its\n // reserved-pool worker on commit (D7). Same `tx` as the inserts above, so\n // delivery is gated on the per-event drain tx committing. Best-effort: a\n // notify failure is non-fatal (the reserved-pool worker still polls).\n if (this.listenNotify) {\n try {\n await pgNotify(tx, JOBS_WAKE_CHANNEL, wrapperPool);\n } catch (err) {\n this.logger.warn(\n `pg_notify(${JOBS_WAKE_CHANNEL}, ${wrapperPool}) failed for ` +\n `wrapper run ${wrapperRunId}: ${(err as Error).message} ` +\n `(non-fatal — the reserved-pool worker still polls).`,\n );\n }\n }\n\n delivered++;\n }\n\n return {\n delivered,\n dedupSkips,\n triggerCount: triggers.length,\n auditBlocked: 0,\n };\n }\n\n private warnAuditBlockedOnce(event: DomainEvent): void {\n if (this.warnedAuditTypes.has(event.type)) return;\n this.warnedAuditTypes.add(event.type);\n this.logger.warn(\n `Bridge guard blocked audit-tier event '${event.type}' (event.id=${event.id}). ` +\n `Registry says this event is not bridge-eligible; a bridge_trigger row exists ` +\n `out-of-band. Investigate registry/runtime drift.`,\n );\n }\n\n private lookupTriggers(\n eventType: string,\n ): BridgeTriggerEntry[] {\n const candidates = this.registry[eventType as EventTypeName];\n return (candidates ?? []) as BridgeTriggerEntry[];\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAgCA,SAAS,QAAQ,YAAY,QAAQ,gBAAgB;AACrD,SAAS,kBAAkB;AAC3B,SAAS,UAAU;AAmBnB,IAAM,oBAA4C;AAAA,EAChD,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,UAAU;AACZ;AAGO,IAAM,wBAAN,MAA8D;AAAA,EAKnE,YAGmB,WAA2B,CAAC,GAS5B,eAAwB,OACzC;AAViB;AASA;AAAA,EAChB;AAAA,EAVgB;AAAA,EASA;AAAA,EAhBF,SAAS,IAAI,OAAO,sBAAsB,IAAI;AAAA,EACvD,sBAAsB;AAAA,EACb,mBAAmB,oBAAI,IAAY;AAAA,EAiBpD,MAAM,aACJ,OACA,IACkC;AAMlC,QAAI,MAAM,WAAW,MAAM,MAAM,SAAS;AACxC,WAAK,qBAAqB,KAAK;AAC/B,aAAO;AAAA,QACL,WAAW;AAAA,QACX,YAAY;AAAA,QACZ,cAAc;AAAA,QACd,cAAc;AAAA,MAChB;AAAA,IACF;AAEA,UAAM,WAAW,KAAK,eAAe,MAAM,IAAI;AAC/C,QAAI,SAAS,WAAW,GAAG;AACzB,aAAO;AAAA,QACL,WAAW;AAAA,QACX,YAAY;AAAA,QACZ,cAAc;AAAA,QACd,cAAc;AAAA,MAChB;AAAA,IACF;AAEA,UAAM,YACH,MAAM,WAAW,WAAW,KAA4B;AAC3D,UAAM,WACH,MAAM,WAAW,UAAU,KAAmC;AACjE,UAAM,cAAc,YAAY,kBAAkB,SAAS,IAAI;AAE/D,QAAI,CAAC,aAAa;AAIhB,UAAI,CAAC,KAAK,qBAAqB;AAC7B,aAAK,sBAAsB;AAC3B,aAAK,OAAO;AAAA,UACV,2EACc,MAAM,EAAE,eAAe,MAAM,IAAI,cAChC,OAAO,SAAS,CAAC;AAAA,QAIlC;AAAA,MACF;AACA,aAAO;AAAA,QACL,WAAW;AAAA,QACX,YAAY;AAAA,QACZ,cAAc,SAAS;AAAA,QACvB,cAAc;AAAA,MAChB;AAAA,IACF;AAEA,QAAI,YAAY;AAChB,QAAI,aAAa;AACjB,UAAM,SAAS;AAaf,eAAW,WAAW,UAAU;AAC9B,YAAM,aAAa,WAAW;AAC9B,YAAM,eAAe,WAAW;AAkBhC,YAAO,GACJ,OAAO,OAAO,EACd,OAAO;AAAA,QACN,IAAI;AAAA,QACJ,SAAS;AAAA,QACT,YAAY;AAAA,QACZ,WAAW;AAAA,QACX,MAAM;AAAA,QACN,QAAQ;AAAA,QACR,OAAO,EAAE,WAAW;AAAA,QACpB,eAAe;AAAA,QACf,YAAY,MAAM;AAAA,QAClB;AAAA,MACF,CAAC;AAGH,YAAM,WAAW,MAAO,GAGrB,OAAO,cAAc,EACrB,OAAO;AAAA,QACN,IAAI;AAAA,QACJ,SAAS,MAAM;AAAA,QACf,WAAW,QAAQ;AAAA,QACnB;AAAA,QACA,QAAQ;AAAA,QACR;AAAA,MACF,CAAC,EACA,oBAAoB;AAAA,QACnB,QAAQ,CAAC,eAAe,SAAS,eAAe,SAAS;AAAA,MAC3D,CAAC,EACA,UAAU,EAAE,IAAI,eAAe,GAAG,CAAC;AAEtC,UAAI,SAAS,WAAW,GAAG;AAKzB,cAAO,GAKJ,OAAO,OAAO,EACd,MAAM,GAAG,QAAQ,IAAI,YAAY,CAAC;AACrC;AACA;AAAA,MACF;AAMA,UAAI,KAAK,cAAc;AACrB,YAAI;AACF,gBAAM,SAAS,IAAI,mBAAmB,WAAW;AAAA,QACnD,SAAS,KAAK;AACZ,eAAK,OAAO;AAAA,YACV,aAAa,iBAAiB,KAAK,WAAW,4BAC7B,YAAY,KAAM,IAAc,OAAO;AAAA,UAE1D;AAAA,QACF;AAAA,MACF;AAEA;AAAA,IACF;AAEA,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA,cAAc,SAAS;AAAA,MACvB,cAAc;AAAA,IAChB;AAAA,EACF;AAAA,EAEQ,qBAAqB,OAA0B;AACrD,QAAI,KAAK,iBAAiB,IAAI,MAAM,IAAI,EAAG;AAC3C,SAAK,iBAAiB,IAAI,MAAM,IAAI;AACpC,SAAK,OAAO;AAAA,MACV,0CAA0C,MAAM,IAAI,eAAe,MAAM,EAAE;AAAA,IAG7E;AAAA,EACF;AAAA,EAEQ,eACN,WACsB;AACtB,UAAM,aAAa,KAAK,SAAS,SAA0B;AAC3D,WAAQ,cAAc,CAAC;AAAA,EACzB;AACF;AA7Ma,wBAAN;AAAA,EADN,WAAW;AAAA,EAOP,4BAAS;AAAA,EACT,0BAAO,eAAe;AAAA,EAQtB,4BAAS;AAAA,EACT,0BAAO,kBAAkB;AAAA,GAhBjB;","names":[]}