@akagilnc/pi-workflow-roles 0.1.5289 → 0.1.5301

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.
@@ -31,10 +31,6 @@ export {
31
31
  import type { FixerPhase } from "../package-contracts/fixer-output.ts";
32
32
  import type { FixerPrerequisite } from "../package-contracts/fixer-packet.ts";
33
33
  import { parseCollectorRepository } from "../collector-config.ts";
34
- import {
35
- interpretDurableCourtTicketNumbers,
36
- sameCourtTicketNumbers,
37
- } from "../diarist-contracts.ts";
38
34
  import type { DoctorCaseIdentity } from "../doctor-contracts.ts";
39
35
  import type { NotarySourceRunLocator } from "../notary-contracts.ts";
40
36
  import {
@@ -1177,13 +1173,6 @@ type LoadedAdmittedRequestFields = {
1177
1173
  readonly derived?: DerivedMergerEnvelope;
1178
1174
  readonly correlationId?: string;
1179
1175
  readonly ticketNumber?: number;
1180
- /** #871 typed co-review set restored on countersign resume. */
1181
- readonly courtTicketNumbers?: readonly number[];
1182
- /**
1183
- * #871 durable set present-but-damaged diagnostic. Countersign resume settles
1184
- * controlled failure with this text; not a structural usage rejection.
1185
- */
1186
- readonly courtTicketNumbersDamage?: string;
1187
1176
  /** Collector — admitted repository/PR identity restored on resume (#633). */
1188
1177
  readonly prNumber?: number;
1189
1178
  readonly repository?: string;
@@ -1223,90 +1212,13 @@ function parsePersistedTicketIdentity(
1223
1212
  };
1224
1213
  }
1225
1214
 
1226
- /**
1227
- * #871 durable set from one run page.
1228
- * Absent → absent. Present damage keeps the original reason (no throw here).
1229
- */
1230
- function readDurableCourtTicketNumbersPage(
1231
- record: Record<string, unknown>,
1232
- principalTicket: number | undefined,
1233
- pageLabel: string,
1234
- ):
1235
- | { readonly kind: "absent" }
1236
- | { readonly kind: "ok"; readonly tickets: readonly number[] }
1237
- | { readonly kind: "damage"; readonly reason: string } {
1238
- const interpreted = interpretDurableCourtTicketNumbers(record, {
1239
- ...(principalTicket === undefined ? {} : { principalTicket }),
1240
- });
1241
- if (interpreted.kind === "damage") {
1242
- return {
1243
- kind: "damage",
1244
- reason: `role run ${pageLabel} courtTicketNumbers is damaged: ${interpreted.reason}`,
1245
- };
1246
- }
1247
- if (interpreted.kind === "ok") {
1248
- return { kind: "ok", tickets: interpreted.tickets };
1249
- }
1250
- return { kind: "absent" };
1251
- }
1252
-
1253
- /**
1254
- * Merge admitted + invocation #871 sets.
1255
- * Both present must match; one present wins; both absent stays legacy.
1256
- * Damage / cross-page mismatch return a diagnostic — countersign resume settles
1257
- * controlled failure; load itself does not structural-reject.
1258
- */
1259
- function mergeDurableCourtTicketNumbers(input: {
1260
- readonly admittedRecord: Record<string, unknown> | undefined;
1261
- readonly invocationRecord: Record<string, unknown> | undefined;
1262
- readonly principalTicket: number | undefined;
1263
- }):
1264
- | { readonly kind: "ok"; readonly tickets?: readonly number[] }
1265
- | { readonly kind: "damage"; readonly reason: string } {
1266
- const fromAdmitted =
1267
- input.admittedRecord === undefined
1268
- ? ({ kind: "absent" } as const)
1269
- : readDurableCourtTicketNumbersPage(
1270
- input.admittedRecord,
1271
- input.principalTicket,
1272
- "admitted-request",
1273
- );
1274
- const fromInvocation =
1275
- input.invocationRecord === undefined
1276
- ? ({ kind: "absent" } as const)
1277
- : readDurableCourtTicketNumbersPage(
1278
- input.invocationRecord,
1279
- input.principalTicket,
1280
- "invocation",
1281
- );
1282
- if (fromAdmitted.kind === "damage") return fromAdmitted;
1283
- if (fromInvocation.kind === "damage") return fromInvocation;
1284
- if (fromAdmitted.kind === "ok" && fromInvocation.kind === "ok") {
1285
- if (!sameCourtTicketNumbers(fromAdmitted.tickets, fromInvocation.tickets)) {
1286
- return {
1287
- kind: "damage",
1288
- reason:
1289
- "role run courtTicketNumbers differs between admitted-request and invocation",
1290
- };
1291
- }
1292
- return { kind: "ok", tickets: fromAdmitted.tickets };
1293
- }
1294
- if (fromAdmitted.kind === "ok") return { kind: "ok", tickets: fromAdmitted.tickets };
1295
- if (fromInvocation.kind === "ok") return { kind: "ok", tickets: fromInvocation.tickets };
1296
- return { kind: "ok" };
1297
- }
1298
-
1299
1215
  function restoredTicketFields(fields: LoadedAdmittedRequestFields): {
1300
1216
  correlationId?: string;
1301
1217
  ticketNumber?: number;
1302
- courtTicketNumbers?: readonly number[];
1303
1218
  } {
1304
1219
  return {
1305
1220
  ...(fields.correlationId === undefined ? {} : { correlationId: fields.correlationId }),
1306
1221
  ...(fields.ticketNumber === undefined ? {} : { ticketNumber: fields.ticketNumber }),
1307
- ...(fields.courtTicketNumbers === undefined
1308
- ? {}
1309
- : { courtTicketNumbers: fields.courtTicketNumbers }),
1310
1222
  };
1311
1223
  }
1312
1224
 
@@ -1352,10 +1264,6 @@ async function loadResumableRunRecord(
1352
1264
  let derived: DerivedMergerEnvelope | undefined;
1353
1265
  let correlationId: string | undefined;
1354
1266
  let ticketNumber: number | undefined;
1355
- let courtTicketNumbers: readonly number[] | undefined;
1356
- let courtTicketNumbersDamage: string | undefined;
1357
- let admittedIdentityRecord: Record<string, unknown> | undefined;
1358
- let invocationIdentityRecord: Record<string, unknown> | undefined;
1359
1267
  let prNumber: number | undefined;
1360
1268
  let repository: string | undefined;
1361
1269
  let repositoryDisplay: string | undefined;
@@ -1525,7 +1433,6 @@ async function loadResumableRunRecord(
1525
1433
  };
1526
1434
  }
1527
1435
  }
1528
- admittedIdentityRecord = record;
1529
1436
  const fromAdmitted = parsePersistedTicketIdentity(record);
1530
1437
  correlationId = fromAdmitted.correlationId;
1531
1438
  ticketNumber = fromAdmitted.ticketNumber;
@@ -1549,7 +1456,6 @@ async function loadResumableRunRecord(
1549
1456
  !Array.isArray(invocationRaw)
1550
1457
  ) {
1551
1458
  const rec = invocationRaw as Record<string, unknown>;
1552
- invocationIdentityRecord = rec;
1553
1459
  if (typeof rec.provider === "string" && typeof rec.model === "string") {
1554
1460
  model = {
1555
1461
  provider: rec.provider,
@@ -1584,19 +1490,6 @@ async function loadResumableRunRecord(
1584
1490
  );
1585
1491
  }
1586
1492
  }
1587
- // #871: resolve set after main ticket so principal membership can be checked.
1588
- // Present-but-damaged / cross-page mismatch keep diagnostic for countersign
1589
- // controlled-failure; both-absent stays legacy; single lawful page restores.
1590
- const mergedSet = mergeDurableCourtTicketNumbers({
1591
- admittedRecord: admittedIdentityRecord,
1592
- invocationRecord: invocationIdentityRecord,
1593
- principalTicket: ticketNumber,
1594
- });
1595
- if (mergedSet.kind === "damage") {
1596
- courtTicketNumbersDamage = mergedSet.reason;
1597
- } else if (mergedSet.tickets !== undefined) {
1598
- courtTicketNumbers = mergedSet.tickets;
1599
- }
1600
1493
  const sourceRunLeaf = basename(sourceRunPath ?? "").split("@");
1601
1494
  const referencedRunId = sourceRun?.runId ?? sourceRunLeaf[0];
1602
1495
  const referencedRole = sourceRun?.role ?? sourceRunLeaf[1];
@@ -1634,10 +1527,6 @@ async function loadResumableRunRecord(
1634
1527
  ...(derived === undefined ? {} : { derived }),
1635
1528
  ...(correlationId === undefined ? {} : { correlationId }),
1636
1529
  ...(ticketNumber === undefined ? {} : { ticketNumber }),
1637
- ...(courtTicketNumbers === undefined ? {} : { courtTicketNumbers }),
1638
- ...(courtTicketNumbersDamage === undefined
1639
- ? {}
1640
- : { courtTicketNumbersDamage }),
1641
1530
  ...(prNumber === undefined ? {} : { prNumber }),
1642
1531
  ...(repository === undefined ? {} : { repository }),
1643
1532
  ...(repositoryDisplay === undefined ? {} : { repositoryDisplay }),
@@ -1782,12 +1671,6 @@ function admitResumedRole(loaded: {
1782
1671
  const admitted: AdmittedCountersignInvocation = {
1783
1672
  role: "countersign",
1784
1673
  ...base,
1785
- ...(base.courtTicketNumbers === undefined
1786
- ? {}
1787
- : { courtTicketNumbers: base.courtTicketNumbers }),
1788
- ...(fields.courtTicketNumbersDamage === undefined
1789
- ? {}
1790
- : { courtTicketNumbersDamage: fields.courtTicketNumbersDamage }),
1791
1674
  };
1792
1675
  return admitted;
1793
1676
  }
@@ -421,8 +421,8 @@ export async function summonPublicRole(
421
421
  // Nested court stations keep station-child semantics; dual-lens
422
422
  // ordinary Reviewer axes opt out (#946 / ADR 0082).
423
423
  ...(options.stationChild === false ? {} : { stationChild: true }),
424
- // Forward composition-root adapters so nested court stations (e.g.
425
- // countersign → diarist) select the same faux/production table (#924).
424
+ // Forward composition-root adapters so nested stations (e.g.
425
+ // secretariat → diarist) select the same faux/production table (#924).
426
426
  ...(options.hostAdapters === undefined
427
427
  ? {}
428
428
  : { hostAdapters: options.hostAdapters }),
@@ -535,7 +535,7 @@ export async function summonPublicRole(
535
535
  }
536
536
 
537
537
  const stderr = captured?.stderrText();
538
- // An escalated officer can return its court diarist's escalation verbatim.
538
+ // Secretariat can return its preliminary diarist's escalation verbatim.
539
539
  // The terminal's independent run, not the officer, is the gate pointer.
540
540
  const runDirectory = result.terminal !== undefined
541
541
  && result.terminal.roleOutcome.role !== options.role
@@ -73,6 +73,7 @@ import {
73
73
  import { SECRETARIAT_OUTPUT_TOOL_NAME } from "./secretariat-contracts.ts";
74
74
  import {
75
75
  projectDiaristSessions,
76
+ projectDiaristTicketSessions,
76
77
  } from "./diarist-contracts.ts";
77
78
  import { commitDiaristProjection } from "./diarist.ts";
78
79
  import { TicketProvenanceInputError } from "./ticket-provenance.ts";
@@ -834,7 +835,7 @@ function readDiaristRunCoordinates(ctx: HostContext): {
834
835
 
835
836
  /** Plain-language re-ask when diarist bounds cannot be used (#901 / reask-not-explode). */
836
837
  const DIARIST_BOUNDS_REASK =
837
- "边界无法使用。请重交 sessions:每卷 path + ranges,每端以原生 id 或本轮行号二选一指名。" as const;
838
+ "边界无法使用。多票请逐票重交 ticketSessions,单票重交 sessions;每卷 path + ranges,每端以原生 id 或本轮行号二选一指名。" as const;
838
839
  /**
839
840
  * #708 / #779 / #901: 起居郎 public seat on the shared filed-officer envelope.
840
841
  * LLM judges ticket + dialogue bounds; mechanical layer reprojects the unique
@@ -870,18 +871,23 @@ export function createDiaristRoleRuntime(
870
871
  await bindTicketNumberOnRunDirectory(coords.runDirectory, ticketNumber);
871
872
  }
872
873
  }
873
- const sessions = projectDiaristSessions(parameters);
874
- if (sessions === undefined) {
874
+ const singleSessions = submitted && !Object.hasOwn(submitted, "ticketSessions")
875
+ ? projectDiaristSessions(parameters)
876
+ : undefined;
877
+ const ticketSessions = submitted && Object.hasOwn(submitted, "ticketSessions")
878
+ ? projectDiaristTicketSessions(submitted)
879
+ : singleSessions === undefined
880
+ ? undefined
881
+ : [{ ticketNumber: ticketNumber ?? null, sessions: singleSessions }];
882
+ if (ticketSessions === undefined) {
875
883
  throw new ParentQueueReaskError(DIARIST_BOUNDS_REASK);
876
884
  }
877
- let facts;
878
885
  try {
879
- facts = await commitDiaristProjection({
880
- ticketNumber: ticketNumber ?? null,
886
+ await commitDiaristProjection({
881
887
  cwd: coords.projectRoot,
882
888
  home: coords.home,
883
889
  runDirectory: coords.runDirectory,
884
- sessions,
890
+ tickets: ticketSessions,
885
891
  });
886
892
  } catch (error) {
887
893
  // Bound/session input failures → reask via typed identity (not message prefix).
@@ -162,11 +162,6 @@ export async function rehomeUnboundTicketProvenance(
162
162
  await unlink(source);
163
163
  }
164
164
 
165
- export type ReprojectTicketProvenanceResult = {
166
- readonly recordFile: string;
167
- readonly lines: readonly TicketProvenanceLine[];
168
- };
169
-
170
165
  /**
171
166
  * Resolve a bound endpoint against this round's session lines.
172
167
  * id → first physical line carrying that native id; line → that 1-based line.
@@ -327,53 +322,45 @@ async function projectSessionRanges(input: {
327
322
  }
328
323
 
329
324
  /**
330
- * Append dialogue projection from LLM-submitted bounds into records.jsonl.
325
+ * Project every submitted boundary before appending any ticket's record.
331
326
  * #1090: 纯追加——不回读已成录历史查重、不折叠、不刷新;同一区间再次提交也留下新的追加记录。
332
327
  * 证不出的 body 原字节原样留卷。
333
328
  */
334
- export async function reprojectTicketProvenance(input: {
335
- readonly ticketNumber: number | null;
329
+ export async function reprojectTicketProvenanceBatch(input: {
336
330
  readonly cwd: string;
337
331
  readonly home?: string;
338
332
  readonly runDirectory?: string;
339
- readonly sessions: readonly TicketProvenanceSession[];
340
- }): Promise<ReprojectTicketProvenanceResult> {
341
- const recordInput = ticketProvenanceRecordInput(
342
- input.ticketNumber,
343
- input.cwd,
344
- input.home,
345
- input.runDirectory,
346
- );
347
- const resolved = resolveSitianRecordPath(recordInput);
348
- if (input.sessions.length === 0) {
349
- return {
350
- recordFile: resolved.recordFile,
351
- lines: [],
352
- };
333
+ readonly tickets: readonly {
334
+ readonly ticketNumber: number | null;
335
+ readonly sessions: readonly TicketProvenanceSession[];
336
+ }[];
337
+ }): Promise<void> {
338
+ const projections = [];
339
+ for (const ticket of input.tickets) {
340
+ const recordInput = ticketProvenanceRecordInput(
341
+ ticket.ticketNumber, input.cwd, input.home, input.runDirectory,
342
+ );
343
+ const entries: (TicketProvenanceLine | TicketProvenanceRaw)[] = [];
344
+ for (let s = 0; s < ticket.sessions.length; s += 1) {
345
+ const projected = await projectSessionRanges({
346
+ s,
347
+ session: ticket.sessions[s]!,
348
+ ...(input.home === undefined ? {} : { home: input.home }),
349
+ });
350
+ entries.push(...projected.entries);
351
+ }
352
+ projections.push({ ticket, recordInput, entries });
353
353
  }
354
354
 
355
- const entries: (TicketProvenanceLine | TicketProvenanceRaw)[] = [];
356
- for (let s = 0; s < input.sessions.length; s += 1) {
357
- const session = input.sessions[s]!;
358
- const projected = await projectSessionRanges({
359
- s,
360
- session,
361
- ...(input.home === undefined ? {} : { home: input.home }),
355
+ for (const { ticket, recordInput, entries } of projections) {
356
+ if (ticket.sessions.length === 0) continue;
357
+ appendSitianRecord({
358
+ ...recordInput,
359
+ payload: {
360
+ type: "ticket-provenance-append",
361
+ sessions: ticket.sessions,
362
+ lines: entries,
363
+ },
362
364
  });
363
- entries.push(...projected.entries);
364
365
  }
365
-
366
- const pointer = appendSitianRecord({
367
- ...recordInput,
368
- payload: {
369
- type: "ticket-provenance-append",
370
- sessions: input.sessions,
371
- lines: entries,
372
- },
373
- });
374
-
375
- return {
376
- recordFile: pointer.recordFile,
377
- lines: entries.filter((entry): entry is TicketProvenanceLine => "speaker" in entry),
378
- };
379
366
  }