@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
package/src/judge-auditor.ts
CHANGED
|
@@ -1,45 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
runComplianceAudit,
|
|
3
|
-
type AuditorSummon,
|
|
4
|
-
type ComplianceDecision,
|
|
5
|
-
} from "./compliance-transport.ts";
|
|
6
|
-
import { auditorRunDirectory } from "./auditor-dossier-tool.ts";
|
|
7
|
-
import {
|
|
8
|
-
readJudgeAuditSubjects,
|
|
9
|
-
requireAuditMaterials,
|
|
10
|
-
resolveAuditDossier,
|
|
11
|
-
} from "./dossier-resolution.ts";
|
|
12
|
-
import type { HostContext } from "./host-contracts.ts";
|
|
13
|
-
|
|
14
|
-
export const JUDGE_AUDIT_TOOL_NAME = "ak_soul_audit_decision";
|
|
15
|
-
export const SOUL_AUDIT_TOOL_NAME = JUDGE_AUDIT_TOOL_NAME;
|
|
16
|
-
|
|
17
|
-
export type JudgeAuditOptions = {
|
|
18
|
-
context: HostContext;
|
|
19
|
-
signal?: AbortSignal;
|
|
20
|
-
/** Same seam as runComplianceAudit options — offline tracers only. */
|
|
21
|
-
summonAuditor?: AuditorSummon;
|
|
22
|
-
};
|
|
23
|
-
|
|
24
1
|
/**
|
|
25
|
-
* Judge
|
|
26
|
-
*
|
|
2
|
+
* Judge nested-audit tool name retained for settlement / historical session faces.
|
|
3
|
+
* Live judge↔auditor review queue is the shared gate envelope (#756) — no
|
|
4
|
+
* createPiJudgeAuditor compliance wrapper remains.
|
|
27
5
|
*/
|
|
28
|
-
export
|
|
29
|
-
|
|
30
|
-
const dossier = resolveAuditDossier();
|
|
31
|
-
requireAuditMaterials(dossier);
|
|
32
|
-
const subjects = readJudgeAuditSubjects(options.context);
|
|
33
|
-
requireAuditMaterials(subjects);
|
|
34
|
-
|
|
35
|
-
return runComplianceAudit({
|
|
36
|
-
subject: "judge",
|
|
37
|
-
context: options.context,
|
|
38
|
-
...(auditorRunDirectory(options.context) === undefined
|
|
39
|
-
? {}
|
|
40
|
-
: { runDirectory: auditorRunDirectory(options.context) }),
|
|
41
|
-
...(options.signal === undefined ? {} : { signal: options.signal }),
|
|
42
|
-
...(options.summonAuditor === undefined ? {} : { summonAuditor: options.summonAuditor }),
|
|
43
|
-
});
|
|
44
|
-
};
|
|
45
|
-
}
|
|
6
|
+
export const JUDGE_AUDIT_TOOL_NAME = "ak_soul_audit_decision";
|
|
7
|
+
export const SOUL_AUDIT_TOOL_NAME = JUDGE_AUDIT_TOOL_NAME;
|
package/src/judge-role.ts
CHANGED
|
@@ -2,19 +2,20 @@ import type { RoleHost, HostContext, HostToolResult, HostGatekeeperActions } fro
|
|
|
2
2
|
import { stringEnum } from "./host-contracts.ts";
|
|
3
3
|
import { Type, type Static } from "typebox";
|
|
4
4
|
|
|
5
|
-
import { disposeComplianceDecision } from "./audit-escalation.ts";
|
|
6
|
-
import type { ComplianceDecision } from "./compliance-transport.ts";
|
|
7
|
-
import { joinReadableGateItems } from "./readable-gate-item.ts";
|
|
8
5
|
import { withInfrastructureFailureDeclaration } from "./package-contracts/terminating-infrastructure.ts";
|
|
6
|
+
import { ParentQueueReaskError } from "./submission-errors.ts";
|
|
9
7
|
|
|
10
8
|
import {
|
|
11
|
-
JUDGE_ACCEPTED_AUDIT_NO_RECEIPT_TEXT,
|
|
12
9
|
JUDGE_ACCEPTED_TEXT,
|
|
13
10
|
JUDGE_OUTPUT_TOOL_NAME,
|
|
14
11
|
validateAcceptedJudgeDetails,
|
|
15
12
|
type JudgeVerdict,
|
|
16
13
|
} from "./package-contracts/judge-output.ts";
|
|
17
14
|
|
|
15
|
+
const JUDGE_QUEUE_STATUSES = new Set(["converged", "continue", "escalate"]);
|
|
16
|
+
const JUDGE_STATUS_REASK =
|
|
17
|
+
"judgeStatus 不是 converged、continue、escalate 三态之一。请重新交卷,status 写明其一。" as const;
|
|
18
|
+
|
|
18
19
|
export { JUDGE_OUTPUT_TOOL_NAME };
|
|
19
20
|
export type { JudgeVerdict };
|
|
20
21
|
|
|
@@ -53,13 +54,8 @@ export const judgeVerdictSchema = withInfrastructureFailureDeclaration(
|
|
|
53
54
|
|
|
54
55
|
type JudgeVerdictParameters = Static<typeof judgeVerdictSchema>;
|
|
55
56
|
|
|
56
|
-
export type SoulAuditResult = ComplianceDecision;
|
|
57
|
-
|
|
58
57
|
export type JudgeRoleDependencies = {
|
|
59
58
|
loadSoul(): Promise<string>;
|
|
60
|
-
auditSoulCompliance(
|
|
61
|
-
options: { context: HostContext; signal?: AbortSignal },
|
|
62
|
-
): Promise<SoulAuditResult>;
|
|
63
59
|
};
|
|
64
60
|
|
|
65
61
|
export type JudgeRoleHostActions = HostGatekeeperActions;
|
|
@@ -86,15 +82,34 @@ export function createJudgeRoleRuntime(
|
|
|
86
82
|
pi.registerTool({
|
|
87
83
|
name: JUDGE_OUTPUT_TOOL_NAME,
|
|
88
84
|
label: "大理寺输出",
|
|
89
|
-
description: "
|
|
85
|
+
description: "提交大理寺终局判词;受理前经符宝郎内闸与审刑院合规审核。",
|
|
90
86
|
promptSnippet: "提交大理寺终局判词",
|
|
91
87
|
parameters: judgeVerdictSchema,
|
|
92
88
|
async execute(toolCallId: string, parameters: Static<typeof judgeVerdictSchema>, signal: AbortSignal | undefined, _onUpdate: unknown, ctx: HostContext): Promise<HostToolResult<unknown>> {
|
|
93
89
|
if (soul === undefined) throw new Error("大理寺职分未装载");
|
|
90
|
+
// #756 queue: read judgeStatus only — escalate skips gates (thrown to caller);
|
|
91
|
+
// unreadable status returns to judge; else 符宝郎内闸 then 审刑院合规.
|
|
92
|
+
const rawStatus =
|
|
93
|
+
parameters !== null && typeof parameters === "object" && !Array.isArray(parameters)
|
|
94
|
+
&& typeof (parameters as Record<string, unknown>).judgeStatus === "string"
|
|
95
|
+
? (parameters as Record<string, unknown>).judgeStatus as string
|
|
96
|
+
: undefined;
|
|
97
|
+
if (rawStatus === undefined || !JUDGE_QUEUE_STATUSES.has(rawStatus)) {
|
|
98
|
+
throw new ParentQueueReaskError(JUDGE_STATUS_REASK);
|
|
99
|
+
}
|
|
100
|
+
if (rawStatus === "escalate") {
|
|
101
|
+
// Parent escalate → throw to caller as-is; officers do not attend (#753 / #756).
|
|
102
|
+
const verdict = validateVerdict(parameters);
|
|
103
|
+
return {
|
|
104
|
+
content: [{ type: "text" as const, text: JUDGE_ACCEPTED_TEXT }],
|
|
105
|
+
details: verdict,
|
|
106
|
+
terminate: true as const,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
94
109
|
const verdict = validateVerdict(parameters);
|
|
95
110
|
// Candidate verdict is already on the parent session books as this
|
|
96
111
|
// tool-call leaf (first-record-then-audit; run 019fea05 L61/L62).
|
|
97
|
-
//
|
|
112
|
+
// #753: 符宝郎内闸 — queue only, raw receipt on bounce/escalate.
|
|
98
113
|
await pi.requireGatekeeperPass!({
|
|
99
114
|
context: ctx,
|
|
100
115
|
subject: { kind: "judge_draft" },
|
|
@@ -102,49 +117,21 @@ export function createJudgeRoleRuntime(
|
|
|
102
117
|
hostActions,
|
|
103
118
|
toolCallId,
|
|
104
119
|
});
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
)
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
content: [{ type: "text" as const, text: JUDGE_ACCEPTED_TEXT }],
|
|
121
|
-
details: acceptedDetails,
|
|
122
|
-
terminate: true as const,
|
|
123
|
-
...(usage === undefined ? {} : { usage }),
|
|
124
|
-
}),
|
|
125
|
-
noReceipt: (auditNoReceipt, usageProjection) => ({
|
|
126
|
-
content: [{ type: "text" as const, text: JUDGE_ACCEPTED_AUDIT_NO_RECEIPT_TEXT }],
|
|
127
|
-
details: { ...acceptedDetails, auditNoReceipt },
|
|
128
|
-
terminate: true as const,
|
|
129
|
-
...usageProjection,
|
|
130
|
-
}),
|
|
131
|
-
// #757: parent stands with auditor raw reply — no unreadable judgment.
|
|
132
|
-
received: (auditReceived, usageProjection) => ({
|
|
133
|
-
content: [{ type: "text" as const, text: JUDGE_ACCEPTED_TEXT }],
|
|
134
|
-
details: { ...acceptedDetails, audit: auditReceived.reply },
|
|
135
|
-
terminate: true as const,
|
|
136
|
-
...usageProjection,
|
|
137
|
-
}),
|
|
138
|
-
bounce: (violations) => {
|
|
139
|
-
throw new Error(
|
|
140
|
-
`大理寺回执违 soul:${joinReadableGateItems(violations)}`,
|
|
141
|
-
);
|
|
142
|
-
},
|
|
143
|
-
escalate: (result) => result,
|
|
144
|
-
},
|
|
145
|
-
// #380: escalate deliveredOutput must carry the same mechanical projection.
|
|
146
|
-
acceptedDetails,
|
|
147
|
-
);
|
|
120
|
+
// #756: 审刑院合规路径 — same review-queue law as 符宝郎/察院.
|
|
121
|
+
// pass → accept; bounce|escalate → raw auditor receipt back to judge;
|
|
122
|
+
// not three-state → resume auditor; no round cap; no disposeCompliance mapping.
|
|
123
|
+
await pi.requireGatekeeperPass!({
|
|
124
|
+
context: ctx,
|
|
125
|
+
subject: { kind: "judge_compliance" },
|
|
126
|
+
...(signal === undefined ? {} : { signal }),
|
|
127
|
+
hostActions,
|
|
128
|
+
toolCallId,
|
|
129
|
+
});
|
|
130
|
+
return {
|
|
131
|
+
content: [{ type: "text" as const, text: JUDGE_ACCEPTED_TEXT }],
|
|
132
|
+
details: verdict,
|
|
133
|
+
terminate: true as const,
|
|
134
|
+
};
|
|
148
135
|
},
|
|
149
136
|
});
|
|
150
137
|
pi.on("before_agent_start", (event) => {
|
package/src/notary-contracts.ts
CHANGED
|
@@ -53,13 +53,10 @@ export type NotarySourceRunLocator = {
|
|
|
53
53
|
readonly role: string;
|
|
54
54
|
};
|
|
55
55
|
|
|
56
|
+
/** Recognition face only — fields retained as submitted (#753, no disposition/findings forge). */
|
|
56
57
|
export type NotaryOutput =
|
|
57
|
-
| { readonly status: "pass"; readonly findings
|
|
58
|
-
| {
|
|
59
|
-
readonly status: "bounce";
|
|
60
|
-
readonly disposition: "rewrite";
|
|
61
|
-
readonly findings: readonly string[];
|
|
62
|
-
}
|
|
58
|
+
| { readonly status: "pass"; readonly findings?: unknown }
|
|
59
|
+
| { readonly status: "bounce"; readonly findings?: unknown }
|
|
63
60
|
| {
|
|
64
61
|
readonly status: "escalate";
|
|
65
62
|
readonly reason?: unknown;
|
|
@@ -70,32 +67,16 @@ function isRecord(value: unknown): value is Record<string, unknown> {
|
|
|
70
67
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
71
68
|
}
|
|
72
69
|
|
|
73
|
-
function asStringArray(value: unknown): readonly string[] {
|
|
74
|
-
if (!Array.isArray(value)) return [];
|
|
75
|
-
return value.filter((item): item is string => typeof item === "string");
|
|
76
|
-
}
|
|
77
|
-
|
|
78
70
|
/**
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
*
|
|
71
|
+
* Recognize one lawful explicit Notary release (pass | bounce | escalate).
|
|
72
|
+
* #753: no field rewrite — submitted params retained as-is (no disposition forge,
|
|
73
|
+
* no findings array rewrite). Recognition only for recording/settlement callers.
|
|
82
74
|
*/
|
|
83
75
|
export function projectLawfulNotaryOutput(value: unknown): NotaryOutput | undefined {
|
|
84
76
|
if (!isRecord(value)) return undefined;
|
|
85
77
|
const status = typeof value.status === "string" ? value.status : undefined;
|
|
86
|
-
if (status === "bounce") {
|
|
87
|
-
|
|
88
|
-
if (clone.disposition === undefined) clone.disposition = "rewrite";
|
|
89
|
-
if (!Array.isArray(clone.findings)) clone.findings = asStringArray(clone.findings);
|
|
90
|
-
return clone as NotaryOutput;
|
|
91
|
-
}
|
|
92
|
-
if (status === "pass") {
|
|
93
|
-
const clone = structuredClone(value) as Record<string, unknown>;
|
|
94
|
-
if (!Array.isArray(clone.findings)) clone.findings = asStringArray(clone.findings);
|
|
95
|
-
return clone as NotaryOutput;
|
|
96
|
-
}
|
|
97
|
-
if (status === "escalate") {
|
|
98
|
-
return structuredClone(value) as NotaryOutput;
|
|
78
|
+
if (status === "bounce" || status === "pass" || status === "escalate") {
|
|
79
|
+
return value as NotaryOutput;
|
|
99
80
|
}
|
|
100
81
|
return undefined;
|
|
101
82
|
}
|
package/src/notary-role.ts
CHANGED
|
@@ -12,8 +12,6 @@ import {
|
|
|
12
12
|
NOTARY_SOURCE_RUN_FLAG,
|
|
13
13
|
NOTARY_TICKET_FLAG,
|
|
14
14
|
notaryOutputSchema,
|
|
15
|
-
projectLawfulNotaryOutput,
|
|
16
|
-
retainNotarySubmission,
|
|
17
15
|
type NotarySourceRunLocator,
|
|
18
16
|
} from "./notary-contracts.ts";
|
|
19
17
|
|
|
@@ -170,14 +168,11 @@ export function createNotaryRoleRuntime(
|
|
|
170
168
|
if (activation === undefined) {
|
|
171
169
|
throw new Error("符宝郎未激活");
|
|
172
170
|
}
|
|
173
|
-
//
|
|
174
|
-
// (第 0 条 / ADR 0055): lawful pass/bounce/escalate projected; else params as-is.
|
|
171
|
+
// #753: handler only records — params as submitted, no findings/disposition rewrite.
|
|
175
172
|
// #541 infra declaration + sole-final barrier are ledger-owned (#575).
|
|
176
|
-
const lawful = projectLawfulNotaryOutput(parameters);
|
|
177
|
-
const details = lawful ?? retainNotarySubmission(parameters);
|
|
178
173
|
return {
|
|
179
174
|
content: [{ type: "text" as const, text: NOTARY_ACCEPTED_TEXT }],
|
|
180
|
-
details,
|
|
175
|
+
details: parameters,
|
|
181
176
|
terminate: true as const,
|
|
182
177
|
};
|
|
183
178
|
},
|
|
@@ -221,10 +221,10 @@ export function validateAcceptedDetails(
|
|
|
221
221
|
[COLLECTOR_OUTPUT_TOOL]: [],
|
|
222
222
|
[DOCTOR_OUTPUT_TOOL_NAME]: ["completed", "refused"],
|
|
223
223
|
[MERGER_OUTPUT_TOOL_NAME]: ["completed", "escalate"],
|
|
224
|
-
[NOTARY_OUTPUT_TOOL_NAME]: ["pass", "bounce"],
|
|
224
|
+
[NOTARY_OUTPUT_TOOL_NAME]: ["pass", "bounce", "escalate"],
|
|
225
225
|
[COUNTERSIGN_OUTPUT_TOOL_NAME]: ["converged", "continue", "escalate"],
|
|
226
226
|
[GLEANER_LEFT_OUTPUT_TOOL_NAME]: ["completed"],
|
|
227
|
-
[INSPECTOR_OUTPUT_TOOL_NAME]: ["pass", "bounce"],
|
|
227
|
+
[INSPECTOR_OUTPUT_TOOL_NAME]: ["pass", "bounce", "escalate"],
|
|
228
228
|
[GATEKEEPER_OUTPUT_TOOL_NAME]: ["dispatch", "pass"],
|
|
229
229
|
[NAVIGATOR_OUTPUT_TOOL_NAME]: ["advice"],
|
|
230
230
|
[AUDITOR_OUTPUT_TOOL_NAME]: ["pass", "bounce", "escalate"],
|
|
@@ -44,6 +44,17 @@ import {
|
|
|
44
44
|
export type InspectorRunEnv = PostAdmissionEnv & {
|
|
45
45
|
principalAuthority: DurablePrincipalAuthority;
|
|
46
46
|
createRunId?: () => string;
|
|
47
|
+
/**
|
|
48
|
+
* #753 nested gate re-ask: plain-language instruction on same-ticket resume.
|
|
49
|
+
* Only set by summonPublicRole when the prior officer reply was not three-state.
|
|
50
|
+
* Never a public CLI argv — must not pollute the 卷宗指针 parentRunPath key (#747).
|
|
51
|
+
*/
|
|
52
|
+
reviewReask?: string;
|
|
53
|
+
/**
|
|
54
|
+
* #753/#750 same-parent re-summons: human-readable new-submission pointers.
|
|
55
|
+
* Rides summons.instruction when reviewReask is absent. Fresh mint keeps argv 卷宗指针.
|
|
56
|
+
*/
|
|
57
|
+
gateReviewInstruction?: string;
|
|
47
58
|
};
|
|
48
59
|
|
|
49
60
|
/** Project admitted invocation onto the host-neutral turn request. */
|
|
@@ -87,11 +98,18 @@ export async function runPublicInspector(
|
|
|
87
98
|
// #771: no mechanical ticket match against instruction text; parent-run path only.
|
|
88
99
|
// No bare catch→fresh: lookup/resume failures surface; only true absence mints new.
|
|
89
100
|
const projectRoot = parsed.project ?? env.cwd;
|
|
101
|
+
// #747: parentRunPath is the pure 卷宗指针 path only — never reask/materials text.
|
|
102
|
+
// #753: gate re-ask / new-submission pointers ride summons.instruction on resume.
|
|
90
103
|
const parentRunPath = parentRunPathFromGatePointerInstruction(parsed.instruction);
|
|
91
104
|
if (parentRunPath !== undefined) {
|
|
105
|
+
const resumeInstruction = env.reviewReask ?? env.gateReviewInstruction;
|
|
92
106
|
const summons: SameTicketSummonsMaterials = {
|
|
93
|
-
|
|
94
|
-
|
|
107
|
+
...(resumeInstruction === undefined
|
|
108
|
+
? {
|
|
109
|
+
instruction: parsed.instruction,
|
|
110
|
+
instructionEmpty: parsed.instruction.trim() === "",
|
|
111
|
+
}
|
|
112
|
+
: { instruction: resumeInstruction, instructionEmpty: false }),
|
|
95
113
|
attachmentPaths: parsed.attachmentPaths,
|
|
96
114
|
};
|
|
97
115
|
const resumed = await tryResumeSameTicketSeatRun({
|
|
@@ -109,6 +127,18 @@ export async function runPublicInspector(
|
|
|
109
127
|
),
|
|
110
128
|
});
|
|
111
129
|
if (resumed !== undefined) return resumed;
|
|
130
|
+
// Reask without a prior same-parent run cannot deliver the plain-language ask
|
|
131
|
+
// on a fresh mint without inventing a second prompt path — fail loud (#753).
|
|
132
|
+
// gateReviewInstruction alone is resume-only; fresh mint keeps argv 卷宗指针.
|
|
133
|
+
if (env.reviewReask !== undefined) {
|
|
134
|
+
presentStructuralRejection(
|
|
135
|
+
new CliUsageError(
|
|
136
|
+
"inspector review reask requires a prior same-parent run to resume",
|
|
137
|
+
),
|
|
138
|
+
io,
|
|
139
|
+
);
|
|
140
|
+
return { exitCode: 2 };
|
|
141
|
+
}
|
|
112
142
|
}
|
|
113
143
|
|
|
114
144
|
let admitted: AdmittedInspectorInvocation;
|
|
@@ -63,6 +63,17 @@ export type AdmittedInstructionSeatInvocation =
|
|
|
63
63
|
export type InstructionSeatRunEnv = PostAdmissionEnv & {
|
|
64
64
|
principalAuthority: DurablePrincipalAuthority;
|
|
65
65
|
createRunId?: () => string;
|
|
66
|
+
/**
|
|
67
|
+
* #756 nested gate re-ask for auditor: plain-language instruction on same-ticket resume.
|
|
68
|
+
* Only set by summonPublicRole when the prior officer reply was not three-state.
|
|
69
|
+
* Never a public CLI argv — must not pollute the --source-run parent lookup key (#747).
|
|
70
|
+
*/
|
|
71
|
+
reviewReask?: string;
|
|
72
|
+
/**
|
|
73
|
+
* #753/#750 same-parent re-summons: human-readable new-submission pointers.
|
|
74
|
+
* Rides summons.instruction when reviewReask is absent. Fresh mint keeps argv instruction.
|
|
75
|
+
*/
|
|
76
|
+
gateReviewInstruction?: string;
|
|
66
77
|
};
|
|
67
78
|
|
|
68
79
|
/** Project an admitted instruction-seat invocation onto the host-neutral turn request. */
|
|
@@ -283,9 +294,15 @@ export async function runPublicInstructionSeat(
|
|
|
283
294
|
}
|
|
284
295
|
}
|
|
285
296
|
|
|
297
|
+
// #756: auditor reask / new-submission pointers ride summons.instruction on resume.
|
|
298
|
+
const resumeInstruction = env.reviewReask ?? env.gateReviewInstruction;
|
|
286
299
|
const summons: SameTicketSummonsMaterials = {
|
|
287
|
-
|
|
288
|
-
|
|
300
|
+
...(resumeInstruction === undefined
|
|
301
|
+
? {
|
|
302
|
+
instruction: parsed.instruction,
|
|
303
|
+
instructionEmpty: parsed.instruction.trim() === "",
|
|
304
|
+
}
|
|
305
|
+
: { instruction: resumeInstruction, instructionEmpty: false }),
|
|
289
306
|
attachmentPaths: parsed.attachmentPaths,
|
|
290
307
|
};
|
|
291
308
|
if (role === "auditor" && auditorSourceRun !== undefined) {
|
|
@@ -309,6 +326,17 @@ export async function runPublicInstructionSeat(
|
|
|
309
326
|
}),
|
|
310
327
|
});
|
|
311
328
|
if (resumed !== undefined) return resumed;
|
|
329
|
+
// Reask without a prior same-parent run cannot deliver the plain-language ask
|
|
330
|
+
// on a fresh mint without inventing a second prompt path — fail loud (#753 / #756).
|
|
331
|
+
if (env.reviewReask !== undefined) {
|
|
332
|
+
presentStructuralRejection(
|
|
333
|
+
new CliUsageError(
|
|
334
|
+
"auditor review reask requires a prior same-parent run to resume",
|
|
335
|
+
),
|
|
336
|
+
io,
|
|
337
|
+
);
|
|
338
|
+
return { exitCode: 2 };
|
|
339
|
+
}
|
|
312
340
|
}
|
|
313
341
|
|
|
314
342
|
let admitted: AdmittedInstructionSeatInvocation;
|
|
@@ -4,9 +4,6 @@
|
|
|
4
4
|
* the shared post-admission seam; this module keeps only Notary adapters.
|
|
5
5
|
* #637 / #747: same-parent (--source-run) re-summons resume the seat's previous run.
|
|
6
6
|
*/
|
|
7
|
-
import { existsSync } from "node:fs";
|
|
8
|
-
|
|
9
|
-
import { gateSubmissionCandidatePath } from "../auditor-dossier-tool.ts";
|
|
10
7
|
import type { DurablePrincipalAuthority, RoleTurnRequest } from "../host-contracts.ts";
|
|
11
8
|
import {
|
|
12
9
|
NotarySourceRunError,
|
|
@@ -22,6 +19,7 @@ import {
|
|
|
22
19
|
} from "./invocation.ts";
|
|
23
20
|
import { tryResumeSameTicketSeatRun } from "./seat-ticket-binding.ts";
|
|
24
21
|
import {
|
|
22
|
+
prepareSummonsResumeMaterials,
|
|
25
23
|
runPostAdmissionOneShot,
|
|
26
24
|
type PostAdmissionAdapters,
|
|
27
25
|
type PostAdmissionEnv,
|
|
@@ -29,7 +27,6 @@ import {
|
|
|
29
27
|
resumeTurnRequestProjectionOptions,
|
|
30
28
|
} from "./post-admission.ts";
|
|
31
29
|
import {
|
|
32
|
-
appendResumeMaterialReread,
|
|
33
30
|
loadResumableNotaryRun,
|
|
34
31
|
markRunAdmitted,
|
|
35
32
|
type PublicResumeRequest,
|
|
@@ -49,6 +46,17 @@ import {
|
|
|
49
46
|
export type NotaryRunEnv = PostAdmissionEnv & {
|
|
50
47
|
principalAuthority: DurablePrincipalAuthority;
|
|
51
48
|
createRunId?: () => string;
|
|
49
|
+
/**
|
|
50
|
+
* #753 nested gate re-ask: plain-language instruction on same-ticket resume.
|
|
51
|
+
* Only set by summonPublicRole when the prior officer reply was not three-state.
|
|
52
|
+
* Never a public CLI argv — external callers still have zero prompt.
|
|
53
|
+
*/
|
|
54
|
+
reviewReask?: string;
|
|
55
|
+
/**
|
|
56
|
+
* #753/#750 same-parent re-summons: human-readable new-submission pointers.
|
|
57
|
+
* Rides summons.instruction when reviewReask is absent. Fresh mint ignores it.
|
|
58
|
+
*/
|
|
59
|
+
gateReviewInstruction?: string;
|
|
52
60
|
};
|
|
53
61
|
|
|
54
62
|
/** Project admitted invocation onto the host-neutral turn request. */
|
|
@@ -112,10 +120,16 @@ export async function runPublicNotary(
|
|
|
112
120
|
throw error;
|
|
113
121
|
}
|
|
114
122
|
// #747: officer resume key is this parent source-run path (not ticket number).
|
|
123
|
+
// #753: gate re-ask and new-submission pointers share summons.instruction
|
|
124
|
+
// (reask wins when both present; no parallel stack).
|
|
115
125
|
{
|
|
126
|
+
const resumeInstruction = env.reviewReask ?? env.gateReviewInstruction;
|
|
116
127
|
const summons: SameTicketSummonsMaterials = {
|
|
117
128
|
sourceRunPath: source.runDirectory,
|
|
118
129
|
sourceRun: source,
|
|
130
|
+
...(resumeInstruction === undefined
|
|
131
|
+
? {}
|
|
132
|
+
: { instruction: resumeInstruction, instructionEmpty: false }),
|
|
119
133
|
};
|
|
120
134
|
const resumed = await tryResumeSameTicketSeatRun({
|
|
121
135
|
home: env.home,
|
|
@@ -132,6 +146,18 @@ export async function runPublicNotary(
|
|
|
132
146
|
),
|
|
133
147
|
});
|
|
134
148
|
if (resumed !== undefined) return resumed;
|
|
149
|
+
// Reask without a prior same-parent run cannot deliver the plain-language ask
|
|
150
|
+
// on a fresh mint without inventing a second prompt path — fail loud (#753).
|
|
151
|
+
// gateReviewInstruction alone is resume-only materials; fresh mint ignores it.
|
|
152
|
+
if (env.reviewReask !== undefined) {
|
|
153
|
+
presentStructuralRejection(
|
|
154
|
+
new CliUsageError(
|
|
155
|
+
"notary review reask requires a prior same-parent run to resume",
|
|
156
|
+
),
|
|
157
|
+
io,
|
|
158
|
+
);
|
|
159
|
+
return { exitCode: 2 };
|
|
160
|
+
}
|
|
135
161
|
}
|
|
136
162
|
|
|
137
163
|
let admitted: AdmittedNotaryInvocation;
|
|
@@ -238,20 +264,26 @@ export async function runPublicNotaryResume(
|
|
|
238
264
|
}
|
|
239
265
|
return loaded;
|
|
240
266
|
},
|
|
241
|
-
buildTurnRequest: (admitted, effective) => {
|
|
242
|
-
|
|
267
|
+
buildTurnRequest: async (admitted, effective) => {
|
|
268
|
+
// #755: review continuation is plain dialogue / resume envelope — no
|
|
269
|
+
//「重新读」candidate line, no engine handbook packaging.
|
|
270
|
+
// #753: non-three-state re-ask rides as summons.instruction (人话重问).
|
|
271
|
+
const summonsPrepared =
|
|
272
|
+
effective.summons === undefined
|
|
273
|
+
? undefined
|
|
274
|
+
: await prepareSummonsResumeMaterials(
|
|
275
|
+
admitted.runDirectory,
|
|
276
|
+
effective.summons,
|
|
277
|
+
);
|
|
278
|
+
return buildNotaryTurnRequest(
|
|
243
279
|
admitted,
|
|
244
|
-
|
|
245
|
-
|
|
280
|
+
resumeTurnRequestProjectionOptions(
|
|
281
|
+
admitted,
|
|
282
|
+
effective,
|
|
283
|
+
env,
|
|
284
|
+
summonsPrepared,
|
|
285
|
+
),
|
|
246
286
|
);
|
|
247
|
-
const candidatePath = gateSubmissionCandidatePath(admitted.sourceRunPath);
|
|
248
|
-
const prompt = existsSync(candidatePath)
|
|
249
|
-
? appendResumeMaterialReread(projection.continuation.prompt, candidatePath)
|
|
250
|
-
: projection.continuation.prompt;
|
|
251
|
-
return buildNotaryTurnRequest(admitted, {
|
|
252
|
-
...projection,
|
|
253
|
-
continuation: { kind: "resume", prompt },
|
|
254
|
-
});
|
|
255
287
|
},
|
|
256
288
|
adapters: notaryAdapters(),
|
|
257
289
|
...(env.engine === undefined ? {} : { effectiveEngine: env.engine }),
|
|
@@ -11,7 +11,7 @@ import { isAbsolute, join, resolve } from "node:path";
|
|
|
11
11
|
|
|
12
12
|
import {
|
|
13
13
|
buildResumeContinuationPrompt,
|
|
14
|
-
|
|
14
|
+
RESUME_TRANSPORT_ENVELOPE,
|
|
15
15
|
type PublicResumeRequest,
|
|
16
16
|
type SameTicketSummonsMaterials,
|
|
17
17
|
} from "./run-lifecycle.ts";
|
|
@@ -22,7 +22,6 @@ import {
|
|
|
22
22
|
freezeAttachmentsIntoRun,
|
|
23
23
|
} from "./invocation.ts";
|
|
24
24
|
import { pathContainedIn } from "../activation-ledger-topology.ts";
|
|
25
|
-
import { engineSessionMaterialFromOptions } from "../package-resources/engine-material.ts";
|
|
26
25
|
|
|
27
26
|
import type {
|
|
28
27
|
ControlledFailureCause,
|
|
@@ -494,15 +493,18 @@ export async function dispatchPostAdmissionTurn<
|
|
|
494
493
|
}
|
|
495
494
|
|
|
496
495
|
/**
|
|
497
|
-
* Shared resume continuation projection (#471 / #600 / #633 / #637):
|
|
498
|
-
* model/engine/timeout axes, restored correlation, and either
|
|
499
|
-
* - manual resume: package envelope / optional caller
|
|
500
|
-
*
|
|
501
|
-
*
|
|
502
|
-
*
|
|
503
|
-
*
|
|
496
|
+
* Shared resume continuation projection (#471 / #600 / #633 / #637 / #755):
|
|
497
|
+
* seat-table model/engine/timeout axes, restored correlation, and either
|
|
498
|
+
* - manual resume (no same-ticket summons): package envelope / optional caller
|
|
499
|
+
* message, with engine-axis handbook via buildResumeContinuationPrompt, or
|
|
500
|
+
* - same-ticket summons (审核循环续话): caller/peer words + optional frozen
|
|
501
|
+
* attachment paths only — no「重新读」、no engine handbook packaging
|
|
502
|
+
* (#750/#755), whether or not attachments are present.
|
|
503
|
+
* Caller message wins as prompt base when supplied (bytes unchanged, including
|
|
504
|
+
* blank/whitespace); else summons instruction. Attachment projection must not
|
|
505
|
+
* re-interpret the caller message as instructionEmpty.
|
|
504
506
|
* Seats add only their activation projection. Call prepareSummonsResumeMaterials
|
|
505
|
-
* first when request.summons carries attachment paths.
|
|
507
|
+
* first when request.summons carries instruction or attachment paths.
|
|
506
508
|
*/
|
|
507
509
|
export function resumeTurnRequestProjectionOptions(
|
|
508
510
|
admitted: AdmittedRoleInvocation,
|
|
@@ -514,32 +516,21 @@ export function resumeTurnRequestProjectionOptions(
|
|
|
514
516
|
readonly attachments: readonly { frozenPath: string }[];
|
|
515
517
|
},
|
|
516
518
|
): RoleTurnRequestProjectionOptions {
|
|
517
|
-
const engineMaterial = engineSessionMaterialFromOptions({
|
|
518
|
-
...(env.engine === undefined ? {} : { engine: env.engine }),
|
|
519
|
-
packageRoot: env.packageRoot,
|
|
520
|
-
});
|
|
521
519
|
let prompt: string;
|
|
522
520
|
if (request.message !== undefined) {
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
instruction: request.message,
|
|
535
|
-
instructionEmpty: false,
|
|
536
|
-
attachments: summonsPrepared.attachments,
|
|
537
|
-
},
|
|
538
|
-
engineMaterial,
|
|
539
|
-
),
|
|
540
|
-
engineMaterial,
|
|
541
|
-
);
|
|
521
|
+
if (summonsPrepared !== undefined) {
|
|
522
|
+
// #755: same-ticket review / open-court — caller words + optional paths.
|
|
523
|
+
// Attachments are not a gate: message-only summons must stay plain too.
|
|
524
|
+
prompt = buildInstructionTransportPrompt({
|
|
525
|
+
instruction: request.message,
|
|
526
|
+
instructionEmpty: false,
|
|
527
|
+
attachments: summonsPrepared.attachments,
|
|
528
|
+
});
|
|
529
|
+
} else if (request.summons !== undefined) {
|
|
530
|
+
// #755: same-ticket summons without prepared materials — caller words only.
|
|
531
|
+
prompt = request.message;
|
|
542
532
|
} else {
|
|
533
|
+
// Bare manual resume — outsourcing engine axis keeps handbook (#600/#736).
|
|
543
534
|
prompt = buildResumeContinuationPrompt({
|
|
544
535
|
packageRoot: env.packageRoot,
|
|
545
536
|
...(env.engine === undefined ? {} : { engine: env.engine }),
|
|
@@ -547,11 +538,14 @@ export function resumeTurnRequestProjectionOptions(
|
|
|
547
538
|
});
|
|
548
539
|
}
|
|
549
540
|
} else if (summonsPrepared !== undefined) {
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
541
|
+
// #755: same-ticket review summons — instruction/attachments only.
|
|
542
|
+
prompt = buildInstructionTransportPrompt(summonsPrepared);
|
|
543
|
+
} else if (request.summons !== undefined) {
|
|
544
|
+
// #755: same-ticket summons with no instruction/attachments (e.g. notary
|
|
545
|
+
// source-run pointer) — plain resume envelope, no handbook / 重新读.
|
|
546
|
+
prompt = RESUME_TRANSPORT_ENVELOPE;
|
|
554
547
|
} else {
|
|
548
|
+
// Bare manual resume — outsourcing engine axis keeps handbook (#600/#736).
|
|
555
549
|
prompt = buildResumeContinuationPrompt({
|
|
556
550
|
packageRoot: env.packageRoot,
|
|
557
551
|
...(env.engine === undefined ? {} : { engine: env.engine }),
|