@akagilnc/pi-workflow-roles 0.1.2369 → 0.1.2379
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/public-cli/main.js +690 -590
- package/package.json +1 -1
- package/resources/engines/agy.md +10 -2
- package/src/analyst-gate-cycles-read.ts +45 -5
- package/src/public-cli/settlement.ts +191 -71
- package/src/public-cli/terminal.ts +57 -0
package/package.json
CHANGED
package/resources/engines/agy.md
CHANGED
|
@@ -15,7 +15,7 @@ sandboxed print mode with the prompt as the positional/print argument and a
|
|
|
15
15
|
log file for diagnostics:
|
|
16
16
|
|
|
17
17
|
```bash
|
|
18
|
-
agy --sandbox --dangerously-skip-permissions --print 'YOUR_LABOR_PROMPT' --log-file /tmp/agy-labor.log
|
|
18
|
+
agy --sandbox --dangerously-skip-permissions --print-timeout 30m --print 'YOUR_LABOR_PROMPT' --log-file /tmp/agy-labor.log
|
|
19
19
|
```
|
|
20
20
|
|
|
21
21
|
`--dangerously-skip-permissions` is required in headless labor: the CLI's
|
|
@@ -31,9 +31,17 @@ this host (2026-08-26): `gemini-3.7-flash-high`, `gemini-3.7-flash-medium`,
|
|
|
31
31
|
`gemini-3.7-flash-low`, and 3.6 equivalents.
|
|
32
32
|
|
|
33
33
|
```bash
|
|
34
|
-
agy --sandbox --dangerously-skip-permissions --model gemini-3.7-flash-high --print 'YOUR_LABOR_PROMPT' --log-file /tmp/agy-labor.log
|
|
34
|
+
agy --sandbox --dangerously-skip-permissions --print-timeout 30m --model gemini-3.7-flash-high --print 'YOUR_LABOR_PROMPT' --log-file /tmp/agy-labor.log
|
|
35
35
|
```
|
|
36
36
|
|
|
37
37
|
When the dispatch order names a model, pass it verbatim via `--model`; an
|
|
38
38
|
unknown model id is an engine-process failure (typed failure, stop — per
|
|
39
39
|
`../engine-dispatch.md`).
|
|
40
|
+
|
|
41
|
+
## Print-mode timeout
|
|
42
|
+
|
|
43
|
+
`--print-timeout` defaults to 5m0s — too short for labor turns; a full apply
|
|
44
|
+
labor exceeded it (host-verified 2026-08-26, run 01a03dae-5635@coder,
|
|
45
|
+
"timeout waiting for response"). Labor invocations pass `--print-timeout 30m`.
|
|
46
|
+
A timeout that still fires is an engine-process failure: typed failure and
|
|
47
|
+
STOP per `../engine-dispatch.md`.
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Sole nested-volume reader for gate-cycle facts under session/auditor-roles/.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* families must not open a second disk scan — they
|
|
4
|
+
* Consumers: Analyst sole ledger scan (classifyScopedRun) and Terminal menxia
|
|
5
|
+
* projection (#478). Metric families must not open a second disk scan — they
|
|
6
|
+
* consume retained facts. Terminal settlement reuses this same pairing seam
|
|
7
|
+
* (no second auditor-roles scanner).
|
|
6
8
|
*
|
|
7
9
|
* Naming: records may carry pre-#440 menxia/jishizhong/fubaolang tool faces or
|
|
8
10
|
* the current gatekeeper/inspector/notary English face. Projection always uses
|
|
@@ -40,8 +42,20 @@ export type AnalystGateCycleRound = {
|
|
|
40
42
|
readonly officerWallMs: number;
|
|
41
43
|
readonly officerStartedAt: string;
|
|
42
44
|
readonly officerEndedAt: string;
|
|
43
|
-
/**
|
|
45
|
+
/**
|
|
46
|
+
* Typed string findings retained from the accepted officer receipt (#478 Terminal
|
|
47
|
+
* projection). Analyst metrics still consume findingsCount only — never prose.
|
|
48
|
+
*/
|
|
49
|
+
readonly findings: readonly string[];
|
|
50
|
+
/** findings.length — retained so metric families need not re-derive. */
|
|
44
51
|
readonly findingsCount: number;
|
|
52
|
+
/** Accepted dispatch receipt status (paired rounds are always "dispatch"). */
|
|
53
|
+
readonly dispatchStatus: string;
|
|
54
|
+
/**
|
|
55
|
+
* Optional seat-reduction reason from the accepted dispatch receipt.
|
|
56
|
+
* Absent when the dispatch did not write a non-empty reason — never invented.
|
|
57
|
+
*/
|
|
58
|
+
readonly dispatchReason?: string;
|
|
45
59
|
};
|
|
46
60
|
|
|
47
61
|
const DISPATCH_TOOLS = new Set(["ak_menxia_output", "ak_gatekeeper_output"]);
|
|
@@ -80,6 +94,22 @@ function normalizeOfficerArg(raw: unknown): "inspector" | "notary" | undefined {
|
|
|
80
94
|
return OFFICER_ARG_ALIASES[raw.trim()];
|
|
81
95
|
}
|
|
82
96
|
|
|
97
|
+
/** Typed string findings only — non-strings dropped; missing/non-array → []. */
|
|
98
|
+
function asStringFindings(value: unknown): readonly string[] {
|
|
99
|
+
if (!Array.isArray(value)) return [];
|
|
100
|
+
return value.filter((item): item is string => typeof item === "string");
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Optional non-empty dispatch reason. Trim only decides emptiness; a non-empty
|
|
105
|
+
* durable reason is returned as written (gatekeeper keeps reason as-is).
|
|
106
|
+
*/
|
|
107
|
+
function optionalDispatchReason(raw: unknown): string | undefined {
|
|
108
|
+
if (typeof raw !== "string") return undefined;
|
|
109
|
+
if (raw.trim() === "") return undefined;
|
|
110
|
+
return raw;
|
|
111
|
+
}
|
|
112
|
+
|
|
83
113
|
type AcceptedGateToolCall = {
|
|
84
114
|
readonly toolName: string;
|
|
85
115
|
readonly args: Record<string, unknown> | undefined;
|
|
@@ -177,6 +207,8 @@ type ClassifiedVolume =
|
|
|
177
207
|
readonly kind: "dispatch";
|
|
178
208
|
readonly startedAt: string;
|
|
179
209
|
readonly officer: "inspector" | "notary";
|
|
210
|
+
readonly status: string;
|
|
211
|
+
readonly reason?: string;
|
|
180
212
|
}
|
|
181
213
|
| {
|
|
182
214
|
readonly kind: "officer";
|
|
@@ -184,6 +216,7 @@ type ClassifiedVolume =
|
|
|
184
216
|
readonly endedAt: string;
|
|
185
217
|
readonly officer: "inspector" | "notary";
|
|
186
218
|
readonly status: string;
|
|
219
|
+
readonly findings: readonly string[];
|
|
187
220
|
readonly findingsCount: number;
|
|
188
221
|
readonly officerWallMs: number;
|
|
189
222
|
};
|
|
@@ -200,8 +233,8 @@ async function classifyAuditorVolume(
|
|
|
200
233
|
|
|
201
234
|
const span = requireAcceptedGateSpan(rows, filePath);
|
|
202
235
|
const status = requireAcceptedGateStatus(call.args, filePath);
|
|
203
|
-
const findings = call.args?.findings;
|
|
204
|
-
const findingsCount =
|
|
236
|
+
const findings = asStringFindings(call.args?.findings);
|
|
237
|
+
const findingsCount = findings.length;
|
|
205
238
|
|
|
206
239
|
if (DISPATCH_TOOLS.has(call.toolName)) {
|
|
207
240
|
// Gatekeeper contract terminals: dispatch | incomplete. Incomplete is a
|
|
@@ -218,10 +251,13 @@ async function classifyAuditorVolume(
|
|
|
218
251
|
`accepted dispatch receipt missing or unknown officer in ${filePath}`,
|
|
219
252
|
);
|
|
220
253
|
}
|
|
254
|
+
const reason = optionalDispatchReason(call.args?.reason);
|
|
221
255
|
return {
|
|
222
256
|
kind: "dispatch",
|
|
223
257
|
startedAt: span.startedAt,
|
|
224
258
|
officer,
|
|
259
|
+
status,
|
|
260
|
+
...(reason === undefined ? {} : { reason }),
|
|
225
261
|
};
|
|
226
262
|
}
|
|
227
263
|
|
|
@@ -238,6 +274,7 @@ async function classifyAuditorVolume(
|
|
|
238
274
|
endedAt: span.endedAt,
|
|
239
275
|
officer,
|
|
240
276
|
status,
|
|
277
|
+
findings,
|
|
241
278
|
findingsCount,
|
|
242
279
|
officerWallMs: span.wallMs,
|
|
243
280
|
};
|
|
@@ -278,7 +315,10 @@ function pairGateRounds(
|
|
|
278
315
|
officerWallMs: match.officer.officerWallMs,
|
|
279
316
|
officerStartedAt: match.officer.startedAt,
|
|
280
317
|
officerEndedAt: match.officer.endedAt,
|
|
318
|
+
findings: match.officer.findings,
|
|
281
319
|
findingsCount: match.officer.findingsCount,
|
|
320
|
+
dispatchStatus: vol.status,
|
|
321
|
+
...(vol.reason === undefined ? {} : { dispatchReason: vol.reason }),
|
|
282
322
|
});
|
|
283
323
|
}
|
|
284
324
|
|
|
@@ -8,6 +8,11 @@ import { constants as fsConstants } from "node:fs";
|
|
|
8
8
|
import { appendFile, lstat, mkdir, open, readFile, readdir, writeFile } from "node:fs/promises";
|
|
9
9
|
import { dirname, join } from "node:path";
|
|
10
10
|
|
|
11
|
+
import {
|
|
12
|
+
readAnalystGateCyclesFromAuditorRoles,
|
|
13
|
+
type AnalystGateCycleRound,
|
|
14
|
+
} from "../analyst-gate-cycles-read.ts";
|
|
15
|
+
|
|
11
16
|
import { isAuditEscalationResult } from "../audit-escalation.ts";
|
|
12
17
|
import { AUDITOR_SOUL_ROLES } from "../auditor-soul.ts";
|
|
13
18
|
import { DOCTOR_AUDIT_TOOL_NAME } from "../doctor-auditor.ts";
|
|
@@ -119,6 +124,8 @@ import {
|
|
|
119
124
|
type AuditIncompleteResidual,
|
|
120
125
|
type ControlledFailureCause,
|
|
121
126
|
type TerminalArtifactRef,
|
|
127
|
+
type TerminalMenxiaFact,
|
|
128
|
+
type TerminalMenxiaSeat,
|
|
122
129
|
type TerminalNavigatorFact,
|
|
123
130
|
type TerminalResult,
|
|
124
131
|
type TerminalResume,
|
|
@@ -2088,21 +2095,27 @@ export async function trySettleComplianceAuditIncompleteTerminalResult(
|
|
|
2088
2095
|
outputToolName,
|
|
2089
2096
|
);
|
|
2090
2097
|
if (extracted === undefined) return undefined;
|
|
2098
|
+
// Catch covers publication only — menxia read errors keep their session/JSONL identity
|
|
2099
|
+
// and must not be washed into the publication-failure label.
|
|
2100
|
+
let evidence: TerminalArtifactRef;
|
|
2091
2101
|
try {
|
|
2092
|
-
|
|
2102
|
+
evidence = await publishComplianceAuditIncompleteEvidence(
|
|
2093
2103
|
admitted,
|
|
2094
2104
|
extracted.outcome,
|
|
2095
2105
|
);
|
|
2096
|
-
return {
|
|
2097
|
-
roleOutcome: extracted.outcome,
|
|
2098
|
-
navigator: extractNavigatorFact(entries),
|
|
2099
|
-
artifacts: [evidence],
|
|
2100
|
-
runId: admitted.runId,
|
|
2101
|
-
};
|
|
2102
2106
|
} catch (error) {
|
|
2103
2107
|
// Publication failure is a non-lawful terminal, never an accepted audit result.
|
|
2104
2108
|
return auditPublicationFailureTerminal(admitted, entries, extracted.outcome, error);
|
|
2105
2109
|
}
|
|
2110
|
+
return withOptionalMenxiaProjection(
|
|
2111
|
+
{
|
|
2112
|
+
roleOutcome: extracted.outcome,
|
|
2113
|
+
navigator: extractNavigatorFact(entries),
|
|
2114
|
+
artifacts: [evidence],
|
|
2115
|
+
runId: admitted.runId,
|
|
2116
|
+
},
|
|
2117
|
+
admitted.sessionDirectory,
|
|
2118
|
+
);
|
|
2106
2119
|
}
|
|
2107
2120
|
|
|
2108
2121
|
/** Lawful Judge outcomes extracted from session (never a fabricated failure Receipt). */
|
|
@@ -2249,6 +2262,75 @@ function parseNavigatorAttendanceDetails(
|
|
|
2249
2262
|
};
|
|
2250
2263
|
}
|
|
2251
2264
|
|
|
2265
|
+
/**
|
|
2266
|
+
* Project paired gate-cycle rounds onto the public Terminal menxia region (#478).
|
|
2267
|
+
* actualSeats are derived only from accepted paired receipts — never from soul
|
|
2268
|
+
* expected/missing officer judgments.
|
|
2269
|
+
*/
|
|
2270
|
+
export function projectTerminalMenxiaFact(
|
|
2271
|
+
rounds: readonly AnalystGateCycleRound[],
|
|
2272
|
+
): TerminalMenxiaFact | undefined {
|
|
2273
|
+
if (rounds.length === 0) return undefined;
|
|
2274
|
+
const seen = new Set<TerminalMenxiaSeat>();
|
|
2275
|
+
// Every paired round implies an accepted gatekeeper dispatch volume.
|
|
2276
|
+
seen.add("gatekeeper");
|
|
2277
|
+
for (const round of rounds) seen.add(round.officer);
|
|
2278
|
+
const actualSeats = (["gatekeeper", "inspector", "notary"] as const).filter(
|
|
2279
|
+
(seat) => seen.has(seat),
|
|
2280
|
+
);
|
|
2281
|
+
return {
|
|
2282
|
+
actualSeats,
|
|
2283
|
+
rounds: rounds.map((round) => ({
|
|
2284
|
+
roundIndex: round.roundIndex,
|
|
2285
|
+
dispatch: {
|
|
2286
|
+
status: round.dispatchStatus,
|
|
2287
|
+
officer: round.officer,
|
|
2288
|
+
...(round.dispatchReason === undefined
|
|
2289
|
+
? {}
|
|
2290
|
+
: { reason: round.dispatchReason }),
|
|
2291
|
+
},
|
|
2292
|
+
officer: {
|
|
2293
|
+
seat: round.officer,
|
|
2294
|
+
status: round.status,
|
|
2295
|
+
findings: round.findings,
|
|
2296
|
+
},
|
|
2297
|
+
})),
|
|
2298
|
+
};
|
|
2299
|
+
}
|
|
2300
|
+
|
|
2301
|
+
/**
|
|
2302
|
+
* Read menxia facts from the run's session/auditor-roles nest via the sole
|
|
2303
|
+
* nested-volume reader (#446/#478). Missing directory → undefined (no-gate
|
|
2304
|
+
* zero change). Damaged discovered volumes propagate — never wash to "no gate".
|
|
2305
|
+
*/
|
|
2306
|
+
export async function extractMenxiaFactFromSessionDirectory(
|
|
2307
|
+
sessionDirectory: string,
|
|
2308
|
+
): Promise<TerminalMenxiaFact | undefined> {
|
|
2309
|
+
const rounds = await readAnalystGateCyclesFromAuditorRoles(
|
|
2310
|
+
join(sessionDirectory, "auditor-roles"),
|
|
2311
|
+
);
|
|
2312
|
+
return projectTerminalMenxiaFact(rounds);
|
|
2313
|
+
}
|
|
2314
|
+
|
|
2315
|
+
/**
|
|
2316
|
+
* Attach optional menxia projection onto a settled Terminal base.
|
|
2317
|
+
* Shared by every settle path so auditor-roles is scanned once here only.
|
|
2318
|
+
* `runId` is not required — resumable failures omit it by contract.
|
|
2319
|
+
* Menxia read damage propagates with its real identity (never washed to no-gate
|
|
2320
|
+
* or swallowed); callers that already hold a controlled failure still surface the
|
|
2321
|
+
* JSONL/session cause rather than pretend the gate was absent.
|
|
2322
|
+
*/
|
|
2323
|
+
async function withOptionalMenxiaProjection<
|
|
2324
|
+
T extends {
|
|
2325
|
+
roleOutcome: TerminalRoleOutcome;
|
|
2326
|
+
navigator: TerminalNavigatorFact;
|
|
2327
|
+
artifacts: readonly TerminalArtifactRef[];
|
|
2328
|
+
},
|
|
2329
|
+
>(base: T, sessionDirectory: string): Promise<T & { menxia?: TerminalMenxiaFact }> {
|
|
2330
|
+
const menxia = await extractMenxiaFactFromSessionDirectory(sessionDirectory);
|
|
2331
|
+
return menxia === undefined ? base : { ...base, menxia };
|
|
2332
|
+
}
|
|
2333
|
+
|
|
2252
2334
|
export function extractNavigatorFact(
|
|
2253
2335
|
entries: readonly SessionEntry[],
|
|
2254
2336
|
): TerminalNavigatorFact {
|
|
@@ -2580,12 +2662,15 @@ async function settleLawfulJudgeTerminalResult(
|
|
|
2580
2662
|
roleOutcome,
|
|
2581
2663
|
admitted.sessionDirectory,
|
|
2582
2664
|
);
|
|
2583
|
-
return
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2665
|
+
return withOptionalMenxiaProjection(
|
|
2666
|
+
{
|
|
2667
|
+
roleOutcome,
|
|
2668
|
+
navigator,
|
|
2669
|
+
artifacts,
|
|
2670
|
+
runId: admitted.runId,
|
|
2671
|
+
},
|
|
2672
|
+
admitted.sessionDirectory,
|
|
2673
|
+
);
|
|
2589
2674
|
}
|
|
2590
2675
|
|
|
2591
2676
|
/**
|
|
@@ -2638,12 +2723,15 @@ async function settleLawfulCoderTerminalResult(
|
|
|
2638
2723
|
: { methodProvenance: options.methodProvenance }),
|
|
2639
2724
|
},
|
|
2640
2725
|
);
|
|
2641
|
-
return
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
|
|
2726
|
+
return withOptionalMenxiaProjection(
|
|
2727
|
+
{
|
|
2728
|
+
roleOutcome: extracted.outcome,
|
|
2729
|
+
navigator,
|
|
2730
|
+
artifacts,
|
|
2731
|
+
runId: admitted.runId,
|
|
2732
|
+
},
|
|
2733
|
+
admitted.sessionDirectory,
|
|
2734
|
+
);
|
|
2647
2735
|
}
|
|
2648
2736
|
|
|
2649
2737
|
/** Settle a lawful Coder Terminal from the admitted session (shared #106 success interface). */
|
|
@@ -2847,12 +2935,15 @@ async function settleLawfulFixerTerminalResult(
|
|
|
2847
2935
|
methodInvocations,
|
|
2848
2936
|
},
|
|
2849
2937
|
);
|
|
2850
|
-
return
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
|
|
2938
|
+
return withOptionalMenxiaProjection(
|
|
2939
|
+
{
|
|
2940
|
+
roleOutcome: extracted.outcome,
|
|
2941
|
+
navigator,
|
|
2942
|
+
artifacts,
|
|
2943
|
+
runId: admitted.runId,
|
|
2944
|
+
},
|
|
2945
|
+
admitted.sessionDirectory,
|
|
2946
|
+
);
|
|
2856
2947
|
}
|
|
2857
2948
|
|
|
2858
2949
|
/** Settle a lawful Fixer Terminal from the admitted session (shared #106 success interface). */
|
|
@@ -3005,12 +3096,15 @@ async function settleLawfulCollectorTerminalResult(
|
|
|
3005
3096
|
admitted.sessionDirectory,
|
|
3006
3097
|
{ collectorReceipt: extracted.receipt },
|
|
3007
3098
|
);
|
|
3008
|
-
return
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3099
|
+
return withOptionalMenxiaProjection(
|
|
3100
|
+
{
|
|
3101
|
+
roleOutcome: extracted.outcome,
|
|
3102
|
+
navigator,
|
|
3103
|
+
artifacts,
|
|
3104
|
+
runId: admitted.runId,
|
|
3105
|
+
},
|
|
3106
|
+
admitted.sessionDirectory,
|
|
3107
|
+
);
|
|
3014
3108
|
}
|
|
3015
3109
|
|
|
3016
3110
|
/** Settle a lawful Collector Terminal from the admitted session. */
|
|
@@ -3189,12 +3283,15 @@ async function settleLawfulDoctorTerminalResult(
|
|
|
3189
3283
|
admitted.sessionDirectory,
|
|
3190
3284
|
extracted.output === undefined ? {} : { doctorOutput: extracted.output },
|
|
3191
3285
|
);
|
|
3192
|
-
return
|
|
3193
|
-
|
|
3194
|
-
|
|
3195
|
-
|
|
3196
|
-
|
|
3197
|
-
|
|
3286
|
+
return withOptionalMenxiaProjection(
|
|
3287
|
+
{
|
|
3288
|
+
roleOutcome: extracted.outcome,
|
|
3289
|
+
navigator,
|
|
3290
|
+
artifacts,
|
|
3291
|
+
runId: admitted.runId,
|
|
3292
|
+
},
|
|
3293
|
+
admitted.sessionDirectory,
|
|
3294
|
+
);
|
|
3198
3295
|
}
|
|
3199
3296
|
|
|
3200
3297
|
/** Settle a lawful Doctor Terminal from the admitted session. */
|
|
@@ -3283,12 +3380,15 @@ async function settleLawfulNotaryTerminalResult(
|
|
|
3283
3380
|
return undefined;
|
|
3284
3381
|
}
|
|
3285
3382
|
const navigator = extractNavigatorFact(entries);
|
|
3286
|
-
return
|
|
3287
|
-
|
|
3288
|
-
|
|
3289
|
-
|
|
3290
|
-
|
|
3291
|
-
|
|
3383
|
+
return withOptionalMenxiaProjection(
|
|
3384
|
+
{
|
|
3385
|
+
roleOutcome: extracted.outcome,
|
|
3386
|
+
navigator,
|
|
3387
|
+
artifacts: [],
|
|
3388
|
+
runId: admitted.runId,
|
|
3389
|
+
},
|
|
3390
|
+
admitted.sessionDirectory,
|
|
3391
|
+
);
|
|
3292
3392
|
}
|
|
3293
3393
|
|
|
3294
3394
|
/** Settle a lawful Notary Terminal from the admitted session. */
|
|
@@ -3549,12 +3649,15 @@ async function settleLawfulReviewerTerminalResult(
|
|
|
3549
3649
|
methodInvocations,
|
|
3550
3650
|
},
|
|
3551
3651
|
);
|
|
3552
|
-
return
|
|
3553
|
-
|
|
3554
|
-
|
|
3555
|
-
|
|
3556
|
-
|
|
3557
|
-
|
|
3652
|
+
return withOptionalMenxiaProjection(
|
|
3653
|
+
{
|
|
3654
|
+
roleOutcome: extracted.outcome,
|
|
3655
|
+
navigator,
|
|
3656
|
+
artifacts,
|
|
3657
|
+
runId: admitted.runId,
|
|
3658
|
+
},
|
|
3659
|
+
admitted.sessionDirectory,
|
|
3660
|
+
);
|
|
3558
3661
|
}
|
|
3559
3662
|
|
|
3560
3663
|
/** Settle a lawful Reviewer Terminal from the admitted session (shared #106 success interface). */
|
|
@@ -3815,12 +3918,15 @@ async function settleLawfulMergerTerminalResult(
|
|
|
3815
3918
|
methodInvocations,
|
|
3816
3919
|
},
|
|
3817
3920
|
);
|
|
3818
|
-
return
|
|
3819
|
-
|
|
3820
|
-
|
|
3821
|
-
|
|
3822
|
-
|
|
3823
|
-
|
|
3921
|
+
return withOptionalMenxiaProjection(
|
|
3922
|
+
{
|
|
3923
|
+
roleOutcome: extracted.outcome,
|
|
3924
|
+
navigator,
|
|
3925
|
+
artifacts,
|
|
3926
|
+
runId: admitted.runId,
|
|
3927
|
+
},
|
|
3928
|
+
admitted.sessionDirectory,
|
|
3929
|
+
);
|
|
3824
3930
|
}
|
|
3825
3931
|
|
|
3826
3932
|
/** Settle a lawful Merger Terminal from the admitted session (shared #106 success interface). */
|
|
@@ -4170,10 +4276,16 @@ export async function settleFailureTerminalResult(
|
|
|
4170
4276
|
const facts = parseNoReceiptLifecycleFacts(raw);
|
|
4171
4277
|
if (facts.runPointer === admitted.runDirectory && facts.attemptPointer === `current:${admitted.runDirectory}`) {
|
|
4172
4278
|
const decisiveFacts: NoReceiptLifecycleFacts = facts;
|
|
4173
|
-
|
|
4174
|
-
|
|
4175
|
-
|
|
4176
|
-
|
|
4279
|
+
// #478: no_receipt is still a public Terminal — project accepted gate facts.
|
|
4280
|
+
return withOptionalMenxiaProjection(
|
|
4281
|
+
{
|
|
4282
|
+
roleOutcome: { kind: "no_receipt", role: admitted.role, status: "no-accepted-receipt", ...facts, decisiveFacts },
|
|
4283
|
+
navigator: await extractNavigatorFactFromAdmittedSession(admitted),
|
|
4284
|
+
artifacts: [],
|
|
4285
|
+
runId: admitted.runId,
|
|
4286
|
+
},
|
|
4287
|
+
admitted.sessionDirectory,
|
|
4288
|
+
);
|
|
4177
4289
|
}
|
|
4178
4290
|
} catch { /* malformed lifecycle bytes remain the existing nonzero output failure */ }
|
|
4179
4291
|
}
|
|
@@ -4213,12 +4325,16 @@ export async function settleFailureTerminalResult(
|
|
|
4213
4325
|
diagnostic: publicDiagnostic,
|
|
4214
4326
|
decisiveFacts: publicFacts,
|
|
4215
4327
|
};
|
|
4216
|
-
|
|
4217
|
-
|
|
4218
|
-
|
|
4219
|
-
|
|
4220
|
-
|
|
4221
|
-
|
|
4328
|
+
// #478: resume desensitization stays; menxia is additive typed fact only.
|
|
4329
|
+
return withOptionalMenxiaProjection(
|
|
4330
|
+
{
|
|
4331
|
+
roleOutcome,
|
|
4332
|
+
navigator: redactNavigatorFactForPublicTerminal(navigator, admitted.runId),
|
|
4333
|
+
artifacts: [],
|
|
4334
|
+
resume: options.resume,
|
|
4335
|
+
},
|
|
4336
|
+
admitted.sessionDirectory,
|
|
4337
|
+
);
|
|
4222
4338
|
}
|
|
4223
4339
|
const roleOutcome: TerminalRoleOutcome = {
|
|
4224
4340
|
kind: "failure",
|
|
@@ -4227,12 +4343,16 @@ export async function settleFailureTerminalResult(
|
|
|
4227
4343
|
diagnostic: failure.diagnostic,
|
|
4228
4344
|
decisiveFacts,
|
|
4229
4345
|
};
|
|
4230
|
-
|
|
4231
|
-
|
|
4232
|
-
|
|
4233
|
-
|
|
4234
|
-
|
|
4235
|
-
|
|
4346
|
+
// #478: ordinary controlled failure still surfaces accepted gate facts.
|
|
4347
|
+
return withOptionalMenxiaProjection(
|
|
4348
|
+
{
|
|
4349
|
+
roleOutcome,
|
|
4350
|
+
navigator,
|
|
4351
|
+
artifacts,
|
|
4352
|
+
runId: admitted.runId,
|
|
4353
|
+
},
|
|
4354
|
+
admitted.sessionDirectory,
|
|
4355
|
+
);
|
|
4236
4356
|
}
|
|
4237
4357
|
|
|
4238
4358
|
/** Judge-named alias retained for #107 call sites. */
|
|
@@ -215,6 +215,42 @@ export type TerminalResume = {
|
|
|
215
215
|
readonly command: string;
|
|
216
216
|
};
|
|
217
217
|
|
|
218
|
+
/** Current English menxia seat faces projected on Terminal (#478). */
|
|
219
|
+
export type TerminalMenxiaSeat = "gatekeeper" | "inspector" | "notary";
|
|
220
|
+
|
|
221
|
+
/** One accepted province dispatch receipt (status/officer + optional reduce-seat reason). */
|
|
222
|
+
export type TerminalMenxiaDispatch = {
|
|
223
|
+
readonly status: string;
|
|
224
|
+
readonly officer: "inspector" | "notary";
|
|
225
|
+
/** Present only when the accepted dispatch wrote a non-empty reason. */
|
|
226
|
+
readonly reason?: string;
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
/** One accepted officer report: seat, status, full typed findings. */
|
|
230
|
+
export type TerminalMenxiaOfficerReport = {
|
|
231
|
+
readonly seat: "inspector" | "notary";
|
|
232
|
+
readonly status: string;
|
|
233
|
+
readonly findings: readonly string[];
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
/** One paired dispatch↔officer gate round on the public Terminal. */
|
|
237
|
+
export type TerminalMenxiaRound = {
|
|
238
|
+
readonly roundIndex: number;
|
|
239
|
+
readonly dispatch: TerminalMenxiaDispatch;
|
|
240
|
+
readonly officer: TerminalMenxiaOfficerReport;
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Optional menxia province projection (#478).
|
|
245
|
+
* Absent when no accepted paired gate rounds exist (no-gate zero change).
|
|
246
|
+
* Only durable accepted child receipts — never soul-derived expected/missing seats.
|
|
247
|
+
*/
|
|
248
|
+
export type TerminalMenxiaFact = {
|
|
249
|
+
/** Seats that actually ran, derived from accepted paired receipts. */
|
|
250
|
+
readonly actualSeats: readonly TerminalMenxiaSeat[];
|
|
251
|
+
readonly rounds: readonly TerminalMenxiaRound[];
|
|
252
|
+
};
|
|
253
|
+
|
|
218
254
|
/** Public free-text stand-in when an exact Role run ID is stripped outside resume.command. */
|
|
219
255
|
export const REDACTED_RUN_ID_TOKEN = "[run-id]" as const;
|
|
220
256
|
|
|
@@ -240,6 +276,11 @@ export type TerminalResult = {
|
|
|
240
276
|
roleOutcome: TerminalRoleOutcome;
|
|
241
277
|
navigator: TerminalNavigatorFact;
|
|
242
278
|
artifacts: readonly TerminalArtifactRef[];
|
|
279
|
+
/**
|
|
280
|
+
* Optional menxia province facts (#478). Present only when accepted paired
|
|
281
|
+
* gate rounds exist under session/auditor-roles; omitted on no-gate runs.
|
|
282
|
+
*/
|
|
283
|
+
menxia?: TerminalMenxiaFact;
|
|
243
284
|
/** Call-local auto-resume observation (0..2) for this single LLM call; read-only, not persisted. */
|
|
244
285
|
autoResumeCount?: number;
|
|
245
286
|
} & (
|
|
@@ -330,6 +371,22 @@ export function formatTerminalResult(result: TerminalResult): string {
|
|
|
330
371
|
for (const artifact of result.artifacts) {
|
|
331
372
|
lines.push(`artifact\t${artifact.kind}\t${encodeTerminalField(artifact.path)}`);
|
|
332
373
|
}
|
|
374
|
+
// Menxia region is unfrozen presentation of typed facts (ADR 0052) — machines
|
|
375
|
+
// read result.menxia, never these row labels.
|
|
376
|
+
if (result.menxia !== undefined) {
|
|
377
|
+
lines.push(
|
|
378
|
+
`menxia\t${encodeTerminalField(result.menxia.actualSeats.join(","))}\t${result.menxia.rounds.length}`,
|
|
379
|
+
);
|
|
380
|
+
for (const round of result.menxia.rounds) {
|
|
381
|
+
const reason =
|
|
382
|
+
round.dispatch.reason === undefined
|
|
383
|
+
? ""
|
|
384
|
+
: encodeTerminalField(round.dispatch.reason);
|
|
385
|
+
lines.push(
|
|
386
|
+
`menxia-round\t${round.roundIndex}\t${round.dispatch.status}\t${round.dispatch.officer}\t${reason}\t${round.officer.seat}\t${encodeTerminalField(round.officer.status)}\t${encodeTerminalField(JSON.stringify(round.officer.findings))}`,
|
|
387
|
+
);
|
|
388
|
+
}
|
|
389
|
+
}
|
|
333
390
|
if (result.resume !== undefined) {
|
|
334
391
|
// Resumable failure: run ID is revealed only inside the complete resume command.
|
|
335
392
|
lines.push(`resume\t${encodeTerminalField(result.resume.command)}`);
|