@akagilnc/pi-workflow-roles 0.1.3685 → 0.1.3702
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 +499 -559
- package/dist/analyst-gate-cycles-read.js +11 -1
- package/dist/archivist-record-entry.js +1 -1
- package/dist/auditor-dossier-tool.js +12 -0
- package/dist/dossier-resolution.js +0 -35
- package/dist/gatekeeper-pass-envelope.js +39 -34
- package/dist/gatekeeper-role.js +70 -77
- package/dist/judge-auditor.js +5 -24
- package/dist/judge-role.js +39 -42
- package/dist/notary-contracts.js +2 -17
- package/dist/notary-role.js +3 -6
- package/dist/package-contracts/judge-output.js +0 -2
- package/dist/package-contracts/terminating-tools.js +2 -2
- package/dist/public-cli/inspector-run.js +16 -2
- package/dist/public-cli/instruction-seat-run.js +14 -2
- package/dist/public-cli/main.js +189 -214
- package/dist/public-cli/notary-run.js +23 -20
- package/dist/public-cli/post-admission.js +30 -23
- package/dist/public-cli/run-lifecycle.js +6 -14
- package/dist/public-role-summons.js +38 -11
- package/dist/role-runtime.js +28 -3
- package/dist/submission-correctable-error.js +2 -1
- package/dist/submission-errors.js +26 -11
- package/dist/submission-ledger.js +7 -23
- package/extensions/role-runtime.ts +0 -2
- package/package.json +1 -1
- package/souls/countersign.md +12 -11
- package/souls/notary.md +5 -0
- package/src/acp-host/production-host.ts +1 -4
- package/src/acp-host/role-envelope.ts +1 -1
- package/src/analyst-gate-cycles-read.ts +10 -1
- package/src/archivist-record-entry.ts +7 -3
- package/src/auditor-dossier-tool.ts +21 -0
- package/src/dossier-resolution.ts +0 -39
- package/src/gatekeeper-pass-envelope.ts +59 -43
- package/src/gatekeeper-role.ts +114 -113
- package/src/host-contracts.ts +3 -3
- package/src/judge-auditor.ts +5 -43
- package/src/judge-role.ts +41 -54
- package/src/notary-contracts.ts +8 -27
- package/src/notary-role.ts +2 -7
- package/src/package-contracts/judge-output.ts +0 -1
- package/src/package-contracts/terminating-tools.ts +2 -2
- package/src/public-cli/inspector-run.ts +32 -2
- package/src/public-cli/instruction-seat-run.ts +30 -2
- package/src/public-cli/notary-run.ts +48 -16
- package/src/public-cli/post-admission.ts +31 -37
- package/src/public-cli/run-lifecycle.ts +6 -17
- package/src/public-role-summons.ts +76 -12
- package/src/role-runtime.ts +34 -9
- package/src/submission-correctable-error.ts +2 -0
- package/src/submission-errors.ts +28 -11
- package/src/submission-ledger.ts +8 -32
- package/dist/shape-unreadable-failure.js +0 -34
|
@@ -1,18 +1,10 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Public Notary Role run: admit source-run locator → shared post-admission coordinator
|
|
3
|
-
* → settle Terminal result (#448 / #517). Zero caller prompt/attachment. Lifecycle is
|
|
4
|
-
* the shared post-admission seam; this module keeps only Notary adapters.
|
|
5
|
-
* #637 / #747: same-parent (--source-run) re-summons resume the seat's previous run.
|
|
6
|
-
*/
|
|
7
|
-
import { existsSync } from "node:fs";
|
|
8
|
-
import { gateSubmissionCandidatePath } from "../auditor-dossier-tool.js";
|
|
9
1
|
import { NotarySourceRunError, resolveNotarySourceRunLocator, } from "../notary-source-run.js";
|
|
10
2
|
import { engineSessionMaterialFromOptions } from "../package-resources/engine-material.js";
|
|
11
3
|
import { CliUsageError } from "./cli-errors.js";
|
|
12
4
|
import { admitNotaryInvocation, buildNotaryTransportPrompt, } from "./invocation.js";
|
|
13
5
|
import { tryResumeSameTicketSeatRun } from "./seat-ticket-binding.js";
|
|
14
|
-
import { runPostAdmissionOneShot, runPostAdmissionSeatResume, resumeTurnRequestProjectionOptions, } from "./post-admission.js";
|
|
15
|
-
import {
|
|
6
|
+
import { prepareSummonsResumeMaterials, runPostAdmissionOneShot, runPostAdmissionSeatResume, resumeTurnRequestProjectionOptions, } from "./post-admission.js";
|
|
7
|
+
import { loadResumableNotaryRun, markRunAdmitted, } from "./run-lifecycle.js";
|
|
16
8
|
import { presentStructuralRejection, trySettleNotaryTerminalResult, } from "./settlement.js";
|
|
17
9
|
import { projectRoleTurnRequest, } from "./turn-request.js";
|
|
18
10
|
/** Project admitted invocation onto the host-neutral turn request. */
|
|
@@ -60,10 +52,16 @@ export async function runPublicNotary(argv, env, io, parseNotaryArgv) {
|
|
|
60
52
|
throw error;
|
|
61
53
|
}
|
|
62
54
|
// #747: officer resume key is this parent source-run path (not ticket number).
|
|
55
|
+
// #753: gate re-ask and new-submission pointers share summons.instruction
|
|
56
|
+
// (reask wins when both present; no parallel stack).
|
|
63
57
|
{
|
|
58
|
+
const resumeInstruction = env.reviewReask ?? env.gateReviewInstruction;
|
|
64
59
|
const summons = {
|
|
65
60
|
sourceRunPath: source.runDirectory,
|
|
66
61
|
sourceRun: source,
|
|
62
|
+
...(resumeInstruction === undefined
|
|
63
|
+
? {}
|
|
64
|
+
: { instruction: resumeInstruction, instructionEmpty: false }),
|
|
67
65
|
};
|
|
68
66
|
const resumed = await tryResumeSameTicketSeatRun({
|
|
69
67
|
home: env.home,
|
|
@@ -76,6 +74,13 @@ export async function runPublicNotary(argv, env, io, parseNotaryArgv) {
|
|
|
76
74
|
});
|
|
77
75
|
if (resumed !== undefined)
|
|
78
76
|
return resumed;
|
|
77
|
+
// Reask without a prior same-parent run cannot deliver the plain-language ask
|
|
78
|
+
// on a fresh mint without inventing a second prompt path — fail loud (#753).
|
|
79
|
+
// gateReviewInstruction alone is resume-only materials; fresh mint ignores it.
|
|
80
|
+
if (env.reviewReask !== undefined) {
|
|
81
|
+
presentStructuralRejection(new CliUsageError("notary review reask requires a prior same-parent run to resume"), io);
|
|
82
|
+
return { exitCode: 2 };
|
|
83
|
+
}
|
|
79
84
|
}
|
|
80
85
|
let admitted;
|
|
81
86
|
try {
|
|
@@ -161,16 +166,14 @@ export async function runPublicNotaryResume(request, env, io) {
|
|
|
161
166
|
}
|
|
162
167
|
return loaded;
|
|
163
168
|
},
|
|
164
|
-
buildTurnRequest: (admitted, effective) => {
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
continuation: { kind: "resume", prompt },
|
|
173
|
-
});
|
|
169
|
+
buildTurnRequest: async (admitted, effective) => {
|
|
170
|
+
// #755: review continuation is plain dialogue / resume envelope — no
|
|
171
|
+
//「重新读」candidate line, no engine handbook packaging.
|
|
172
|
+
// #753: non-three-state re-ask rides as summons.instruction (人话重问).
|
|
173
|
+
const summonsPrepared = effective.summons === undefined
|
|
174
|
+
? undefined
|
|
175
|
+
: await prepareSummonsResumeMaterials(admitted.runDirectory, effective.summons);
|
|
176
|
+
return buildNotaryTurnRequest(admitted, resumeTurnRequestProjectionOptions(admitted, effective, env, summonsPrepared));
|
|
174
177
|
},
|
|
175
178
|
adapters: notaryAdapters(),
|
|
176
179
|
...(env.engine === undefined ? {} : { effectiveEngine: env.engine }),
|
|
@@ -8,11 +8,10 @@
|
|
|
8
8
|
import { randomUUID } from "node:crypto";
|
|
9
9
|
import { readFile, writeFile } from "node:fs/promises";
|
|
10
10
|
import { isAbsolute, join, resolve } from "node:path";
|
|
11
|
-
import { buildResumeContinuationPrompt,
|
|
11
|
+
import { buildResumeContinuationPrompt, RESUME_TRANSPORT_ENVELOPE, } from "./run-lifecycle.js";
|
|
12
12
|
import { CliUsageError } from "./cli-errors.js";
|
|
13
13
|
import { buildInstructionTransportPrompt, freezeAttachmentsIntoRun, } from "./invocation.js";
|
|
14
14
|
import { pathContainedIn } from "../activation-ledger-topology.js";
|
|
15
|
-
import { engineSessionMaterialFromOptions } from "../package-resources/engine-material.js";
|
|
16
15
|
import { projectCaseDossierPointerSection } from "./case-dossier-delivery.js";
|
|
17
16
|
/** Append one system section to a continuation prompt, keeping its kind. */
|
|
18
17
|
function appendContinuationSection(continuation, section) {
|
|
@@ -259,36 +258,37 @@ export async function dispatchPostAdmissionTurn(input) {
|
|
|
259
258
|
}
|
|
260
259
|
}
|
|
261
260
|
/**
|
|
262
|
-
* Shared resume continuation projection (#471 / #600 / #633 / #637):
|
|
263
|
-
* model/engine/timeout axes, restored correlation, and either
|
|
264
|
-
* - manual resume: package envelope / optional caller
|
|
265
|
-
*
|
|
266
|
-
*
|
|
267
|
-
*
|
|
268
|
-
*
|
|
261
|
+
* Shared resume continuation projection (#471 / #600 / #633 / #637 / #755):
|
|
262
|
+
* seat-table model/engine/timeout axes, restored correlation, and either
|
|
263
|
+
* - manual resume (no same-ticket summons): package envelope / optional caller
|
|
264
|
+
* message, with engine-axis handbook via buildResumeContinuationPrompt, or
|
|
265
|
+
* - same-ticket summons (审核循环续话): caller/peer words + optional frozen
|
|
266
|
+
* attachment paths only — no「重新读」、no engine handbook packaging
|
|
267
|
+
* (#750/#755), whether or not attachments are present.
|
|
268
|
+
* Caller message wins as prompt base when supplied (bytes unchanged, including
|
|
269
|
+
* blank/whitespace); else summons instruction. Attachment projection must not
|
|
270
|
+
* re-interpret the caller message as instructionEmpty.
|
|
269
271
|
* Seats add only their activation projection. Call prepareSummonsResumeMaterials
|
|
270
|
-
* first when request.summons carries attachment paths.
|
|
272
|
+
* first when request.summons carries instruction or attachment paths.
|
|
271
273
|
*/
|
|
272
274
|
export function resumeTurnRequestProjectionOptions(admitted, request, env, summonsPrepared) {
|
|
273
|
-
const engineMaterial = engineSessionMaterialFromOptions({
|
|
274
|
-
...(env.engine === undefined ? {} : { engine: env.engine }),
|
|
275
|
-
packageRoot: env.packageRoot,
|
|
276
|
-
});
|
|
277
275
|
let prompt;
|
|
278
276
|
if (request.message !== undefined) {
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
if (summonsPrepared !== undefined &&
|
|
284
|
-
summonsPrepared.attachments.length > 0) {
|
|
285
|
-
prompt = instructResumeHandbookRead(buildInstructionTransportPrompt({
|
|
277
|
+
if (summonsPrepared !== undefined) {
|
|
278
|
+
// #755: same-ticket review / open-court — caller words + optional paths.
|
|
279
|
+
// Attachments are not a gate: message-only summons must stay plain too.
|
|
280
|
+
prompt = buildInstructionTransportPrompt({
|
|
286
281
|
instruction: request.message,
|
|
287
282
|
instructionEmpty: false,
|
|
288
283
|
attachments: summonsPrepared.attachments,
|
|
289
|
-
}
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
else if (request.summons !== undefined) {
|
|
287
|
+
// #755: same-ticket summons without prepared materials — caller words only.
|
|
288
|
+
prompt = request.message;
|
|
290
289
|
}
|
|
291
290
|
else {
|
|
291
|
+
// Bare manual resume — outsourcing engine axis keeps handbook (#600/#736).
|
|
292
292
|
prompt = buildResumeContinuationPrompt({
|
|
293
293
|
packageRoot: env.packageRoot,
|
|
294
294
|
...(env.engine === undefined ? {} : { engine: env.engine }),
|
|
@@ -297,9 +297,16 @@ export function resumeTurnRequestProjectionOptions(admitted, request, env, summo
|
|
|
297
297
|
}
|
|
298
298
|
}
|
|
299
299
|
else if (summonsPrepared !== undefined) {
|
|
300
|
-
|
|
300
|
+
// #755: same-ticket review summons — instruction/attachments only.
|
|
301
|
+
prompt = buildInstructionTransportPrompt(summonsPrepared);
|
|
302
|
+
}
|
|
303
|
+
else if (request.summons !== undefined) {
|
|
304
|
+
// #755: same-ticket summons with no instruction/attachments (e.g. notary
|
|
305
|
+
// source-run pointer) — plain resume envelope, no handbook / 重新读.
|
|
306
|
+
prompt = RESUME_TRANSPORT_ENVELOPE;
|
|
301
307
|
}
|
|
302
308
|
else {
|
|
309
|
+
// Bare manual resume — outsourcing engine axis keeps handbook (#600/#736).
|
|
303
310
|
prompt = buildResumeContinuationPrompt({
|
|
304
311
|
packageRoot: env.packageRoot,
|
|
305
312
|
...(env.engine === undefined ? {} : { engine: env.engine }),
|
|
@@ -32,11 +32,10 @@ function resumeRereadInstruction(materialPath, handbook) {
|
|
|
32
32
|
: `重新读 ${materialPath}`;
|
|
33
33
|
}
|
|
34
34
|
/**
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
* Handbook keeps the argv suffix; other materials are path-only.
|
|
35
|
+
* Engine-axis resume-only material lines (#736 / ADR 0069·0071).
|
|
36
|
+
* #755 withdrew this rewrite from 审核循环续话; review same-ticket resume stays
|
|
37
|
+
* plain dialogue via resumeTurnRequestProjectionOptions. Outsourcing resume
|
|
38
|
+
* still rewrites neutral handbook/path pointers into 重新读 instructions.
|
|
40
39
|
* First-round delivery is unchanged; never pastes material body.
|
|
41
40
|
*/
|
|
42
41
|
export function instructResumeHandbookRead(prompt, engineMaterial) {
|
|
@@ -56,16 +55,9 @@ export function instructResumeHandbookRead(prompt, engineMaterial) {
|
|
|
56
55
|
})
|
|
57
56
|
.join("\n");
|
|
58
57
|
}
|
|
59
|
-
/** Append a live-path reread instruction when the pointer is not already on the continuation. */
|
|
60
|
-
export function appendResumeMaterialReread(prompt, materialPath) {
|
|
61
|
-
const instruction = resumeRereadInstruction(materialPath, false);
|
|
62
|
-
const lines = prompt.split("\n");
|
|
63
|
-
if (lines.includes(instruction))
|
|
64
|
-
return prompt;
|
|
65
|
-
return prompt.length === 0 ? instruction : `${prompt}\n${instruction}`;
|
|
66
|
-
}
|
|
67
58
|
/**
|
|
68
|
-
* Unique continuation-prompt selector for manual/auto resume
|
|
59
|
+
* Unique continuation-prompt selector for manual/auto engine-axis resume
|
|
60
|
+
* (#471 / #600 / #736). Not used for 审核循环 same-ticket summons (#755).
|
|
69
61
|
* Message present → base bytes unchanged; absent → package transport envelope.
|
|
70
62
|
* When engine material is present, append structured engine coordinates then
|
|
71
63
|
* rewrite absolute material pointer lines into 重新读 instructions. Zero parse,
|
|
@@ -162,7 +162,11 @@ async function summonPublicRole(options) {
|
|
|
162
162
|
// Host config passthrough only — same face as public CLI (#422 / #675).
|
|
163
163
|
...config.autoResumeLimit === void 0 ? {} : { autoResumeLimit: config.autoResumeLimit },
|
|
164
164
|
// Parent cancellation reaches the nested activation's own turn dispatch.
|
|
165
|
-
...options.signal === void 0 ? {} : { signal: options.signal }
|
|
165
|
+
...options.signal === void 0 ? {} : { signal: options.signal },
|
|
166
|
+
// #753: reask rides the existing notary same-ticket resume summons.instruction.
|
|
167
|
+
...options.reviewReask === void 0 ? {} : { reviewReask: options.reviewReask },
|
|
168
|
+
// #753/#750: new-submission pointers on same-parent resume (not conclusion re-ask).
|
|
169
|
+
...options.gateReviewInstruction === void 0 ? {} : { gateReviewInstruction: options.gateReviewInstruction }
|
|
166
170
|
};
|
|
167
171
|
const captured = options.io === void 0 ? createCapturingIo() : void 0;
|
|
168
172
|
const io = options.io ?? captured.io;
|
|
@@ -258,25 +262,48 @@ async function summonGateOfficer(options) {
|
|
|
258
262
|
const { homeFromRunDirectory } = await import("./activation-ledger-topology.js");
|
|
259
263
|
home = homeFromRunDirectory(options.sourceRunDirectory);
|
|
260
264
|
}
|
|
265
|
+
let gateReviewInstruction;
|
|
266
|
+
if (options.reask === void 0) {
|
|
267
|
+
const { buildGateOfficerReviewInstruction } = await import("./auditor-dossier-tool.js");
|
|
268
|
+
gateReviewInstruction = buildGateOfficerReviewInstruction({
|
|
269
|
+
sourceRunDirectory: options.sourceRunDirectory,
|
|
270
|
+
...options.submissionCandidatePath === void 0 ? {} : { submissionCandidatePath: options.submissionCandidatePath }
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
const common = {
|
|
274
|
+
cwd: options.cwd,
|
|
275
|
+
...home === void 0 ? {} : { home },
|
|
276
|
+
...options.packageRoot === void 0 ? {} : { packageRoot: options.packageRoot },
|
|
277
|
+
...options.io === void 0 ? {} : { io: options.io },
|
|
278
|
+
...options.signal === void 0 ? {} : { signal: options.signal },
|
|
279
|
+
...options.reask === void 0 ? {} : { reviewReask: options.reask },
|
|
280
|
+
...gateReviewInstruction === void 0 ? {} : { gateReviewInstruction }
|
|
281
|
+
};
|
|
261
282
|
if (options.officer === "notary") {
|
|
262
283
|
return summonPublicRole({
|
|
263
284
|
role: "notary",
|
|
264
285
|
argv: ["--source-run", options.sourceRunDirectory, "--project", options.cwd],
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
286
|
+
...common
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
if (options.officer === "auditor") {
|
|
290
|
+
const { AUDITOR_DOSSIER_PROMPT } = await import("./compliance-transport.js");
|
|
291
|
+
return summonPublicRole({
|
|
292
|
+
role: "auditor",
|
|
293
|
+
argv: [
|
|
294
|
+
"--subject",
|
|
295
|
+
"judge",
|
|
296
|
+
"--source-run",
|
|
297
|
+
options.sourceRunDirectory,
|
|
298
|
+
AUDITOR_DOSSIER_PROMPT
|
|
299
|
+
],
|
|
300
|
+
...common
|
|
270
301
|
});
|
|
271
302
|
}
|
|
272
303
|
return summonPublicRole({
|
|
273
304
|
role: "inspector",
|
|
274
305
|
argv: [`\u5377\u5B97\u6307\u9488\uFF1A${options.sourceRunDirectory}`],
|
|
275
|
-
|
|
276
|
-
...home === void 0 ? {} : { home },
|
|
277
|
-
...options.packageRoot === void 0 ? {} : { packageRoot: options.packageRoot },
|
|
278
|
-
...options.io === void 0 ? {} : { io: options.io },
|
|
279
|
-
...options.signal === void 0 ? {} : { signal: options.signal }
|
|
306
|
+
...common
|
|
280
307
|
});
|
|
281
308
|
}
|
|
282
309
|
export {
|
package/dist/role-runtime.js
CHANGED
|
@@ -183,6 +183,8 @@ export { ACCEPTED_ACTIVATION_EVENT, ACCEPTED_ACTIVATION_FACT_KEYS, ActivationGit
|
|
|
183
183
|
export { DISPATCH_STUB_EVENT, buildDispatchStubFact, reconcileInvocation, } from "./activation-reconciliation.js";
|
|
184
184
|
export { TOOL_EXECUTION_UPDATE_HEARTBEAT, TOOL_EXECUTION_UPDATE_THROTTLE_MS, createToolExecutionObservationFace, isProducingToolUpdate, systemToolExecutionObservationMonoNow, toolExecutionObservationRecordSchema, validateToolExecutionObservationRecord, writeToolExecutionObservationRecord, } from "./tool-execution-observation.js";
|
|
185
185
|
export { NOTARY_OUTPUT_TOOL, INSPECTOR_OUTPUT_TOOL, GatekeeperDecisionError, createGatekeeperOutputTool, runGatekeeper, } from "./gatekeeper-role.js";
|
|
186
|
+
export { gateOfficerForSubject } from "./gatekeeper-role.js";
|
|
187
|
+
import { ParentQueueReaskError } from "./submission-errors.js";
|
|
186
188
|
export { DOCTOR_EVIDENCE_TOOL_NAME, DOCTOR_OUTPUT_TOOL_NAME, } from "./doctor-role.js";
|
|
187
189
|
export { validateDoctorSubmissionShape, validateDoctorOutput, DoctorEvidenceStore } from "./doctor-contracts.js";
|
|
188
190
|
export { loadDoctorCase } from "./doctor-evidence.js";
|
|
@@ -194,7 +196,7 @@ export { fixerOutputSchema, validateFixerOutput, validateFixerOutputForPacket }
|
|
|
194
196
|
export { fixerPrerequisiteSchema, fixerPrerequisitesSchema, parseFixerPrerequisites, validateFixerPrerequisites } from "./package-contracts/fixer-packet.js";
|
|
195
197
|
export { AUDIT_ESCALATION_KIND, buildAuditEscalationResult, disposeComplianceDecision, isAuditEscalationResult, projectAuditEscalation } from "./audit-escalation.js";
|
|
196
198
|
export { AUDITOR_SOUL_ROLES, AK_ROLE_AUDITOR_SUBJECT_ENV, loadAuditorSoul, loadAuditorSoulFromSubjectInput, resolveAuditorSubject, } from "./auditor-soul.js";
|
|
197
|
-
export { JUDGE_AUDIT_TOOL_NAME, SOUL_AUDIT_TOOL_NAME
|
|
199
|
+
export { JUDGE_AUDIT_TOOL_NAME, SOUL_AUDIT_TOOL_NAME } from "./judge-auditor.js";
|
|
198
200
|
export { DOCTOR_AUDIT_TOOL_NAME, createPiDoctorAuditor } from "./doctor-auditor.js";
|
|
199
201
|
export { COLLECTOR_OBSERVE_TOOL, COLLECTOR_OUTPUT_TOOL, COLLECTOR_READ_TOOL, COLLECTOR_REQUEST_TOOL, COLLECTOR_WAIT_TOOL, } from "./collector-role.js";
|
|
200
202
|
export * from "./navigator-attendance.js";
|
|
@@ -630,11 +632,35 @@ function loadFrozenDiaristCatalog(getFlag) {
|
|
|
630
632
|
}
|
|
631
633
|
return loadDiaristSourceCatalog(raw);
|
|
632
634
|
}
|
|
635
|
+
/** Countersign status words the queue reads (#753). */
|
|
636
|
+
const COUNTERSIGN_QUEUE_STATUSES = new Set(["converged", "continue", "escalate"]);
|
|
637
|
+
/**
|
|
638
|
+
* Plain-language re-ask when countersignStatus is not a known queue word.
|
|
639
|
+
* Back to countersign itself — notary is not summoned (#753).
|
|
640
|
+
*/
|
|
641
|
+
const COUNTERSIGN_STATUS_REASK = "countersignStatus 不是 converged、continue、escalate 三态之一。请重新交卷,status 写明其一。";
|
|
633
642
|
export function createCountersignRoleRuntime(roleHost, dependencies, hostActions) {
|
|
634
643
|
// Notary inner gate difference only — lifecycle stays on the shared envelope.
|
|
635
644
|
// Pointer-only summons: officer self-fetches from run dossier (#632 / ADR 0079).
|
|
645
|
+
// #753 queue: read countersignStatus only — escalate skips gate (thrown to caller);
|
|
646
|
+
// unreadable status returns to countersign; else notary inner gate.
|
|
636
647
|
const beforeAccept = hostActions !== undefined && roleHost.requireGatekeeperPass !== undefined
|
|
637
|
-
? async ({ toolCallId, signal, ctx }) => {
|
|
648
|
+
? async ({ toolCallId, parameters, signal, ctx }) => {
|
|
649
|
+
const record = parameters !== null && typeof parameters === "object" && !Array.isArray(parameters)
|
|
650
|
+
? parameters
|
|
651
|
+
: undefined;
|
|
652
|
+
const status = record !== undefined && typeof record.countersignStatus === "string"
|
|
653
|
+
? record.countersignStatus
|
|
654
|
+
: undefined;
|
|
655
|
+
if (status === undefined || !COUNTERSIGN_QUEUE_STATUSES.has(status)) {
|
|
656
|
+
// Parent status unreadable → back to countersign itself; do not summon notary,
|
|
657
|
+
// do not forge an officer bounce face (#753).
|
|
658
|
+
throw new ParentQueueReaskError(COUNTERSIGN_STATUS_REASK);
|
|
659
|
+
}
|
|
660
|
+
if (status === "escalate") {
|
|
661
|
+
// Parent escalate → throw to caller as-is; notary does not attend (#753).
|
|
662
|
+
return undefined;
|
|
663
|
+
}
|
|
638
664
|
await roleHost.requireGatekeeperPass({
|
|
639
665
|
context: ctx,
|
|
640
666
|
subject: { kind: "countersign_verdict" },
|
|
@@ -1000,7 +1026,6 @@ export function createRoleRuntimeExtension(dependencies) {
|
|
|
1000
1026
|
};
|
|
1001
1027
|
const judge = createJudgeRoleRuntime(roleHost, {
|
|
1002
1028
|
loadSoul: dependencies.loadJudgeSoul,
|
|
1003
|
-
auditSoulCompliance: dependencies.auditSoulCompliance,
|
|
1004
1029
|
}, hostActions);
|
|
1005
1030
|
const fixer = createFixerRoleRuntime(roleHost, {
|
|
1006
1031
|
async loadSoul() {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { GatekeeperDecisionError, WorkerCommitReminderError, WorkerPrefixReminderError, WorkerUnfinishedReasonReminderError, } from "./submission-errors.js";
|
|
1
|
+
import { GatekeeperDecisionError, ParentQueueReaskError, WorkerCommitReminderError, WorkerPrefixReminderError, WorkerUnfinishedReasonReminderError, } from "./submission-errors.js";
|
|
2
2
|
/** Shared, unforgeable identity for submission errors that the same session may correct. */
|
|
3
3
|
const correctableSubmissionErrorBrand = Symbol("ak-roles.correctable-submission-error");
|
|
4
4
|
export class CorrectableSubmissionError extends Error {
|
|
@@ -15,6 +15,7 @@ export function isCorrectableSubmissionError(error) {
|
|
|
15
15
|
export function isCorrectableExecuteError(error) {
|
|
16
16
|
return (isCorrectableSubmissionError(error)
|
|
17
17
|
|| error instanceof GatekeeperDecisionError
|
|
18
|
+
|| error instanceof ParentQueueReaskError
|
|
18
19
|
|| error instanceof WorkerCommitReminderError
|
|
19
20
|
|| error instanceof WorkerPrefixReminderError
|
|
20
21
|
|| error instanceof WorkerUnfinishedReasonReminderError);
|
|
@@ -1,21 +1,25 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { readableGateItem } from "./readable-gate-item.js";
|
|
2
|
+
/**
|
|
3
|
+
* Tool-result text the parent model sees (#753 / #750 evidence).
|
|
4
|
+
* bounce | escalate → officer receipt verbatim (JSON when structured).
|
|
5
|
+
* no_receipt → honest lifecycle fact. No findings rewrite, no「(无 findings)」.
|
|
6
|
+
* #775: structured field content via readableGateItem (DRY with other gate seams).
|
|
7
|
+
*/
|
|
8
|
+
function serializeReceipt(receipt) {
|
|
9
|
+
return readableGateItem(receipt);
|
|
10
|
+
}
|
|
2
11
|
function gatekeeperNonPassMessage(result) {
|
|
3
|
-
if (result.status === "bounce") {
|
|
4
|
-
|
|
5
|
-
? "(无 findings)"
|
|
6
|
-
: joinReadableGateItems(result.findings);
|
|
7
|
-
return `门下省打回重写,findings:${findings}`;
|
|
8
|
-
}
|
|
9
|
-
if (result.status === "unreadable") {
|
|
10
|
-
return `门下省官回执形状不可读(${result.officer}):${result.reason}`;
|
|
12
|
+
if (result.status === "bounce" || result.status === "escalate") {
|
|
13
|
+
return serializeReceipt(result.receipt);
|
|
11
14
|
}
|
|
15
|
+
// no_receipt
|
|
12
16
|
return `门下省 ${result.status}(${result.stage}):${result.reason}`;
|
|
13
17
|
}
|
|
14
18
|
/** Structured non-pass; `.result` is session-projected via tool_result, message feeds the model. */
|
|
15
19
|
export class GatekeeperDecisionError extends Error {
|
|
16
20
|
result;
|
|
17
|
-
constructor(result) {
|
|
18
|
-
super(gatekeeperNonPassMessage(result));
|
|
21
|
+
constructor(result, message) {
|
|
22
|
+
super(message ?? gatekeeperNonPassMessage(result));
|
|
19
23
|
this.name = "GatekeeperDecisionError";
|
|
20
24
|
this.result = result;
|
|
21
25
|
}
|
|
@@ -41,3 +45,14 @@ export class WorkerUnfinishedReasonReminderError extends Error {
|
|
|
41
45
|
this.name = "WorkerUnfinishedReasonReminderError";
|
|
42
46
|
}
|
|
43
47
|
}
|
|
48
|
+
/**
|
|
49
|
+
* Parent seat status unreadable for queueing (#753).
|
|
50
|
+
* Correctable back to the parent itself — not a gate officer bounce, no officer field.
|
|
51
|
+
*/
|
|
52
|
+
export class ParentQueueReaskError extends Error {
|
|
53
|
+
code = "parent_queue_reask";
|
|
54
|
+
constructor(message) {
|
|
55
|
+
super(message);
|
|
56
|
+
this.name = "ParentQueueReaskError";
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { resolveActivationLedgerHome, tryHomeFromAkRolesPath, } from "./activation-ledger-topology.js";
|
|
2
|
-
import { isAuditEscalationProjection
|
|
3
|
-
import { GatekeeperEscalationError } from "./gatekeeper-role.js";
|
|
2
|
+
import { isAuditEscalationProjection } from "./audit-escalation.js";
|
|
4
3
|
import { acceptedFacts, isTerminatingToolName, } from "./package-contracts/terminating-tools.js";
|
|
5
4
|
import { runIdFromRunDirectory } from "./run-terminal-artifacts.js";
|
|
6
5
|
import { readSitianRecords, resolveSitianRecordPathInLedger, sitianReport } from "./sitian-facade.js";
|
|
@@ -293,14 +292,6 @@ export function createSubmissionLedgerHost(host, outputTools, failInfrastructure
|
|
|
293
292
|
// correctable-rejection path as execute-thrown rejections below. The
|
|
294
293
|
// candidate is booked first so the bounced attempt stays observable.
|
|
295
294
|
append({ type: "candidate", attemptId, toolCallId, toolName: tool.name, sequence: ++state.sequence });
|
|
296
|
-
const projectOfficerEscalation = (officer, original, deliveredOutput = original) => projectAuditEscalation({
|
|
297
|
-
...original,
|
|
298
|
-
status: "escalate",
|
|
299
|
-
officer,
|
|
300
|
-
reason: original.reason === undefined
|
|
301
|
-
? `门下省${officer}上呈(原卷未附 reason)`
|
|
302
|
-
: original.reason,
|
|
303
|
-
}, deliveredOutput);
|
|
304
295
|
let result;
|
|
305
296
|
try {
|
|
306
297
|
failOnInfrastructureFailureDeclaration(params, {
|
|
@@ -311,11 +302,9 @@ export function createSubmissionLedgerHost(host, outputTools, failInfrastructure
|
|
|
311
302
|
result = await tool.execute(toolCallId, params, signal, update, context);
|
|
312
303
|
}
|
|
313
304
|
catch (error) {
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
}
|
|
318
|
-
else if (isCorrectableExecuteError(error)) {
|
|
305
|
+
// #753: gate no longer throws GatekeeperEscalationError to select parent
|
|
306
|
+
// next-step. Officer bounce|escalate returns as correctable with raw receipt.
|
|
307
|
+
if (isCorrectableExecuteError(error)) {
|
|
319
308
|
append({
|
|
320
309
|
type: "outcome",
|
|
321
310
|
attemptId,
|
|
@@ -337,14 +326,9 @@ export function createSubmissionLedgerHost(host, outputTools, failInfrastructure
|
|
|
337
326
|
throw error;
|
|
338
327
|
}
|
|
339
328
|
}
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
!Array.isArray(result.details) &&
|
|
344
|
-
result.details.status === "escalate") {
|
|
345
|
-
const details = result.details;
|
|
346
|
-
result = projectOfficerEscalation(role, details);
|
|
347
|
-
}
|
|
329
|
+
// #753 escalate-thrown-verbatim: officer escalate seals as accepted with the
|
|
330
|
+
// raw receipt — no projectOfficerEscalation rewrite, no fabricated reason.
|
|
331
|
+
// Compliance seats still return live audit_escalation projections below.
|
|
348
332
|
if (isAuditEscalationProjection(result.details)) {
|
|
349
333
|
const candidates = rounds.get(attemptId) ?? [];
|
|
350
334
|
candidates.push({
|
|
@@ -35,7 +35,6 @@ import {
|
|
|
35
35
|
createProductionMergerGitState,
|
|
36
36
|
formatNavigatorRoleHelp,
|
|
37
37
|
} from "../src/role-runtime.ts";
|
|
38
|
-
import { createPiJudgeAuditor } from "../src/judge-auditor.ts";
|
|
39
38
|
import { loadAuditorSoulFromSubjectInput } from "../src/auditor-soul.ts";
|
|
40
39
|
import { loadGatekeeperSessionMaterials, loadMainRoleSessionMaterials } from "../src/session-opening-materials.ts";
|
|
41
40
|
const extensionPath = fileURLToPath(import.meta.url);
|
|
@@ -175,7 +174,6 @@ export default function roleRuntime(pi: ExtensionAPI): void {
|
|
|
175
174
|
},
|
|
176
175
|
runReviewerDispatch: (dispatch, options) => reviewerAgent.run(dispatch, options),
|
|
177
176
|
shutdownReviewerAgent: () => reviewerAgent.shutdown(),
|
|
178
|
-
auditSoulCompliance: (options) => createPiJudgeAuditor()(options),
|
|
179
177
|
}, {
|
|
180
178
|
transcriptFromContext,
|
|
181
179
|
oauthKeepalive: { providers: oauthKeepaliveProviders },
|
package/package.json
CHANGED
package/souls/countersign.md
CHANGED
|
@@ -7,26 +7,26 @@
|
|
|
7
7
|
|
|
8
8
|
**一、立法。** 先为本票立「适用法」,写进判词;后面每一步只对着它问,未立法不得往下走。适用法三部分:
|
|
9
9
|
1 票面本文,含置顶冻结原话;起居录里决策过程
|
|
10
|
-
2
|
|
10
|
+
2 第一法源立法(最高法):该票起居录与陛下原话,全局宪法;
|
|
11
11
|
3 第二发源立法:
|
|
12
|
-
适用 ADR——由你自行检索,按票面触及的席位、接缝、术语在 docs/adr 与 CONTEXT.md
|
|
12
|
+
适用 ADR——由你自行检索,按票面触及的席位、接缝、术语在 docs/adr 与 CONTEXT.md 查全,票面引没引都算——并逐键列出其决策键;仓级 CLAUDE.md、质量法、审刑院法典;
|
|
13
13
|
既有契约:CONTEXT.md 词表、被改动接缝的现行行为、相关票与在飞分支。
|
|
14
14
|
|
|
15
|
-
4
|
|
15
|
+
4 第二法源合法性检查:第一法源,判断第二法源 以及 输入的 prombt 是否有超出或不足,曲解。如有,除非有陛下原话批准,否则直接封驳要求改正或陛下批准。
|
|
16
16
|
|
|
17
|
-
**二、相抵。**
|
|
17
|
+
**二、相抵。** 票面与法源有无抵触,有无与在飞票冲突。
|
|
18
18
|
|
|
19
|
-
**三、缺失。**
|
|
19
|
+
**三、缺失。** 法源要求的,票面有没有漏:适用 ADR 未被引用即缺失,引用须写 `docs/adr/...md` 路径;ADR 每个决策键须有落点或明写「由 #x 承接」;验收面须覆盖票面每条主张;前置产物、决定、答复须在;承重主张的源头不存在、不支持、已过时,同为缺失。
|
|
20
20
|
|
|
21
|
-
**四、擅加。**
|
|
21
|
+
**四、擅加。** 票面有没有超出法源的机制、约束、验收、术语。
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
各步取证按《审法·取证边界》:读码、开卷、传召皆可;探针只落 worktree 与临时目录,不得删改其外任何路径。交付时候清理回原样
|
|
24
24
|
|
|
25
25
|
## 审读五问
|
|
26
26
|
|
|
27
27
|
四步是审读,五问是裁决口径,对应关系固定,不重做:
|
|
28
28
|
1. 票面是否符合既定制度——由「相抵」答;
|
|
29
|
-
2.
|
|
29
|
+
2. 授权是否真实——由「立法②」答:不认转述与口头;
|
|
30
30
|
3. 文书是否与原意一致——由「缺失」「擅加」答:无过度解释、无夹带、无缺口;
|
|
31
31
|
4. 是否存在必须退回重议的问题;
|
|
32
32
|
5. 是否已具备正式发布与执行资格。
|
|
@@ -35,12 +35,13 @@
|
|
|
35
35
|
|
|
36
36
|
## 判词
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
事实与处方分开对宪:裁决落法度与事实;施工设计与实现细节过早堆上票面即为失职。
|
|
39
39
|
|
|
40
40
|
- 署(converged)——四步无碍、五问皆有据可答,具备开工资格;
|
|
41
41
|
- 封驳(continue)——存在必须退回重议的问题;写明退给谁、缺什么、属哪一步;
|
|
42
|
-
- 上呈(escalate
|
|
42
|
+
- 上呈(escalate)——授权存疑、法源冲突或须陛下取舍。**上呈原样抛给调用者。**
|
|
43
|
+
|
|
43
44
|
|
|
44
45
|
主张必须附证据或法的具体条目。finding 提类别,同类一次说全(审刑院法典·审官纪律)。
|
|
45
46
|
|
|
46
|
-
|
|
47
|
+
交卷后由符宝郎内闸核旨。无法解决的上抛陛下。
|
package/souls/notary.md
CHANGED
|
@@ -7,3 +7,8 @@
|
|
|
7
7
|
**二、核旨**:以所读起居录为据,核受审之物——**票面与判词**——有没有加戏:每一条**重大决策/设计/改变实际行为的**机制/约束条款逐条追到陛下原话为止——ADR 决策键只是索引,键的表述超出同行原话即加戏(门槛见审刑院法典;2026-09-06 owner:#636/#637「每次独立 run」判例);票面本身是不是陛下要的同样逐条追,**不因票面已签押、判词已引用而免核**。引 ADR 之名而无 key 绑定、引票面而票面无原话,同为加戏。核键的做法:把键值与所绑原话并排逐字比——原话没说的动作(删、改、加机制、定顺序)键值不得含;同题在起居录里有更早原话的,一并对撞,后话只覆盖它明说的部分,没说的部分仍以前话为准。键值已写进 ADR、票面已过庭、判词已引用,都不算原话,不豁免。判词与票面对不对得上不归你。任一病成立,点名该条驳回;拿不准陛下本意的,上呈。
|
|
8
8
|
|
|
9
9
|
方法:按条封驳。取证按《审法·取证边界》:只读;探针只落 worktree 与临时目录,不得删改其外任何路径。无法解决的上抛陛下。
|
|
10
|
+
|
|
11
|
+
## 结论
|
|
12
|
+
|
|
13
|
+
结论以三态明示(不规定格式):`pass`(过)/`bounce`(打回)/`escalate`(上呈)。
|
|
14
|
+
**打回或上呈的话就是给对方看的原文**——给事中收到的就是你写的回执,不是代码改写的摘要。
|
|
@@ -14,7 +14,6 @@ import { createGhCollectorGitHubTransport, createGhIssueSoftFetcher } from "../c
|
|
|
14
14
|
import { createPiDoctorAuditor } from "../doctor-auditor.ts";
|
|
15
15
|
import { loadDoctorCase } from "../doctor-evidence.ts";
|
|
16
16
|
import type { DurablePrincipalAuthority, RoleTurnHost } from "../host-contracts.ts";
|
|
17
|
-
import { createPiJudgeAuditor } from "../judge-auditor.ts";
|
|
18
17
|
import { createProductionMergerGitState } from "../merger-git-state.ts";
|
|
19
18
|
import { createNativeNavigatorSessionFactory, createNavigatorAttendance } from "../navigator-attendance.ts";
|
|
20
19
|
import { loadNavigatorWorkContext } from "../navigator-work-context.ts";
|
|
@@ -42,7 +41,6 @@ const navigatorRoutePlaybookPath = fileURLToPath(
|
|
|
42
41
|
|
|
43
42
|
/** Host-neutral packaged role runtime deps for the ACP parent-process envelope. */
|
|
44
43
|
export function createAcpRoleRuntimeDependencies(packageRoot: string): RoleRuntimeDependencies {
|
|
45
|
-
const judgeAuditor = createPiJudgeAuditor();
|
|
46
44
|
const doctorAuditor = createPiDoctorAuditor();
|
|
47
45
|
const reviewerAgent = createPerDispatchReviewerAgent({ packageRoot });
|
|
48
46
|
const navigatorSessionFactory = createNativeNavigatorSessionFactory();
|
|
@@ -80,8 +78,7 @@ export function createAcpRoleRuntimeDependencies(packageRoot: string): RoleRunti
|
|
|
80
78
|
}
|
|
81
79
|
return loadHomeCanonicalSkillBinding(name);
|
|
82
80
|
},
|
|
83
|
-
// #590:
|
|
84
|
-
auditSoulCompliance: (options) => judgeAuditor(options),
|
|
81
|
+
// #590: doctor compliance still on disposeCompliance path; judge→auditor is gate queue (#756).
|
|
85
82
|
auditDoctorCompliance: (options) => doctorAuditor(options),
|
|
86
83
|
runReviewerDispatch: (dispatch, options) => reviewerAgent.run(dispatch, options),
|
|
87
84
|
shutdownReviewerAgent: () => reviewerAgent.shutdown(),
|
|
@@ -298,7 +298,7 @@ export async function prepareAcpRoleEnvelope(options: {
|
|
|
298
298
|
if (record.kind === "role_infrastructure_failure") return;
|
|
299
299
|
const code = typeof record.code === "string" && record.code.length > 0
|
|
300
300
|
? record.code
|
|
301
|
-
: record.status === "bounce" || record.status === "
|
|
301
|
+
: record.status === "bounce" || record.status === "escalate" || record.status === "no_receipt"
|
|
302
302
|
? record.status
|
|
303
303
|
: undefined;
|
|
304
304
|
if (code === undefined) return;
|
|
@@ -477,6 +477,10 @@ export async function readAnalystGateCyclesFromAuditorRoles(
|
|
|
477
477
|
? [auditorRolesDirectory]
|
|
478
478
|
: auditorRolesDirectory;
|
|
479
479
|
const volumes: ClassifiedVolume[] = [];
|
|
480
|
+
// Same officer session pointed at N times (historical multi-mint pointers, or
|
|
481
|
+
// one parent booking many leaves) must classify once — else each accepted
|
|
482
|
+
// seal is counted ×N in terminal gate-round (#753 acceptance A).
|
|
483
|
+
const classifiedOfficerSessions = new Set<string>();
|
|
480
484
|
for (const directory of directories) {
|
|
481
485
|
let names: string[];
|
|
482
486
|
try {
|
|
@@ -495,10 +499,15 @@ export async function readAnalystGateCyclesFromAuditorRoles(
|
|
|
495
499
|
}
|
|
496
500
|
for (const name of names) {
|
|
497
501
|
const path = join(directory, name);
|
|
498
|
-
const
|
|
502
|
+
const fromPointer = name.endsWith(".pointer.json");
|
|
503
|
+
const sessionPath = fromPointer
|
|
499
504
|
? await resolveOfficerSessionFromPointerFile(path)
|
|
500
505
|
: path;
|
|
501
506
|
if (sessionPath === undefined) continue;
|
|
507
|
+
if (fromPointer) {
|
|
508
|
+
if (classifiedOfficerSessions.has(sessionPath)) continue;
|
|
509
|
+
classifiedOfficerSessions.add(sessionPath);
|
|
510
|
+
}
|
|
502
511
|
const classified = await classifyAuditorVolume(sessionPath);
|
|
503
512
|
for (const volume of classified) {
|
|
504
513
|
if (
|