@akagilnc/pi-workflow-roles 0.1.5207 → 0.1.5216
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/README.md +1 -1
- package/dist/acp-host/production-host.js +163 -709
- package/dist/headless-host/production-host.js +139 -685
- package/dist/migrate-book-topology.js +0 -1
- package/dist/public-cli/main.js +0 -2
- package/dist/sitian-appender.js +0 -1
- package/dist/submission-ledger.js +8 -29
- package/dist/ticket-provenance-contracts.js +4 -42
- package/dist/ticket-provenance.js +27 -456
- package/package.json +2 -3
- package/scripts/build-package.mjs +1 -3
- package/src/diarist.ts +5 -5
- package/src/host-contracts.ts +0 -100
- package/src/role-runtime.ts +4 -57
- package/src/sitian-appender.ts +0 -1
- package/src/sitian-contracts.ts +0 -3
- package/src/submission-ledger.ts +10 -31
- package/src/ticket-provenance-contracts.ts +10 -48
- package/src/ticket-provenance.ts +33 -499
- package/dist/pi/in-process-session.js +0 -660
- package/dist/stream-idle-guard.js +0 -67
- package/schemas/tool-execution-observation.schema.json +0 -107
- package/scripts/generate-tool-execution-observation-schema.ts +0 -7
- package/src/in-process-session.ts +0 -1
- package/src/pi/in-process-session.ts +0 -861
- package/src/stream-idle-guard.ts +0 -98
- package/src/tool-execution-observation.ts +0 -168
package/src/host-contracts.ts
CHANGED
|
@@ -386,109 +386,9 @@ export interface RoleHost {
|
|
|
386
386
|
getCommands?(): Array<{ name: string }>;
|
|
387
387
|
}
|
|
388
388
|
|
|
389
|
-
/** Institutional sub-session seats (#518 §1). */
|
|
390
|
-
export type InstitutionalSeat =
|
|
391
|
-
| "gatekeeper"
|
|
392
|
-
| "inspector"
|
|
393
|
-
| "notary"
|
|
394
|
-
| "auditor"
|
|
395
|
-
| (string & {});
|
|
396
|
-
|
|
397
389
|
/** Non-secret host-neutral seat model selection. Single truth source is RoleTurnModelConfig. */
|
|
398
390
|
export type HostInstitutionalModelSelection = RoleTurnModelConfig;
|
|
399
391
|
|
|
400
|
-
/** Usage statistics for institutional sub-session events and turns. */
|
|
401
|
-
export type HostSessionUsage = {
|
|
402
|
-
readonly input: number;
|
|
403
|
-
readonly output: number;
|
|
404
|
-
readonly cacheRead: number;
|
|
405
|
-
readonly cacheWrite: number;
|
|
406
|
-
readonly totalTokens: number;
|
|
407
|
-
readonly cost: {
|
|
408
|
-
readonly input: number;
|
|
409
|
-
readonly output: number;
|
|
410
|
-
readonly cacheRead: number;
|
|
411
|
-
readonly cacheWrite: number;
|
|
412
|
-
readonly total: number;
|
|
413
|
-
};
|
|
414
|
-
};
|
|
415
|
-
|
|
416
|
-
/** Closed stream event union consumed by institutional callers (#518 §1③). */
|
|
417
|
-
export type HostInstitutionalSessionEvent =
|
|
418
|
-
| {
|
|
419
|
-
readonly type: "message_end";
|
|
420
|
-
readonly role: "assistant" | "user" | string;
|
|
421
|
-
readonly message?: unknown;
|
|
422
|
-
readonly usage?: HostSessionUsage;
|
|
423
|
-
}
|
|
424
|
-
| {
|
|
425
|
-
readonly type: "turn_end";
|
|
426
|
-
readonly stopReason?: string;
|
|
427
|
-
}
|
|
428
|
-
| {
|
|
429
|
-
readonly type: "tool_call";
|
|
430
|
-
readonly toolCallId: string;
|
|
431
|
-
readonly toolName: string;
|
|
432
|
-
readonly args?: unknown;
|
|
433
|
-
}
|
|
434
|
-
| {
|
|
435
|
-
readonly type: "tool_result";
|
|
436
|
-
readonly toolCallId: string;
|
|
437
|
-
readonly toolName: string;
|
|
438
|
-
readonly isError?: boolean;
|
|
439
|
-
readonly details?: unknown;
|
|
440
|
-
};
|
|
441
|
-
|
|
442
|
-
/** Terminal result of an institutional assistant turn (#518 §1③). */
|
|
443
|
-
export type HostAssistantTurnResult = {
|
|
444
|
-
readonly text: string;
|
|
445
|
-
readonly stopReason?: string;
|
|
446
|
-
readonly errorMessage?: string;
|
|
447
|
-
readonly usage?: HostSessionUsage;
|
|
448
|
-
readonly messages?: readonly unknown[];
|
|
449
|
-
};
|
|
450
|
-
|
|
451
|
-
/**
|
|
452
|
-
* Handle to an active institutional sub-session (#518 §1②).
|
|
453
|
-
* Does not leak AgentSession, ModelRuntime, or Provider objects out of the adapter.
|
|
454
|
-
*/
|
|
455
|
-
export interface HostInstitutionalSessionHandle {
|
|
456
|
-
readonly sessionFile?: string;
|
|
457
|
-
readonly sessionId?: string;
|
|
458
|
-
prompt(text: string): Promise<HostAssistantTurnResult>;
|
|
459
|
-
subscribe(listener: (event: HostInstitutionalSessionEvent) => void): () => void;
|
|
460
|
-
abort(): void;
|
|
461
|
-
close(): Promise<void>;
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
/** Open options for an institutional sub-session (#518 §1①). */
|
|
465
|
-
export type HostInstitutionalSessionOptions = {
|
|
466
|
-
readonly cwd: string;
|
|
467
|
-
readonly selection: HostInstitutionalModelSelection;
|
|
468
|
-
readonly systemPrompt: string;
|
|
469
|
-
readonly tools?: readonly HostToolDefinition[];
|
|
470
|
-
readonly customTools?: readonly unknown[];
|
|
471
|
-
readonly noTools?: "all" | "builtin";
|
|
472
|
-
readonly toolsAllowlist?: readonly string[];
|
|
473
|
-
readonly agentDir?: string;
|
|
474
|
-
readonly credentialScratchParent?: string;
|
|
475
|
-
readonly signal?: AbortSignal;
|
|
476
|
-
readonly idleRetry?: boolean;
|
|
477
|
-
readonly sessionIdentity?: {
|
|
478
|
-
readonly kind: string;
|
|
479
|
-
readonly subject?: string;
|
|
480
|
-
readonly parent?: { getSessionFile(): string | undefined };
|
|
481
|
-
};
|
|
482
|
-
readonly sessionManager?: unknown;
|
|
483
|
-
};
|
|
484
|
-
|
|
485
|
-
/** Host-neutral institutional sub-session open seam. */
|
|
486
|
-
export interface InstitutionalSessionHost {
|
|
487
|
-
openInstitutionalSession(
|
|
488
|
-
options: HostInstitutionalSessionOptions,
|
|
489
|
-
): Promise<HostInstitutionalSessionHandle>;
|
|
490
|
-
}
|
|
491
|
-
|
|
492
392
|
/** Host-owned durable record session used by AK ledger placement. */
|
|
493
393
|
export interface HostRecordSession {
|
|
494
394
|
getSessionFile(): string | undefined;
|
package/src/role-runtime.ts
CHANGED
|
@@ -24,12 +24,6 @@ import {
|
|
|
24
24
|
} from "./activation-ledger.ts";
|
|
25
25
|
import { readPackageMaterial } from "./session-opening-materials.ts";
|
|
26
26
|
import { writeStderrJsonlRecord } from "./stderr-jsonl.ts";
|
|
27
|
-
import {
|
|
28
|
-
createToolExecutionObservationFace,
|
|
29
|
-
systemToolExecutionObservationMonoNow,
|
|
30
|
-
writeToolExecutionObservationRecord,
|
|
31
|
-
type ToolExecutionObservationWriter,
|
|
32
|
-
} from "./tool-execution-observation.ts";
|
|
33
27
|
import {
|
|
34
28
|
ENGINE_DETOUR_TOOL_NAME,
|
|
35
29
|
ENGINE_MODEL_FLAG_NAME,
|
|
@@ -286,17 +280,6 @@ export type {
|
|
|
286
280
|
ActivationSessionManager,
|
|
287
281
|
ActivationSessionPointer,
|
|
288
282
|
} from "./activation-ledger.ts";
|
|
289
|
-
export {
|
|
290
|
-
TOOL_EXECUTION_UPDATE_HEARTBEAT,
|
|
291
|
-
TOOL_EXECUTION_UPDATE_THROTTLE_MS,
|
|
292
|
-
createToolExecutionObservationFace,
|
|
293
|
-
isProducingToolUpdate,
|
|
294
|
-
systemToolExecutionObservationMonoNow,
|
|
295
|
-
toolExecutionObservationRecordSchema,
|
|
296
|
-
validateToolExecutionObservationRecord,
|
|
297
|
-
writeToolExecutionObservationRecord,
|
|
298
|
-
} from "./tool-execution-observation.ts";
|
|
299
|
-
export type { ToolExecutionObservationRecord, ToolExecutionObservationWriter } from "./tool-execution-observation.ts";
|
|
300
283
|
import {
|
|
301
284
|
NOTARY_OUTPUT_TOOL,
|
|
302
285
|
INSPECTOR_OUTPUT_TOOL,
|
|
@@ -477,11 +460,6 @@ export type RoleRuntimeDependencies = {
|
|
|
477
460
|
loadNavigatorWorkContext?(options: { context: HostContext; role: string; phase: NavigatorPhase; getFlag?: (name: string) => unknown }): Promise<NavigatorWorkContext>;
|
|
478
461
|
activationClock?(): string;
|
|
479
462
|
activationTraceWriter?: (record: ActivationTraceRecord) => void | Promise<void>;
|
|
480
|
-
/** Wall-clock ISO timestamps for tool-execution observation records; defaults to activationClock/Date. */
|
|
481
|
-
toolExecutionObservationClock?(): string;
|
|
482
|
-
/** Monotonic ms clock for update throttling; defaults to performance.now (not Date.now). */
|
|
483
|
-
toolExecutionObservationMonoNow?(): number;
|
|
484
|
-
toolExecutionObservationWriter?: ToolExecutionObservationWriter;
|
|
485
463
|
};
|
|
486
464
|
|
|
487
465
|
function abortContext(ctx: { abort(): void }): void {
|
|
@@ -1081,7 +1059,7 @@ export function createRoleRuntimeExtension(
|
|
|
1081
1059
|
// terminating-tool rejections and mechanical delivery requests share two turns.
|
|
1082
1060
|
let receiptDelivery = createReceiptDeliveryPolicy();
|
|
1083
1061
|
let noReceiptRecorded = false;
|
|
1084
|
-
// Public-run fetch observation
|
|
1062
|
+
// Public-run fetch observation.
|
|
1085
1063
|
let priorFetch: typeof globalThis.fetch | undefined;
|
|
1086
1064
|
let fetchWrapped = false;
|
|
1087
1065
|
/** Envelope-owned: abort/teardown attendance without re-blocking the parent court (#959). */
|
|
@@ -1498,7 +1476,6 @@ export function createRoleRuntimeExtension(
|
|
|
1498
1476
|
disposeNavigatorAttendanceNonBlocking(attendanceToDispose);
|
|
1499
1477
|
pendingInfrastructureFailures.clear();
|
|
1500
1478
|
pendingSubmissionNonPassByToolCallId.clear();
|
|
1501
|
-
observationFace.reset();
|
|
1502
1479
|
});
|
|
1503
1480
|
|
|
1504
1481
|
const hostActions = {
|
|
@@ -1736,38 +1713,9 @@ export function createRoleRuntimeExtension(
|
|
|
1736
1713
|
|
|
1737
1714
|
const clock = dependencies.activationClock ?? (() => new Date().toISOString());
|
|
1738
1715
|
const writeTrace = dependencies.activationTraceWriter ?? writeActivationTraceRecord;
|
|
1739
|
-
const observationFace = createToolExecutionObservationFace({
|
|
1740
|
-
role: () => selectedRole,
|
|
1741
|
-
admitted: () => admitted,
|
|
1742
|
-
clock: dependencies.toolExecutionObservationClock ?? clock,
|
|
1743
|
-
monoNow: dependencies.toolExecutionObservationMonoNow ?? systemToolExecutionObservationMonoNow,
|
|
1744
|
-
write: dependencies.toolExecutionObservationWriter ?? writeToolExecutionObservationRecord,
|
|
1745
|
-
});
|
|
1746
|
-
// ExtensionRunner.emit catches ordinary handler throws, emits extension error, and continues.
|
|
1747
|
-
// Observation plane failures must still hit the shared infrastructure termination path
|
|
1748
|
-
// (abort + nonzero print/json exit) with the original cause before that swallow.
|
|
1749
|
-
const observe = async (
|
|
1750
|
-
run: () => void | Promise<void>,
|
|
1751
|
-
ctx: HostContext,
|
|
1752
|
-
): Promise<void> => {
|
|
1753
|
-
try {
|
|
1754
|
-
await run();
|
|
1755
|
-
} catch (error) {
|
|
1756
|
-
failInfrastructure(error, ctx);
|
|
1757
|
-
}
|
|
1758
|
-
};
|
|
1759
|
-
roleHost.on("tool_execution_start", async (event, ctx) => {
|
|
1760
|
-
await observe(() => observationFace.onStart(event), ctx);
|
|
1761
|
-
});
|
|
1762
|
-
roleHost.on("tool_execution_update", async (event, ctx) => {
|
|
1763
|
-
await observe(() => observationFace.onUpdate(event), ctx);
|
|
1764
|
-
});
|
|
1765
|
-
roleHost.on("tool_execution_end", async (event, ctx) => {
|
|
1766
|
-
await observe(() => observationFace.onEnd(event), ctx);
|
|
1767
|
-
});
|
|
1768
1716
|
|
|
1769
1717
|
// Public Role run: record typed non-success HTTP for error evidence + v1 resume.
|
|
1770
|
-
// Same observation owner
|
|
1718
|
+
// Same observation owner → typed-provider-http
|
|
1771
1719
|
// sidecar (settlement already merges observation.httpStatus into knownFailure).
|
|
1772
1720
|
// after_provider_response covers the success-path onResponse face; fetch wrap covers
|
|
1773
1721
|
// non-2xx Responses where openai-completions throws before onResponse (#675).
|
|
@@ -1805,7 +1753,7 @@ export function createRoleRuntimeExtension(
|
|
|
1805
1753
|
});
|
|
1806
1754
|
|
|
1807
1755
|
roleHost.on("session_start", async (event, ctx) => {
|
|
1808
|
-
// Scope fetch observation to this public run
|
|
1756
|
+
// Scope fetch observation to this public run.
|
|
1809
1757
|
if (!fetchWrapped && typeof globalThis.fetch === "function") {
|
|
1810
1758
|
priorFetch = globalThis.fetch.bind(globalThis);
|
|
1811
1759
|
const underlying = priorFetch;
|
|
@@ -1827,7 +1775,7 @@ export function createRoleRuntimeExtension(
|
|
|
1827
1775
|
provider,
|
|
1828
1776
|
});
|
|
1829
1777
|
} catch {
|
|
1830
|
-
// Observation must not break the provider stream
|
|
1778
|
+
// Observation must not break the provider stream.
|
|
1831
1779
|
}
|
|
1832
1780
|
}
|
|
1833
1781
|
return response;
|
|
@@ -1842,7 +1790,6 @@ export function createRoleRuntimeExtension(
|
|
|
1842
1790
|
collectorFirstDispatchDone = false;
|
|
1843
1791
|
receiptDelivery = createReceiptDeliveryPolicy();
|
|
1844
1792
|
noReceiptRecorded = false;
|
|
1845
|
-
observationFace.reset();
|
|
1846
1793
|
pendingNavigatorPresentation = undefined;
|
|
1847
1794
|
pendingNavigatorSettlement = undefined;
|
|
1848
1795
|
pendingInfrastructureFailures.clear();
|
package/src/sitian-appender.ts
CHANGED
|
@@ -353,7 +353,6 @@ export function appendSitianRecord(input: SitianRecordInput): RecordPointer {
|
|
|
353
353
|
identity,
|
|
354
354
|
...(input.subject === undefined ? {} : { subject: input.subject }),
|
|
355
355
|
...(input.sessionParent === undefined ? {} : { sessionParent: input.sessionParent }),
|
|
356
|
-
...(input.priorEventId === undefined ? {} : { priorEventId: input.priorEventId }),
|
|
357
356
|
timestamp,
|
|
358
357
|
host,
|
|
359
358
|
...(input.source === undefined ? {} : { source: input.source }),
|
package/src/sitian-contracts.ts
CHANGED
|
@@ -37,8 +37,6 @@ export type SitianRecord = {
|
|
|
37
37
|
readonly subject?: SitianSubject | undefined;
|
|
38
38
|
/** Parent session principal link / nesting origin. */
|
|
39
39
|
readonly sessionParent?: string | undefined;
|
|
40
|
-
/** Prior event identity in a submission ledger chain (S4; distinct from sessionParent). */
|
|
41
|
-
readonly priorEventId?: string | undefined;
|
|
42
40
|
readonly timestamp: string;
|
|
43
41
|
readonly host: string;
|
|
44
42
|
readonly source?: string | undefined;
|
|
@@ -65,7 +63,6 @@ export type SitianRecordInput = {
|
|
|
65
63
|
readonly sessionParent?: string | undefined;
|
|
66
64
|
/** Run owner for ticket provenance before a ticket is known. */
|
|
67
65
|
readonly runDirectory?: string | undefined;
|
|
68
|
-
readonly priorEventId?: string | undefined;
|
|
69
66
|
readonly timestamp?: string | undefined;
|
|
70
67
|
readonly host?: string | undefined;
|
|
71
68
|
readonly source?: string | undefined;
|
package/src/submission-ledger.ts
CHANGED
|
@@ -146,7 +146,7 @@ async function submissionRecordFile(cwd: string, runId: string, scope: Submissio
|
|
|
146
146
|
/**
|
|
147
147
|
* Discriminated owned-row view:
|
|
148
148
|
* - unknown run → file absent + empty owned (read APIs only)
|
|
149
|
-
* - located ledger → file is string;
|
|
149
|
+
* - located ledger → file is string; write consumers may build RecordPointer
|
|
150
150
|
*/
|
|
151
151
|
type OwnedSubmissionRecords =
|
|
152
152
|
| { readonly file: undefined; readonly owned: readonly [] }
|
|
@@ -491,11 +491,10 @@ export async function readLatestSubmissionOutcome(
|
|
|
491
491
|
return undefined;
|
|
492
492
|
}
|
|
493
493
|
|
|
494
|
-
type LedgerState = {
|
|
494
|
+
type LedgerState = { sequence: number };
|
|
495
495
|
|
|
496
496
|
async function restoreState(cwd: string, runId: string, scope: SubmissionLedgerReadScope): Promise<LedgerState> {
|
|
497
497
|
const located = await readOwnedSubmissionRecords(cwd, runId, scope);
|
|
498
|
-
// Unknown-run empty set: no prior chain. Owned rows without a file are an internal bug.
|
|
499
498
|
if (located.file === undefined) {
|
|
500
499
|
if (located.owned.length !== 0) {
|
|
501
500
|
throw new Error(
|
|
@@ -504,19 +503,8 @@ async function restoreState(cwd: string, runId: string, scope: SubmissionLedgerR
|
|
|
504
503
|
}
|
|
505
504
|
return { sequence: 0 };
|
|
506
505
|
}
|
|
507
|
-
const {
|
|
508
|
-
const last = owned.at(-1);
|
|
506
|
+
const { owned } = located;
|
|
509
507
|
return {
|
|
510
|
-
...(last === undefined
|
|
511
|
-
? {}
|
|
512
|
-
: {
|
|
513
|
-
prior: {
|
|
514
|
-
identity: last.identity,
|
|
515
|
-
recordFile: file,
|
|
516
|
-
kind: last.kind,
|
|
517
|
-
level: last.level,
|
|
518
|
-
},
|
|
519
|
-
}),
|
|
520
508
|
sequence: owned.reduce((maximum, record) => {
|
|
521
509
|
const payload = record.payload as Partial<SubmissionLedgerEvent> | undefined;
|
|
522
510
|
return payload?.type === "candidate" && typeof payload.sequence === "number"
|
|
@@ -547,7 +535,7 @@ function homeFromHostContext(context: HostContext, home?: string): string | unde
|
|
|
547
535
|
|
|
548
536
|
/**
|
|
549
537
|
* #959: seal one accepted submission without a model tool call.
|
|
550
|
-
* Same ledger row shape
|
|
538
|
+
* Same ledger row shape as the terminating-tool wrap.
|
|
551
539
|
* Used when a prose-exit seat (navigator) harvests the final assistant text.
|
|
552
540
|
*/
|
|
553
541
|
export async function sealAcceptedSubmission(options: {
|
|
@@ -561,15 +549,10 @@ export async function sealAcceptedSubmission(options: {
|
|
|
561
549
|
const attemptId = attemptIdentity(options.context, runId);
|
|
562
550
|
const sessionParent = sessionParentFromHostContext(options.context);
|
|
563
551
|
const home = homeFromHostContext(options.context, options.home);
|
|
564
|
-
|
|
565
|
-
...(home === undefined ? {} : { home }),
|
|
566
|
-
...(sessionParent === undefined ? {} : { sessionParent }),
|
|
567
|
-
});
|
|
568
|
-
const pointer = sitianReport({
|
|
552
|
+
sitianReport({
|
|
569
553
|
level: "event",
|
|
570
554
|
kind: "sealed",
|
|
571
555
|
subject: { runId, attemptId },
|
|
572
|
-
...(state.prior === undefined ? {} : { priorEventId: state.prior.identity }),
|
|
573
556
|
payload: {
|
|
574
557
|
type: "sealed",
|
|
575
558
|
attemptId,
|
|
@@ -582,7 +565,6 @@ export async function sealAcceptedSubmission(options: {
|
|
|
582
565
|
...(home !== undefined ? { home } : {}),
|
|
583
566
|
...(sessionParent === undefined ? {} : { sessionParent }),
|
|
584
567
|
});
|
|
585
|
-
state.prior = pointer;
|
|
586
568
|
}
|
|
587
569
|
|
|
588
570
|
/**
|
|
@@ -611,32 +593,29 @@ export function createSubmissionLedgerHost(
|
|
|
611
593
|
states.set(runId, pending);
|
|
612
594
|
return pending;
|
|
613
595
|
})();
|
|
614
|
-
const appendFor = (
|
|
596
|
+
const appendFor = (context: HostContext, runId: string, attemptId: string, event: SubmissionLedgerEvent): RecordPointer => {
|
|
615
597
|
const home = resolveHomeFromContext(context);
|
|
616
598
|
const sessionParent = sessionParentFromHostContext(context);
|
|
617
|
-
|
|
599
|
+
return sitianReport({
|
|
618
600
|
level: "event",
|
|
619
601
|
kind: event.type,
|
|
620
602
|
subject: { runId, attemptId },
|
|
621
|
-
...(state.prior === undefined ? {} : { priorEventId: state.prior.identity }),
|
|
622
603
|
payload: event,
|
|
623
604
|
source: "role-runtime",
|
|
624
605
|
cwd: context.cwd,
|
|
625
606
|
...(home !== undefined ? { home } : {}),
|
|
626
607
|
...(sessionParent === undefined ? {} : { sessionParent }),
|
|
627
608
|
});
|
|
628
|
-
state.prior = pointer;
|
|
629
|
-
return pointer;
|
|
630
609
|
};
|
|
631
610
|
|
|
632
611
|
host.on("turn_end", async (event, context) => {
|
|
633
612
|
try {
|
|
634
613
|
const runId = runIdentity(context);
|
|
635
614
|
const attemptId = attemptIdentity(context, runId);
|
|
636
|
-
const state = await stateFor(context, runId);
|
|
637
615
|
const calls = event.calls.map(({ toolCallId: id, toolName: name }) => ({ id, name }));
|
|
638
616
|
if (calls.length > 0) {
|
|
639
|
-
|
|
617
|
+
await stateFor(context, runId);
|
|
618
|
+
appendFor(context, runId, attemptId, { type: "roundContext", attemptId, calls });
|
|
640
619
|
}
|
|
641
620
|
} catch (error) {
|
|
642
621
|
failInfrastructure(error, context);
|
|
@@ -663,7 +642,7 @@ export function createSubmissionLedgerHost(
|
|
|
663
642
|
const runId = runIdentity(context);
|
|
664
643
|
const attemptId = attemptIdentity(context, runId);
|
|
665
644
|
const state = await stateFor(context, runId);
|
|
666
|
-
const append = (event: SubmissionLedgerEvent) => appendFor(
|
|
645
|
+
const append = (event: SubmissionLedgerEvent) => appendFor(context, runId, attemptId, event);
|
|
667
646
|
// #541 / #575: shared infra-declaration fail lives on the ledger seam.
|
|
668
647
|
// #641 chain②: seats may bounce a misdeclared infrastructure failure
|
|
669
648
|
// as correctable (2.1/2.2/2.3 keep paths).
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* 起居录(ticket-provenance)typed 形状 —— ADR 0075
|
|
2
|
+
* 起居录(ticket-provenance)typed 形状 —— ADR 0075 / ADR 0081 / #1090。
|
|
3
3
|
*
|
|
4
|
-
* 一册=一个追加式 records.jsonl
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* 交卷 `sessions` 输入语义仍是「本轮对话边界」;累计并集是机械合并,不是角色交什么。
|
|
4
|
+
* 一册=一个追加式 records.jsonl。每轮交卷的 `sessions`=本轮对话边界;
|
|
5
|
+
* 成录接缝按该边界从宿主卷投影并追加,不回读已成录历史去重或折叠。
|
|
6
|
+
* 既有「首行册子头+裸对话行」snapshot 仍可读;后续提交不回写旧行。
|
|
8
7
|
*/
|
|
9
8
|
|
|
10
9
|
/** Sitian kind for per-ticket court diary volumes. */
|
|
@@ -30,14 +29,14 @@ export type TicketProvenanceRange = {
|
|
|
30
29
|
|
|
31
30
|
/**
|
|
32
31
|
* 一卷:会话卷路径 + 区间声明。
|
|
33
|
-
*
|
|
32
|
+
* 交卷与每条追加提交的 payload.sessions 同型=该次边界。
|
|
34
33
|
*/
|
|
35
34
|
export type TicketProvenanceSession = {
|
|
36
35
|
readonly path: string;
|
|
37
36
|
readonly ranges: readonly TicketProvenanceRange[];
|
|
38
37
|
};
|
|
39
38
|
|
|
40
|
-
/**
|
|
39
|
+
/** 旧 snapshot 册子头形状(存量可读;#1090 后新提交不再维护折叠头)。 */
|
|
41
40
|
export type TicketProvenanceHeader = {
|
|
42
41
|
readonly repo: string;
|
|
43
42
|
readonly ticket: number | null;
|
|
@@ -48,15 +47,15 @@ export type TicketProvenanceHeader = {
|
|
|
48
47
|
|
|
49
48
|
/**
|
|
50
49
|
* 一条对话(存于不可变投影提交;旧 snapshot 中也可为裸行)。
|
|
51
|
-
* `id` 按源事实存在则记、不存在不编;`s`
|
|
50
|
+
* `id` 按源事实存在则记、不存在不编;`s` 为本轮 sessions 下标。
|
|
52
51
|
*/
|
|
53
52
|
export type TicketProvenanceLine = {
|
|
54
53
|
readonly speaker: TicketProvenanceSpeaker;
|
|
55
|
-
/**
|
|
54
|
+
/** 本轮 sessions 下标。 */
|
|
56
55
|
readonly s: number;
|
|
57
|
-
/** Logical source order
|
|
56
|
+
/** Logical source order within the source volume at projection time. */
|
|
58
57
|
readonly sourcePosition?: number;
|
|
59
|
-
/** Replay-invariant structural identity
|
|
58
|
+
/** Replay-invariant structural identity for id-less source rows. */
|
|
60
59
|
readonly sourceIdentity?: string;
|
|
61
60
|
readonly id?: string;
|
|
62
61
|
readonly text: string;
|
|
@@ -75,19 +74,6 @@ function positiveInteger(value: unknown): number | undefined {
|
|
|
75
74
|
return undefined;
|
|
76
75
|
}
|
|
77
76
|
|
|
78
|
-
function nonNegativeInteger(value: unknown): number | undefined {
|
|
79
|
-
if (typeof value === "number" && Number.isSafeInteger(value) && value >= 0) return value;
|
|
80
|
-
if (typeof value === "string" && /^(0|[1-9][0-9]*)$/.test(value)) {
|
|
81
|
-
const parsed = Number(value);
|
|
82
|
-
if (Number.isSafeInteger(parsed)) return parsed;
|
|
83
|
-
}
|
|
84
|
-
return undefined;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
function projectSpeaker(value: unknown): TicketProvenanceSpeaker | undefined {
|
|
88
|
-
return value === "owner" || value === "runner" ? value : undefined;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
77
|
function projectBound(value: unknown): TicketProvenanceBound | undefined {
|
|
92
78
|
if (!isRecord(value)) return undefined;
|
|
93
79
|
const id = typeof value.id === "string" && value.id !== "" ? value.id : undefined;
|
|
@@ -149,27 +135,3 @@ export function projectTicketProvenanceHeader(
|
|
|
149
135
|
sessions,
|
|
150
136
|
};
|
|
151
137
|
}
|
|
152
|
-
|
|
153
|
-
/** 读回一条对话行。 */
|
|
154
|
-
export function projectTicketProvenanceLine(
|
|
155
|
-
value: unknown,
|
|
156
|
-
): TicketProvenanceLine | undefined {
|
|
157
|
-
if (!isRecord(value)) return undefined;
|
|
158
|
-
const speaker = projectSpeaker(value.speaker);
|
|
159
|
-
const s = nonNegativeInteger(value.s);
|
|
160
|
-
if (speaker === undefined || s === undefined) return undefined;
|
|
161
|
-
if (typeof value.text !== "string") return undefined;
|
|
162
|
-
const sourcePosition = nonNegativeInteger(value.sourcePosition);
|
|
163
|
-
const sourceIdentity = typeof value.sourceIdentity === "string" && value.sourceIdentity !== ""
|
|
164
|
-
? value.sourceIdentity
|
|
165
|
-
: undefined;
|
|
166
|
-
const id = typeof value.id === "string" && value.id !== "" ? value.id : undefined;
|
|
167
|
-
return {
|
|
168
|
-
speaker,
|
|
169
|
-
s,
|
|
170
|
-
...(sourcePosition === undefined ? {} : { sourcePosition }),
|
|
171
|
-
...(sourceIdentity === undefined ? {} : { sourceIdentity }),
|
|
172
|
-
...(id === undefined ? {} : { id }),
|
|
173
|
-
text: value.text,
|
|
174
|
-
};
|
|
175
|
-
}
|