@agentcomms/events-daemon 0.16.0 → 0.18.0

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.
@@ -1,12 +1,12 @@
1
- import { a as number, c as unknown, o as strictObject, s as string, t as McpServer } from "./mcp-DXXb3Vv3-B0sHZfig.mjs";
2
- import { d as isJudgeKind, l as EventDomainError, n as canonicalWebhookTarget } from "./webhook-target-BkA_wHIu.mjs";
1
+ import { a as number, c as unknown, o as strictObject, s as string, t as McpServer } from "./mcp-DIH4cS6P-YuKZfqTg.mjs";
2
+ import { a as EventDomainError, c as JUDGE_KIND_LOCAL_ENDPOINT, f as validateLocalEndpoint, g as parseIpLiteral, h as assertApprovedAddressSet, l as JUDGE_KIND_TYPESAFE, n as canonicalWebhookTarget, o as JUDGE_KINDS } from "./webhook-target-DyDTwWhV.mjs";
3
3
  import { createHash, randomBytes } from "node:crypto";
4
4
  import { chmod, lstat, mkdir, open, readFile, realpath, rm, writeFile } from "node:fs/promises";
5
5
  import { createConnection } from "node:net";
6
6
  import { CommsError, ERROR_REGISTRY, canonicalDisclosureBinding, canonicalJson, isCommsError, neutralise, resolvePaths, sha256Hex } from "@agentcomms/core";
7
7
  import { constants } from "node:fs";
8
8
  import { basename, dirname, join } from "node:path";
9
- import { TEST_CLOUD_EVENT, canonicaliseCondition, catalogueEntry, compileMapping, isJsonValue, validateCloudEventType } from "@agentcomms/events";
9
+ import { TEST_CLOUD_EVENT, canonicaliseAgenticCondition, canonicaliseCondition, catalogueEntry, compileMapping, isJsonValue, parsePointer, validateCloudEventType } from "@agentcomms/events";
10
10
  //#region src/network/error-sink.ts
11
11
  /**
12
12
  * Keeps an owned network resource from turning a later transport error into an uncaught exception.
@@ -532,7 +532,10 @@ async function heldList(options = {}) {
532
532
  }
533
533
  /** Terminal/app-only operation; Task 5 intentionally provides no MCP adapter. */
