@akagilnc/pi-workflow-roles 0.1.4021 → 0.1.4035
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/acp-host/production-host.js +208 -107
- package/dist/headless-host/production-host.js +208 -107
- package/dist/navigator-attendance.js +2 -0
- package/dist/navigator-public-session.js +18 -34
- package/dist/navigator-session-contracts.js +19 -0
- package/dist/pi/known-failure.js +3 -4
- package/dist/public-cli/auto-resume.js +20 -7
- package/dist/public-cli/diarist-run.js +9 -23
- package/dist/public-cli/instruction-seat-run.js +3 -1
- package/dist/public-cli/judge-run.js +3 -1
- package/dist/public-cli/main.js +203 -112
- package/dist/public-cli/settlement.js +64 -61
- package/dist/public-cli/terminal.js +1 -11
- package/dist/submission-ledger.js +109 -11
- package/package.json +1 -1
- package/src/host-contracts.ts +8 -4
- package/src/navigator-attendance.ts +2 -0
- package/src/navigator-public-session.ts +19 -55
- package/src/navigator-session-contracts.ts +39 -0
- package/src/pi/known-failure.ts +3 -4
- package/src/public-cli/auto-resume.ts +57 -20
- package/src/public-cli/cli.ts +2 -2
- package/src/public-cli/collector-run.ts +3 -1
- package/src/public-cli/countersign-run.ts +34 -27
- package/src/public-cli/diarist-run.ts +10 -27
- package/src/public-cli/instruction-seat-run.ts +3 -1
- package/src/public-cli/judge-run.ts +3 -1
- package/src/public-cli/reviewer-run.ts +3 -1
- package/src/public-cli/settlement.ts +83 -84
- package/src/public-cli/terminal.ts +7 -16
- package/src/submission-ledger.ts +147 -13
package/src/submission-ledger.ts
CHANGED
|
@@ -24,6 +24,8 @@ export type SubmissionLedgerEvent =
|
|
|
24
24
|
readonly toolCallId: string;
|
|
25
25
|
readonly toolName: string;
|
|
26
26
|
readonly sequence: number;
|
|
27
|
+
/** Seat identity — machine fact beside the payload (ADR 0042 / #881). */
|
|
28
|
+
readonly role?: TerminalRoleName;
|
|
27
29
|
/** LLM tool-call params at call time (#836 原话). */
|
|
28
30
|
readonly params?: unknown;
|
|
29
31
|
}
|
|
@@ -79,9 +81,19 @@ function attemptIdentity(context: HostContext, runId: string): string {
|
|
|
79
81
|
|
|
80
82
|
/** One recorded role submission as stored — original payload plus host identity. */
|
|
81
83
|
export type RecordedSubmissionRow = {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
+
/**
|
|
85
|
+
* Seat identity when known. Historical correctable/infrastructure rows may omit it;
|
|
86
|
+
* payloads still project (#881). Terminal acceptance kind still requires a role match.
|
|
87
|
+
*/
|
|
88
|
+
readonly role?: TerminalRoleName;
|
|
89
|
+
/**
|
|
90
|
+
* Recording class on the ledger. Terminal acceptance kind still only follows
|
|
91
|
+
* `accepted` / `audit-escalation`; every class carries the original payload (#881).
|
|
92
|
+
*/
|
|
93
|
+
readonly kind: "accepted" | "audit-escalation" | "correctable-rejection" | "infrastructure" | "candidate";
|
|
84
94
|
readonly accepted: unknown;
|
|
95
|
+
/** Present when the ledger row names the tool call — used to dedupe candidate+outcome. */
|
|
96
|
+
readonly toolCallId?: string;
|
|
85
97
|
};
|
|
86
98
|
|
|
87
99
|
/** Closed-submission callback: original payload, no status/facts projection (#836). */
|
|
@@ -191,8 +203,59 @@ function recordedRole(payload: { role?: unknown; projection?: { role?: unknown }
|
|
|
191
203
|
return undefined;
|
|
192
204
|
}
|
|
193
205
|
|
|
206
|
+
/** Prefer a more complete row for the same tool call without inventing a sole winner across calls. */
|
|
207
|
+
function rowRank(kind: RecordedSubmissionRow["kind"]): number {
|
|
208
|
+
switch (kind) {
|
|
209
|
+
case "accepted":
|
|
210
|
+
return 4;
|
|
211
|
+
case "audit-escalation":
|
|
212
|
+
return 3;
|
|
213
|
+
case "correctable-rejection":
|
|
214
|
+
case "infrastructure":
|
|
215
|
+
return 2;
|
|
216
|
+
case "candidate":
|
|
217
|
+
return 1;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
194
221
|
/**
|
|
195
|
-
*
|
|
222
|
+
* Same-call identity for reader pairing only (#881 / #836).
|
|
223
|
+
* attemptId is already on the record (subject/payload); bare toolCallId alone
|
|
224
|
+
* collapses distinct court attempts that reused a host call id.
|
|
225
|
+
*/
|
|
226
|
+
function submissionCallKey(attemptId: string | undefined, toolCallId: string): string {
|
|
227
|
+
return `${attemptId ?? ""}\0${toolCallId}`;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function rowFromPayload(
|
|
231
|
+
kind: RecordedSubmissionRow["kind"],
|
|
232
|
+
payload: {
|
|
233
|
+
role?: unknown;
|
|
234
|
+
projection?: { role?: unknown };
|
|
235
|
+
accepted?: unknown;
|
|
236
|
+
params?: unknown;
|
|
237
|
+
toolCallId?: unknown;
|
|
238
|
+
},
|
|
239
|
+
accepted: unknown,
|
|
240
|
+
roleFallback?: TerminalRoleName,
|
|
241
|
+
): RecordedSubmissionRow {
|
|
242
|
+
const role = recordedRole(payload) ?? roleFallback;
|
|
243
|
+
return {
|
|
244
|
+
...(role === undefined ? {} : { role }),
|
|
245
|
+
kind,
|
|
246
|
+
accepted,
|
|
247
|
+
...(typeof payload.toolCallId === "string" && payload.toolCallId.length > 0
|
|
248
|
+
? { toolCallId: payload.toolCallId }
|
|
249
|
+
: {}),
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* All recorded role submissions in ledger order (#836 multi-submit / #881).
|
|
255
|
+
* Projects every original payload — sealed, audit-escalation, correctable-rejection,
|
|
256
|
+
* infrastructure, and bare candidate — without outcome-class filtering.
|
|
257
|
+
* Same call (candidate + outcome both carrying params) appears once — keyed by
|
|
258
|
+
* recorded attemptId + toolCallId so distinct court attempts stay distinct (#881).
|
|
196
259
|
* `accepted` is the original payload; never rebuilt from a status/facts envelope.
|
|
197
260
|
*/
|
|
198
261
|
export async function readRecordedSubmissionRows(
|
|
@@ -204,27 +267,95 @@ export async function readRecordedSubmissionRows(
|
|
|
204
267
|
const { owned } = await readOwnedSubmissionRecords(cwd, runId, scope.home);
|
|
205
268
|
const scoped = recordsForAttempt(owned, scope.attemptId);
|
|
206
269
|
const out: RecordedSubmissionRow[] = [];
|
|
270
|
+
const indexByCall = new Map<string, number>();
|
|
271
|
+
// Recover seat identity for historical non-sealed rows that omitted role (#881).
|
|
272
|
+
const roleByCall = new Map<string, TerminalRoleName>();
|
|
273
|
+
for (const record of scoped) {
|
|
274
|
+
const payload = record.payload as {
|
|
275
|
+
toolCallId?: unknown;
|
|
276
|
+
role?: unknown;
|
|
277
|
+
projection?: { role?: unknown };
|
|
278
|
+
} | undefined;
|
|
279
|
+
if (typeof payload?.toolCallId !== "string" || payload.toolCallId.length === 0) continue;
|
|
280
|
+
const role = recordedRole(payload);
|
|
281
|
+
if (role !== undefined) {
|
|
282
|
+
roleByCall.set(submissionCallKey(recordAttemptId(record), payload.toolCallId), role);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
const take = (row: RecordedSubmissionRow, callKey: string | undefined): void => {
|
|
287
|
+
const toolCallId = row.toolCallId;
|
|
288
|
+
if (toolCallId !== undefined && callKey !== undefined) {
|
|
289
|
+
const existingIndex = indexByCall.get(callKey);
|
|
290
|
+
if (existingIndex !== undefined) {
|
|
291
|
+
const existing = out[existingIndex]!;
|
|
292
|
+
if (rowRank(row.kind) >= rowRank(existing.kind)) {
|
|
293
|
+
out[existingIndex] = {
|
|
294
|
+
...row,
|
|
295
|
+
toolCallId,
|
|
296
|
+
// Keep a previously recovered role when the upgraded row still omits it.
|
|
297
|
+
...(row.role === undefined && existing.role !== undefined ? { role: existing.role } : {}),
|
|
298
|
+
};
|
|
299
|
+
} else if (existing.role === undefined && row.role !== undefined) {
|
|
300
|
+
out[existingIndex] = { ...existing, role: row.role };
|
|
301
|
+
}
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
indexByCall.set(callKey, out.length);
|
|
305
|
+
}
|
|
306
|
+
out.push(row);
|
|
307
|
+
};
|
|
308
|
+
|
|
207
309
|
for (const record of scoped) {
|
|
310
|
+
const attemptId = recordAttemptId(record);
|
|
311
|
+
if (record.kind === "candidate") {
|
|
312
|
+
const payload = record.payload as Partial<Extract<SubmissionLedgerEvent, { type: "candidate" }>> & {
|
|
313
|
+
projection?: { role?: unknown };
|
|
314
|
+
} | undefined;
|
|
315
|
+
if (payload?.type !== "candidate" || payload.params === undefined) continue;
|
|
316
|
+
const callKey =
|
|
317
|
+
typeof payload.toolCallId === "string"
|
|
318
|
+
? submissionCallKey(attemptId, payload.toolCallId)
|
|
319
|
+
: undefined;
|
|
320
|
+
const fallback = callKey !== undefined ? roleByCall.get(callKey) : undefined;
|
|
321
|
+
take(rowFromPayload("candidate", payload, payload.params, fallback), callKey);
|
|
322
|
+
continue;
|
|
323
|
+
}
|
|
208
324
|
if (record.kind === "sealed") {
|
|
209
325
|
const payload = record.payload as Partial<Extract<SubmissionLedgerEvent, { type: "sealed" }>> & {
|
|
210
326
|
projection?: { role?: unknown };
|
|
211
327
|
} | undefined;
|
|
212
328
|
if (payload?.type !== "sealed" || payload.accepted === undefined) continue;
|
|
213
|
-
const
|
|
214
|
-
|
|
215
|
-
|
|
329
|
+
const callKey =
|
|
330
|
+
typeof payload.toolCallId === "string"
|
|
331
|
+
? submissionCallKey(attemptId, payload.toolCallId)
|
|
332
|
+
: undefined;
|
|
333
|
+
const fallback = callKey !== undefined ? roleByCall.get(callKey) : undefined;
|
|
334
|
+
take(rowFromPayload("accepted", payload, payload.accepted, fallback), callKey);
|
|
216
335
|
continue;
|
|
217
336
|
}
|
|
218
337
|
if (record.kind !== "outcome") continue;
|
|
219
338
|
const payload = record.payload as Partial<Extract<SubmissionLedgerEvent, { type: "outcome" }>> & {
|
|
220
339
|
projection?: { role?: unknown };
|
|
221
340
|
} | undefined;
|
|
222
|
-
if (payload?.type !== "outcome" || payload.
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
341
|
+
if (payload?.type !== "outcome" || payload.accepted === undefined) continue;
|
|
342
|
+
const outcome = payload.outcome;
|
|
343
|
+
const kind: RecordedSubmissionRow["kind"] |
|
|
344
|
+
undefined =
|
|
345
|
+
outcome === "audit-escalation"
|
|
346
|
+
? "audit-escalation"
|
|
347
|
+
: outcome === "correctable-rejection"
|
|
348
|
+
? "correctable-rejection"
|
|
349
|
+
: outcome === "infrastructure"
|
|
350
|
+
? "infrastructure"
|
|
351
|
+
: undefined;
|
|
352
|
+
if (kind === undefined) continue;
|
|
353
|
+
const callKey =
|
|
354
|
+
typeof payload.toolCallId === "string"
|
|
355
|
+
? submissionCallKey(attemptId, payload.toolCallId)
|
|
356
|
+
: undefined;
|
|
357
|
+
const fallback = callKey !== undefined ? roleByCall.get(callKey) : undefined;
|
|
358
|
+
take(rowFromPayload(kind, payload, payload.accepted, fallback), callKey);
|
|
228
359
|
}
|
|
229
360
|
return out;
|
|
230
361
|
}
|
|
@@ -241,7 +372,7 @@ export async function readRecordedSubmissions(
|
|
|
241
372
|
return (await readRecordedSubmissionRows(cwd, runId, homeOrScope)).map((row) => row.accepted);
|
|
242
373
|
}
|
|
243
374
|
|
|
244
|
-
/** True when the run has at least one recorded
|
|
375
|
+
/** True when the run has at least one recorded original payload (any outcome class). */
|
|
245
376
|
export async function hasRecordedSubmission(
|
|
246
377
|
cwd: string,
|
|
247
378
|
runId: string,
|
|
@@ -364,6 +495,7 @@ export function createSubmissionLedgerHost(
|
|
|
364
495
|
toolCallId,
|
|
365
496
|
toolName: tool.name,
|
|
366
497
|
sequence: ++state.sequence,
|
|
498
|
+
role,
|
|
367
499
|
params,
|
|
368
500
|
});
|
|
369
501
|
let result: HostToolResult<unknown>;
|
|
@@ -389,6 +521,7 @@ export function createSubmissionLedgerHost(
|
|
|
389
521
|
outcome: "correctable-rejection",
|
|
390
522
|
code: "typed-bounce",
|
|
391
523
|
diagnostic: error instanceof Error ? error.message : String(error),
|
|
524
|
+
role,
|
|
392
525
|
accepted: params,
|
|
393
526
|
});
|
|
394
527
|
throw error;
|
|
@@ -399,6 +532,7 @@ export function createSubmissionLedgerHost(
|
|
|
399
532
|
toolCallId,
|
|
400
533
|
outcome: "infrastructure",
|
|
401
534
|
diagnostic: error instanceof Error ? error.message : String(error),
|
|
535
|
+
role,
|
|
402
536
|
accepted: params,
|
|
403
537
|
});
|
|
404
538
|
throw error;
|