@remnic/core 9.7.10 → 9.7.11
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.
- package/dist/access-boundary.d.ts +1 -1
- package/dist/access-boundary.js +1 -1
- package/dist/access-cli.js +7 -7
- package/dist/access-http.d.ts +2 -1
- package/dist/access-http.js +5 -5
- package/dist/access-mcp.js +4 -4
- package/dist/access-operations-batch.js +2 -2
- package/dist/access-operations.d.ts +4 -4
- package/dist/access-operations.js +3 -3
- package/dist/access-schema.d.ts +64 -64
- package/dist/access-surface-catalog.js +2 -0
- package/dist/access-surface-catalog.js.map +1 -1
- package/dist/{chunk-N3LWQJ6Y.js → chunk-5U65RIVI.js} +294 -2
- package/dist/chunk-5U65RIVI.js.map +1 -0
- package/dist/{chunk-UZRIKUFS.js → chunk-6LM6PPDX.js} +3 -1
- package/dist/chunk-6LM6PPDX.js.map +1 -0
- package/dist/chunk-7XRUYC6G.js +1794 -0
- package/dist/chunk-7XRUYC6G.js.map +1 -0
- package/dist/{chunk-VDLMAJXS.js → chunk-GHVJASQ4.js} +2 -2
- package/dist/{chunk-7EX4YOKH.js → chunk-JYRFO4EH.js} +2 -2
- package/dist/{chunk-QVALQE4P.js → chunk-QHT4W3RU.js} +126 -8
- package/dist/chunk-QHT4W3RU.js.map +1 -0
- package/dist/{chunk-7CKS4AXY.js → chunk-W6R43NLA.js} +3 -3
- package/dist/cli.js +6 -6
- package/dist/index.d.ts +3990 -4
- package/dist/index.js +54 -7
- package/dist/orchestrator.js +7 -7
- package/dist/schemas.d.ts +52 -52
- package/dist/shared-context/manager.d.ts +8 -8
- package/dist/transfer/types.d.ts +66 -66
- package/package.json +2 -2
- package/src/access-boundary.ts +2 -0
- package/src/access-http.ts +147 -6
- package/src/access-mcp-cancellation.test.ts +2 -2
- package/src/access-operations.ts +2 -0
- package/src/access-surface-catalog.ts +2 -0
- package/src/index.ts +53 -0
- package/src/relay/mission-access.test.ts +379 -0
- package/src/relay/mission-access.ts +125 -0
- package/src/relay/mission-fixture.ts +301 -0
- package/src/relay/mission.test.ts +964 -0
- package/src/relay/mission.ts +1725 -0
- package/dist/chunk-FNJX2O6G.js +0 -467
- package/dist/chunk-FNJX2O6G.js.map +0 -1
- package/dist/chunk-N3LWQJ6Y.js.map +0 -1
- package/dist/chunk-QVALQE4P.js.map +0 -1
- package/dist/chunk-UZRIKUFS.js.map +0 -1
- /package/dist/{chunk-VDLMAJXS.js.map → chunk-GHVJASQ4.js.map} +0 -0
- /package/dist/{chunk-7EX4YOKH.js.map → chunk-JYRFO4EH.js.map} +0 -0
- /package/dist/{chunk-7CKS4AXY.js.map → chunk-W6R43NLA.js.map} +0 -0
|
@@ -0,0 +1,1794 @@
|
|
|
1
|
+
import {
|
|
2
|
+
memoryStoreRequestSchema
|
|
3
|
+
} from "./chunk-2MR3MFQB.js";
|
|
4
|
+
import {
|
|
5
|
+
defineOperation
|
|
6
|
+
} from "./chunk-6LM6PPDX.js";
|
|
7
|
+
import {
|
|
8
|
+
CorrectionContractError,
|
|
9
|
+
DECISION_SUBCOMMANDS,
|
|
10
|
+
DELTA_SUBCOMMANDS,
|
|
11
|
+
EngramAccessInputError,
|
|
12
|
+
isCodegraphToolName
|
|
13
|
+
} from "./chunk-3OQ4IZJN.js";
|
|
14
|
+
import {
|
|
15
|
+
serializeMutations,
|
|
16
|
+
withHeldFileLock
|
|
17
|
+
} from "./chunk-LTJAMRGI.js";
|
|
18
|
+
|
|
19
|
+
// src/access-operations.ts
|
|
20
|
+
import { z as z3 } from "zod";
|
|
21
|
+
|
|
22
|
+
// src/relay/mission-access.ts
|
|
23
|
+
import { z as z2 } from "zod";
|
|
24
|
+
|
|
25
|
+
// src/relay/mission.ts
|
|
26
|
+
import { createHash, randomUUID } from "crypto";
|
|
27
|
+
import { promises as fs, constants as fsConstants } from "fs";
|
|
28
|
+
import path from "path";
|
|
29
|
+
import { z } from "zod";
|
|
30
|
+
var RELAY_MISSION_SCHEMA_VERSION = "1";
|
|
31
|
+
var RELAY_MISSION_MAX_FILE_BYTES = 4 * 1024 * 1024;
|
|
32
|
+
var RELAY_MISSION_MAX_LINE_BYTES = 64 * 1024;
|
|
33
|
+
var RELAY_MISSION_MAX_EVENTS = 2e3;
|
|
34
|
+
var RELAY_MISSION_DEFAULT_EVENT_LIMIT = 200;
|
|
35
|
+
var RELAY_MISSION_MAX_EVENT_LIMIT = 500;
|
|
36
|
+
var RelayMissionIdSchema = z.string().min(1).max(64).regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/, {
|
|
37
|
+
message: "must contain only lowercase letters, numbers, and single hyphens"
|
|
38
|
+
});
|
|
39
|
+
var identifierSchema = z.string().min(1).max(128).regex(/^[A-Za-z0-9](?:[A-Za-z0-9._:@-]{0,126}[A-Za-z0-9])?$/, {
|
|
40
|
+
message: "must be a bounded identifier"
|
|
41
|
+
});
|
|
42
|
+
var namespaceSchema = z.string().trim().min(1).max(128);
|
|
43
|
+
var authenticatedPrincipalSchema = z.string().trim().min(1).max(256);
|
|
44
|
+
var shortTextSchema = z.string().trim().min(1).max(240);
|
|
45
|
+
var statementSchema = z.string().trim().min(1).max(4e3);
|
|
46
|
+
var uniqueIdentifierListSchema = (minimum, maximum) => z.array(identifierSchema).min(minimum).max(maximum).refine((values) => new Set(values).size === values.length, "must not contain duplicate identifiers");
|
|
47
|
+
var RelayIsoDateTimeSchema = z.string().datetime({ offset: true }).refine((value) => Number.isFinite(Date.parse(value)), "must be a representable timestamp");
|
|
48
|
+
var RelayEvidenceRefSchema = z.object({
|
|
49
|
+
kind: z.enum(["memory", "recall_audit", "source", "test", "commit", "correction", "agent_output", "approval"]),
|
|
50
|
+
id: identifierSchema,
|
|
51
|
+
label: shortTextSchema,
|
|
52
|
+
locator: z.string().trim().min(1).max(2048).optional(),
|
|
53
|
+
capture: z.enum(["at_action", "historical_lookup", "fixture"])
|
|
54
|
+
}).strict();
|
|
55
|
+
var evidenceListSchema = z.array(RelayEvidenceRefSchema).max(16);
|
|
56
|
+
var agentIdentityFields = {
|
|
57
|
+
agentId: identifierSchema,
|
|
58
|
+
sessionId: identifierSchema
|
|
59
|
+
};
|
|
60
|
+
var RelayMissionPayloadUnionSchema = z.discriminatedUnion("kind", [
|
|
61
|
+
z.object({
|
|
62
|
+
kind: z.literal("mission_started"),
|
|
63
|
+
title: shortTextSchema,
|
|
64
|
+
objective: statementSchema,
|
|
65
|
+
runMode: z.enum(["live", "replay", "fixture"]),
|
|
66
|
+
evidence: evidenceListSchema.default([])
|
|
67
|
+
}).strict(),
|
|
68
|
+
z.object({
|
|
69
|
+
kind: z.literal("agent_status"),
|
|
70
|
+
...agentIdentityFields,
|
|
71
|
+
label: shortTextSchema,
|
|
72
|
+
role: shortTextSchema,
|
|
73
|
+
status: z.enum(["idle", "working", "blocked", "complete", "failed"]),
|
|
74
|
+
detail: statementSchema.optional(),
|
|
75
|
+
evidence: evidenceListSchema.default([])
|
|
76
|
+
}).strict(),
|
|
77
|
+
z.object({
|
|
78
|
+
kind: z.literal("agent_output"),
|
|
79
|
+
...agentIdentityFields,
|
|
80
|
+
outputId: identifierSchema,
|
|
81
|
+
summary: statementSchema,
|
|
82
|
+
evidence: evidenceListSchema.default([])
|
|
83
|
+
}).strict(),
|
|
84
|
+
z.object({
|
|
85
|
+
kind: z.literal("belief_observed"),
|
|
86
|
+
...agentIdentityFields,
|
|
87
|
+
beliefId: identifierSchema,
|
|
88
|
+
decisionId: identifierSchema,
|
|
89
|
+
statement: statementSchema,
|
|
90
|
+
confidence: z.number().finite().min(0).max(1).optional(),
|
|
91
|
+
evidence: evidenceListSchema.default([])
|
|
92
|
+
}).strict(),
|
|
93
|
+
z.object({
|
|
94
|
+
kind: z.literal("conflict_detected"),
|
|
95
|
+
conflictId: identifierSchema,
|
|
96
|
+
decisionIds: uniqueIdentifierListSchema(2, 8),
|
|
97
|
+
agentIds: uniqueIdentifierListSchema(2, 16),
|
|
98
|
+
summary: statementSchema,
|
|
99
|
+
evidence: evidenceListSchema.default([])
|
|
100
|
+
}).strict(),
|
|
101
|
+
z.object({
|
|
102
|
+
kind: z.literal("test_result"),
|
|
103
|
+
testId: identifierSchema,
|
|
104
|
+
decisionId: identifierSchema,
|
|
105
|
+
correctionId: identifierSchema.optional(),
|
|
106
|
+
command: z.string().trim().min(1).max(1e3),
|
|
107
|
+
status: z.enum(["passed", "failed", "error"]),
|
|
108
|
+
summary: statementSchema,
|
|
109
|
+
durationMs: z.number().int().nonnegative().max(36e5).optional(),
|
|
110
|
+
evidence: evidenceListSchema.default([])
|
|
111
|
+
}).strict(),
|
|
112
|
+
z.object({
|
|
113
|
+
kind: z.literal("correction_proposed"),
|
|
114
|
+
correctionId: identifierSchema,
|
|
115
|
+
conflictId: identifierSchema,
|
|
116
|
+
proposedDecisionId: identifierSchema,
|
|
117
|
+
supersedesDecisionIds: uniqueIdentifierListSchema(1, 8),
|
|
118
|
+
statement: statementSchema,
|
|
119
|
+
rationale: statementSchema,
|
|
120
|
+
proposedBy: identifierSchema,
|
|
121
|
+
evidence: evidenceListSchema.default([])
|
|
122
|
+
}).strict(),
|
|
123
|
+
z.object({
|
|
124
|
+
kind: z.literal("correction_approved"),
|
|
125
|
+
correctionId: identifierSchema,
|
|
126
|
+
approvedBy: z.object({
|
|
127
|
+
kind: z.enum(["human", "agent"]),
|
|
128
|
+
id: identifierSchema,
|
|
129
|
+
label: shortTextSchema
|
|
130
|
+
}).strict(),
|
|
131
|
+
note: statementSchema.optional(),
|
|
132
|
+
evidence: evidenceListSchema.default([])
|
|
133
|
+
}).strict(),
|
|
134
|
+
z.object({
|
|
135
|
+
kind: z.literal("decision_superseded"),
|
|
136
|
+
decisionId: identifierSchema,
|
|
137
|
+
replacementDecisionId: identifierSchema,
|
|
138
|
+
correctionId: identifierSchema,
|
|
139
|
+
evidence: evidenceListSchema.default([])
|
|
140
|
+
}).strict(),
|
|
141
|
+
z.object({
|
|
142
|
+
kind: z.literal("recall_observed"),
|
|
143
|
+
...agentIdentityFields,
|
|
144
|
+
recallReceiptId: identifierSchema,
|
|
145
|
+
decisionId: identifierSchema,
|
|
146
|
+
query: statementSchema,
|
|
147
|
+
capturedAtAction: z.boolean(),
|
|
148
|
+
evidence: evidenceListSchema.default([])
|
|
149
|
+
}).strict(),
|
|
150
|
+
z.object({
|
|
151
|
+
kind: z.literal("propagation_verified"),
|
|
152
|
+
...agentIdentityFields,
|
|
153
|
+
correctionId: identifierSchema,
|
|
154
|
+
decisionId: identifierSchema,
|
|
155
|
+
recallReceiptId: identifierSchema,
|
|
156
|
+
staleDecisionAbsent: z.boolean(),
|
|
157
|
+
evidence: evidenceListSchema.default([])
|
|
158
|
+
}).strict(),
|
|
159
|
+
z.object({
|
|
160
|
+
kind: z.literal("mission_completed"),
|
|
161
|
+
outcome: z.enum(["recovered", "failed", "inconclusive"]),
|
|
162
|
+
summary: statementSchema,
|
|
163
|
+
evidence: evidenceListSchema.default([])
|
|
164
|
+
}).strict()
|
|
165
|
+
]);
|
|
166
|
+
var RelayMissionPayloadSchema = RelayMissionPayloadUnionSchema.superRefine((value, ctx) => {
|
|
167
|
+
if (value.kind === "decision_superseded" && value.decisionId === value.replacementDecisionId) {
|
|
168
|
+
ctx.addIssue({
|
|
169
|
+
code: z.ZodIssueCode.custom,
|
|
170
|
+
message: "a decision cannot supersede itself",
|
|
171
|
+
path: ["replacementDecisionId"]
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
if (value.kind === "correction_approved" && !value.evidence.some((item) => item.kind === "approval")) {
|
|
175
|
+
ctx.addIssue({
|
|
176
|
+
code: z.ZodIssueCode.custom,
|
|
177
|
+
message: "correction approval requires approval evidence",
|
|
178
|
+
path: ["evidence"]
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
if (value.kind === "decision_superseded" && !value.evidence.some((item) => item.kind === "correction" && item.id === value.correctionId)) {
|
|
182
|
+
ctx.addIssue({
|
|
183
|
+
code: z.ZodIssueCode.custom,
|
|
184
|
+
message: "decision supersession requires matching correction evidence",
|
|
185
|
+
path: ["evidence"]
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
if (value.kind !== "recall_observed" && value.kind !== "propagation_verified") return;
|
|
189
|
+
const matchingRecallEvidence = value.evidence.find(
|
|
190
|
+
(item) => item.kind === "recall_audit" && item.id === value.recallReceiptId
|
|
191
|
+
);
|
|
192
|
+
if (!matchingRecallEvidence) {
|
|
193
|
+
ctx.addIssue({
|
|
194
|
+
code: z.ZodIssueCode.custom,
|
|
195
|
+
message: "recall proof requires a matching recall-audit reference",
|
|
196
|
+
path: ["evidence"]
|
|
197
|
+
});
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
if (value.kind === "recall_observed") {
|
|
201
|
+
const expectedCapture = value.capturedAtAction ? "at_action" : "historical_lookup";
|
|
202
|
+
if (matchingRecallEvidence.capture !== expectedCapture && matchingRecallEvidence.capture !== "fixture") {
|
|
203
|
+
ctx.addIssue({
|
|
204
|
+
code: z.ZodIssueCode.custom,
|
|
205
|
+
message: `recall evidence must be labeled ${expectedCapture}`,
|
|
206
|
+
path: ["evidence", value.evidence.indexOf(matchingRecallEvidence), "capture"]
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
var RelayMissionEventInputSchema = z.object({
|
|
212
|
+
occurredAt: RelayIsoDateTimeSchema.optional(),
|
|
213
|
+
idempotencyKey: identifierSchema.optional(),
|
|
214
|
+
payload: RelayMissionPayloadSchema
|
|
215
|
+
}).strict();
|
|
216
|
+
var RelayMissionEventSchema = z.object({
|
|
217
|
+
schemaVersion: z.literal(RELAY_MISSION_SCHEMA_VERSION),
|
|
218
|
+
eventId: identifierSchema,
|
|
219
|
+
missionId: RelayMissionIdSchema,
|
|
220
|
+
namespace: namespaceSchema,
|
|
221
|
+
authenticatedPrincipal: authenticatedPrincipalSchema.optional(),
|
|
222
|
+
recordedAt: RelayIsoDateTimeSchema,
|
|
223
|
+
occurredAt: RelayIsoDateTimeSchema,
|
|
224
|
+
idempotencyKey: identifierSchema.optional(),
|
|
225
|
+
payload: RelayMissionPayloadSchema
|
|
226
|
+
}).strict();
|
|
227
|
+
var RelayMissionReadOptionsSchema = z.object({
|
|
228
|
+
since: RelayIsoDateTimeSchema.optional(),
|
|
229
|
+
until: RelayIsoDateTimeSchema.optional(),
|
|
230
|
+
limit: z.number().int().min(1).max(RELAY_MISSION_MAX_EVENT_LIMIT).default(RELAY_MISSION_DEFAULT_EVENT_LIMIT)
|
|
231
|
+
}).strict().refine(
|
|
232
|
+
(value) => value.since === void 0 || value.until === void 0 || Date.parse(value.since) < Date.parse(value.until),
|
|
233
|
+
{ message: "since must be earlier than until", path: ["until"] }
|
|
234
|
+
);
|
|
235
|
+
var RelayMissionStoreError = class extends Error {
|
|
236
|
+
constructor(code, message, options) {
|
|
237
|
+
super(message, options);
|
|
238
|
+
this.code = code;
|
|
239
|
+
this.name = "RelayMissionStoreError";
|
|
240
|
+
}
|
|
241
|
+
code;
|
|
242
|
+
};
|
|
243
|
+
var RelayMissionStore = class {
|
|
244
|
+
rootDir;
|
|
245
|
+
namespace;
|
|
246
|
+
now;
|
|
247
|
+
createEventId;
|
|
248
|
+
maxFileBytes;
|
|
249
|
+
maxEvents;
|
|
250
|
+
lockMaxWaitMs;
|
|
251
|
+
constructor(options) {
|
|
252
|
+
if (typeof options.rootDir !== "string" || options.rootDir.trim().length === 0) {
|
|
253
|
+
throw new TypeError("RelayMissionStore rootDir must be a non-empty string");
|
|
254
|
+
}
|
|
255
|
+
this.rootDir = path.resolve(options.rootDir);
|
|
256
|
+
this.namespace = namespaceSchema.parse(options.namespace);
|
|
257
|
+
this.now = options.now ?? (() => /* @__PURE__ */ new Date());
|
|
258
|
+
this.createEventId = options.createEventId ?? (() => `relay-${randomUUID()}`);
|
|
259
|
+
this.maxFileBytes = positiveIntegerOption(options.maxFileBytes, "maxFileBytes", RELAY_MISSION_MAX_FILE_BYTES);
|
|
260
|
+
this.maxEvents = positiveIntegerOption(options.maxEvents, "maxEvents", RELAY_MISSION_MAX_EVENTS);
|
|
261
|
+
this.lockMaxWaitMs = positiveIntegerOption(options.lockMaxWaitMs, "lockMaxWaitMs", 5e3);
|
|
262
|
+
}
|
|
263
|
+
async append(missionIdValue, inputValue, hooks = {}) {
|
|
264
|
+
const missionId = RelayMissionIdSchema.parse(missionIdValue);
|
|
265
|
+
const input = RelayMissionEventInputSchema.parse(inputValue);
|
|
266
|
+
const authenticatedPrincipal = hooks.authenticatedPrincipal === void 0 ? void 0 : authenticatedPrincipalSchema.parse(hooks.authenticatedPrincipal);
|
|
267
|
+
const missionDir = await this.openMissionDirectory(true);
|
|
268
|
+
const filePath = path.join(missionDir.accessPath, `${missionId}.jsonl`);
|
|
269
|
+
const logicalFilePath = path.join(missionDir.logicalPath, `${missionId}.jsonl`);
|
|
270
|
+
const lockPath = `${filePath}.lock`;
|
|
271
|
+
try {
|
|
272
|
+
return await serializeMutations(
|
|
273
|
+
`relay-mission:${logicalFilePath}`,
|
|
274
|
+
() => withHeldFileLock(
|
|
275
|
+
lockPath,
|
|
276
|
+
{ staleMs: 3e4, maxWaitMs: this.lockMaxWaitMs, heartbeatMs: 1e4 },
|
|
277
|
+
async (acquired) => {
|
|
278
|
+
if (!acquired) {
|
|
279
|
+
throw new RelayMissionStoreError("lock_unavailable", "could not acquire Relay mission lock");
|
|
280
|
+
}
|
|
281
|
+
const existing = await this.readFile(filePath, missionId);
|
|
282
|
+
if (input.idempotencyKey) {
|
|
283
|
+
const replay = existing.events.find((event2) => event2.idempotencyKey === input.idempotencyKey);
|
|
284
|
+
if (replay) {
|
|
285
|
+
if (!sameIdempotentInput(replay, input, authenticatedPrincipal)) {
|
|
286
|
+
throw new RelayMissionStoreError(
|
|
287
|
+
"idempotency_conflict",
|
|
288
|
+
`idempotency key ${input.idempotencyKey} was already used for different input`
|
|
289
|
+
);
|
|
290
|
+
}
|
|
291
|
+
return { appended: false, replayed: true, event: replay };
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
if (existing.events.length >= this.maxEvents) {
|
|
295
|
+
throw new RelayMissionStoreError(
|
|
296
|
+
"limit_exceeded",
|
|
297
|
+
`mission ${missionId} reached the ${this.maxEvents}-event limit`
|
|
298
|
+
);
|
|
299
|
+
}
|
|
300
|
+
await hooks.beforeAppend?.();
|
|
301
|
+
const recordedAt = validNow(this.now);
|
|
302
|
+
const event = RelayMissionEventSchema.parse({
|
|
303
|
+
schemaVersion: RELAY_MISSION_SCHEMA_VERSION,
|
|
304
|
+
eventId: this.createEventId(),
|
|
305
|
+
missionId,
|
|
306
|
+
namespace: this.namespace,
|
|
307
|
+
...authenticatedPrincipal === void 0 ? {} : { authenticatedPrincipal },
|
|
308
|
+
recordedAt,
|
|
309
|
+
occurredAt: input.occurredAt ?? recordedAt,
|
|
310
|
+
...input.idempotencyKey ? { idempotencyKey: input.idempotencyKey } : {},
|
|
311
|
+
payload: input.payload
|
|
312
|
+
});
|
|
313
|
+
const line = `${JSON.stringify(event)}
|
|
314
|
+
`;
|
|
315
|
+
const lineBytes = Buffer.byteLength(line, "utf8");
|
|
316
|
+
if (lineBytes > RELAY_MISSION_MAX_LINE_BYTES) {
|
|
317
|
+
throw new RelayMissionStoreError(
|
|
318
|
+
"limit_exceeded",
|
|
319
|
+
`Relay mission event exceeds ${RELAY_MISSION_MAX_LINE_BYTES} bytes`
|
|
320
|
+
);
|
|
321
|
+
}
|
|
322
|
+
if (existing.rawBytes + lineBytes > this.maxFileBytes) {
|
|
323
|
+
throw new RelayMissionStoreError(
|
|
324
|
+
"limit_exceeded",
|
|
325
|
+
`mission ${missionId} would exceed the ${this.maxFileBytes}-byte limit`
|
|
326
|
+
);
|
|
327
|
+
}
|
|
328
|
+
await this.appendFile(filePath, line);
|
|
329
|
+
return { appended: true, replayed: false, event };
|
|
330
|
+
}
|
|
331
|
+
)
|
|
332
|
+
);
|
|
333
|
+
} finally {
|
|
334
|
+
await missionDir.handle.close().catch(() => void 0);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
async read(missionIdValue, readOptions = {}) {
|
|
338
|
+
const missionId = RelayMissionIdSchema.parse(missionIdValue);
|
|
339
|
+
const options = RelayMissionReadOptionsSchema.parse(readOptions);
|
|
340
|
+
const missionDir = await this.openMissionDirectory(false);
|
|
341
|
+
if (missionDir === null) {
|
|
342
|
+
return reduceRelayMission({
|
|
343
|
+
missionId,
|
|
344
|
+
namespace: this.namespace,
|
|
345
|
+
events: [],
|
|
346
|
+
fileExists: false,
|
|
347
|
+
options
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
const filePath = path.join(missionDir.accessPath, `${missionId}.jsonl`);
|
|
351
|
+
const logicalFilePath = path.join(missionDir.logicalPath, `${missionId}.jsonl`);
|
|
352
|
+
try {
|
|
353
|
+
return await serializeMutations(`relay-mission:${logicalFilePath}`, async () => {
|
|
354
|
+
const read = await this.readFile(filePath, missionId);
|
|
355
|
+
return reduceRelayMission({
|
|
356
|
+
missionId,
|
|
357
|
+
namespace: this.namespace,
|
|
358
|
+
events: read.events,
|
|
359
|
+
corruptLines: read.corruptLines,
|
|
360
|
+
fileExists: read.exists,
|
|
361
|
+
options
|
|
362
|
+
});
|
|
363
|
+
});
|
|
364
|
+
} finally {
|
|
365
|
+
await missionDir.handle.close().catch(() => void 0);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
async openMissionDirectory(create) {
|
|
369
|
+
let currentHandle;
|
|
370
|
+
try {
|
|
371
|
+
currentHandle = await openVerifiedDirectory(this.rootDir, "Relay root must be a real directory");
|
|
372
|
+
let logicalPath = this.rootDir;
|
|
373
|
+
for (const segment of ["state", "relay", "missions"]) {
|
|
374
|
+
let childHandle;
|
|
375
|
+
try {
|
|
376
|
+
childHandle = create ? await openOrCreatePinnedChildDirectory(currentHandle, segment) : await openVerifiedDirectory(
|
|
377
|
+
path.join(pinnedDirectoryPath(currentHandle), segment),
|
|
378
|
+
"Relay directory symlinks are rejected"
|
|
379
|
+
);
|
|
380
|
+
} catch (error) {
|
|
381
|
+
if (!create && error.code === "ENOENT") {
|
|
382
|
+
await currentHandle.close();
|
|
383
|
+
return null;
|
|
384
|
+
}
|
|
385
|
+
throw error;
|
|
386
|
+
}
|
|
387
|
+
await currentHandle.close();
|
|
388
|
+
currentHandle = childHandle;
|
|
389
|
+
logicalPath = path.join(logicalPath, segment);
|
|
390
|
+
}
|
|
391
|
+
return {
|
|
392
|
+
logicalPath,
|
|
393
|
+
accessPath: pinnedDirectoryPath(currentHandle),
|
|
394
|
+
handle: currentHandle
|
|
395
|
+
};
|
|
396
|
+
} catch (error) {
|
|
397
|
+
await currentHandle?.close().catch(() => void 0);
|
|
398
|
+
if (error instanceof RelayMissionStoreError) throw error;
|
|
399
|
+
throw new RelayMissionStoreError("unsafe_path", "Relay mission directory is unavailable or unsafe", {
|
|
400
|
+
cause: error
|
|
401
|
+
});
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
async readFile(filePath, missionId) {
|
|
405
|
+
let handle;
|
|
406
|
+
try {
|
|
407
|
+
handle = await fs.open(filePath, fsConstants.O_RDONLY | fsConstants.O_NOFOLLOW);
|
|
408
|
+
const info = await handle.stat();
|
|
409
|
+
if (!info.isFile()) {
|
|
410
|
+
throw new RelayMissionStoreError("unsafe_path", "Relay mission path is not a file");
|
|
411
|
+
}
|
|
412
|
+
if (info.nlink !== 1) {
|
|
413
|
+
throw new RelayMissionStoreError("unsafe_path", "Relay mission hard links are rejected");
|
|
414
|
+
}
|
|
415
|
+
if (info.size > this.maxFileBytes) {
|
|
416
|
+
throw new RelayMissionStoreError(
|
|
417
|
+
"limit_exceeded",
|
|
418
|
+
`mission ${missionId} exceeds the ${this.maxFileBytes}-byte read limit`
|
|
419
|
+
);
|
|
420
|
+
}
|
|
421
|
+
const raw = await handle.readFile("utf8");
|
|
422
|
+
const parsed = parseMissionJsonl(raw, missionId, this.namespace, this.maxEvents);
|
|
423
|
+
return { exists: true, rawBytes: Buffer.byteLength(raw, "utf8"), ...parsed };
|
|
424
|
+
} catch (error) {
|
|
425
|
+
if (error.code === "ENOENT") {
|
|
426
|
+
return { exists: false, events: [], corruptLines: 0, rawBytes: 0 };
|
|
427
|
+
}
|
|
428
|
+
if (error instanceof RelayMissionStoreError) throw error;
|
|
429
|
+
throw new RelayMissionStoreError("read_failed", "failed to read Relay mission", {
|
|
430
|
+
cause: error
|
|
431
|
+
});
|
|
432
|
+
} finally {
|
|
433
|
+
await handle?.close().catch(() => void 0);
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
async appendFile(filePath, line) {
|
|
437
|
+
let handle;
|
|
438
|
+
try {
|
|
439
|
+
handle = await fs.open(
|
|
440
|
+
filePath,
|
|
441
|
+
fsConstants.O_WRONLY | fsConstants.O_CREAT | fsConstants.O_APPEND | fsConstants.O_NOFOLLOW,
|
|
442
|
+
384
|
|
443
|
+
);
|
|
444
|
+
const info = await handle.stat();
|
|
445
|
+
if (!info.isFile()) {
|
|
446
|
+
throw new RelayMissionStoreError("unsafe_path", "Relay mission path is not a file");
|
|
447
|
+
}
|
|
448
|
+
if (info.nlink !== 1) {
|
|
449
|
+
throw new RelayMissionStoreError("unsafe_path", "Relay mission hard links are rejected");
|
|
450
|
+
}
|
|
451
|
+
await handle.chmod(384);
|
|
452
|
+
await handle.writeFile(line, "utf8");
|
|
453
|
+
await handle.sync();
|
|
454
|
+
} catch (error) {
|
|
455
|
+
if (error instanceof RelayMissionStoreError) throw error;
|
|
456
|
+
if (error.code === "ELOOP") {
|
|
457
|
+
throw new RelayMissionStoreError("unsafe_path", "Relay mission symlink is rejected", {
|
|
458
|
+
cause: error
|
|
459
|
+
});
|
|
460
|
+
}
|
|
461
|
+
throw new RelayMissionStoreError("write_failed", "failed to append Relay mission", {
|
|
462
|
+
cause: error
|
|
463
|
+
});
|
|
464
|
+
} finally {
|
|
465
|
+
await handle?.close().catch(() => void 0);
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
};
|
|
469
|
+
function reduceRelayMission(input) {
|
|
470
|
+
const missionId = RelayMissionIdSchema.parse(input.missionId);
|
|
471
|
+
const namespace = namespaceSchema.parse(input.namespace);
|
|
472
|
+
const options = RelayMissionReadOptionsSchema.parse(input.options ?? {});
|
|
473
|
+
const corruptLines = input.corruptLines ?? 0;
|
|
474
|
+
const sinceMs = options.since ? Date.parse(options.since) : void 0;
|
|
475
|
+
const untilMs = options.until ? Date.parse(options.until) : void 0;
|
|
476
|
+
const appendPositions = new Map(input.events.map((event, index) => [event, index]));
|
|
477
|
+
const orderedEvents = [...input.events].sort(compareRelayEvents);
|
|
478
|
+
const firstStartEvent = input.events.find((event) => event.payload.kind === "mission_started");
|
|
479
|
+
const firstCompletionEvent = input.events.find((event) => event.payload.kind === "mission_completed");
|
|
480
|
+
const firstStartPosition = firstStartEvent === void 0 ? -1 : appendPositions.get(firstStartEvent) ?? -1;
|
|
481
|
+
const firstCompletionPosition = firstCompletionEvent === void 0 ? -1 : appendPositions.get(firstCompletionEvent) ?? -1;
|
|
482
|
+
const filteredEvents = orderedEvents.filter((event) => {
|
|
483
|
+
const occurredAt = Date.parse(event.occurredAt);
|
|
484
|
+
return (sinceMs === void 0 || occurredAt >= sinceMs) && (untilMs === void 0 || occurredAt < untilMs);
|
|
485
|
+
});
|
|
486
|
+
const agents = /* @__PURE__ */ new Map();
|
|
487
|
+
const decisions = /* @__PURE__ */ new Map();
|
|
488
|
+
const conflicts = /* @__PURE__ */ new Map();
|
|
489
|
+
const corrections = /* @__PURE__ */ new Map();
|
|
490
|
+
const tests = [];
|
|
491
|
+
const propagation = [];
|
|
492
|
+
const beliefAppendPositions = /* @__PURE__ */ new Map();
|
|
493
|
+
const conflictAppendPositions = /* @__PURE__ */ new Map();
|
|
494
|
+
const correctionProposalAppendPositions = /* @__PURE__ */ new Map();
|
|
495
|
+
const correctionApprovalAppendPositions = /* @__PURE__ */ new Map();
|
|
496
|
+
const correctionAppliedAppendPositions = /* @__PURE__ */ new Map();
|
|
497
|
+
const recallAppendPositions = /* @__PURE__ */ new Map();
|
|
498
|
+
const propagationAppendPositions = /* @__PURE__ */ new Map();
|
|
499
|
+
const testAppendPositions = /* @__PURE__ */ new Map();
|
|
500
|
+
const missingEvidence = /* @__PURE__ */ new Set();
|
|
501
|
+
if (corruptLines > 0) missingEvidence.add("mission:corrupt-events");
|
|
502
|
+
const substantiveAgentIds = /* @__PURE__ */ new Set();
|
|
503
|
+
const substantiveSessionIds = /* @__PURE__ */ new Set();
|
|
504
|
+
const conflictDisagreementIds = /* @__PURE__ */ new Set();
|
|
505
|
+
const groundedCorrectionIds = /* @__PURE__ */ new Set();
|
|
506
|
+
let title = null;
|
|
507
|
+
let objective = null;
|
|
508
|
+
let runMode = null;
|
|
509
|
+
let startedAt = null;
|
|
510
|
+
let completedAt = null;
|
|
511
|
+
let status = "not_started";
|
|
512
|
+
let outcome = null;
|
|
513
|
+
const ensureAgent = (agentId, sessionId, occurredAt) => {
|
|
514
|
+
const existing = agents.get(agentId);
|
|
515
|
+
if (existing) {
|
|
516
|
+
if (!existing.sessionIds.includes(sessionId)) existing.sessionIds.push(sessionId);
|
|
517
|
+
existing.lastSeenAt = occurredAt;
|
|
518
|
+
return existing;
|
|
519
|
+
}
|
|
520
|
+
const created = {
|
|
521
|
+
agentId,
|
|
522
|
+
label: agentId,
|
|
523
|
+
role: "Codex agent",
|
|
524
|
+
status: "working",
|
|
525
|
+
sessionIds: [sessionId],
|
|
526
|
+
outputs: [],
|
|
527
|
+
recalls: [],
|
|
528
|
+
lastSeenAt: occurredAt
|
|
529
|
+
};
|
|
530
|
+
agents.set(agentId, created);
|
|
531
|
+
return created;
|
|
532
|
+
};
|
|
533
|
+
const markSubstantiveParticipation = (agentId, sessionId) => {
|
|
534
|
+
substantiveAgentIds.add(agentId);
|
|
535
|
+
if (sessionId) substantiveSessionIds.add(sessionId);
|
|
536
|
+
};
|
|
537
|
+
for (const event of orderedEvents) {
|
|
538
|
+
const payload = event.payload;
|
|
539
|
+
const appendPosition = appendPositions.get(event) ?? -1;
|
|
540
|
+
if (payload.kind !== "mission_started" && firstStartEvent !== void 0 && (appendPosition < firstStartPosition || compareRelayEvents(event, firstStartEvent) < 0)) {
|
|
541
|
+
missingEvidence.add(`mission:event-before-start:${event.eventId}`);
|
|
542
|
+
collectMissingEvidence(missingEvidence, event, payload.evidence);
|
|
543
|
+
continue;
|
|
544
|
+
}
|
|
545
|
+
if (payload.kind !== "mission_completed" && (outcome !== null || firstCompletionPosition >= 0 && appendPosition > firstCompletionPosition)) {
|
|
546
|
+
missingEvidence.add(`mission:event-after-completion:${event.eventId}`);
|
|
547
|
+
if (payload.kind === "mission_started") missingEvidence.add("mission:lifecycle-order");
|
|
548
|
+
collectMissingEvidence(missingEvidence, event, payload.evidence);
|
|
549
|
+
continue;
|
|
550
|
+
}
|
|
551
|
+
switch (payload.kind) {
|
|
552
|
+
case "mission_started":
|
|
553
|
+
if (startedAt !== null) {
|
|
554
|
+
missingEvidence.add("mission:duplicate-start");
|
|
555
|
+
collectMissingEvidence(missingEvidence, event, payload.evidence);
|
|
556
|
+
break;
|
|
557
|
+
}
|
|
558
|
+
title = payload.title;
|
|
559
|
+
objective = payload.objective;
|
|
560
|
+
runMode = payload.runMode;
|
|
561
|
+
startedAt = event.occurredAt;
|
|
562
|
+
if (outcome === null) status = "active";
|
|
563
|
+
collectMissingEvidence(missingEvidence, event, payload.evidence);
|
|
564
|
+
break;
|
|
565
|
+
case "agent_status": {
|
|
566
|
+
const agent = ensureAgent(payload.agentId, payload.sessionId, event.occurredAt);
|
|
567
|
+
markSubstantiveParticipation(payload.agentId, payload.sessionId);
|
|
568
|
+
agent.label = payload.label;
|
|
569
|
+
agent.role = payload.role;
|
|
570
|
+
agent.status = payload.status;
|
|
571
|
+
collectMissingEvidence(missingEvidence, event, payload.evidence);
|
|
572
|
+
break;
|
|
573
|
+
}
|
|
574
|
+
case "agent_output": {
|
|
575
|
+
const agent = ensureAgent(payload.agentId, payload.sessionId, event.occurredAt);
|
|
576
|
+
markSubstantiveParticipation(payload.agentId, payload.sessionId);
|
|
577
|
+
agent.outputs.push({
|
|
578
|
+
outputId: payload.outputId,
|
|
579
|
+
summary: payload.summary,
|
|
580
|
+
occurredAt: event.occurredAt,
|
|
581
|
+
evidence: payload.evidence
|
|
582
|
+
});
|
|
583
|
+
collectMissingEvidence(missingEvidence, event, payload.evidence);
|
|
584
|
+
break;
|
|
585
|
+
}
|
|
586
|
+
case "belief_observed": {
|
|
587
|
+
ensureAgent(payload.agentId, payload.sessionId, event.occurredAt);
|
|
588
|
+
markSubstantiveParticipation(payload.agentId, payload.sessionId);
|
|
589
|
+
recordEarliestAppendPosition(
|
|
590
|
+
beliefAppendPositions,
|
|
591
|
+
beliefAppendPositionKey(payload.agentId, payload.decisionId),
|
|
592
|
+
appendPosition
|
|
593
|
+
);
|
|
594
|
+
const existing = decisions.get(payload.decisionId);
|
|
595
|
+
if (existing) {
|
|
596
|
+
if (!decisionStatementsMatch(existing.statement, payload.statement)) {
|
|
597
|
+
missingEvidence.add(`decision:${payload.decisionId}:statement-consistency`);
|
|
598
|
+
}
|
|
599
|
+
if (!existing.heldByAgentIds.includes(payload.agentId)) {
|
|
600
|
+
existing.heldByAgentIds.push(payload.agentId);
|
|
601
|
+
}
|
|
602
|
+
if (!existing.beliefIds.includes(payload.beliefId)) existing.beliefIds.push(payload.beliefId);
|
|
603
|
+
existing.evidence.push(...payload.evidence);
|
|
604
|
+
} else {
|
|
605
|
+
decisions.set(payload.decisionId, {
|
|
606
|
+
decisionId: payload.decisionId,
|
|
607
|
+
statement: payload.statement,
|
|
608
|
+
status: "active",
|
|
609
|
+
heldByAgentIds: [payload.agentId],
|
|
610
|
+
beliefIds: [payload.beliefId],
|
|
611
|
+
evidence: [...payload.evidence],
|
|
612
|
+
firstObservedAt: event.occurredAt
|
|
613
|
+
});
|
|
614
|
+
}
|
|
615
|
+
collectMissingEvidence(missingEvidence, event, payload.evidence);
|
|
616
|
+
break;
|
|
617
|
+
}
|
|
618
|
+
case "conflict_detected": {
|
|
619
|
+
recordEarliestAppendPosition(conflictAppendPositions, payload.conflictId, appendPosition);
|
|
620
|
+
const normalizedDecisionStatements = payload.decisionIds.map((decisionId) => decisions.get(decisionId)?.statement).filter((statement) => statement !== void 0).map(normalizeDecisionStatement);
|
|
621
|
+
if (normalizedDecisionStatements.length !== payload.decisionIds.length || new Set(normalizedDecisionStatements).size < 2) {
|
|
622
|
+
missingEvidence.add(`conflict:${payload.conflictId}:distinct-decision-statements`);
|
|
623
|
+
} else {
|
|
624
|
+
conflictDisagreementIds.add(payload.conflictId);
|
|
625
|
+
}
|
|
626
|
+
const participantHoldings = payload.agentIds.map((agentId) => ({
|
|
627
|
+
agentId,
|
|
628
|
+
decisionIds: uniqueSorted(
|
|
629
|
+
payload.decisionIds.filter((decisionId) => decisions.get(decisionId)?.heldByAgentIds.includes(agentId))
|
|
630
|
+
)
|
|
631
|
+
}));
|
|
632
|
+
for (const participant of participantHoldings) {
|
|
633
|
+
if (participant.decisionIds.length === 0) {
|
|
634
|
+
missingEvidence.add(`conflict:${payload.conflictId}:participant:${participant.agentId}:decision-link`);
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
for (const decisionId of payload.decisionIds) {
|
|
638
|
+
if (!participantHoldings.some((participant) => participant.decisionIds.includes(decisionId))) {
|
|
639
|
+
missingEvidence.add(`conflict:${payload.conflictId}:decision:${decisionId}:participant-link`);
|
|
640
|
+
}
|
|
641
|
+
if (!payload.agentIds.some(
|
|
642
|
+
(agentId) => (beliefAppendPositions.get(beliefAppendPositionKey(agentId, decisionId)) ?? Number.POSITIVE_INFINITY) < appendPosition
|
|
643
|
+
)) {
|
|
644
|
+
missingEvidence.add(`conflict:${payload.conflictId}:decision:${decisionId}:append-order`);
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
for (const agentId of payload.agentIds) {
|
|
648
|
+
if (!payload.decisionIds.some(
|
|
649
|
+
(decisionId) => (beliefAppendPositions.get(beliefAppendPositionKey(agentId, decisionId)) ?? Number.POSITIVE_INFINITY) < appendPosition
|
|
650
|
+
)) {
|
|
651
|
+
missingEvidence.add(`conflict:${payload.conflictId}:participant:${agentId}:append-order`);
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
if (participantHoldings.every((participant) => participant.decisionIds.length > 0) && new Set(participantHoldings.map((participant) => participant.decisionIds.join("\0"))).size < 2) {
|
|
655
|
+
missingEvidence.add(`conflict:${payload.conflictId}:distinct-participant-beliefs`);
|
|
656
|
+
}
|
|
657
|
+
if (conflicts.has(payload.conflictId)) {
|
|
658
|
+
missingEvidence.add(`conflict:${payload.conflictId}:duplicate`);
|
|
659
|
+
} else {
|
|
660
|
+
conflicts.set(payload.conflictId, {
|
|
661
|
+
conflictId: payload.conflictId,
|
|
662
|
+
decisionIds: uniqueSorted(payload.decisionIds),
|
|
663
|
+
agentIds: uniqueSorted(payload.agentIds),
|
|
664
|
+
summary: payload.summary,
|
|
665
|
+
status: "open",
|
|
666
|
+
occurredAt: event.occurredAt,
|
|
667
|
+
evidence: payload.evidence
|
|
668
|
+
});
|
|
669
|
+
}
|
|
670
|
+
for (const agentId of payload.agentIds) substantiveAgentIds.add(agentId);
|
|
671
|
+
collectMissingEvidence(missingEvidence, event, payload.evidence);
|
|
672
|
+
break;
|
|
673
|
+
}
|
|
674
|
+
case "test_result": {
|
|
675
|
+
const testSnapshot = {
|
|
676
|
+
testId: payload.testId,
|
|
677
|
+
decisionId: payload.decisionId,
|
|
678
|
+
...payload.correctionId === void 0 ? {} : { correctionId: payload.correctionId },
|
|
679
|
+
command: payload.command,
|
|
680
|
+
status: payload.status,
|
|
681
|
+
summary: payload.summary,
|
|
682
|
+
...payload.durationMs === void 0 ? {} : { durationMs: payload.durationMs },
|
|
683
|
+
occurredAt: event.occurredAt,
|
|
684
|
+
evidence: payload.evidence
|
|
685
|
+
};
|
|
686
|
+
tests.push(testSnapshot);
|
|
687
|
+
testAppendPositions.set(testSnapshot, appendPosition);
|
|
688
|
+
collectMissingEvidence(missingEvidence, event, payload.evidence);
|
|
689
|
+
break;
|
|
690
|
+
}
|
|
691
|
+
case "correction_proposed": {
|
|
692
|
+
if (corrections.has(payload.correctionId)) {
|
|
693
|
+
missingEvidence.add(`correction:${payload.correctionId}:duplicate-proposal`);
|
|
694
|
+
collectMissingEvidence(missingEvidence, event, payload.evidence);
|
|
695
|
+
break;
|
|
696
|
+
}
|
|
697
|
+
substantiveAgentIds.add(payload.proposedBy);
|
|
698
|
+
const correction = {
|
|
699
|
+
correctionId: payload.correctionId,
|
|
700
|
+
conflictId: payload.conflictId,
|
|
701
|
+
proposedDecisionId: payload.proposedDecisionId,
|
|
702
|
+
supersedesDecisionIds: uniqueSorted(payload.supersedesDecisionIds),
|
|
703
|
+
statement: payload.statement,
|
|
704
|
+
rationale: payload.rationale,
|
|
705
|
+
proposedBy: payload.proposedBy,
|
|
706
|
+
status: "proposed",
|
|
707
|
+
proposedAt: event.occurredAt,
|
|
708
|
+
evidence: [...payload.evidence]
|
|
709
|
+
};
|
|
710
|
+
corrections.set(payload.correctionId, correction);
|
|
711
|
+
correctionProposalAppendPositions.set(payload.correctionId, appendPosition);
|
|
712
|
+
const existingProposedDecision = decisions.get(payload.proposedDecisionId);
|
|
713
|
+
const replacementStatementMatches = existingProposedDecision === void 0 || decisionStatementsMatch(existingProposedDecision.statement, payload.statement);
|
|
714
|
+
if (!replacementStatementMatches) {
|
|
715
|
+
missingEvidence.add(`correction:${payload.correctionId}:replacement-statement`);
|
|
716
|
+
}
|
|
717
|
+
if (existingProposedDecision === void 0) {
|
|
718
|
+
decisions.set(payload.proposedDecisionId, {
|
|
719
|
+
decisionId: payload.proposedDecisionId,
|
|
720
|
+
statement: payload.statement,
|
|
721
|
+
status: "proposed",
|
|
722
|
+
heldByAgentIds: [],
|
|
723
|
+
beliefIds: [],
|
|
724
|
+
evidence: [...payload.evidence],
|
|
725
|
+
firstObservedAt: event.occurredAt
|
|
726
|
+
});
|
|
727
|
+
}
|
|
728
|
+
const conflict = conflicts.get(payload.conflictId);
|
|
729
|
+
const conflictAppendPosition = conflictAppendPositions.get(payload.conflictId);
|
|
730
|
+
const conflictPredatesProposal = conflictAppendPosition !== void 0 && conflictAppendPosition < appendPosition;
|
|
731
|
+
if (!conflictPredatesProposal) {
|
|
732
|
+
missingEvidence.add(`correction:${payload.correctionId}:conflict-append-order`);
|
|
733
|
+
}
|
|
734
|
+
const correctionSourceIds = sourceEvidenceIds(payload.evidence);
|
|
735
|
+
if (correctionSourceIds.size === 0) {
|
|
736
|
+
missingEvidence.add(`correction:${payload.correctionId}:source`);
|
|
737
|
+
}
|
|
738
|
+
if (conflict) {
|
|
739
|
+
const conflictSourceIds = sourceEvidenceIds(conflict.evidence);
|
|
740
|
+
if (conflictSourceIds.size === 0) {
|
|
741
|
+
missingEvidence.add(`conflict:${payload.conflictId}:source`);
|
|
742
|
+
}
|
|
743
|
+
const sourceLinked = [...correctionSourceIds].some((sourceId) => conflictSourceIds.has(sourceId));
|
|
744
|
+
if (!sourceLinked) {
|
|
745
|
+
missingEvidence.add(`correction:${payload.correctionId}:source-link`);
|
|
746
|
+
}
|
|
747
|
+
if (!correctionCoversConflict(correction, conflict)) {
|
|
748
|
+
missingEvidence.add(`conflict:${payload.conflictId}:decision-link`);
|
|
749
|
+
} else if (sourceLinked && conflictPredatesProposal && conflictDisagreementIds.has(payload.conflictId) && replacementStatementMatches) {
|
|
750
|
+
groundedCorrectionIds.add(payload.correctionId);
|
|
751
|
+
conflict.status = "proposed";
|
|
752
|
+
conflict.correctionId = payload.correctionId;
|
|
753
|
+
}
|
|
754
|
+
} else {
|
|
755
|
+
missingEvidence.add(`conflict:${payload.conflictId}:observation`);
|
|
756
|
+
}
|
|
757
|
+
status = "awaiting_approval";
|
|
758
|
+
collectMissingEvidence(missingEvidence, event, payload.evidence);
|
|
759
|
+
break;
|
|
760
|
+
}
|
|
761
|
+
case "correction_approved": {
|
|
762
|
+
if (payload.approvedBy.kind === "agent") substantiveAgentIds.add(payload.approvedBy.id);
|
|
763
|
+
const correction = corrections.get(payload.correctionId);
|
|
764
|
+
if (correction) {
|
|
765
|
+
const proposalAppendPosition = correctionProposalAppendPositions.get(payload.correctionId);
|
|
766
|
+
const proposalPredatesApproval = proposalAppendPosition !== void 0 && proposalAppendPosition < appendPosition;
|
|
767
|
+
const authenticatedHumanApproval = payload.approvedBy.kind !== "human" || runMode !== "live" || event.authenticatedPrincipal === payload.approvedBy.id;
|
|
768
|
+
if (!proposalPredatesApproval) {
|
|
769
|
+
missingEvidence.add(`correction:${payload.correctionId}:approval-append-order`);
|
|
770
|
+
} else if (!authenticatedHumanApproval) {
|
|
771
|
+
missingEvidence.add(`correction:${payload.correctionId}:authenticated-human-approval`);
|
|
772
|
+
} else if (correction.approvedAt === void 0) {
|
|
773
|
+
correction.approvedAt = event.occurredAt;
|
|
774
|
+
correction.approvedBy = payload.approvedBy;
|
|
775
|
+
correction.approvalNote = payload.note;
|
|
776
|
+
if (event.authenticatedPrincipal !== void 0) {
|
|
777
|
+
correction.approvalPrincipal = event.authenticatedPrincipal;
|
|
778
|
+
}
|
|
779
|
+
correctionApprovalAppendPositions.set(payload.correctionId, appendPosition);
|
|
780
|
+
if (correction.status === "proposed") correction.status = "approved";
|
|
781
|
+
status = "correcting";
|
|
782
|
+
} else {
|
|
783
|
+
missingEvidence.add(`correction:${payload.correctionId}:duplicate-approval`);
|
|
784
|
+
}
|
|
785
|
+
correction.evidence.push(...payload.evidence);
|
|
786
|
+
} else {
|
|
787
|
+
missingEvidence.add(`correction:${payload.correctionId}:proposal`);
|
|
788
|
+
}
|
|
789
|
+
collectMissingEvidence(missingEvidence, event, payload.evidence);
|
|
790
|
+
break;
|
|
791
|
+
}
|
|
792
|
+
case "decision_superseded": {
|
|
793
|
+
const correction = corrections.get(payload.correctionId);
|
|
794
|
+
if (!correction) {
|
|
795
|
+
missingEvidence.add(`correction:${payload.correctionId}:proposal`);
|
|
796
|
+
collectMissingEvidence(missingEvidence, event, payload.evidence);
|
|
797
|
+
break;
|
|
798
|
+
}
|
|
799
|
+
if (correction.approvedAt === void 0 || correction.approvedBy === void 0) {
|
|
800
|
+
missingEvidence.add(`correction:${payload.correctionId}:approval`);
|
|
801
|
+
collectMissingEvidence(missingEvidence, event, payload.evidence);
|
|
802
|
+
break;
|
|
803
|
+
}
|
|
804
|
+
const approvalAppendPosition = correctionApprovalAppendPositions.get(payload.correctionId);
|
|
805
|
+
if (approvalAppendPosition === void 0 || approvalAppendPosition >= appendPosition) {
|
|
806
|
+
missingEvidence.add(`correction:${payload.correctionId}:approval-append-order`);
|
|
807
|
+
collectMissingEvidence(missingEvidence, event, payload.evidence);
|
|
808
|
+
break;
|
|
809
|
+
}
|
|
810
|
+
const conflict = conflicts.get(correction.conflictId);
|
|
811
|
+
if (!conflict || !correctionCoversConflict(correction, conflict)) {
|
|
812
|
+
missingEvidence.add(`conflict:${correction.conflictId}:decision-link`);
|
|
813
|
+
collectMissingEvidence(missingEvidence, event, payload.evidence);
|
|
814
|
+
break;
|
|
815
|
+
}
|
|
816
|
+
if (!groundedCorrectionIds.has(payload.correctionId)) {
|
|
817
|
+
missingEvidence.add(`correction:${payload.correctionId}:source-link`);
|
|
818
|
+
collectMissingEvidence(missingEvidence, event, payload.evidence);
|
|
819
|
+
break;
|
|
820
|
+
}
|
|
821
|
+
if (!correction.supersedesDecisionIds.includes(payload.decisionId) || correction.proposedDecisionId !== payload.replacementDecisionId) {
|
|
822
|
+
missingEvidence.add(`correction:${payload.correctionId}:supersession-link`);
|
|
823
|
+
collectMissingEvidence(missingEvidence, event, payload.evidence);
|
|
824
|
+
break;
|
|
825
|
+
}
|
|
826
|
+
const stale = decisions.get(payload.decisionId);
|
|
827
|
+
const replacement = decisions.get(payload.replacementDecisionId);
|
|
828
|
+
if (!stale) missingEvidence.add(`decision:${payload.decisionId}:observation`);
|
|
829
|
+
if (!replacement) missingEvidence.add(`decision:${payload.replacementDecisionId}:replacement`);
|
|
830
|
+
if (!stale || !replacement) {
|
|
831
|
+
collectMissingEvidence(missingEvidence, event, payload.evidence);
|
|
832
|
+
break;
|
|
833
|
+
}
|
|
834
|
+
stale.status = "superseded";
|
|
835
|
+
stale.supersededAt = event.occurredAt;
|
|
836
|
+
stale.supersededBy = payload.replacementDecisionId;
|
|
837
|
+
stale.correctionId = payload.correctionId;
|
|
838
|
+
stale.evidence.push(...payload.evidence);
|
|
839
|
+
replacement.status = "active";
|
|
840
|
+
replacement.evidence.push(...payload.evidence);
|
|
841
|
+
correction.evidence.push(...payload.evidence);
|
|
842
|
+
if (correctionSupersessionComplete(correction, decisions)) {
|
|
843
|
+
correction.appliedAt ??= event.occurredAt;
|
|
844
|
+
recordEarliestAppendPosition(correctionAppliedAppendPositions, payload.correctionId, appendPosition);
|
|
845
|
+
if (correction.status !== "propagated") correction.status = "applied";
|
|
846
|
+
conflict.status = "resolved";
|
|
847
|
+
}
|
|
848
|
+
collectMissingEvidence(missingEvidence, event, payload.evidence);
|
|
849
|
+
break;
|
|
850
|
+
}
|
|
851
|
+
case "recall_observed": {
|
|
852
|
+
const agent = ensureAgent(payload.agentId, payload.sessionId, event.occurredAt);
|
|
853
|
+
const coldStart = !substantiveAgentIds.has(payload.agentId) && !substantiveSessionIds.has(payload.sessionId) && agent.recalls.length === 0;
|
|
854
|
+
const recallSnapshot = {
|
|
855
|
+
recallReceiptId: payload.recallReceiptId,
|
|
856
|
+
sessionId: payload.sessionId,
|
|
857
|
+
decisionId: payload.decisionId,
|
|
858
|
+
query: payload.query,
|
|
859
|
+
capturedAtAction: payload.capturedAtAction,
|
|
860
|
+
coldStart,
|
|
861
|
+
occurredAt: event.occurredAt,
|
|
862
|
+
evidence: payload.evidence
|
|
863
|
+
};
|
|
864
|
+
agent.recalls.push(recallSnapshot);
|
|
865
|
+
recallAppendPositions.set(recallSnapshot, appendPosition);
|
|
866
|
+
markSubstantiveParticipation(payload.agentId, payload.sessionId);
|
|
867
|
+
const decision = decisions.get(payload.decisionId);
|
|
868
|
+
if (decision && !decision.heldByAgentIds.includes(payload.agentId)) {
|
|
869
|
+
decision.heldByAgentIds.push(payload.agentId);
|
|
870
|
+
}
|
|
871
|
+
if (!decision) missingEvidence.add(`decision:${payload.decisionId}:recall-target`);
|
|
872
|
+
collectMissingEvidence(missingEvidence, event, payload.evidence);
|
|
873
|
+
break;
|
|
874
|
+
}
|
|
875
|
+
case "propagation_verified": {
|
|
876
|
+
const agent = ensureAgent(payload.agentId, payload.sessionId, event.occurredAt);
|
|
877
|
+
const correction = corrections.get(payload.correctionId);
|
|
878
|
+
if (!correction) {
|
|
879
|
+
missingEvidence.add(`correction:${payload.correctionId}:proposal`);
|
|
880
|
+
collectMissingEvidence(missingEvidence, event, payload.evidence);
|
|
881
|
+
break;
|
|
882
|
+
}
|
|
883
|
+
if (correction.approvedAt === void 0 || correction.approvedBy === void 0) {
|
|
884
|
+
missingEvidence.add(`correction:${payload.correctionId}:approval`);
|
|
885
|
+
collectMissingEvidence(missingEvidence, event, payload.evidence);
|
|
886
|
+
break;
|
|
887
|
+
}
|
|
888
|
+
if (correction.status !== "applied" && correction.status !== "propagated" || correction.appliedAt === void 0 || correction.proposedDecisionId !== payload.decisionId) {
|
|
889
|
+
missingEvidence.add(`correction:${payload.correctionId}:supersession`);
|
|
890
|
+
collectMissingEvidence(missingEvidence, event, payload.evidence);
|
|
891
|
+
break;
|
|
892
|
+
}
|
|
893
|
+
const recalled = agent.recalls.find(
|
|
894
|
+
(recall) => recall.recallReceiptId === payload.recallReceiptId && recall.sessionId === payload.sessionId && recall.decisionId === payload.decisionId
|
|
895
|
+
);
|
|
896
|
+
if (!recalled) {
|
|
897
|
+
missingEvidence.add(`recall:${payload.recallReceiptId}:observation`);
|
|
898
|
+
collectMissingEvidence(missingEvidence, event, payload.evidence);
|
|
899
|
+
break;
|
|
900
|
+
}
|
|
901
|
+
const appliedAppendPosition = correctionAppliedAppendPositions.get(payload.correctionId);
|
|
902
|
+
const recallAppendPosition = recallAppendPositions.get(recalled);
|
|
903
|
+
if (appliedAppendPosition === void 0 || recallAppendPosition === void 0 || appliedAppendPosition >= recallAppendPosition) {
|
|
904
|
+
missingEvidence.add(`recall:${payload.recallReceiptId}:post-application-append-order`);
|
|
905
|
+
collectMissingEvidence(missingEvidence, event, payload.evidence);
|
|
906
|
+
break;
|
|
907
|
+
}
|
|
908
|
+
if (recallAppendPosition >= appendPosition) {
|
|
909
|
+
missingEvidence.add(`recall:${payload.recallReceiptId}:propagation-append-order`);
|
|
910
|
+
collectMissingEvidence(missingEvidence, event, payload.evidence);
|
|
911
|
+
break;
|
|
912
|
+
}
|
|
913
|
+
if (!recalled.capturedAtAction) {
|
|
914
|
+
missingEvidence.add(`recall:${payload.recallReceiptId}:at-action`);
|
|
915
|
+
collectMissingEvidence(missingEvidence, event, payload.evidence);
|
|
916
|
+
break;
|
|
917
|
+
}
|
|
918
|
+
if (!recalled.coldStart) {
|
|
919
|
+
missingEvidence.add(`recall:${payload.recallReceiptId}:cold-start`);
|
|
920
|
+
collectMissingEvidence(missingEvidence, event, payload.evidence);
|
|
921
|
+
break;
|
|
922
|
+
}
|
|
923
|
+
if (compareInstants(correction.appliedAt, recalled.occurredAt) >= 0) {
|
|
924
|
+
missingEvidence.add(`recall:${payload.recallReceiptId}:post-application`);
|
|
925
|
+
collectMissingEvidence(missingEvidence, event, payload.evidence);
|
|
926
|
+
break;
|
|
927
|
+
}
|
|
928
|
+
if (compareInstants(recalled.occurredAt, event.occurredAt) >= 0) {
|
|
929
|
+
missingEvidence.add(`recall:${payload.recallReceiptId}:propagation-order`);
|
|
930
|
+
collectMissingEvidence(missingEvidence, event, payload.evidence);
|
|
931
|
+
break;
|
|
932
|
+
}
|
|
933
|
+
const propagationSnapshot = {
|
|
934
|
+
correctionId: payload.correctionId,
|
|
935
|
+
agentId: payload.agentId,
|
|
936
|
+
sessionId: payload.sessionId,
|
|
937
|
+
decisionId: payload.decisionId,
|
|
938
|
+
recallReceiptId: payload.recallReceiptId,
|
|
939
|
+
staleDecisionAbsent: payload.staleDecisionAbsent,
|
|
940
|
+
occurredAt: event.occurredAt,
|
|
941
|
+
evidence: payload.evidence
|
|
942
|
+
};
|
|
943
|
+
propagation.push(propagationSnapshot);
|
|
944
|
+
propagationAppendPositions.set(propagationSnapshot, appendPosition);
|
|
945
|
+
correction.evidence.push(...payload.evidence);
|
|
946
|
+
if (payload.staleDecisionAbsent) {
|
|
947
|
+
correction.status = "propagated";
|
|
948
|
+
correction.propagatedAt = event.occurredAt;
|
|
949
|
+
}
|
|
950
|
+
status = payload.staleDecisionAbsent ? "verified" : "correcting";
|
|
951
|
+
collectMissingEvidence(missingEvidence, event, payload.evidence);
|
|
952
|
+
break;
|
|
953
|
+
}
|
|
954
|
+
case "mission_completed":
|
|
955
|
+
if (outcome !== null) {
|
|
956
|
+
missingEvidence.add("mission:duplicate-completion");
|
|
957
|
+
collectMissingEvidence(missingEvidence, event, payload.evidence);
|
|
958
|
+
break;
|
|
959
|
+
}
|
|
960
|
+
if (startedAt === null) missingEvidence.add("mission:start");
|
|
961
|
+
outcome = {
|
|
962
|
+
result: payload.outcome,
|
|
963
|
+
summary: payload.summary,
|
|
964
|
+
occurredAt: event.occurredAt,
|
|
965
|
+
evidence: payload.evidence
|
|
966
|
+
};
|
|
967
|
+
completedAt = event.occurredAt;
|
|
968
|
+
status = payload.outcome === "failed" ? "failed" : "completed";
|
|
969
|
+
collectMissingEvidence(missingEvidence, event, payload.evidence);
|
|
970
|
+
break;
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
for (const conflict of conflicts.values()) {
|
|
974
|
+
if (sourceEvidenceIds(conflict.evidence).size === 0) {
|
|
975
|
+
missingEvidence.add(`conflict:${conflict.conflictId}:source`);
|
|
976
|
+
}
|
|
977
|
+
for (const decisionId of conflict.decisionIds) {
|
|
978
|
+
if (!decisions.has(decisionId)) missingEvidence.add(`decision:${decisionId}:conflict-target`);
|
|
979
|
+
}
|
|
980
|
+
for (const agentId of conflict.agentIds) {
|
|
981
|
+
if (!agents.has(agentId)) missingEvidence.add(`agent:${agentId}:conflict-participant`);
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
for (const correction of corrections.values()) {
|
|
985
|
+
if (sourceEvidenceIds(correction.evidence).size === 0) {
|
|
986
|
+
missingEvidence.add(`correction:${correction.correctionId}:source`);
|
|
987
|
+
}
|
|
988
|
+
if (correction.approvedAt === void 0 || correction.approvedBy === void 0) {
|
|
989
|
+
missingEvidence.add(`correction:${correction.correctionId}:approval`);
|
|
990
|
+
} else if (correction.approvedBy.kind !== "human") {
|
|
991
|
+
missingEvidence.add(`correction:${correction.correctionId}:human-approval`);
|
|
992
|
+
} else if (runMode === "live" && correction.approvalPrincipal !== correction.approvedBy.id) {
|
|
993
|
+
missingEvidence.add(`correction:${correction.correctionId}:authenticated-human-approval`);
|
|
994
|
+
}
|
|
995
|
+
if (correction.status === "approved" || correction.status === "proposed") {
|
|
996
|
+
missingEvidence.add(`correction:${correction.correctionId}:supersession`);
|
|
997
|
+
}
|
|
998
|
+
if (correction.status === "applied") {
|
|
999
|
+
missingEvidence.add(`correction:${correction.correctionId}:propagation`);
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
const liveFixtureEvidenceEventIds = runMode === "live" ? orderedEvents.filter((event) => event.payload.evidence.some((item) => item.capture === "fixture")).map((event) => event.eventId) : [];
|
|
1003
|
+
for (const eventId of liveFixtureEvidenceEventIds) {
|
|
1004
|
+
missingEvidence.add(`mission:live-fixture-evidence:${eventId}`);
|
|
1005
|
+
}
|
|
1006
|
+
const captureTrustValid = liveFixtureEvidenceEventIds.length === 0;
|
|
1007
|
+
const sortedDecisions = [...decisions.values()].map((decision) => ({
|
|
1008
|
+
...decision,
|
|
1009
|
+
heldByAgentIds: uniqueSorted(decision.heldByAgentIds),
|
|
1010
|
+
beliefIds: uniqueSorted(decision.beliefIds),
|
|
1011
|
+
evidence: uniqueEvidence(decision.evidence)
|
|
1012
|
+
})).sort((a, b) => compareText(a.decisionId, b.decisionId));
|
|
1013
|
+
const coldStartVerified = captureTrustValid && propagation.some((item) => item.staleDecisionAbsent);
|
|
1014
|
+
const passingOutcomeVerified = captureTrustValid && outcome?.result === "recovered" && tests.some((test) => {
|
|
1015
|
+
const testAppendPosition = testAppendPositions.get(test);
|
|
1016
|
+
if (test.status !== "passed" || test.correctionId === void 0 || testAppendPosition === void 0 || firstCompletionPosition < 0 || testAppendPosition >= firstCompletionPosition || compareInstants(test.occurredAt, outcome.occurredAt) >= 0) {
|
|
1017
|
+
return false;
|
|
1018
|
+
}
|
|
1019
|
+
const correction = corrections.get(test.correctionId);
|
|
1020
|
+
if (correction?.status !== "propagated" || correction.proposedDecisionId !== test.decisionId || !test.evidence.some((item) => item.kind === "correction" && item.id === correction.correctionId) || !test.evidence.some((item) => item.kind === "test")) {
|
|
1021
|
+
return false;
|
|
1022
|
+
}
|
|
1023
|
+
return propagation.some((item) => {
|
|
1024
|
+
const propagationAppendPosition = propagationAppendPositions.get(item);
|
|
1025
|
+
return item.staleDecisionAbsent && item.correctionId === correction.correctionId && item.decisionId === test.decisionId && propagationAppendPosition !== void 0 && propagationAppendPosition < testAppendPosition && compareInstants(item.occurredAt, test.occurredAt) < 0;
|
|
1026
|
+
});
|
|
1027
|
+
});
|
|
1028
|
+
if (outcome && !passingOutcomeVerified) missingEvidence.add("outcome:passing-test");
|
|
1029
|
+
if (outcome?.result === "recovered" && !coldStartVerified) {
|
|
1030
|
+
missingEvidence.add("outcome:cold-start-propagation");
|
|
1031
|
+
}
|
|
1032
|
+
if (input.events.length > 0 && startedAt === null) missingEvidence.add("mission:start");
|
|
1033
|
+
if (startedAt !== null && completedAt !== null && compareInstants(startedAt, completedAt) >= 0) {
|
|
1034
|
+
missingEvidence.add("mission:lifecycle-order");
|
|
1035
|
+
}
|
|
1036
|
+
if (firstStartEvent !== void 0 && firstCompletionEvent !== void 0 && (firstStartPosition >= firstCompletionPosition || compareRelayEvents(firstStartEvent, firstCompletionEvent) >= 0)) {
|
|
1037
|
+
missingEvidence.add("mission:lifecycle-order");
|
|
1038
|
+
}
|
|
1039
|
+
const eventWindow = filteredEvents.slice(Math.max(0, filteredEvents.length - options.limit));
|
|
1040
|
+
const found = input.events.length > 0;
|
|
1041
|
+
return {
|
|
1042
|
+
schemaVersion: RELAY_MISSION_SCHEMA_VERSION,
|
|
1043
|
+
missionId,
|
|
1044
|
+
namespace,
|
|
1045
|
+
found,
|
|
1046
|
+
readHealth: corruptLines > 0 ? "partial" : found || input.fileExists ? "ok" : "empty",
|
|
1047
|
+
status,
|
|
1048
|
+
mission: { title, objective, runMode, startedAt, completedAt },
|
|
1049
|
+
agents: [...agents.values()].map((agent) => ({
|
|
1050
|
+
...agent,
|
|
1051
|
+
sessionIds: uniqueSorted(agent.sessionIds),
|
|
1052
|
+
outputs: agent.outputs.sort((a, b) => compareTimedIds(a, b, "outputId")),
|
|
1053
|
+
recalls: agent.recalls.sort((a, b) => compareTimedIds(a, b, "recallReceiptId"))
|
|
1054
|
+
})).sort((a, b) => compareText(a.agentId, b.agentId)),
|
|
1055
|
+
decisions: sortedDecisions,
|
|
1056
|
+
conflicts: [...conflicts.values()].sort((a, b) => compareText(a.conflictId, b.conflictId)),
|
|
1057
|
+
corrections: [...corrections.values()].map((correction) => ({ ...correction, evidence: uniqueEvidence(correction.evidence) })).sort((a, b) => compareText(a.correctionId, b.correctionId)),
|
|
1058
|
+
tests: tests.sort((a, b) => compareTimedIds(a, b, "testId")),
|
|
1059
|
+
propagation: propagation.sort((a, b) => {
|
|
1060
|
+
const byTime = compareInstants(a.occurredAt, b.occurredAt);
|
|
1061
|
+
if (byTime !== 0) return byTime;
|
|
1062
|
+
const byAgent = compareText(a.agentId, b.agentId);
|
|
1063
|
+
return byAgent !== 0 ? byAgent : compareText(a.recallReceiptId, b.recallReceiptId);
|
|
1064
|
+
}),
|
|
1065
|
+
outcome,
|
|
1066
|
+
receipt: {
|
|
1067
|
+
complete: status === "completed" && outcome?.result === "recovered" && passingOutcomeVerified && coldStartVerified && missingEvidence.size === 0,
|
|
1068
|
+
missingEvidence: [...missingEvidence].sort(compareText),
|
|
1069
|
+
activeDecisionIds: sortedDecisions.filter((decision) => decision.status === "active").map((decision) => decision.decisionId),
|
|
1070
|
+
supersededDecisionIds: sortedDecisions.filter((decision) => decision.status === "superseded").map((decision) => decision.decisionId),
|
|
1071
|
+
coldStartVerified,
|
|
1072
|
+
passingOutcomeVerified
|
|
1073
|
+
},
|
|
1074
|
+
bounds: {
|
|
1075
|
+
totalEvents: filteredEvents.length,
|
|
1076
|
+
returnedEvents: eventWindow.length,
|
|
1077
|
+
corruptLines,
|
|
1078
|
+
truncated: filteredEvents.length > eventWindow.length,
|
|
1079
|
+
since: options.since ?? null,
|
|
1080
|
+
until: options.until ?? null
|
|
1081
|
+
},
|
|
1082
|
+
events: eventWindow
|
|
1083
|
+
};
|
|
1084
|
+
}
|
|
1085
|
+
function compareRelayEvents(a, b) {
|
|
1086
|
+
const byOccurrence = compareInstants(a.occurredAt, b.occurredAt);
|
|
1087
|
+
if (byOccurrence !== 0) return byOccurrence;
|
|
1088
|
+
const byRecord = compareInstants(a.recordedAt, b.recordedAt);
|
|
1089
|
+
if (byRecord !== 0) return byRecord;
|
|
1090
|
+
return compareText(a.eventId, b.eventId);
|
|
1091
|
+
}
|
|
1092
|
+
function parseMissionJsonl(raw, missionId, namespace, maxEvents) {
|
|
1093
|
+
const events = [];
|
|
1094
|
+
let corruptLines = 0;
|
|
1095
|
+
for (const line of raw.split("\n")) {
|
|
1096
|
+
if (line.trim().length === 0) continue;
|
|
1097
|
+
if (Buffer.byteLength(line, "utf8") > RELAY_MISSION_MAX_LINE_BYTES) {
|
|
1098
|
+
corruptLines += 1;
|
|
1099
|
+
continue;
|
|
1100
|
+
}
|
|
1101
|
+
let candidate;
|
|
1102
|
+
try {
|
|
1103
|
+
candidate = JSON.parse(line);
|
|
1104
|
+
} catch {
|
|
1105
|
+
corruptLines += 1;
|
|
1106
|
+
continue;
|
|
1107
|
+
}
|
|
1108
|
+
const parsed = RelayMissionEventSchema.safeParse(candidate);
|
|
1109
|
+
if (!parsed.success || parsed.data.missionId !== missionId || parsed.data.namespace !== namespace) {
|
|
1110
|
+
corruptLines += 1;
|
|
1111
|
+
continue;
|
|
1112
|
+
}
|
|
1113
|
+
if (events.length >= maxEvents) {
|
|
1114
|
+
throw new RelayMissionStoreError(
|
|
1115
|
+
"limit_exceeded",
|
|
1116
|
+
`mission ${missionId} exceeds the ${maxEvents}-event read limit`
|
|
1117
|
+
);
|
|
1118
|
+
}
|
|
1119
|
+
events.push(parsed.data);
|
|
1120
|
+
}
|
|
1121
|
+
return { events, corruptLines };
|
|
1122
|
+
}
|
|
1123
|
+
function collectMissingEvidence(missing, event, evidence) {
|
|
1124
|
+
if (evidence.length === 0) missing.add(`event:${event.eventId}:evidence`);
|
|
1125
|
+
}
|
|
1126
|
+
function sameIdempotentInput(event, input, authenticatedPrincipal) {
|
|
1127
|
+
if (event.authenticatedPrincipal !== authenticatedPrincipal) return false;
|
|
1128
|
+
if (input.occurredAt !== void 0 && event.occurredAt !== input.occurredAt) return false;
|
|
1129
|
+
return stableJson(event.payload) === stableJson(input.payload);
|
|
1130
|
+
}
|
|
1131
|
+
function stableJson(value) {
|
|
1132
|
+
if (Array.isArray(value)) return `[${value.map(stableJson).join(",")}]`;
|
|
1133
|
+
if (value && typeof value === "object") {
|
|
1134
|
+
const entries = Object.entries(value).sort(([a], [b]) => compareText(a, b)).map(([key, child]) => `${JSON.stringify(key)}:${stableJson(child)}`);
|
|
1135
|
+
return `{${entries.join(",")}}`;
|
|
1136
|
+
}
|
|
1137
|
+
return JSON.stringify(value) ?? "null";
|
|
1138
|
+
}
|
|
1139
|
+
function uniqueEvidence(evidence) {
|
|
1140
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
1141
|
+
for (const item of evidence) byKey.set(`${item.kind}\0${item.id}`, item);
|
|
1142
|
+
return [...byKey.values()].sort((a, b) => {
|
|
1143
|
+
const byKind = compareText(a.kind, b.kind);
|
|
1144
|
+
return byKind !== 0 ? byKind : compareText(a.id, b.id);
|
|
1145
|
+
});
|
|
1146
|
+
}
|
|
1147
|
+
function uniqueSorted(values) {
|
|
1148
|
+
return [...new Set(values)].sort(compareText);
|
|
1149
|
+
}
|
|
1150
|
+
function compareText(a, b) {
|
|
1151
|
+
if (a < b) return -1;
|
|
1152
|
+
if (a > b) return 1;
|
|
1153
|
+
return 0;
|
|
1154
|
+
}
|
|
1155
|
+
function compareInstants(a, b) {
|
|
1156
|
+
const aMs = Date.parse(a);
|
|
1157
|
+
const bMs = Date.parse(b);
|
|
1158
|
+
if (aMs < bMs) return -1;
|
|
1159
|
+
if (aMs > bMs) return 1;
|
|
1160
|
+
return 0;
|
|
1161
|
+
}
|
|
1162
|
+
function compareTimedIds(a, b, idKey) {
|
|
1163
|
+
const byTime = compareInstants(a.occurredAt, b.occurredAt);
|
|
1164
|
+
if (byTime !== 0) return byTime;
|
|
1165
|
+
return compareText(String(a[idKey]), String(b[idKey]));
|
|
1166
|
+
}
|
|
1167
|
+
function beliefAppendPositionKey(agentId, decisionId) {
|
|
1168
|
+
return `${agentId}\0${decisionId}`;
|
|
1169
|
+
}
|
|
1170
|
+
function normalizeDecisionStatement(statement) {
|
|
1171
|
+
return statement.normalize("NFKC").trim().toLowerCase().replace(/\s+/g, " ").replace(/[.!?]+$/, "");
|
|
1172
|
+
}
|
|
1173
|
+
function decisionStatementsMatch(left, right) {
|
|
1174
|
+
return normalizeDecisionStatement(left) === normalizeDecisionStatement(right);
|
|
1175
|
+
}
|
|
1176
|
+
function recordEarliestAppendPosition(positions, key, position) {
|
|
1177
|
+
const current = positions.get(key);
|
|
1178
|
+
if (current === void 0 || position < current) positions.set(key, position);
|
|
1179
|
+
}
|
|
1180
|
+
function correctionSupersessionComplete(correction, decisions) {
|
|
1181
|
+
return correction.supersedesDecisionIds.every((decisionId) => {
|
|
1182
|
+
const decision = decisions.get(decisionId);
|
|
1183
|
+
return decision?.status === "superseded" && decision.supersededBy === correction.proposedDecisionId && decision.correctionId === correction.correctionId;
|
|
1184
|
+
});
|
|
1185
|
+
}
|
|
1186
|
+
function correctionCoversConflict(correction, conflict) {
|
|
1187
|
+
const expectedSuperseded = uniqueSorted(
|
|
1188
|
+
conflict.decisionIds.filter((decisionId) => decisionId !== correction.proposedDecisionId)
|
|
1189
|
+
);
|
|
1190
|
+
const declaredSuperseded = uniqueSorted(correction.supersedesDecisionIds);
|
|
1191
|
+
return expectedSuperseded.length === declaredSuperseded.length && expectedSuperseded.every((decisionId, index) => decisionId === declaredSuperseded[index]);
|
|
1192
|
+
}
|
|
1193
|
+
function sourceEvidenceIds(evidence) {
|
|
1194
|
+
return new Set(evidence.filter((item) => item.kind === "source").map((item) => item.id));
|
|
1195
|
+
}
|
|
1196
|
+
function positiveIntegerOption(value, name, fallback) {
|
|
1197
|
+
if (value === void 0) return fallback;
|
|
1198
|
+
if (!Number.isInteger(value) || value <= 0) {
|
|
1199
|
+
throw new TypeError(`RelayMissionStore ${name} must be a positive integer`);
|
|
1200
|
+
}
|
|
1201
|
+
return value;
|
|
1202
|
+
}
|
|
1203
|
+
function validNow(now) {
|
|
1204
|
+
const value = now();
|
|
1205
|
+
if (!(value instanceof Date) || !Number.isFinite(value.getTime())) {
|
|
1206
|
+
throw new TypeError("RelayMissionStore now() must return a valid Date");
|
|
1207
|
+
}
|
|
1208
|
+
return value.toISOString();
|
|
1209
|
+
}
|
|
1210
|
+
async function openOrCreatePinnedChildDirectory(parentHandle, segment) {
|
|
1211
|
+
const directory = path.join(pinnedDirectoryPath(parentHandle), segment);
|
|
1212
|
+
try {
|
|
1213
|
+
await fs.mkdir(directory, { mode: 448 });
|
|
1214
|
+
} catch (error) {
|
|
1215
|
+
if (error.code !== "EEXIST") throw error;
|
|
1216
|
+
}
|
|
1217
|
+
return openVerifiedDirectory(directory, "Relay directory symlinks are rejected");
|
|
1218
|
+
}
|
|
1219
|
+
async function openVerifiedDirectory(directory, unsafeMessage) {
|
|
1220
|
+
const before = await fs.lstat(directory);
|
|
1221
|
+
if (before.isSymbolicLink() || !before.isDirectory()) {
|
|
1222
|
+
throw new RelayMissionStoreError("unsafe_path", unsafeMessage);
|
|
1223
|
+
}
|
|
1224
|
+
const handle = await fs.open(directory, fsConstants.O_RDONLY | fsConstants.O_DIRECTORY | fsConstants.O_NOFOLLOW);
|
|
1225
|
+
try {
|
|
1226
|
+
const openInfo = await handle.stat();
|
|
1227
|
+
const after = await fs.lstat(directory);
|
|
1228
|
+
if (after.isSymbolicLink() || !after.isDirectory() || before.dev !== openInfo.dev || before.ino !== openInfo.ino || after.dev !== openInfo.dev || after.ino !== openInfo.ino) {
|
|
1229
|
+
throw new RelayMissionStoreError("unsafe_path", "Relay directory changed during validation");
|
|
1230
|
+
}
|
|
1231
|
+
return handle;
|
|
1232
|
+
} catch (error) {
|
|
1233
|
+
await handle.close().catch(() => void 0);
|
|
1234
|
+
throw error;
|
|
1235
|
+
}
|
|
1236
|
+
}
|
|
1237
|
+
function pinnedDirectoryPath(handle) {
|
|
1238
|
+
if (process.platform === "linux") return `/proc/self/fd/${handle.fd}`;
|
|
1239
|
+
if (process.platform === "darwin" || process.platform === "freebsd" || process.platform === "openbsd") {
|
|
1240
|
+
return `/dev/fd/${handle.fd}`;
|
|
1241
|
+
}
|
|
1242
|
+
throw new RelayMissionStoreError(
|
|
1243
|
+
"unsafe_path",
|
|
1244
|
+
`Relay pinned directory access is unsupported on ${process.platform}`
|
|
1245
|
+
);
|
|
1246
|
+
}
|
|
1247
|
+
function relayMissionReceiptDigest(snapshot) {
|
|
1248
|
+
const receipt = {
|
|
1249
|
+
schemaVersion: snapshot.schemaVersion,
|
|
1250
|
+
missionId: snapshot.missionId,
|
|
1251
|
+
namespace: snapshot.namespace,
|
|
1252
|
+
status: snapshot.status,
|
|
1253
|
+
decisions: snapshot.decisions,
|
|
1254
|
+
corrections: snapshot.corrections,
|
|
1255
|
+
propagation: snapshot.propagation,
|
|
1256
|
+
tests: snapshot.tests,
|
|
1257
|
+
outcome: snapshot.outcome,
|
|
1258
|
+
receipt: snapshot.receipt
|
|
1259
|
+
};
|
|
1260
|
+
return createHash("sha256").update(stableJson(receipt)).digest("hex");
|
|
1261
|
+
}
|
|
1262
|
+
|
|
1263
|
+
// src/relay/mission-access.ts
|
|
1264
|
+
var namespaceSchema2 = z2.string().trim().min(1).max(128).nullable().optional();
|
|
1265
|
+
var RelayMissionAppendAccessSchema = z2.object({
|
|
1266
|
+
missionId: RelayMissionIdSchema,
|
|
1267
|
+
namespace: namespaceSchema2,
|
|
1268
|
+
event: RelayMissionEventInputSchema
|
|
1269
|
+
}).strict();
|
|
1270
|
+
var optionalLimitSchema = z2.preprocess((value) => {
|
|
1271
|
+
if (value === void 0 || value === null) return void 0;
|
|
1272
|
+
if (typeof value === "string" && /^(?:0|[1-9]\d*)$/.test(value)) return Number(value);
|
|
1273
|
+
return value;
|
|
1274
|
+
}, z2.number().int().min(1).max(RELAY_MISSION_MAX_EVENT_LIMIT).optional());
|
|
1275
|
+
var RelayMissionReadAccessSchema = z2.object({
|
|
1276
|
+
missionId: RelayMissionIdSchema,
|
|
1277
|
+
namespace: namespaceSchema2,
|
|
1278
|
+
since: RelayIsoDateTimeSchema.optional(),
|
|
1279
|
+
until: RelayIsoDateTimeSchema.optional(),
|
|
1280
|
+
limit: optionalLimitSchema
|
|
1281
|
+
}).strict().refine(
|
|
1282
|
+
(value) => value.since === void 0 || value.until === void 0 || Date.parse(value.since) < Date.parse(value.until),
|
|
1283
|
+
{ message: "since must be earlier than until", path: ["until"] }
|
|
1284
|
+
);
|
|
1285
|
+
async function appendRelayMissionEvent(service, input, authenticatedPrincipal, beforeAppend) {
|
|
1286
|
+
const resolved = await service.getWritableStorageForNamespace(input.namespace ?? void 0, authenticatedPrincipal);
|
|
1287
|
+
const store = new RelayMissionStore({
|
|
1288
|
+
rootDir: resolved.storage.dir,
|
|
1289
|
+
namespace: resolved.namespace
|
|
1290
|
+
});
|
|
1291
|
+
return store.append(input.missionId, input.event, { authenticatedPrincipal, beforeAppend });
|
|
1292
|
+
}
|
|
1293
|
+
async function readRelayMission(service, input, authenticatedPrincipal) {
|
|
1294
|
+
const resolved = await service.getReadableStorageForNamespace(input.namespace ?? void 0, authenticatedPrincipal);
|
|
1295
|
+
const store = new RelayMissionStore({
|
|
1296
|
+
rootDir: resolved.storage.dir,
|
|
1297
|
+
namespace: resolved.namespace
|
|
1298
|
+
});
|
|
1299
|
+
const options = RelayMissionReadOptionsSchema.parse({
|
|
1300
|
+
...input.since === void 0 ? {} : { since: input.since },
|
|
1301
|
+
...input.until === void 0 ? {} : { until: input.until },
|
|
1302
|
+
...input.limit === void 0 ? {} : { limit: input.limit }
|
|
1303
|
+
});
|
|
1304
|
+
return store.read(input.missionId, options);
|
|
1305
|
+
}
|
|
1306
|
+
var relayMissionAppendOperation = defineOperation({
|
|
1307
|
+
name: "relay_mission_append",
|
|
1308
|
+
description: "Append one evidence-backed event to an isolated Relay mission.",
|
|
1309
|
+
schema: RelayMissionAppendAccessSchema,
|
|
1310
|
+
handler: async (input, ctx) => ({
|
|
1311
|
+
result: await appendRelayMissionEvent(ctx.service, input, ctx.authenticatedPrincipal, ctx.hooks?.enforceWriteQuota)
|
|
1312
|
+
})
|
|
1313
|
+
});
|
|
1314
|
+
var relayMissionReadOperation = defineOperation({
|
|
1315
|
+
name: "relay_mission_read",
|
|
1316
|
+
description: "Read one bounded, browser-ready Relay mission receipt.",
|
|
1317
|
+
schema: RelayMissionReadAccessSchema,
|
|
1318
|
+
handler: async (input, ctx) => ({
|
|
1319
|
+
result: await readRelayMission(ctx.service, input, ctx.authenticatedPrincipal)
|
|
1320
|
+
})
|
|
1321
|
+
});
|
|
1322
|
+
|
|
1323
|
+
// src/access-operations.ts
|
|
1324
|
+
var memoryGetSchema = z3.object({
|
|
1325
|
+
memoryId: z3.string().trim().min(1, "memoryId is required").max(512),
|
|
1326
|
+
// Issue #1582 — when memoryId is a `[m:xxxx]` handle, sessionKey scopes the
|
|
1327
|
+
// resolution to this session's recent recall history.
|
|
1328
|
+
sessionKey: z3.string().trim().min(1).max(512).nullable().optional(),
|
|
1329
|
+
namespace: z3.string().trim().max(256).nullable().optional()
|
|
1330
|
+
});
|
|
1331
|
+
var memoryGetOperation = defineOperation({
|
|
1332
|
+
name: "memory_get",
|
|
1333
|
+
description: "Fetch one memory by id.",
|
|
1334
|
+
schema: memoryGetSchema,
|
|
1335
|
+
handler: async (input, ctx) => {
|
|
1336
|
+
const result = await ctx.service.memoryGet(
|
|
1337
|
+
input.memoryId,
|
|
1338
|
+
input.namespace ?? void 0,
|
|
1339
|
+
ctx.authenticatedPrincipal,
|
|
1340
|
+
input.sessionKey ?? void 0
|
|
1341
|
+
);
|
|
1342
|
+
return { result };
|
|
1343
|
+
}
|
|
1344
|
+
});
|
|
1345
|
+
var memorySearchSchema = z3.object({
|
|
1346
|
+
query: z3.string().trim().min(1, "query is required").max(2048),
|
|
1347
|
+
namespace: z3.string().trim().max(256).nullable().optional(),
|
|
1348
|
+
// No upper cap: the pre-boundary MCP handler forwarded any finite number to
|
|
1349
|
+
// memorySearch, and the QMD/search backends honor large limits. Capping at
|
|
1350
|
+
// 100 would reject existing clients that request larger result sets.
|
|
1351
|
+
maxResults: z3.number().int().min(1).nullable().optional(),
|
|
1352
|
+
collection: z3.string().trim().min(1).max(256).nullable().optional()
|
|
1353
|
+
});
|
|
1354
|
+
var memorySearchOperation = defineOperation({
|
|
1355
|
+
name: "memory_search",
|
|
1356
|
+
description: "Search memories across readable namespaces.",
|
|
1357
|
+
schema: memorySearchSchema,
|
|
1358
|
+
handler: async (input, ctx) => {
|
|
1359
|
+
const result = await ctx.service.memorySearch({
|
|
1360
|
+
query: input.query,
|
|
1361
|
+
namespace: input.namespace ?? void 0,
|
|
1362
|
+
maxResults: input.maxResults ?? void 0,
|
|
1363
|
+
collection: input.collection ?? void 0,
|
|
1364
|
+
principal: ctx.authenticatedPrincipal
|
|
1365
|
+
});
|
|
1366
|
+
return { result };
|
|
1367
|
+
}
|
|
1368
|
+
});
|
|
1369
|
+
var memoryStoreOperation = defineOperation({
|
|
1370
|
+
name: "memory_store",
|
|
1371
|
+
description: "Store an explicit memory through the access layer.",
|
|
1372
|
+
// Reuse the existing schema verbatim — the migration is behavior-preserving;
|
|
1373
|
+
// the schema's external contract is NOT changing in this PR (per the issue's
|
|
1374
|
+
// pitfall note).
|
|
1375
|
+
schema: memoryStoreRequestSchema,
|
|
1376
|
+
handler: async (input, ctx) => {
|
|
1377
|
+
const result = await ctx.service.memoryStore(
|
|
1378
|
+
{
|
|
1379
|
+
...input,
|
|
1380
|
+
authenticatedPrincipal: ctx.authenticatedPrincipal,
|
|
1381
|
+
...ctx.sourceConnector ? { sourceConnector: ctx.sourceConnector } : {}
|
|
1382
|
+
},
|
|
1383
|
+
// Forward transport-level hooks (e.g. HTTP's atomic write-quota gate)
|
|
1384
|
+
// so the hook still fires inside the service's idempotent-write lock —
|
|
1385
|
+
// never before, never on a replay (#1434 invariant preserved by the
|
|
1386
|
+
// boundary migration).
|
|
1387
|
+
ctx.hooks
|
|
1388
|
+
);
|
|
1389
|
+
return { result };
|
|
1390
|
+
}
|
|
1391
|
+
});
|
|
1392
|
+
var codingDecisionSchema = z3.preprocess(
|
|
1393
|
+
(data) => {
|
|
1394
|
+
if (data && typeof data === "object" && !Array.isArray(data)) {
|
|
1395
|
+
const out = {};
|
|
1396
|
+
for (const [k, v] of Object.entries(data)) {
|
|
1397
|
+
if (v !== null) out[k] = v;
|
|
1398
|
+
}
|
|
1399
|
+
return out;
|
|
1400
|
+
}
|
|
1401
|
+
return data;
|
|
1402
|
+
},
|
|
1403
|
+
z3.object({
|
|
1404
|
+
subcommand: z3.enum(DECISION_SUBCOMMANDS),
|
|
1405
|
+
sessionKey: z3.string().trim().max(512).optional(),
|
|
1406
|
+
namespace: z3.string().trim().max(256).optional(),
|
|
1407
|
+
id: z3.string().trim().max(512).optional(),
|
|
1408
|
+
title: z3.string().trim().max(512).optional(),
|
|
1409
|
+
status: z3.string().trim().max(64).optional(),
|
|
1410
|
+
context: z3.string().trim().max(8192).optional(),
|
|
1411
|
+
decision: z3.string().trim().max(8192).optional(),
|
|
1412
|
+
consequences: z3.string().trim().max(8192).optional(),
|
|
1413
|
+
entityRefs: z3.array(z3.string().trim().min(1).max(256)).optional(),
|
|
1414
|
+
supersedesId: z3.string().trim().max(512).optional()
|
|
1415
|
+
})
|
|
1416
|
+
);
|
|
1417
|
+
var codingDecisionOperation = defineOperation({
|
|
1418
|
+
name: "coding_decision",
|
|
1419
|
+
description: "List, get, record, or supersede decision records in the session's coding namespace (issue #1548 Track A).",
|
|
1420
|
+
schema: codingDecisionSchema,
|
|
1421
|
+
handler: async (input, ctx) => {
|
|
1422
|
+
const result = await ctx.service.codingDecision(input, ctx.authenticatedPrincipal, ctx.sourceConnector);
|
|
1423
|
+
return { result };
|
|
1424
|
+
}
|
|
1425
|
+
});
|
|
1426
|
+
var codingArchitectureSchema = z3.preprocess(
|
|
1427
|
+
(data) => {
|
|
1428
|
+
if (data !== null && typeof data === "object" && !Array.isArray(data)) {
|
|
1429
|
+
const obj = data;
|
|
1430
|
+
const cleaned = {};
|
|
1431
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
1432
|
+
if (value !== null) cleaned[key] = value;
|
|
1433
|
+
}
|
|
1434
|
+
return cleaned;
|
|
1435
|
+
}
|
|
1436
|
+
return data;
|
|
1437
|
+
},
|
|
1438
|
+
z3.object({
|
|
1439
|
+
subcommand: z3.enum(["get", "refresh"]),
|
|
1440
|
+
sessionKey: z3.string().optional(),
|
|
1441
|
+
namespace: z3.string().optional()
|
|
1442
|
+
})
|
|
1443
|
+
);
|
|
1444
|
+
var codingArchitectureOperation = defineOperation({
|
|
1445
|
+
name: "coding_architecture",
|
|
1446
|
+
description: "Get or refresh the architecture card for the session's coding namespace (issue #1548 Track A PR 3).",
|
|
1447
|
+
schema: codingArchitectureSchema,
|
|
1448
|
+
handler: async (input, ctx) => {
|
|
1449
|
+
const result = await ctx.service.codingArchitecture(input, ctx.authenticatedPrincipal, ctx.sourceConnector);
|
|
1450
|
+
return { result };
|
|
1451
|
+
}
|
|
1452
|
+
});
|
|
1453
|
+
var codegraphSurfaceSchema = z3.preprocess(
|
|
1454
|
+
(data) => {
|
|
1455
|
+
if (data !== null && typeof data === "object" && !Array.isArray(data)) {
|
|
1456
|
+
const obj = data;
|
|
1457
|
+
const cleaned = {};
|
|
1458
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
1459
|
+
if (value !== null) cleaned[key] = value;
|
|
1460
|
+
}
|
|
1461
|
+
return cleaned;
|
|
1462
|
+
}
|
|
1463
|
+
return data;
|
|
1464
|
+
},
|
|
1465
|
+
z3.object({
|
|
1466
|
+
tool: z3.string().refine(isCodegraphToolName, {
|
|
1467
|
+
message: "tool must be one of the codegraph tool names"
|
|
1468
|
+
}),
|
|
1469
|
+
sessionKey: z3.string().max(512).optional(),
|
|
1470
|
+
principal: z3.string().max(256).optional(),
|
|
1471
|
+
project: z3.string().max(256).optional(),
|
|
1472
|
+
query: z3.string().max(2048).optional(),
|
|
1473
|
+
limit: z3.number().int().positive().max(200).optional(),
|
|
1474
|
+
start: z3.string().max(512).optional(),
|
|
1475
|
+
direction: z3.string().max(64).optional(),
|
|
1476
|
+
depth: z3.number().int().positive().max(10).optional(),
|
|
1477
|
+
qualifiedName: z3.string().max(1024).optional(),
|
|
1478
|
+
path: z3.string().max(2048).optional(),
|
|
1479
|
+
structuredQuery: z3.record(z3.string(), z3.unknown()).optional(),
|
|
1480
|
+
head: z3.string().max(256).optional(),
|
|
1481
|
+
repoRoot: z3.string().max(2048).optional(),
|
|
1482
|
+
mode: z3.string().max(64).optional(),
|
|
1483
|
+
confirm: z3.boolean().optional(),
|
|
1484
|
+
subcommand: z3.string().max(64).optional(),
|
|
1485
|
+
id: z3.string().max(512).optional(),
|
|
1486
|
+
title: z3.string().max(512).optional(),
|
|
1487
|
+
status: z3.string().max(64).optional(),
|
|
1488
|
+
context: z3.string().max(8192).optional(),
|
|
1489
|
+
decision: z3.string().max(8192).optional(),
|
|
1490
|
+
consequences: z3.string().max(8192).optional(),
|
|
1491
|
+
entityRefs: z3.array(z3.string().max(256)).optional(),
|
|
1492
|
+
supersedesId: z3.string().max(512).optional(),
|
|
1493
|
+
traces: z3.array(z3.unknown()).optional()
|
|
1494
|
+
})
|
|
1495
|
+
);
|
|
1496
|
+
var codingDeltaSchema = z3.preprocess(
|
|
1497
|
+
(data) => {
|
|
1498
|
+
if (data !== null && typeof data === "object" && !Array.isArray(data)) {
|
|
1499
|
+
const obj = data;
|
|
1500
|
+
const cleaned = {};
|
|
1501
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
1502
|
+
if (value !== null) cleaned[key] = value;
|
|
1503
|
+
}
|
|
1504
|
+
return cleaned;
|
|
1505
|
+
}
|
|
1506
|
+
return data;
|
|
1507
|
+
},
|
|
1508
|
+
z3.object({
|
|
1509
|
+
subcommand: z3.enum(DELTA_SUBCOMMANDS),
|
|
1510
|
+
sessionKey: z3.string().trim().max(512).optional(),
|
|
1511
|
+
namespace: z3.string().trim().max(256).optional()
|
|
1512
|
+
})
|
|
1513
|
+
);
|
|
1514
|
+
var codingDeltaOperation = defineOperation({
|
|
1515
|
+
name: "coding_delta",
|
|
1516
|
+
description: "Get the session delta (commits + touched files since last seen) for the session's coding namespace (issue #1548 Track A PR 4).",
|
|
1517
|
+
schema: codingDeltaSchema,
|
|
1518
|
+
handler: async (input, ctx) => {
|
|
1519
|
+
const result = await ctx.service.codingDelta(input, ctx.authenticatedPrincipal);
|
|
1520
|
+
return { result };
|
|
1521
|
+
}
|
|
1522
|
+
});
|
|
1523
|
+
var memoryCorrectPlanSchema = z3.preprocess(
|
|
1524
|
+
(data) => {
|
|
1525
|
+
if (data && typeof data === "object" && !Array.isArray(data)) {
|
|
1526
|
+
const out = {};
|
|
1527
|
+
for (const [k, v] of Object.entries(data)) {
|
|
1528
|
+
if (v !== null) out[k] = v;
|
|
1529
|
+
}
|
|
1530
|
+
return out;
|
|
1531
|
+
}
|
|
1532
|
+
return data;
|
|
1533
|
+
},
|
|
1534
|
+
z3.object({
|
|
1535
|
+
text: z3.string().trim().min(1).max(1e4),
|
|
1536
|
+
targetIds: z3.array(z3.string().trim().min(1).max(512)).optional(),
|
|
1537
|
+
sessionKey: z3.string().trim().max(512).optional(),
|
|
1538
|
+
namespace: z3.string().trim().max(256).optional()
|
|
1539
|
+
})
|
|
1540
|
+
);
|
|
1541
|
+
var memoryCorrectPlanOperation = defineOperation({
|
|
1542
|
+
name: "memory_correct_plan",
|
|
1543
|
+
description: "Plan a memory correction from a plain-language statement (issue #1580). Returns a CorrectionPlan with a diff preview; apply via memory_correct_apply.",
|
|
1544
|
+
schema: memoryCorrectPlanSchema,
|
|
1545
|
+
handler: async (input, ctx) => {
|
|
1546
|
+
try {
|
|
1547
|
+
const result = await ctx.service.correctionPlan({
|
|
1548
|
+
text: input.text,
|
|
1549
|
+
...input.targetIds ? { targetIds: input.targetIds } : {},
|
|
1550
|
+
...input.sessionKey ? { sessionKey: input.sessionKey } : {},
|
|
1551
|
+
...input.namespace ? { namespace: input.namespace } : {},
|
|
1552
|
+
...ctx.authenticatedPrincipal ? { principal: ctx.authenticatedPrincipal } : {}
|
|
1553
|
+
});
|
|
1554
|
+
return { result };
|
|
1555
|
+
} catch (err) {
|
|
1556
|
+
if (err instanceof CorrectionContractError) throw new EngramAccessInputError(err.message);
|
|
1557
|
+
throw err;
|
|
1558
|
+
}
|
|
1559
|
+
}
|
|
1560
|
+
});
|
|
1561
|
+
var memoryCorrectApplySchema = z3.preprocess(
|
|
1562
|
+
(data) => {
|
|
1563
|
+
if (data && typeof data === "object" && !Array.isArray(data)) {
|
|
1564
|
+
const out = {};
|
|
1565
|
+
for (const [k, v] of Object.entries(data)) {
|
|
1566
|
+
if (v !== null) out[k] = v;
|
|
1567
|
+
}
|
|
1568
|
+
return out;
|
|
1569
|
+
}
|
|
1570
|
+
return data;
|
|
1571
|
+
},
|
|
1572
|
+
z3.object({
|
|
1573
|
+
planId: z3.string().trim().min(1).max(512),
|
|
1574
|
+
confirm: z3.boolean().optional(),
|
|
1575
|
+
sessionKey: z3.string().trim().max(512).optional(),
|
|
1576
|
+
namespace: z3.string().trim().max(256).optional()
|
|
1577
|
+
})
|
|
1578
|
+
);
|
|
1579
|
+
var memoryCorrectApplyOperation = defineOperation({
|
|
1580
|
+
name: "memory_correct_apply",
|
|
1581
|
+
description: "Apply a planned memory correction by planId (issue #1580). Requires confirm: true when correction.applyRequiresConfirm is on (default).",
|
|
1582
|
+
schema: memoryCorrectApplySchema,
|
|
1583
|
+
handler: async (input, ctx) => {
|
|
1584
|
+
try {
|
|
1585
|
+
const result = await ctx.service.correctionApply(input.planId, {
|
|
1586
|
+
confirm: input.confirm === true,
|
|
1587
|
+
...input.sessionKey ? { sessionKey: input.sessionKey } : {},
|
|
1588
|
+
...input.namespace ? { namespace: input.namespace } : {},
|
|
1589
|
+
...ctx.authenticatedPrincipal ? { principal: ctx.authenticatedPrincipal } : {}
|
|
1590
|
+
});
|
|
1591
|
+
return { result };
|
|
1592
|
+
} catch (err) {
|
|
1593
|
+
if (err instanceof CorrectionContractError) throw new EngramAccessInputError(err.message);
|
|
1594
|
+
throw err;
|
|
1595
|
+
}
|
|
1596
|
+
}
|
|
1597
|
+
});
|
|
1598
|
+
var codegraphIndexOperation = defineOperation({
|
|
1599
|
+
name: "codegraph_index",
|
|
1600
|
+
description: "Codegraph parity tool (issue #1554): index. Delegates to the shared codegraph surface handler.",
|
|
1601
|
+
schema: codegraphSurfaceSchema,
|
|
1602
|
+
handler: async (input, ctx) => {
|
|
1603
|
+
const result = await ctx.service.codegraphTool(input, ctx.authenticatedPrincipal, ctx.sourceConnector);
|
|
1604
|
+
return { result };
|
|
1605
|
+
}
|
|
1606
|
+
});
|
|
1607
|
+
var codegraphListProjectsOperation = defineOperation({
|
|
1608
|
+
name: "codegraph_list_projects",
|
|
1609
|
+
description: "Codegraph parity tool (issue #1554): list_projects. Delegates to the shared codegraph surface handler.",
|
|
1610
|
+
schema: codegraphSurfaceSchema,
|
|
1611
|
+
handler: async (input, ctx) => {
|
|
1612
|
+
const result = await ctx.service.codegraphTool(input, ctx.authenticatedPrincipal, ctx.sourceConnector);
|
|
1613
|
+
return { result };
|
|
1614
|
+
}
|
|
1615
|
+
});
|
|
1616
|
+
var codegraphDeleteProjectOperation = defineOperation({
|
|
1617
|
+
name: "codegraph_delete_project",
|
|
1618
|
+
description: "Codegraph parity tool (issue #1554): delete_project. Delegates to the shared codegraph surface handler.",
|
|
1619
|
+
schema: codegraphSurfaceSchema,
|
|
1620
|
+
handler: async (input, ctx) => {
|
|
1621
|
+
const result = await ctx.service.codegraphTool(input, ctx.authenticatedPrincipal, ctx.sourceConnector);
|
|
1622
|
+
return { result };
|
|
1623
|
+
}
|
|
1624
|
+
});
|
|
1625
|
+
var codegraphIndexStatusOperation = defineOperation({
|
|
1626
|
+
name: "codegraph_index_status",
|
|
1627
|
+
description: "Codegraph parity tool (issue #1554): index_status. Delegates to the shared codegraph surface handler.",
|
|
1628
|
+
schema: codegraphSurfaceSchema,
|
|
1629
|
+
handler: async (input, ctx) => {
|
|
1630
|
+
const result = await ctx.service.codegraphTool(input, ctx.authenticatedPrincipal, ctx.sourceConnector);
|
|
1631
|
+
return { result };
|
|
1632
|
+
}
|
|
1633
|
+
});
|
|
1634
|
+
var codegraphSearchGraphOperation = defineOperation({
|
|
1635
|
+
name: "codegraph_search_graph",
|
|
1636
|
+
description: "Codegraph parity tool (issue #1554): search_graph. Delegates to the shared codegraph surface handler.",
|
|
1637
|
+
schema: codegraphSurfaceSchema,
|
|
1638
|
+
handler: async (input, ctx) => {
|
|
1639
|
+
const result = await ctx.service.codegraphTool(input, ctx.authenticatedPrincipal, ctx.sourceConnector);
|
|
1640
|
+
return { result };
|
|
1641
|
+
}
|
|
1642
|
+
});
|
|
1643
|
+
var codegraphTracePathOperation = defineOperation({
|
|
1644
|
+
name: "codegraph_trace_path",
|
|
1645
|
+
description: "Codegraph parity tool (issue #1554): trace_path. Delegates to the shared codegraph surface handler.",
|
|
1646
|
+
schema: codegraphSurfaceSchema,
|
|
1647
|
+
handler: async (input, ctx) => {
|
|
1648
|
+
const result = await ctx.service.codegraphTool(input, ctx.authenticatedPrincipal, ctx.sourceConnector);
|
|
1649
|
+
return { result };
|
|
1650
|
+
}
|
|
1651
|
+
});
|
|
1652
|
+
var codegraphDetectChangesOperation = defineOperation({
|
|
1653
|
+
name: "codegraph_detect_changes",
|
|
1654
|
+
description: "Codegraph parity tool (issue #1554): detect_changes. Delegates to the shared codegraph surface handler.",
|
|
1655
|
+
schema: codegraphSurfaceSchema,
|
|
1656
|
+
handler: async (input, ctx) => {
|
|
1657
|
+
const result = await ctx.service.codegraphTool(input, ctx.authenticatedPrincipal, ctx.sourceConnector);
|
|
1658
|
+
return { result };
|
|
1659
|
+
}
|
|
1660
|
+
});
|
|
1661
|
+
var codegraphQueryGraphOperation = defineOperation({
|
|
1662
|
+
name: "codegraph_query_graph",
|
|
1663
|
+
description: "Codegraph parity tool (issue #1554): query_graph. Delegates to the shared codegraph surface handler.",
|
|
1664
|
+
schema: codegraphSurfaceSchema,
|
|
1665
|
+
handler: async (input, ctx) => {
|
|
1666
|
+
const result = await ctx.service.codegraphTool(input, ctx.authenticatedPrincipal, ctx.sourceConnector);
|
|
1667
|
+
return { result };
|
|
1668
|
+
}
|
|
1669
|
+
});
|
|
1670
|
+
var codegraphGetSchemaOperation = defineOperation({
|
|
1671
|
+
name: "codegraph_get_schema",
|
|
1672
|
+
description: "Codegraph parity tool (issue #1554): get_schema. Delegates to the shared codegraph surface handler.",
|
|
1673
|
+
schema: codegraphSurfaceSchema,
|
|
1674
|
+
handler: async (input, ctx) => {
|
|
1675
|
+
const result = await ctx.service.codegraphTool(input, ctx.authenticatedPrincipal, ctx.sourceConnector);
|
|
1676
|
+
return { result };
|
|
1677
|
+
}
|
|
1678
|
+
});
|
|
1679
|
+
var codegraphGetSnippetOperation = defineOperation({
|
|
1680
|
+
name: "codegraph_get_snippet",
|
|
1681
|
+
description: "Codegraph parity tool (issue #1554): get_snippet. Delegates to the shared codegraph surface handler.",
|
|
1682
|
+
schema: codegraphSurfaceSchema,
|
|
1683
|
+
handler: async (input, ctx) => {
|
|
1684
|
+
const result = await ctx.service.codegraphTool(input, ctx.authenticatedPrincipal, ctx.sourceConnector);
|
|
1685
|
+
return { result };
|
|
1686
|
+
}
|
|
1687
|
+
});
|
|
1688
|
+
var codegraphGetArchitectureOperation = defineOperation({
|
|
1689
|
+
name: "codegraph_get_architecture",
|
|
1690
|
+
description: "Codegraph parity tool (issue #1554): get_architecture. Delegates to the shared codegraph surface handler.",
|
|
1691
|
+
schema: codegraphSurfaceSchema,
|
|
1692
|
+
handler: async (input, ctx) => {
|
|
1693
|
+
const result = await ctx.service.codegraphTool(input, ctx.authenticatedPrincipal, ctx.sourceConnector);
|
|
1694
|
+
return { result };
|
|
1695
|
+
}
|
|
1696
|
+
});
|
|
1697
|
+
var codegraphSearchCodeOperation = defineOperation({
|
|
1698
|
+
name: "codegraph_search_code",
|
|
1699
|
+
description: "Codegraph parity tool (issue #1554): search_code. Delegates to the shared codegraph surface handler.",
|
|
1700
|
+
schema: codegraphSurfaceSchema,
|
|
1701
|
+
handler: async (input, ctx) => {
|
|
1702
|
+
const result = await ctx.service.codegraphTool(input, ctx.authenticatedPrincipal, ctx.sourceConnector);
|
|
1703
|
+
return { result };
|
|
1704
|
+
}
|
|
1705
|
+
});
|
|
1706
|
+
var codegraphManageAdrOperation = defineOperation({
|
|
1707
|
+
name: "codegraph_manage_adr",
|
|
1708
|
+
description: "Codegraph parity tool (issue #1554): manage_adr. Delegates to the shared codegraph surface handler.",
|
|
1709
|
+
schema: codegraphSurfaceSchema,
|
|
1710
|
+
handler: async (input, ctx) => {
|
|
1711
|
+
const result = await ctx.service.codegraphTool(input, ctx.authenticatedPrincipal, ctx.sourceConnector);
|
|
1712
|
+
return { result };
|
|
1713
|
+
}
|
|
1714
|
+
});
|
|
1715
|
+
var codegraphIngestTracesOperation = defineOperation({
|
|
1716
|
+
name: "codegraph_ingest_traces",
|
|
1717
|
+
description: "Codegraph parity tool (issue #1554): ingest_traces. Delegates to the shared codegraph surface handler.",
|
|
1718
|
+
schema: codegraphSurfaceSchema,
|
|
1719
|
+
handler: async (input, ctx) => {
|
|
1720
|
+
const result = await ctx.service.codegraphTool(input, ctx.authenticatedPrincipal, ctx.sourceConnector);
|
|
1721
|
+
return { result };
|
|
1722
|
+
}
|
|
1723
|
+
});
|
|
1724
|
+
var REGISTERED_OPERATIONS = [
|
|
1725
|
+
memoryGetOperation.spec.name,
|
|
1726
|
+
memorySearchOperation.spec.name,
|
|
1727
|
+
memoryStoreOperation.spec.name,
|
|
1728
|
+
codingDecisionOperation.spec.name,
|
|
1729
|
+
codingArchitectureOperation.spec.name,
|
|
1730
|
+
codegraphIndexOperation.spec.name,
|
|
1731
|
+
codegraphListProjectsOperation.spec.name,
|
|
1732
|
+
codegraphDeleteProjectOperation.spec.name,
|
|
1733
|
+
codegraphIndexStatusOperation.spec.name,
|
|
1734
|
+
codegraphSearchGraphOperation.spec.name,
|
|
1735
|
+
codegraphTracePathOperation.spec.name,
|
|
1736
|
+
codegraphDetectChangesOperation.spec.name,
|
|
1737
|
+
codegraphQueryGraphOperation.spec.name,
|
|
1738
|
+
codegraphGetSchemaOperation.spec.name,
|
|
1739
|
+
codegraphGetSnippetOperation.spec.name,
|
|
1740
|
+
codegraphGetArchitectureOperation.spec.name,
|
|
1741
|
+
codegraphSearchCodeOperation.spec.name,
|
|
1742
|
+
codegraphManageAdrOperation.spec.name,
|
|
1743
|
+
codegraphIngestTracesOperation.spec.name,
|
|
1744
|
+
codingDeltaOperation.spec.name,
|
|
1745
|
+
memoryCorrectPlanOperation.spec.name,
|
|
1746
|
+
memoryCorrectApplyOperation.spec.name
|
|
1747
|
+
];
|
|
1748
|
+
|
|
1749
|
+
export {
|
|
1750
|
+
RELAY_MISSION_SCHEMA_VERSION,
|
|
1751
|
+
RELAY_MISSION_MAX_FILE_BYTES,
|
|
1752
|
+
RELAY_MISSION_MAX_LINE_BYTES,
|
|
1753
|
+
RELAY_MISSION_MAX_EVENTS,
|
|
1754
|
+
RELAY_MISSION_DEFAULT_EVENT_LIMIT,
|
|
1755
|
+
RELAY_MISSION_MAX_EVENT_LIMIT,
|
|
1756
|
+
RelayEvidenceRefSchema,
|
|
1757
|
+
RelayMissionPayloadSchema,
|
|
1758
|
+
RelayMissionEventInputSchema,
|
|
1759
|
+
RelayMissionEventSchema,
|
|
1760
|
+
RelayMissionReadOptionsSchema,
|
|
1761
|
+
RelayMissionStoreError,
|
|
1762
|
+
RelayMissionStore,
|
|
1763
|
+
reduceRelayMission,
|
|
1764
|
+
compareRelayEvents,
|
|
1765
|
+
relayMissionReceiptDigest,
|
|
1766
|
+
appendRelayMissionEvent,
|
|
1767
|
+
readRelayMission,
|
|
1768
|
+
relayMissionAppendOperation,
|
|
1769
|
+
relayMissionReadOperation,
|
|
1770
|
+
memoryGetOperation,
|
|
1771
|
+
memorySearchOperation,
|
|
1772
|
+
memoryStoreOperation,
|
|
1773
|
+
codingDecisionOperation,
|
|
1774
|
+
codingArchitectureOperation,
|
|
1775
|
+
codingDeltaOperation,
|
|
1776
|
+
memoryCorrectPlanOperation,
|
|
1777
|
+
memoryCorrectApplyOperation,
|
|
1778
|
+
codegraphIndexOperation,
|
|
1779
|
+
codegraphListProjectsOperation,
|
|
1780
|
+
codegraphDeleteProjectOperation,
|
|
1781
|
+
codegraphIndexStatusOperation,
|
|
1782
|
+
codegraphSearchGraphOperation,
|
|
1783
|
+
codegraphTracePathOperation,
|
|
1784
|
+
codegraphDetectChangesOperation,
|
|
1785
|
+
codegraphQueryGraphOperation,
|
|
1786
|
+
codegraphGetSchemaOperation,
|
|
1787
|
+
codegraphGetSnippetOperation,
|
|
1788
|
+
codegraphGetArchitectureOperation,
|
|
1789
|
+
codegraphSearchCodeOperation,
|
|
1790
|
+
codegraphManageAdrOperation,
|
|
1791
|
+
codegraphIngestTracesOperation,
|
|
1792
|
+
REGISTERED_OPERATIONS
|
|
1793
|
+
};
|
|
1794
|
+
//# sourceMappingURL=chunk-7XRUYC6G.js.map
|