@akagilnc/pi-workflow-roles 0.1.2135 → 0.1.2146
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/compliance-transport.js +19 -24
- package/dist/doctor-contracts.js +10 -2
- package/dist/engine-detour-tool.js +5 -15
- package/dist/engine-detour.js +3 -11
- package/dist/engine-labor-fallback.js +129 -114
- package/dist/evidence-child-executor.js +3 -4
- package/dist/merger-contracts.js +9 -2
- package/dist/navigator-attendance.js +11 -4
- package/dist/package-contracts/judge-output.js +8 -1
- package/dist/package-contracts/reviewer-output.js +9 -1
- package/dist/package-contracts/terminating-tools.js +14 -5
- package/dist/public-cli/main.js +123 -125
- package/package.json +1 -1
- package/resources/engines/codex.md +3 -4
- package/resources/engines/grok-4.6.md +5 -6
- package/resources/engines/kimi.md +2 -2
- package/resources/engines/opus.md +2 -2
- package/scripts/build-package.mjs +2 -0
- package/src/collector-role.ts +5 -33
- package/src/compliance-transport.ts +19 -24
- package/src/doctor-contracts.ts +19 -3
- package/src/engine-detour-tool.ts +6 -21
- package/src/engine-detour.ts +3 -15
- package/src/engine-labor-fallback.ts +100 -2
- package/src/evidence-child-executor.ts +3 -4
- package/src/factory-board.ts +6 -2
- package/src/merger-contracts.ts +18 -3
- package/src/navigator-attendance.ts +18 -4
- package/src/package-contracts/judge-output.ts +25 -2
- package/src/package-contracts/reviewer-output.ts +23 -2
- package/src/package-contracts/terminating-tools.ts +22 -6
- package/src/package-contracts/worker-output.ts +10 -2
- package/src/public-cli/settlement.ts +51 -17
- package/src/role-runtime.ts +8 -4
- package/src/taishi-metric-families/acceptance-success-rework.ts +6 -3
- package/dist/package-owned-tool-idle.js +0 -223
- package/src/package-owned-tool-idle.ts +0 -257
package/README.md
CHANGED
|
@@ -40,7 +40,7 @@ ak-role config unset-engine judge
|
|
|
40
40
|
|
|
41
41
|
Receipts are typed, so callers compose roles without parsing prose; ordering and stopping stay caller-owned. Programmatic consumers derive contracts from the exported schemas in `src/package-contracts/`, not from this guide.
|
|
42
42
|
|
|
43
|
-
When a labor-engine detour fails and the seat continues the labor on the main road, the typed receipt may carry a mechanical `engineLaborFallback` field: `{ engine, failure, laborBy: "seat" }`. It appears only after a real detour failure that fell back to seat labor
|
|
43
|
+
When a labor-engine detour fails and the seat continues the labor on the main road, the typed receipt may carry a mechanical `engineLaborFallback` field: `{ engine, failure, laborBy: "seat" }`. It appears only after a real detour failure that fell back to seat labor—not on detour success or caller cancel. First failure wins for the activation; model-forged `engineLaborFallback` keys are stripped unless the package latch recorded one. Sole producer: `src/engine-labor-fallback.ts`; decision record: [ADR 0071](docs/adr/0071-engine-detour-failure-seat-fallback-declaration.md). This README only projects that contract.
|
|
44
44
|
|
|
45
45
|
## Call the roles
|
|
46
46
|
|
package/README.zh-CN.md
CHANGED
|
@@ -40,7 +40,7 @@ ak-role config unset-engine judge
|
|
|
40
40
|
|
|
41
41
|
回执是 typed 的,调用者不必解析散文即可组合角色;顺序与停止归调用者。编程消费者从 `src/package-contracts/` 导出推导契约,不从本文。
|
|
42
42
|
|
|
43
|
-
当劳务引擎绕行失败、座席回到主路继续劳务时,typed 回执可带机械字段 `engineLaborFallback`:`{ engine, failure, laborBy: "seat" }
|
|
43
|
+
当劳务引擎绕行失败、座席回到主路继续劳务时,typed 回执可带机械字段 `engineLaborFallback`:`{ engine, failure, laborBy: "seat" }`。仅在真实绕行失败并座席顶班后出现——成功绕行或调用方 cancel 不出现。同一次 activation 内先到先得;无包内 latch 时剥离模型伪造的 `engineLaborFallback` 键。唯一构造点:`src/engine-labor-fallback.ts`;决策记录:[ADR 0071](docs/adr/0071-engine-detour-failure-seat-fallback-declaration.md)。本文只投影该契约。
|
|
44
44
|
|
|
45
45
|
## 调用百官
|
|
46
46
|
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { Type } from "typebox";
|
|
2
2
|
import { executeAuditorChild, } from "./evidence-child-executor.js";
|
|
3
3
|
import { createAuditorDossierTool } from "./auditor-dossier-tool.js";
|
|
4
|
-
import { withPackageOwnedToolIdleSuspended } from "./package-owned-tool-idle.js";
|
|
5
4
|
/** Zero-projection kickoff — soul already carries dossier-fetch duty; no hand-delivered materials. */
|
|
6
5
|
export const AUDITOR_DOSSIER_PROMPT = "Audit the current run dossier.";
|
|
7
6
|
const nonblank = Type.String({ minLength: 1, pattern: "\\S" });
|
|
@@ -62,28 +61,24 @@ export function readComplianceCandidate(arguments_, usage) {
|
|
|
62
61
|
return { status: "audit-incomplete", observation: { kind: "object-status-unreadable", status: status === undefined ? "missing" : "unknown" }, candidate: arguments_, ...(usage === undefined ? {} : { usage }) };
|
|
63
62
|
}
|
|
64
63
|
export async function runComplianceAudit(options) {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
retainResponse: (response) => retainComplianceResponse(options.context, response),
|
|
77
|
-
...(options.runCompletion === undefined ? {} : { runCompletion: options.runCompletion }),
|
|
78
|
-
...(options.signal === undefined ? {} : { signal: options.signal }),
|
|
79
|
-
});
|
|
80
|
-
if (receipt.noReceiptLifecycle !== undefined) {
|
|
81
|
-
return {
|
|
82
|
-
status: "no-receipt",
|
|
83
|
-
...receipt.noReceiptLifecycle,
|
|
84
|
-
...(receipt.response.usage === undefined ? {} : { usage: receipt.response.usage }),
|
|
85
|
-
};
|
|
86
|
-
}
|
|
87
|
-
return readComplianceCandidate(receipt.decision, receipt.response.usage);
|
|
64
|
+
const prompt = options.serializedInput ?? AUDITOR_DOSSIER_PROMPT;
|
|
65
|
+
const receipt = await executeAuditorChild({
|
|
66
|
+
tool: options.tool,
|
|
67
|
+
dossierTool: createAuditorDossierTool(options.runDirectory),
|
|
68
|
+
systemPrompt: options.systemPrompt,
|
|
69
|
+
prompt,
|
|
70
|
+
roleLabel: options.roleLabel,
|
|
71
|
+
context: options.context,
|
|
72
|
+
retainResponse: (response) => retainComplianceResponse(options.context, response),
|
|
73
|
+
...(options.runCompletion === undefined ? {} : { runCompletion: options.runCompletion }),
|
|
74
|
+
...(options.signal === undefined ? {} : { signal: options.signal }),
|
|
88
75
|
});
|
|
76
|
+
if (receipt.noReceiptLifecycle !== undefined) {
|
|
77
|
+
return {
|
|
78
|
+
status: "no-receipt",
|
|
79
|
+
...receipt.noReceiptLifecycle,
|
|
80
|
+
...(receipt.response.usage === undefined ? {} : { usage: receipt.response.usage }),
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
return readComplianceCandidate(receipt.decision, receipt.response.usage);
|
|
89
84
|
}
|
package/dist/doctor-contracts.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Type } from "typebox";
|
|
2
2
|
import { canonicalJson } from "./canonical-json.js";
|
|
3
|
+
import { seatFallbackBaseStatus, seatFallbackStatusHasLawfulEvidence, } from "./engine-labor-fallback.js";
|
|
3
4
|
import { openToolObjectFromUnion } from "./open-tool-schema.js";
|
|
4
5
|
export const DOCTOR_EVIDENCE_TOOL_NAME = "ak_doctor_evidence";
|
|
5
6
|
export const DOCTOR_OUTPUT_TOOL_NAME = "ak_doctor_output";
|
|
@@ -66,13 +67,20 @@ catch {
|
|
|
66
67
|
} }
|
|
67
68
|
export function validateDoctorSubmissionShape(value) {
|
|
68
69
|
const status = read(value, "status");
|
|
69
|
-
|
|
70
|
+
const base = typeof status === "string" ? seatFallbackBaseStatus(status) : status;
|
|
71
|
+
if (base !== "completed" && base !== "refused")
|
|
70
72
|
throw new DoctorSubmissionContractError("Doctor submission has no recognized execution status");
|
|
73
|
+
// ADR 0071: tainted status requires latch-shaped engineLaborFallback evidence.
|
|
74
|
+
if (typeof status === "string" && !seatFallbackStatusHasLawfulEvidence(status, value)) {
|
|
75
|
+
throw new DoctorSubmissionContractError("Doctor submission has no recognized execution status");
|
|
76
|
+
}
|
|
71
77
|
return value;
|
|
72
78
|
}
|
|
73
79
|
export function validateRecordedDoctorOutput(value) {
|
|
74
80
|
const output = validateDoctorSubmissionShape(value);
|
|
75
|
-
|
|
81
|
+
const status = read(output, "status");
|
|
82
|
+
const base = typeof status === "string" ? seatFallbackBaseStatus(status) : status;
|
|
83
|
+
if (base === "completed" && read(output, "cost") === undefined)
|
|
76
84
|
throw new Error("Completed Doctor receipt has no runtime-owned cost testimony");
|
|
77
85
|
return output;
|
|
78
86
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { Type } from "typebox";
|
|
2
2
|
import { ENGINE_DETOUR_ALREADY_USED_DIAGNOSTIC, ENGINE_DETOUR_TOOL_NAME, engineDetourFailureDiagnostic, engineNameFromEnv, isEngineDetourFailure, runEngineDetourOnce, } from "./engine-detour.js";
|
|
3
3
|
import { activationEngineLaborFallbackLatch, recordEngineLaborFallback, } from "./engine-labor-fallback.js";
|
|
4
|
-
import { isPackageOwnedToolIdleTimeoutError, pokePackageOwnedToolIdle, wrapPackageOwnedToolDefinition, } from "./package-owned-tool-idle.js";
|
|
5
4
|
const engineDetourArgsSchema = Type.Object({
|
|
6
5
|
argv: Type.Array(Type.String({ minLength: 1 }), {
|
|
7
6
|
minItems: 1,
|
|
@@ -23,14 +22,8 @@ function seatFallbackToolResult(field, failure) {
|
|
|
23
22
|
},
|
|
24
23
|
};
|
|
25
24
|
}
|
|
26
|
-
/** Caller/upper-layer cancel must propagate;
|
|
25
|
+
/** Caller/upper-layer cancel must propagate; process failure is seat-fallback, not cancel. */
|
|
27
26
|
function isCallerCancellation(error, signal) {
|
|
28
|
-
if (isPackageOwnedToolIdleTimeoutError(error))
|
|
29
|
-
return false;
|
|
30
|
-
if (signal !== undefined &&
|
|
31
|
-
isPackageOwnedToolIdleTimeoutError(signal.reason)) {
|
|
32
|
-
return false;
|
|
33
|
-
}
|
|
34
27
|
if (signal?.aborted === true)
|
|
35
28
|
return true;
|
|
36
29
|
if (typeof error === "object" &&
|
|
@@ -44,13 +37,13 @@ function isCallerCancellation(error, signal) {
|
|
|
44
37
|
* Build one once-latch detour tool definition for a configured engine name.
|
|
45
38
|
* `latch` is shared so parent registration can reset between activations.
|
|
46
39
|
* `fail` owns host abort (parent) vs throw (evidence child) for tool misuse only.
|
|
47
|
-
* Engine process failure (nonzero/empty/spawn
|
|
40
|
+
* Engine process failure (nonzero/empty/spawn) soft-returns seat fallback (#380).
|
|
48
41
|
* Caller AbortSignal cancel propagates without writing fallback.
|
|
49
42
|
*/
|
|
50
43
|
export function createEngineDetourToolDefinition(input) {
|
|
51
44
|
const latch = input.latch ?? { used: false };
|
|
52
45
|
const engineName = input.engineName;
|
|
53
|
-
return
|
|
46
|
+
return {
|
|
54
47
|
name: ENGINE_DETOUR_TOOL_NAME,
|
|
55
48
|
label: "Engine Detour",
|
|
56
49
|
description: `Run one labor-engine subprocess (engine=${engineName}) and return its stdout to this session. Call at most once per activation. Build argv from the host CLI actual interface for this engine name; when optional packaged notes are present in the session prompt, follow those bytes too.`,
|
|
@@ -83,17 +76,14 @@ export function createEngineDetourToolDefinition(input) {
|
|
|
83
76
|
};
|
|
84
77
|
let result;
|
|
85
78
|
try {
|
|
86
|
-
// Byte activity on stdout/stderr touches the outer package-owned idle clock
|
|
87
|
-
// (183s silence law unchanged). True hangs still die; slow streaming engines live.
|
|
88
79
|
result = await runEngineDetourOnce({
|
|
89
80
|
argv,
|
|
90
81
|
cwd: ctx.cwd,
|
|
91
82
|
...(signal === undefined ? {} : { signal }),
|
|
92
|
-
onOutputActivity: pokePackageOwnedToolIdle,
|
|
93
83
|
});
|
|
94
84
|
}
|
|
95
85
|
catch (error) {
|
|
96
|
-
// Caller cancel: propagate.
|
|
86
|
+
// Caller cancel: propagate. Spawn/engine failure: seat fallback.
|
|
97
87
|
if (isCallerCancellation(error, signal)) {
|
|
98
88
|
throw error;
|
|
99
89
|
}
|
|
@@ -111,7 +101,7 @@ export function createEngineDetourToolDefinition(input) {
|
|
|
111
101
|
},
|
|
112
102
|
};
|
|
113
103
|
},
|
|
114
|
-
}
|
|
104
|
+
};
|
|
115
105
|
}
|
|
116
106
|
/**
|
|
117
107
|
* Register the engine-generic detour tool once for this process when any role has
|
package/dist/engine-detour.js
CHANGED
|
@@ -48,8 +48,8 @@ export async function runEngineDetourOnce(input) {
|
|
|
48
48
|
return await new Promise((resolve, reject) => {
|
|
49
49
|
let settled = false;
|
|
50
50
|
const signal = input.signal;
|
|
51
|
-
// Own abort→kill explicitly so rejection preserves signal.reason (caller cancel
|
|
52
|
-
//
|
|
51
|
+
// Own abort→kill explicitly so rejection preserves signal.reason (caller cancel).
|
|
52
|
+
// Do not pass `signal` to spawn (Node replaces reason).
|
|
53
53
|
const child = spawn(command, args, {
|
|
54
54
|
cwd: input.cwd,
|
|
55
55
|
env: input.env ?? process.env,
|
|
@@ -57,18 +57,11 @@ export async function runEngineDetourOnce(input) {
|
|
|
57
57
|
});
|
|
58
58
|
let stdout = "";
|
|
59
59
|
let stderr = "";
|
|
60
|
-
const noteActivity = (chunk) => {
|
|
61
|
-
if (chunk.length === 0)
|
|
62
|
-
return;
|
|
63
|
-
input.onOutputActivity?.();
|
|
64
|
-
};
|
|
65
60
|
child.stdout.setEncoding("utf8").on("data", (chunk) => {
|
|
66
61
|
stdout += chunk;
|
|
67
|
-
noteActivity(chunk);
|
|
68
62
|
});
|
|
69
63
|
child.stderr.setEncoding("utf8").on("data", (chunk) => {
|
|
70
64
|
stderr += chunk;
|
|
71
|
-
noteActivity(chunk);
|
|
72
65
|
});
|
|
73
66
|
const fail = (error) => {
|
|
74
67
|
if (settled)
|
|
@@ -89,8 +82,7 @@ export async function runEngineDetourOnce(input) {
|
|
|
89
82
|
resolve(result);
|
|
90
83
|
};
|
|
91
84
|
const onAbort = () => {
|
|
92
|
-
// Fail synchronously so
|
|
93
|
-
// before the outer package-owned idle hard-reject drain.
|
|
85
|
+
// Fail synchronously so caller-cancel soft-settle preserves signal.reason.
|
|
94
86
|
fail(signal !== undefined ? abortReasonError(signal) : new Error("aborted"));
|
|
95
87
|
try {
|
|
96
88
|
child.kill("SIGTERM");
|
|
@@ -1,121 +1,136 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* #380 — sole shared seat-fallback declaration after engine detour failure.
|
|
3
|
-
* Detour rejoins the main road (ADR 0069); silence is the only crime.
|
|
4
|
-
* Construction of the typed receipt field lives in exactly one site (S1).
|
|
5
|
-
*/
|
|
6
|
-
/** Activation-scoped latch holder (one parent seat activation at a time). */
|
|
7
1
|
let activationLatch;
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
});
|
|
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
|
+
});
|
|
17
10
|
}
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
export function withEngineLaborFallbackField(receipt, field) {
|
|
40
|
-
if (field !== undefined) {
|
|
41
|
-
return { ...receipt, ...field };
|
|
42
|
-
}
|
|
43
|
-
if (!Object.prototype.hasOwnProperty.call(receipt, "engineLaborFallback")) {
|
|
44
|
-
return receipt;
|
|
45
|
-
}
|
|
46
|
-
const { engineLaborFallback: _forged, ...rest } = receipt;
|
|
47
|
-
return rest;
|
|
48
|
-
}
|
|
49
|
-
/** Install the activation-scoped latch (any role session_start with engine). */
|
|
50
|
-
export function installActivationEngineLaborFallbackLatch(latch) {
|
|
51
|
-
activationLatch = latch;
|
|
52
|
-
}
|
|
53
|
-
/** Clear activation latch (session end / next activation). */
|
|
54
|
-
export function clearActivationEngineLaborFallbackLatch() {
|
|
55
|
-
activationLatch = undefined;
|
|
56
|
-
}
|
|
57
|
-
/** Active activation latch, if any (legs inherit parent seat activation). */
|
|
58
|
-
export function activationEngineLaborFallbackLatch() {
|
|
59
|
-
return activationLatch;
|
|
60
|
-
}
|
|
61
|
-
/** Read fallback field from the active activation latch. */
|
|
62
|
-
export function readActivationEngineLaborFallbackField() {
|
|
63
|
-
return readEngineLaborFallbackField(activationLatch);
|
|
64
|
-
}
|
|
65
|
-
/**
|
|
66
|
-
* Read a previously attached declaration from a typed receipt / details object.
|
|
67
|
-
* Rebuilds via the sole construction site — callers must spread, never re-key.
|
|
68
|
-
*/
|
|
69
|
-
export function readEngineLaborFallbackFieldFrom(source) {
|
|
70
|
-
if (typeof source !== "object" || source === null || Array.isArray(source)) {
|
|
71
|
-
return undefined;
|
|
72
|
-
}
|
|
73
|
-
let raw;
|
|
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;
|
|
74
32
|
try {
|
|
75
|
-
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
return undefined;
|
|
33
|
+
value = receipt[key];
|
|
34
|
+
} catch {
|
|
35
|
+
continue;
|
|
79
36
|
}
|
|
80
|
-
if (typeof
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
if (
|
|
84
|
-
|
|
85
|
-
rec.laborBy !== "seat") {
|
|
86
|
-
return undefined;
|
|
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 };
|
|
87
42
|
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
});
|
|
43
|
+
next[key] = tainted;
|
|
44
|
+
}
|
|
45
|
+
return next === void 0 ? receipt : next;
|
|
92
46
|
}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
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
|
+
}
|
|
121
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
|
+
};
|
|
@@ -11,7 +11,6 @@ import { AUDITOR_COMPLIANCE_FAILURE_ENTRY_TYPE, AUDITOR_PARENT_ATTEMPT_BINDING_E
|
|
|
11
11
|
import { createEngineDetourToolDefinition } from "./engine-detour-tool.js";
|
|
12
12
|
import { engineNameFromEnv } from "./engine-detour.js";
|
|
13
13
|
import { appendEngineSessionMaterial, engineSessionMaterialFromOptions, } from "./package-resources/engine-material.js";
|
|
14
|
-
import { wrapPackageOwnedToolDefinition } from "./package-owned-tool-idle.js";
|
|
15
14
|
import { createReceiptDeliveryPolicy, NO_RECEIPT_LIFECYCLE_ENTRY_TYPE, RECEIPT_DELIVERY_PROMPT } from "./receipt-delivery-policy.js";
|
|
16
15
|
import { REVIEWER_VERIFICATION_BOUNDARY } from "./reviewer-construction.js";
|
|
17
16
|
import { createStreamIdleGuard, isStreamIdleTimeoutError } from "./stream-idle-guard.js";
|
|
@@ -599,7 +598,7 @@ export async function executeAuditorChild(options) {
|
|
|
599
598
|
let decisionToolFailure;
|
|
600
599
|
const decisionToolFailures = new Map();
|
|
601
600
|
const delivery = createReceiptDeliveryPolicy();
|
|
602
|
-
const tool =
|
|
601
|
+
const tool = {
|
|
603
602
|
...options.tool,
|
|
604
603
|
label: options.roleLabel,
|
|
605
604
|
async execute(...args) {
|
|
@@ -625,7 +624,7 @@ export async function executeAuditorChild(options) {
|
|
|
625
624
|
throw error;
|
|
626
625
|
}
|
|
627
626
|
},
|
|
628
|
-
}
|
|
627
|
+
};
|
|
629
628
|
const parentSessionManager = options.context.sessionManager;
|
|
630
629
|
const parentHeader = parentSessionManager?.getHeader?.();
|
|
631
630
|
const parentSessionFile = parentSessionManager?.getSessionFile?.();
|
|
@@ -644,7 +643,7 @@ export async function executeAuditorChild(options) {
|
|
|
644
643
|
thinkingLevel: options.context.thinkingLevel ?? "off",
|
|
645
644
|
modelRuntime: inherited.runtime,
|
|
646
645
|
systemPrompt: options.systemPrompt,
|
|
647
|
-
customTools: [
|
|
646
|
+
customTools: [{ ...options.dossierTool, label: options.roleLabel }, tool],
|
|
648
647
|
sessionManager: auditorSessionManager,
|
|
649
648
|
});
|
|
650
649
|
const binding = {
|
package/dist/merger-contracts.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Type } from "typebox";
|
|
2
2
|
import { isFullGitObjectId } from "./git-object-id.js";
|
|
3
3
|
import { exactUtf8 } from "./exact-utf8.js";
|
|
4
|
+
import { seatFallbackBaseStatus, seatFallbackStatusHasLawfulEvidence, } from "./engine-labor-fallback.js";
|
|
4
5
|
import { sha256Hex } from "./sha256.js";
|
|
5
6
|
import { openToolObjectFromUnion } from "./open-tool-schema.js";
|
|
6
7
|
const oidPattern = "^(?:[0-9a-f]{40}|[0-9a-f]{64})$";
|
|
@@ -68,9 +69,15 @@ export function validateMergerInput(value) {
|
|
|
68
69
|
export function validateMergerOutput(value, expectedAttemptId) {
|
|
69
70
|
if (!record(value) || (expectedAttemptId !== undefined && value.attemptId !== expectedAttemptId))
|
|
70
71
|
throw new Error("Merger output attempt mismatch");
|
|
71
|
-
|
|
72
|
+
const status = typeof value.status === "string" ? value.status : undefined;
|
|
73
|
+
const statusBase = status !== undefined ? seatFallbackBaseStatus(status) : undefined;
|
|
74
|
+
// ADR 0071: tainted status requires latch-shaped engineLaborFallback evidence.
|
|
75
|
+
if (status !== undefined && !seatFallbackStatusHasLawfulEvidence(status, value)) {
|
|
76
|
+
throw new Error("Merger output has no recognized execution discriminator");
|
|
77
|
+
}
|
|
78
|
+
if (statusBase === "completed" && isFullGitObjectId(value.mergeCommitId))
|
|
72
79
|
return structuredClone(value);
|
|
73
|
-
if (
|
|
80
|
+
if (statusBase === "escalate")
|
|
74
81
|
return structuredClone(value);
|
|
75
82
|
throw new Error("Merger output has no recognized execution discriminator");
|
|
76
83
|
}
|
|
@@ -6,6 +6,7 @@ import { ModelRuntime } from "@earendil-works/pi-coding-agent";
|
|
|
6
6
|
import { createAssistantMessageEventStream } from "@earendil-works/pi-ai";
|
|
7
7
|
import { Type } from "typebox";
|
|
8
8
|
import { Value } from "typebox/value";
|
|
9
|
+
import { seatFallbackBaseStatus } from "./engine-labor-fallback.js";
|
|
9
10
|
import {
|
|
10
11
|
NAVIGATOR_INVOCATION_ENTRY,
|
|
11
12
|
mintNavigatorInvocationId
|
|
@@ -14,7 +15,6 @@ import { PACKAGED_ROLE_REGISTRY, packagedRoleMetadata } from "./packaged-role-re
|
|
|
14
15
|
import { openInProcessAgentSession } from "./in-process-session.js";
|
|
15
16
|
import { renderPublicAkRoleCommand } from "./public-command-renderer.js";
|
|
16
17
|
import { issueRoot, subjectPath } from "./work-subject-identity.js";
|
|
17
|
-
import { wrapPackageOwnedToolDefinition } from "./package-owned-tool-idle.js";
|
|
18
18
|
import { createReceiptDeliveryPolicy, NO_RECEIPT_LIFECYCLE_ENTRY_TYPE, RECEIPT_DELIVERY_PROMPT } from "./receipt-delivery-policy.js";
|
|
19
19
|
import { recordTypedProviderHttpStatus } from "./typed-provider-http.js";
|
|
20
20
|
import {
|
|
@@ -247,7 +247,7 @@ function parseNavigatorModelSetting(value) {
|
|
|
247
247
|
return { provider, model, thinkingLevel: suffix === "max" ? "max" : "off" };
|
|
248
248
|
}
|
|
249
249
|
function createNavigatorPrepareTool(onOutput) {
|
|
250
|
-
return
|
|
250
|
+
return {
|
|
251
251
|
name: NAVIGATOR_PREPARE_TOOL_NAME,
|
|
252
252
|
label: "Navigator preparation",
|
|
253
253
|
description: "Submit Navigator direction advice. Provide candidates with next.role (phase when meaningful). route/matches/reason/command are optional context, not acceptance gates.",
|
|
@@ -256,7 +256,14 @@ function createNavigatorPrepareTool(onOutput) {
|
|
|
256
256
|
onOutput(value);
|
|
257
257
|
return { content: [{ type: "text", text: "Navigator preparation accepted" }], details: value, terminate: true };
|
|
258
258
|
}
|
|
259
|
-
}
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
function statusListMatchesSettlement(candidateStatuses, settlementStatus) {
|
|
262
|
+
if (candidateStatuses.includes(settlementStatus)) return true;
|
|
263
|
+
const settlementBase = seatFallbackBaseStatus(settlementStatus);
|
|
264
|
+
return candidateStatuses.some(
|
|
265
|
+
(status) => seatFallbackBaseStatus(status) === settlementBase
|
|
266
|
+
);
|
|
260
267
|
}
|
|
261
268
|
function selectNavigatorCandidate(candidates, settlement) {
|
|
262
269
|
if (settlement.kind !== "accepted") return void 0;
|
|
@@ -268,7 +275,7 @@ function selectNavigatorCandidate(candidates, settlement) {
|
|
|
268
275
|
if (rolePhaseMatched.length > 0) {
|
|
269
276
|
if (settlement.status !== void 0) {
|
|
270
277
|
const statusSpecific = rolePhaseMatched.find(
|
|
271
|
-
(candidate) => candidate.matches?.statuses
|
|
278
|
+
(candidate) => candidate.matches?.statuses !== void 0 && statusListMatchesSettlement(candidate.matches.statuses, settlement.status)
|
|
272
279
|
);
|
|
273
280
|
if (statusSpecific !== void 0) {
|
|
274
281
|
return { candidate: statusSpecific, matchedToSettlement: true };
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
/** Package-owned Judge output leaf — no role registration surface. */
|
|
2
|
+
import { seatFallbackBaseStatus, seatFallbackStatusHasLawfulEvidence, } from "../engine-labor-fallback.js";
|
|
2
3
|
export const JUDGE_OUTPUT_TOOL_NAME = "ak_judge_output";
|
|
3
4
|
export const JUDGE_ACCEPTED_TEXT = "Judge verdict accepted";
|
|
4
5
|
export function validateAcceptedJudgeDetails(verdict) {
|
|
@@ -11,7 +12,13 @@ export function validateAcceptedJudgeDetails(verdict) {
|
|
|
11
12
|
catch {
|
|
12
13
|
throw new Error("Judge verdict has no execution discriminator");
|
|
13
14
|
}
|
|
14
|
-
if (
|
|
15
|
+
if (typeof judgeStatus !== "string") {
|
|
16
|
+
throw new Error("Judge verdict has no execution discriminator");
|
|
17
|
+
}
|
|
18
|
+
const base = seatFallbackBaseStatus(judgeStatus);
|
|
19
|
+
if (["converged", "continue", "escalate"].includes(base) &&
|
|
20
|
+
seatFallbackStatusHasLawfulEvidence(judgeStatus, verdict)) {
|
|
15
21
|
return verdict;
|
|
22
|
+
}
|
|
16
23
|
throw new Error("Judge verdict has no execution discriminator");
|
|
17
24
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
/** Package-owned Reviewer intent and runtime-receipt leaves — no role registration surface. */
|
|
2
|
+
import { seatFallbackBaseStatus, seatFallbackStatusHasLawfulEvidence, } from "../engine-labor-fallback.js";
|
|
2
3
|
export const REVIEWER_OUTPUT_TOOL_NAME = "ak_reviewer_output";
|
|
3
4
|
export const REVIEWER_ACCEPTED_TEXT = "Reviewer report accepted";
|
|
4
5
|
function isRecord(value) {
|
|
@@ -24,6 +25,11 @@ export function validateReviewerIntent(output) {
|
|
|
24
25
|
}
|
|
25
26
|
/** Validate runtime-owned facts at their real identity seams (target pins + plain text). */
|
|
26
27
|
export function validateRuntimeReviewerReceipt(output) {
|
|
28
|
+
const status = read(output, "status");
|
|
29
|
+
// ADR 0071: tainted top-level status requires latch-shaped engineLaborFallback evidence.
|
|
30
|
+
if (typeof status === "string" && !seatFallbackStatusHasLawfulEvidence(status, output)) {
|
|
31
|
+
throw new Error("Reviewer receipt has no recognized execution discriminator");
|
|
32
|
+
}
|
|
27
33
|
const acceptedBatch = read(output, "acceptedBatch");
|
|
28
34
|
const identities = read(output, "identities");
|
|
29
35
|
const construction = read(identities, "construction");
|
|
@@ -91,7 +97,9 @@ export function validateRuntimeReviewerReceipt(output) {
|
|
|
91
97
|
export function projectReviewerIntentToReceipt(intentValue, receiptValue) {
|
|
92
98
|
const intent = validateReviewerIntent(intentValue);
|
|
93
99
|
const receipt = validateRuntimeReviewerReceipt(receiptValue);
|
|
94
|
-
|
|
100
|
+
const receiptStatus = String(receipt.status);
|
|
101
|
+
const receiptBase = seatFallbackBaseStatus(receiptStatus);
|
|
102
|
+
if (receiptBase !== intent.status || (intent.status === "completed" ? receipt.diagnostic !== undefined : receipt.diagnostic !== intent.diagnostic)) {
|
|
95
103
|
throw new Error("Reviewer intent and runtime receipt disagree");
|
|
96
104
|
}
|
|
97
105
|
return receipt;
|