@akagilnc/pi-workflow-roles 0.1.3565 → 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/README.md +4 -1
- package/README.zh-CN.md +1 -1
- package/dist/acp-host/production-host.js +18477 -8099
- 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-contracts.js +72 -0
- 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 +44 -3
- package/dist/package-resources/method-skill.js +254 -0
- package/dist/packaged-role-registry.js +56 -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 +1511 -1124
- 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 +8 -2
- 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 +8 -0
- package/package.json +1 -1
- package/resources/diarist-collect.md +6 -10
- package/scripts/build-package.mjs +2 -1
- package/souls/diarist.md +9 -0
- package/souls/doctor-auditor.md +1 -0
- package/souls/evidence-child.md +1 -0
- package/src/acp-host/production-host.ts +4 -0
- package/src/acp-host/role-envelope.ts +4 -3
- 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/diarist-contracts.ts +88 -0
- package/src/diarist-role.ts +60 -0
- package/src/diarist.ts +253 -179
- 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 +15 -2
- 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 +53 -3
- package/src/packaged-role-registry.ts +63 -0
- package/src/pi/adapter.ts +2 -1
- package/src/pi/in-process-session.ts +38 -12
- package/src/pi/role-turn-host.ts +42 -0
- package/src/public-cli/cli.ts +43 -6
- package/src/public-cli/countersign-run.ts +9 -129
- package/src/public-cli/diarist-run.ts +312 -0
- package/src/public-cli/instruction-seat-run.ts +289 -50
- package/src/public-cli/invocation.ts +87 -25
- package/src/public-cli/option-definitions.ts +79 -0
- package/src/public-cli/post-admission.ts +9 -3
- package/src/public-cli/registry.ts +7 -1
- package/src/public-cli/run-lifecycle.ts +53 -6
- package/src/public-cli/settlement.ts +170 -7
- package/src/public-cli/terminal.ts +4 -1
- 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 +275 -23
- 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/src/ticket-provenance-contracts.ts +1 -0
- package/src/ticket-provenance.ts +0 -23
- package/dist/evidence-child-executor.js +0 -829
- package/src/diarist-llm-collector.ts +0 -324
- package/src/evidence-child-executor.ts +0 -1140
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared submit-path envelope for 门下省 gates (ADR 0018 / #675).
|
|
3
|
+
* Owns officer-pointer book + host abort/non-pass faces.
|
|
4
|
+
* Role modules only project via projectGatekeeperRun / runGatekeeper — no book, no catch.
|
|
5
|
+
*/
|
|
6
|
+
import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
7
|
+
import { bookDirectOfficerRunPointer } from "./archivist-record-entry.ts";
|
|
8
|
+
import type { HostContext } from "./host-contracts.ts";
|
|
9
|
+
import {
|
|
10
|
+
GatekeeperDecisionError,
|
|
11
|
+
GatekeeperEscalationError,
|
|
12
|
+
projectGatekeeperRun,
|
|
13
|
+
type GatekeeperPassHostActions,
|
|
14
|
+
type GatekeeperResult,
|
|
15
|
+
type GatekeeperSubject,
|
|
16
|
+
type GateOfficerSummon,
|
|
17
|
+
} from "./gatekeeper-role.ts";
|
|
18
|
+
import type { PublicSummonResult } from "./public-role-summons.ts";
|
|
19
|
+
import { sessionFileFromPublicSummon } from "./session-assistant-usage.ts";
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Book a typed pointer under parent session/auditor-roles (archivist-owned write).
|
|
23
|
+
* Offline mocks without a real session leave no nested volume (lawful zero).
|
|
24
|
+
*/
|
|
25
|
+
function bookDirectOfficerPointer(
|
|
26
|
+
context: ExtensionContext | HostContext,
|
|
27
|
+
officer: "inspector" | "notary",
|
|
28
|
+
result: GatekeeperResult,
|
|
29
|
+
summoned: PublicSummonResult,
|
|
30
|
+
): void {
|
|
31
|
+
if (
|
|
32
|
+
result.status !== "pass"
|
|
33
|
+
&& result.status !== "bounce"
|
|
34
|
+
&& result.status !== "escalate"
|
|
35
|
+
&& result.status !== "unreadable"
|
|
36
|
+
) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const parentFile = context.sessionManager?.getSessionFile?.();
|
|
40
|
+
if (typeof parentFile !== "string" || parentFile.trim() === "") return;
|
|
41
|
+
const sessionFile = sessionFileFromPublicSummon(summoned);
|
|
42
|
+
if (sessionFile === undefined) {
|
|
43
|
+
// No independent 正本 to point at — do not synthesize a parallel session.
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
bookDirectOfficerRunPointer({
|
|
47
|
+
parentSessionFile: parentFile,
|
|
48
|
+
officer,
|
|
49
|
+
sessionFile,
|
|
50
|
+
...(typeof summoned.runDirectory === "string" && summoned.runDirectory.trim() !== ""
|
|
51
|
+
? { runDirectory: summoned.runDirectory }
|
|
52
|
+
: {}),
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Shared envelope: project gate, book officer pointer, map onto host actions.
|
|
58
|
+
* unreadable = parent stands (ADR 0055); never mechanical NonPass reject.
|
|
59
|
+
*/
|
|
60
|
+
export async function requireGatekeeperPass(options: {
|
|
61
|
+
readonly context: ExtensionContext | HostContext;
|
|
62
|
+
readonly subject: GatekeeperSubject;
|
|
63
|
+
readonly signal?: AbortSignal;
|
|
64
|
+
readonly hostActions: GatekeeperPassHostActions;
|
|
65
|
+
readonly toolCallId: string;
|
|
66
|
+
/** Lowest seam: same as runGatekeeper options.summonOfficer — offline tracers only. */
|
|
67
|
+
readonly summonOfficer?: GateOfficerSummon;
|
|
68
|
+
}): Promise<void> {
|
|
69
|
+
const projected = await projectGatekeeperRun({
|
|
70
|
+
context: options.context,
|
|
71
|
+
subject: options.subject,
|
|
72
|
+
...(options.signal === undefined ? {} : { signal: options.signal }),
|
|
73
|
+
...(options.summonOfficer === undefined ? {} : { summonOfficer: options.summonOfficer }),
|
|
74
|
+
});
|
|
75
|
+
const gatekeeper = projected.result;
|
|
76
|
+
// Envelope-owned pointer book. Failure is host infrastructure — single face.
|
|
77
|
+
if (projected.summoned !== undefined) {
|
|
78
|
+
try {
|
|
79
|
+
bookDirectOfficerPointer(
|
|
80
|
+
options.context,
|
|
81
|
+
projected.officer,
|
|
82
|
+
gatekeeper,
|
|
83
|
+
projected.summoned,
|
|
84
|
+
);
|
|
85
|
+
} catch (error) {
|
|
86
|
+
options.hostActions.failInfrastructure(error, options.context, options.toolCallId);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
if (gatekeeper.status === "pass") return;
|
|
90
|
+
// ADR 0055 / #675: shape-unreadable officer output must not mechanically reject parent.
|
|
91
|
+
if (gatekeeper.status === "unreadable") return;
|
|
92
|
+
if (gatekeeper.status === "transport_failure") {
|
|
93
|
+
const error = new Error(`交卷闸 transport_failure(${gatekeeper.stage}):${gatekeeper.reason}`) as Error & {
|
|
94
|
+
stage: typeof gatekeeper.stage;
|
|
95
|
+
reason: string;
|
|
96
|
+
submission?: unknown;
|
|
97
|
+
};
|
|
98
|
+
error.stage = gatekeeper.stage;
|
|
99
|
+
error.reason = gatekeeper.reason;
|
|
100
|
+
if (gatekeeper.submission !== undefined) error.submission = gatekeeper.submission;
|
|
101
|
+
options.hostActions.failInfrastructure(error, options.context, options.toolCallId);
|
|
102
|
+
}
|
|
103
|
+
if (gatekeeper.status === "escalate") {
|
|
104
|
+
throw new GatekeeperEscalationError(gatekeeper);
|
|
105
|
+
}
|
|
106
|
+
// bounce / no_receipt: typed non-pass — envelope owns execute→tool_result bridge.
|
|
107
|
+
options.hostActions.bindSubmissionNonPass(options.toolCallId, gatekeeper);
|
|
108
|
+
throw new GatekeeperDecisionError(gatekeeper);
|
|
109
|
+
}
|
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
|
@@ -125,7 +125,14 @@ export type RoleTurnActivation =
|
|
|
125
125
|
}
|
|
126
126
|
| { readonly role: "inspector" }
|
|
127
127
|
| { readonly role: "gatekeeper" }
|
|
128
|
-
| { readonly role: "navigator" }
|
|
128
|
+
| { readonly role: "navigator" }
|
|
129
|
+
| { readonly role: "auditor" }
|
|
130
|
+
| { readonly role: "evidence-child" }
|
|
131
|
+
| {
|
|
132
|
+
readonly role: "diarist";
|
|
133
|
+
/** Frozen source-catalog path; absent for a true-unbound summons (#708). */
|
|
134
|
+
readonly sourcesPath?: string;
|
|
135
|
+
};
|
|
129
136
|
|
|
130
137
|
export type RoleTurnContinuation =
|
|
131
138
|
| { readonly kind: "initial"; readonly prompt: string }
|
|
@@ -165,6 +172,12 @@ export type RoleTurnRequest = {
|
|
|
165
172
|
readonly runDirectory: string;
|
|
166
173
|
readonly correlationId?: string;
|
|
167
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;
|
|
168
181
|
/** Set by post-admission only on a real host switch; never on same-host resume. */
|
|
169
182
|
readonly hostTransition?: RoleTurnHostTransition;
|
|
170
183
|
/**
|
|
@@ -290,7 +303,7 @@ type HostGatekeeperSubject = {
|
|
|
290
303
|
readonly kind: "worker_completion" | "judge_draft" | "countersign_verdict";
|
|
291
304
|
};
|
|
292
305
|
/** Gatekeeper bounce/no_receipt plus other correct submission rejects share one projection map. */
|
|
293
|
-
type HostGatekeeperNonPass = { readonly status: "bounce" | "no_receipt" } & Record<string, unknown>;
|
|
306
|
+
type HostGatekeeperNonPass = { readonly status: "bounce" | "no_receipt" | "unreadable" } & Record<string, unknown>;
|
|
294
307
|
export type HostSubmissionNonPass =
|
|
295
308
|
| HostGatekeeperNonPass
|
|
296
309
|
| { readonly code: "coder_skill_expansion_evidence_missing" };
|