534
534
  async function decideHeld(decisionId, decision, options = {}) {
535
- return new EventControlClient({ stateDir: options.stateDir }).request("decideHeld", {
535
+ return new EventControlClient({
536
+ stateDir: options.stateDir,
537
+ clientName: "interactive-terminal"
538
+ }).request("decideHeld", {
536
539
  decisionId,
537
540
  decision
538
541
  });
@@ -583,6 +586,25 @@ function assertDoctorReportV1(report) {
583
586
  if (Object.keys(report).some((key) => !DOCTOR_REPORT_V1_KEYS.includes(key))) throw new Error("doctor-v1 report is closed");
584
587
  return report;
585
588
  }
589
+ const DOCTOR_REPORT_V2_KEYS = [
590
+ "schemaVersion",
591
+ "owner",
592
+ "switch",
593
+ "lineages",
594
+ "superseded",
595
+ "points",
596
+ "awaitingReapproval",
597
+ "activationIntents",
598
+ "sources",
599
+ "recovery",
600
+ "judgeBoundary",
601
+ "judge",
602
+ "whatsapp"
603
+ ];
604
+ function assertDoctorReportV2(report) {
605
+ if (Object.keys(report).some((key) => !DOCTOR_REPORT_V2_KEYS.includes(key))) throw new Error("doctor-v2 report is closed");
606
+ return report;
607
+ }
586
608
  async function doctor(options = {}) {
587
609
  return await new EventControlClient({ stateDir: options.stateDir }).request("doctor");
588
610
  }
@@ -810,7 +832,7 @@ async function removeTarget(targetId, options = {}) {
810
832
  //#endregion
811
833
  //#region src/version.ts
812
834
  /** The package version, read from package.json at build time. */
813
- const VERSION = "0.16.0";
835
+ const VERSION = "0.18.0";
814
836
  //#endregion
815
837
  //#region src/mcp/server.ts
816
838
  function reply(data) {
@@ -829,6 +851,10 @@ async function createEventsMcpServer(options = {}) {
829
851
  name: "agent-events",
830
852
  version: VERSION
831
853
  });
854
+ const b3 = (operation, args, throughOwner) => options.b3Registrar === void 0 ? throughOwner() : options.b3Registrar.owner.handle({
855
+ operation,
856
+ args
857
+ });
832
858
  server.registerTool("events_status", {
833
859
  title: "Local event service status",
834
860
  description: "Reports whether the local event service has an owner.",
@@ -872,7 +898,7 @@ async function createEventsMcpServer(options = {}) {
872
898
  destructiveHint: false,
873
899
  idempotentHint: true
874
900
  });
875
- runtimeTool("events_doctor", "Local event service doctor", "Reports content-free lineage validation, pending metadata/materialisation retry health, recovery and protocol health.", doctor, {
901
+ runtimeTool("events_doctor", "Local event service doctor", "Reports content-free lineage, retry, recovery, judge authority, hold-clock and protocol health.", doctor, {
876
902
  destructiveHint: false,
877
903
  idempotentHint: true
878
904
  });
@@ -934,25 +960,28 @@ async function createEventsMcpServer(options = {}) {
934
960
  strictControlTool("events_subscriber_add", "Add subscriber", "Creates one immutable subscriber version.", { document: unknown() }, (args) => addSubscriber(args.document, options), true);
935
961
  strictControlTool("events_subscriber_update", "Update subscriber", "Creates one replacement immutable subscriber version.", { document: unknown() }, (args) => updateSubscriber(args.document, options), true);
936
962
  strictControlTool("events_subscriber_remove", "Remove subscriber", "Revokes every live version of one subscriber and closes its streams.", { subscriberId: string().min(1) }, (args) => removeSubscriber(args.subscriberId, options), true);
937
- strictControlTool("events_judges_list", "List judges", "Returns the typed Phase-E unavailable result.", {}, () => judgesList(options));
938
- strictControlTool("events_judge_add", "Add judge", "Returns the typed Phase-E unavailable result.", { document: unknown() }, (args) => addJudge(args.document, options), true);
939
- strictControlTool("events_judge_update", "Update judge", "Returns the typed Phase-E unavailable result.", { document: unknown() }, (args) => updateJudge(args.document, options), true);
940
- strictControlTool("events_judge_remove", "Remove judge", "Returns the typed Phase-E unavailable result.", { judgeId: string().min(1) }, (args) => removeJudge(args.judgeId, options), true);
941
- strictControlTool("events_judge_test", "Test judge", "Returns the typed Phase-E unavailable result.", {
963
+ strictControlTool("events_judges_list", "List judges", "Lists content-free immutable judge metadata.", {}, () => judgesList(options));
964
+ strictControlTool("events_judge_add", "Add judge", "Creates an immutable, initially inactive judge version.", { document: unknown() }, (args) => b3("addJudge", { document: args.document }, () => addJudge(args.document, options)), true);
965
+ strictControlTool("events_judge_update", "Update judge", "Creates an immutable replacement judge version.", { document: unknown() }, (args) => b3("updateJudge", { document: args.document }, () => updateJudge(args.document, options)), true);
966
+ strictControlTool("events_judge_remove", "Remove judge", "Removes every live immutable version of one judge.", { judgeId: string().min(1) }, (args) => b3("removeJudge", { judgeId: args.judgeId }, () => removeJudge(args.judgeId, options)), true);
967
+ strictControlTool("events_judge_test", "Test judge", "Tests one active exact judge version with the daemon-fixed synthetic event.", {
942
968
  judgeId: string().min(1),
943
969
  version: number().int().positive()
944
970
  }, (args) => judgeTest(args.judgeId, args.version, options));
945
- strictControlTool("events_budget_show", "Show budget", "Returns the typed Phase-E unavailable result.", {}, () => budgetShow(options));
946
- strictControlTool("events_budget_update", "Update budget", "Returns the typed Phase-E unavailable result.", { document: unknown() }, (args) => updateBudget(args.document, options), true);
947
- strictControlTool("events_judge_kinds_list", "List judge kinds", "Returns the typed Phase-E unavailable result.", {}, () => judgeKindsList(options));
948
- strictControlTool("events_judge_kind_enable", "Enable judge kind", "Returns the typed Phase-E or E2 unavailable result.", { kind: string().min(1) }, (args) => enableJudgeKind(args.kind, options), true);
949
- strictControlTool("events_judge_kind_disable", "Disable judge kind", "Returns the typed Phase-E or E2 unavailable result.", { kind: string().min(1) }, (args) => disableJudgeKind(args.kind, options), true);
971
+ strictControlTool("events_budget_show", "Show budget", "Lists immutable judge budgets and the active singleton.", {}, () => budgetShow(options));
972
+ strictControlTool("events_budget_update", "Update budget", "Creates a pending immutable global budget and prepares its approval.", { document: unknown() }, (args) => b3("updateBudget", { document: args.document }, () => updateBudget(args.document, options)), true);
973
+ strictControlTool("events_judge_kinds_list", "List judge kinds", "Lists disabled/enabled judge kinds and the typed Laya E2 seam.", {}, () => judgeKindsList(options));
974
+ strictControlTool("events_judge_kind_enable", "Enable judge kind", "Prepares, but never approves or claims, judge-kind enablement.", { kind: string().min(1) }, (args) => b3("enableJudgeKind", { kind: args.kind }, () => enableJudgeKind(args.kind, options)), true);
975
+ strictControlTool("events_judge_kind_disable", "Disable judge kind", "Immediately disables one available judge kind; Laya remains typed E2-unavailable.", { kind: string().min(1) }, (args) => {
976
+ const kind = args.kind;
977
+ return b3("disableJudgeKind", { kind }, () => disableJudgeKind(kind, options));
978
+ }, true);
950
979
  strictControlTool("events_judge_model_status", "Judge model status", "Returns the typed Phase-E2 unavailable result.", {}, () => judgeModelStatus(options));
951
980
  strictControlTool("events_judge_model_remove", "Remove judge model", "Returns the typed Phase-E2 unavailable result.", {}, () => removeJudgeModel(options), true);
952
981
  strictControlTool("events_deliveries_list", "List deliveries", "Lists content-free delivery metadata.", {}, () => deliveriesList(options));
953
982
  strictControlTool("events_delivery_retry", "Retry delivery", "Retries one exact retryable delivery.", { deliveryId: string().min(1) }, (args) => retryDelivery(args.deliveryId, options), true);
954
983
  strictControlTool("events_delivery_drop", "Drop delivery", "Drops one exact dead-letter delivery and its retained payload.", { deliveryId: string().min(1) }, (args) => dropDelivery(args.deliveryId, options), true);
955
- strictControlTool("events_held_list", "List held decisions", "Returns the typed empty held-decision result; judges, which can hold an event, are not available yet.", {}, () => heldList(options));
984
+ strictControlTool("events_held_list", "List held decisions", "Lists content-free held-decision metadata; only a terminal/app may resolve one.", {}, () => heldList(options));
956
985
  controlTool("events_catalogue_show", "Show local event definition", "Shows one selectable local event definition.", { type: string() }, (args) => catalogueShow(args.type, options));
957
986
  controlTool("events_sources_list", "List event sources", "Lists configured local event sources.", {}, () => sourcesList(options));
958
987
  controlTool("events_source_show", "Show event source", "Shows one configured local event source.", { source: string() }, (args) => sourceShow(args.source, options));
@@ -973,12 +1002,253 @@ async function createEventsMcpServer(options = {}) {
973
1002
  return {
974
1003
  server,
975
1004
  async connectStdio() {
976
- const { StdioServerTransport } = await import("./stdio-CD7QQBAh.mjs");
1005
+ const { StdioServerTransport } = await import("./stdio-Dp1EE6ok.mjs");
977
1006
  await server.connect(new StdioServerTransport());
978
1007
  }
979
1008
  };
980
1009
  }
981
1010
  //#endregion
1011
+ //#region src/domain/judges.ts
1012
+ const TYPESAFE_SYSTEM_ONE_ENDPOINT = "https://api.typesafe.ai/v1/systemone";
1013
+ const JUDGE_BUDGET_ID = "judge-budget";
1014
+ /** Provider record: docs/superpowers/plans/2026-10-10-events-phase-e-provider-record.md, read 2026-10-10. */
1015
+ const APPROVED_TYPESAFE_MODELS = ["jev-1.13.0"];
1016
+ /** Phase E's closed registry. The lifecycle module owns the literal vocabulary; this registry owns its availability. */
1017
+ const JUDGE_KIND_DEFINITIONS = [
1018
+ {
1019
+ kind: JUDGE_KINDS[0],
1020
+ availability: "available"
1021
+ },
1022
+ {
1023
+ kind: JUDGE_KINDS[1],
1024
+ availability: "unavailable",
1025
+ unavailableCode: "E2_REQUIRED"
1026
+ },
1027
+ {
1028
+ kind: JUDGE_KINDS[2],
1029
+ availability: "available"
1030
+ }
1031
+ ];
1032
+ function fail$3(message, code = "VERSION_DOCUMENT_INVALID") {
1033
+ throw new EventDomainError(code, message);
1034
+ }
1035
+ function record$1(value, name) {
1036
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return fail$3(`${name} is an object`);
1037
+ try {
1038
+ return JSON.parse(canonicalJson(value));
1039
+ } catch {
1040
+ return fail$3(`${name} is canonical JSON`);
1041
+ }
1042
+ }
1043
+ function exactKeys$1(value, keys, name) {
1044
+ const found = Object.keys(value).sort();
1045
+ const wanted = [...keys].sort();
1046
+ if (found.length !== wanted.length || found.some((key, index) => key !== wanted[index])) fail$3(`${name} has exactly its canonical fields`);
1047
+ }
1048
+ function text$1(value, name) {
1049
+ if (typeof value !== "string" || value.length === 0) return fail$3(`${name} is a non-empty string`);
1050
+ return value;
1051
+ }
1052
+ function positiveInteger$2(value, name) {
1053
+ if (!Number.isSafeInteger(value) || value < 1) return fail$3(`${name} is a positive safe integer`);
1054
+ return value;
1055
+ }
1056
+ function protocol(value, name) {
1057
+ if (value.protocol === "noul") {
1058
+ exactKeys$1(value, ["protocol"], name);
1059
+ return { protocol: "noul" };
1060
+ }
1061
+ if (value.protocol !== "json-score") return fail$3(`${name} has protocol noul or json-score`);
1062
+ exactKeys$1(value, ["protocol", "scorePointer"], name);
1063
+ const scorePointer = text$1(value.scorePointer, `${name} scorePointer`);
1064
+ const parsed = parsePointer(scorePointer);
1065
+ if (!parsed.ok || parsed.value.includes("*")) return fail$3(`${name} scorePointer is one concrete JSON Pointer`);
1066
+ return {
1067
+ protocol: "json-score",
1068
+ scorePointer
1069
+ };
1070
+ }
1071
+ function identity(value, name) {
1072
+ return {
1073
+ judgeId: text$1(value.judgeId, `${name} id`),
1074
+ version: positiveInteger$2(value.version, `${name} version`)
1075
+ };
1076
+ }
1077
+ function localAddress(value) {
1078
+ if (!Array.isArray(value) || value.length !== 1) return fail$3("a local judge approvedAddressSet has one exact literal");
1079
+ const entry = text$1(value[0], "a local judge approvedAddressSet entry");
1080
+ try {
1081
+ assertApprovedAddressSet([entry]);
1082
+ return [parseIpLiteral(entry).address];
1083
+ } catch {
1084
+ return fail$3("a local judge approvedAddressSet has one valid literal");
1085
+ }
1086
+ }
1087
+ /** The one canonical, immutable judge document form. E2's laya seam is recognised but intentionally unavailable. */
1088
+ function canonicalJudge(value) {
1089
+ const judge = record$1(value, "a judge document");
1090
+ const kind = judge.kind;
1091
+ if (!JUDGE_KINDS.includes(kind)) return fail$3("a judge document has a known judge kind");
1092
+ if (kind === "laya") return fail$3("laya is unavailable until E2", "E2_REQUIRED");
1093
+ if (kind === "typesafe") {
1094
+ exactKeys$1(judge, [
1095
+ "judgeId",
1096
+ "version",
1097
+ "kind",
1098
+ "provider",
1099
+ "model",
1100
+ "endpoint",
1101
+ "promptTemplate",
1102
+ "protocol"
1103
+ ], "a typesafe judge document");
1104
+ if (judge.provider !== "typesafe") return fail$3("a typesafe judge names the TypeSafe Jev adapter");
1105
+ if (!APPROVED_TYPESAFE_MODELS.includes(judge.model)) return fail$3("a typesafe judge names one concrete model listed in the provider record");
1106
+ if (judge.endpoint !== "https://api.typesafe.ai/v1/systemone") return fail$3("a typesafe judge has its fixed System One endpoint");
1107
+ if (protocol({ protocol: judge.protocol }, "a typesafe judge document").protocol !== "noul") return fail$3("a typesafe judge uses the noul protocol");
1108
+ return {
1109
+ ...identity(judge, "a typesafe judge"),
1110
+ kind: JUDGE_KIND_TYPESAFE,
1111
+ provider: JUDGE_KIND_TYPESAFE,
1112
+ model: judge.model,
1113
+ endpoint: TYPESAFE_SYSTEM_ONE_ENDPOINT,
1114
+ promptTemplate: text$1(judge.promptTemplate, "a typesafe judge prompt template"),
1115
+ protocol: "noul"
1116
+ };
1117
+ }
1118
+ const localProtocol = protocol(judge.protocol === "json-score" ? {
1119
+ protocol: judge.protocol,
1120
+ scorePointer: judge.scorePointer
1121
+ } : { protocol: judge.protocol }, "a local judge document");
1122
+ exactKeys$1(judge, localProtocol.protocol === "json-score" ? [
1123
+ "judgeId",
1124
+ "version",
1125
+ "kind",
1126
+ "provider",
1127
+ "model",
1128
+ "endpoint",
1129
+ "approvedAddressSet",
1130
+ "promptTemplate",
1131
+ "protocol",
1132
+ "scorePointer"
1133
+ ] : [
1134
+ "judgeId",
1135
+ "version",
1136
+ "kind",
1137
+ "provider",
1138
+ "model",
1139
+ "endpoint",
1140
+ "approvedAddressSet",
1141
+ "promptTemplate",
1142
+ "protocol"
1143
+ ], "a local judge document");
1144
+ const approvedAddressSet = localAddress(judge.approvedAddressSet);
1145
+ const endpoint = text$1(judge.endpoint, "a local judge endpoint");
1146
+ try {
1147
+ const local = validateLocalEndpoint(endpoint, approvedAddressSet);
1148
+ if (local.url.search !== "") return fail$3("a local judge endpoint has no query");
1149
+ return {
1150
+ ...identity(judge, "a local judge"),
1151
+ kind: JUDGE_KIND_LOCAL_ENDPOINT,
1152
+ provider: text$1(judge.provider, "a local judge provider"),
1153
+ model: text$1(judge.model, "a local judge model"),
1154
+ endpoint: local.url.href,
1155
+ approvedAddressSet,
1156
+ promptTemplate: text$1(judge.promptTemplate, "a local judge prompt template"),
1157
+ ...localProtocol
1158
+ };
1159
+ } catch (error) {
1160
+ if (error instanceof EventDomainError) throw error;
1161
+ return fail$3("a local judge has a literal loopback endpoint and its exact approved address");
1162
+ }
1163
+ }
1164
+ function limits(value, name) {
1165
+ const limit = record$1(value, name);
1166
+ exactKeys$1(limit, [
1167
+ "callsPerRollingHour",
1168
+ "inputTokensPerRolling30Days",
1169
+ "concurrency"
1170
+ ], name);
1171
+ return {
1172
+ callsPerRollingHour: positiveInteger$2(limit.callsPerRollingHour, `${name} callsPerRollingHour`),
1173
+ inputTokensPerRolling30Days: positiveInteger$2(limit.inputTokensPerRolling30Days, `${name} inputTokensPerRolling30Days`),
1174
+ concurrency: positiveInteger$2(limit.concurrency, `${name} concurrency`)
1175
+ };
1176
+ }
1177
+ /** The singleton's complete global and per-provider rolling ceilings, with no implicit defaults. */
1178
+ function canonicalJudgeBudget(value) {
1179
+ const budget = record$1(value, "a judge budget document");
1180
+ exactKeys$1(budget, [
1181
+ "budgetId",
1182
+ "version",
1183
+ "global",
1184
+ "providers"
1185
+ ], "a judge budget document");
1186
+ if (budget.budgetId !== "judge-budget") return fail$3(`a judge budget id is ${JUDGE_BUDGET_ID}`);
1187
+ if (!Array.isArray(budget.providers)) return fail$3("judge budget providers are an array");
1188
+ const providers = budget.providers.map((entry) => {
1189
+ const provider = record$1(entry, "a judge provider budget");
1190
+ exactKeys$1(provider, [
1191
+ "provider",
1192
+ "callsPerRollingHour",
1193
+ "inputTokensPerRolling30Days",
1194
+ "concurrency"
1195
+ ], "a judge provider budget");
1196
+ return {
1197
+ provider: text$1(provider.provider, "a judge provider id"),
1198
+ callsPerRollingHour: positiveInteger$2(provider.callsPerRollingHour, "a judge provider budget callsPerRollingHour"),
1199
+ inputTokensPerRolling30Days: positiveInteger$2(provider.inputTokensPerRolling30Days, "a judge provider budget inputTokensPerRolling30Days"),
1200
+ concurrency: positiveInteger$2(provider.concurrency, "a judge provider budget concurrency")
1201
+ };
1202
+ });
1203
+ if ([...providers].sort((left, right) => left.provider < right.provider ? -1 : left.provider > right.provider ? 1 : 0).some((entry, index) => entry.provider !== providers[index]?.provider) || new Set(providers.map((entry) => entry.provider)).size !== providers.length) return fail$3("judge budget providers are sorted and duplicate-free");
1204
+ return {
1205
+ budgetId: JUDGE_BUDGET_ID,
1206
+ version: positiveInteger$2(budget.version, "a judge budget version"),
1207
+ global: limits(budget.global, "a global judge budget"),
1208
+ providers
1209
+ };
1210
+ }
1211
+ /** The closed kind registry lookup, including E2's intentionally unavailable laya slot. */
1212
+ function judgeKindDefinition(kind) {
1213
+ const definition = JUDGE_KIND_DEFINITIONS.find((candidate) => candidate.kind === kind);
1214
+ if (definition === void 0) return fail$3("a judge kind has a registry definition");
1215
+ return definition;
1216
+ }
1217
+ /** Canonicalises one inert kind-enablement version; no pointer or availability change happens here. */
1218
+ function canonicalJudgeKindEnablement(value) {
1219
+ const enablement = record$1(value, "a judge-kind document");
1220
+ if (!JUDGE_KINDS.includes(enablement.kind)) return fail$3("a judge-kind document has a known judge kind");
1221
+ const kind = enablement.kind;
1222
+ if (judgeKindDefinition(kind).availability === "unavailable") return fail$3("laya is unavailable until E2", "E2_REQUIRED");
1223
+ const id = `judge-kind:${kind}`;
1224
+ if (enablement.id !== id) return fail$3(`a judge-kind document id is ${id}`);
1225
+ if (kind === "typesafe") {
1226
+ exactKeys$1(enablement, [
1227
+ "id",
1228
+ "kind",
1229
+ "version",
1230
+ "endpoint"
1231
+ ], "a typesafe judge-kind document");
1232
+ if (enablement.endpoint !== "https://api.typesafe.ai/v1/systemone") return fail$3("a typesafe judge-kind document has the fixed System One endpoint");
1233
+ return {
1234
+ id: "judge-kind:typesafe",
1235
+ kind: JUDGE_KIND_TYPESAFE,
1236
+ version: positiveInteger$2(enablement.version, "a judge-kind version"),
1237
+ endpoint: TYPESAFE_SYSTEM_ONE_ENDPOINT
1238
+ };
1239
+ }
1240
+ exactKeys$1(enablement, [
1241
+ "id",
1242
+ "kind",
1243
+ "version"
1244
+ ], "a local-endpoint judge-kind document");
1245
+ return {
1246
+ id: "judge-kind:local-endpoint",
1247
+ kind: JUDGE_KIND_LOCAL_ENDPOINT,
1248
+ version: positiveInteger$2(enablement.version, "a judge-kind version")
1249
+ };
1250
+ }
1251
+ //#endregion
982
1252
  //#region src/domain/source-options.ts
983
1253
  function fail$2(message) {
984
1254
  throw new EventDomainError("VERSION_DOCUMENT_INVALID", message);
@@ -1263,19 +1533,6 @@ function canonicalTarget(value) {
1263
1533
  default: return fail("a target document has a known kind");
1264
1534
  }
1265
1535
  }
1266
- /** The one canonical form of a judge version — stored, and embedded in every rule that names it. */
1267
- function canonicalJudge(value) {
1268
- const judge = cloneJsonRecord(value, "a judge document");
1269
- if (!isJudgeKind(judge.kind)) return fail("a judge document has a known judge kind");
1270
- return {
1271
- ...judge,
1272
- judgeId: requiredText(judge.judgeId, "a judge id"),
1273
- version: positiveInteger(judge.version, "a judge version"),
1274
- kind: judge.kind,
1275
- provider: requiredText(judge.provider, "a judge provider"),
1276
- model: requiredText(judge.model, "a judge model")
1277
- };
1278
- }
1279
1536
  /** The one canonical form of a subscriber version — stored, and embedded in every rule that names it. */
1280
1537
  function canonicalSubscriber(value) {
1281
1538
  const subscriber = cloneJsonRecord(value, "a subscriber document");
@@ -1338,6 +1595,15 @@ function canonicalFullRuleDocument(value) {
1338
1595
  if (!eventType.startsWith(`${source.channel}.`)) return fail("a rule event type belongs to its source channel", "SOURCE_CHANNEL_UNSUPPORTED");
1339
1596
  const condition = canonicaliseCondition(definition.value, rule.condition);
1340
1597
  if (!condition.ok) return fail(condition.issues[0]?.message ?? "the rule condition is not valid");
1598
+ let agentic;
1599
+ if (rule.agentic !== void 0) {
1600
+ const canonical = canonicaliseAgenticCondition(definition.value, condition.value, rule.agentic);
1601
+ if (!canonical.ok) return fail(canonical.issues[0]?.message ?? "the rule agentic condition is not valid");
1602
+ agentic = {
1603
+ ...canonical.value,
1604
+ judge: canonicalJudge(canonical.value.judge)
1605
+ };
1606
+ }
1341
1607
  const mapping = canonicalJsonValue(rule.mapping, "rule mapping");
1342
1608
  const compiledMapping = compileMapping(definition.value, mapping);
1343
1609
  if (!compiledMapping.ok) return fail(compiledMapping.issues[0]?.message ?? "the rule mapping is not valid");
@@ -1349,6 +1615,7 @@ function canonicalFullRuleDocument(value) {
1349
1615
  if (subscribers.find((subscriber) => subscriber.subscriberId === target.subscriberId && subscriber.version === target.subscriberVersion) === void 0) return fail("an SSE target embeds its exact subscriber version");
1350
1616
  }
1351
1617
  const judges = Array.isArray(rule.judges) ? rule.judges.map(canonicalJudge) : fail("rule judges are an array");
1618
+ if (judges.length !== 0) return fail("rule judges are represented only by the optional agentic sibling");
1352
1619
  let cloudEventType;
1353
1620
  if (rule.cloudEventType !== void 0) {
1354
1621
  const chosen = validateCloudEventType(rule.cloudEventType);
@@ -1364,6 +1631,7 @@ function canonicalFullRuleDocument(value) {
1364
1631
  version: eventVersion
1365
1632
  },
1366
1633
  condition: condition.value,
1634
+ ...agentic === void 0 ? {} : { agentic },
1367
1635
  mapping,
1368
1636
  ...cloudEventType === void 0 ? {} : { cloudEventType },
1369
1637
  targets,
@@ -1373,23 +1641,6 @@ function canonicalFullRuleDocument(value) {
1373
1641
  retention: canonicalRetention(rule.retention)
1374
1642
  };
1375
1643
  }
1376
- function canonicalBudget(value) {
1377
- const budget = cloneJsonRecord(value, "a judge budget document");
1378
- return {
1379
- ...budget,
1380
- budgetId: requiredText(budget.budgetId, "a judge budget id"),
1381
- version: positiveInteger(budget.version, "a judge budget version")
1382
- };
1383
- }
1384
- function canonicalEnablement(value) {
1385
- const enablement = cloneJsonRecord(value, "a judge-kind document");
1386
- if (!isJudgeKind(enablement.kind)) return fail("a judge-kind document has a known judge kind");
1387
- return {
1388
- ...enablement,
1389
- kind: enablement.kind,
1390
- version: positiveInteger(enablement.version, "a judge-kind version")
1391
- };
1392
- }
1393
1644
  function canonicalEnableAll(value) {
1394
1645
  const document = cloneJsonRecord(value, "an enable-all document");
1395
1646
  if (!Array.isArray(document.ruleVersions)) return fail("enable-all rule versions are an array");
@@ -1426,12 +1677,12 @@ function normaliseActivationDocument(value) {
1426
1677
  case "judge-budget": return {
1427
1678
  documentVersion: 1,
1428
1679
  kind: "judge-budget",
1429
- budget: canonicalBudget(document.budget)
1680
+ budget: canonicalJudgeBudget(document.budget)
1430
1681
  };
1431
1682
  case "judge-kind": return {
1432
1683
  documentVersion: 1,
1433
1684
  kind: "judge-kind",
1434
- enablement: canonicalEnablement(document.enablement)
1685
+ enablement: canonicalJudgeKindEnablement(document.enablement)
1435
1686
  };
1436
1687
  case "enable-all": return canonicalEnableAll(document);
1437
1688
  default: return fail("an activation document has a known kind");
@@ -1466,11 +1717,11 @@ function derivedVersions(document) {
1466
1717
  id: subscriber.subscriberId,
1467
1718
  version: subscriber.version
1468
1719
  })),
1469
- ...document.rule.judges.map((judge) => ({
1720
+ ...document.rule.agentic === void 0 ? [] : [{
1470
1721
  kind: "judge",
1471
- id: judge.judgeId,
1472
- version: judge.version
1473
- }))
1722
+ id: document.rule.agentic.judge.judgeId,
1723
+ version: document.rule.agentic.judge.version
1724
+ }]
1474
1725
  ];
1475
1726
  case "judge-budget": return [{
1476
1727
  kind: "judge-budget",
@@ -2232,4 +2483,4 @@ const B3_CONTROL_CONTRACT = Object.freeze({
2232
2483
  judgeUnavailable: B3_JUDGE_UNAVAILABLE_VARIANTS
2233
2484
  });
2234
2485
  //#endregion
2235
- export { updateRule as $, eventPaths as $t, normaliseSourceOptions as A, EventControlClient as At, subscribersList as B, newInstanceRecord as Bt, normaliseActivationDocument as C, deliveriesList as Ct, normaliseGmailSourceOptions as D, catalogueList as Dt, classifySourceOptionChange as E, retryDelivery as Et, targetsList as F, encodeControlFrame as Ft, sourceShow as G, assertControlSupported as Gt, stop as H, readInstance as Ht, updateTarget as I, isControlHello as It, disableRule as J, verifyControlSocket as Jt, sourcesList as K, assertSocketPathFits as Kt, targetTest as L, isControlRequest as Lt, createEventsMcpServer as M, CONTROL_PROTOCOL_VERSIONS as Mt, addTarget as N, ControlFrameReader as Nt, normaliseResendSourceOptions as O, catalogueShow as Ot, removeTarget as P, controlFailure as Pt, rulesList as Q, ensureOwnerOnlyFile as Qt, addSubscriber as R, negotiateVersion as Rt, disclosureBindingFor as S, decideHeld as St, sseDeliveryTarget as T, heldList as Tt, status as U, removeInstance as Ut, updateSubscriber as V, processIsLive as Vt, loadSqlite as W, writeInstance as Wt, removeRule as X, ensureEventPaths as Xt, enableRule as Y, verifyPrivateSocketDirectory as Yt, ruleShow as Z, ensureEventSocketDirectory as Zt, activationDocumentDigest as _, assertDoctorReportV1 as _t, B3_CONTROL_V1_OPERATION_SPECS as a, budgetShow as at, canonicalSubscriber as b, isActivationFailureCode as bt, B3_CONTROL_V1_SUCCESSOR_REQUIREMENT as c, judgeKindsList as ct, B3_SECRET_TERMINAL_ORIGIN as d, judgesList as dt, installErrorSink as en, ruleTest as et, isB3ControlOperation as f, removeJudge as ft, isOwnerControlWireOperation as g, enableAll as gt, OWNER_CONTROL_WIRES as h, updateJudge as ht, B3_CONTROL_ERROR_CODES as i, addJudge as it, normaliseWhatsAppSourceOptions as j, probeControl as jt, normaliseSlackSourceOptions as k, approvalView as kt, B3_DESKTOP_CONTROL_OPERATIONS as l, judgeModelStatus as lt, renderB3ApprovalPreviewV1 as m, updateBudget as mt, B3_CAPABILITIES as n, pause as nt, B3_CONTROL_V1_RESULT_OPERATIONS as o, disableJudgeKind as ot, isB3SecretOperation as p, removeJudgeModel as pt, createRule as q, controlEndpoint as qt, B3_CONTROL_CONTRACT as r, resume as rt, B3_CONTROL_V1_SCHEMA_VERSION as s, enableJudgeKind as st, B3_APPROVAL_VIEW_VARIANTS as t, ruleTestRetained as tt, B3_JUDGE_UNAVAILABLE_VARIANTS as u, judgeTest as ut, canonicalFullRuleDocument as v, doctor as vt, canonicalSseSubscriber as w, dropDelivery as wt, canonicalTarget as x, disableAll as xt, canonicalJudge as y, ACTIVATION_FAILURE as yt, removeSubscriber as z, mayRecoverStaleInstance as zt };
2486
+ export { sourcesList as $, assertControlSupported as $t, normaliseWhatsAppSourceOptions as A, decideHeld as At, addTarget as B, CONTROL_PROTOCOL_VERSIONS as Bt, canonicalSseSubscriber as C, enableAll as Ct, normaliseResendSourceOptions as D, ACTIVATION_FAILURE as Dt, normaliseGmailSourceOptions as E, doctor as Et, canonicalJudgeBudget as F, catalogueList as Ft, addSubscriber as G, isControlRequest as Gt, targetsList as H, controlFailure as Ht, canonicalJudgeKindEnablement as I, catalogueShow as It, updateSubscriber as J, newInstanceRecord as Jt, removeSubscriber as K, negotiateVersion as Kt, judgeKindDefinition as L, approvalView as Lt, JUDGE_BUDGET_ID as M, dropDelivery as Mt, JUDGE_KIND_DEFINITIONS as N, heldList as Nt, normaliseSlackSourceOptions as O, isActivationFailureCode as Ot, canonicalJudge as P, retryDelivery as Pt, sourceShow as Q, writeInstance as Qt, createEventsMcpServer as R, EventControlClient as Rt, normaliseActivationDocument as S, updateJudge as St, classifySourceOptionChange as T, assertDoctorReportV2 as Tt, updateTarget as U, encodeControlFrame as Ut, removeTarget as V, ControlFrameReader as Vt, targetTest as W, isControlHello as Wt, status as X, readInstance as Xt, stop as Y, processIsLive as Yt, loadSqlite as Z, removeInstance as Zt, activationDocumentDigest as _, judgeTest as _t, B3_CONTROL_V1_OPERATION_SPECS as a, ensureEventSocketDirectory as an, rulesList as at, canonicalTarget as b, removeJudgeModel as bt, B3_CONTROL_V1_SUCCESSOR_REQUIREMENT as c, installErrorSink as cn, ruleTestRetained as ct, B3_SECRET_TERMINAL_ORIGIN as d, addJudge as dt, assertSocketPathFits as en, createRule as et, isB3ControlOperation as f, budgetShow as ft, isOwnerControlWireOperation as g, judgeModelStatus as gt, OWNER_CONTROL_WIRES as h, judgeKindsList as ht, B3_CONTROL_ERROR_CODES as i, ensureEventPaths as in, ruleShow as it, APPROVED_TYPESAFE_MODELS as j, deliveriesList as jt, normaliseSourceOptions as k, disableAll as kt, B3_DESKTOP_CONTROL_OPERATIONS as l, pause as lt, renderB3ApprovalPreviewV1 as m, enableJudgeKind as mt, B3_CAPABILITIES as n, verifyControlSocket as nn, enableRule as nt, B3_CONTROL_V1_RESULT_OPERATIONS as o, ensureOwnerOnlyFile as on, updateRule as ot, isB3SecretOperation as p, disableJudgeKind as pt, subscribersList as q, mayRecoverStaleInstance as qt, B3_CONTROL_CONTRACT as r, verifyPrivateSocketDirectory as rn, removeRule as rt, B3_CONTROL_V1_SCHEMA_VERSION as s, eventPaths as sn, ruleTest as st, B3_APPROVAL_VIEW_VARIANTS as t, controlEndpoint as tn, disableRule as tt, B3_JUDGE_UNAVAILABLE_VARIANTS as u, resume as ut, canonicalFullRuleDocument as v, judgesList as vt, sseDeliveryTarget as w, assertDoctorReportV1 as wt, disclosureBindingFor as x, updateBudget as xt, canonicalSubscriber as y, removeJudge as yt, VERSION as z, probeControl as zt };