@akagilnc/pi-workflow-roles 0.1.2397 → 0.1.2402
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 +1 -1
- package/README.zh-CN.md +1 -1
- package/dist/doctor-contracts.js +2 -9
- package/dist/engine-detour-tool.js +10 -35
- package/dist/evidence-child-executor.js +11 -3
- package/dist/merger-contracts.js +2 -8
- package/dist/navigator-attendance.js +1 -9
- package/dist/notary-contracts.js +3 -8
- package/dist/package-contracts/judge-output.js +1 -4
- package/dist/package-contracts/reviewer-output.js +1 -7
- package/dist/package-contracts/terminating-tools.js +5 -10
- package/dist/public-cli/main.js +24 -101
- package/package.json +1 -1
- package/scripts/build-package.mjs +1 -2
- package/src/analyst-metric-families/acceptance-success-rework.ts +3 -6
- package/src/collector-role.ts +1 -8
- package/src/doctor-contracts.ts +3 -18
- package/src/doctor-role.ts +1 -5
- package/src/engine-detour-tool.ts +16 -51
- package/src/evidence-child-executor.ts +11 -3
- package/src/factory-board.ts +2 -4
- package/src/judge-role.ts +1 -7
- package/src/merger-contracts.ts +3 -17
- package/src/merger-role.ts +1 -8
- package/src/navigator-attendance.ts +1 -14
- package/src/notary-contracts.ts +4 -24
- package/src/notary-role.ts +1 -3
- package/src/package-contracts/judge-output.ts +2 -17
- package/src/package-contracts/reviewer-output.ts +2 -21
- package/src/package-contracts/terminating-tools.ts +4 -13
- package/src/package-contracts/worker-output.ts +2 -10
- package/src/public-cli/settlement.ts +8 -20
- package/src/reviewer-role.ts +2 -10
- package/src/role-runtime.ts +1 -28
- package/src/worker-role.ts +2 -14
- package/dist/engine-labor-fallback.js +0 -136
- package/src/engine-labor-fallback.ts +0 -270
package/src/factory-board.ts
CHANGED
|
@@ -20,7 +20,6 @@ import { randomUUID } from "node:crypto";
|
|
|
20
20
|
import { lstat, mkdir, realpath, rename, rm, writeFile } from "node:fs/promises";
|
|
21
21
|
import { basename, dirname, join, relative, resolve, sep } from "node:path";
|
|
22
22
|
|
|
23
|
-
import { seatFallbackBaseStatus } from "./engine-labor-fallback.ts";
|
|
24
23
|
import {
|
|
25
24
|
formatDurationZh,
|
|
26
25
|
formatLocalDateTime,
|
|
@@ -177,8 +176,7 @@ export function decideTicketCurrentState(input: {
|
|
|
177
176
|
const latest = sortRunsByStart(input.runs).at(-1)!;
|
|
178
177
|
if (!latest.hasResult) return unacceptedBand(latest.mtimeMs, input.now.getTime());
|
|
179
178
|
// Escalate is an awaiting overlay: same placement and sort band, distinct state.
|
|
180
|
-
|
|
181
|
-
if (seatFallbackBaseStatus(latest.resultStatus) === "escalate") return "escalate-awaiting";
|
|
179
|
+
if ((latest.resultStatus) === "escalate") return "escalate-awaiting";
|
|
182
180
|
return "accepted-awaiting";
|
|
183
181
|
}
|
|
184
182
|
|
|
@@ -847,7 +845,7 @@ function buildBreadcrumbSteps(runs: readonly TicketTrajectoryRun[]): BreadcrumbS
|
|
|
847
845
|
const isRejected = group.runs.some(
|
|
848
846
|
(run) =>
|
|
849
847
|
run.hasResult &&
|
|
850
|
-
REJECTED_RESULT_STATUSES.has(
|
|
848
|
+
REJECTED_RESULT_STATUSES.has((run.resultStatus)),
|
|
851
849
|
);
|
|
852
850
|
steps.push({
|
|
853
851
|
station: group.station,
|
package/src/judge-role.ts
CHANGED
|
@@ -8,10 +8,6 @@ import { Type, type Static } from "typebox";
|
|
|
8
8
|
|
|
9
9
|
import { disposeComplianceDecision } from "./audit-escalation.ts";
|
|
10
10
|
import type { ComplianceDecision } from "./compliance-transport.ts";
|
|
11
|
-
import {
|
|
12
|
-
readActivationEngineLaborFallbackField,
|
|
13
|
-
withEngineLaborFallbackField,
|
|
14
|
-
} from "./engine-labor-fallback.ts";
|
|
15
11
|
import { requireGatekeeperPass, type GatekeeperPassHostActions } from "./gatekeeper-role.ts";
|
|
16
12
|
|
|
17
13
|
import {
|
|
@@ -137,9 +133,7 @@ export function createJudgeRoleRuntime(
|
|
|
137
133
|
} catch (error) {
|
|
138
134
|
hostActions.failInfrastructure(error, ctx, toolCallId);
|
|
139
135
|
}
|
|
140
|
-
|
|
141
|
-
const laborFallback = readActivationEngineLaborFallbackField();
|
|
142
|
-
const acceptedDetails = withEngineLaborFallbackField(verdict, laborFallback);
|
|
136
|
+
const acceptedDetails = verdict;
|
|
143
137
|
return disposeComplianceDecision<AgentToolResult<unknown>>(
|
|
144
138
|
audit,
|
|
145
139
|
{
|
package/src/merger-contracts.ts
CHANGED
|
@@ -1,11 +1,6 @@
|
|
|
1
1
|
import { Type, type Static } from "typebox";
|
|
2
2
|
import { isFullGitObjectId } from "./git-object-id.ts";
|
|
3
3
|
import { exactUtf8 } from "./exact-utf8.ts";
|
|
4
|
-
import {
|
|
5
|
-
seatFallbackBaseStatus,
|
|
6
|
-
seatFallbackStatusHasLawfulEvidence,
|
|
7
|
-
type WithEngineLaborFallback,
|
|
8
|
-
} from "./engine-labor-fallback.ts";
|
|
9
4
|
import { sha256Hex } from "./sha256.ts";
|
|
10
5
|
import { openToolObjectFromUnion } from "./open-tool-schema.ts";
|
|
11
6
|
|
|
@@ -29,13 +24,9 @@ export const mergerOutputSchema = openToolObjectFromUnion(mergerOutputVariants);
|
|
|
29
24
|
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;
|
|
30
25
|
export type MergerMaterial = DeepReadonly<Static<typeof materialSchema>>;
|
|
31
26
|
export type MergerInput = DeepReadonly<Static<typeof mergerInputSchema>>;
|
|
32
|
-
type
|
|
27
|
+
export type MergerOutput =
|
|
33
28
|
| { status: "completed"; attemptId: string; report: string; mergeCommitId: string }
|
|
34
29
|
| { status: "escalate"; attemptId: string; diagnosis: string; report: string };
|
|
35
|
-
/** Clean submission shape or seat-fallback tainted accepted receipt (ADR 0071). */
|
|
36
|
-
export type MergerOutput =
|
|
37
|
-
| MergerOutputClean
|
|
38
|
-
| WithEngineLaborFallback<MergerOutputClean>;
|
|
39
30
|
export const MERGER_OUTPUT_TOOL_NAME = "ak_merger_output";
|
|
40
31
|
export const MERGER_ACCEPTED_TEXT = "Merger output accepted";
|
|
41
32
|
|
|
@@ -75,12 +66,7 @@ export function validateMergerInput(value: unknown): MergerInput {
|
|
|
75
66
|
export function validateMergerOutput(value: unknown, expectedAttemptId?: string): MergerOutput {
|
|
76
67
|
if (!record(value) || (expectedAttemptId !== undefined && value.attemptId !== expectedAttemptId)) throw new Error("Merger output attempt mismatch");
|
|
77
68
|
const status = typeof value.status === "string" ? value.status : undefined;
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
if (status !== undefined && !seatFallbackStatusHasLawfulEvidence(status, value)) {
|
|
81
|
-
throw new Error("Merger output has no recognized execution discriminator");
|
|
82
|
-
}
|
|
83
|
-
if (statusBase === "completed" && isFullGitObjectId(value.mergeCommitId)) return structuredClone(value) as MergerOutput;
|
|
84
|
-
if (statusBase === "escalate") return structuredClone(value) as MergerOutput;
|
|
69
|
+
if (status === "completed" && isFullGitObjectId(value.mergeCommitId)) return structuredClone(value) as MergerOutput;
|
|
70
|
+
if (status === "escalate") return structuredClone(value) as MergerOutput;
|
|
85
71
|
throw new Error("Merger output has no recognized execution discriminator");
|
|
86
72
|
}
|
package/src/merger-role.ts
CHANGED
|
@@ -1,8 +1,4 @@
|
|
|
1
1
|
import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
2
|
-
import {
|
|
3
|
-
readActivationEngineLaborFallbackField,
|
|
4
|
-
withEngineLaborFallbackField,
|
|
5
|
-
} from "./engine-labor-fallback.ts";
|
|
6
2
|
import { MERGER_ACCEPTED_TEXT, MERGER_OUTPUT_TOOL_NAME, mergerOutputSchema, validateMergerInput, validateMergerOutput, type MergerInput } from "./merger-contracts.ts";
|
|
7
3
|
import type { MergerGitState } from "./merger-git-state.ts";
|
|
8
4
|
import { exactUtf8 } from "./exact-utf8.ts";
|
|
@@ -51,10 +47,7 @@ export function createMergerRoleRuntime(pi: ExtensionAPI, dependencies: MergerRo
|
|
|
51
47
|
if (state.mergeCommitId !== output.mergeCommitId || !same(state.parentObjectIds, [activation.input.targetObjectId, activation.input.sourceObjectId]) || state.unmergedPaths.length !== 0 || !state.worktreeClean || state.resolutionChangedPaths.some(path => !scope.has(path))) host.failInfrastructure(new Error("Merger completed-state verification failed"), ctx, id);
|
|
52
48
|
}
|
|
53
49
|
accepted = true;
|
|
54
|
-
const acceptedDetails =
|
|
55
|
-
output,
|
|
56
|
-
readActivationEngineLaborFallbackField(),
|
|
57
|
-
);
|
|
50
|
+
const acceptedDetails = output;
|
|
58
51
|
return { content: [{ type: "text" as const, text: MERGER_ACCEPTED_TEXT }], details: acceptedDetails, terminate: true as const };
|
|
59
52
|
} });
|
|
60
53
|
pi.on("before_agent_start", event => { if (!activation) throw new Error("Merger is not activated"); const admitted = { attemptId: activation.input.attemptId, targetObjectId: activation.input.targetObjectId, sourceObjectId: activation.input.sourceObjectId, task: materialText(activation.input, "task"), authority: materialText(activation.input, "authority"), targetIntent: materialText(activation.input, "targetIntent"), sourceIntent: materialText(activation.input, "sourceIntent"), expectedConflictPaths: activation.input.expectedConflictPaths, resolutionScope: activation.input.resolutionScope, authorizedChecks: activation.input.authorizedChecks }; return { systemPrompt: `${event.systemPrompt}\n\n<merger_soul>\n${activation.soul}\n</merger_soul>\n\n<merger_assignment>\n${JSON.stringify(admitted)}\n</merger_assignment>` }; });
|
|
@@ -8,7 +8,6 @@ import { createAssistantMessageEventStream } from "@earendil-works/pi-ai";
|
|
|
8
8
|
import { Type, type Static } from "typebox";
|
|
9
9
|
import { Value } from "typebox/value";
|
|
10
10
|
|
|
11
|
-
import { seatFallbackBaseStatus } from "./engine-labor-fallback.ts";
|
|
12
11
|
import {
|
|
13
12
|
NAVIGATOR_INVOCATION_ENTRY,
|
|
14
13
|
mintNavigatorInvocationId,
|
|
@@ -462,18 +461,6 @@ export type NavigatorCandidateSelection = {
|
|
|
462
461
|
readonly matchedToSettlement: boolean;
|
|
463
462
|
};
|
|
464
463
|
|
|
465
|
-
/** Match route-playbook statuses against settlement, treating seat-fallback taint as base-equivalent. */
|
|
466
|
-
function statusListMatchesSettlement(
|
|
467
|
-
candidateStatuses: readonly string[],
|
|
468
|
-
settlementStatus: string,
|
|
469
|
-
): boolean {
|
|
470
|
-
if (candidateStatuses.includes(settlementStatus)) return true;
|
|
471
|
-
const settlementBase = seatFallbackBaseStatus(settlementStatus);
|
|
472
|
-
return candidateStatuses.some(
|
|
473
|
-
(status) => seatFallbackBaseStatus(status) === settlementBase,
|
|
474
|
-
);
|
|
475
|
-
}
|
|
476
|
-
|
|
477
464
|
export function selectNavigatorCandidate(
|
|
478
465
|
candidates: readonly NavigatorCandidate[],
|
|
479
466
|
settlement: NavigatorSettlement,
|
|
@@ -492,7 +479,7 @@ export function selectNavigatorCandidate(
|
|
|
492
479
|
const statusSpecific = rolePhaseMatched.find(
|
|
493
480
|
(candidate) =>
|
|
494
481
|
candidate.matches?.statuses !== undefined &&
|
|
495
|
-
|
|
482
|
+
candidate.matches.statuses.includes(settlement.status!),
|
|
496
483
|
);
|
|
497
484
|
if (statusSpecific !== undefined) {
|
|
498
485
|
return { candidate: statusSpecific, matchedToSettlement: true };
|
package/src/notary-contracts.ts
CHANGED
|
@@ -5,13 +5,6 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { Type } from "typebox";
|
|
7
7
|
|
|
8
|
-
import {
|
|
9
|
-
readActivationEngineLaborFallbackField,
|
|
10
|
-
seatFallbackBaseStatus,
|
|
11
|
-
seatFallbackStatusHasLawfulEvidence,
|
|
12
|
-
withEngineLaborFallbackField,
|
|
13
|
-
type WithEngineLaborFallback,
|
|
14
|
-
} from "./engine-labor-fallback.ts";
|
|
15
8
|
import { openToolObject } from "./open-tool-schema.ts";
|
|
16
9
|
|
|
17
10
|
export const NOTARY_OUTPUT_TOOL_NAME = "ak_notary_output";
|
|
@@ -45,7 +38,7 @@ export type NotarySourceRunLocator = {
|
|
|
45
38
|
readonly role: string;
|
|
46
39
|
};
|
|
47
40
|
|
|
48
|
-
type
|
|
41
|
+
export type NotaryOutput =
|
|
49
42
|
| { readonly status: "pass"; readonly findings: readonly string[] }
|
|
50
43
|
| {
|
|
51
44
|
readonly status: "bounce";
|
|
@@ -53,11 +46,6 @@ type NotaryOutputClean =
|
|
|
53
46
|
readonly findings: readonly string[];
|
|
54
47
|
};
|
|
55
48
|
|
|
56
|
-
/** Clean submission or seat-fallback tainted accepted receipt (ADR 0071). */
|
|
57
|
-
export type NotaryOutput =
|
|
58
|
-
| NotaryOutputClean
|
|
59
|
-
| WithEngineLaborFallback<NotaryOutputClean>;
|
|
60
|
-
|
|
61
49
|
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
62
50
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
63
51
|
}
|
|
@@ -76,10 +64,10 @@ export function validateNotaryOutput(value: unknown): NotaryOutput {
|
|
|
76
64
|
throw new Error("Notary output has no recognized execution discriminator");
|
|
77
65
|
}
|
|
78
66
|
const statusRaw = typeof value.status === "string" ? value.status : undefined;
|
|
79
|
-
if (statusRaw === undefined
|
|
67
|
+
if (statusRaw === undefined) {
|
|
80
68
|
throw new Error("Notary output has no recognized execution discriminator");
|
|
81
69
|
}
|
|
82
|
-
const status =
|
|
70
|
+
const status = statusRaw;
|
|
83
71
|
if (status === "bounce") {
|
|
84
72
|
const clone = structuredClone(value) as Record<string, unknown>;
|
|
85
73
|
if (clone.disposition === undefined) clone.disposition = "rewrite";
|
|
@@ -94,20 +82,12 @@ export function validateNotaryOutput(value: unknown): NotaryOutput {
|
|
|
94
82
|
throw new Error("Notary output has no recognized execution discriminator");
|
|
95
83
|
}
|
|
96
84
|
|
|
97
|
-
/** Shape check for recorded accepted details (may include engineLaborFallback). */
|
|
98
85
|
export function validateRecordedNotaryOutput(value: unknown): NotaryOutput {
|
|
99
86
|
return validateNotaryOutput(value);
|
|
100
87
|
}
|
|
101
88
|
|
|
102
|
-
export function withNotaryAcceptedDetails(output: NotaryOutput): NotaryOutput {
|
|
103
|
-
return withEngineLaborFallbackField(
|
|
104
|
-
output,
|
|
105
|
-
readActivationEngineLaborFallbackField(),
|
|
106
|
-
) as NotaryOutput;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
89
|
export function notaryDecisiveFacts(output: NotaryOutput): Record<string, unknown> {
|
|
110
|
-
const status =
|
|
90
|
+
const status = String(output.status);
|
|
111
91
|
const facts: Record<string, unknown> = { status, officer: "notary" };
|
|
112
92
|
if (status === "pass" || status === "bounce") {
|
|
113
93
|
const findings = (output as { findings?: unknown }).findings;
|
package/src/notary-role.ts
CHANGED
|
@@ -14,7 +14,6 @@ import {
|
|
|
14
14
|
NOTARY_SOURCE_RUN_FLAG,
|
|
15
15
|
notaryOutputSchema,
|
|
16
16
|
validateNotaryOutput,
|
|
17
|
-
withNotaryAcceptedDetails,
|
|
18
17
|
type NotarySourceRunLocator,
|
|
19
18
|
} from "./notary-contracts.ts";
|
|
20
19
|
|
|
@@ -114,10 +113,9 @@ export function createNotaryRoleRuntime(
|
|
|
114
113
|
? error
|
|
115
114
|
: new Error(String(error));
|
|
116
115
|
}
|
|
117
|
-
const acceptedDetails = withNotaryAcceptedDetails(output);
|
|
118
116
|
return {
|
|
119
117
|
content: [{ type: "text" as const, text: NOTARY_ACCEPTED_TEXT }],
|
|
120
|
-
details:
|
|
118
|
+
details: output,
|
|
121
119
|
terminate: true as const,
|
|
122
120
|
};
|
|
123
121
|
},
|
|
@@ -1,11 +1,5 @@
|
|
|
1
1
|
/** Package-owned Judge output leaf — no role registration surface. */
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
seatFallbackBaseStatus,
|
|
5
|
-
seatFallbackStatusHasLawfulEvidence,
|
|
6
|
-
type SeatFallbackTaintedStatus,
|
|
7
|
-
type WithEngineLaborFallback,
|
|
8
|
-
} from "../engine-labor-fallback.ts";
|
|
9
3
|
|
|
10
4
|
export const JUDGE_OUTPUT_TOOL_NAME = "ak_judge_output";
|
|
11
5
|
export const JUDGE_ACCEPTED_TEXT = "Judge verdict accepted";
|
|
@@ -17,7 +11,7 @@ export type JudgeClass = {
|
|
|
17
11
|
disposition: string;
|
|
18
12
|
};
|
|
19
13
|
|
|
20
|
-
type
|
|
14
|
+
export type JudgeVerdict =
|
|
21
15
|
| { judgeStatus: "converged"; note?: string; evidence?: unknown }
|
|
22
16
|
| {
|
|
23
17
|
judgeStatus: "continue";
|
|
@@ -33,11 +27,6 @@ type JudgeVerdictClean =
|
|
|
33
27
|
evidence?: unknown;
|
|
34
28
|
};
|
|
35
29
|
|
|
36
|
-
/** Clean submission shape or seat-fallback tainted accepted receipt (ADR 0071). */
|
|
37
|
-
export type JudgeVerdict =
|
|
38
|
-
| JudgeVerdictClean
|
|
39
|
-
| WithEngineLaborFallback<JudgeVerdictClean>;
|
|
40
|
-
|
|
41
30
|
export function validateAcceptedJudgeDetails(verdict: unknown): JudgeVerdict {
|
|
42
31
|
if (verdict === null || typeof verdict !== "object" || Array.isArray(verdict)) throw new Error("Judge verdict has no execution discriminator");
|
|
43
32
|
let judgeStatus: unknown;
|
|
@@ -49,12 +38,8 @@ export function validateAcceptedJudgeDetails(verdict: unknown): JudgeVerdict {
|
|
|
49
38
|
if (typeof judgeStatus !== "string") {
|
|
50
39
|
throw new Error("Judge verdict has no execution discriminator");
|
|
51
40
|
}
|
|
52
|
-
const base = seatFallbackBaseStatus(judgeStatus) as SeatFallbackTaintedStatus<
|
|
53
|
-
"converged" | "continue" | "escalate"
|
|
54
|
-
>;
|
|
55
41
|
if (
|
|
56
|
-
["converged", "continue", "escalate"].includes(
|
|
57
|
-
seatFallbackStatusHasLawfulEvidence(judgeStatus, verdict)
|
|
42
|
+
["converged", "continue", "escalate"].includes(judgeStatus)
|
|
58
43
|
) {
|
|
59
44
|
return verdict as JudgeVerdict;
|
|
60
45
|
}
|
|
@@ -1,11 +1,5 @@
|
|
|
1
1
|
/** Package-owned Reviewer intent and runtime-receipt leaves — no role registration surface. */
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
seatFallbackBaseStatus,
|
|
5
|
-
seatFallbackStatusHasLawfulEvidence,
|
|
6
|
-
type SeatFallbackTaintedStatus,
|
|
7
|
-
type WithEngineLaborFallback,
|
|
8
|
-
} from "../engine-labor-fallback.ts";
|
|
9
3
|
import type { ReviewerAcceptedEvidence, ReviewerFailureClassification, ReviewerWorkspaceDisposition } from "../reviewer-execution-ledger.ts";
|
|
10
4
|
|
|
11
5
|
export const REVIEWER_OUTPUT_TOOL_NAME = "ak_reviewer_output";
|
|
@@ -36,7 +30,7 @@ export type RuntimeReviewerAcceptedBatch = Readonly<{
|
|
|
36
30
|
}>;
|
|
37
31
|
/** Honest Spec-child disposition on the receipt face. */
|
|
38
32
|
export type RuntimeReviewerSpecDisposition = "launched" | "skipped-missing";
|
|
39
|
-
type
|
|
33
|
+
export type RuntimeReviewerReceiptV2 = Readonly<{
|
|
40
34
|
version: 2;
|
|
41
35
|
status: "completed" | "refused";
|
|
42
36
|
diagnostic?: string;
|
|
@@ -55,14 +49,6 @@ type RuntimeReviewerReceiptV2Clean = Readonly<{
|
|
|
55
49
|
target?: ReviewerAcceptedEvidence["target"];
|
|
56
50
|
}>;
|
|
57
51
|
}>;
|
|
58
|
-
/** Clean runtime receipt or seat-fallback tainted accepted receipt (ADR 0071). */
|
|
59
|
-
export type RuntimeReviewerReceiptV2 =
|
|
60
|
-
| RuntimeReviewerReceiptV2Clean
|
|
61
|
-
| WithEngineLaborFallback<
|
|
62
|
-
Omit<RuntimeReviewerReceiptV2Clean, "status"> & {
|
|
63
|
-
status: SeatFallbackTaintedStatus<"completed" | "refused">;
|
|
64
|
-
}
|
|
65
|
-
>;
|
|
66
52
|
|
|
67
53
|
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
68
54
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -102,10 +88,6 @@ export function validateReviewerIntent(output: unknown): ReviewerIntent {
|
|
|
102
88
|
/** Validate runtime-owned facts at their real identity seams (target pins + plain text). */
|
|
103
89
|
export function validateRuntimeReviewerReceipt(output: unknown): RuntimeReviewerReceiptV2 {
|
|
104
90
|
const status = read(output, "status");
|
|
105
|
-
// ADR 0071: tainted top-level status requires latch-shaped engineLaborFallback evidence.
|
|
106
|
-
if (typeof status === "string" && !seatFallbackStatusHasLawfulEvidence(status, output)) {
|
|
107
|
-
throw new Error("Reviewer receipt has no recognized execution discriminator");
|
|
108
|
-
}
|
|
109
91
|
const acceptedBatch = read(output, "acceptedBatch");
|
|
110
92
|
const identities = read(output, "identities");
|
|
111
93
|
const construction = read(identities, "construction");
|
|
@@ -173,8 +155,7 @@ export function projectReviewerIntentToReceipt(intentValue: unknown, receiptValu
|
|
|
173
155
|
const intent = validateReviewerIntent(intentValue);
|
|
174
156
|
const receipt = validateRuntimeReviewerReceipt(receiptValue);
|
|
175
157
|
const receiptStatus = String(receipt.status);
|
|
176
|
-
|
|
177
|
-
if (receiptBase !== intent.status || (intent.status === "completed" ? receipt.diagnostic !== undefined : receipt.diagnostic !== intent.diagnostic)) {
|
|
158
|
+
if (receiptStatus !== intent.status || (intent.status === "completed" ? receipt.diagnostic !== undefined : receipt.diagnostic !== intent.diagnostic)) {
|
|
178
159
|
throw new Error("Reviewer intent and runtime receipt disagree");
|
|
179
160
|
}
|
|
180
161
|
return receipt;
|
|
@@ -25,10 +25,6 @@ import {
|
|
|
25
25
|
type RuntimeReviewerReceiptV2,
|
|
26
26
|
} from "./reviewer-output.ts";
|
|
27
27
|
import { isAuditEscalationResult } from "../audit-escalation.ts";
|
|
28
|
-
import {
|
|
29
|
-
seatFallbackBaseStatus,
|
|
30
|
-
seatFallbackStatusHasLawfulEvidence,
|
|
31
|
-
} from "../engine-labor-fallback.ts";
|
|
32
28
|
import { DOCTOR_OUTPUT_TOOL_NAME, validateDoctorSubmissionShape, validateRecordedDoctorOutput, type DoctorOutput, type DoctorSubmission } from "../doctor-contracts.ts";
|
|
33
29
|
import { MERGER_ACCEPTED_TEXT, MERGER_OUTPUT_TOOL_NAME, validateMergerOutput, type MergerOutput } from "../merger-contracts.ts";
|
|
34
30
|
import { NOTARY_ACCEPTED_TEXT, NOTARY_OUTPUT_TOOL_NAME, validateRecordedNotaryOutput, type NotaryOutput } from "../notary-contracts.ts";
|
|
@@ -171,16 +167,11 @@ export function validateAcceptedDetails(
|
|
|
171
167
|
[NOTARY_OUTPUT_TOOL_NAME]: ["pass", "bounce"],
|
|
172
168
|
};
|
|
173
169
|
const collectorDiscriminator = toolName === COLLECTOR_OUTPUT_TOOL && Array.isArray(candidate?.groups);
|
|
174
|
-
const baseDiscriminator =
|
|
175
|
-
// ADR 0071: `-by-fallback` is not independently lawful — require latch-shaped evidence.
|
|
176
|
-
const taintedWithoutEvidence =
|
|
177
|
-
typeof discriminator === "string" &&
|
|
178
|
-
!seatFallbackStatusHasLawfulEvidence(discriminator, details);
|
|
170
|
+
const baseDiscriminator = discriminator;
|
|
179
171
|
const runtimeBindingMissing =
|
|
180
172
|
(toolName === DOCTOR_OUTPUT_TOOL_NAME && baseDiscriminator === "completed" && !(candidate?.cost !== null && typeof candidate?.cost === "object")) ||
|
|
181
173
|
(toolName === REVIEWER_OUTPUT_TOOL_NAME && candidate?.version !== 2);
|
|
182
174
|
if (
|
|
183
|
-
taintedWithoutEvidence ||
|
|
184
175
|
runtimeBindingMissing ||
|
|
185
176
|
(!collectorDiscriminator && (typeof discriminator !== "string" || !lawfulStatuses[toolName].includes(baseDiscriminator as string)))
|
|
186
177
|
) {
|
|
@@ -219,12 +210,12 @@ export function validateAcceptedLifecycle(
|
|
|
219
210
|
const details = validateAcceptedDetails(toolName, detailsValue);
|
|
220
211
|
if (toolName === DOCTOR_OUTPUT_TOOL_NAME) {
|
|
221
212
|
const testimony = validateDoctorSubmissionShape(argumentsValue);
|
|
222
|
-
if (
|
|
213
|
+
if ((String(testimony.status)) === "refused") {
|
|
223
214
|
if (!deepEqual(testimony, details)) throw new Error("accepted tool lifecycle details mismatch");
|
|
224
215
|
return details;
|
|
225
216
|
}
|
|
226
217
|
const receipt = details as DoctorOutput & { cost?: unknown };
|
|
227
|
-
if (
|
|
218
|
+
if ((String(receipt.status)) !== "completed") {
|
|
228
219
|
throw new Error("accepted tool lifecycle details mismatch");
|
|
229
220
|
}
|
|
230
221
|
const { cost: _runtimeCost, ...projected } = receipt;
|
|
@@ -253,7 +244,7 @@ export function acceptedFacts(toolName: TerminatingToolName, details: AcceptedDe
|
|
|
253
244
|
case MERGER_OUTPUT_TOOL_NAME: {
|
|
254
245
|
const output = details as unknown as Record<string, unknown>;
|
|
255
246
|
const status = output.status as string;
|
|
256
|
-
return { status, ...(
|
|
247
|
+
return { status, ...(status === "completed" && typeof output.mergeCommitId === "string" ? { commit: output.mergeCommitId } : {}) };
|
|
257
248
|
}
|
|
258
249
|
case COLLECTOR_OUTPUT_TOOL:
|
|
259
250
|
return { status: "collected" };
|
|
@@ -15,24 +15,16 @@ export type {
|
|
|
15
15
|
} from "./fixer-output.ts";
|
|
16
16
|
export { fixerPrerequisiteSchema, fixerPrerequisitesSchema, parseFixerPrerequisites, validateFixerPrerequisites } from "./fixer-packet.ts";
|
|
17
17
|
export type { FixerInvocationInput, FixerPrerequisite } from "./fixer-packet.ts";
|
|
18
|
-
import type { WithEngineLaborFallback } from "../engine-labor-fallback.ts";
|
|
19
18
|
import { validateFixerOutput, type FixerOutput } from "./fixer-output.ts";
|
|
20
19
|
|
|
21
20
|
export const CODER_OUTPUT_TOOL_NAME = "ak_coder_output";
|
|
22
21
|
export const CODER_ACCEPTED_TEXT = "Coder report accepted";
|
|
23
22
|
export type WorkerRoleLabel = "Coder" | "Fixer";
|
|
24
|
-
type
|
|
23
|
+
export type CoderOutput =
|
|
25
24
|
| { status: "planned"; report: string }
|
|
26
25
|
| { status: "completed" | "refused"; report: string }
|
|
27
26
|
| { status: "unfinished"; report: string; remainingScope: string; reason?: string };
|
|
28
|
-
|
|
29
|
-
export type CoderOutput =
|
|
30
|
-
| CoderOutputClean
|
|
31
|
-
| WithEngineLaborFallback<CoderOutputClean>;
|
|
32
|
-
export type WorkerOutput =
|
|
33
|
-
| CoderOutput
|
|
34
|
-
| FixerOutput
|
|
35
|
-
| WithEngineLaborFallback<FixerOutput>;
|
|
27
|
+
export type WorkerOutput = CoderOutput | FixerOutput;
|
|
36
28
|
|
|
37
29
|
export function validateAcceptedCoderDetails(output: unknown): CoderOutput {
|
|
38
30
|
return output as CoderOutput;
|
|
@@ -39,11 +39,6 @@ import {
|
|
|
39
39
|
COLLECTOR_WAIT_TOOL,
|
|
40
40
|
} from "../collector-ledger.ts";
|
|
41
41
|
import { ENGINE_DETOUR_TOOL_NAME } from "../engine-detour.ts";
|
|
42
|
-
import {
|
|
43
|
-
readEngineLaborFallbackFieldFrom,
|
|
44
|
-
seatFallbackBaseStatus,
|
|
45
|
-
seatFallbackStatusHasLawfulEvidence,
|
|
46
|
-
} from "../engine-labor-fallback.ts";
|
|
47
42
|
import {
|
|
48
43
|
JUDGE_OUTPUT_TOOL_NAME,
|
|
49
44
|
type JudgeVerdict,
|
|
@@ -1170,10 +1165,8 @@ function judgeDecisiveFacts(
|
|
|
1170
1165
|
const facts: Record<string, unknown> = {
|
|
1171
1166
|
judgeStatus,
|
|
1172
1167
|
...auditNoReceiptDecisiveFact(verdict),
|
|
1173
|
-
// #380: spread sole-built field; do not re-key here (S1).
|
|
1174
|
-
...readEngineLaborFallbackFieldFrom(verdict),
|
|
1175
1168
|
};
|
|
1176
|
-
const statusBase =
|
|
1169
|
+
const statusBase = judgeStatus;
|
|
1177
1170
|
if (statusBase === "continue") {
|
|
1178
1171
|
const fix = safelyRead(verdict, "fix");
|
|
1179
1172
|
if (fix.readable && isRecord(fix.value)) {
|
|
@@ -1227,7 +1220,7 @@ function coderDecisiveFacts(output: CoderOutput): Record<string, unknown> {
|
|
|
1227
1220
|
if (status.readable && typeof status.value === "string") facts.coderStatus = status.value;
|
|
1228
1221
|
const statusBase =
|
|
1229
1222
|
status.readable && typeof status.value === "string"
|
|
1230
|
-
?
|
|
1223
|
+
? (status.value)
|
|
1231
1224
|
: undefined;
|
|
1232
1225
|
const remainingScope = safelyRead(candidate, "remainingScope");
|
|
1233
1226
|
if (statusBase === "unfinished" && remainingScope.readable && typeof remainingScope.value === "string") facts.remainingScope = remainingScope.value;
|
|
@@ -1247,7 +1240,7 @@ function fixerDecisiveFacts(output: FixerOutput): Record<string, unknown> {
|
|
|
1247
1240
|
if (status.readable && typeof status.value === "string") facts.fixerStatus = status.value;
|
|
1248
1241
|
const statusBase =
|
|
1249
1242
|
status.readable && typeof status.value === "string"
|
|
1250
|
-
?
|
|
1243
|
+
? (status.value)
|
|
1251
1244
|
: undefined;
|
|
1252
1245
|
const remainingScope = safelyRead(candidate, "remainingScope");
|
|
1253
1246
|
if ((statusBase === "unfinished" || statusBase === "refused") && remainingScope.readable && typeof remainingScope.value === "string") facts.remainingScope = remainingScope.value;
|
|
@@ -1340,7 +1333,7 @@ function doctorDecisiveFacts(output: DoctorOutput): Record<string, unknown> {
|
|
|
1340
1333
|
if (status.readable && typeof status.value === "string") facts.doctorStatus = status.value;
|
|
1341
1334
|
const statusBase =
|
|
1342
1335
|
status.readable && typeof status.value === "string"
|
|
1343
|
-
?
|
|
1336
|
+
? (status.value)
|
|
1344
1337
|
: undefined;
|
|
1345
1338
|
if (statusBase === "refused") {
|
|
1346
1339
|
const reason = safelyRead(candidate, "reason");
|
|
@@ -1389,8 +1382,6 @@ function reviewerDecisiveFacts(
|
|
|
1389
1382
|
amendmentAxes,
|
|
1390
1383
|
acceptedBatchPresent: acceptedBatch.readable && acceptedBatch.value !== undefined,
|
|
1391
1384
|
...auditNoReceiptDecisiveFact(candidate),
|
|
1392
|
-
// #380: spread sole-built field; do not re-key here (S1).
|
|
1393
|
-
...readEngineLaborFallbackFieldFrom(candidate),
|
|
1394
1385
|
};
|
|
1395
1386
|
if (status.readable && typeof status.value === "string") facts.reviewerStatus = status.value;
|
|
1396
1387
|
if (
|
|
@@ -1402,7 +1393,7 @@ function reviewerDecisiveFacts(
|
|
|
1402
1393
|
const diagnostic = safelyRead(candidate, "diagnostic");
|
|
1403
1394
|
const statusBase =
|
|
1404
1395
|
status.readable && typeof status.value === "string"
|
|
1405
|
-
?
|
|
1396
|
+
? (status.value)
|
|
1406
1397
|
: undefined;
|
|
1407
1398
|
if (statusBase === "refused" && diagnostic.readable) {
|
|
1408
1399
|
facts.diagnosticPresent = typeof diagnostic.value === "string" && diagnostic.value.trim().length > 0;
|
|
@@ -1903,10 +1894,8 @@ export function extractJudgeRoleOutcome(
|
|
|
1903
1894
|
const statusRead = safelyRead(details, "judgeStatus");
|
|
1904
1895
|
if (!statusRead.readable || typeof statusRead.value !== "string") continue;
|
|
1905
1896
|
const judgeStatus = statusRead.value;
|
|
1906
|
-
const statusBase =
|
|
1897
|
+
const statusBase = judgeStatus;
|
|
1907
1898
|
if (statusBase !== "converged" && statusBase !== "continue" && statusBase !== "escalate") continue;
|
|
1908
|
-
// ADR 0071: `-by-fallback` without latch-shaped evidence is not a lawful terminal.
|
|
1909
|
-
if (!seatFallbackStatusHasLawfulEvidence(judgeStatus, details)) continue;
|
|
1910
1899
|
return {
|
|
1911
1900
|
kind: "accepted",
|
|
1912
1901
|
role: "judge",
|
|
@@ -3012,10 +3001,9 @@ async function settleLawfulDoctorTerminalResult(
|
|
|
3012
3001
|
const extracted = extractDoctorRoleOutcome(entries);
|
|
3013
3002
|
if (extracted === undefined) return undefined;
|
|
3014
3003
|
// Bind completed receipt case identity to the admitted Issue evidence case.
|
|
3015
|
-
// Seat-fallback may taint status; base semantics still require case binding.
|
|
3016
3004
|
if (
|
|
3017
3005
|
extracted.output !== undefined &&
|
|
3018
|
-
|
|
3006
|
+
(String(extracted.output.status)) === "completed"
|
|
3019
3007
|
) {
|
|
3020
3008
|
const completedCase = (
|
|
3021
3009
|
extracted.output as {
|
|
@@ -3466,7 +3454,7 @@ function mergerDecisiveFacts(output: MergerOutput): Record<string, unknown> {
|
|
|
3466
3454
|
if (attemptId.readable && attemptId.value !== undefined) facts.attemptId = attemptId.value;
|
|
3467
3455
|
const statusBase =
|
|
3468
3456
|
status.readable && typeof status.value === "string"
|
|
3469
|
-
?
|
|
3457
|
+
? (status.value)
|
|
3470
3458
|
: undefined;
|
|
3471
3459
|
const decisiveKey = statusBase === "completed" ? "mergeCommitId" : "diagnosis";
|
|
3472
3460
|
const decisive = safelyRead(candidate, decisiveKey);
|
package/src/reviewer-role.ts
CHANGED
|
@@ -7,10 +7,6 @@ export type { CanonicalSkillBinding };
|
|
|
7
7
|
import { disposeComplianceDecision } from "./audit-escalation.ts";
|
|
8
8
|
import type { ComplianceDecision } from "./compliance-transport.ts";
|
|
9
9
|
import { appendActiveSessionCustomEntry } from "./compliance-transport.ts";
|
|
10
|
-
import {
|
|
11
|
-
readActivationEngineLaborFallbackField,
|
|
12
|
-
withEngineLaborFallbackField,
|
|
13
|
-
} from "./engine-labor-fallback.ts";
|
|
14
10
|
import { REVIEWER_CANDIDATE_ENTRY_TYPE } from "./dossier-resolution.ts";
|
|
15
11
|
import { type ReviewerSpecDisposition } from "./reviewer-construction.ts";
|
|
16
12
|
import { createReviewerDispatcher, type AcceptedReviewerDispatch, type AcceptedReviewerExecution, type ReviewerIssueFetcher, type ReviewerPinnedGitReader } from "./reviewer-dispatch.ts";
|
|
@@ -160,15 +156,11 @@ export function createReviewerRoleRuntime(
|
|
|
160
156
|
const output = validateReviewerIntent(parameters);
|
|
161
157
|
let record: ReviewerExecutionRecord;
|
|
162
158
|
try { record = ledger.recordForAudit(output.status); } catch (error) { if ((error as any)?.fatalReviewerInfrastructure) hostActions.failInfrastructure(error, toolCtx, id); throw error; }
|
|
163
|
-
const candidate =
|
|
164
|
-
assembleRuntimeReviewerReceipt({
|
|
159
|
+
const candidate = assembleRuntimeReviewerReceipt({
|
|
165
160
|
intent: output,
|
|
166
161
|
record,
|
|
167
162
|
canonicalSkillText: binding.snapshot.raw,
|
|
168
|
-
})
|
|
169
|
-
// #380: sole-built declaration when any leg detour fell back to seat labor.
|
|
170
|
-
readActivationEngineLaborFallbackField(),
|
|
171
|
-
);
|
|
163
|
+
});
|
|
172
164
|
// First-record-then-audit: candidate lands on the parent session books
|
|
173
165
|
// before the auditor is spawned (zero hand-delivery).
|
|
174
166
|
try {
|
package/src/role-runtime.ts
CHANGED
|
@@ -23,13 +23,6 @@ import {
|
|
|
23
23
|
} from "./tool-execution-observation.ts";
|
|
24
24
|
import { ENGINE_DETOUR_TOOL_NAME } from "./engine-detour.ts";
|
|
25
25
|
import { registerEngineDetourTool } from "./engine-detour-tool.ts";
|
|
26
|
-
import {
|
|
27
|
-
createEngineLaborFallbackLatch,
|
|
28
|
-
installActivationEngineLaborFallbackLatch,
|
|
29
|
-
restoreEngineLaborFallbackFromSessionEntries,
|
|
30
|
-
seatFallbackBaseStatus,
|
|
31
|
-
seatFallbackStatusHasLawfulEvidence,
|
|
32
|
-
} from "./engine-labor-fallback.ts";
|
|
33
26
|
import { createReceiptDeliveryPolicy, NO_RECEIPT_LIFECYCLE_ENTRY_TYPE, RECEIPT_DELIVERY_PROMPT } from "./receipt-delivery-policy.ts";
|
|
34
27
|
import { createOAuthKeepalive, type OAuthKeepaliveOptions } from "./oauth-keepalive.ts";
|
|
35
28
|
|
|
@@ -614,12 +607,7 @@ export function publicNavigatorSettlement(role: string, phase: NavigatorPhase, e
|
|
|
614
607
|
const status = typeof details.status === "string"
|
|
615
608
|
? details.status
|
|
616
609
|
: typeof details.judgeStatus === "string" ? details.judgeStatus : undefined;
|
|
617
|
-
|
|
618
|
-
if (status !== undefined && !seatFallbackStatusHasLawfulEvidence(status, event.details)) {
|
|
619
|
-
return undefined;
|
|
620
|
-
}
|
|
621
|
-
// Seat-fallback taint keeps escalate semantics (base) while preserving the polluted token.
|
|
622
|
-
if (status !== undefined && seatFallbackBaseStatus(status) === "escalate") {
|
|
610
|
+
if (status !== undefined && status === "escalate") {
|
|
623
611
|
return { kind: "human_decision", role, phase, status };
|
|
624
612
|
}
|
|
625
613
|
return { kind: "accepted", role, phase, ...(status === undefined ? {} : { status }) };
|
|
@@ -652,9 +640,7 @@ export function createRoleRuntimeExtension(
|
|
|
652
640
|
const pendingInfrastructureFailures = new Map<string, PendingInfrastructureFailure>();
|
|
653
641
|
// Envelope-owned execute→tool_result bridge for Gatekeeper non-pass (ADR 0018).
|
|
654
642
|
const pendingGatekeeperNonPassByToolCallId = new Map<string, GatekeeperNonPassResult>();
|
|
655
|
-
// #357 T2 / #378 / #380 / #391: engine detour once-latch + seat-fallback latch (any role+engine).
|
|
656
643
|
let engineDetourRegistration: ReturnType<typeof registerEngineDetourTool> | undefined;
|
|
657
|
-
let engineLaborFallbackLatch = createEngineLaborFallbackLatch();
|
|
658
644
|
// #288 primary-session thin adapter. The policy is the sole budget owner;
|
|
659
645
|
// terminating-tool rejections and mechanical delivery requests share two turns.
|
|
660
646
|
let receiptDelivery = createReceiptDeliveryPolicy();
|
|
@@ -1140,18 +1126,6 @@ export function createRoleRuntimeExtension(
|
|
|
1140
1126
|
pendingNavigatorSettlement = undefined;
|
|
1141
1127
|
pendingInfrastructureFailures.clear();
|
|
1142
1128
|
pendingGatekeeperNonPassByToolCallId.clear();
|
|
1143
|
-
engineLaborFallbackLatch = createEngineLaborFallbackLatch();
|
|
1144
|
-
// #380 resume: restore sole-built fallback from durable same-session detour results.
|
|
1145
|
-
const sessionEntries =
|
|
1146
|
-
typeof ctx.sessionManager?.getEntries === "function"
|
|
1147
|
-
? ctx.sessionManager.getEntries()
|
|
1148
|
-
: [];
|
|
1149
|
-
restoreEngineLaborFallbackFromSessionEntries(
|
|
1150
|
-
engineLaborFallbackLatch,
|
|
1151
|
-
sessionEntries,
|
|
1152
|
-
ENGINE_DETOUR_TOOL_NAME,
|
|
1153
|
-
);
|
|
1154
|
-
installActivationEngineLaborFallbackLatch(engineLaborFallbackLatch);
|
|
1155
1129
|
engineDetourRegistration?.resetLatch();
|
|
1156
1130
|
navigatorWorkContext = undefined;
|
|
1157
1131
|
// #351: OAuth keepalive is orthogonal to --ak-role; start before role early-return
|
|
@@ -1267,7 +1241,6 @@ export function createRoleRuntimeExtension(
|
|
|
1267
1241
|
await executeActivationStage(entry.role, activationStage(entry.role, runtime), { clock, writeTrace });
|
|
1268
1242
|
// #357 T2 / #378 / #380 / #391: any role+engine activation registers the package detour tool once.
|
|
1269
1243
|
// Gate is env presence only — no per-engine execute branch; no role-module spawn.
|
|
1270
|
-
// Seat-fallback latch is activation-scoped (installed at session_start) so legs share it.
|
|
1271
1244
|
if (engineDetourRegistration === undefined) {
|
|
1272
1245
|
engineDetourRegistration = registerEngineDetourTool(pi, hostActions);
|
|
1273
1246
|
if (!engineDetourRegistration.registered) {
|