@akagilnc/pi-workflow-roles 0.1.3572 → 0.1.3621
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 +20239 -10556
- package/dist/analyst-gate-cycles-read.js +387 -0
- package/dist/archivist-record-entry.js +22 -1
- package/dist/audit-escalation.js +6 -0
- package/dist/auditor-soul.js +74 -0
- package/dist/collector-config.js +86 -0
- package/dist/collector-evidence.js +316 -0
- package/dist/collector-github.js +527 -0
- package/dist/collector-ledger.js +853 -0
- package/dist/collector-tool-schemas.js +33 -0
- package/dist/compliance-transport.js +104 -52
- package/dist/diarist-mechanical.js +411 -0
- package/dist/diarist-ticket-resolution.js +177 -0
- package/dist/diarist.js +311 -0
- package/dist/doctor-auditor.js +25 -0
- package/dist/doctor-contracts.js +2 -0
- package/dist/doctor-evidence.js +142 -0
- package/dist/gatekeeper-role.js +104 -81
- package/dist/host-transition-prior-native.js +78 -0
- package/dist/institutional-resolution.js +1 -95
- package/dist/judge-auditor.js +26 -0
- package/dist/ledger-session-read.js +227 -0
- package/dist/merger-git-state.js +78 -0
- package/dist/navigator-attendance.js +15 -7
- package/dist/navigator-public-session.js +170 -0
- package/dist/navigator-session-contracts.js +36 -40
- package/dist/notary-source-run.js +122 -0
- package/dist/package-contracts/auditor-output.js +66 -0
- package/dist/package-contracts/evidence-child-output.js +34 -0
- package/dist/package-contracts/judge-output.js +2 -0
- package/dist/package-contracts/terminating-tools.js +25 -2
- package/dist/package-resources/method-skill.js +254 -0
- package/dist/packaged-role-registry.js +36 -0
- package/dist/pi/durable-principal.js +61 -0
- package/dist/pi/in-process-session.js +25 -6
- package/dist/pi/known-failure.js +52 -0
- package/dist/pi/role-turn-host.js +430 -0
- package/dist/public-cli/auto-resume.js +414 -0
- package/dist/public-cli/cli-errors.js +8 -0
- package/dist/public-cli/cli-io.js +1 -0
- package/dist/public-cli/command-renderer.js +5 -0
- package/dist/public-cli/doctor-run.js +84 -0
- package/dist/public-cli/inspector-run.js +136 -0
- package/dist/public-cli/instruction-seat-run.js +256 -0
- package/dist/public-cli/invocation.js +2225 -0
- package/dist/public-cli/judge-run.js +118 -0
- package/dist/public-cli/load-production-acp-host.js +40 -0
- package/dist/public-cli/main.js +1140 -652
- package/dist/public-cli/notary-run.js +161 -0
- package/dist/public-cli/option-definitions.js +1192 -0
- package/dist/public-cli/post-admission.js +667 -0
- package/dist/public-cli/public-run-credentials.js +49 -0
- package/dist/public-cli/registry.js +4 -1
- package/dist/public-cli/reviewer-dispatch-rejection.js +77 -0
- package/dist/public-cli/run-lifecycle.js +1344 -0
- package/dist/public-cli/seat-ticket-binding.js +113 -0
- package/dist/public-cli/settlement.js +3441 -0
- package/dist/public-cli/terminal.js +135 -0
- package/dist/public-cli/turn-request.js +25 -0
- package/dist/public-role-summons.js +301 -0
- package/dist/receipt-delivery-policy.js +10 -0
- package/dist/reviewer-child-executor.js +80 -8
- package/dist/reviewer-execution-ledger.js +2 -1
- package/dist/run-terminal-artifacts.js +195 -0
- package/dist/run-ticket-number.js +40 -0
- package/dist/session-assistant-usage.js +107 -0
- package/dist/shape-unreadable-failure.js +34 -0
- package/dist/submission-errors.js +3 -0
- package/dist/submission-ledger.js +388 -0
- package/dist/ticket-provenance-contracts.js +115 -0
- package/dist/ticket-provenance.js +340 -0
- package/extensions/role-runtime.ts +7 -0
- package/package.json +1 -1
- package/scripts/build-package.mjs +2 -1
- package/souls/doctor-auditor.md +1 -0
- package/souls/evidence-child.md +1 -0
- package/src/acp-host/production-host.ts +3 -0
- package/src/acp-host/role-envelope.ts +2 -2
- package/src/acp-host/role-turn-host.ts +9 -1
- package/src/analyst-gate-cycles-read.ts +37 -2
- package/src/archivist-record-entry.ts +45 -1
- package/src/audit-escalation.ts +17 -0
- package/src/auditor-role.ts +22 -0
- package/src/auditor-soul.ts +42 -0
- package/src/compliance-transport.ts +177 -66
- package/src/doctor-auditor.ts +10 -14
- package/src/doctor-contracts.ts +1 -0
- package/src/doctor-role.ts +2 -2
- package/src/evidence-child-role.ts +22 -0
- package/src/gatekeeper-pass-envelope.ts +109 -0
- package/src/gatekeeper-role.ts +145 -104
- package/src/host-contracts.ts +9 -1
- package/src/institutional-resolution.ts +8 -163
- package/src/judge-auditor.ts +10 -15
- package/src/judge-role.ts +8 -0
- package/src/navigator-attendance.ts +25 -9
- package/src/navigator-public-session.ts +217 -0
- package/src/navigator-session-contracts.ts +61 -54
- package/src/notary-source-run.ts +3 -1
- package/src/package-contracts/auditor-output.ts +82 -0
- package/src/package-contracts/evidence-child-output.ts +51 -0
- package/src/package-contracts/judge-output.ts +1 -0
- package/src/package-contracts/reviewer-output.ts +2 -2
- package/src/package-contracts/terminating-tools.ts +31 -1
- package/src/packaged-role-registry.ts +43 -0
- package/src/pi/adapter.ts +2 -1
- package/src/pi/in-process-session.ts +38 -12
- package/src/pi/role-turn-host.ts +34 -0
- package/src/public-cli/cli.ts +14 -6
- package/src/public-cli/instruction-seat-run.ts +289 -50
- package/src/public-cli/invocation.ts +66 -25
- package/src/public-cli/option-definitions.ts +61 -0
- package/src/public-cli/post-admission.ts +7 -1
- package/src/public-cli/registry.ts +4 -1
- package/src/public-cli/run-lifecycle.ts +22 -3
- package/src/public-cli/settlement.ts +120 -5
- package/src/public-cli/terminal.ts +2 -0
- package/src/public-role-summons.ts +431 -0
- package/src/receipt-delivery-policy.ts +10 -0
- package/src/reviewer-agent.ts +1 -1
- package/src/reviewer-child-executor.ts +114 -12
- package/src/reviewer-execution-ledger.ts +3 -2
- package/src/role-runtime.ts +158 -17
- package/src/session-assistant-usage.ts +119 -0
- package/src/session-opening-materials.ts +1 -1
- package/src/shape-unreadable-failure.ts +49 -0
- package/src/submission-errors.ts +3 -0
- package/dist/evidence-child-executor.js +0 -829
- package/src/evidence-child-executor.ts +0 -1140
package/src/gatekeeper-role.ts
CHANGED
|
@@ -1,16 +1,11 @@
|
|
|
1
|
-
import { Type } from "typebox";
|
|
2
1
|
import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
3
2
|
import type { HostContext } from "./host-contracts.ts";
|
|
4
3
|
|
|
5
4
|
import {
|
|
6
5
|
auditorRunDirectory,
|
|
7
|
-
createAuditorDossierTool,
|
|
8
6
|
persistGateSubmissionCandidate,
|
|
9
7
|
} from "./auditor-dossier-tool.ts";
|
|
10
|
-
import { executeAuditorChild, type AuditorDecisionTool } from "./evidence-child-executor.ts";
|
|
11
|
-
import { openToolObject } from "./open-tool-schema.ts";
|
|
12
8
|
import type { NoReceiptLifecycleFacts } from "./receipt-delivery-policy.ts";
|
|
13
|
-
import { loadGatekeeperSessionMaterials } from "./session-opening-materials.ts";
|
|
14
9
|
import { GatekeeperDecisionError } from "./submission-errors.ts";
|
|
15
10
|
import { INSPECTOR_OUTPUT_TOOL_NAME } from "./inspector-contracts.ts";
|
|
16
11
|
import {
|
|
@@ -18,6 +13,9 @@ import {
|
|
|
18
13
|
gatekeeperDecisionSchema,
|
|
19
14
|
gatekeeperOutputSchema,
|
|
20
15
|
} from "./package-contracts/gatekeeper-output.ts";
|
|
16
|
+
import type { PublicSummonResult } from "./public-role-summons.ts";
|
|
17
|
+
import type { TerminalResult } from "./public-cli/terminal.ts";
|
|
18
|
+
import { retainedShapeUnreadable } from "./shape-unreadable-failure.ts";
|
|
21
19
|
export const INSPECTOR_OUTPUT_TOOL = INSPECTOR_OUTPUT_TOOL_NAME;
|
|
22
20
|
export const NOTARY_OUTPUT_TOOL = "ak_notary_output";
|
|
23
21
|
|
|
@@ -47,6 +45,13 @@ export type GatekeeperResult =
|
|
|
47
45
|
readonly submission: unknown;
|
|
48
46
|
}
|
|
49
47
|
| { readonly status: "no_receipt"; readonly stage: "inspector" | "notary"; readonly reason: string; readonly facts: NoReceiptLifecycleFacts }
|
|
48
|
+
| {
|
|
49
|
+
/** Shape-unreadable officer output — typed fact, not a forged bounce (ADR 0055 / §0). */
|
|
50
|
+
readonly status: "unreadable";
|
|
51
|
+
readonly officer: "inspector" | "notary";
|
|
52
|
+
readonly reason: string;
|
|
53
|
+
readonly submission: unknown;
|
|
54
|
+
}
|
|
50
55
|
| {
|
|
51
56
|
readonly status: "transport_failure";
|
|
52
57
|
readonly stage: "inspector" | "notary";
|
|
@@ -57,7 +62,7 @@ export type GatekeeperResult =
|
|
|
57
62
|
|
|
58
63
|
export type GatekeeperNonPassResult = Extract<
|
|
59
64
|
GatekeeperResult,
|
|
60
|
-
{ status: "bounce" | "no_receipt" }
|
|
65
|
+
{ status: "bounce" | "no_receipt" | "unreadable" }
|
|
61
66
|
>;
|
|
62
67
|
|
|
63
68
|
function gateSeatLabel(stage: "inspector" | "notary"): string {
|
|
@@ -75,14 +80,24 @@ export class GatekeeperEscalationError extends Error {
|
|
|
75
80
|
}
|
|
76
81
|
}
|
|
77
82
|
|
|
83
|
+
export type GateOfficerSummon = (
|
|
84
|
+
officer: "inspector" | "notary",
|
|
85
|
+
sourceRunDirectory: string,
|
|
86
|
+
/** Parent cancellation forwarded to the nested activation (#675). */
|
|
87
|
+
signal?: AbortSignal,
|
|
88
|
+
) => Promise<PublicSummonResult>;
|
|
89
|
+
|
|
78
90
|
export type RunGatekeeperOptions = {
|
|
79
91
|
readonly context: ExtensionContext | HostContext;
|
|
80
92
|
readonly subject: GatekeeperSubject;
|
|
81
93
|
readonly signal?: AbortSignal;
|
|
82
|
-
|
|
83
|
-
/** Run directory carrying the institutional resolution page (#518). Derives
|
|
84
|
-
* from context when absent. */
|
|
94
|
+
/** Run directory of the parent role (pointer-only summons, ADR 0079). */
|
|
85
95
|
readonly runDirectory?: string;
|
|
96
|
+
/**
|
|
97
|
+
* Test seam for public-role summons. Production calls the shared public
|
|
98
|
+
* activation path (#675); inject only in offline tracers.
|
|
99
|
+
*/
|
|
100
|
+
readonly summonOfficer?: GateOfficerSummon;
|
|
86
101
|
};
|
|
87
102
|
|
|
88
103
|
export type GatekeeperPassHostActions = {
|
|
@@ -91,15 +106,6 @@ export type GatekeeperPassHostActions = {
|
|
|
91
106
|
bindSubmissionNonPass(toolCallId: string, result: GatekeeperNonPassResult): void;
|
|
92
107
|
};
|
|
93
108
|
|
|
94
|
-
// Unknown fields so wrong types/spellings still reach projection (ADR 0055/0057; 仓第 0 条).
|
|
95
|
-
// Opening goes through the sole openToolObject owner — no parallel transport helper.
|
|
96
|
-
const officerDecisionSchema = openToolObject(Type.Object({
|
|
97
|
-
status: Type.Unknown({ description: "pass | bounce | escalate — 形状指引,非 schema 闸" }),
|
|
98
|
-
reason: Type.Optional(Type.Unknown({ description: "status 为 escalate 时的理由" })),
|
|
99
|
-
findings: Type.Unknown({ description: "string[] findings,随 pass、bounce 或 escalate 留存" }),
|
|
100
|
-
}));
|
|
101
|
-
|
|
102
|
-
|
|
103
109
|
/**
|
|
104
110
|
* Direct-seat decision tool spec (#639). Lifecycle assembly stays on the
|
|
105
111
|
* registration envelope — src/role-runtime.ts (ADR 0018). Schema authority is
|
|
@@ -121,30 +127,18 @@ function result(content: string, details: unknown) {
|
|
|
121
127
|
return { content: [{ type: "text" as const, text: content }], details };
|
|
122
128
|
}
|
|
123
129
|
|
|
124
|
-
/** Shared officer decision tool — open transport; projection owns legality. */
|
|
125
|
-
export function createOfficerDecisionTool(name: string): AuditorDecisionTool {
|
|
126
|
-
return {
|
|
127
|
-
name,
|
|
128
|
-
description: "提交一份 typed pass/bounce/escalate 决议。",
|
|
129
|
-
parameters: officerDecisionSchema,
|
|
130
|
-
async execute(_id, args) { return result(`已收 ${String((args as { status?: unknown })?.status)}`, args); },
|
|
131
|
-
};
|
|
132
|
-
}
|
|
133
|
-
|
|
134
130
|
/** Gatekeeper province decision tool — open transport; package-contract projection owns legality. */
|
|
135
|
-
export function createGatekeeperOutputTool()
|
|
131
|
+
export function createGatekeeperOutputTool() {
|
|
136
132
|
return {
|
|
137
133
|
name: GATEKEEPER_OUTPUT_TOOL_NAME,
|
|
138
134
|
description: "提交门下省派官决定。",
|
|
139
135
|
parameters: gatekeeperDecisionSchema,
|
|
140
|
-
async execute(_id, args
|
|
136
|
+
async execute(_id: string, args: unknown) {
|
|
137
|
+
return result(`已收 ${String((args as { status?: unknown })?.status)}`, args);
|
|
138
|
+
},
|
|
141
139
|
};
|
|
142
140
|
}
|
|
143
141
|
|
|
144
|
-
async function defaultLoadSoul(role: "inspector" | "notary"): Promise<string> {
|
|
145
|
-
return loadGatekeeperSessionMaterials(role);
|
|
146
|
-
}
|
|
147
|
-
|
|
148
142
|
function failureReason(error: unknown): string {
|
|
149
143
|
if (error instanceof AggregateError) return error.errors.map(failureReason).join("; ");
|
|
150
144
|
return error instanceof Error ? `${error.name}: ${error.message}` : String(error);
|
|
@@ -173,17 +167,19 @@ function retainedSubmission(decision: unknown): unknown {
|
|
|
173
167
|
}
|
|
174
168
|
|
|
175
169
|
/**
|
|
176
|
-
*
|
|
177
|
-
*
|
|
170
|
+
* Shape-unreadable officer decision — retain original candidate + typed reason.
|
|
171
|
+
* Not a forged bounce, not transport abort (CLAUDE.md §0 / ADR 0055).
|
|
172
|
+
* Real provider/engine/disk failures stay transport_failure elsewhere.
|
|
178
173
|
*/
|
|
179
|
-
function
|
|
180
|
-
|
|
174
|
+
function shapeUnreadable(
|
|
175
|
+
officer: "inspector" | "notary",
|
|
181
176
|
decision: unknown,
|
|
182
|
-
|
|
177
|
+
reason = "decision 无显式 pass/bounce/escalate",
|
|
178
|
+
): Extract<GatekeeperResult, { status: "unreadable" }> {
|
|
183
179
|
return {
|
|
184
|
-
status: "
|
|
185
|
-
|
|
186
|
-
reason
|
|
180
|
+
status: "unreadable",
|
|
181
|
+
officer,
|
|
182
|
+
reason,
|
|
187
183
|
submission: retainedSubmission(decision),
|
|
188
184
|
};
|
|
189
185
|
}
|
|
@@ -198,7 +194,7 @@ function projectOfficerDecision(
|
|
|
198
194
|
decision: unknown,
|
|
199
195
|
): GatekeeperResult {
|
|
200
196
|
const record = readRecord(decision);
|
|
201
|
-
if (record === undefined) return
|
|
197
|
+
if (record === undefined) return shapeUnreadable(officer, decision);
|
|
202
198
|
if (record.status === "bounce") {
|
|
203
199
|
return {
|
|
204
200
|
status: "bounce",
|
|
@@ -224,76 +220,121 @@ function projectOfficerDecision(
|
|
|
224
220
|
submission: retainedSubmission(decision),
|
|
225
221
|
};
|
|
226
222
|
}
|
|
227
|
-
return
|
|
223
|
+
return shapeUnreadable(officer, decision);
|
|
228
224
|
}
|
|
229
225
|
|
|
230
|
-
/**
|
|
231
|
-
|
|
232
|
-
|
|
226
|
+
/** Map a public-role terminal onto the gate officer result surface. */
|
|
227
|
+
function projectOfficerTerminal(
|
|
228
|
+
officer: "inspector" | "notary",
|
|
229
|
+
summoned: PublicSummonResult,
|
|
230
|
+
): GatekeeperResult {
|
|
231
|
+
const terminal: TerminalResult | undefined = summoned.terminal;
|
|
232
|
+
const outcome = terminal?.roleOutcome;
|
|
233
|
+
if (outcome === undefined) {
|
|
234
|
+
const detail = summoned.stderr?.trim();
|
|
235
|
+
return {
|
|
236
|
+
status: "transport_failure",
|
|
237
|
+
stage: officer,
|
|
238
|
+
reason: detail && detail.length > 0
|
|
239
|
+
? `${gateSeatLabel(officer)} public summon exit ${summoned.exitCode}: ${detail}`
|
|
240
|
+
: `${gateSeatLabel(officer)} public summon produced no terminal (exit ${summoned.exitCode})`,
|
|
241
|
+
submission: summoned,
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
if (outcome.kind === "no_receipt") {
|
|
245
|
+
return {
|
|
246
|
+
status: "no_receipt",
|
|
247
|
+
stage: officer,
|
|
248
|
+
reason: `${gateSeatLabel(officer)}未产生已接受回执即散局`,
|
|
249
|
+
facts: outcome,
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
if (outcome.kind === "failure") {
|
|
253
|
+
// Single settlement marker only (ADR 0055 / #675) — no cause=output re-derivation.
|
|
254
|
+
const shape = retainedShapeUnreadable(outcome.decisiveFacts);
|
|
255
|
+
if (shape !== undefined) {
|
|
256
|
+
return shapeUnreadable(officer, shape.candidate, outcome.diagnostic);
|
|
257
|
+
}
|
|
258
|
+
return {
|
|
259
|
+
status: "transport_failure",
|
|
260
|
+
stage: officer,
|
|
261
|
+
reason: outcome.diagnostic,
|
|
262
|
+
submission: outcome.decisiveFacts,
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
if (outcome.kind === "accepted") {
|
|
266
|
+
return projectOfficerDecision(officer, {
|
|
267
|
+
status: outcome.status,
|
|
268
|
+
...outcome.decisiveFacts,
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
return {
|
|
272
|
+
status: "transport_failure",
|
|
273
|
+
stage: officer,
|
|
274
|
+
reason: `${gateSeatLabel(officer)} public summon returned unusable terminal kind`,
|
|
275
|
+
submission: outcome,
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/** Projection carrier for the shared submit envelope (ADR 0018). No lifecycle book here. */
|
|
280
|
+
export type GatekeeperProjection = {
|
|
281
|
+
readonly officer: "inspector" | "notary";
|
|
282
|
+
readonly result: GatekeeperResult;
|
|
283
|
+
/** Present only when a public summon actually returned (not transport pre-summon failure). */
|
|
284
|
+
readonly summoned?: PublicSummonResult;
|
|
285
|
+
};
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Summon + project only. Lifecycle book and host abort face live on the shared
|
|
289
|
+
* submit envelope (`gatekeeper-pass-envelope.ts`, ADR 0018 / #675).
|
|
290
|
+
*/
|
|
291
|
+
export async function projectGatekeeperRun(
|
|
292
|
+
options: RunGatekeeperOptions,
|
|
293
|
+
): Promise<GatekeeperProjection> {
|
|
233
294
|
const officer = options.subject.kind === "worker_completion" ? "inspector" : "notary";
|
|
234
|
-
// Resolve once so dossier tool and child session share the same run binding (#632).
|
|
235
295
|
const runDirectory = options.runDirectory ?? auditorRunDirectory(options.context);
|
|
296
|
+
if (runDirectory === undefined) {
|
|
297
|
+
return {
|
|
298
|
+
officer,
|
|
299
|
+
result: {
|
|
300
|
+
status: "transport_failure",
|
|
301
|
+
stage: officer,
|
|
302
|
+
reason: `${gateSeatLabel(officer)} requires a parent run directory pointer`,
|
|
303
|
+
},
|
|
304
|
+
};
|
|
305
|
+
}
|
|
236
306
|
// Pointer-only summons need a resolvable leaf: Grok session.jsonl is header-only
|
|
237
307
|
// (#617 DK-4); write the in-memory tool-call candidate as a run artifact first (#632).
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
? undefined
|
|
241
|
-
: persistGateSubmissionCandidate(runDirectory, options.context);
|
|
308
|
+
persistGateSubmissionCandidate(runDirectory, options.context);
|
|
309
|
+
let summoned: PublicSummonResult;
|
|
242
310
|
try {
|
|
243
|
-
const
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
...(options.signal === undefined ? {} : { signal: options.signal }),
|
|
256
|
-
...(runDirectory === undefined ? {} : { runDirectory }),
|
|
257
|
-
});
|
|
258
|
-
if (officerRun.noReceiptLifecycle !== undefined) {
|
|
259
|
-
return { status: "no_receipt", stage: officer, reason: `${gateSeatLabel(officer)}未产生已接受回执即散局`, facts: officerRun.noReceiptLifecycle };
|
|
260
|
-
}
|
|
261
|
-
return projectOfficerDecision(officer, officerRun.decision);
|
|
311
|
+
const summon =
|
|
312
|
+
options.summonOfficer
|
|
313
|
+
?? (async (nextOfficer, sourceRunDirectory, officerSignal) => {
|
|
314
|
+
const { summonGateOfficer } = await import("./public-role-summons.ts");
|
|
315
|
+
return summonGateOfficer({
|
|
316
|
+
officer: nextOfficer,
|
|
317
|
+
sourceRunDirectory,
|
|
318
|
+
cwd: options.context.cwd ?? process.cwd(),
|
|
319
|
+
...(officerSignal === undefined ? {} : { signal: officerSignal }),
|
|
320
|
+
});
|
|
321
|
+
});
|
|
322
|
+
summoned = await summon(officer, runDirectory, options.signal);
|
|
262
323
|
} catch (error) {
|
|
263
|
-
return {
|
|
324
|
+
return {
|
|
325
|
+
officer,
|
|
326
|
+
result: { status: "transport_failure", stage: officer, reason: failureReason(error) },
|
|
327
|
+
};
|
|
264
328
|
}
|
|
329
|
+
return {
|
|
330
|
+
officer,
|
|
331
|
+
result: projectOfficerTerminal(officer, summoned),
|
|
332
|
+
summoned,
|
|
333
|
+
};
|
|
265
334
|
}
|
|
266
335
|
|
|
267
|
-
/**
|
|
268
|
-
export async function
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
readonly signal?: AbortSignal;
|
|
272
|
-
readonly hostActions: GatekeeperPassHostActions;
|
|
273
|
-
readonly toolCallId: string;
|
|
274
|
-
}): Promise<void> {
|
|
275
|
-
const gatekeeper = await runGatekeeper({
|
|
276
|
-
context: options.context,
|
|
277
|
-
subject: options.subject,
|
|
278
|
-
...(options.signal === undefined ? {} : { signal: options.signal }),
|
|
279
|
-
});
|
|
280
|
-
if (gatekeeper.status === "pass") return;
|
|
281
|
-
if (gatekeeper.status === "transport_failure") {
|
|
282
|
-
// Typed stage/reason/submission ride failInfrastructure → durable tool_result (#475).
|
|
283
|
-
const error = new Error(`交卷闸 transport_failure(${gatekeeper.stage}):${gatekeeper.reason}`) as Error & {
|
|
284
|
-
stage: typeof gatekeeper.stage;
|
|
285
|
-
reason: string;
|
|
286
|
-
submission?: unknown;
|
|
287
|
-
};
|
|
288
|
-
error.stage = gatekeeper.stage;
|
|
289
|
-
error.reason = gatekeeper.reason;
|
|
290
|
-
if (gatekeeper.submission !== undefined) error.submission = gatekeeper.submission;
|
|
291
|
-
options.hostActions.failInfrastructure(error, options.context, options.toolCallId);
|
|
292
|
-
}
|
|
293
|
-
if (gatekeeper.status === "escalate") {
|
|
294
|
-
throw new GatekeeperEscalationError(gatekeeper);
|
|
295
|
-
}
|
|
296
|
-
// Envelope owns the execute→tool_result bridge; this module only projects + throws.
|
|
297
|
-
options.hostActions.bindSubmissionNonPass(options.toolCallId, gatekeeper);
|
|
298
|
-
throw new GatekeeperDecisionError(gatekeeper);
|
|
336
|
+
/** Submission-gate summons: subject kind → officer; activation is public role path (#675). Projection only. */
|
|
337
|
+
export async function runGatekeeper(options: RunGatekeeperOptions): Promise<GatekeeperResult> {
|
|
338
|
+
const { result } = await projectGatekeeperRun(options);
|
|
339
|
+
return result;
|
|
299
340
|
}
|
package/src/host-contracts.ts
CHANGED
|
@@ -126,6 +126,8 @@ export type RoleTurnActivation =
|
|
|
126
126
|
| { readonly role: "inspector" }
|
|
127
127
|
| { readonly role: "gatekeeper" }
|
|
128
128
|
| { readonly role: "navigator" }
|
|
129
|
+
| { readonly role: "auditor" }
|
|
130
|
+
| { readonly role: "evidence-child" }
|
|
129
131
|
| {
|
|
130
132
|
readonly role: "diarist";
|
|
131
133
|
/** Frozen source-catalog path; absent for a true-unbound summons (#708). */
|
|
@@ -170,6 +172,12 @@ export type RoleTurnRequest = {
|
|
|
170
172
|
readonly runDirectory: string;
|
|
171
173
|
readonly correlationId?: string;
|
|
172
174
|
readonly timeoutMs?: number;
|
|
175
|
+
/**
|
|
176
|
+
* Parent cancellation for a nested activation (role-inside-role public summons,
|
|
177
|
+
* #675). The host terminates its child when this aborts; a public CLI process
|
|
178
|
+
* has no parent to observe and leaves it absent.
|
|
179
|
+
*/
|
|
180
|
+
readonly signal?: AbortSignal;
|
|
173
181
|
/** Set by post-admission only on a real host switch; never on same-host resume. */
|
|
174
182
|
readonly hostTransition?: RoleTurnHostTransition;
|
|
175
183
|
/**
|
|
@@ -295,7 +303,7 @@ type HostGatekeeperSubject = {
|
|
|
295
303
|
readonly kind: "worker_completion" | "judge_draft" | "countersign_verdict";
|
|
296
304
|
};
|
|
297
305
|
/** Gatekeeper bounce/no_receipt plus other correct submission rejects share one projection map. */
|
|
298
|
-
type HostGatekeeperNonPass = { readonly status: "bounce" | "no_receipt" } & Record<string, unknown>;
|
|
306
|
+
type HostGatekeeperNonPass = { readonly status: "bounce" | "no_receipt" | "unreadable" } & Record<string, unknown>;
|
|
299
307
|
export type HostSubmissionNonPass =
|
|
300
308
|
| HostGatekeeperNonPass
|
|
301
309
|
| { readonly code: "coder_skill_expansion_evidence_missing" };
|
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Province-officer model authority (#453/#620) and shared seatModelOnly projection.
|
|
3
|
+
* #675 deleted the independent institutional-resolution.json seat page and the
|
|
4
|
+
* child-session open path that consumed it. Seat resolution for every activation
|
|
5
|
+
* is the live public seat table (model/host/engine).
|
|
6
|
+
*/
|
|
4
7
|
import type {
|
|
5
8
|
GateOfficerSeat,
|
|
6
9
|
PublicCliConfig,
|
|
@@ -8,70 +11,20 @@ import type {
|
|
|
8
11
|
} from "./public-cli/config.ts";
|
|
9
12
|
import { seatModelOnly } from "./public-cli/registry.ts";
|
|
10
13
|
|
|
11
|
-
export const INSTITUTIONAL_RESOLUTION_FILE = "institutional-resolution.json" as const;
|
|
12
|
-
|
|
13
|
-
/** Non-secret per-seat model selection — alias of the single host-neutral RoleTurnModelConfig. */
|
|
14
|
-
export type InstitutionalSeatSelection = RoleTurnModelConfig;
|
|
15
|
-
|
|
16
14
|
/**
|
|
17
15
|
* Configured province-officer resolution (#453/#620 authority seam):
|
|
18
16
|
* officer persistent > gatekeeper persistent > unconfigured.
|
|
19
|
-
* No startup candidates and no parent-session fallback —
|
|
20
|
-
*
|
|
21
|
-
* this typed result as-is.
|
|
17
|
+
* No startup candidates and no parent-session fallback — direct call and config
|
|
18
|
+
* display consume this typed result as-is.
|
|
22
19
|
*/
|
|
23
20
|
export type ConfiguredProvinceOfficerResolution = {
|
|
24
21
|
readonly selection?: SeatModelConfig;
|
|
25
22
|
readonly source: "persistent" | "inherit-gatekeeper" | "unconfigured";
|
|
26
23
|
};
|
|
27
24
|
|
|
28
|
-
export type InstitutionalResolutionPage = {
|
|
29
|
-
readonly version: 1;
|
|
30
|
-
readonly seats: {
|
|
31
|
-
readonly gatekeeper?: InstitutionalSeatSelection;
|
|
32
|
-
readonly inspector?: InstitutionalSeatSelection;
|
|
33
|
-
readonly notary?: InstitutionalSeatSelection;
|
|
34
|
-
readonly auditor?: InstitutionalSeatSelection;
|
|
35
|
-
readonly evidenceChild?: InstitutionalSeatSelection;
|
|
36
|
-
readonly [seat: string]: InstitutionalSeatSelection | undefined;
|
|
37
|
-
};
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
/** Why institutional seat read failed — structured, not free-text. */
|
|
41
|
-
export type InstitutionalResolutionFailureReason =
|
|
42
|
-
| "missing-page"
|
|
43
|
-
| "missing-seat"
|
|
44
|
-
| "corrupted"
|
|
45
|
-
| "invalid-format";
|
|
46
|
-
|
|
47
|
-
export class InstitutionalResolutionError extends Error {
|
|
48
|
-
readonly reason: InstitutionalResolutionFailureReason;
|
|
49
|
-
constructor(
|
|
50
|
-
message: string,
|
|
51
|
-
reason: InstitutionalResolutionFailureReason,
|
|
52
|
-
options?: ErrorOptions,
|
|
53
|
-
) {
|
|
54
|
-
super(message, options);
|
|
55
|
-
this.name = "InstitutionalResolutionError";
|
|
56
|
-
this.reason = reason;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
function cleanSelection(model?: { provider?: string; model?: string; thinking?: string }): InstitutionalSeatSelection | undefined {
|
|
61
|
-
if (model === undefined) return undefined;
|
|
62
|
-
if (typeof model.provider !== "string" || typeof model.model !== "string") return undefined;
|
|
63
|
-
return {
|
|
64
|
-
provider: model.provider,
|
|
65
|
-
model: model.model,
|
|
66
|
-
...(model.thinking === undefined ? {} : { thinking: model.thinking }),
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
|
|
70
25
|
/**
|
|
71
26
|
* Authority for configured province-officer model+source (#453/#620):
|
|
72
27
|
* own persistent > gatekeeper persistent > unconfigured.
|
|
73
|
-
* Shared by resolveInstitutionalSeatSelections (plus parent fallback),
|
|
74
|
-
* resolveEffectiveSeat subordinate branch, and roles/config display.
|
|
75
28
|
* Model-axis projection stays seatModelOnly (single implementation in registry).
|
|
76
29
|
*/
|
|
77
30
|
export function resolveConfiguredProvinceOfficer(
|
|
@@ -91,111 +44,3 @@ export function resolveConfiguredProvinceOfficer(
|
|
|
91
44
|
}
|
|
92
45
|
return { source: "unconfigured" };
|
|
93
46
|
}
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Resolve effective per-seat institutional selections (#518 §2 Hop 1; #620):
|
|
97
|
-
* - gatekeeper / inspector / notary: resolveConfiguredProvinceOfficer then
|
|
98
|
-
* parent effective on the province path only
|
|
99
|
-
* - auditor / evidenceChild: parent effective
|
|
100
|
-
* - navigator: explicit config seat only. Navigator model authority stays
|
|
101
|
-
* `navigator-model.json`; the page never carries a parent-inherited navigator
|
|
102
|
-
* seat, so host-neutral transport cannot shadow that setting (#590 Out of Scope:
|
|
103
|
-
* 席位表/模型路由变更归 owner 域).
|
|
104
|
-
*/
|
|
105
|
-
export function resolveInstitutionalSeatSelections(
|
|
106
|
-
config: PublicCliConfig,
|
|
107
|
-
parentEffectiveModel?: { provider: string; model: string; thinking?: string },
|
|
108
|
-
): InstitutionalResolutionPage {
|
|
109
|
-
const parentSelection = cleanSelection(parentEffectiveModel);
|
|
110
|
-
|
|
111
|
-
const gatekeeper =
|
|
112
|
-
resolveConfiguredProvinceOfficer(config, "gatekeeper").selection ?? parentSelection;
|
|
113
|
-
const inspector =
|
|
114
|
-
resolveConfiguredProvinceOfficer(config, "inspector").selection ?? parentSelection;
|
|
115
|
-
const notary =
|
|
116
|
-
resolveConfiguredProvinceOfficer(config, "notary").selection ?? parentSelection;
|
|
117
|
-
const auditor = parentSelection;
|
|
118
|
-
const evidenceChild = parentSelection;
|
|
119
|
-
const navigator = cleanSelection(seatModelOnly(config.seats?.navigator));
|
|
120
|
-
|
|
121
|
-
return {
|
|
122
|
-
version: 1,
|
|
123
|
-
seats: {
|
|
124
|
-
...(gatekeeper === undefined ? {} : { gatekeeper }),
|
|
125
|
-
...(inspector === undefined ? {} : { inspector }),
|
|
126
|
-
...(notary === undefined ? {} : { notary }),
|
|
127
|
-
...(auditor === undefined ? {} : { auditor }),
|
|
128
|
-
...(evidenceChild === undefined ? {} : { evidenceChild }),
|
|
129
|
-
...(navigator === undefined ? {} : { navigator }),
|
|
130
|
-
},
|
|
131
|
-
};
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* Persist institutional resolution page to run directory (#518 §2 Hop 2).
|
|
136
|
-
* Rewritten on each dispatch and resume. Zero secrets inside page.
|
|
137
|
-
*/
|
|
138
|
-
export async function writeInstitutionalResolutionPage(
|
|
139
|
-
runDirectory: string,
|
|
140
|
-
page: InstitutionalResolutionPage,
|
|
141
|
-
): Promise<void> {
|
|
142
|
-
const filePath = join(runDirectory, INSTITUTIONAL_RESOLUTION_FILE);
|
|
143
|
-
await writeFile(filePath, `${JSON.stringify(page, null, 2)}\n`, "utf8");
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* Read institutional seat selection from run directory (#518 §2 Hop 3).
|
|
148
|
-
* Fails loud if page is missing, corrupted, or does not contain a resolution for the seat.
|
|
149
|
-
*/
|
|
150
|
-
export async function readInstitutionalSeatSelection(
|
|
151
|
-
runDirectory: string,
|
|
152
|
-
seat: string,
|
|
153
|
-
): Promise<InstitutionalSeatSelection> {
|
|
154
|
-
const filePath = join(runDirectory, INSTITUTIONAL_RESOLUTION_FILE);
|
|
155
|
-
let raw: string;
|
|
156
|
-
try {
|
|
157
|
-
raw = await readFile(filePath, "utf8");
|
|
158
|
-
} catch (error) {
|
|
159
|
-
throw new InstitutionalResolutionError(
|
|
160
|
-
`institutional resolution page is missing at ${filePath}`,
|
|
161
|
-
"missing-page",
|
|
162
|
-
{ cause: error },
|
|
163
|
-
);
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
let page: unknown;
|
|
167
|
-
try {
|
|
168
|
-
page = JSON.parse(raw);
|
|
169
|
-
} catch (error) {
|
|
170
|
-
throw new InstitutionalResolutionError(
|
|
171
|
-
`institutional resolution page is corrupted at ${filePath}`,
|
|
172
|
-
"corrupted",
|
|
173
|
-
{ cause: error },
|
|
174
|
-
);
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
if (typeof page !== "object" || page === null || (page as { version?: unknown }).version !== 1) {
|
|
178
|
-
throw new InstitutionalResolutionError(
|
|
179
|
-
`institutional resolution page format is invalid at ${filePath}`,
|
|
180
|
-
"invalid-format",
|
|
181
|
-
);
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
const seats = (page as { seats?: Record<string, unknown> }).seats;
|
|
185
|
-
if (typeof seats !== "object" || seats === null) {
|
|
186
|
-
throw new InstitutionalResolutionError(
|
|
187
|
-
`institutional resolution page missing seats object at ${filePath}`,
|
|
188
|
-
"invalid-format",
|
|
189
|
-
);
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
const selection = cleanSelection(seats[seat] as InstitutionalSeatSelection | undefined);
|
|
193
|
-
if (selection === undefined) {
|
|
194
|
-
throw new InstitutionalResolutionError(
|
|
195
|
-
`institutional resolution page has no resolution for seat "${seat}" at ${filePath}`,
|
|
196
|
-
"missing-seat",
|
|
197
|
-
);
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
return selection;
|
|
201
|
-
}
|
package/src/judge-auditor.ts
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
|
-
createComplianceDecisionTool,
|
|
3
2
|
runComplianceAudit,
|
|
3
|
+
type AuditorSummon,
|
|
4
4
|
type ComplianceDecision,
|
|
5
5
|
} from "./compliance-transport.ts";
|
|
6
6
|
import { auditorRunDirectory } from "./auditor-dossier-tool.ts";
|
|
7
|
-
import { loadAuditorSoul } from "./auditor-soul.ts";
|
|
8
7
|
import {
|
|
9
8
|
readJudgeAuditSubjects,
|
|
10
9
|
requireAuditMaterials,
|
|
@@ -18,17 +17,13 @@ export const SOUL_AUDIT_TOOL_NAME = JUDGE_AUDIT_TOOL_NAME;
|
|
|
18
17
|
export type JudgeAuditOptions = {
|
|
19
18
|
context: HostContext;
|
|
20
19
|
signal?: AbortSignal;
|
|
20
|
+
/** Same seam as runComplianceAudit options — offline tracers only. */
|
|
21
|
+
summonAuditor?: AuditorSummon;
|
|
21
22
|
};
|
|
22
23
|
|
|
23
|
-
const auditDecisionTool = createComplianceDecisionTool(
|
|
24
|
-
JUDGE_AUDIT_TOOL_NAME,
|
|
25
|
-
"提交 typed pass/revise/escalate 决议(大理寺审刑)。",
|
|
26
|
-
);
|
|
27
|
-
|
|
28
24
|
/**
|
|
29
|
-
* Judge auditor
|
|
30
|
-
*
|
|
31
|
-
* proceeds without that pointer and self-locates per soul.
|
|
25
|
+
* Judge compliance via public auditor activation (#675 / ADR 0062 / owner r11).
|
|
26
|
+
* 审刑院 is an independent role; subject=judge selects souls/judge-auditor.md.
|
|
32
27
|
*/
|
|
33
28
|
export function createPiJudgeAuditor(): (options: JudgeAuditOptions) => Promise<ComplianceDecision> {
|
|
34
29
|
return async (options) => {
|
|
@@ -38,13 +33,13 @@ export function createPiJudgeAuditor(): (options: JudgeAuditOptions) => Promise<
|
|
|
38
33
|
requireAuditMaterials(subjects);
|
|
39
34
|
|
|
40
35
|
return runComplianceAudit({
|
|
41
|
-
|
|
42
|
-
systemPrompt: await loadAuditorSoul("judge"),
|
|
43
|
-
roleLabel: "Judge compliance audit",
|
|
44
|
-
invalidDecisionLabel: "invalid judge audit decision",
|
|
36
|
+
subject: "judge",
|
|
45
37
|
context: options.context,
|
|
46
|
-
...(auditorRunDirectory(options.context) === undefined
|
|
38
|
+
...(auditorRunDirectory(options.context) === undefined
|
|
39
|
+
? {}
|
|
40
|
+
: { runDirectory: auditorRunDirectory(options.context) }),
|
|
47
41
|
...(options.signal === undefined ? {} : { signal: options.signal }),
|
|
42
|
+
...(options.summonAuditor === undefined ? {} : { summonAuditor: options.summonAuditor }),
|
|
48
43
|
});
|
|
49
44
|
};
|
|
50
45
|
}
|
package/src/judge-role.ts
CHANGED
|
@@ -8,6 +8,7 @@ import { withInfrastructureFailureDeclaration } from "./package-contracts/termin
|
|
|
8
8
|
|
|
9
9
|
import {
|
|
10
10
|
JUDGE_ACCEPTED_AUDIT_NO_RECEIPT_TEXT,
|
|
11
|
+
JUDGE_ACCEPTED_AUDIT_UNREADABLE_TEXT,
|
|
11
12
|
JUDGE_ACCEPTED_TEXT,
|
|
12
13
|
JUDGE_OUTPUT_TOOL_NAME,
|
|
13
14
|
validateAcceptedJudgeDetails,
|
|
@@ -127,6 +128,13 @@ export function createJudgeRoleRuntime(
|
|
|
127
128
|
terminate: true as const,
|
|
128
129
|
...usageProjection,
|
|
129
130
|
}),
|
|
131
|
+
// ADR 0055: parent stands with typed unreadable audit fact — not forged pass.
|
|
132
|
+
unreadable: (auditUnreadable, usageProjection) => ({
|
|
133
|
+
content: [{ type: "text" as const, text: JUDGE_ACCEPTED_AUDIT_UNREADABLE_TEXT }],
|
|
134
|
+
details: { ...acceptedDetails, auditUnreadable },
|
|
135
|
+
terminate: true as const,
|
|
136
|
+
...usageProjection,
|
|
137
|
+
}),
|
|
130
138
|
revise: (violations) => {
|
|
131
139
|
throw new Error(
|
|
132
140
|
`大理寺回执违 soul:${violations.join("; ")}`,
|