arkgate 2.7.0 → 2.8.1

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 (40) hide show
  1. package/CHANGELOG.md +45 -1
  2. package/README.md +8 -0
  3. package/bin/lib/agent-gates.mjs +48 -228
  4. package/bin/lib/architecture-scan.mjs +20 -0
  5. package/bin/lib/ast-scan.mjs +232 -4
  6. package/bin/lib/codex-home.mjs +320 -0
  7. package/bin/lib/doctor-plan.mjs +2 -0
  8. package/bin/lib/remediation.mjs +44 -12
  9. package/bin/lib/ts-resolve.mjs +5 -4
  10. package/dist/index.cjs +417 -338
  11. package/dist/index.cjs.map +1 -1
  12. package/dist/index.d.cts +29 -9
  13. package/dist/index.d.ts +29 -9
  14. package/dist/index.js +417 -338
  15. package/dist/index.js.map +1 -1
  16. package/dist/nestjs/index.cjs +452 -373
  17. package/dist/nestjs/index.cjs.map +1 -1
  18. package/dist/nestjs/index.d.cts +1 -1
  19. package/dist/nestjs/index.d.ts +1 -1
  20. package/dist/nestjs/index.js +452 -373
  21. package/dist/nestjs/index.js.map +1 -1
  22. package/dist/runtime/index.cjs +417 -338
  23. package/dist/runtime/index.cjs.map +1 -1
  24. package/dist/runtime/index.d.cts +1 -1
  25. package/dist/runtime/index.d.ts +1 -1
  26. package/dist/runtime/index.js +417 -338
  27. package/dist/runtime/index.js.map +1 -1
  28. package/dist/{types-CP3KkwZt.d.cts → types-CSJhEOk2.d.cts} +34 -0
  29. package/dist/{types-CP3KkwZt.d.ts → types-CSJhEOk2.d.ts} +34 -0
  30. package/docs/agent-guide.md +1 -1
  31. package/docs/ai-gates.md +41 -7
  32. package/docs/brownfield-adoption.md +7 -0
  33. package/docs/demos/03-copilot-autopilot.md +3 -2
  34. package/docs/enthusiast/reference-commands.md +2 -2
  35. package/docs/package-surface.md +1 -1
  36. package/docs/production-hardening.md +11 -4
  37. package/package.json +2 -1
  38. package/server.json +2 -2
  39. package/templates/skills/ark-explain.md +3 -2
  40. package/templates/skills/ark-loop.md +2 -1
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/version.ts
2
- var version = "2.7.0";
2
+ var version = "2.8.1";
3
3
 
4
4
  // src/kernel/intent/IntentRegistry.ts
5
5
  var IntentRegistry = class {
@@ -467,12 +467,39 @@ var ObservedLayerFlowViolationError = class extends Error {
467
467
  }
468
468
  };
469
469
 
