@akagilnc/pi-workflow-roles 0.1.1883 → 0.1.1918
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/evidence-child-executor.js +153 -16
- package/dist/navigator-attendance.js +64 -29
- package/dist/public-cli/main.js +786 -373
- package/dist/reviewer-child-executor.js +1 -1
- package/dist/typed-provider-http.js +60 -0
- package/dist/upstream-error-testimony.js +19 -0
- package/package.json +1 -1
- package/scripts/build-package.mjs +2 -0
- package/src/evidence-child-executor.ts +177 -24
- package/src/factory-board.ts +60 -3
- package/src/navigator-attendance.ts +86 -33
- package/src/public-cli/cli.ts +96 -39
- package/src/public-cli/coder-run.ts +36 -11
- package/src/public-cli/collector-run.ts +8 -3
- package/src/public-cli/doctor-run.ts +1 -0
- package/src/public-cli/explicit-internal.ts +61 -19
- package/src/public-cli/fixer-run.ts +36 -11
- package/src/public-cli/invocation.ts +137 -101
- package/src/public-cli/judge-run.ts +39 -11
- package/src/public-cli/merger-run.ts +36 -11
- package/src/public-cli/reviewer-run.ts +35 -11
- package/src/public-cli/run-lifecycle.ts +89 -76
- package/src/public-cli/settlement.ts +256 -66
- package/src/reviewer-child-executor.ts +1 -1
- package/src/role-runtime.ts +18 -8
- package/src/ticket-frontmatter.ts +94 -0
- package/src/ticket-trajectory.ts +145 -5
- package/src/typed-provider-http.ts +99 -0
- package/src/upstream-error-testimony.ts +45 -0
|
@@ -21,6 +21,12 @@ import {
|
|
|
21
21
|
type ReviewerPreflightViolation,
|
|
22
22
|
} from "../reviewer-dispatch.ts";
|
|
23
23
|
import type { ControlledFailureCause } from "./terminal.ts";
|
|
24
|
+
import {
|
|
25
|
+
hasUpstreamErrorTestimony,
|
|
26
|
+
projectConfirmedRemotePayload,
|
|
27
|
+
} from "../upstream-error-testimony.ts";
|
|
28
|
+
|
|
29
|
+
export { hasUpstreamErrorTestimony } from "../upstream-error-testimony.ts";
|
|
24
30
|
|
|
25
31
|
/** Durable Reviewer-rejection child→parent page under AK_ROLE_RUN_DIR. */
|
|
26
32
|
const REVIEWER_DISPATCH_REJECTION_FILE = "typed-known-failure.json";
|
|
@@ -147,34 +153,70 @@ export type ExplicitInternalKnownFailure = {
|
|
|
147
153
|
readonly details?: Readonly<Record<string, unknown>>;
|
|
148
154
|
};
|
|
149
155
|
|
|
156
|
+
function nonEmptyString(value: unknown): string | undefined {
|
|
157
|
+
return typeof value === "string" && value.trim() !== "" ? value : undefined;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function sessionStopDetails(input: {
|
|
161
|
+
readonly errorMessage?: string | null;
|
|
162
|
+
readonly provider?: string;
|
|
163
|
+
readonly model?: string;
|
|
164
|
+
readonly api?: string;
|
|
165
|
+
readonly rawStopReason?: string;
|
|
166
|
+
readonly httpStatus?: number;
|
|
167
|
+
readonly diagnostics?: unknown;
|
|
168
|
+
readonly body?: unknown;
|
|
169
|
+
readonly code?: unknown;
|
|
170
|
+
readonly errno?: unknown;
|
|
171
|
+
}): Record<string, unknown> {
|
|
172
|
+
const details: Record<string, unknown> = {};
|
|
173
|
+
const errorMessage = nonEmptyString(input.errorMessage);
|
|
174
|
+
if (errorMessage !== undefined) details.errorMessage = errorMessage;
|
|
175
|
+
const api = nonEmptyString(input.api);
|
|
176
|
+
if (api !== undefined) details.api = api;
|
|
177
|
+
const rawStopReason = nonEmptyString(input.rawStopReason);
|
|
178
|
+
if (rawStopReason !== undefined) details.rawStopReason = rawStopReason;
|
|
179
|
+
const testimony = hasUpstreamErrorTestimony(input);
|
|
180
|
+
if (testimony) {
|
|
181
|
+
const provider = nonEmptyString(input.provider);
|
|
182
|
+
if (provider !== undefined) details.provider = provider;
|
|
183
|
+
const model = nonEmptyString(input.model);
|
|
184
|
+
if (model !== undefined) details.model = model;
|
|
185
|
+
}
|
|
186
|
+
if (typeof input.httpStatus === "number") details.httpStatus = input.httpStatus;
|
|
187
|
+
if (input.diagnostics !== undefined) details.diagnostics = input.diagnostics;
|
|
188
|
+
// SDK structured payload fields: project only when held on a confirmed-remote node.
|
|
189
|
+
if (testimony) Object.assign(details, projectConfirmedRemotePayload(input));
|
|
190
|
+
return details;
|
|
191
|
+
}
|
|
192
|
+
|
|
150
193
|
/**
|
|
151
|
-
*
|
|
152
|
-
*
|
|
153
|
-
*
|
|
194
|
+
* Project a native session assistant stop onto the existing knownFailure chain.
|
|
195
|
+
* Classification follows two-way testimony: typed HTTP status or SDK structure
|
|
196
|
+
* keeps provider; stopReason, configured provider/model, or errorMessage prose
|
|
197
|
+
* alone is the existing unrecognized value. Present upstream payload is preserved
|
|
198
|
+
* in details without rewriting; missing fields are omitted.
|
|
154
199
|
*/
|
|
155
200
|
export function knownFailureFromProviderStop(input: {
|
|
156
201
|
readonly stopReason?: string;
|
|
157
202
|
readonly errorMessage?: string | null;
|
|
158
203
|
readonly provider?: string;
|
|
159
204
|
readonly model?: string;
|
|
205
|
+
readonly api?: string;
|
|
206
|
+
readonly rawStopReason?: string;
|
|
207
|
+
readonly httpStatus?: number;
|
|
208
|
+
readonly diagnostics?: unknown;
|
|
209
|
+
readonly body?: unknown;
|
|
210
|
+
readonly code?: unknown;
|
|
211
|
+
readonly errno?: unknown;
|
|
160
212
|
}): ExplicitInternalKnownFailure | undefined {
|
|
161
|
-
if (input.stopReason !== "error") return undefined;
|
|
162
|
-
const diagnostic =
|
|
163
|
-
|
|
164
|
-
? input.errorMessage.trim()
|
|
165
|
-
: "provider failure";
|
|
166
|
-
const identity: { name: string; code?: string } = {
|
|
167
|
-
name: "ProviderStopError",
|
|
168
|
-
};
|
|
169
|
-
if (typeof input.provider === "string" && input.provider.trim() !== "") {
|
|
170
|
-
identity.code = input.provider;
|
|
171
|
-
} else if (typeof input.model === "string" && input.model.trim() !== "") {
|
|
172
|
-
identity.code = input.model;
|
|
173
|
-
}
|
|
213
|
+
if (input.stopReason !== "error" && input.stopReason !== "aborted") return undefined;
|
|
214
|
+
const diagnostic = nonEmptyString(input.errorMessage);
|
|
215
|
+
const details = sessionStopDetails(input);
|
|
174
216
|
return {
|
|
175
|
-
cause: "provider",
|
|
176
|
-
|
|
177
|
-
|
|
217
|
+
cause: hasUpstreamErrorTestimony(input) ? "provider" : "unrecognized",
|
|
218
|
+
...(diagnostic === undefined ? {} : { diagnostic }),
|
|
219
|
+
...(Object.keys(details).length === 0 ? {} : { details }),
|
|
178
220
|
};
|
|
179
221
|
}
|
|
180
222
|
|
|
@@ -47,7 +47,7 @@ import {
|
|
|
47
47
|
RESUME_TRANSPORT_ENVELOPE,
|
|
48
48
|
RunWriterLeaseHeldError,
|
|
49
49
|
type RunWriterLease,
|
|
50
|
-
|
|
50
|
+
type TypedProviderHttpObservation,
|
|
51
51
|
} from "./run-lifecycle.ts";
|
|
52
52
|
import {
|
|
53
53
|
classifyPostAdmissionFailure,
|
|
@@ -59,7 +59,9 @@ import {
|
|
|
59
59
|
isLawfulTypedTerminalOutcome,
|
|
60
60
|
presentFailureTerminal,
|
|
61
61
|
presentStructuralRejection,
|
|
62
|
-
|
|
62
|
+
resolveAuditedRunnerFailureResolution,
|
|
63
|
+
resolveControlledFailureResumeObservation,
|
|
64
|
+
controlledFailureInputFromResolution,
|
|
63
65
|
explicitInternalKnownFailureClassificationInput,
|
|
64
66
|
settleFailureTerminalResult,
|
|
65
67
|
trySettleFixerTerminalResult,
|
|
@@ -205,6 +207,8 @@ async function presentControlledFailure(
|
|
|
205
207
|
stderr: string;
|
|
206
208
|
thrown?: unknown;
|
|
207
209
|
knownFailure?: ExplicitInternalKnownFailure;
|
|
210
|
+
typedHttpObservationSettled?: true;
|
|
211
|
+
typedHttpObservation?: TypedProviderHttpObservation;
|
|
208
212
|
},
|
|
209
213
|
io: CliIo,
|
|
210
214
|
): Promise<{
|
|
@@ -213,10 +217,23 @@ async function presentControlledFailure(
|
|
|
213
217
|
terminal: TerminalResult;
|
|
214
218
|
}> {
|
|
215
219
|
const hasThrown = Object.hasOwn(failureInput, "thrown");
|
|
220
|
+
const resumeObservation = await resolveControlledFailureResumeObservation({
|
|
221
|
+
runDirectory: admitted.runDirectory,
|
|
222
|
+
...(failureInput.typedHttpObservationSettled === true
|
|
223
|
+
? {
|
|
224
|
+
typedHttpObservationSettled: true as const,
|
|
225
|
+
...(failureInput.typedHttpObservation === undefined
|
|
226
|
+
? {}
|
|
227
|
+
: { typedHttpObservation: failureInput.typedHttpObservation }),
|
|
228
|
+
}
|
|
229
|
+
: {}),
|
|
230
|
+
});
|
|
231
|
+
const knownFailure =
|
|
232
|
+
failureInput.knownFailure ?? resumeObservation.observationReadFailure;
|
|
216
233
|
const session =
|
|
217
234
|
!hasThrown &&
|
|
218
235
|
!failureInput.timedOut &&
|
|
219
|
-
|
|
236
|
+
knownFailure === undefined
|
|
220
237
|
? await inspectJudgeSession(admitted.sessionFile)
|
|
221
238
|
: undefined;
|
|
222
239
|
const failure = classifyPostAdmissionFailure({
|
|
@@ -224,12 +241,12 @@ async function presentControlledFailure(
|
|
|
224
241
|
code: failureInput.code,
|
|
225
242
|
stderr: failureInput.stderr,
|
|
226
243
|
...(hasThrown ? { thrown: failureInput.thrown } : {}),
|
|
227
|
-
...explicitInternalKnownFailureClassificationInput(
|
|
244
|
+
...explicitInternalKnownFailureClassificationInput(knownFailure),
|
|
228
245
|
...(session === undefined ? {} : { session }),
|
|
229
246
|
});
|
|
230
247
|
|
|
231
248
|
const hasLawfulTerminalResult = await hasLawfulFixerTerminalResult(admitted);
|
|
232
|
-
const typedHttp429 =
|
|
249
|
+
const typedHttp429 = resumeObservation.typedHttp429;
|
|
233
250
|
const sessionPrincipalAvailable = await isSessionPrincipalAvailable(
|
|
234
251
|
admitted.sessionFile,
|
|
235
252
|
);
|
|
@@ -295,8 +312,9 @@ async function dispatchAdmittedFixer(input: {
|
|
|
295
312
|
PI_CODING_AGENT_DIR: env.agentDir,
|
|
296
313
|
AK_ROLE_RUN_DIR: admitted.runDirectory,
|
|
297
314
|
};
|
|
298
|
-
|
|
299
|
-
|
|
315
|
+
const correlationId = admitted.correlationId ?? env.correlationId;
|
|
316
|
+
if (correlationId !== undefined && correlationId.trim() !== "") {
|
|
317
|
+
childEnv.AK_CORRELATION_ID = correlationId;
|
|
300
318
|
}
|
|
301
319
|
|
|
302
320
|
let result: ExplicitInternalPiResult;
|
|
@@ -386,10 +404,11 @@ async function dispatchAdmittedFixer(input: {
|
|
|
386
404
|
env.model,
|
|
387
405
|
env.credentials,
|
|
388
406
|
);
|
|
389
|
-
const
|
|
407
|
+
const resolution = await resolveAuditedRunnerFailureResolution({
|
|
390
408
|
runner: result.knownFailure,
|
|
391
409
|
sessionFile: admitted.sessionFile,
|
|
392
410
|
credential: credentialFailure,
|
|
411
|
+
runDirectory: admitted.runDirectory,
|
|
393
412
|
});
|
|
394
413
|
return await presentControlledFailure(
|
|
395
414
|
admitted,
|
|
@@ -397,7 +416,7 @@ async function dispatchAdmittedFixer(input: {
|
|
|
397
416
|
timedOut: result.timedOut,
|
|
398
417
|
code: result.code,
|
|
399
418
|
stderr: result.stderr,
|
|
400
|
-
...(
|
|
419
|
+
...controlledFailureInputFromResolution(resolution),
|
|
401
420
|
},
|
|
402
421
|
io,
|
|
403
422
|
);
|
|
@@ -489,7 +508,10 @@ export async function runPublicFixer(
|
|
|
489
508
|
|
|
490
509
|
return await dispatchAdmittedFixer({
|
|
491
510
|
admitted,
|
|
492
|
-
env
|
|
511
|
+
env: {
|
|
512
|
+
...env,
|
|
513
|
+
...(admitted.correlationId === undefined ? {} : { correlationId: admitted.correlationId }),
|
|
514
|
+
},
|
|
493
515
|
io,
|
|
494
516
|
extraArgs,
|
|
495
517
|
lease,
|
|
@@ -575,7 +597,10 @@ export async function runPublicFixerResume(
|
|
|
575
597
|
|
|
576
598
|
return await dispatchAdmittedFixer({
|
|
577
599
|
admitted,
|
|
578
|
-
env
|
|
600
|
+
env: {
|
|
601
|
+
...env,
|
|
602
|
+
...(admitted.correlationId === undefined ? {} : { correlationId: admitted.correlationId }),
|
|
603
|
+
},
|
|
579
604
|
io,
|
|
580
605
|
extraArgs,
|
|
581
606
|
lease,
|
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
} from "../activation-ledger-topology.ts";
|
|
21
21
|
import { resolveBookKeyFromGit } from "../activation-ledger-git.ts";
|
|
22
22
|
import { roleRunSessionCoordinates } from "../sitian-role-run-coordinates.ts";
|
|
23
|
+
import { resolveTicketNumberFromAttachmentBodies } from "../ticket-frontmatter.ts";
|
|
23
24
|
import {
|
|
24
25
|
loadDoctorCase,
|
|
25
26
|
} from "../doctor-evidence.ts";
|
|
@@ -73,6 +74,16 @@ export type AdmittedRoleInvocationBase = {
|
|
|
73
74
|
/** Exact Pi session file principal (bound at admission; reopened on resume). */
|
|
74
75
|
readonly sessionFile: string;
|
|
75
76
|
readonly admittedRequestPath: string;
|
|
77
|
+
/**
|
|
78
|
+
* Optional opaque invocation correlation restored from a prior admitted page
|
|
79
|
+
* (ADR 0049 host channel). Admission does not mint ticket-binding ids.
|
|
80
|
+
*/
|
|
81
|
+
readonly correlationId?: string;
|
|
82
|
+
/**
|
|
83
|
+
* Typed ticket face from frozen attachment frontmatter (`ticketNumber`).
|
|
84
|
+
* Absent when no attachment carries a valid contract field (unbound).
|
|
85
|
+
*/
|
|
86
|
+
readonly ticketNumber?: number;
|
|
76
87
|
};
|
|
77
88
|
|
|
78
89
|
export type AdmittedJudgeInvocation = AdmittedRoleInvocationBase & {
|
|
@@ -153,7 +164,7 @@ export type AdmittedRoleInvocation =
|
|
|
153
164
|
|
|
154
165
|
type RoleInvocationLedgerSource = Pick<
|
|
155
166
|
AdmittedRoleInvocationBase,
|
|
156
|
-
"runId" | "bookKey" | "projectRoot" | "runDirectory" | "sessionDirectory" | "sessionFile"
|
|
167
|
+
"runId" | "bookKey" | "projectRoot" | "runDirectory" | "sessionDirectory" | "sessionFile" | "correlationId" | "ticketNumber"
|
|
157
168
|
>;
|
|
158
169
|
|
|
159
170
|
/**
|
|
@@ -173,6 +184,8 @@ async function writeRoleInvocationLedger(
|
|
|
173
184
|
runDirectory: source.runDirectory,
|
|
174
185
|
sessionDirectory: source.sessionDirectory,
|
|
175
186
|
sessionFile: source.sessionFile,
|
|
187
|
+
...(source.correlationId === undefined ? {} : { correlationId: source.correlationId }),
|
|
188
|
+
...(source.ticketNumber === undefined ? {} : { ticketNumber: source.ticketNumber }),
|
|
176
189
|
};
|
|
177
190
|
await writeFile(
|
|
178
191
|
join(source.runDirectory, "invocation.json"),
|
|
@@ -525,7 +538,7 @@ async function freezeRegularFileAttachment(
|
|
|
525
538
|
sourcePath: string,
|
|
526
539
|
destinationDir: string,
|
|
527
540
|
index: number,
|
|
528
|
-
): Promise<FrozenAttachment> {
|
|
541
|
+
): Promise<{ attachment: FrozenAttachment; body: Buffer }> {
|
|
529
542
|
const absolute = isAbsolute(sourcePath) ? sourcePath : resolve(sourcePath);
|
|
530
543
|
let st;
|
|
531
544
|
try {
|
|
@@ -546,14 +559,49 @@ async function freezeRegularFileAttachment(
|
|
|
546
559
|
const frozenPath = join(destinationDir, name);
|
|
547
560
|
await writeFile(frozenPath, bytes);
|
|
548
561
|
return {
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
562
|
+
attachment: {
|
|
563
|
+
provenancePath: absolute,
|
|
564
|
+
frozenPath,
|
|
565
|
+
byteLength: bytes.byteLength,
|
|
566
|
+
sha256: sha256Hex(bytes),
|
|
567
|
+
mediaKind: "regular-file",
|
|
568
|
+
},
|
|
569
|
+
body: bytes,
|
|
554
570
|
};
|
|
555
571
|
}
|
|
556
572
|
|
|
573
|
+
/** Freeze attachments and resolve typed ticketNumber from frozen bodies (bind-if-present). */
|
|
574
|
+
async function freezeAttachmentsWithTicketNumber(
|
|
575
|
+
attachmentPaths: readonly string[],
|
|
576
|
+
attachmentsDirectory: string,
|
|
577
|
+
): Promise<{
|
|
578
|
+
readonly attachments: FrozenAttachment[];
|
|
579
|
+
readonly ticketNumber?: number;
|
|
580
|
+
}> {
|
|
581
|
+
const attachments: FrozenAttachment[] = [];
|
|
582
|
+
const bodies: Buffer[] = [];
|
|
583
|
+
for (let i = 0; i < attachmentPaths.length; i += 1) {
|
|
584
|
+
const frozen = await freezeRegularFileAttachment(
|
|
585
|
+
attachmentPaths[i]!,
|
|
586
|
+
attachmentsDirectory,
|
|
587
|
+
i,
|
|
588
|
+
);
|
|
589
|
+
attachments.push(frozen.attachment);
|
|
590
|
+
bodies.push(frozen.body);
|
|
591
|
+
}
|
|
592
|
+
const ticketNumber = resolveTicketNumberFromAttachmentBodies(bodies);
|
|
593
|
+
return {
|
|
594
|
+
attachments,
|
|
595
|
+
...(ticketNumber === undefined ? {} : { ticketNumber }),
|
|
596
|
+
};
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
function ticketAdmissionFields(
|
|
600
|
+
ticketNumber: number | undefined,
|
|
601
|
+
): { ticketNumber?: number } {
|
|
602
|
+
return ticketNumber === undefined ? {} : { ticketNumber };
|
|
603
|
+
}
|
|
604
|
+
|
|
557
605
|
export type AdmitJudgeInvocationOptions = {
|
|
558
606
|
home: string;
|
|
559
607
|
cwd: string;
|
|
@@ -583,16 +631,11 @@ export async function admitJudgeInvocation(
|
|
|
583
631
|
ensureRealDirectoryTree(ledgerHome, sessionDirectory);
|
|
584
632
|
ensureRealDirectoryTree(ledgerHome, attachmentsDirectory);
|
|
585
633
|
|
|
586
|
-
const attachments
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
attachmentsDirectory,
|
|
592
|
-
i,
|
|
593
|
-
),
|
|
594
|
-
);
|
|
595
|
-
}
|
|
634
|
+
const { attachments, ticketNumber } = await freezeAttachmentsWithTicketNumber(
|
|
635
|
+
options.attachmentPaths,
|
|
636
|
+
attachmentsDirectory,
|
|
637
|
+
);
|
|
638
|
+
const ticketFields = ticketAdmissionFields(ticketNumber);
|
|
596
639
|
|
|
597
640
|
const instruction = options.instruction;
|
|
598
641
|
const instructionEmpty = instruction.trim() === "";
|
|
@@ -604,6 +647,7 @@ export async function admitJudgeInvocation(
|
|
|
604
647
|
runDirectory,
|
|
605
648
|
sessionDirectory,
|
|
606
649
|
sessionFile,
|
|
650
|
+
...ticketFields,
|
|
607
651
|
instruction,
|
|
608
652
|
instructionEmpty,
|
|
609
653
|
attachments: attachments.map((a) => ({
|
|
@@ -630,6 +674,7 @@ export async function admitJudgeInvocation(
|
|
|
630
674
|
sessionDirectory,
|
|
631
675
|
sessionFile,
|
|
632
676
|
admittedRequestPath,
|
|
677
|
+
...ticketFields,
|
|
633
678
|
};
|
|
634
679
|
}
|
|
635
680
|
|
|
@@ -721,16 +766,11 @@ export async function admitCoderInvocation(
|
|
|
721
766
|
ensureRealDirectoryTree(ledgerHome, sessionDirectory);
|
|
722
767
|
ensureRealDirectoryTree(ledgerHome, attachmentsDirectory);
|
|
723
768
|
|
|
724
|
-
const attachments
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
attachmentsDirectory,
|
|
730
|
-
i,
|
|
731
|
-
),
|
|
732
|
-
);
|
|
733
|
-
}
|
|
769
|
+
const { attachments, ticketNumber } = await freezeAttachmentsWithTicketNumber(
|
|
770
|
+
options.attachmentPaths,
|
|
771
|
+
attachmentsDirectory,
|
|
772
|
+
);
|
|
773
|
+
const ticketFields = ticketAdmissionFields(ticketNumber);
|
|
734
774
|
|
|
735
775
|
const taskPath = join(runDirectory, "task.md");
|
|
736
776
|
await writeFile(taskPath, instruction, "utf8");
|
|
@@ -744,6 +784,7 @@ export async function admitCoderInvocation(
|
|
|
744
784
|
runDirectory,
|
|
745
785
|
sessionDirectory,
|
|
746
786
|
sessionFile,
|
|
787
|
+
...ticketFields,
|
|
747
788
|
instruction,
|
|
748
789
|
instructionEmpty: false,
|
|
749
790
|
taskPath,
|
|
@@ -773,6 +814,7 @@ export async function admitCoderInvocation(
|
|
|
773
814
|
sessionFile,
|
|
774
815
|
admittedRequestPath,
|
|
775
816
|
taskPath,
|
|
817
|
+
...ticketFields,
|
|
776
818
|
};
|
|
777
819
|
}
|
|
778
820
|
|
|
@@ -828,34 +870,15 @@ export async function admitFixerInvocation(
|
|
|
828
870
|
throw new CliUsageError("fixer phase must be plan or apply");
|
|
829
871
|
}
|
|
830
872
|
|
|
831
|
-
|
|
832
|
-
const runId = (options.createRunId ?? uuidv7)();
|
|
833
|
-
const { ledgerHome, bookKey, runDirectory, sessionDirectory, sessionFile } =
|
|
834
|
-
roleRunSessionCoordinates({ cwd: projectRoot, runId, role: "fixer", home: options.home });
|
|
835
|
-
const attachmentsDirectory = join(runDirectory, "attachments");
|
|
836
|
-
ensureRealDirectoryTree(ledgerHome, sessionDirectory);
|
|
837
|
-
ensureRealDirectoryTree(ledgerHome, attachmentsDirectory);
|
|
838
|
-
|
|
839
|
-
const attachments: FrozenAttachment[] = [];
|
|
840
|
-
for (let i = 0; i < options.attachmentPaths.length; i += 1) {
|
|
841
|
-
attachments.push(
|
|
842
|
-
await freezeRegularFileAttachment(
|
|
843
|
-
options.attachmentPaths[i]!,
|
|
844
|
-
attachmentsDirectory,
|
|
845
|
-
i,
|
|
846
|
-
),
|
|
847
|
-
);
|
|
848
|
-
}
|
|
849
|
-
|
|
873
|
+
// Validate/read prerequisites before freezing request materials.
|
|
850
874
|
let prerequisites: readonly FixerPrerequisite[] = Object.freeze([]);
|
|
851
|
-
let
|
|
875
|
+
let prerequisitesSource: string | undefined;
|
|
852
876
|
if (options.prerequisitesPath !== undefined) {
|
|
853
877
|
const absolutePrereq = isAbsolute(options.prerequisitesPath)
|
|
854
878
|
? options.prerequisitesPath
|
|
855
879
|
: resolve(options.prerequisitesPath);
|
|
856
|
-
let source: string;
|
|
857
880
|
try {
|
|
858
|
-
|
|
881
|
+
prerequisitesSource = await readFile(absolutePrereq, "utf8");
|
|
859
882
|
} catch (error) {
|
|
860
883
|
throw new CliUsageError(
|
|
861
884
|
`fixer prerequisites path is unreadable: ${options.prerequisitesPath}`,
|
|
@@ -863,13 +886,31 @@ export async function admitFixerInvocation(
|
|
|
863
886
|
);
|
|
864
887
|
}
|
|
865
888
|
try {
|
|
866
|
-
prerequisites = parseFixerPrerequisites(
|
|
889
|
+
prerequisites = parseFixerPrerequisites(prerequisitesSource);
|
|
867
890
|
} catch (error) {
|
|
868
891
|
if (error instanceof FixerPacketValidationError) {
|
|
869
892
|
throw new CliUsageError(error.message, { cause: error });
|
|
870
893
|
}
|
|
871
894
|
throw error;
|
|
872
895
|
}
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
const projectRoot = resolve(options.project ?? options.cwd);
|
|
899
|
+
const runId = (options.createRunId ?? uuidv7)();
|
|
900
|
+
const { ledgerHome, bookKey, runDirectory, sessionDirectory, sessionFile } =
|
|
901
|
+
roleRunSessionCoordinates({ cwd: projectRoot, runId, role: "fixer", home: options.home });
|
|
902
|
+
const attachmentsDirectory = join(runDirectory, "attachments");
|
|
903
|
+
ensureRealDirectoryTree(ledgerHome, sessionDirectory);
|
|
904
|
+
ensureRealDirectoryTree(ledgerHome, attachmentsDirectory);
|
|
905
|
+
|
|
906
|
+
const { attachments, ticketNumber } = await freezeAttachmentsWithTicketNumber(
|
|
907
|
+
options.attachmentPaths,
|
|
908
|
+
attachmentsDirectory,
|
|
909
|
+
);
|
|
910
|
+
const ticketFields = ticketAdmissionFields(ticketNumber);
|
|
911
|
+
|
|
912
|
+
let prerequisitesPath: string | undefined;
|
|
913
|
+
if (prerequisitesSource !== undefined) {
|
|
873
914
|
prerequisitesPath = join(runDirectory, "prerequisites.json");
|
|
874
915
|
await writeFile(
|
|
875
916
|
prerequisitesPath,
|
|
@@ -890,6 +931,7 @@ export async function admitFixerInvocation(
|
|
|
890
931
|
runDirectory,
|
|
891
932
|
sessionDirectory,
|
|
892
933
|
sessionFile,
|
|
934
|
+
...ticketFields,
|
|
893
935
|
instruction,
|
|
894
936
|
instructionEmpty: false,
|
|
895
937
|
packetPath,
|
|
@@ -926,6 +968,7 @@ export async function admitFixerInvocation(
|
|
|
926
968
|
packetPath,
|
|
927
969
|
...(prerequisitesPath === undefined ? {} : { prerequisitesPath }),
|
|
928
970
|
prerequisites,
|
|
971
|
+
...ticketFields,
|
|
929
972
|
};
|
|
930
973
|
}
|
|
931
974
|
|
|
@@ -1103,6 +1146,19 @@ export async function admitCollectorInvocation(
|
|
|
1103
1146
|
repository = resolveGitHubRemoteRepository(projectRoot);
|
|
1104
1147
|
}
|
|
1105
1148
|
|
|
1149
|
+
// Validate optional request-manifest before freezing request materials.
|
|
1150
|
+
let manifest = emptyCollectorManifest();
|
|
1151
|
+
let manifestCanonicalJson: string | undefined;
|
|
1152
|
+
if (options.requestManifestPath !== undefined) {
|
|
1153
|
+
try {
|
|
1154
|
+
manifest = await loadCollectorManifest(options.requestManifestPath);
|
|
1155
|
+
manifestCanonicalJson = manifest.canonicalJson;
|
|
1156
|
+
} catch (error) {
|
|
1157
|
+
throw new CliUsageError(error instanceof Error ? error.message : String(error), { cause: error });
|
|
1158
|
+
}
|
|
1159
|
+
}
|
|
1160
|
+
const manifestDigest = manifest.digest;
|
|
1161
|
+
|
|
1106
1162
|
const runId = (options.createRunId ?? uuidv7)();
|
|
1107
1163
|
const { ledgerHome, bookKey, runDirectory, sessionDirectory, sessionFile } =
|
|
1108
1164
|
roleRunSessionCoordinates({ cwd: projectRoot, runId, role: "collector", home: options.home });
|
|
@@ -1110,30 +1166,17 @@ export async function admitCollectorInvocation(
|
|
|
1110
1166
|
ensureRealDirectoryTree(ledgerHome, sessionDirectory);
|
|
1111
1167
|
ensureRealDirectoryTree(ledgerHome, attachmentsDirectory);
|
|
1112
1168
|
|
|
1113
|
-
const attachments
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
attachmentPaths[i]!,
|
|
1119
|
-
attachmentsDirectory,
|
|
1120
|
-
i,
|
|
1121
|
-
),
|
|
1122
|
-
);
|
|
1123
|
-
}
|
|
1169
|
+
const { attachments, ticketNumber } = await freezeAttachmentsWithTicketNumber(
|
|
1170
|
+
options.attachmentPaths ?? [],
|
|
1171
|
+
attachmentsDirectory,
|
|
1172
|
+
);
|
|
1173
|
+
const ticketFields = ticketAdmissionFields(ticketNumber);
|
|
1124
1174
|
|
|
1125
|
-
let manifest = emptyCollectorManifest();
|
|
1126
1175
|
let requestManifestPath: string | undefined;
|
|
1127
|
-
if (
|
|
1128
|
-
try {
|
|
1129
|
-
manifest = await loadCollectorManifest(options.requestManifestPath);
|
|
1130
|
-
} catch (error) {
|
|
1131
|
-
throw new CliUsageError(error instanceof Error ? error.message : String(error), { cause: error });
|
|
1132
|
-
}
|
|
1176
|
+
if (manifestCanonicalJson !== undefined) {
|
|
1133
1177
|
requestManifestPath = join(runDirectory, "request-manifest.json");
|
|
1134
|
-
await writeFile(requestManifestPath,
|
|
1178
|
+
await writeFile(requestManifestPath, manifestCanonicalJson, "utf8");
|
|
1135
1179
|
}
|
|
1136
|
-
const manifestDigest = manifest.digest;
|
|
1137
1180
|
|
|
1138
1181
|
const instruction = options.instruction ?? "";
|
|
1139
1182
|
const instructionEmpty = instruction.trim() === "";
|
|
@@ -1145,6 +1188,7 @@ export async function admitCollectorInvocation(
|
|
|
1145
1188
|
runDirectory,
|
|
1146
1189
|
sessionDirectory,
|
|
1147
1190
|
sessionFile,
|
|
1191
|
+
...ticketFields,
|
|
1148
1192
|
instruction,
|
|
1149
1193
|
instructionEmpty,
|
|
1150
1194
|
prNumber,
|
|
@@ -1184,6 +1228,7 @@ export async function admitCollectorInvocation(
|
|
|
1184
1228
|
repository,
|
|
1185
1229
|
...(requestManifestPath === undefined ? {} : { requestManifestPath }),
|
|
1186
1230
|
manifestDigest,
|
|
1231
|
+
...ticketFields,
|
|
1187
1232
|
};
|
|
1188
1233
|
}
|
|
1189
1234
|
|
|
@@ -1462,17 +1507,11 @@ export async function admitDoctorInvocation(
|
|
|
1462
1507
|
ensureRealDirectoryTree(ledgerHome, sessionDirectory);
|
|
1463
1508
|
ensureRealDirectoryTree(ledgerHome, attachmentsDirectory);
|
|
1464
1509
|
|
|
1465
|
-
const attachments
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
attachmentPaths[i]!,
|
|
1471
|
-
attachmentsDirectory,
|
|
1472
|
-
i,
|
|
1473
|
-
),
|
|
1474
|
-
);
|
|
1475
|
-
}
|
|
1510
|
+
const { attachments, ticketNumber } = await freezeAttachmentsWithTicketNumber(
|
|
1511
|
+
options.attachmentPaths ?? [],
|
|
1512
|
+
attachmentsDirectory,
|
|
1513
|
+
);
|
|
1514
|
+
const ticketFields = ticketAdmissionFields(ticketNumber);
|
|
1476
1515
|
|
|
1477
1516
|
const instruction = options.instruction ?? "";
|
|
1478
1517
|
const instructionEmpty = instruction.trim() === "";
|
|
@@ -1484,6 +1523,7 @@ export async function admitDoctorInvocation(
|
|
|
1484
1523
|
runDirectory,
|
|
1485
1524
|
sessionDirectory,
|
|
1486
1525
|
sessionFile,
|
|
1526
|
+
...ticketFields,
|
|
1487
1527
|
instruction,
|
|
1488
1528
|
instructionEmpty,
|
|
1489
1529
|
issueNumber: options.issueNumber,
|
|
@@ -1520,6 +1560,7 @@ export async function admitDoctorInvocation(
|
|
|
1520
1560
|
issueNumber: options.issueNumber,
|
|
1521
1561
|
caseRunsPath,
|
|
1522
1562
|
caseIdentity,
|
|
1563
|
+
...ticketFields,
|
|
1523
1564
|
};
|
|
1524
1565
|
}
|
|
1525
1566
|
|
|
@@ -1625,16 +1666,11 @@ export async function admitReviewerInvocation(
|
|
|
1625
1666
|
ensureRealDirectoryTree(ledgerHome, attachmentsDirectory);
|
|
1626
1667
|
|
|
1627
1668
|
// Public parse already rejects attachments; keep freeze loop for structural symmetry.
|
|
1628
|
-
const attachments
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
attachmentsDirectory,
|
|
1634
|
-
i,
|
|
1635
|
-
),
|
|
1636
|
-
);
|
|
1637
|
-
}
|
|
1669
|
+
const { attachments, ticketNumber } = await freezeAttachmentsWithTicketNumber(
|
|
1670
|
+
options.attachmentPaths,
|
|
1671
|
+
attachmentsDirectory,
|
|
1672
|
+
);
|
|
1673
|
+
const ticketFields = ticketAdmissionFields(ticketNumber);
|
|
1638
1674
|
|
|
1639
1675
|
const instruction = options.instruction;
|
|
1640
1676
|
const instructionEmpty = instruction.trim() === "";
|
|
@@ -1646,6 +1682,7 @@ export async function admitReviewerInvocation(
|
|
|
1646
1682
|
runDirectory,
|
|
1647
1683
|
sessionDirectory,
|
|
1648
1684
|
sessionFile,
|
|
1685
|
+
...ticketFields,
|
|
1649
1686
|
instruction,
|
|
1650
1687
|
instructionEmpty,
|
|
1651
1688
|
baseRevision: options.baseRevision,
|
|
@@ -1678,6 +1715,7 @@ export async function admitReviewerInvocation(
|
|
|
1678
1715
|
sessionFile,
|
|
1679
1716
|
admittedRequestPath,
|
|
1680
1717
|
baseRevision: options.baseRevision,
|
|
1718
|
+
...ticketFields,
|
|
1681
1719
|
};
|
|
1682
1720
|
}
|
|
1683
1721
|
|
|
@@ -1845,16 +1883,11 @@ export async function admitMergerInvocation(
|
|
|
1845
1883
|
ensureRealDirectoryTree(ledgerHome, sessionDirectory);
|
|
1846
1884
|
ensureRealDirectoryTree(ledgerHome, attachmentsDirectory);
|
|
1847
1885
|
|
|
1848
|
-
const attachments
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
attachmentsDirectory,
|
|
1854
|
-
i,
|
|
1855
|
-
),
|
|
1856
|
-
);
|
|
1857
|
-
}
|
|
1886
|
+
const { attachments, ticketNumber } = await freezeAttachmentsWithTicketNumber(
|
|
1887
|
+
options.attachmentPaths,
|
|
1888
|
+
attachmentsDirectory,
|
|
1889
|
+
);
|
|
1890
|
+
const ticketFields = ticketAdmissionFields(ticketNumber);
|
|
1858
1891
|
|
|
1859
1892
|
// Intent materials seed primary-source investigation; the method owns the work.
|
|
1860
1893
|
const targetIntent = mergerMaterialFromUtf8(
|
|
@@ -1866,6 +1899,7 @@ export async function admitMergerInvocation(
|
|
|
1866
1899
|
const taskMaterial = mergerMaterialFromUtf8(instruction);
|
|
1867
1900
|
const authorityMaterial = mergerMaterialFromUtf8(instruction);
|
|
1868
1901
|
|
|
1902
|
+
// Validate merger envelope before placing admitted identity.
|
|
1869
1903
|
const mergerInput = validateMergerInput({
|
|
1870
1904
|
version: 1,
|
|
1871
1905
|
attemptId: runId,
|
|
@@ -1898,6 +1932,7 @@ export async function admitMergerInvocation(
|
|
|
1898
1932
|
runDirectory,
|
|
1899
1933
|
sessionDirectory,
|
|
1900
1934
|
sessionFile,
|
|
1935
|
+
...ticketFields,
|
|
1901
1936
|
instruction,
|
|
1902
1937
|
instructionEmpty: false,
|
|
1903
1938
|
mergerInputPath,
|
|
@@ -1938,6 +1973,7 @@ export async function admitMergerInvocation(
|
|
|
1938
1973
|
admittedRequestPath,
|
|
1939
1974
|
mergerInputPath,
|
|
1940
1975
|
derived: admitted.derived,
|
|
1976
|
+
...ticketFields,
|
|
1941
1977
|
};
|
|
1942
1978
|
}
|
|
1943
1979
|
|