@akagilnc/pi-workflow-roles 0.1.2479 → 0.1.2497
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/doctor-contracts.js +2 -1
- package/dist/merger-contracts.js +2 -1
- package/dist/notary-contracts.js +3 -2
- package/dist/package-contracts/fixer-output.js +2 -1
- package/dist/package-contracts/terminating-infrastructure.js +90 -0
- package/dist/public-cli/main.js +65 -12
- package/package.json +1 -1
- package/resources/navigator-route-playbook.md +2 -2
- package/src/collector-role.ts +6 -0
- package/src/collector-tool-schemas.ts +4 -1
- package/src/doctor-contracts.ts +4 -1
- package/src/doctor-role.ts +2 -1
- package/src/judge-role.ts +35 -26
- package/src/merger-contracts.ts +4 -1
- package/src/merger-role.ts +5 -1
- package/src/notary-contracts.ts +11 -8
- package/src/notary-role.ts +6 -0
- package/src/package-contracts/fixer-output.ts +4 -1
- package/src/package-contracts/terminating-infrastructure.ts +132 -0
- package/src/reviewer-role.ts +10 -1
- package/src/worker-role.ts +14 -2
package/dist/doctor-contracts.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Type } from "typebox";
|
|
2
2
|
import { canonicalJson } from "./canonical-json.js";
|
|
3
3
|
import { openToolObjectFromUnion } from "./open-tool-schema.js";
|
|
4
|
+
import { withInfrastructureFailureDeclaration } from "./package-contracts/terminating-infrastructure.js";
|
|
4
5
|
export const DOCTOR_EVIDENCE_TOOL_NAME = "ak_doctor_evidence";
|
|
5
6
|
export const DOCTOR_OUTPUT_TOOL_NAME = "ak_doctor_output";
|
|
6
7
|
export const DOCTOR_ACCEPTED_TEXT = "太医署回执已接受";
|
|
@@ -49,7 +50,7 @@ const doctorSubmissionVariants = Type.Union([
|
|
|
49
50
|
missingEvidence: Type.Array(Type.Object({ need: nonblank, targetKeys: Type.Array(nonblank, { minItems: 1 }) }, { additionalProperties: false }), { minItems: 1, description: "如实证词所需而尚缺的证据" }),
|
|
50
51
|
}, { additionalProperties: false, description: "证据不足以支撑如实案证词" }),
|
|
51
52
|
]);
|
|
52
|
-
export const doctorSubmissionSchema = openToolObjectFromUnion(doctorSubmissionVariants);
|
|
53
|
+
export const doctorSubmissionSchema = withInfrastructureFailureDeclaration(openToolObjectFromUnion(doctorSubmissionVariants));
|
|
53
54
|
export const doctorOutputSchema = Type.Union([
|
|
54
55
|
Type.Object({ status: Type.Literal("completed"), case: caseIdentity, findings: Type.Array(finding), cost }, { additionalProperties: false }),
|
|
55
56
|
doctorSubmissionVariants.anyOf[1],
|
package/dist/merger-contracts.js
CHANGED
|
@@ -3,6 +3,7 @@ import { isFullGitObjectId } from "./git-object-id.js";
|
|
|
3
3
|
import { exactUtf8 } from "./exact-utf8.js";
|
|
4
4
|
import { sha256Hex } from "./sha256.js";
|
|
5
5
|
import { openToolObjectFromUnion } from "./open-tool-schema.js";
|
|
6
|
+
import { withInfrastructureFailureDeclaration } from "./package-contracts/terminating-infrastructure.js";
|
|
6
7
|
const oidPattern = "^(?:[0-9a-f]{40}|[0-9a-f]{64})$";
|
|
7
8
|
const materialSchema = Type.Object({ bytesBase64: Type.String(), sha256: Type.String() }, { additionalProperties: false });
|
|
8
9
|
const checkSchema = Type.Object({ name: Type.String({ minLength: 1 }), argv: Type.Array(Type.String({ minLength: 1 }), { minItems: 1 }) }, { additionalProperties: false });
|
|
@@ -18,7 +19,7 @@ const mergerOutputVariants = Type.Union([
|
|
|
18
19
|
Type.Object({ status: Type.Literal("completed", { description: "completed — 形状指引,非 schema 闸" }), attemptId: Type.String({ minLength: 1, description: "已受理合并 attempt 身份" }), report: Type.String({ minLength: 1, description: "如实结果报告" }), mergeCommitId: Type.String({ pattern: oidPattern, description: "已核验的完成合并 commit object ID" }) }, { additionalProperties: false }),
|
|
19
20
|
Type.Object({ status: Type.Literal("escalate", { description: "escalate — 形状指引,非 schema 闸" }), attemptId: Type.String({ minLength: 1, description: "已受理合并 attempt 身份" }), diagnosis: Type.String({ minLength: 1, description: "合并完成需升级的原因" }), report: Type.String({ minLength: 1, description: "如实结果报告" }) }, { additionalProperties: false }),
|
|
20
21
|
]);
|
|
21
|
-
export const mergerOutputSchema = openToolObjectFromUnion(mergerOutputVariants);
|
|
22
|
+
export const mergerOutputSchema = withInfrastructureFailureDeclaration(openToolObjectFromUnion(mergerOutputVariants));
|
|
22
23
|
export const MERGER_OUTPUT_TOOL_NAME = "ak_merger_output";
|
|
23
24
|
export const MERGER_ACCEPTED_TEXT = "合并回执已接受";
|
|
24
25
|
const record = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
package/dist/notary-contracts.js
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { Type } from "typebox";
|
|
7
7
|
import { openToolObject } from "./open-tool-schema.js";
|
|
8
|
+
import { withInfrastructureFailureDeclaration } from "./package-contracts/terminating-infrastructure.js";
|
|
8
9
|
export const NOTARY_OUTPUT_TOOL_NAME = "ak_notary_output";
|
|
9
10
|
export const NOTARY_ACCEPTED_TEXT = "符宝郎回执已接受";
|
|
10
11
|
export const NOTARY_SOURCE_RUN_FLAG = {
|
|
@@ -16,14 +17,14 @@ export const NOTARY_SOURCE_RUN_FLAG = {
|
|
|
16
17
|
};
|
|
17
18
|
/** Package-owned kickoff only — callers supply zero prompt bytes (ADR 0067 / #448). */
|
|
18
19
|
export const NOTARY_FIXED_KICKOFF = "符宝郎案卷已受理;来源 run 定位见会话材料。";
|
|
19
|
-
export const notaryOutputSchema = openToolObject(Type.Object({
|
|
20
|
+
export const notaryOutputSchema = withInfrastructureFailureDeclaration(openToolObject(Type.Object({
|
|
20
21
|
status: Type.Unknown({
|
|
21
22
|
description: "pass | bounce — 形状指引,非 schema 闸",
|
|
22
23
|
}),
|
|
23
24
|
findings: Type.Unknown({
|
|
24
25
|
description: "string[] findings,随 pass 或 bounce 留存",
|
|
25
26
|
}),
|
|
26
|
-
}));
|
|
27
|
+
})));
|
|
27
28
|
function isRecord(value) {
|
|
28
29
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
29
30
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Type } from "typebox";
|
|
2
2
|
import { FIXER_PREREQUISITE_ID_PATTERN } from "./fixer-packet.js";
|
|
3
3
|
import { openToolObjectFromUnion } from "../open-tool-schema.js";
|
|
4
|
+
import { withInfrastructureFailureDeclaration } from "./terminating-infrastructure.js";
|
|
4
5
|
export const FIXER_OUTPUT_TOOL_NAME = "ak_fixer_output";
|
|
5
6
|
export const FIXER_ACCEPTED_TEXT = "修内司回执已接受";
|
|
6
7
|
const nonblankTransportString = Type.String({ minLength: 1 });
|
|
@@ -37,7 +38,7 @@ const fixerOutputVariants = Type.Union([
|
|
|
37
38
|
Type.Object({ status: Type.Literal("refused", { description: "refused — 形状指引,非 schema 闸" }), report: Type.String({ minLength: 1, description: "如实结果报告" }), classResults: Type.Array(classResultSchema, { minItems: 1, description: "各类拒绝结算" }) }),
|
|
38
39
|
Type.Object({ status: Type.Literal("partially_completed", { description: "partially_completed — 形状指引,非 schema 闸" }), report: Type.String({ minLength: 1, description: "如实结果报告" }), classResults: Type.Array(classResultSchema, { minItems: 1, description: "各类完成或拒绝结算" }), testEvidence: Type.Optional(testEvidenceSchema) }),
|
|
39
40
|
]);
|
|
40
|
-
export const fixerOutputSchema = openToolObjectFromUnion(fixerOutputVariants);
|
|
41
|
+
export const fixerOutputSchema = withInfrastructureFailureDeclaration(openToolObjectFromUnion(fixerOutputVariants));
|
|
41
42
|
export function validateFixerOutput(value, _phase) {
|
|
42
43
|
return value;
|
|
43
44
|
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Package-owned shared infrastructure-failure declaration for every primary
|
|
3
|
+
* packaged-role output tool (#541).
|
|
4
|
+
*
|
|
5
|
+
* One module owns what the judge mandates be shared (not reimplemented per
|
|
6
|
+
* seat): the typed `infrastructureFailure.diagnostic` declaration composed into
|
|
7
|
+
* each output tool's schema, and the single early host `failInfrastructure`
|
|
8
|
+
* call each output `execute` makes before any role business validation / gate /
|
|
9
|
+
* audit / ledger / Git work. The accepted status sets are intentionally NOT
|
|
10
|
+
* extended: an infra declaration fails BEFORE accepted validation, never
|
|
11
|
+
* becomes an accepted receipt. The diagnostic is carried verbatim on the thrown
|
|
12
|
+
* Error so settlement keeps the original cause (kind=failure, exit 1).
|
|
13
|
+
*/
|
|
14
|
+
import { Type } from "typebox";
|
|
15
|
+
export const INFRASTRUCTURE_FAILURE_DECLARATION_KEY = "infrastructureFailure";
|
|
16
|
+
export const INFRASTRUCTURE_FAILURE_DIAGNOSTIC_KEY = "diagnostic";
|
|
17
|
+
/** Shared typed declaration fragment: `infrastructureFailure.diagnostic` = non-empty string. */
|
|
18
|
+
const infrastructureFailureDeclarationSchema = Type.Object({
|
|
19
|
+
[INFRASTRUCTURE_FAILURE_DECLARATION_KEY]: Type.Object({
|
|
20
|
+
[INFRASTRUCTURE_FAILURE_DIAGNOSTIC_KEY]: Type.String({
|
|
21
|
+
minLength: 1,
|
|
22
|
+
description: "非空基础设施失败诊断",
|
|
23
|
+
}),
|
|
24
|
+
}, {
|
|
25
|
+
additionalProperties: true,
|
|
26
|
+
description: "基础设施失败声明",
|
|
27
|
+
}),
|
|
28
|
+
}, { additionalProperties: true });
|
|
29
|
+
/**
|
|
30
|
+
* Compose the shared infrastructure-failure declaration into an open output
|
|
31
|
+
* tool-object schema. Returns an open object (additionalProperties: true,
|
|
32
|
+
* required: []) with the base schema's properties plus the shared declaration.
|
|
33
|
+
* Static typing is preserved on the base (`as S`), so existing
|
|
34
|
+
* `Static<typeof ...>` derived parameter types are unchanged.
|
|
35
|
+
*/
|
|
36
|
+
export function withInfrastructureFailureDeclaration(schema) {
|
|
37
|
+
const baseProperties = schema
|
|
38
|
+
.properties;
|
|
39
|
+
const properties = {
|
|
40
|
+
...(baseProperties ?? {}),
|
|
41
|
+
[INFRASTRUCTURE_FAILURE_DECLARATION_KEY]: infrastructureFailureDeclarationSchema.properties[INFRASTRUCTURE_FAILURE_DECLARATION_KEY],
|
|
42
|
+
};
|
|
43
|
+
const object = Type.Object(properties, { additionalProperties: true });
|
|
44
|
+
object.required = [];
|
|
45
|
+
return object;
|
|
46
|
+
}
|
|
47
|
+
/** Safe recognition of the typed declaration; non-shapes / hostile input fail closed. */
|
|
48
|
+
function isInfrastructureFailureDeclaration(parameters) {
|
|
49
|
+
if (parameters === null ||
|
|
50
|
+
typeof parameters !== "object" ||
|
|
51
|
+
Array.isArray(parameters)) {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
const record = parameters;
|
|
55
|
+
if (!Object.hasOwn(record, INFRASTRUCTURE_FAILURE_DECLARATION_KEY))
|
|
56
|
+
return false;
|
|
57
|
+
const declaration = record[INFRASTRUCTURE_FAILURE_DECLARATION_KEY];
|
|
58
|
+
if (declaration === null ||
|
|
59
|
+
typeof declaration !== "object" ||
|
|
60
|
+
Array.isArray(declaration)) {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
const diagnostic = declaration[INFRASTRUCTURE_FAILURE_DIAGNOSTIC_KEY];
|
|
64
|
+
return typeof diagnostic === "string" && diagnostic.trim().length > 0;
|
|
65
|
+
}
|
|
66
|
+
/** Non-empty trimmed diagnostic from the declaration, else undefined. */
|
|
67
|
+
function infrastructureFailureDiagnostic(parameters) {
|
|
68
|
+
if (!isInfrastructureFailureDeclaration(parameters))
|
|
69
|
+
return undefined;
|
|
70
|
+
const declaration = parameters[INFRASTRUCTURE_FAILURE_DECLARATION_KEY];
|
|
71
|
+
const diagnostic = declaration[INFRASTRUCTURE_FAILURE_DIAGNOSTIC_KEY];
|
|
72
|
+
return typeof diagnostic === "string" ? diagnostic.trim() : undefined;
|
|
73
|
+
}
|
|
74
|
+
/** diagnostic → Error, name stamped so the host error identity is observable. */
|
|
75
|
+
function infrastructureFailureError(diagnostic) {
|
|
76
|
+
const error = new Error(diagnostic);
|
|
77
|
+
error.name = "InfrastructureFailure";
|
|
78
|
+
return error;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* The one early call for every terminating output `execute`: if the parameters
|
|
82
|
+
* carry the infra declaration, hand the diagnostic error to the shared host
|
|
83
|
+
* `failInfrastructure` seam (which aborts the run). No-op otherwise.
|
|
84
|
+
*/
|
|
85
|
+
export function failOnInfrastructureFailureDeclaration(parameters, hostActions, ctx, toolCallId) {
|
|
86
|
+
const diagnostic = infrastructureFailureDiagnostic(parameters);
|
|
87
|
+
if (diagnostic === undefined)
|
|
88
|
+
return;
|
|
89
|
+
hostActions.failInfrastructure(infrastructureFailureError(diagnostic), ctx, toolCallId);
|
|
90
|
+
}
|
package/dist/public-cli/main.js
CHANGED
|
@@ -14012,6 +14012,44 @@ var init_open_tool_schema = __esm({
|
|
|
14012
14012
|
}
|
|
14013
14013
|
});
|
|
14014
14014
|
|
|
14015
|
+
// src/package-contracts/terminating-infrastructure.ts
|
|
14016
|
+
function withInfrastructureFailureDeclaration(schema) {
|
|
14017
|
+
const baseProperties = schema.properties;
|
|
14018
|
+
const properties = {
|
|
14019
|
+
...baseProperties ?? {},
|
|
14020
|
+
[INFRASTRUCTURE_FAILURE_DECLARATION_KEY]: infrastructureFailureDeclarationSchema.properties[INFRASTRUCTURE_FAILURE_DECLARATION_KEY]
|
|
14021
|
+
};
|
|
14022
|
+
const object = typebox_exports.Object(properties, { additionalProperties: true });
|
|
14023
|
+
object.required = [];
|
|
14024
|
+
return object;
|
|
14025
|
+
}
|
|
14026
|
+
var INFRASTRUCTURE_FAILURE_DECLARATION_KEY, INFRASTRUCTURE_FAILURE_DIAGNOSTIC_KEY, infrastructureFailureDeclarationSchema;
|
|
14027
|
+
var init_terminating_infrastructure = __esm({
|
|
14028
|
+
"src/package-contracts/terminating-infrastructure.ts"() {
|
|
14029
|
+
"use strict";
|
|
14030
|
+
init_build();
|
|
14031
|
+
INFRASTRUCTURE_FAILURE_DECLARATION_KEY = "infrastructureFailure";
|
|
14032
|
+
INFRASTRUCTURE_FAILURE_DIAGNOSTIC_KEY = "diagnostic";
|
|
14033
|
+
infrastructureFailureDeclarationSchema = typebox_exports.Object(
|
|
14034
|
+
{
|
|
14035
|
+
[INFRASTRUCTURE_FAILURE_DECLARATION_KEY]: typebox_exports.Object(
|
|
14036
|
+
{
|
|
14037
|
+
[INFRASTRUCTURE_FAILURE_DIAGNOSTIC_KEY]: typebox_exports.String({
|
|
14038
|
+
minLength: 1,
|
|
14039
|
+
description: "\u975E\u7A7A\u57FA\u7840\u8BBE\u65BD\u5931\u8D25\u8BCA\u65AD"
|
|
14040
|
+
})
|
|
14041
|
+
},
|
|
14042
|
+
{
|
|
14043
|
+
additionalProperties: true,
|
|
14044
|
+
description: "\u57FA\u7840\u8BBE\u65BD\u5931\u8D25\u58F0\u660E"
|
|
14045
|
+
}
|
|
14046
|
+
)
|
|
14047
|
+
},
|
|
14048
|
+
{ additionalProperties: true }
|
|
14049
|
+
);
|
|
14050
|
+
}
|
|
14051
|
+
});
|
|
14052
|
+
|
|
14015
14053
|
// src/package-contracts/fixer-output.ts
|
|
14016
14054
|
function validateFixerOutput(value, _phase) {
|
|
14017
14055
|
return value;
|
|
@@ -14023,6 +14061,7 @@ var init_fixer_output = __esm({
|
|
|
14023
14061
|
init_build();
|
|
14024
14062
|
init_fixer_packet();
|
|
14025
14063
|
init_open_tool_schema();
|
|
14064
|
+
init_terminating_infrastructure();
|
|
14026
14065
|
FIXER_OUTPUT_TOOL_NAME = "ak_fixer_output";
|
|
14027
14066
|
nonblankTransportString = typebox_exports.String({ minLength: 1 });
|
|
14028
14067
|
authorityBlockerSchema = typebox_exports.Object({ cause: typebox_exports.Literal("authority_violation"), evidence: nonblankTransportString });
|
|
@@ -14057,7 +14096,9 @@ var init_fixer_output = __esm({
|
|
|
14057
14096
|
typebox_exports.Object({ status: typebox_exports.Literal("refused", { description: "refused \u2014 \u5F62\u72B6\u6307\u5F15\uFF0C\u975E schema \u95F8" }), report: typebox_exports.String({ minLength: 1, description: "\u5982\u5B9E\u7ED3\u679C\u62A5\u544A" }), classResults: typebox_exports.Array(classResultSchema, { minItems: 1, description: "\u5404\u7C7B\u62D2\u7EDD\u7ED3\u7B97" }) }),
|
|
14058
14097
|
typebox_exports.Object({ status: typebox_exports.Literal("partially_completed", { description: "partially_completed \u2014 \u5F62\u72B6\u6307\u5F15\uFF0C\u975E schema \u95F8" }), report: typebox_exports.String({ minLength: 1, description: "\u5982\u5B9E\u7ED3\u679C\u62A5\u544A" }), classResults: typebox_exports.Array(classResultSchema, { minItems: 1, description: "\u5404\u7C7B\u5B8C\u6210\u6216\u62D2\u7EDD\u7ED3\u7B97" }), testEvidence: typebox_exports.Optional(testEvidenceSchema) })
|
|
14059
14098
|
]);
|
|
14060
|
-
fixerOutputSchema =
|
|
14099
|
+
fixerOutputSchema = withInfrastructureFailureDeclaration(
|
|
14100
|
+
openToolObjectFromUnion(fixerOutputVariants)
|
|
14101
|
+
);
|
|
14061
14102
|
}
|
|
14062
14103
|
});
|
|
14063
14104
|
|
|
@@ -14116,6 +14157,7 @@ var init_doctor_contracts = __esm({
|
|
|
14116
14157
|
init_build();
|
|
14117
14158
|
init_canonical_json();
|
|
14118
14159
|
init_open_tool_schema();
|
|
14160
|
+
init_terminating_infrastructure();
|
|
14119
14161
|
DOCTOR_OUTPUT_TOOL_NAME = "ak_doctor_output";
|
|
14120
14162
|
DOCTOR_TARGET_KINDS = ["law", "gate", "template", "station", "seat"];
|
|
14121
14163
|
nonblank = typebox_exports.String({ minLength: 1, pattern: "\\S" });
|
|
@@ -14166,7 +14208,9 @@ var init_doctor_contracts = __esm({
|
|
|
14166
14208
|
missingEvidence: typebox_exports.Array(typebox_exports.Object({ need: nonblank, targetKeys: typebox_exports.Array(nonblank, { minItems: 1 }) }, { additionalProperties: false }), { minItems: 1, description: "\u5982\u5B9E\u8BC1\u8BCD\u6240\u9700\u800C\u5C1A\u7F3A\u7684\u8BC1\u636E" })
|
|
14167
14209
|
}, { additionalProperties: false, description: "\u8BC1\u636E\u4E0D\u8DB3\u4EE5\u652F\u6491\u5982\u5B9E\u6848\u8BC1\u8BCD" })
|
|
14168
14210
|
]);
|
|
14169
|
-
doctorSubmissionSchema =
|
|
14211
|
+
doctorSubmissionSchema = withInfrastructureFailureDeclaration(
|
|
14212
|
+
openToolObjectFromUnion(doctorSubmissionVariants)
|
|
14213
|
+
);
|
|
14170
14214
|
doctorOutputSchema = typebox_exports.Union([
|
|
14171
14215
|
typebox_exports.Object({ status: typebox_exports.Literal("completed"), case: caseIdentity, findings: typebox_exports.Array(finding), cost }, { additionalProperties: false }),
|
|
14172
14216
|
doctorSubmissionVariants.anyOf[1]
|
|
@@ -14272,6 +14316,7 @@ var init_merger_contracts = __esm({
|
|
|
14272
14316
|
init_exact_utf8();
|
|
14273
14317
|
init_sha256();
|
|
14274
14318
|
init_open_tool_schema();
|
|
14319
|
+
init_terminating_infrastructure();
|
|
14275
14320
|
oidPattern = "^(?:[0-9a-f]{40}|[0-9a-f]{64})$";
|
|
14276
14321
|
materialSchema = typebox_exports.Object({ bytesBase64: typebox_exports.String(), sha256: typebox_exports.String() }, { additionalProperties: false });
|
|
14277
14322
|
checkSchema = typebox_exports.Object({ name: typebox_exports.String({ minLength: 1 }), argv: typebox_exports.Array(typebox_exports.String({ minLength: 1 }), { minItems: 1 }) }, { additionalProperties: false });
|
|
@@ -14289,7 +14334,9 @@ var init_merger_contracts = __esm({
|
|
|
14289
14334
|
typebox_exports.Object({ status: typebox_exports.Literal("completed", { description: "completed \u2014 \u5F62\u72B6\u6307\u5F15\uFF0C\u975E schema \u95F8" }), attemptId: typebox_exports.String({ minLength: 1, description: "\u5DF2\u53D7\u7406\u5408\u5E76 attempt \u8EAB\u4EFD" }), report: typebox_exports.String({ minLength: 1, description: "\u5982\u5B9E\u7ED3\u679C\u62A5\u544A" }), mergeCommitId: typebox_exports.String({ pattern: oidPattern, description: "\u5DF2\u6838\u9A8C\u7684\u5B8C\u6210\u5408\u5E76 commit object ID" }) }, { additionalProperties: false }),
|
|
14290
14335
|
typebox_exports.Object({ status: typebox_exports.Literal("escalate", { description: "escalate \u2014 \u5F62\u72B6\u6307\u5F15\uFF0C\u975E schema \u95F8" }), attemptId: typebox_exports.String({ minLength: 1, description: "\u5DF2\u53D7\u7406\u5408\u5E76 attempt \u8EAB\u4EFD" }), diagnosis: typebox_exports.String({ minLength: 1, description: "\u5408\u5E76\u5B8C\u6210\u9700\u5347\u7EA7\u7684\u539F\u56E0" }), report: typebox_exports.String({ minLength: 1, description: "\u5982\u5B9E\u7ED3\u679C\u62A5\u544A" }) }, { additionalProperties: false })
|
|
14291
14336
|
]);
|
|
14292
|
-
mergerOutputSchema =
|
|
14337
|
+
mergerOutputSchema = withInfrastructureFailureDeclaration(
|
|
14338
|
+
openToolObjectFromUnion(mergerOutputVariants)
|
|
14339
|
+
);
|
|
14293
14340
|
MERGER_OUTPUT_TOOL_NAME = "ak_merger_output";
|
|
14294
14341
|
record = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
14295
14342
|
blank = (v) => typeof v !== "string" || v.trim().length === 0;
|
|
@@ -14351,17 +14398,20 @@ var init_notary_contracts = __esm({
|
|
|
14351
14398
|
"use strict";
|
|
14352
14399
|
init_build();
|
|
14353
14400
|
init_open_tool_schema();
|
|
14401
|
+
init_terminating_infrastructure();
|
|
14354
14402
|
NOTARY_OUTPUT_TOOL_NAME = "ak_notary_output";
|
|
14355
14403
|
NOTARY_FIXED_KICKOFF = "\u7B26\u5B9D\u90CE\u6848\u5377\u5DF2\u53D7\u7406\uFF1B\u6765\u6E90 run \u5B9A\u4F4D\u89C1\u4F1A\u8BDD\u6750\u6599\u3002";
|
|
14356
|
-
notaryOutputSchema =
|
|
14357
|
-
|
|
14358
|
-
|
|
14359
|
-
|
|
14360
|
-
|
|
14361
|
-
|
|
14362
|
-
|
|
14404
|
+
notaryOutputSchema = withInfrastructureFailureDeclaration(
|
|
14405
|
+
openToolObject(
|
|
14406
|
+
typebox_exports.Object({
|
|
14407
|
+
status: typebox_exports.Unknown({
|
|
14408
|
+
description: "pass | bounce \u2014 \u5F62\u72B6\u6307\u5F15\uFF0C\u975E schema \u95F8"
|
|
14409
|
+
}),
|
|
14410
|
+
findings: typebox_exports.Unknown({
|
|
14411
|
+
description: "string[] findings\uFF0C\u968F pass \u6216 bounce \u7559\u5B58"
|
|
14412
|
+
})
|
|
14363
14413
|
})
|
|
14364
|
-
|
|
14414
|
+
)
|
|
14365
14415
|
);
|
|
14366
14416
|
}
|
|
14367
14417
|
});
|
|
@@ -20488,6 +20538,7 @@ var init_collector_tool_schemas = __esm({
|
|
|
20488
20538
|
"use strict";
|
|
20489
20539
|
init_build();
|
|
20490
20540
|
init_collector_evidence();
|
|
20541
|
+
init_terminating_infrastructure();
|
|
20491
20542
|
collectorObserveArgsSchema = typebox_exports.Object({}, { additionalProperties: false });
|
|
20492
20543
|
collectorRequestArgsSchema = typebox_exports.Object({
|
|
20493
20544
|
requestId: typebox_exports.String({ minLength: 1, description: "\u914D\u7F6E\u8BF7\u6C42\u8EAB\u4EFD" }),
|
|
@@ -20496,7 +20547,9 @@ var init_collector_tool_schemas = __esm({
|
|
|
20496
20547
|
collectorWaitArgsSchema = typebox_exports.Object({
|
|
20497
20548
|
durationMs: typebox_exports.Integer({ minimum: 1, maximum: COLLECTOR_ELIGIBILITY_MS, description: "\u7B49\u5F85\u6BEB\u79D2\uFF1B\u5355\u6B21\u4E0A\u9650\u4E94\u5206\u949F\u4E14\u4E0D\u8D85\u5269\u4F59\u8D44\u683C" })
|
|
20498
20549
|
}, { additionalProperties: false });
|
|
20499
|
-
collectorOutputArgsSchema =
|
|
20550
|
+
collectorOutputArgsSchema = withInfrastructureFailureDeclaration(
|
|
20551
|
+
typebox_exports.Object({}, { additionalProperties: true })
|
|
20552
|
+
);
|
|
20500
20553
|
collectorOutputArgsSchema.required = [];
|
|
20501
20554
|
}
|
|
20502
20555
|
});
|
package/package.json
CHANGED
package/src/collector-role.ts
CHANGED
|
@@ -30,6 +30,9 @@ import {
|
|
|
30
30
|
buildCollectorReceipt,
|
|
31
31
|
type CollectorReceipt,
|
|
32
32
|
} from "./collector-receipt.ts";
|
|
33
|
+
import {
|
|
34
|
+
failOnInfrastructureFailureDeclaration,
|
|
35
|
+
} from "./package-contracts/terminating-infrastructure.ts";
|
|
33
36
|
import {
|
|
34
37
|
collectorObserveArgsSchema,
|
|
35
38
|
collectorOutputArgsSchema,
|
|
@@ -388,6 +391,9 @@ export function createCollectorRoleRuntime(
|
|
|
388
391
|
throw new Error("通进司未激活");
|
|
389
392
|
}
|
|
390
393
|
try {
|
|
394
|
+
// #541: infra declaration fails via the shared host seam before the
|
|
395
|
+
// operational ledger begins / a receipt is built.
|
|
396
|
+
failOnInfrastructureFailureDeclaration(params, hostActions, ctx, toolCallId);
|
|
391
397
|
assertSoleFinalCollectorOutput(toolCallId, ctx);
|
|
392
398
|
activation.ledger.beginOperational(COLLECTOR_OUTPUT_TOOL, toolCallId);
|
|
393
399
|
const receipt: CollectorReceipt = buildCollectorReceipt(
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Type, type Static } from "typebox";
|
|
2
2
|
import { COLLECTOR_ELIGIBILITY_MS } from "./collector-evidence.ts";
|
|
3
|
+
import { withInfrastructureFailureDeclaration } from "./package-contracts/terminating-infrastructure.ts";
|
|
3
4
|
|
|
4
5
|
export const collectorObserveArgsSchema = Type.Object({}, { additionalProperties: false });
|
|
5
6
|
export const collectorRequestArgsSchema = Type.Object({
|
|
@@ -10,7 +11,9 @@ export const collectorWaitArgsSchema = Type.Object({
|
|
|
10
11
|
durationMs: Type.Integer({ minimum: 1, maximum: COLLECTOR_ELIGIBILITY_MS, description: "等待毫秒;单次上限五分钟且不超剩余资格" }),
|
|
11
12
|
}, { additionalProperties: false });
|
|
12
13
|
/** Runtime owns the observed groups; the model only signals sole-final submission. */
|
|
13
|
-
export const collectorOutputArgsSchema =
|
|
14
|
+
export const collectorOutputArgsSchema = withInfrastructureFailureDeclaration(
|
|
15
|
+
Type.Object({}, { additionalProperties: true }),
|
|
16
|
+
);
|
|
14
17
|
(collectorOutputArgsSchema as unknown as { required: string[] }).required = [];
|
|
15
18
|
|
|
16
19
|
export type CollectorObserveArgs = Static<typeof collectorObserveArgsSchema>;
|
package/src/doctor-contracts.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Type } from "typebox";
|
|
2
2
|
import { canonicalJson } from "./canonical-json.ts";
|
|
3
3
|
import { openToolObjectFromUnion } from "./open-tool-schema.ts";
|
|
4
|
+
import { withInfrastructureFailureDeclaration } from "./package-contracts/terminating-infrastructure.ts";
|
|
4
5
|
|
|
5
6
|
export const DOCTOR_EVIDENCE_TOOL_NAME = "ak_doctor_evidence";
|
|
6
7
|
export const DOCTOR_OUTPUT_TOOL_NAME = "ak_doctor_output";
|
|
@@ -87,7 +88,9 @@ const doctorSubmissionVariants = Type.Union([
|
|
|
87
88
|
missingEvidence: Type.Array(Type.Object({ need: nonblank, targetKeys: Type.Array(nonblank, { minItems: 1 }) }, { additionalProperties: false }), { minItems: 1, description: "如实证词所需而尚缺的证据" }),
|
|
88
89
|
}, { additionalProperties: false, description: "证据不足以支撑如实案证词" }),
|
|
89
90
|
]);
|
|
90
|
-
export const doctorSubmissionSchema =
|
|
91
|
+
export const doctorSubmissionSchema = withInfrastructureFailureDeclaration(
|
|
92
|
+
openToolObjectFromUnion(doctorSubmissionVariants),
|
|
93
|
+
);
|
|
91
94
|
export const doctorOutputSchema = Type.Union([
|
|
92
95
|
Type.Object({ status: Type.Literal("completed"), case: caseIdentity, findings: Type.Array(finding), cost }, { additionalProperties: false }),
|
|
93
96
|
doctorSubmissionVariants.anyOf[1]!,
|
package/src/doctor-role.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type { AgentToolResult, ExtensionAPI, ExtensionContext } from "@earendil-
|
|
|
2
2
|
import { disposeComplianceDecision } from "./audit-escalation.ts";
|
|
3
3
|
import { appendActiveSessionCustomEntry, type ComplianceDecision } from "./compliance-transport.ts";
|
|
4
4
|
import { DOCTOR_CANDIDATE_ENTRY_TYPE } from "./dossier-resolution.ts";
|
|
5
|
+
import { failOnInfrastructureFailureDeclaration } from "./package-contracts/terminating-infrastructure.ts";
|
|
5
6
|
import { DOCTOR_ACCEPTED_AUDIT_NO_RECEIPT_TEXT, DOCTOR_ACCEPTED_TEXT, DOCTOR_EVIDENCE_TOOL_NAME, DOCTOR_OUTPUT_TOOL_DESCRIPTION, DOCTOR_OUTPUT_TOOL_NAME, DoctorEvidenceStore, doctorEvidenceReadSchema, doctorSubmissionSchema, validateDoctorOutput, type DoctorCase } from "./doctor-contracts.ts";
|
|
6
7
|
|
|
7
8
|
export { DOCTOR_EVIDENCE_TOOL_NAME, DOCTOR_OUTPUT_TOOL_NAME };
|
|
@@ -12,7 +13,7 @@ export function createDoctorRoleRuntime(pi: ExtensionAPI, dependencies: DoctorRo
|
|
|
12
13
|
let activation: { soul: string; patient: DoctorCase; store: DoctorEvidenceStore } | undefined; let registered = false; pi.registerFlag(DOCTOR_CASE_FLAG.name, DOCTOR_CASE_FLAG.definition);
|
|
13
14
|
return { async activate() { const path = pi.getFlag(DOCTOR_CASE_FLAG.name); if (typeof path !== "string" || !path.trim()) throw new Error("Doctor requires --ak-doctor-case"); const soul = (await dependencies.loadSoul()).trim(); if (!soul) throw new Error("Doctor soul is empty"); const patient = await dependencies.loadCase(path); activation = { soul, patient, store: new DoctorEvidenceStore(patient) };
|
|
14
15
|
if (!registered) { registered = true; pi.registerTool({ name: DOCTOR_EVIDENCE_TOOL_NAME, label: "太医署证据", description: "分页读取留存的 Pi session 字节。", parameters: doctorEvidenceReadSchema, async execute(_id, params: { evidenceId: string; offset?: number; limit?: number }) { if (!activation) throw new Error("太医署未激活"); const details = activation.store.read(params.evidenceId, params.offset, params.limit); return { content: [{ type: "text" as const, text: JSON.stringify(details) }], details }; } });
|
|
15
|
-
pi.registerTool({ name: DOCTOR_OUTPUT_TOOL_NAME, label: "太医署输出", description: DOCTOR_OUTPUT_TOOL_DESCRIPTION, parameters: doctorSubmissionSchema, async execute(id, params, signal, _update, ctx): Promise<AgentToolResult<unknown>> { if (!activation) throw new Error("太医署未激活"); singleton(id, ctx); const testimony = validateDoctorOutput(params, activation.patient, activation.store); try { appendActiveSessionCustomEntry(ctx, DOCTOR_CANDIDATE_ENTRY_TYPE, { version: 1, testimony, readRecord: activation.store.readRecord(), patientIdentity: activation.patient.identity }, { unavailable: "太医署候选留存不可用", failed: "太医署候选留存失败" }); } catch (error) { host.failInfrastructure(error, ctx, id); } let audit: ComplianceDecision; try { audit = await dependencies.auditCompliance(signal === undefined ? { context: ctx } : { context: ctx, signal }); } catch (error) { host.failInfrastructure(error, ctx, id); } const details = testimony.status === "completed" ? { ...testimony, cost: activation.patient.cost } : testimony; const acceptedDetails = details; return disposeComplianceDecision<AgentToolResult<unknown>>(audit, { pass: (usage) => ({ content: [{ type: "text" as const, text: DOCTOR_ACCEPTED_TEXT }], details: acceptedDetails, terminate: true as const, ...(usage === undefined ? {} : { usage }) }), noReceipt: (auditNoReceipt, usageProjection) => ({ content: [{ type: "text" as const, text: DOCTOR_ACCEPTED_AUDIT_NO_RECEIPT_TEXT }], details: { ...acceptedDetails, auditNoReceipt }, terminate: true as const, ...usageProjection }), revise: (violations) => { throw new Error(`太医署回执违 soul:${violations.join("; ")}`); }, escalate: (result) => result }, acceptedDetails); } });
|
|
16
|
+
pi.registerTool({ name: DOCTOR_OUTPUT_TOOL_NAME, label: "太医署输出", description: DOCTOR_OUTPUT_TOOL_DESCRIPTION, parameters: doctorSubmissionSchema, async execute(id, params, signal, _update, ctx): Promise<AgentToolResult<unknown>> { if (!activation) throw new Error("太医署未激活"); failOnInfrastructureFailureDeclaration(params, host, ctx, id); singleton(id, ctx); const testimony = validateDoctorOutput(params, activation.patient, activation.store); try { appendActiveSessionCustomEntry(ctx, DOCTOR_CANDIDATE_ENTRY_TYPE, { version: 1, testimony, readRecord: activation.store.readRecord(), patientIdentity: activation.patient.identity }, { unavailable: "太医署候选留存不可用", failed: "太医署候选留存失败" }); } catch (error) { host.failInfrastructure(error, ctx, id); } let audit: ComplianceDecision; try { audit = await dependencies.auditCompliance(signal === undefined ? { context: ctx } : { context: ctx, signal }); } catch (error) { host.failInfrastructure(error, ctx, id); } const details = testimony.status === "completed" ? { ...testimony, cost: activation.patient.cost } : testimony; const acceptedDetails = details; return disposeComplianceDecision<AgentToolResult<unknown>>(audit, { pass: (usage) => ({ content: [{ type: "text" as const, text: DOCTOR_ACCEPTED_TEXT }], details: acceptedDetails, terminate: true as const, ...(usage === undefined ? {} : { usage }) }), noReceipt: (auditNoReceipt, usageProjection) => ({ content: [{ type: "text" as const, text: DOCTOR_ACCEPTED_AUDIT_NO_RECEIPT_TEXT }], details: { ...acceptedDetails, auditNoReceipt }, terminate: true as const, ...usageProjection }), revise: (violations) => { throw new Error(`太医署回执违 soul:${violations.join("; ")}`); }, escalate: (result) => result }, acceptedDetails); } });
|
|
16
17
|
pi.on("before_agent_start", (event) => { if (!activation) throw new Error("太医署未激活"); const catalog = { version: activation.patient.version, identity: activation.patient.identity, admittedMetrics: { provenance: "由留存 session 字节推导,封入受理回执。", cost: activation.patient.cost }, lawfulTargetKeys: ["case", ...activation.patient.cost.invocations.sources], evidence: activation.patient.evidence.map(({ id, kind, sha256, byteLength, contentLength }) => ({ id, kind, sha256, byteLength, contentLength })) }; return { systemPrompt: `${event.systemPrompt}\n\n<doctor_soul>\n${activation.soul}\n</doctor_soul>\n\n<doctor_case>\n${JSON.stringify(catalog)}\n</doctor_case>` }; }); }
|
|
17
18
|
const required = [DOCTOR_EVIDENCE_TOOL_NAME, DOCTOR_OUTPUT_TOOL_NAME]; const names = pi.getAllTools().map((tool) => tool.name); for (const name of required) if (names.filter((item) => item === name).length !== 1) throw new Error(`Doctor required tool collision or missing: ${name}`); pi.setActiveTools(required); const active = pi.getActiveTools?.() ?? required; if (active.length !== 2 || !required.every((name) => active.includes(name))) throw new Error("Doctor active tool narrowing failed"); } };
|
|
18
19
|
}
|
package/src/judge-role.ts
CHANGED
|
@@ -9,6 +9,10 @@ import { Type, type Static } from "typebox";
|
|
|
9
9
|
import { disposeComplianceDecision } from "./audit-escalation.ts";
|
|
10
10
|
import type { ComplianceDecision } from "./compliance-transport.ts";
|
|
11
11
|
import { requireGatekeeperPass, type GatekeeperPassHostActions } from "./gatekeeper-role.ts";
|
|
12
|
+
import {
|
|
13
|
+
failOnInfrastructureFailureDeclaration,
|
|
14
|
+
withInfrastructureFailureDeclaration,
|
|
15
|
+
} from "./package-contracts/terminating-infrastructure.ts";
|
|
12
16
|
|
|
13
17
|
import {
|
|
14
18
|
JUDGE_ACCEPTED_AUDIT_NO_RECEIPT_TEXT,
|
|
@@ -21,34 +25,36 @@ import {
|
|
|
21
25
|
export { JUDGE_OUTPUT_TOOL_NAME };
|
|
22
26
|
export type { JudgeVerdict };
|
|
23
27
|
|
|
24
|
-
const judgeVerdictSchema =
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
Type.
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
export const judgeVerdictSchema = withInfrastructureFailureDeclaration(
|
|
29
|
+
Type.Object(
|
|
30
|
+
{
|
|
31
|
+
judgeStatus: StringEnum(["converged", "continue", "escalate"] as const, { description: "converged | continue | escalate — 形状指引,非 schema 闸" }),
|
|
32
|
+
fix: Type.Optional(
|
|
33
|
+
Type.Object(
|
|
34
|
+
{ summary: Type.String({ minLength: 1, description: "continue 时的补救摘要" }) },
|
|
35
|
+
{ additionalProperties: false, description: "continue 时的补救说明" },
|
|
36
|
+
),
|
|
31
37
|
),
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
38
|
+
classes: Type.Optional(Type.Array(Type.Object({
|
|
39
|
+
name: Type.String({ minLength: 1 }),
|
|
40
|
+
owner: Type.String({ minLength: 1 }),
|
|
41
|
+
boundary: Type.String({ minLength: 1 }),
|
|
42
|
+
disposition: Type.String({ minLength: 1 }),
|
|
43
|
+
}, { additionalProperties: false }), { minItems: 1, description: "已裁决 finding 类及其 owner 与修理边界" })),
|
|
44
|
+
note: Type.Optional(Type.String({ minLength: 1, description: "可选裁决附注" })),
|
|
45
|
+
evidence: Type.Optional(Type.Unknown({ description: "留存的裁决证据" })),
|
|
46
|
+
decisionGate: Type.Optional(
|
|
47
|
+
Type.Object(
|
|
48
|
+
{
|
|
49
|
+
question: Type.String({ minLength: 1 }),
|
|
50
|
+
options: Type.Array(Type.String({ minLength: 1 }), { minItems: 1 }),
|
|
51
|
+
},
|
|
52
|
+
{ additionalProperties: false, description: "需人权威处置的问题与选项" },
|
|
53
|
+
),
|
|
48
54
|
),
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
55
|
+
},
|
|
56
|
+
{ additionalProperties: true },
|
|
57
|
+
),
|
|
52
58
|
);
|
|
53
59
|
(judgeVerdictSchema as unknown as { required: string[] }).required = [];
|
|
54
60
|
|
|
@@ -109,6 +115,9 @@ export function createJudgeRoleRuntime(
|
|
|
109
115
|
parameters: judgeVerdictSchema,
|
|
110
116
|
async execute(toolCallId, parameters, signal, _onUpdate, ctx): Promise<AgentToolResult<unknown>> {
|
|
111
117
|
if (soul === undefined) throw new Error("大理寺职分未装载");
|
|
118
|
+
// #541: infra declaration fails via the shared host seam before any
|
|
119
|
+
// Gatekeeper + audit courtyard work.
|
|
120
|
+
failOnInfrastructureFailureDeclaration(parameters, hostActions, ctx, toolCallId);
|
|
112
121
|
requireSingletonSubmissionCall(toolCallId, ctx);
|
|
113
122
|
const verdict = validateVerdict(parameters);
|
|
114
123
|
// Candidate verdict is already on the parent session books as this
|
package/src/merger-contracts.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { isFullGitObjectId } from "./git-object-id.ts";
|
|
|
3
3
|
import { exactUtf8 } from "./exact-utf8.ts";
|
|
4
4
|
import { sha256Hex } from "./sha256.ts";
|
|
5
5
|
import { openToolObjectFromUnion } from "./open-tool-schema.ts";
|
|
6
|
+
import { withInfrastructureFailureDeclaration } from "./package-contracts/terminating-infrastructure.ts";
|
|
6
7
|
|
|
7
8
|
const oidPattern = "^(?:[0-9a-f]{40}|[0-9a-f]{64})$";
|
|
8
9
|
const materialSchema = Type.Object({ bytesBase64: Type.String(), sha256: Type.String() }, { additionalProperties: false });
|
|
@@ -19,7 +20,9 @@ const mergerOutputVariants = Type.Union([
|
|
|
19
20
|
Type.Object({ status: Type.Literal("completed", { description: "completed — 形状指引,非 schema 闸" }), attemptId: Type.String({ minLength: 1, description: "已受理合并 attempt 身份" }), report: Type.String({ minLength: 1, description: "如实结果报告" }), mergeCommitId: Type.String({ pattern: oidPattern, description: "已核验的完成合并 commit object ID" }) }, { additionalProperties: false }),
|
|
20
21
|
Type.Object({ status: Type.Literal("escalate", { description: "escalate — 形状指引,非 schema 闸" }), attemptId: Type.String({ minLength: 1, description: "已受理合并 attempt 身份" }), diagnosis: Type.String({ minLength: 1, description: "合并完成需升级的原因" }), report: Type.String({ minLength: 1, description: "如实结果报告" }) }, { additionalProperties: false }),
|
|
21
22
|
]);
|
|
22
|
-
export const mergerOutputSchema =
|
|
23
|
+
export const mergerOutputSchema = withInfrastructureFailureDeclaration(
|
|
24
|
+
openToolObjectFromUnion(mergerOutputVariants),
|
|
25
|
+
);
|
|
23
26
|
|
|
24
27
|
export type DeepReadonly<T> = T extends (...args: never[]) => unknown ? T : T extends readonly (infer U)[] ? readonly DeepReadonly<U>[] : T extends object ? { readonly [K in keyof T]: DeepReadonly<T[K]> } : T;
|
|
25
28
|
export type MergerMaterial = DeepReadonly<Static<typeof materialSchema>>;
|
package/src/merger-role.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
2
2
|
import { MERGER_ACCEPTED_TEXT, MERGER_OUTPUT_TOOL_NAME, mergerOutputSchema, validateMergerInput, validateMergerOutput, type MergerInput } from "./merger-contracts.ts";
|
|
3
3
|
import type { MergerGitState } from "./merger-git-state.ts";
|
|
4
|
+
import { failOnInfrastructureFailureDeclaration } from "./package-contracts/terminating-infrastructure.ts";
|
|
4
5
|
import { exactUtf8 } from "./exact-utf8.ts";
|
|
5
6
|
import { isFullGitObjectId } from "./git-object-id.ts";
|
|
6
7
|
|
|
@@ -28,10 +29,13 @@ export function createMergerRoleRuntime(pi: ExtensionAPI, dependencies: MergerRo
|
|
|
28
29
|
if (state.targetObjectId !== input.targetObjectId || state.sourceObjectId !== input.sourceObjectId || !same(state.unmergedPaths, input.expectedConflictPaths) || state.unmergedPaths.length === 0 || !isFullGitObjectId(state.automaticMergeTreeId) || state.automaticMergeTreeId.length !== input.targetObjectId.length) throw new Error("Merger activation rejected repository parent, merge, automatic-result, or complete conflict-set drift");
|
|
29
30
|
activation = { soul, input, automaticMergeTreeId: state.automaticMergeTreeId }; accepted = false;
|
|
30
31
|
if (!registered) { registered = true;
|
|
31
|
-
pi.registerTool({ name: MERGER_OUTPUT_TOOL_NAME, label: "合并输出", description: "提交合并结果;输出分支为 completed 与 escalate
|
|
32
|
+
pi.registerTool({ name: MERGER_OUTPUT_TOOL_NAME, label: "合并输出", description: "提交合并结果;输出分支为 completed 与 escalate", promptSnippet: "提交合并结果", parameters: mergerOutputSchema,
|
|
32
33
|
async execute(id, params, _signal, _update, ctx) {
|
|
33
34
|
if (!activation) throw new Error("校书郎未激活");
|
|
34
35
|
if (accepted) throw new Error("合并回执已受理");
|
|
36
|
+
// #541: infra declaration fails via the shared host seam before output
|
|
37
|
+
// validation / Git verification / accepted=true.
|
|
38
|
+
failOnInfrastructureFailureDeclaration(params, host, ctx, id);
|
|
35
39
|
let output;
|
|
36
40
|
try {
|
|
37
41
|
singleton(id, ctx);
|
package/src/notary-contracts.ts
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
import { Type } from "typebox";
|
|
7
7
|
|
|
8
8
|
import { openToolObject } from "./open-tool-schema.ts";
|
|
9
|
+
import { withInfrastructureFailureDeclaration } from "./package-contracts/terminating-infrastructure.ts";
|
|
9
10
|
|
|
10
11
|
export const NOTARY_OUTPUT_TOOL_NAME = "ak_notary_output";
|
|
11
12
|
export const NOTARY_ACCEPTED_TEXT = "符宝郎回执已接受";
|
|
@@ -21,15 +22,17 @@ export const NOTARY_SOURCE_RUN_FLAG = {
|
|
|
21
22
|
export const NOTARY_FIXED_KICKOFF =
|
|
22
23
|
"符宝郎案卷已受理;来源 run 定位见会话材料。";
|
|
23
24
|
|
|
24
|
-
export const notaryOutputSchema =
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
export const notaryOutputSchema = withInfrastructureFailureDeclaration(
|
|
26
|
+
openToolObject(
|
|
27
|
+
Type.Object({
|
|
28
|
+
status: Type.Unknown({
|
|
29
|
+
description: "pass | bounce — 形状指引,非 schema 闸",
|
|
30
|
+
}),
|
|
31
|
+
findings: Type.Unknown({
|
|
32
|
+
description: "string[] findings,随 pass 或 bounce 留存",
|
|
33
|
+
}),
|
|
28
34
|
}),
|
|
29
|
-
|
|
30
|
-
description: "string[] findings,随 pass 或 bounce 留存",
|
|
31
|
-
}),
|
|
32
|
-
}),
|
|
35
|
+
),
|
|
33
36
|
);
|
|
34
37
|
|
|
35
38
|
export type NotarySourceRunLocator = {
|
package/src/notary-role.ts
CHANGED
|
@@ -17,6 +17,9 @@ import {
|
|
|
17
17
|
retainNotarySubmission,
|
|
18
18
|
type NotarySourceRunLocator,
|
|
19
19
|
} from "./notary-contracts.ts";
|
|
20
|
+
import {
|
|
21
|
+
failOnInfrastructureFailureDeclaration,
|
|
22
|
+
} from "./package-contracts/terminating-infrastructure.ts";
|
|
20
23
|
|
|
21
24
|
export {
|
|
22
25
|
NOTARY_ACCEPTED_TEXT,
|
|
@@ -98,6 +101,9 @@ export function createNotaryRoleRuntime(
|
|
|
98
101
|
if (activation === undefined) {
|
|
99
102
|
throw new Error("符宝郎未激活");
|
|
100
103
|
}
|
|
104
|
+
// #541: infra declaration fails via the shared host seam before any
|
|
105
|
+
// pass/bounce projection.
|
|
106
|
+
failOnInfrastructureFailureDeclaration(parameters, host, ctx, toolCallId);
|
|
101
107
|
// Unique submission + terminate only. Shape is not an admission gate
|
|
102
108
|
// (第 0 条 / ADR 0055): lawful pass/bounce projected; else params as-is.
|
|
103
109
|
requireSingletonSubmissionCall(toolCallId, ctx);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Type, type Static } from "typebox";
|
|
2
2
|
import { FIXER_PREREQUISITE_ID_PATTERN, type FixerInvocationInput } from "./fixer-packet.ts";
|
|
3
3
|
import { openToolObjectFromUnion } from "../open-tool-schema.ts";
|
|
4
|
+
import { withInfrastructureFailureDeclaration } from "./terminating-infrastructure.ts";
|
|
4
5
|
|
|
5
6
|
export const FIXER_OUTPUT_TOOL_NAME = "ak_fixer_output";
|
|
6
7
|
export const FIXER_ACCEPTED_TEXT = "修内司回执已接受";
|
|
@@ -40,7 +41,9 @@ const fixerOutputVariants = Type.Union([
|
|
|
40
41
|
Type.Object({ status: Type.Literal("refused", { description: "refused — 形状指引,非 schema 闸" }), report: Type.String({ minLength: 1, description: "如实结果报告" }), classResults: Type.Array(classResultSchema, { minItems: 1, description: "各类拒绝结算" }) }),
|
|
41
42
|
Type.Object({ status: Type.Literal("partially_completed", { description: "partially_completed — 形状指引,非 schema 闸" }), report: Type.String({ minLength: 1, description: "如实结果报告" }), classResults: Type.Array(classResultSchema, { minItems: 1, description: "各类完成或拒绝结算" }), testEvidence: Type.Optional(testEvidenceSchema) }),
|
|
42
43
|
]);
|
|
43
|
-
export const fixerOutputSchema =
|
|
44
|
+
export const fixerOutputSchema = withInfrastructureFailureDeclaration(
|
|
45
|
+
openToolObjectFromUnion(fixerOutputVariants),
|
|
46
|
+
);
|
|
44
47
|
|
|
45
48
|
export type FixerBlocker = Static<typeof blockerSchema>;
|
|
46
49
|
export type FixerClassResult = Static<typeof classResultSchema>;
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Package-owned shared infrastructure-failure declaration for every primary
|
|
3
|
+
* packaged-role output tool (#541).
|
|
4
|
+
*
|
|
5
|
+
* One module owns what the judge mandates be shared (not reimplemented per
|
|
6
|
+
* seat): the typed `infrastructureFailure.diagnostic` declaration composed into
|
|
7
|
+
* each output tool's schema, and the single early host `failInfrastructure`
|
|
8
|
+
* call each output `execute` makes before any role business validation / gate /
|
|
9
|
+
* audit / ledger / Git work. The accepted status sets are intentionally NOT
|
|
10
|
+
* extended: an infra declaration fails BEFORE accepted validation, never
|
|
11
|
+
* becomes an accepted receipt. The diagnostic is carried verbatim on the thrown
|
|
12
|
+
* Error so settlement keeps the original cause (kind=failure, exit 1).
|
|
13
|
+
*/
|
|
14
|
+
import { Type, type TSchema } from "typebox";
|
|
15
|
+
|
|
16
|
+
export const INFRASTRUCTURE_FAILURE_DECLARATION_KEY =
|
|
17
|
+
"infrastructureFailure" as const;
|
|
18
|
+
export const INFRASTRUCTURE_FAILURE_DIAGNOSTIC_KEY = "diagnostic" as const;
|
|
19
|
+
|
|
20
|
+
/** Shared typed declaration fragment: `infrastructureFailure.diagnostic` = non-empty string. */
|
|
21
|
+
const infrastructureFailureDeclarationSchema = Type.Object(
|
|
22
|
+
{
|
|
23
|
+
[INFRASTRUCTURE_FAILURE_DECLARATION_KEY]: Type.Object(
|
|
24
|
+
{
|
|
25
|
+
[INFRASTRUCTURE_FAILURE_DIAGNOSTIC_KEY]: Type.String({
|
|
26
|
+
minLength: 1,
|
|
27
|
+
description: "非空基础设施失败诊断",
|
|
28
|
+
}),
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
additionalProperties: true,
|
|
32
|
+
description: "基础设施失败声明",
|
|
33
|
+
},
|
|
34
|
+
),
|
|
35
|
+
},
|
|
36
|
+
{ additionalProperties: true },
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Compose the shared infrastructure-failure declaration into an open output
|
|
41
|
+
* tool-object schema. Returns an open object (additionalProperties: true,
|
|
42
|
+
* required: []) with the base schema's properties plus the shared declaration.
|
|
43
|
+
* Static typing is preserved on the base (`as S`), so existing
|
|
44
|
+
* `Static<typeof ...>` derived parameter types are unchanged.
|
|
45
|
+
*/
|
|
46
|
+
export function withInfrastructureFailureDeclaration<
|
|
47
|
+
S extends TSchema & { properties?: Record<string, TSchema> },
|
|
48
|
+
>(schema: S): S {
|
|
49
|
+
const baseProperties = (schema as { properties?: Record<string, TSchema> })
|
|
50
|
+
.properties;
|
|
51
|
+
const properties: Record<string, TSchema> = {
|
|
52
|
+
...(baseProperties ?? {}),
|
|
53
|
+
[INFRASTRUCTURE_FAILURE_DECLARATION_KEY]:
|
|
54
|
+
infrastructureFailureDeclarationSchema.properties[
|
|
55
|
+
INFRASTRUCTURE_FAILURE_DECLARATION_KEY
|
|
56
|
+
],
|
|
57
|
+
};
|
|
58
|
+
const object = Type.Object(properties, { additionalProperties: true });
|
|
59
|
+
(object as unknown as { required: string[] }).required = [];
|
|
60
|
+
return object as unknown as S;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** Structural host seam subset shared by every terminating execute path. */
|
|
64
|
+
type TerminatingInfrastructureHostActions<C> = {
|
|
65
|
+
failInfrastructure(error: unknown, ctx: C, toolCallId?: string): never;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
/** Safe recognition of the typed declaration; non-shapes / hostile input fail closed. */
|
|
69
|
+
function isInfrastructureFailureDeclaration(
|
|
70
|
+
parameters: unknown,
|
|
71
|
+
): boolean {
|
|
72
|
+
if (
|
|
73
|
+
parameters === null ||
|
|
74
|
+
typeof parameters !== "object" ||
|
|
75
|
+
Array.isArray(parameters)
|
|
76
|
+
) {
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
const record = parameters as Record<string, unknown>;
|
|
80
|
+
if (!Object.hasOwn(record, INFRASTRUCTURE_FAILURE_DECLARATION_KEY)) return false;
|
|
81
|
+
const declaration = record[INFRASTRUCTURE_FAILURE_DECLARATION_KEY];
|
|
82
|
+
if (
|
|
83
|
+
declaration === null ||
|
|
84
|
+
typeof declaration !== "object" ||
|
|
85
|
+
Array.isArray(declaration)
|
|
86
|
+
) {
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
const diagnostic = (declaration as Record<string, unknown>)[
|
|
90
|
+
INFRASTRUCTURE_FAILURE_DIAGNOSTIC_KEY
|
|
91
|
+
];
|
|
92
|
+
return typeof diagnostic === "string" && diagnostic.trim().length > 0;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/** Non-empty trimmed diagnostic from the declaration, else undefined. */
|
|
96
|
+
function infrastructureFailureDiagnostic(
|
|
97
|
+
parameters: unknown,
|
|
98
|
+
): string | undefined {
|
|
99
|
+
if (!isInfrastructureFailureDeclaration(parameters)) return undefined;
|
|
100
|
+
const declaration = (parameters as Record<string, unknown>)[
|
|
101
|
+
INFRASTRUCTURE_FAILURE_DECLARATION_KEY
|
|
102
|
+
] as Record<string, unknown>;
|
|
103
|
+
const diagnostic = declaration[INFRASTRUCTURE_FAILURE_DIAGNOSTIC_KEY];
|
|
104
|
+
return typeof diagnostic === "string" ? diagnostic.trim() : undefined;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/** diagnostic → Error, name stamped so the host error identity is observable. */
|
|
108
|
+
function infrastructureFailureError(diagnostic: string): Error {
|
|
109
|
+
const error = new Error(diagnostic);
|
|
110
|
+
error.name = "InfrastructureFailure";
|
|
111
|
+
return error;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* The one early call for every terminating output `execute`: if the parameters
|
|
116
|
+
* carry the infra declaration, hand the diagnostic error to the shared host
|
|
117
|
+
* `failInfrastructure` seam (which aborts the run). No-op otherwise.
|
|
118
|
+
*/
|
|
119
|
+
export function failOnInfrastructureFailureDeclaration<C>(
|
|
120
|
+
parameters: unknown,
|
|
121
|
+
hostActions: TerminatingInfrastructureHostActions<C>,
|
|
122
|
+
ctx: C,
|
|
123
|
+
toolCallId: string,
|
|
124
|
+
): void {
|
|
125
|
+
const diagnostic = infrastructureFailureDiagnostic(parameters);
|
|
126
|
+
if (diagnostic === undefined) return;
|
|
127
|
+
hostActions.failInfrastructure(
|
|
128
|
+
infrastructureFailureError(diagnostic),
|
|
129
|
+
ctx,
|
|
130
|
+
toolCallId,
|
|
131
|
+
);
|
|
132
|
+
}
|
package/src/reviewer-role.ts
CHANGED
|
@@ -10,6 +10,10 @@ import { ReviewerDispatchExecutionError, type ReviewerDispatchRunResult } from "
|
|
|
10
10
|
import { createReviewerExecutionLedger, projectAcceptedDispatch, projectReviewerDispatchOutcome, type ReviewerExecutionRecord } from "./reviewer-execution-ledger.ts";
|
|
11
11
|
import { assembleRuntimeReviewerReceipt } from "./reviewer-settlement.ts";
|
|
12
12
|
import { REVIEWER_ACCEPTED_TEXT, REVIEWER_OUTPUT_TOOL_NAME, validateReviewerIntent, type ReviewerIntent } from "./package-contracts/reviewer-output.ts";
|
|
13
|
+
import {
|
|
14
|
+
failOnInfrastructureFailureDeclaration,
|
|
15
|
+
withInfrastructureFailureDeclaration,
|
|
16
|
+
} from "./package-contracts/terminating-infrastructure.ts";
|
|
13
17
|
|
|
14
18
|
export { REVIEWER_OUTPUT_TOOL_NAME };
|
|
15
19
|
export type { ReviewerIntent };
|
|
@@ -39,7 +43,9 @@ const reviewerOutputVariants = Type.Union([
|
|
|
39
43
|
amendments: Type.Optional(reviewerAmendmentsSchema),
|
|
40
44
|
}, { additionalProperties: false }),
|
|
41
45
|
]);
|
|
42
|
-
const reviewerOutputSchema =
|
|
46
|
+
export const reviewerOutputSchema = withInfrastructureFailureDeclaration(
|
|
47
|
+
openToolObjectFromUnion(reviewerOutputVariants),
|
|
48
|
+
);
|
|
43
49
|
export type ReviewerRoleDependencies = {
|
|
44
50
|
loadSoul(): Promise<string>;
|
|
45
51
|
loadCanonicalSkillBinding(name: "code-review"): Promise<AnyCanonicalSkillBinding>;
|
|
@@ -147,6 +153,9 @@ export function createReviewerRoleRuntime(
|
|
|
147
153
|
pi.registerTool({ name: REVIEWER_OUTPUT_TOOL_NAME, label: "御史台输出", description: "Standards/Spec 评审腿由 runtime 以取证子会话代跑,本席收腿报告后交薄回执。", promptSnippet: "提交御史台终局回执", parameters: reviewerOutputSchema,
|
|
148
154
|
async execute(id, parameters, _signal, _update, toolCtx): Promise<AgentToolResult<unknown>> {
|
|
149
155
|
if (!soul || !binding) throw new Error("御史台输入未装载");
|
|
156
|
+
// #541: infra declaration fails via the shared host seam before the
|
|
157
|
+
// ledger audit record / receipt assembly / shutdown.
|
|
158
|
+
failOnInfrastructureFailureDeclaration(parameters, hostActions, toolCtx, id);
|
|
150
159
|
requireSoleReviewerOutputCall(id, toolCtx);
|
|
151
160
|
const output = validateReviewerIntent(parameters);
|
|
152
161
|
let record: ReviewerExecutionRecord;
|
package/src/worker-role.ts
CHANGED
|
@@ -6,6 +6,10 @@ import type {
|
|
|
6
6
|
} from "@earendil-works/pi-coding-agent";
|
|
7
7
|
import { Type, type Static } from "typebox";
|
|
8
8
|
import { openToolObjectFromUnion } from "./open-tool-schema.ts";
|
|
9
|
+
import {
|
|
10
|
+
failOnInfrastructureFailureDeclaration,
|
|
11
|
+
withInfrastructureFailureDeclaration,
|
|
12
|
+
} from "./package-contracts/terminating-infrastructure.ts";
|
|
9
13
|
|
|
10
14
|
import type {
|
|
11
15
|
AnyCanonicalSkillBinding,
|
|
@@ -85,7 +89,9 @@ const coderOutputVariants = Type.Union([
|
|
|
85
89
|
})),
|
|
86
90
|
}, { additionalProperties: false }),
|
|
87
91
|
]);
|
|
88
|
-
const coderOutputSchema =
|
|
92
|
+
export const coderOutputSchema = withInfrastructureFailureDeclaration(
|
|
93
|
+
openToolObjectFromUnion(coderOutputVariants),
|
|
94
|
+
);
|
|
89
95
|
export type { FixerOutput, CoderOutput };
|
|
90
96
|
export const FIXER_FLAG_DEFINITIONS = {
|
|
91
97
|
packet: {
|
|
@@ -262,13 +268,16 @@ export function createFixerRoleRuntime(
|
|
|
262
268
|
pi.registerTool({
|
|
263
269
|
name: FIXER_OUTPUT_TOOL_NAME,
|
|
264
270
|
label: "修内司输出",
|
|
265
|
-
description: "
|
|
271
|
+
description: "提交修内司终局回执",
|
|
266
272
|
promptSnippet: "提交修内司终局回执",
|
|
267
273
|
parameters: fixerOutputSchema,
|
|
268
274
|
async execute(toolCallId, parameters, _signal, _onUpdate, ctx): Promise<AgentToolResult<unknown>> {
|
|
269
275
|
if (packet === undefined || phase === undefined) {
|
|
270
276
|
throw new Error("修内司修理包与阶段未装载");
|
|
271
277
|
}
|
|
278
|
+
// #541: infra declaration fails via the shared host seam before any
|
|
279
|
+
// submission gate + Gatekeeper work.
|
|
280
|
+
failOnInfrastructureFailureDeclaration(parameters, hostActions, ctx, toolCallId);
|
|
272
281
|
requireSingletonSubmissionCall(
|
|
273
282
|
toolCallId,
|
|
274
283
|
FIXER_OUTPUT_TOOL_NAME,
|
|
@@ -400,6 +409,9 @@ export function createCoderRoleRuntime(
|
|
|
400
409
|
if (task === undefined || phase === undefined) {
|
|
401
410
|
throw new Error("将作监任务与阶段未装载");
|
|
402
411
|
}
|
|
412
|
+
// #541: infra declaration fails via the shared host seam before any
|
|
413
|
+
// submission gate + Gatekeeper work.
|
|
414
|
+
failOnInfrastructureFailureDeclaration(parameters, hostActions, ctx, toolCallId);
|
|
403
415
|
requireSingletonSubmissionCall(
|
|
404
416
|
toolCallId,
|
|
405
417
|
CODER_OUTPUT_TOOL_NAME,
|