470
- // src/kernel/event-bus/EventBus.ts
471
- var interceptorSequence = 0;
472
- function nextInterceptorRegistrationId() {
473
- interceptorSequence += 1;
474
- return `interceptor-${Date.now()}-${interceptorSequence}`;
470
+ // src/kernel/event-bus/publishGuards.ts
471
+ function assertIntentAllowed(intentName, options) {
472
+ if (!options.strictRegistry && !options.validateIntentNaming) {
473
+ return;
474
+ }
475
+ if (options.validateIntentNaming) {
476
+ const validation = validateIntentName(intentName);
477
+ if (!validation.valid) {
478
+ throw new InvalidIntentNameError(intentName, validation.reason);
479
+ }
480
+ }
481
+ if (options.strictRegistry && options.intentRegistry && !options.intentRegistry.has(intentName)) {
482
+ throw new UnregisteredIntentError(intentName);
483
+ }
484
+ }
485
+ function assertSourceAllowed(event, options) {
486
+ if (!options.requireKnownSource) return;
487
+ if (!event.metadata.source || event.metadata.source === "unknown") {
488
+ throw new UnknownEventSourceError(event.intent);
489
+ }
490
+ if (options.intentRegistry && !options.intentRegistry.has(event.metadata.source)) {
491
+ throw new UnknownEventSourceError(event.intent, event.metadata.source);
492
+ }
475
493
  }
494
+ function assertContractAllowed(event, options) {
495
+ if (!options.eventContracts) return;
496
+ const result = options.eventContracts.validate(event);
497
+ if (!result.ok && (options.strictEventContracts || result.contract)) {
498
+ throw new EventContractViolationError(event.intent, result.issues);
499
+ }
500
+ }
501
+
502
+ // src/kernel/event-bus/payloadPatch.ts
476
503
  function isPlainRecord(value) {
477
504
  if (typeof value !== "object" || value === null || Array.isArray(value)) {
478
505
  return false;
@@ -543,29 +570,318 @@ function applyPayloadPatch(payload, patch) {
543
570
  }
544
571
  return mergeRecordPatch(payload, patch);
545
572
  }
573
+
574
+ // src/kernel/event-bus/publishInterceptors.ts
575
+ async function applyInterceptors(event, deps) {
576
+ if (event.metadata.allowInterception === false) {
577
+ return event;
578
+ }
579
+ const matching = [...deps.interceptorsForIntent(event.intent)];
580
+ let current = event;
581
+ for (const registration of matching) {
582
+ const patches = [];
583
+ try {
584
+ await Promise.resolve(
585
+ registration.interceptor({
586
+ event: current,
587
+ intercept: (patch) => {
588
+ patches.push(patch);
589
+ }
590
+ })
591
+ );
592
+ if (patches.length === 0) {
593
+ continue;
594
+ }
595
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString();
596
+ let candidate = {
597
+ ...current,
598
+ metadata: {
599
+ ...current.metadata,
600
+ interceptions: [
601
+ ...current.metadata.interceptions ?? [],
602
+ { interceptorId: registration.interceptorId, timestamp }
603
+ ]
604
+ }
605
+ };
606
+ for (const patch of patches) {
607
+ candidate = {
608
+ ...candidate,
609
+ payload: applyPayloadPatch(candidate.payload, patch),
610
+ metadata: { ...candidate.metadata }
611
+ };
612
+ }
613
+ assertContractAllowed(candidate, {
614
+ eventContracts: deps.eventContracts,
615
+ strictEventContracts: deps.strictEventContracts
616
+ });
617
+ current = candidate;
618
+ registration.lastInterceptedAt = timestamp;
619
+ deps.appendTrace({
620
+ type: "event.intercepted",
621
+ timestamp,
622
+ intent: current.intent,
623
+ correlationId: current.metadata.correlationId,
624
+ traceId: current.metadata.traceId,
625
+ spanId: current.metadata.spanId,
626
+ details: {
627
+ registrationId: registration.registrationId,
628
+ interceptorId: registration.interceptorId,
629
+ patchesApplied: patches.length
630
+ }
631
+ });
632
+ await deps.recordAudit("event.intercepted", current, {
633
+ registrationId: registration.registrationId,
634
+ interceptorId: registration.interceptorId,
635
+ patchesApplied: patches.length
636
+ });
637
+ } catch (err) {
638
+ await recordInterceptorError(registration, current, err, deps);
639
+ }
640
+ }
641
+ return current;
642
+ }
643
+ async function recordInterceptorError(interceptor, event, error, deps) {
644
+ const message = error instanceof Error ? error.message : String(error);
645
+ deps.appendTrace({
646
+ type: "interceptor.error",
647
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
648
+ intent: event.intent,
649
+ correlationId: event.metadata.correlationId,
650
+ traceId: event.metadata.traceId,
651
+ spanId: event.metadata.spanId,
652
+ details: {
653
+ registrationId: interceptor.registrationId,
654
+ interceptorId: interceptor.interceptorId,
655
+ error: message
656
+ }
657
+ });
658
+ await deps.recordAudit("interceptor.error", event, {
659
+ registrationId: interceptor.registrationId,
660
+ interceptorId: interceptor.interceptorId,
661
+ error: message
662
+ });
663
+ }
664
+
665
+ // src/kernel/event-bus/observedLayerFlow.ts
666
+ async function assertObservedLayerFlowAllowed(event, deps) {
667
+ if (deps.mode === "off" || !deps.architectureProfile) {
668
+ return;
669
+ }
670
+ const source = event.metadata.source;
671
+ if (!source || source === "unknown") return;
672
+ const profile = deps.architectureProfile;
673
+ const fromLayer = profile.resolveLayer(source);
674
+ const toLayer = profile.resolveLayer(event.intent);
675
+ if (!fromLayer || !toLayer) return;
676
+ const blocked = profile.rules.find(
677
+ (rule) => !rule.allowed && rule.from === fromLayer && rule.to === toLayer
678
+ );
679
+ if (!blocked) return;
680
+ const severity = deps.mode;
681
+ const message = blocked.message ?? `Observed layer violation: "${source}" (${fromLayer}) must not produce "${event.intent}" (${toLayer}).`;
682
+ const details = {
683
+ source,
684
+ intent: event.intent,
685
+ fromLayer,
686
+ toLayer,
687
+ severity,
688
+ message,
689
+ rule: blocked
690
+ };
691
+ deps.appendTrace({
692
+ type: "layer.observedViolation",
693
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
694
+ intent: event.intent,
695
+ correlationId: event.metadata.correlationId,
696
+ traceId: event.metadata.traceId,
697
+ spanId: event.metadata.spanId,
698
+ details
699
+ });
700
+ await deps.recordAudit("layer.observedViolation", event, details);
701
+ if (severity === "hard") {
702
+ throw new ObservedLayerFlowViolationError(
703
+ source,
704
+ event.intent,
705
+ fromLayer,
706
+ toLayer,
707
+ message
708
+ );
709
+ }
710
+ }
711
+
712
+ // src/kernel/event-bus/publishPolicy.ts
713
+ async function enforcePublishPolicy(event, deps) {
714
+ const ctx = deps.getPolicyContext(event);
715
+ let policyResult;
716
+ try {
717
+ policyResult = deps.policyEngine.enforce(ctx);
718
+ } catch (err) {
719
+ if (err instanceof PolicyViolationError) {
720
+ deps.appendTrace({
721
+ type: "policy.hardViolation",
722
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
723
+ intent: event.intent,
724
+ correlationId: event.metadata.correlationId,
725
+ traceId: event.metadata.traceId,
726
+ spanId: event.metadata.spanId,
727
+ details: { violations: err.violations }
728
+ });
729
+ await deps.recordAudit("policy.hardViolation", event, {
730
+ violations: err.violations
731
+ });
732
+ }
733
+ throw err;
734
+ }
735
+ if (policyResult.softViolations.length > 0) {
736
+ deps.appendTrace({
737
+ type: "policy.softViolation",
738
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
739
+ intent: event.intent,
740
+ correlationId: event.metadata.correlationId,
741
+ traceId: event.metadata.traceId,
742
+ spanId: event.metadata.spanId,
743
+ details: { violations: policyResult.softViolations }
744
+ });
745
+ await deps.recordAudit("policy.softViolation", event, {
746
+ violations: policyResult.softViolations
747
+ });
748
+ if (deps.onSoftViolation) {
749
+ await deps.safeHook(
750
+ () => deps.onSoftViolation(policyResult, event),
751
+ "onSoftViolation",
752
+ event
753
+ );
754
+ }
755
+ }
756
+ }
757
+
758
+ // src/kernel/event-bus/publishRecording.ts
759
+ function appendHistory(buffers, record) {
760
+ buffers.history.push(record);
761
+ if (buffers.maxHistorySize !== void 0 && buffers.history.length > buffers.maxHistorySize) {
762
+ buffers.history.splice(0, buffers.history.length - buffers.maxHistorySize);
763
+ }
764
+ }
765
+ function appendTrace(buffers, record) {
766
+ buffers.trace.push(record);
767
+ if (buffers.maxHistorySize !== void 0 && buffers.trace.length > buffers.maxHistorySize) {
768
+ buffers.trace.splice(0, buffers.trace.length - buffers.maxHistorySize);
769
+ }
770
+ for (const sink of buffers.traceSinks) {
771
+ try {
772
+ sink(record);
773
+ } catch {
774
+ }
775
+ }
776
+ }
777
+ async function recordAudit(buffers, type, event, details) {
778
+ if (!buffers.auditTrail) return;
779
+ try {
780
+ await buffers.auditTrail.record({
781
+ type,
782
+ source: event.metadata.source,
783
+ intent: event.intent,
784
+ correlationId: event.metadata.correlationId,
785
+ causationId: event.metadata.causationId,
786
+ subject: event.intent,
787
+ details
788
+ });
789
+ } catch (err) {
790
+ appendTrace(buffers, {
791
+ type: "hook.error",
792
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
793
+ intent: event.intent,
794
+ correlationId: event.metadata.correlationId,
795
+ traceId: event.metadata.traceId,
796
+ spanId: event.metadata.spanId,
797
+ details: {
798
+ hook: "auditTrail",
799
+ error: err instanceof Error ? err.message : String(err)
800
+ }
801
+ });
802
+ }
803
+ }
804
+ async function recordRawPublishDiagnostic(buffers, event) {
805
+ const details = {
806
+ intent: event.intent,
807
+ source: event.metadata.source,
808
+ suggestion: "Publish through a registered intent creator so strict registry, contracts, and agent tooling share one source of truth."
809
+ };
810
+ appendTrace(buffers, {
811
+ type: "event.rawPublish",
812
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
813
+ intent: event.intent,
814
+ correlationId: event.metadata.correlationId,
815
+ traceId: event.metadata.traceId,
816
+ spanId: event.metadata.spanId,
817
+ details
818
+ });
819
+ await recordAudit(buffers, "event.rawPublish", event, details);
820
+ }
821
+ async function recordSuccessfulPublish(buffers, event, subscribersNotified) {
822
+ const record = {
823
+ event,
824
+ publishedAt: (/* @__PURE__ */ new Date()).toISOString(),
825
+ subscribersNotified
826
+ };
827
+ appendHistory(buffers, record);
828
+ await buffers.outbox?.enqueue(event);
829
+ appendTrace(buffers, {
830
+ type: "event.published",
831
+ timestamp: record.publishedAt,
832
+ intent: event.intent,
833
+ correlationId: event.metadata.correlationId,
834
+ traceId: event.metadata.traceId,
835
+ spanId: event.metadata.spanId,
836
+ details: { subscribersNotified }
837
+ });
838
+ await recordAudit(buffers, "event.published", event, {
839
+ subscribersNotified
840
+ });
841
+ return record;
842
+ }
843
+ function enrichMetadata(base, extra, instanceId) {
844
+ return {
845
+ ...base,
846
+ ...extra,
847
+ occurredAt: extra.occurredAt || base.occurredAt || (/* @__PURE__ */ new Date()).toISOString(),
848
+ source: extra.source || base.source || "unknown",
849
+ kernelInstanceId: extra.kernelInstanceId ?? base.kernelInstanceId ?? instanceId,
850
+ eventVersion: extra.eventVersion ?? base.eventVersion,
851
+ schemaVersion: extra.schemaVersion ?? base.schemaVersion,
852
+ allowInterception: extra.allowInterception ?? base.allowInterception,
853
+ interceptions: extra.interceptions ?? base.interceptions,
854
+ correlationId: extra.correlationId ?? base.correlationId,
855
+ causationId: extra.causationId ?? base.causationId,
856
+ traceId: extra.traceId ?? base.traceId,
857
+ spanId: extra.spanId ?? base.spanId,
858
+ parentSpanId: extra.parentSpanId ?? base.parentSpanId
859
+ };
860
+ }
861
+
862
+ // src/kernel/event-bus/EventBus.ts
863
+ var interceptorSequence = 0;
864
+ function nextInterceptorRegistrationId() {
865
+ interceptorSequence += 1;
866
+ return `interceptor-${Date.now()}-${interceptorSequence}`;
867
+ }
546
868
  var EventBusImpl = class {
547
869
  subscriptions = [];
548
870
  subscriptionsByIntent = /* @__PURE__ */ new Map();
549
871
  interceptors = [];
550
872
  interceptorsByIntent = /* @__PURE__ */ new Map();
551
- history = [];
552
- trace = [];
873
+ recording;
553
874
  onPublish;
554
875
  onSoftViolation;
555
876
  onHandlerError;
556
- auditTrail;
557
877
  eventContracts;
558
878
  strictEventContracts;
559
879
  requireKnownSource;
560
880
  architectureProfile;
561
881
  enforceObservedLayerFlowMode;
562
- outbox;
563
- instanceId;
564
- traceSinks;
565
882
  rethrowHandlerErrors;
566
883
  policyEngine;
567
884
  getPolicyContext;
568
- maxHistorySize;
569
885
  intentRegistry;
570
886
  dependencyGraph;
571
887
  strictRegistry;
@@ -574,21 +890,25 @@ var EventBusImpl = class {
574
890
  this.onPublish = options.onPublish;
575
891
  this.onSoftViolation = options.onSoftViolation;
576
892
  this.onHandlerError = options.onHandlerError;
577
- this.auditTrail = options.auditTrail;
578
893
  this.eventContracts = options.eventContracts;
579
894
  this.strictEventContracts = options.strictEventContracts ?? false;
580
895
  this.requireKnownSource = options.requireKnownSource ?? false;
581
896
  this.architectureProfile = options.architectureProfile;
582
897
  this.enforceObservedLayerFlowMode = options.enforceObservedLayerFlow ?? "off";
583
- this.outbox = options.outbox;
584
- this.instanceId = options.instanceId;
585
- this.traceSinks = [...options.traceSinks ?? []];
586
898
  this.rethrowHandlerErrors = options.rethrowHandlerErrors ?? false;
587
- this.maxHistorySize = options.maxHistorySize;
588
899
  this.intentRegistry = options.intentRegistry;
589
900
  this.dependencyGraph = options.dependencyGraph;
590
901
  this.strictRegistry = options.strictRegistry ?? options.intentRegistry !== void 0;
591
902
  this.validateIntentNaming = options.validateIntentNaming ?? this.strictRegistry;
903
+ this.recording = {
904
+ history: [],
905
+ trace: [],
906
+ maxHistorySize: options.maxHistorySize,
907
+ traceSinks: [...options.traceSinks ?? []],
908
+ auditTrail: options.auditTrail,
909
+ outbox: options.outbox,
910
+ instanceId: options.instanceId
911
+ };
592
912
  if (options.policyEngine) {
593
913
  this.policyEngine = options.policyEngine;
594
914
  } else if (options.policies && options.policies.length > 0) {
@@ -619,94 +939,77 @@ var EventBusImpl = class {
619
939
  const created = creator(payload);
620
940
  event = {
621
941
  ...created,
622
- metadata: this.enrichMetadata(created.metadata, extraMeta)
942
+ metadata: enrichMetadata(
943
+ created.metadata,
944
+ extraMeta,
945
+ this.recording.instanceId
946
+ )
623
947
  };
624
948
  } else {
625
949
  const rawEvent = eventOrCreator;
626
950
  const extraMeta = metadata ?? payloadOrMeta ?? {};
627
951
  event = {
628
952
  ...rawEvent,
629
- metadata: this.enrichMetadata(rawEvent.metadata, extraMeta)
953
+ metadata: enrichMetadata(
954
+ rawEvent.metadata,
955
+ extraMeta,
956
+ this.recording.instanceId
957
+ )
630
958
  };
631
959
  }
632
960
  if (rawPublish && this.strictRegistry) {
633
- await this.recordRawPublishDiagnostic(event);
634
- }
635
- this.assertIntentAllowed(event.intent);
636
- this.assertSourceAllowed(event);
637
- this.assertContractAllowed(event);
638
- event = await this.applyInterceptors(event);
639
- this.assertContractAllowed(event);
640
- await this.assertObservedLayerFlowAllowed(event);
961
+ await recordRawPublishDiagnostic(this.recording, event);
962
+ }
963
+ assertIntentAllowed(event.intent, {
964
+ strictRegistry: this.strictRegistry,
965
+ validateIntentNaming: this.validateIntentNaming,
966
+ intentRegistry: this.intentRegistry
967
+ });
968
+ assertSourceAllowed(event, {
969
+ requireKnownSource: this.requireKnownSource,
970
+ intentRegistry: this.intentRegistry
971
+ });
972
+ assertContractAllowed(event, {
973
+ eventContracts: this.eventContracts,
974
+ strictEventContracts: this.strictEventContracts
975
+ });
976
+ event = await applyInterceptors(event, {
977
+ interceptorsForIntent: (intent) => this.interceptorsByIntent.get(intent) ?? [],
978
+ eventContracts: this.eventContracts,
979
+ strictEventContracts: this.strictEventContracts,
980
+ appendTrace: (r) => this.appendTrace(r),
981
+ recordAudit: (type, e, details) => this.recordAudit(type, e, details)
982
+ });
983
+ assertContractAllowed(event, {
984
+ eventContracts: this.eventContracts,
985
+ strictEventContracts: this.strictEventContracts
986
+ });
987
+ await assertObservedLayerFlowAllowed(event, {
988
+ mode: this.enforceObservedLayerFlowMode,
989
+ architectureProfile: this.architectureProfile,
990
+ appendTrace: (r) => this.appendTrace(r),
991
+ recordAudit: (type, e, details) => this.recordAudit(type, e, details)
992
+ });
641
993
  this.dependencyGraph?.registerEventFlow(event.metadata.source, event.intent);
642
994
  const matching = [...this.subscriptionsByIntent.get(event.intent) ?? []];
643
995
  if (this.policyEngine) {
644
- const ctx = this.getPolicyContext(event);
645
- let policyResult;
646
- try {
647
- policyResult = this.policyEngine.enforce(ctx);
648
- } catch (err) {
649
- if (err instanceof PolicyViolationError) {
650
- this.appendTrace({
651
- type: "policy.hardViolation",
652
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
653
- intent: event.intent,
654
- correlationId: event.metadata.correlationId,
655
- traceId: event.metadata.traceId,
656
- spanId: event.metadata.spanId,
657
- details: { violations: err.violations }
658
- });
659
- await this.recordAudit("policy.hardViolation", event, {
660
- violations: err.violations
661
- });
662
- }
663
- throw err;
664
- }
665
- if (policyResult.softViolations.length > 0) {
666
- this.appendTrace({
667
- type: "policy.softViolation",
668
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
669
- intent: event.intent,
670
- correlationId: event.metadata.correlationId,
671
- traceId: event.metadata.traceId,
672
- spanId: event.metadata.spanId,
673
- details: { violations: policyResult.softViolations }
674
- });
675
- await this.recordAudit("policy.softViolation", event, {
676
- violations: policyResult.softViolations
677
- });
678
- if (this.onSoftViolation) {
679
- await this.safeHook(
680
- () => this.onSoftViolation(policyResult, event),
681
- "onSoftViolation",
682
- event
683
- );
684
- }
685
- }
996
+ await enforcePublishPolicy(event, {
997
+ policyEngine: this.policyEngine,
998
+ getPolicyContext: this.getPolicyContext,
999
+ appendTrace: (r) => this.appendTrace(r),
1000
+ recordAudit: (type, e, details) => this.recordAudit(type, e, details),
1001
+ onSoftViolation: this.onSoftViolation,
1002
+ safeHook: (fn, name, e) => this.safeHook(fn, name, e)
1003
+ });
686
1004
  }
687
- const record = {
1005
+ await recordSuccessfulPublish(
1006
+ this.recording,
688
1007
  event,
689
- publishedAt: (/* @__PURE__ */ new Date()).toISOString(),
690
- subscribersNotified: matching.length
691
- };
692
- this.appendHistory(record);
693
- await this.outbox?.enqueue(event);
694
- this.appendTrace({
695
- type: "event.published",
696
- timestamp: record.publishedAt,
697
- intent: event.intent,
698
- correlationId: event.metadata.correlationId,
699
- traceId: event.metadata.traceId,
700
- spanId: event.metadata.spanId,
701
- details: { subscribersNotified: matching.length }
702
- });
703
- await this.recordAudit("event.published", event, {
704
- subscribersNotified: matching.length
705
- });
706
- const notifications = matching.map(
707
- (sub) => this.invokeHandler(sub, event)
1008
+ matching.length
1009
+ );
1010
+ await Promise.all(
1011
+ matching.map((sub) => this.invokeHandler(sub, event))
708
1012
  );
709
- await Promise.all(notifications);
710
1013
  if (this.onPublish) {
711
1014
  await this.safeHook(
712
1015
  () => this.onPublish(event),
@@ -717,7 +1020,11 @@ var EventBusImpl = class {
717
1020
  }
718
1021
  createPublisher(source) {
719
1022
  const sourceName = typeof source === "string" ? source : source.name;
720
- this.assertIntentAllowed(sourceName);
1023
+ assertIntentAllowed(sourceName, {
1024
+ strictRegistry: this.strictRegistry,
1025
+ validateIntentNaming: this.validateIntentNaming,
1026
+ intentRegistry: this.intentRegistry
1027
+ });
721
1028
  return {
722
1029
  source: sourceName,
723
1030
  publish: async (intent, payload, metadata = {}) => {
@@ -733,7 +1040,11 @@ var EventBusImpl = class {
733
1040
  }
734
1041
  subscribe(intent, handler) {
735
1042
  const intentName = typeof intent === "string" ? intent : intent.name;
736
- this.assertIntentAllowed(intentName);
1043
+ assertIntentAllowed(intentName, {
1044
+ strictRegistry: this.strictRegistry,
1045
+ validateIntentNaming: this.validateIntentNaming,
1046
+ intentRegistry: this.intentRegistry
1047
+ });
737
1048
  const sub = {
738
1049
  intentName,
739
1050
  handler
@@ -754,7 +1065,11 @@ var EventBusImpl = class {
754
1065
  }
755
1066
  registerInterceptor(intent, interceptor, interceptorId) {
756
1067
  const intentName = typeof intent === "string" ? intent : intent.name;
757
- this.assertIntentAllowed(intentName);
1068
+ assertIntentAllowed(intentName, {
1069
+ strictRegistry: this.strictRegistry,
1070
+ validateIntentNaming: this.validateIntentNaming,
1071
+ intentRegistry: this.intentRegistry
1072
+ });
758
1073
  const registration = {
759
1074
  registrationId: nextInterceptorRegistrationId(),
760
1075
  interceptorId: interceptorId ?? intentName,
@@ -793,174 +1108,22 @@ var EventBusImpl = class {
793
1108
  }));
794
1109
  }
795
1110
  getHistory() {
796
- return [...this.history];
1111
+ return [...this.recording.history];
797
1112
  }
798
1113
  clearHistory() {
799
- this.history.length = 0;
1114
+ this.recording.history.length = 0;
800
1115
  }
801
1116
  getTrace() {
802
- return [...this.trace];
1117
+ return [...this.recording.trace];
803
1118
  }
804
1119
  clearTrace() {
805
- this.trace.length = 0;
806
- }
807
- assertIntentAllowed(intentName) {
808
- if (!this.strictRegistry && !this.validateIntentNaming) {
809
- return;
810
- }
811
- if (this.validateIntentNaming) {
812
- const validation = validateIntentName(intentName);
813
- if (!validation.valid) {
814
- throw new InvalidIntentNameError(intentName, validation.reason);
815
- }
816
- }
817
- if (this.strictRegistry && this.intentRegistry && !this.intentRegistry.has(intentName)) {
818
- throw new UnregisteredIntentError(intentName);
819
- }
820
- }
821
- assertSourceAllowed(event) {
822
- if (!this.requireKnownSource) return;
823
- if (!event.metadata.source || event.metadata.source === "unknown") {
824
- throw new UnknownEventSourceError(event.intent);
825
- }
826
- if (this.intentRegistry && !this.intentRegistry.has(event.metadata.source)) {
827
- throw new UnknownEventSourceError(event.intent, event.metadata.source);
828
- }
829
- }
830
- assertContractAllowed(event) {
831
- if (!this.eventContracts) return;
832
- const result = this.eventContracts.validate(event);
833
- if (!result.ok && (this.strictEventContracts || result.contract)) {
834
- throw new EventContractViolationError(event.intent, result.issues);
835
- }
836
- }
837
- /**
838
- * Enforce the OBSERVED producer→event flow (metadata.source → intent) against the
839
- * architecture profile's layer rules. This is the runtime counterpart to the
840
- * declared-model layer policy: it checks what the system actually did, resolving both
841
- * layers directly from the profile. It runs BEFORE the flow is recorded via
842
- * registerEventFlow, so in hard mode a rejected flow leaves no edge in the graph.
843
- */
844
- async assertObservedLayerFlowAllowed(event) {
845
- if (this.enforceObservedLayerFlowMode === "off" || !this.architectureProfile) {
846
- return;
847
- }
848
- const source = event.metadata.source;
849
- if (!source || source === "unknown") return;
850
- const profile = this.architectureProfile;
851
- const fromLayer = profile.resolveLayer(source);
852
- const toLayer = profile.resolveLayer(event.intent);
853
- if (!fromLayer || !toLayer) return;
854
- const blocked = profile.rules.find(
855
- (rule) => !rule.allowed && rule.from === fromLayer && rule.to === toLayer
856
- );
857
- if (!blocked) return;
858
- const severity = this.enforceObservedLayerFlowMode;
859
- const message = blocked.message ?? `Observed layer violation: "${source}" (${fromLayer}) must not produce "${event.intent}" (${toLayer}).`;
860
- const details = {
861
- source,
862
- intent: event.intent,
863
- fromLayer,
864
- toLayer,
865
- severity,
866
- message,
867
- rule: blocked
868
- };
869
- this.appendTrace({
870
- type: "layer.observedViolation",
871
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
872
- intent: event.intent,
873
- correlationId: event.metadata.correlationId,
874
- traceId: event.metadata.traceId,
875
- spanId: event.metadata.spanId,
876
- details
877
- });
878
- await this.recordAudit("layer.observedViolation", event, details);
879
- if (severity === "hard") {
880
- throw new ObservedLayerFlowViolationError(source, event.intent, fromLayer, toLayer, message);
881
- }
1120
+ this.recording.trace.length = 0;
882
1121
  }
883
- async recordRawPublishDiagnostic(event) {
884
- const details = {
885
- intent: event.intent,
886
- source: event.metadata.source,
887
- suggestion: "Publish through a registered intent creator so strict registry, contracts, and agent tooling share one source of truth."
888
- };
889
- this.appendTrace({
890
- type: "event.rawPublish",
891
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
892
- intent: event.intent,
893
- correlationId: event.metadata.correlationId,
894
- traceId: event.metadata.traceId,
895
- spanId: event.metadata.spanId,
896
- details
897
- });
898
- await this.recordAudit("event.rawPublish", event, details);
1122
+ appendTrace(record) {
1123
+ appendTrace(this.recording, record);
899
1124
  }
900
- async applyInterceptors(event) {
901
- if (event.metadata.allowInterception === false) {
902
- return event;
903
- }
904
- const matching = [...this.interceptorsByIntent.get(event.intent) ?? []];
905
- let current = event;
906
- for (const registration of matching) {
907
- const patches = [];
908
- try {
909
- await Promise.resolve(
910
- registration.interceptor({
911
- event: current,
912
- intercept: (patch) => {
913
- patches.push(patch);
914
- }
915
- })
916
- );
917
- if (patches.length === 0) {
918
- continue;
919
- }
920
- const timestamp = (/* @__PURE__ */ new Date()).toISOString();
921
- let candidate = {
922
- ...current,
923
- metadata: {
924
- ...current.metadata,
925
- interceptions: [
926
- ...current.metadata.interceptions ?? [],
927
- { interceptorId: registration.interceptorId, timestamp }
928
- ]
929
- }
930
- };
931
- for (const patch of patches) {
932
- candidate = {
933
- ...candidate,
934
- payload: applyPayloadPatch(candidate.payload, patch),
935
- metadata: { ...candidate.metadata }
936
- };
937
- }
938
- this.assertContractAllowed(candidate);
939
- current = candidate;
940
- registration.lastInterceptedAt = timestamp;
941
- this.appendTrace({
942
- type: "event.intercepted",
943
- timestamp,
944
- intent: current.intent,
945
- correlationId: current.metadata.correlationId,
946
- traceId: current.metadata.traceId,
947
- spanId: current.metadata.spanId,
948
- details: {
949
- registrationId: registration.registrationId,
950
- interceptorId: registration.interceptorId,
951
- patchesApplied: patches.length
952
- }
953
- });
954
- await this.recordAudit("event.intercepted", current, {
955
- registrationId: registration.registrationId,
956
- interceptorId: registration.interceptorId,
957
- patchesApplied: patches.length
958
- });
959
- } catch (err) {
960
- await this.recordInterceptorError(registration, current, err);
961
- }
962
- }
963
- return current;
1125
+ async recordAudit(type, event, details) {
1126
+ await recordAudit(this.recording, type, event, details);
964
1127
  }
965
1128
  async invokeHandler(sub, event) {
966
1129
  try {
@@ -1013,90 +1176,6 @@ var EventBusImpl = class {
1013
1176
  });
1014
1177
  }
1015
1178
  }
1016
- async recordInterceptorError(interceptor, event, error) {
1017
- const message = error instanceof Error ? error.message : String(error);
1018
- this.appendTrace({
1019
- type: "interceptor.error",
1020
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1021
- intent: event.intent,
1022
- correlationId: event.metadata.correlationId,
1023
- traceId: event.metadata.traceId,
1024
- spanId: event.metadata.spanId,
1025
- details: {
1026
- registrationId: interceptor.registrationId,
1027
- interceptorId: interceptor.interceptorId,
1028
- error: message
1029
- }
1030
- });
1031
- await this.recordAudit("interceptor.error", event, {
1032
- registrationId: interceptor.registrationId,
1033
- interceptorId: interceptor.interceptorId,
1034
- error: message
1035
- });
1036
- }
1037
- appendHistory(record) {
1038
- this.history.push(record);
1039
- if (this.maxHistorySize !== void 0 && this.history.length > this.maxHistorySize) {
1040
- this.history.splice(0, this.history.length - this.maxHistorySize);
1041
- }
1042
- }
1043
- appendTrace(record) {
1044
- this.trace.push(record);
1045
- if (this.maxHistorySize !== void 0 && this.trace.length > this.maxHistorySize) {
1046
- this.trace.splice(0, this.trace.length - this.maxHistorySize);
1047
- }
1048
- for (const sink of this.traceSinks) {
1049
- try {
1050
- sink(record);
1051
- } catch {
1052
- }
1053
- }
1054
- }
1055
- async recordAudit(type, event, details) {
1056
- if (!this.auditTrail) return;
1057
- try {
1058
- await this.auditTrail.record({
1059
- type,
1060
- source: event.metadata.source,
1061
- intent: event.intent,
1062
- correlationId: event.metadata.correlationId,
1063
- causationId: event.metadata.causationId,
1064
- subject: event.intent,
1065
- details
1066
- });
1067
- } catch (err) {
1068
- this.appendTrace({
1069
- type: "hook.error",
1070
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1071
- intent: event.intent,
1072
- correlationId: event.metadata.correlationId,
1073
- traceId: event.metadata.traceId,
1074
- spanId: event.metadata.spanId,
1075
- details: {
1076
- hook: "auditTrail",
1077
- error: err instanceof Error ? err.message : String(err)
1078
- }
1079
- });
1080
- }
1081
- }
1082
- enrichMetadata(base, extra) {
1083
- return {
1084
- ...base,
1085
- ...extra,
1086
- occurredAt: extra.occurredAt || base.occurredAt || (/* @__PURE__ */ new Date()).toISOString(),
1087
- source: extra.source || base.source || "unknown",
1088
- kernelInstanceId: extra.kernelInstanceId ?? base.kernelInstanceId ?? this.instanceId,
1089
- eventVersion: extra.eventVersion ?? base.eventVersion,
1090
- schemaVersion: extra.schemaVersion ?? base.schemaVersion,
1091
- allowInterception: extra.allowInterception ?? base.allowInterception,
1092
- interceptions: extra.interceptions ?? base.interceptions,
1093
- correlationId: extra.correlationId ?? base.correlationId,
1094
- causationId: extra.causationId ?? base.causationId,
1095
- traceId: extra.traceId ?? base.traceId,
1096
- spanId: extra.spanId ?? base.spanId,
1097
- parentSpanId: extra.parentSpanId ?? base.parentSpanId
1098
- };
1099
- }
1100
1179
  };
1101
1180
  function createEventBus(options) {
1102
1181
  return new EventBusImpl(options);