@akagilnc/pi-workflow-roles 0.1.3452 → 0.1.3471
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/CLAUDE.md +2 -0
- package/dist/evidence-child-executor.js +2 -11
- package/dist/grok/production-host.js +196 -205
- package/dist/pi/in-process-session.js +4 -0
- package/dist/public-cli/main.js +998 -920
- package/package.json +1 -1
- package/scripts/build-package.mjs +1 -3
- package/src/analyst-gate-cycles-read.ts +3 -21
- package/src/analyst-ledger.ts +11 -42
- package/src/archivist-record-entry.ts +5 -6
- package/src/evidence-child-executor.ts +5 -15
- package/src/grok/production-host.ts +3 -32
- package/src/grok/role-envelope.ts +10 -4
- package/src/host-contracts.ts +4 -11
- package/src/host-transition-prior-native.ts +3 -7
- package/src/ledger-session-read.ts +1 -17
- package/src/pi/in-process-session.ts +6 -2
- package/src/pi/role-turn-host.ts +9 -0
- package/src/public-cli/collector-run.ts +4 -4
- package/src/public-cli/countersign-run.ts +90 -20
- package/src/public-cli/doctor-run.ts +4 -4
- package/src/public-cli/gleaner-left-run.ts +9 -6
- package/src/public-cli/inspector-run.ts +95 -32
- package/src/public-cli/instruction-seat-run.ts +7 -6
- package/src/public-cli/invocation.ts +14 -8
- package/src/public-cli/judge-run.ts +4 -4
- package/src/public-cli/notary-run.ts +91 -30
- package/src/public-cli/post-admission.ts +424 -360
- package/src/public-cli/run-lifecycle.ts +205 -0
- package/src/public-cli/seat-ticket-binding.ts +136 -16
- package/src/public-cli/settlement.ts +74 -52
- package/src/run-ticket-number.ts +53 -0
- package/src/submission-ledger.ts +86 -18
- package/dist/ledger-session-read.js +0 -241
- package/dist/ticket-seat-memory.js +0 -244
- package/src/ticket-seat-memory.ts +0 -454
package/package.json
CHANGED
|
@@ -23,9 +23,7 @@ const entries = [
|
|
|
23
23
|
"archivist-record-entry",
|
|
24
24
|
// Pure subject nest topology — cold discovery without SessionManager (#636).
|
|
25
25
|
"archivist-record-topology",
|
|
26
|
-
//
|
|
27
|
-
"ticket-seat-memory",
|
|
28
|
-
// ticket-seat-memory → session-opening-materials (#636 non-bundle graph closure).
|
|
26
|
+
// Session material loaders used by published non-bundle roots.
|
|
29
27
|
"session-opening-materials",
|
|
30
28
|
// Value-import closure of published non-bundle roots (build-package-only loadable).
|
|
31
29
|
"auditor-dossier-tool",
|
|
@@ -34,11 +34,10 @@ import {
|
|
|
34
34
|
import {
|
|
35
35
|
extractSessionTimestampSpan,
|
|
36
36
|
intervalRowsAroundAnchor,
|
|
37
|
-
LedgerSessionJsonlError,
|
|
38
37
|
readLedgerSessionJsonl,
|
|
39
38
|
type LedgerSessionRow,
|
|
40
39
|
} from "./ledger-session-read.ts";
|
|
41
|
-
|
|
40
|
+
|
|
42
41
|
|
|
43
42
|
/** One completed gate round: direct officer receipt or historical province/officer pair. */
|
|
44
43
|
/** Honest origin discriminant: direct summons vs historical province dispatch. */
|
|
@@ -349,22 +348,7 @@ async function classifyAuditorVolume(
|
|
|
349
348
|
filePath: string,
|
|
350
349
|
): Promise<readonly ClassifiedVolume[]> {
|
|
351
350
|
// Canonical JSONL errors propagate — failure honesty (never wash to fewer rounds).
|
|
352
|
-
|
|
353
|
-
// closed binding must not erase earlier gate rounds (same ownership rule as
|
|
354
|
-
// timeline attribution). Pure nested gate volumes without run bindings stay loud.
|
|
355
|
-
let rows: readonly LedgerSessionRow[];
|
|
356
|
-
try {
|
|
357
|
-
rows = await readLedgerSessionJsonl(filePath);
|
|
358
|
-
} catch (error) {
|
|
359
|
-
if (
|
|
360
|
-
error instanceof LedgerSessionJsonlError
|
|
361
|
-
&& error.prefixRows.some((row) => isTicketSeatRunBindingRow(row))
|
|
362
|
-
) {
|
|
363
|
-
rows = error.prefixRows;
|
|
364
|
-
} else {
|
|
365
|
-
throw error;
|
|
366
|
-
}
|
|
367
|
-
}
|
|
351
|
+
const rows = await readLedgerSessionJsonl(filePath);
|
|
368
352
|
const accepted = extractAllAcceptedGateToolCalls(rows);
|
|
369
353
|
// Rejected-only / non-gate volumes omit (empty accepted set).
|
|
370
354
|
if (accepted.length === 0) return [];
|
|
@@ -455,9 +439,7 @@ function pairGateRounds(
|
|
|
455
439
|
* ENOENT (directory truly absent) → []. ENOTDIR and other errors propagate
|
|
456
440
|
* (failure honesty — damaged topology must not wash to zero rounds).
|
|
457
441
|
*
|
|
458
|
-
*
|
|
459
|
-
* digests shared across parent runs; pass `parentSessionFile` to keep only
|
|
460
|
-
* rounds whose attempt binding names that parent.
|
|
442
|
+
* Pass `parentSessionFile` to keep only rounds whose attempt binding names that parent.
|
|
461
443
|
*/
|
|
462
444
|
export async function readAnalystGateCyclesFromAuditorRoles(
|
|
463
445
|
auditorRolesDirectory: string | readonly string[],
|
package/src/analyst-ledger.ts
CHANGED
|
@@ -25,7 +25,6 @@ import {
|
|
|
25
25
|
extractSessionModelSequence,
|
|
26
26
|
extractSessionTimestampSpan,
|
|
27
27
|
extractSessionToolIntervals,
|
|
28
|
-
intervalRowsForMatchingBinding,
|
|
29
28
|
LedgerSessionJsonlError,
|
|
30
29
|
readLedgerSessionJsonl,
|
|
31
30
|
type LedgerSessionRow,
|
|
@@ -46,11 +45,6 @@ import {
|
|
|
46
45
|
readAnalystGateCyclesFromAuditorRoles,
|
|
47
46
|
type AnalystGateCycleRound,
|
|
48
47
|
} from "./analyst-gate-cycles-read.ts";
|
|
49
|
-
import {
|
|
50
|
-
isTicketSeatRunBindingRow,
|
|
51
|
-
resolveTicketSeatMemoryNestDirectories,
|
|
52
|
-
ticketSeatRunBindingRunId,
|
|
53
|
-
} from "./ticket-seat-memory.ts";
|
|
54
48
|
|
|
55
49
|
export type { AnalystGateCycleRound } from "./analyst-gate-cycles-read.ts";
|
|
56
50
|
|
|
@@ -210,16 +204,9 @@ async function resolveSessionFile(
|
|
|
210
204
|
}
|
|
211
205
|
|
|
212
206
|
/**
|
|
213
|
-
* Attribute session rows to one run
|
|
207
|
+
* Attribute session rows to one run.
|
|
214
208
|
* Private run volumes (session under runDirectory) keep the whole file.
|
|
215
|
-
*
|
|
216
|
-
* whole-volume stats would let later continuations pollute earlier runs.
|
|
217
|
-
* Unbounded external volumes stay honest missing — never silent full ownership.
|
|
218
|
-
*
|
|
219
|
-
* `closed` on shared intervals: a later binding ended ownership before EOF of
|
|
220
|
-
* the provided rows. On damaged-prefix recovery, only closed intervals keep
|
|
221
|
-
* full frame/model/tool facts — open intervals may have lost rows to the bad line.
|
|
222
|
-
* Private volumes are never closed against a prefix (the whole file is this run).
|
|
209
|
+
* External volumes stay honest missing — never silent full ownership.
|
|
223
210
|
*/
|
|
224
211
|
function attributeSessionRowsForRun(input: {
|
|
225
212
|
readonly rows: readonly LedgerSessionRow[];
|
|
@@ -236,19 +223,10 @@ function attributeSessionRowsForRun(input: {
|
|
|
236
223
|
if (pathContainedIn(input.runDirectory, input.sessionFile)) {
|
|
237
224
|
return { kind: "attributed", rows: input.rows, closed: false };
|
|
238
225
|
}
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
);
|
|
244
|
-
if (interval === undefined) {
|
|
245
|
-
return {
|
|
246
|
-
kind: "missing-boundary",
|
|
247
|
-
reason:
|
|
248
|
-
"shared session volume has no ticket-seat run binding for this run",
|
|
249
|
-
};
|
|
250
|
-
}
|
|
251
|
-
return { kind: "attributed", rows: interval.rows, closed: interval.closed };
|
|
226
|
+
return {
|
|
227
|
+
kind: "missing-boundary",
|
|
228
|
+
reason: "session volume is outside the run directory",
|
|
229
|
+
};
|
|
252
230
|
}
|
|
253
231
|
|
|
254
232
|
/**
|
|
@@ -382,8 +360,7 @@ async function classifyScopedRun(input: {
|
|
|
382
360
|
let partialFirstFrameAt: AnalystFirstFrameAt = { status: "absent" };
|
|
383
361
|
let partialLastFrameAt: AnalystOptionalTimestamp = { status: "absent" };
|
|
384
362
|
|
|
385
|
-
// 1) session timeline
|
|
386
|
-
// Damage after a closed binding interval must not erase that run's full facts.
|
|
363
|
+
// 1) session timeline from the run-private volume.
|
|
387
364
|
const sessionFile = await resolveSessionFile(input.runDirectory);
|
|
388
365
|
let rows: readonly LedgerSessionRow[] | undefined;
|
|
389
366
|
const admitAttributed = (
|
|
@@ -516,21 +493,13 @@ async function classifyScopedRun(input: {
|
|
|
516
493
|
// Nested auditor-roles gate pairs stay inside the sole scan (families must
|
|
517
494
|
// not readdir this tree again). Missing directory → []. Damaged discovered
|
|
518
495
|
// nested JSONL is page-local unreadable — never silently under-count rounds.
|
|
519
|
-
// #636: ticket-seat memory nests via sole discovery helper.
|
|
520
496
|
let gateCycles: readonly AnalystGateCycleRound[];
|
|
521
497
|
try {
|
|
522
|
-
const memoryNests = await resolveTicketSeatMemoryNestDirectories({
|
|
523
|
-
runDirectory: input.runDirectory,
|
|
524
|
-
seats: ["inspector", "notary"],
|
|
525
|
-
});
|
|
526
|
-
const directories = [
|
|
527
|
-
join(input.runDirectory, "session", "auditor-roles"),
|
|
528
|
-
...memoryNests,
|
|
529
|
-
];
|
|
530
498
|
const parentSessionFile = join(input.runDirectory, "session", "session.jsonl");
|
|
531
|
-
gateCycles = await readAnalystGateCyclesFromAuditorRoles(
|
|
532
|
-
|
|
533
|
-
|
|
499
|
+
gateCycles = await readAnalystGateCyclesFromAuditorRoles(
|
|
500
|
+
join(input.runDirectory, "session", "auditor-roles"),
|
|
501
|
+
{ parentSessionFile },
|
|
502
|
+
);
|
|
534
503
|
} catch (error) {
|
|
535
504
|
return {
|
|
536
505
|
kind: "unreadable",
|
|
@@ -136,10 +136,9 @@ export type RecordSessionOpen = {
|
|
|
136
136
|
* identity is checked once before SessionManager.open (directory walk cannot see a
|
|
137
137
|
* trailing .jsonl symlink). New principals mint under the already-validated sessionDir
|
|
138
138
|
* via destination-free SessionManager.create — no derived postcondition.
|
|
139
|
-
* Resume via the AK-owned current-session ledger is limited to subject-keyed identity
|
|
140
|
-
* authorized worker-submission-gate durable path
|
|
141
|
-
*
|
|
142
|
-
* a sibling volume selected only by kind/cwd/mtime.
|
|
139
|
+
* Resume via the AK-owned current-session ledger is limited to subject-keyed identity
|
|
140
|
+
* and the authorized worker-submission-gate durable path (ADR 0066).
|
|
141
|
+
* Other ordinary no-subject children (auditor-roles, evidence-children, …) always mint fresh.
|
|
143
142
|
* New persisted principals materialize their deferred session header before return so
|
|
144
143
|
* custom-entry-only writers do not need a parallel delayed-header helper.
|
|
145
144
|
*
|
|
@@ -183,8 +182,8 @@ export function createRecordSessionOpen(options: CreateRecordSessionOptions): Re
|
|
|
183
182
|
const nestAlreadyExists = existsSync(sessionDir);
|
|
184
183
|
// Directory-chain ownership: containment + physical components (no parallel assert).
|
|
185
184
|
ensureRealDirectoryTree(ledgerHome, sessionDir);
|
|
186
|
-
// Subject-keyed nests continue by subject digest; gate
|
|
187
|
-
// authorized no-subject same-nest continuation. All other kinds mint fresh.
|
|
185
|
+
// Subject-keyed nests continue by subject digest; worker-submission-gate is the
|
|
186
|
+
// sole authorized no-subject same-nest continuation. All other kinds mint fresh.
|
|
188
187
|
const mayResumeSameNest =
|
|
189
188
|
options.subject !== undefined || options.kind === WORKER_SUBMISSION_GATE_KIND;
|
|
190
189
|
if (mayResumeSameNest && nestAlreadyExists) {
|
|
@@ -26,12 +26,6 @@ import {
|
|
|
26
26
|
} from "./compliance-transport.ts";
|
|
27
27
|
import { auditorRunDirectory } from "./auditor-dossier-tool.ts";
|
|
28
28
|
import { sitianReport } from "./sitian-facade.ts";
|
|
29
|
-
import {
|
|
30
|
-
isTicketSeatMemorySeat,
|
|
31
|
-
readRunTicketNumber,
|
|
32
|
-
ticketSeatMemorySubject,
|
|
33
|
-
TICKET_SEAT_MEMORY_KIND,
|
|
34
|
-
} from "./ticket-seat-memory.ts";
|
|
35
29
|
import { createEngineDetourToolDefinition } from "./engine-detour-tool.ts";
|
|
36
30
|
import { engineNameFromEnv } from "./engine-detour.ts";
|
|
37
31
|
import {
|
|
@@ -518,7 +512,6 @@ function auditorSeatKey(gateSeat: GateOfficerSeat | undefined): string {
|
|
|
518
512
|
export async function executeAuditorChild(
|
|
519
513
|
options: AuditorRoleOptions,
|
|
520
514
|
): Promise<{ decision: unknown; response: AssistantMessage; noReceiptLifecycle?: NoReceiptLifecycleFacts }> {
|
|
521
|
-
const { createRecordSession } = await import("./archivist-record-entry.ts");
|
|
522
515
|
const runDirectory = options.runDirectory ?? auditorRunDirectory(options.context);
|
|
523
516
|
if (runDirectory === undefined) {
|
|
524
517
|
throw new Error(`${options.roleLabel} requires a run directory carrying the institutional resolution page`);
|
|
@@ -570,16 +563,13 @@ export async function executeAuditorChild(
|
|
|
570
563
|
const parentHeader = parentSessionManager?.getHeader?.();
|
|
571
564
|
const parentSessionFile = parentSessionManager?.getSessionFile?.();
|
|
572
565
|
const parentAttemptEntryId = parentSessionManager?.getLeafId?.();
|
|
573
|
-
//
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
? ticketSeatMemorySubject(ticketNumber, seat)
|
|
578
|
-
: undefined;
|
|
566
|
+
// Institutional child under parent placement for gate/settlement discovery.
|
|
567
|
+
// No ticket:seat subject nest (#636 deleted / ADR 0079). Public officer seats
|
|
568
|
+
// resume via tryResumeSameTicketSeatRun on the seat's own run — not this nest.
|
|
569
|
+
const { createRecordSession } = await import("./archivist-record-entry.ts");
|
|
579
570
|
const auditorSessionManager: SessionManager = createRecordSession({
|
|
580
571
|
cwd,
|
|
581
|
-
kind:
|
|
582
|
-
...(memorySubject === undefined ? {} : { subject: memorySubject }),
|
|
572
|
+
kind: "auditor-roles",
|
|
583
573
|
...(parentSessionManager === undefined ? {} : { parent: parentSessionManager }),
|
|
584
574
|
});
|
|
585
575
|
|
|
@@ -166,26 +166,19 @@ export async function bindProductionGrokIsolation(
|
|
|
166
166
|
* and AK seatbelt hooks via settleProductionGrokHomeCleanup (no silent catch)
|
|
167
167
|
* while preserving the session dossier under runDirectory/grok-home. Success,
|
|
168
168
|
* typed-result, and throw paths all clean up; cleanup failure and primary+cleanup
|
|
169
|
-
* both surface.
|
|
170
|
-
*
|
|
171
|
-
* `noteOpened` fires only after bind succeeds — the actual open event, distinct
|
|
172
|
-
* from turn return/throw — so last-host ownership can retain the opened run
|
|
173
|
-
* even when the body or cleanup later throws (#636).
|
|
169
|
+
* both surface. Same-run Grok isolation only — no cross-run home override (#637).
|
|
174
170
|
*/
|
|
175
171
|
export async function withProductionGrokIsolation<T>(
|
|
176
172
|
runDirectory: string,
|
|
177
173
|
operatorHome: string,
|
|
178
174
|
packageRoot: string,
|
|
179
175
|
run: (binding: ProductionGrokIsolationBinding) => Promise<T>,
|
|
180
|
-
noteOpened?: (runDirectory: string) => void,
|
|
181
176
|
): Promise<T> {
|
|
182
177
|
let binding: ProductionGrokIsolationBinding | undefined;
|
|
183
178
|
let primaryFailure: ProductionGrokPrimaryFailure = NO_PRODUCTION_GROK_PRIMARY_FAILURE;
|
|
184
179
|
let value!: T;
|
|
185
180
|
try {
|
|
186
181
|
binding = await bindProductionGrokIsolation(runDirectory, operatorHome, packageRoot);
|
|
187
|
-
// Open fact: bind succeeded under runDirectory. Not deferred to turn outcome.
|
|
188
|
-
noteOpened?.(runDirectory);
|
|
189
182
|
value = await run(binding);
|
|
190
183
|
} catch (error) {
|
|
191
184
|
primaryFailure = { present: true, value: error };
|
|
@@ -285,26 +278,9 @@ async function recordGrokCapabilities(
|
|
|
285
278
|
);
|
|
286
279
|
}
|
|
287
280
|
|
|
288
|
-
/**
|
|
289
|
-
* Which run directory owns GROK_HOME for this turn (#636 / ADR 0077).
|
|
290
|
-
* Same-host ticket-seat resume reopens the prior native home; otherwise the live run.
|
|
291
|
-
* Private to the production host — not a test seam.
|
|
292
|
-
*/
|
|
293
|
-
function resolveProductionGrokIsolationRunDirectory(
|
|
294
|
-
request: Pick<RoleTurnRequest, "runDirectory" | "continuation" | "nativeHomeRunDirectory">,
|
|
295
|
-
): string {
|
|
296
|
-
if (
|
|
297
|
-
request.continuation.kind === "resume" &&
|
|
298
|
-
typeof request.nativeHomeRunDirectory === "string" &&
|
|
299
|
-
request.nativeHomeRunDirectory.length > 0
|
|
300
|
-
) {
|
|
301
|
-
return request.nativeHomeRunDirectory;
|
|
302
|
-
}
|
|
303
|
-
return request.runDirectory;
|
|
304
|
-
}
|
|
305
|
-
|
|
306
281
|
/**
|
|
307
282
|
* Assemble the production grok-build RoleTurnHost from the S6 true adapter.
|
|
283
|
+
* Isolation always under the live request.runDirectory (same-run resume keeps it).
|
|
308
284
|
*/
|
|
309
285
|
export function createProductionGrokRoleTurnHost(options: ProductionGrokHostOptions): RoleTurnHost {
|
|
310
286
|
const { packageRoot, principalAuthority } = options;
|
|
@@ -342,13 +318,9 @@ export function createProductionGrokRoleTurnHost(options: ProductionGrokHostOpti
|
|
|
342
318
|
|
|
343
319
|
return {
|
|
344
320
|
executeTurn(request) {
|
|
345
|
-
// #636 same-host ticket-seat resume: reopen the prior run's grok-home so
|
|
346
|
-
// session/load hits the ACP storage that bound the shared principal.
|
|
347
|
-
// Fresh runs and cross-host arrivals keep isolating under request.runDirectory.
|
|
348
|
-
const isolationRunDirectory = resolveProductionGrokIsolationRunDirectory(request);
|
|
349
321
|
const execution = serial.then(() =>
|
|
350
322
|
withProductionGrokIsolation(
|
|
351
|
-
|
|
323
|
+
request.runDirectory,
|
|
352
324
|
request.home,
|
|
353
325
|
packageRoot,
|
|
354
326
|
async (binding) => {
|
|
@@ -360,7 +332,6 @@ export function createProductionGrokRoleTurnHost(options: ProductionGrokHostOpti
|
|
|
360
332
|
turn = undefined;
|
|
361
333
|
}
|
|
362
334
|
},
|
|
363
|
-
request.noteNativeHomeOpened,
|
|
364
335
|
),
|
|
365
336
|
);
|
|
366
337
|
serial = execution.then(
|
|
@@ -539,16 +539,19 @@ export async function prepareGrokRoleEnvelope(options: {
|
|
|
539
539
|
const relay = fileURLToPath(new URL("./mcp-relay.mjs", import.meta.url));
|
|
540
540
|
let disposed = false;
|
|
541
541
|
// Tools execute in this process (relay is protocol-only). Mirror Pi's child-env
|
|
542
|
-
// AK_ROLE_RUN_DIR injection onto the parent so ledger
|
|
543
|
-
//
|
|
542
|
+
// AK_ROLE_RUN_DIR / AK_ROLE_COURT_ATTEMPT injection onto the parent so ledger
|
|
543
|
+
// runIdentity and court-attempt identity correlate with settlement. Inject only
|
|
544
544
|
// after prepare succeeds (below); dispose must restore including unset.
|
|
545
545
|
let priorAkRoleRunDir: string | undefined;
|
|
546
|
+
let priorAkRoleCourtAttempt: string | undefined;
|
|
546
547
|
let runDirInjected = false;
|
|
547
|
-
const
|
|
548
|
+
const restoreAkRoleRunEnv = (): void => {
|
|
548
549
|
if (!runDirInjected) return;
|
|
549
550
|
runDirInjected = false;
|
|
550
551
|
if (priorAkRoleRunDir === undefined) delete process.env.AK_ROLE_RUN_DIR;
|
|
551
552
|
else process.env.AK_ROLE_RUN_DIR = priorAkRoleRunDir;
|
|
553
|
+
if (priorAkRoleCourtAttempt === undefined) delete process.env.AK_ROLE_COURT_ATTEMPT;
|
|
554
|
+
else process.env.AK_ROLE_COURT_ATTEMPT = priorAkRoleCourtAttempt;
|
|
552
555
|
};
|
|
553
556
|
const dispose = async (): Promise<void> => {
|
|
554
557
|
if (disposed) return;
|
|
@@ -560,7 +563,7 @@ export async function prepareGrokRoleEnvelope(options: {
|
|
|
560
563
|
cleanupFailures.push(error);
|
|
561
564
|
}
|
|
562
565
|
try {
|
|
563
|
-
|
|
566
|
+
restoreAkRoleRunEnv();
|
|
564
567
|
} catch (error) {
|
|
565
568
|
cleanupFailures.push(error);
|
|
566
569
|
}
|
|
@@ -659,7 +662,10 @@ export async function prepareGrokRoleEnvelope(options: {
|
|
|
659
662
|
}
|
|
660
663
|
|
|
661
664
|
priorAkRoleRunDir = process.env.AK_ROLE_RUN_DIR;
|
|
665
|
+
priorAkRoleCourtAttempt = process.env.AK_ROLE_COURT_ATTEMPT;
|
|
662
666
|
process.env.AK_ROLE_RUN_DIR = request.runDirectory;
|
|
667
|
+
if (request.courtAttemptId === undefined) delete process.env.AK_ROLE_COURT_ATTEMPT;
|
|
668
|
+
else process.env.AK_ROLE_COURT_ATTEMPT = request.courtAttemptId;
|
|
663
669
|
runDirInjected = true;
|
|
664
670
|
|
|
665
671
|
return {
|
package/src/host-contracts.ts
CHANGED
|
@@ -166,18 +166,11 @@ export type RoleTurnRequest = {
|
|
|
166
166
|
/** Set by post-admission only on a real host switch; never on same-host resume. */
|
|
167
167
|
readonly hostTransition?: RoleTurnHostTransition;
|
|
168
168
|
/**
|
|
169
|
-
*
|
|
170
|
-
*
|
|
171
|
-
*
|
|
172
|
-
* Absent → isolate under runDirectory. Never a cross-host byte handoff.
|
|
169
|
+
* Same-ticket re-summons only (#637): opens a new court-turn attempt on the
|
|
170
|
+
* retained run so submission-ledger sole-final is per attempt, not forever.
|
|
171
|
+
* Manual resume never sets this — sealed idempotent short-circuit stays intact.
|
|
173
172
|
*/
|
|
174
|
-
readonly
|
|
175
|
-
/**
|
|
176
|
-
* Production Grok isolation notes the actual open event here after bind succeeds
|
|
177
|
-
* (#636). Open is not the same event as turn return/throw — post-admission uses
|
|
178
|
-
* this fact for last-host ownership instead of inferring open from the turn outcome.
|
|
179
|
-
*/
|
|
180
|
-
readonly noteNativeHomeOpened?: (runDirectory: string) => void;
|
|
173
|
+
readonly courtAttemptId?: string;
|
|
181
174
|
};
|
|
182
175
|
|
|
183
176
|
/** Turn result — only fields upper layers currently consume. */
|
|
@@ -72,17 +72,14 @@ export async function listGrokNativeRecordPaths(runDirectory: string): Promise<s
|
|
|
72
72
|
* Unknown host names → undefined (no inject). Empty native volume still
|
|
73
73
|
* yields a typed switch (empty path list).
|
|
74
74
|
*
|
|
75
|
-
* Grok native home lives under the run that wrote it
|
|
76
|
-
*
|
|
77
|
-
* the scan does not look at an empty fresh run (#636 / #617 DK-4).
|
|
75
|
+
* Grok native home lives under the live run that wrote it (#617 DK-4 / #637
|
|
76
|
+
* same-run resume). No cross-run previousRunDirectory override.
|
|
78
77
|
*/
|
|
79
78
|
export async function projectHostTransitionPriorNative(input: {
|
|
80
79
|
readonly previousHost: string;
|
|
81
80
|
readonly liveHost: string;
|
|
82
81
|
readonly runDirectory: string;
|
|
83
82
|
readonly piSessionFile: string;
|
|
84
|
-
/** Prior run that held Grok native records when principal continued across runs. */
|
|
85
|
-
readonly previousRunDirectory?: string;
|
|
86
83
|
}): Promise<RoleTurnHostTransition | undefined> {
|
|
87
84
|
if (input.previousHost === input.liveHost) return undefined;
|
|
88
85
|
if (!isKnownRoleTurnHost(input.previousHost) || !isKnownRoleTurnHost(input.liveHost)) {
|
|
@@ -96,8 +93,7 @@ export async function projectHostTransitionPriorNative(input: {
|
|
|
96
93
|
};
|
|
97
94
|
}
|
|
98
95
|
// previousHost === "grok-build": DK-7 path handoff only — do not read bytes.
|
|
99
|
-
const
|
|
100
|
-
const paths = await listGrokNativeRecordPaths(grokRoot);
|
|
96
|
+
const paths = await listGrokNativeRecordPaths(input.runDirectory);
|
|
101
97
|
return {
|
|
102
98
|
previousHost: "grok-build",
|
|
103
99
|
priorNativePaths: paths,
|
|
@@ -297,20 +297,4 @@ export function intervalRowsAroundAnchor(
|
|
|
297
297
|
return { rows: rows.slice(start, end), closed: end < rows.length };
|
|
298
298
|
}
|
|
299
299
|
|
|
300
|
-
|
|
301
|
-
* Interval owned by the first binding row that satisfies `matches`.
|
|
302
|
-
* `undefined` when the volume carries no matching binding — callers must not
|
|
303
|
-
* silently treat the whole continuous volume as that owner.
|
|
304
|
-
*/
|
|
305
|
-
export function intervalRowsForMatchingBinding(
|
|
306
|
-
rows: readonly LedgerSessionRow[],
|
|
307
|
-
isBindingRow: (row: LedgerSessionRow) => boolean,
|
|
308
|
-
matches: (row: LedgerSessionRow) => boolean,
|
|
309
|
-
): BindingInterval | undefined {
|
|
310
|
-
for (let i = 0; i < rows.length; i += 1) {
|
|
311
|
-
const row = rows[i]!;
|
|
312
|
-
if (!isBindingRow(row) || !matches(row)) continue;
|
|
313
|
-
return intervalRowsAroundAnchor(rows, i, isBindingRow);
|
|
314
|
-
}
|
|
315
|
-
return undefined;
|
|
316
|
-
}
|
|
300
|
+
|
|
@@ -634,8 +634,8 @@ export async function openPiInstitutionalSession(
|
|
|
634
634
|
}
|
|
635
635
|
|
|
636
636
|
// 7. Create AgentSession — thinking is opaque pass-through. Absent selection
|
|
637
|
-
// omits thinkingLevel (Pi default). Pi clamps unsupported levels itself;
|
|
638
|
-
// we do not re-check or invent defaults.
|
|
637
|
+
// omits thinkingLevel (Pi owns default). Pi clamps unsupported levels itself;
|
|
638
|
+
// we do not re-check or invent package defaults.
|
|
639
639
|
const { session } = await createAgentSession({
|
|
640
640
|
cwd: options.cwd,
|
|
641
641
|
model: effectiveModel,
|
|
@@ -651,6 +651,10 @@ export async function openPiInstitutionalSession(
|
|
|
651
651
|
...(options.toolsAllowlist === undefined ? {} : { tools: options.toolsAllowlist as string[] }),
|
|
652
652
|
...(customTools.length === 0 ? {} : { customTools }),
|
|
653
653
|
});
|
|
654
|
+
await session.setModel(effectiveModel);
|
|
655
|
+
if (options.selection.thinking !== undefined) {
|
|
656
|
+
session.setThinkingLevel(options.selection.thinking as any);
|
|
657
|
+
}
|
|
654
658
|
|
|
655
659
|
// 8. Event subscriptions
|
|
656
660
|
const listeners = new Set<(event: HostInstitutionalSessionEvent) => void>();
|
package/src/pi/role-turn-host.ts
CHANGED
|
@@ -50,6 +50,11 @@ export function buildExplicitInternalActivationArgs(
|
|
|
50
50
|
return ["--no-extensions", "-e", selectedRoleEntry, ...extraArgs];
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
+
/**
|
|
54
|
+
* Pi argv for seat model. Host only passes through resolved values — no local
|
|
55
|
+
* thinking whitelist and no package default fill. Bare provider/model omits
|
|
56
|
+
* --thinking so Pi owns its own default (#346/#384). Explicit thinking only.
|
|
57
|
+
*/
|
|
53
58
|
function buildSeatModelCliArgs(model: RoleTurnModelConfig | undefined): string[] {
|
|
54
59
|
if (model === undefined) return [];
|
|
55
60
|
return [
|
|
@@ -426,12 +431,16 @@ export function createPiRoleTurnHost(config: PiRoleTurnHostConfig): RoleTurnHost
|
|
|
426
431
|
config.extraPiArgs ?? [],
|
|
427
432
|
);
|
|
428
433
|
const args = buildExplicitInternalActivationArgs(roleEntry, extraArgs);
|
|
434
|
+
// Shared envelope isolates this call's court identity: omitting courtAttemptId
|
|
435
|
+
// must not inherit a parent process.env.AK_ROLE_COURT_ATTEMPT (#637).
|
|
429
436
|
const env: NodeJS.ProcessEnv = {
|
|
430
437
|
...process.env,
|
|
431
438
|
HOME: request.home,
|
|
432
439
|
PI_CODING_AGENT_DIR: request.agentDir,
|
|
433
440
|
AK_ROLE_RUN_DIR: request.runDirectory,
|
|
434
441
|
};
|
|
442
|
+
if (request.courtAttemptId === undefined) delete env.AK_ROLE_COURT_ATTEMPT;
|
|
443
|
+
else env.AK_ROLE_COURT_ATTEMPT = request.courtAttemptId;
|
|
435
444
|
applyEngineChildEnv(env, request.engine);
|
|
436
445
|
if (request.correlationId !== undefined && request.correlationId.trim() !== "") {
|
|
437
446
|
env.AK_CORRELATION_ID = request.correlationId;
|
|
@@ -160,16 +160,16 @@ export async function runPublicCollectorResume(
|
|
|
160
160
|
request,
|
|
161
161
|
env,
|
|
162
162
|
io,
|
|
163
|
-
load: () =>
|
|
163
|
+
load: (effective) =>
|
|
164
164
|
loadResumableCollectorRun(
|
|
165
165
|
env.home,
|
|
166
|
-
|
|
166
|
+
effective.runId,
|
|
167
167
|
env.principalAuthority,
|
|
168
168
|
),
|
|
169
|
-
buildTurnRequest: (admitted) =>
|
|
169
|
+
buildTurnRequest: (admitted, effective) =>
|
|
170
170
|
buildCollectorTurnRequest(
|
|
171
171
|
admitted,
|
|
172
|
-
resumeTurnRequestProjectionOptions(admitted,
|
|
172
|
+
resumeTurnRequestProjectionOptions(admitted, effective, env),
|
|
173
173
|
),
|
|
174
174
|
adapters: collectorAdapters(),
|
|
175
175
|
...(env.engine === undefined ? {} : { effectiveEngine: env.engine }),
|