@akagilnc/pi-workflow-roles 0.1.2383 → 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/audit-escalation.js +0 -13
- package/dist/compliance-transport.js +28 -5
- package/dist/doctor-contracts.js +2 -9
- package/dist/dossier-resolution.js +21 -2
- package/dist/engine-detour-tool.js +10 -35
- package/dist/evidence-child-executor.js +12 -4
- package/dist/merger-contracts.js +2 -8
- package/dist/navigator-attendance.js +1 -9
- package/dist/navigator-invocation-identity.js +16 -4
- package/dist/notary-contracts.js +7 -25
- 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 +6 -11
- package/dist/public-cli/main.js +125 -475
- package/package.json +1 -1
- package/scripts/build-package.mjs +1 -2
- package/src/analyst-gate-cycles-read.ts +5 -8
- package/src/analyst-metric-families/acceptance-success-rework.ts +3 -6
- package/src/audit-escalation.ts +0 -25
- package/src/collector-role.ts +1 -8
- package/src/compliance-transport.ts +38 -6
- package/src/doctor-auditor.ts +3 -3
- package/src/doctor-contracts.ts +3 -18
- package/src/doctor-role.ts +1 -5
- package/src/dossier-resolution.ts +25 -4
- package/src/engine-detour-tool.ts +16 -51
- package/src/evidence-child-executor.ts +12 -4
- package/src/factory-board.ts +2 -4
- package/src/gatekeeper-role.ts +33 -43
- package/src/judge-auditor.ts +3 -3
- package/src/judge-role.ts +1 -8
- package/src/merger-contracts.ts +3 -17
- package/src/merger-role.ts +1 -8
- package/src/navigator-attendance.ts +1 -14
- package/src/navigator-invocation-identity.ts +34 -13
- package/src/notary-contracts.ts +9 -43
- package/src/notary-role.ts +3 -5
- 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 +5 -14
- package/src/package-contracts/worker-output.ts +2 -10
- package/src/public-cli/doctor-run.ts +0 -2
- package/src/public-cli/fixer-run.ts +0 -15
- package/src/public-cli/judge-run.ts +0 -16
- package/src/public-cli/notary-run.ts +1 -1
- package/src/public-cli/one-shot-dispatch.ts +1 -1
- package/src/public-cli/reviewer-run.ts +0 -15
- package/src/public-cli/settlement.ts +110 -368
- package/src/public-cli/terminal.ts +3 -71
- package/src/reviewer-auditor.ts +3 -3
- package/src/reviewer-role.ts +2 -11
- package/src/role-runtime.ts +43 -37
- package/src/worker-role.ts +2 -14
- package/dist/engine-labor-fallback.js +0 -136
- package/src/engine-labor-fallback.ts +0 -270
|
@@ -6,7 +6,6 @@
|
|
|
6
6
|
* extra rows or shift column boundaries (note / fix.summary / decision question / reason).
|
|
7
7
|
*/
|
|
8
8
|
import { renderPublicAkRoleCommand } from "./command-renderer.ts";
|
|
9
|
-
import type { ComplianceAuditIncomplete } from "../compliance-transport.ts";
|
|
10
9
|
import type { NavigatorPhase } from "../navigator-attendance.ts";
|
|
11
10
|
import type { NoReceiptLifecycleFacts } from "../receipt-delivery-policy.ts";
|
|
12
11
|
|
|
@@ -41,9 +40,10 @@ export type TerminalRoleName =
|
|
|
41
40
|
| "merger"
|
|
42
41
|
| "notary";
|
|
43
42
|
|
|
43
|
+
/** Merger/Collector residual only — Notary/audit residual abolished (#475). */
|
|
44
44
|
export type ResidualIncompleteTerminalOutcome = {
|
|
45
45
|
kind: "incomplete";
|
|
46
|
-
role: "merger" | "collector"
|
|
46
|
+
role: "merger" | "collector";
|
|
47
47
|
status: "incomplete";
|
|
48
48
|
decision: "no-usable-result";
|
|
49
49
|
candidate: unknown;
|
|
@@ -52,35 +52,6 @@ export type ResidualIncompleteTerminalOutcome = {
|
|
|
52
52
|
decisiveFacts: Readonly<Record<string, unknown>>;
|
|
53
53
|
};
|
|
54
54
|
|
|
55
|
-
export type AuditIncompleteTerminalOutcome = {
|
|
56
|
-
kind: "audit_incomplete";
|
|
57
|
-
role: TerminalRoleName;
|
|
58
|
-
status: "audit-incomplete";
|
|
59
|
-
decision: "no-usable-decision";
|
|
60
|
-
/** The original role submission arguments, retained independently. */
|
|
61
|
-
roleCandidate: unknown;
|
|
62
|
-
/** The malformed auditor candidate and observation retained by compliance transport. */
|
|
63
|
-
audit: ComplianceAuditIncomplete;
|
|
64
|
-
acceptedReceipt: false;
|
|
65
|
-
decisiveFacts: Readonly<Record<string, unknown>>;
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
/** JSON-safe public stand-in for an omitted tool-call `arguments` member. */
|
|
69
|
-
export const JSON_SAFE_UNDEFINED_ARGUMENT = Object.freeze({
|
|
70
|
-
kind: "json-safe-sentinel",
|
|
71
|
-
type: "undefined",
|
|
72
|
-
} as const);
|
|
73
|
-
|
|
74
|
-
export type AuditIncompleteResidual = {
|
|
75
|
-
readonly roleCandidate: unknown;
|
|
76
|
-
readonly audit: ComplianceAuditIncomplete;
|
|
77
|
-
readonly acceptedReceipt: false;
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
export function jsonSafeComplianceCandidate(value: unknown): unknown {
|
|
81
|
-
return value === undefined ? JSON_SAFE_UNDEFINED_ARGUMENT : value;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
55
|
export type NoReceiptTerminalOutcome = NoReceiptLifecycleFacts & {
|
|
85
56
|
kind: "no_receipt";
|
|
86
57
|
role: TerminalRoleName;
|
|
@@ -102,7 +73,6 @@ export type TerminalRoleOutcome =
|
|
|
102
73
|
status: "audit_escalation";
|
|
103
74
|
decisiveFacts: Readonly<Record<string, unknown>>;
|
|
104
75
|
}
|
|
105
|
-
| AuditIncompleteTerminalOutcome
|
|
106
76
|
| ResidualIncompleteTerminalOutcome
|
|
107
77
|
| NoReceiptTerminalOutcome
|
|
108
78
|
| {
|
|
@@ -113,8 +83,6 @@ export type TerminalRoleOutcome =
|
|
|
113
83
|
/** Original diagnostic identity retained for the caller. */
|
|
114
84
|
diagnostic: string;
|
|
115
85
|
decisiveFacts: Readonly<Record<string, unknown>>;
|
|
116
|
-
/** Retained audit residual when publication itself failed. */
|
|
117
|
-
auditResidual?: AuditIncompleteResidual;
|
|
118
86
|
};
|
|
119
87
|
|
|
120
88
|
/** Lawful typed terminal results exit zero (including audit_escalation). */
|
|
@@ -131,7 +99,7 @@ export function exitCodeForTerminalOutcome(
|
|
|
131
99
|
}
|
|
132
100
|
|
|
133
101
|
export function buildResidualIncompleteTerminalOutcome(input: {
|
|
134
|
-
role: "merger" | "collector"
|
|
102
|
+
role: "merger" | "collector";
|
|
135
103
|
candidate: unknown;
|
|
136
104
|
diagnostic: string;
|
|
137
105
|
}): ResidualIncompleteTerminalOutcome {
|
|
@@ -152,42 +120,6 @@ export function buildResidualIncompleteTerminalOutcome(input: {
|
|
|
152
120
|
};
|
|
153
121
|
}
|
|
154
122
|
|
|
155
|
-
export function buildAuditIncompleteTerminalOutcome(input: {
|
|
156
|
-
role: TerminalRoleName;
|
|
157
|
-
roleCandidate: unknown;
|
|
158
|
-
audit: ComplianceAuditIncomplete;
|
|
159
|
-
}): AuditIncompleteTerminalOutcome {
|
|
160
|
-
const roleCandidate = jsonSafeComplianceCandidate(input.roleCandidate);
|
|
161
|
-
const audit = {
|
|
162
|
-
...input.audit,
|
|
163
|
-
candidate: jsonSafeComplianceCandidate(input.audit.candidate),
|
|
164
|
-
};
|
|
165
|
-
return {
|
|
166
|
-
kind: "audit_incomplete",
|
|
167
|
-
role: input.role,
|
|
168
|
-
status: "audit-incomplete",
|
|
169
|
-
decision: "no-usable-decision",
|
|
170
|
-
roleCandidate,
|
|
171
|
-
audit,
|
|
172
|
-
acceptedReceipt: false,
|
|
173
|
-
decisiveFacts: {
|
|
174
|
-
decision: "no-usable-decision",
|
|
175
|
-
roleCandidate,
|
|
176
|
-
auditCandidate: audit.candidate,
|
|
177
|
-
auditObservation: audit.observation,
|
|
178
|
-
observationKind: audit.observation.kind,
|
|
179
|
-
observationType: audit.observation.kind === "non-object-arguments"
|
|
180
|
-
? audit.observation.type
|
|
181
|
-
: audit.observation.kind === "object-status-unreadable"
|
|
182
|
-
? audit.observation.status
|
|
183
|
-
: audit.observation.kind === "missing-subject"
|
|
184
|
-
? audit.observation.subject
|
|
185
|
-
: audit.observation.kind,
|
|
186
|
-
acceptedReceipt: false,
|
|
187
|
-
},
|
|
188
|
-
};
|
|
189
|
-
}
|
|
190
|
-
|
|
191
123
|
export type TerminalNavigatorFact =
|
|
192
124
|
| {
|
|
193
125
|
disposition: "recommendation";
|
package/src/reviewer-auditor.ts
CHANGED
|
@@ -10,8 +10,8 @@ import {
|
|
|
10
10
|
} from "./compliance-transport.ts";
|
|
11
11
|
import {
|
|
12
12
|
readReviewerAuditSubjects,
|
|
13
|
+
requireAuditMaterials,
|
|
13
14
|
resolveAuditDossier,
|
|
14
|
-
toAuditIncomplete,
|
|
15
15
|
} from "./dossier-resolution.ts";
|
|
16
16
|
|
|
17
17
|
export const REVIEWER_AUDIT_TOOL_NAME = "ak_reviewer_audit_decision";
|
|
@@ -35,9 +35,9 @@ export function createPiReviewerAuditor(
|
|
|
35
35
|
): (options: ReviewerAuditOptions) => Promise<ComplianceDecision> {
|
|
36
36
|
return async (options) => {
|
|
37
37
|
const dossier = resolveAuditDossier();
|
|
38
|
-
|
|
38
|
+
requireAuditMaterials(dossier);
|
|
39
39
|
const subjects = readReviewerAuditSubjects(options.context);
|
|
40
|
-
|
|
40
|
+
requireAuditMaterials(subjects);
|
|
41
41
|
|
|
42
42
|
return runComplianceAudit({
|
|
43
43
|
tool: reviewerDecisionTool,
|
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 {
|
|
@@ -210,7 +202,6 @@ export function createReviewerRoleRuntime(
|
|
|
210
202
|
try { await dependencies.shutdownAgent?.(); } catch (error) { hostActions.failInfrastructure(ledger.recordInfrastructureFailure(error), toolCtx, id); }
|
|
211
203
|
return result;
|
|
212
204
|
},
|
|
213
|
-
auditIncomplete: (result) => result,
|
|
214
205
|
},
|
|
215
206
|
candidate,
|
|
216
207
|
);
|
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
|
|
|
@@ -50,6 +43,7 @@ import { decorateSettlementWithNavigation, formatNavigatorReport, NAVIGATOR_EVEN
|
|
|
50
43
|
import {
|
|
51
44
|
buildNavigatorInfrastructureFailureFact,
|
|
52
45
|
classifyPackagedRoleTerminalResult,
|
|
46
|
+
NAVIGATOR_INFRASTRUCTURE_FAILURE_EVIDENCE_KEYS,
|
|
53
47
|
NAVIGATOR_INVOCATION_ENTRY,
|
|
54
48
|
resolveLifecycleInvocationPrincipal,
|
|
55
49
|
} from "./navigator-invocation-identity.ts";
|
|
@@ -220,9 +214,11 @@ import { createMergerRoleRuntime, type MergerRoleDependencies } from "./merger-r
|
|
|
220
214
|
export {
|
|
221
215
|
buildNavigatorInfrastructureFailureFact,
|
|
222
216
|
classifyPackagedRoleTerminalResult,
|
|
217
|
+
hasNavigatorInfrastructureFailureBase,
|
|
223
218
|
isAcceptedPackagedRoleTerminalResult,
|
|
224
219
|
isDurablePackagedRoleTerminalResult,
|
|
225
220
|
isNavigatorInfrastructureFailureFact,
|
|
221
|
+
NAVIGATOR_INFRASTRUCTURE_FAILURE_EVIDENCE_KEYS,
|
|
226
222
|
NAVIGATOR_INFRASTRUCTURE_FAILURE_KIND,
|
|
227
223
|
type NavigatorInfrastructureFailureFact,
|
|
228
224
|
type PackagedRoleTerminalClassification,
|
|
@@ -550,6 +546,35 @@ function failInfrastructure(error: unknown, ctx: ExtensionContext): never {
|
|
|
550
546
|
throw error;
|
|
551
547
|
}
|
|
552
548
|
|
|
549
|
+
/**
|
|
550
|
+
* Envelope-owned pending infrastructure failure: closed fact + original Error evidence.
|
|
551
|
+
* tool_result projects once from this record; settlement consumes durable details as-is.
|
|
552
|
+
*/
|
|
553
|
+
type PendingInfrastructureFailure = {
|
|
554
|
+
readonly details: Record<string, unknown>;
|
|
555
|
+
};
|
|
556
|
+
|
|
557
|
+
function extractInfrastructureFailureEvidence(error: unknown): Record<string, unknown> {
|
|
558
|
+
if (typeof error !== "object" || error === null) return {};
|
|
559
|
+
const record = error as Record<string, unknown>;
|
|
560
|
+
const evidence: Record<string, unknown> = {};
|
|
561
|
+
for (const key of NAVIGATOR_INFRASTRUCTURE_FAILURE_EVIDENCE_KEYS) {
|
|
562
|
+
if (!Object.hasOwn(record, key)) continue;
|
|
563
|
+
// undefined → null so JSON durable details retain the empty-candidate key.
|
|
564
|
+
evidence[key] = record[key] === undefined ? null : record[key];
|
|
565
|
+
}
|
|
566
|
+
return evidence;
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
function buildPendingInfrastructureFailure(error: unknown): PendingInfrastructureFailure {
|
|
570
|
+
return {
|
|
571
|
+
details: {
|
|
572
|
+
...buildNavigatorInfrastructureFailureFact(),
|
|
573
|
+
...extractInfrastructureFailureEvidence(error),
|
|
574
|
+
},
|
|
575
|
+
};
|
|
576
|
+
}
|
|
577
|
+
|
|
553
578
|
function navigatorPhase(pi: ExtensionAPI, role: string): NavigatorPhase {
|
|
554
579
|
const metadata = packagedRoleMetadata(role);
|
|
555
580
|
if (metadata === undefined || metadata.phases[0] === null) return null;
|
|
@@ -582,12 +607,7 @@ export function publicNavigatorSettlement(role: string, phase: NavigatorPhase, e
|
|
|
582
607
|
const status = typeof details.status === "string"
|
|
583
608
|
? details.status
|
|
584
609
|
: typeof details.judgeStatus === "string" ? details.judgeStatus : undefined;
|
|
585
|
-
|
|
586
|
-
if (status !== undefined && !seatFallbackStatusHasLawfulEvidence(status, event.details)) {
|
|
587
|
-
return undefined;
|
|
588
|
-
}
|
|
589
|
-
// Seat-fallback taint keeps escalate semantics (base) while preserving the polluted token.
|
|
590
|
-
if (status !== undefined && seatFallbackBaseStatus(status) === "escalate") {
|
|
610
|
+
if (status !== undefined && status === "escalate") {
|
|
591
611
|
return { kind: "human_decision", role, phase, status };
|
|
592
612
|
}
|
|
593
613
|
return { kind: "accepted", role, phase, ...(status === undefined ? {} : { status }) };
|
|
@@ -616,12 +636,11 @@ export function createRoleRuntimeExtension(
|
|
|
616
636
|
let pendingNavigatorPresentation: { event: import("./navigator-attendance.ts").NavigatorEvent; report: import("./navigator-attendance.ts").NavigatorReport } | undefined;
|
|
617
637
|
let pendingNavigatorSettlement: Promise<void> | undefined;
|
|
618
638
|
let navigatorWorkContext: NavigatorWorkContext | undefined;
|
|
619
|
-
|
|
639
|
+
/** toolCallId → fact+evidence; one-shot projected onto durable tool_result (#475). */
|
|
640
|
+
const pendingInfrastructureFailures = new Map<string, PendingInfrastructureFailure>();
|
|
620
641
|
// Envelope-owned execute→tool_result bridge for Gatekeeper non-pass (ADR 0018).
|
|
621
642
|
const pendingGatekeeperNonPassByToolCallId = new Map<string, GatekeeperNonPassResult>();
|
|
622
|
-
// #357 T2 / #378 / #380 / #391: engine detour once-latch + seat-fallback latch (any role+engine).
|
|
623
643
|
let engineDetourRegistration: ReturnType<typeof registerEngineDetourTool> | undefined;
|
|
624
|
-
let engineLaborFallbackLatch = createEngineLaborFallbackLatch();
|
|
625
644
|
// #288 primary-session thin adapter. The policy is the sole budget owner;
|
|
626
645
|
// terminating-tool rejections and mechanical delivery requests share two turns.
|
|
627
646
|
let receiptDelivery = createReceiptDeliveryPolicy();
|
|
@@ -705,11 +724,11 @@ export function createRoleRuntimeExtension(
|
|
|
705
724
|
pi.on("tool_result", async (event) => {
|
|
706
725
|
const role = selectedRole;
|
|
707
726
|
if (role === undefined) return;
|
|
708
|
-
const
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
727
|
+
const pendingInfra = pendingInfrastructureFailures.get(event.toolCallId);
|
|
728
|
+
const isRoleInfrastructureFailure = pendingInfra !== undefined;
|
|
729
|
+
if (pendingInfra !== undefined) pendingInfrastructureFailures.delete(event.toolCallId);
|
|
730
|
+
// One-shot project fact + typed evidence so live settlement and durable session agree.
|
|
731
|
+
const infrastructureDetails = pendingInfra?.details;
|
|
713
732
|
const classified = infrastructureDetails === undefined
|
|
714
733
|
? event
|
|
715
734
|
: { ...event, details: infrastructureDetails };
|
|
@@ -878,7 +897,7 @@ export function createRoleRuntimeExtension(
|
|
|
878
897
|
navigatorAttendance?.dispose();
|
|
879
898
|
navigatorAttendance = undefined;
|
|
880
899
|
pendingNavigatorSettlement = undefined;
|
|
881
|
-
|
|
900
|
+
pendingInfrastructureFailures.clear();
|
|
882
901
|
pendingGatekeeperNonPassByToolCallId.clear();
|
|
883
902
|
observationFace.reset();
|
|
884
903
|
});
|
|
@@ -886,7 +905,7 @@ export function createRoleRuntimeExtension(
|
|
|
886
905
|
const hostActions = {
|
|
887
906
|
failInfrastructure(error: unknown, ctx: ExtensionContext, toolCallId?: string): never {
|
|
888
907
|
if (toolCallId !== undefined) {
|
|
889
|
-
|
|
908
|
+
pendingInfrastructureFailures.set(toolCallId, buildPendingInfrastructureFailure(error));
|
|
890
909
|
}
|
|
891
910
|
failInfrastructure(error, ctx);
|
|
892
911
|
},
|
|
@@ -1105,20 +1124,8 @@ export function createRoleRuntimeExtension(
|
|
|
1105
1124
|
observationFace.reset();
|
|
1106
1125
|
pendingNavigatorPresentation = undefined;
|
|
1107
1126
|
pendingNavigatorSettlement = undefined;
|
|
1108
|
-
|
|
1127
|
+
pendingInfrastructureFailures.clear();
|
|
1109
1128
|
pendingGatekeeperNonPassByToolCallId.clear();
|
|
1110
|
-
engineLaborFallbackLatch = createEngineLaborFallbackLatch();
|
|
1111
|
-
// #380 resume: restore sole-built fallback from durable same-session detour results.
|
|
1112
|
-
const sessionEntries =
|
|
1113
|
-
typeof ctx.sessionManager?.getEntries === "function"
|
|
1114
|
-
? ctx.sessionManager.getEntries()
|
|
1115
|
-
: [];
|
|
1116
|
-
restoreEngineLaborFallbackFromSessionEntries(
|
|
1117
|
-
engineLaborFallbackLatch,
|
|
1118
|
-
sessionEntries,
|
|
1119
|
-
ENGINE_DETOUR_TOOL_NAME,
|
|
1120
|
-
);
|
|
1121
|
-
installActivationEngineLaborFallbackLatch(engineLaborFallbackLatch);
|
|
1122
1129
|
engineDetourRegistration?.resetLatch();
|
|
1123
1130
|
navigatorWorkContext = undefined;
|
|
1124
1131
|
// #351: OAuth keepalive is orthogonal to --ak-role; start before role early-return
|
|
@@ -1234,7 +1241,6 @@ export function createRoleRuntimeExtension(
|
|
|
1234
1241
|
await executeActivationStage(entry.role, activationStage(entry.role, runtime), { clock, writeTrace });
|
|
1235
1242
|
// #357 T2 / #378 / #380 / #391: any role+engine activation registers the package detour tool once.
|
|
1236
1243
|
// Gate is env presence only — no per-engine execute branch; no role-module spawn.
|
|
1237
|
-
// Seat-fallback latch is activation-scoped (installed at session_start) so legs share it.
|
|
1238
1244
|
if (engineDetourRegistration === undefined) {
|
|
1239
1245
|
engineDetourRegistration = registerEngineDetourTool(pi, hostActions);
|
|
1240
1246
|
if (!engineDetourRegistration.registered) {
|
package/src/worker-role.ts
CHANGED
|
@@ -6,10 +6,6 @@ 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
|
-
readActivationEngineLaborFallbackField,
|
|
11
|
-
withEngineLaborFallbackField,
|
|
12
|
-
} from "./engine-labor-fallback.ts";
|
|
13
9
|
|
|
14
10
|
import type {
|
|
15
11
|
AnyCanonicalSkillBinding,
|
|
@@ -299,11 +295,7 @@ export function createFixerRoleRuntime(
|
|
|
299
295
|
toolCallId,
|
|
300
296
|
});
|
|
301
297
|
}
|
|
302
|
-
|
|
303
|
-
const acceptedDetails = withEngineLaborFallbackField(
|
|
304
|
-
output,
|
|
305
|
-
readActivationEngineLaborFallbackField(),
|
|
306
|
-
);
|
|
298
|
+
const acceptedDetails = output;
|
|
307
299
|
return {
|
|
308
300
|
content: [{ type: "text" as const, text: "Fixer report accepted" }],
|
|
309
301
|
details: acceptedDetails,
|
|
@@ -452,11 +444,7 @@ export function createCoderRoleRuntime(
|
|
|
452
444
|
toolCallId,
|
|
453
445
|
});
|
|
454
446
|
}
|
|
455
|
-
|
|
456
|
-
const acceptedDetails = withEngineLaborFallbackField(
|
|
457
|
-
output,
|
|
458
|
-
readActivationEngineLaborFallbackField(),
|
|
459
|
-
);
|
|
447
|
+
const acceptedDetails = output;
|
|
460
448
|
return {
|
|
461
449
|
content: [{ type: "text" as const, text: "Coder report accepted" }],
|
|
462
450
|
details: acceptedDetails,
|
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
let activationLatch;
|
|
2
|
-
function buildEngineLaborFallbackField(input) {
|
|
3
|
-
return Object.freeze({
|
|
4
|
-
engineLaborFallback: Object.freeze({
|
|
5
|
-
engine: input.engine,
|
|
6
|
-
failure: input.failure,
|
|
7
|
-
laborBy: "seat"
|
|
8
|
-
})
|
|
9
|
-
});
|
|
10
|
-
}
|
|
11
|
-
const SEAT_FALLBACK_STATUS_SUFFIX = "-by-fallback";
|
|
12
|
-
function isSeatFallbackTaintedStatus(status) {
|
|
13
|
-
return status.endsWith(SEAT_FALLBACK_STATUS_SUFFIX);
|
|
14
|
-
}
|
|
15
|
-
function seatFallbackBaseStatus(status) {
|
|
16
|
-
return isSeatFallbackTaintedStatus(status) ? status.slice(0, -SEAT_FALLBACK_STATUS_SUFFIX.length) : status;
|
|
17
|
-
}
|
|
18
|
-
function seatFallbackStatusHasLawfulEvidence(status, source) {
|
|
19
|
-
if (!isSeatFallbackTaintedStatus(status)) return true;
|
|
20
|
-
return readEngineLaborFallbackFieldFrom(source) !== void 0;
|
|
21
|
-
}
|
|
22
|
-
function taintStatusForSeatFallback(status) {
|
|
23
|
-
if (status.length === 0 || isSeatFallbackTaintedStatus(status)) return status;
|
|
24
|
-
return `${status}${SEAT_FALLBACK_STATUS_SUFFIX}`;
|
|
25
|
-
}
|
|
26
|
-
const STATUS_DISCRIMINATOR_KEYS = ["judgeStatus", "status"];
|
|
27
|
-
function taintReceiptStatusDiscriminators(receipt) {
|
|
28
|
-
let next;
|
|
29
|
-
for (const key of STATUS_DISCRIMINATOR_KEYS) {
|
|
30
|
-
if (!Object.prototype.hasOwnProperty.call(receipt, key)) continue;
|
|
31
|
-
let value;
|
|
32
|
-
try {
|
|
33
|
-
value = receipt[key];
|
|
34
|
-
} catch {
|
|
35
|
-
continue;
|
|
36
|
-
}
|
|
37
|
-
if (typeof value !== "string" || value.length === 0) continue;
|
|
38
|
-
const tainted = taintStatusForSeatFallback(value);
|
|
39
|
-
if (tainted === value) continue;
|
|
40
|
-
if (next === void 0) {
|
|
41
|
-
next = { ...receipt };
|
|
42
|
-
}
|
|
43
|
-
next[key] = tainted;
|
|
44
|
-
}
|
|
45
|
-
return next === void 0 ? receipt : next;
|
|
46
|
-
}
|
|
47
|
-
function createEngineLaborFallbackLatch() {
|
|
48
|
-
return { field: void 0 };
|
|
49
|
-
}
|
|
50
|
-
function recordEngineLaborFallback(latch, input) {
|
|
51
|
-
const field = buildEngineLaborFallbackField(input);
|
|
52
|
-
if (latch.field === void 0) latch.field = field;
|
|
53
|
-
return latch.field;
|
|
54
|
-
}
|
|
55
|
-
function readEngineLaborFallbackField(latch) {
|
|
56
|
-
return latch?.field;
|
|
57
|
-
}
|
|
58
|
-
function withEngineLaborFallbackField(receipt, field) {
|
|
59
|
-
if (field !== void 0) {
|
|
60
|
-
const taintedReceipt = taintReceiptStatusDiscriminators(receipt);
|
|
61
|
-
return { ...taintedReceipt, ...field };
|
|
62
|
-
}
|
|
63
|
-
if (!Object.prototype.hasOwnProperty.call(receipt, "engineLaborFallback")) {
|
|
64
|
-
return receipt;
|
|
65
|
-
}
|
|
66
|
-
const { engineLaborFallback: _forged, ...rest } = receipt;
|
|
67
|
-
return rest;
|
|
68
|
-
}
|
|
69
|
-
function installActivationEngineLaborFallbackLatch(latch) {
|
|
70
|
-
activationLatch = latch;
|
|
71
|
-
}
|
|
72
|
-
function clearActivationEngineLaborFallbackLatch() {
|
|
73
|
-
activationLatch = void 0;
|
|
74
|
-
}
|
|
75
|
-
function activationEngineLaborFallbackLatch() {
|
|
76
|
-
return activationLatch;
|
|
77
|
-
}
|
|
78
|
-
function readActivationEngineLaborFallbackField() {
|
|
79
|
-
return readEngineLaborFallbackField(activationLatch);
|
|
80
|
-
}
|
|
81
|
-
function readEngineLaborFallbackFieldFrom(source) {
|
|
82
|
-
if (typeof source !== "object" || source === null || Array.isArray(source)) {
|
|
83
|
-
return void 0;
|
|
84
|
-
}
|
|
85
|
-
let raw;
|
|
86
|
-
try {
|
|
87
|
-
raw = source.engineLaborFallback;
|
|
88
|
-
} catch {
|
|
89
|
-
return void 0;
|
|
90
|
-
}
|
|
91
|
-
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) return void 0;
|
|
92
|
-
const rec = raw;
|
|
93
|
-
if (typeof rec.engine !== "string" || typeof rec.failure !== "string" || rec.laborBy !== "seat") {
|
|
94
|
-
return void 0;
|
|
95
|
-
}
|
|
96
|
-
return buildEngineLaborFallbackField({
|
|
97
|
-
engine: rec.engine,
|
|
98
|
-
failure: rec.failure
|
|
99
|
-
});
|
|
100
|
-
}
|
|
101
|
-
function restoreEngineLaborFallbackFromSessionEntries(latch, entries, toolName) {
|
|
102
|
-
for (const entry of entries) {
|
|
103
|
-
if (typeof entry !== "object" || entry === null) continue;
|
|
104
|
-
const row = entry;
|
|
105
|
-
if (row.type !== "message") continue;
|
|
106
|
-
const message = row.message;
|
|
107
|
-
if (typeof message !== "object" || message === null) continue;
|
|
108
|
-
const msg = message;
|
|
109
|
-
if (msg.role !== "toolResult") continue;
|
|
110
|
-
if (msg.toolName !== toolName) continue;
|
|
111
|
-
const field = readEngineLaborFallbackFieldFrom(msg.details);
|
|
112
|
-
if (field === void 0) continue;
|
|
113
|
-
recordEngineLaborFallback(latch, {
|
|
114
|
-
engine: field.engineLaborFallback.engine,
|
|
115
|
-
failure: field.engineLaborFallback.failure
|
|
116
|
-
});
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
export {
|
|
120
|
-
SEAT_FALLBACK_STATUS_SUFFIX,
|
|
121
|
-
activationEngineLaborFallbackLatch,
|
|
122
|
-
buildEngineLaborFallbackField,
|
|
123
|
-
clearActivationEngineLaborFallbackLatch,
|
|
124
|
-
createEngineLaborFallbackLatch,
|
|
125
|
-
installActivationEngineLaborFallbackLatch,
|
|
126
|
-
isSeatFallbackTaintedStatus,
|
|
127
|
-
readActivationEngineLaborFallbackField,
|
|
128
|
-
readEngineLaborFallbackField,
|
|
129
|
-
readEngineLaborFallbackFieldFrom,
|
|
130
|
-
recordEngineLaborFallback,
|
|
131
|
-
restoreEngineLaborFallbackFromSessionEntries,
|
|
132
|
-
seatFallbackBaseStatus,
|
|
133
|
-
seatFallbackStatusHasLawfulEvidence,
|
|
134
|
-
taintStatusForSeatFallback,
|
|
135
|
-
withEngineLaborFallbackField
|
|
136
|
-
};
|