@akagilnc/pi-workflow-roles 0.1.2068 → 0.1.2071
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/navigator-attendance.js +27 -24
- package/dist/public-cli/main.js +30 -166
- package/package.json +1 -1
- package/src/navigator-attendance.ts +51 -54
- package/src/public-cli/settlement.ts +33 -144
|
@@ -90,13 +90,6 @@ function navigatorUnavailableError(source, error, cause = source) {
|
|
|
90
90
|
const message = error instanceof Error ? error.message : String(error);
|
|
91
91
|
return error instanceof NavigatorUnavailableError ? error : new NavigatorUnavailableError(source, message, cause, error);
|
|
92
92
|
}
|
|
93
|
-
function navigatorAdviceConsistentWithSettlement(next, settlement) {
|
|
94
|
-
if (settlement.kind !== "accepted") return true;
|
|
95
|
-
if (settlement.status === "unfinished" && next.role === "judge") return false;
|
|
96
|
-
if (settlement.role === "fixer" && settlement.phase === "apply" && settlement.status === "completed" && next.role === "fixer" && next.phase === "apply") return false;
|
|
97
|
-
if (next.role !== "merger") return true;
|
|
98
|
-
return settlement.role === "judge" && settlement.status === "converged";
|
|
99
|
-
}
|
|
100
93
|
const prepareSchema = Type.Object({}, { additionalProperties: true });
|
|
101
94
|
const ROUTE_ENTRY = "ak-navigator-route";
|
|
102
95
|
const CONTEXT_ENTRY = "ak-navigator-context";
|
|
@@ -269,17 +262,29 @@ function selectNavigatorCandidate(candidates, settlement) {
|
|
|
269
262
|
if (settlement.kind !== "accepted") return void 0;
|
|
270
263
|
const usable = candidates.filter((candidate) => candidate.next !== void 0);
|
|
271
264
|
if (usable.length === 0) return void 0;
|
|
272
|
-
const
|
|
265
|
+
const rolePhaseMatched = usable.filter(
|
|
273
266
|
(candidate) => candidate.matches !== void 0 && candidate.matches.role === settlement.role && candidate.matches.phase === settlement.phase
|
|
274
267
|
);
|
|
275
|
-
if (
|
|
268
|
+
if (rolePhaseMatched.length > 0) {
|
|
276
269
|
if (settlement.status !== void 0) {
|
|
277
|
-
const statusSpecific =
|
|
278
|
-
|
|
270
|
+
const statusSpecific = rolePhaseMatched.find(
|
|
271
|
+
(candidate) => candidate.matches?.statuses?.includes(settlement.status) === true
|
|
272
|
+
);
|
|
273
|
+
if (statusSpecific !== void 0) {
|
|
274
|
+
return { candidate: statusSpecific, matchedToSettlement: true };
|
|
275
|
+
}
|
|
279
276
|
}
|
|
280
|
-
|
|
277
|
+
const rolePhaseGeneric = rolePhaseMatched.find(
|
|
278
|
+
(candidate) => candidate.matches?.statuses === void 0
|
|
279
|
+
);
|
|
280
|
+
if (rolePhaseGeneric !== void 0) {
|
|
281
|
+
return { candidate: rolePhaseGeneric, matchedToSettlement: true };
|
|
282
|
+
}
|
|
283
|
+
return void 0;
|
|
281
284
|
}
|
|
282
|
-
|
|
285
|
+
const unbound = usable.find((candidate) => candidate.matches === void 0);
|
|
286
|
+
if (unbound === void 0) return void 0;
|
|
287
|
+
return { candidate: unbound, matchedToSettlement: false };
|
|
283
288
|
}
|
|
284
289
|
function formatNavigatorReport(report) {
|
|
285
290
|
const playbookFailure = report.routePlaybookReadFailure === void 0 ? [] : [`\u8DEF\u4E66\u8BFB\u53D6\u5931\u8D25\uFF1A${oneLine(report.routePlaybookReadFailure)}`];
|
|
@@ -375,6 +380,7 @@ function createNavigatorAttendance(options) {
|
|
|
375
380
|
const prepare = async () => {
|
|
376
381
|
const boundSettlement = prepareBoundSettlement;
|
|
377
382
|
prepareBoundSettlement = void 0;
|
|
383
|
+
preparationNoReceipt = false;
|
|
378
384
|
const invocationId = invocationPrincipal;
|
|
379
385
|
activeInvocationId = invocationId;
|
|
380
386
|
if (contextError !== void 0) throw navigatorUnavailableError("context", contextError);
|
|
@@ -704,27 +710,25 @@ ${helpContext}
|
|
|
704
710
|
let prepared = await preparation;
|
|
705
711
|
session?.appendEntry(SETTLEMENT_ENTRY, { invocationId, subjectKey, role: settlement.role, phase: settlement.phase, kind: settlement.kind, ...settlement.status === void 0 ? {} : { status: settlement.status } });
|
|
706
712
|
let selected = selectNavigatorCandidate(prepared, settlement);
|
|
707
|
-
if (selected?.next !== void 0 && !
|
|
713
|
+
if (selected?.candidate.next !== void 0 && !selected.matchedToSettlement) {
|
|
708
714
|
prepareBoundSettlement = settlement;
|
|
709
715
|
prepared = await prepare();
|
|
710
716
|
selected = selectNavigatorCandidate(prepared, settlement);
|
|
711
|
-
if (selected?.next !== void 0 && !navigatorAdviceConsistentWithSettlement(selected.next, settlement)) {
|
|
712
|
-
throw new Error("Navigator advice contradicts the accepted settlement");
|
|
713
|
-
}
|
|
714
717
|
}
|
|
715
|
-
|
|
718
|
+
const selectedCandidate = selected?.candidate;
|
|
719
|
+
if (selectedCandidate?.next === void 0 && preparationNoReceipt) {
|
|
716
720
|
report = { disposition: "no-advice" };
|
|
717
|
-
} else if (
|
|
721
|
+
} else if (selectedCandidate?.next === void 0) {
|
|
718
722
|
throw new Error("Navigator prepared no machine-usable next direction");
|
|
719
723
|
} else {
|
|
720
|
-
const selectedRoute =
|
|
724
|
+
const selectedRoute = selectedCandidate.route;
|
|
721
725
|
const routeChanged = selectedRoute !== void 0 && !routeEqual(previousRoute, selectedRoute);
|
|
722
|
-
const command = renderPublicAkRoleCommand(
|
|
726
|
+
const command = renderPublicAkRoleCommand(selectedCandidate.next);
|
|
723
727
|
report = {
|
|
724
728
|
disposition: "recommendation",
|
|
725
729
|
...routeChanged ? { route: selectedRoute } : {},
|
|
726
|
-
next:
|
|
727
|
-
...
|
|
730
|
+
next: selectedCandidate.next,
|
|
731
|
+
...selectedCandidate.reason === void 0 ? {} : { reason: oneLine(selectedCandidate.reason) },
|
|
728
732
|
...command === void 0 ? {} : { command }
|
|
729
733
|
};
|
|
730
734
|
if (selectedRoute !== void 0) {
|
|
@@ -1056,7 +1060,6 @@ export {
|
|
|
1056
1060
|
createNavigatorPrepareTool,
|
|
1057
1061
|
decorateSettlementWithNavigation,
|
|
1058
1062
|
formatNavigatorReport,
|
|
1059
|
-
navigatorAdviceConsistentWithSettlement,
|
|
1060
1063
|
navigatorModelSettingPath,
|
|
1061
1064
|
navigatorProviderFailure,
|
|
1062
1065
|
navigatorProviderFailureFromError,
|
package/dist/public-cli/main.js
CHANGED
|
@@ -14295,9 +14295,6 @@ var init_merger_contracts = __esm({
|
|
|
14295
14295
|
});
|
|
14296
14296
|
|
|
14297
14297
|
// src/packaged-role-registry.ts
|
|
14298
|
-
function packagedRoleMetadata(role) {
|
|
14299
|
-
return PACKAGED_ROLE_REGISTRY.find((entry) => entry.role === role);
|
|
14300
|
-
}
|
|
14301
14298
|
var PACKAGED_ROLE_REGISTRY;
|
|
14302
14299
|
var init_packaged_role_registry = __esm({
|
|
14303
14300
|
"src/packaged-role-registry.ts"() {
|
|
@@ -14812,9 +14809,6 @@ function physicalPathIdentity(path) {
|
|
|
14812
14809
|
}
|
|
14813
14810
|
}
|
|
14814
14811
|
}
|
|
14815
|
-
function physicallyContainedIn(root, candidate) {
|
|
14816
|
-
return pathContainedIn(physicalPathIdentity(root), physicalPathIdentity(candidate));
|
|
14817
|
-
}
|
|
14818
14812
|
function errnoCode(error) {
|
|
14819
14813
|
return error !== null && typeof error === "object" && "code" in error && typeof error.code === "string" ? error.code : void 0;
|
|
14820
14814
|
}
|
|
@@ -19428,48 +19422,6 @@ var init_engine_detour = __esm({
|
|
|
19428
19422
|
});
|
|
19429
19423
|
|
|
19430
19424
|
// src/work-subject-identity.ts
|
|
19431
|
-
import { resolve as resolve6 } from "node:path";
|
|
19432
|
-
function issueRoot(value) {
|
|
19433
|
-
const normalized = value.replaceAll("\\", "/");
|
|
19434
|
-
const marker = ".ak/work/issues/";
|
|
19435
|
-
const index = normalized.indexOf(marker);
|
|
19436
|
-
if (index < 0) return void 0;
|
|
19437
|
-
const issue = normalized.slice(index + marker.length).split("/")[0]?.split("#")[0];
|
|
19438
|
-
return issue === void 0 || issue === "" ? void 0 : normalized.slice(0, index + marker.length) + issue;
|
|
19439
|
-
}
|
|
19440
|
-
function workIdentityFromCwd(cwd) {
|
|
19441
|
-
const resolvedCwd = resolve6(cwd, ".");
|
|
19442
|
-
const cwdIssue = issueRoot(resolvedCwd);
|
|
19443
|
-
if (cwdIssue !== void 0) return cwdIssue;
|
|
19444
|
-
if (resolvedCwd.includes("/.ak/work/")) return resolvedCwd;
|
|
19445
|
-
return void 0;
|
|
19446
|
-
}
|
|
19447
|
-
function isMachineLedgerSessionPath(sessionPath) {
|
|
19448
|
-
return physicallyContainedIn(resolveActivationLedgerHome(), sessionPath);
|
|
19449
|
-
}
|
|
19450
|
-
function subjectPath(sessionDir, cwd = process.cwd()) {
|
|
19451
|
-
if (sessionDir === "") {
|
|
19452
|
-
return workIdentityFromCwd(cwd) ?? resolve6(cwd, ".ak/work");
|
|
19453
|
-
}
|
|
19454
|
-
const resolvedSession = resolve6(cwd, sessionDir || ".ak/work");
|
|
19455
|
-
if (isMachineLedgerSessionPath(resolvedSession)) {
|
|
19456
|
-
return workIdentityFromCwd(cwd) ?? resolve6(cwd, ".ak/work");
|
|
19457
|
-
}
|
|
19458
|
-
const issue = issueRoot(resolvedSession);
|
|
19459
|
-
if (issue !== void 0) return issue;
|
|
19460
|
-
const runsMarker = "/runs/";
|
|
19461
|
-
const runsIndex = resolvedSession.indexOf(runsMarker);
|
|
19462
|
-
if (runsIndex >= 0) {
|
|
19463
|
-
return resolvedSession.slice(0, runsIndex);
|
|
19464
|
-
}
|
|
19465
|
-
return resolvedSession;
|
|
19466
|
-
}
|
|
19467
|
-
function workSubjectKeyFromProjectRoot(projectRoot) {
|
|
19468
|
-
return subjectPath("", projectRoot);
|
|
19469
|
-
}
|
|
19470
|
-
function workSubjectKeysEqual(left, right) {
|
|
19471
|
-
return physicalPathIdentity(left) === physicalPathIdentity(right);
|
|
19472
|
-
}
|
|
19473
19425
|
var init_work_subject_identity = __esm({
|
|
19474
19426
|
"src/work-subject-identity.ts"() {
|
|
19475
19427
|
"use strict";
|
|
@@ -19510,18 +19462,6 @@ function parseInvocationMarkerIdentity(data) {
|
|
|
19510
19462
|
subjectKey: record4.subjectKey
|
|
19511
19463
|
};
|
|
19512
19464
|
}
|
|
19513
|
-
function markerMatchesExpectedIdentity(marker, expected) {
|
|
19514
|
-
if (marker.role !== expected.role) return false;
|
|
19515
|
-
if (expected.phase !== void 0) {
|
|
19516
|
-
if (marker.phase !== expected.phase) return false;
|
|
19517
|
-
} else if (expected.allowedPhases !== void 0) {
|
|
19518
|
-
if (!expected.allowedPhases.includes(marker.phase)) return false;
|
|
19519
|
-
}
|
|
19520
|
-
if (expected.subjectKey !== void 0) {
|
|
19521
|
-
if (!workSubjectKeysEqual(marker.subjectKey, expected.subjectKey)) return false;
|
|
19522
|
-
}
|
|
19523
|
-
return true;
|
|
19524
|
-
}
|
|
19525
19465
|
function classifyPackagedRoleTerminalResult(message) {
|
|
19526
19466
|
if (typeof message.toolName !== "string") return { kind: "nonterminal" };
|
|
19527
19467
|
if (!PACKAGED_ROLE_OUTPUT_TOOLS.has(message.toolName)) return { kind: "nonterminal" };
|
|
@@ -21011,55 +20951,9 @@ function navigatorPhaseValue(value) {
|
|
|
21011
20951
|
if (value === "plan" || value === "apply") return value;
|
|
21012
20952
|
return null;
|
|
21013
20953
|
}
|
|
21014
|
-
function
|
|
21015
|
-
|
|
21016
|
-
if (admitted.role === "coder" || admitted.role === "fixer") {
|
|
21017
|
-
return { phase: admitted.phase, subjectKey };
|
|
21018
|
-
}
|
|
21019
|
-
return { phase: null, subjectKey };
|
|
21020
|
-
}
|
|
21021
|
-
function independentExpectedIdentity(entries, terminalRole, supplied) {
|
|
21022
|
-
let subjectKey;
|
|
21023
|
-
for (const entry of entries) {
|
|
21024
|
-
if (entry?.type !== "session") continue;
|
|
21025
|
-
if (typeof entry.cwd === "string" && entry.cwd.trim() !== "") {
|
|
21026
|
-
subjectKey = workSubjectKeyFromProjectRoot(entry.cwd);
|
|
21027
|
-
}
|
|
21028
|
-
break;
|
|
21029
|
-
}
|
|
21030
|
-
if (typeof supplied?.subjectKey === "string") {
|
|
21031
|
-
subjectKey = supplied.subjectKey;
|
|
21032
|
-
}
|
|
21033
|
-
let phase;
|
|
21034
|
-
let allowedPhases;
|
|
21035
|
-
if (supplied !== void 0 && Object.hasOwn(supplied, "phase")) {
|
|
21036
|
-
phase = supplied.phase ?? null;
|
|
21037
|
-
} else {
|
|
21038
|
-
const meta = packagedRoleMetadata(terminalRole);
|
|
21039
|
-
if (meta !== void 0) {
|
|
21040
|
-
if (meta.phases.length === 1) {
|
|
21041
|
-
phase = meta.phases[0];
|
|
21042
|
-
} else {
|
|
21043
|
-
allowedPhases = meta.phases;
|
|
21044
|
-
}
|
|
21045
|
-
}
|
|
21046
|
-
}
|
|
21047
|
-
return {
|
|
21048
|
-
role: terminalRole,
|
|
21049
|
-
...phase !== void 0 ? { phase } : {},
|
|
21050
|
-
...allowedPhases !== void 0 ? { allowedPhases } : {},
|
|
21051
|
-
...subjectKey !== void 0 ? { subjectKey } : {}
|
|
21052
|
-
};
|
|
21053
|
-
}
|
|
21054
|
-
function navigatorAttendanceCorrelatedWithBoundMarker(details, attendanceIndex, terminal, marker) {
|
|
21055
|
-
if (attendanceIndex <= terminal.index) return false;
|
|
21056
|
-
if (details.version !== 1) return false;
|
|
21057
|
-
if (details.role !== terminal.role) return false;
|
|
21058
|
-
if (details.role !== marker.role) return false;
|
|
20954
|
+
function navigatorAttendanceCorrelatedWithBoundMarker(details, attendanceIndex, terminalIndex, marker) {
|
|
20955
|
+
if (attendanceIndex <= terminalIndex) return false;
|
|
21059
20956
|
if (details.invocationId !== marker.invocationId) return false;
|
|
21060
|
-
if (details.phase !== marker.phase) return false;
|
|
21061
|
-
if (typeof details.subjectKey !== "string") return false;
|
|
21062
|
-
if (!workSubjectKeysEqual(details.subjectKey, marker.subjectKey)) return false;
|
|
21063
20957
|
return true;
|
|
21064
20958
|
}
|
|
21065
20959
|
function parseNavigatorAttendanceDetails(details) {
|
|
@@ -21110,39 +21004,32 @@ function parseNavigatorAttendanceDetails(details) {
|
|
|
21110
21004
|
reason: "Navigator attendance disposition is unparseable"
|
|
21111
21005
|
};
|
|
21112
21006
|
}
|
|
21113
|
-
function extractNavigatorFact(entries
|
|
21114
|
-
const
|
|
21115
|
-
if (
|
|
21007
|
+
function extractNavigatorFact(entries) {
|
|
21008
|
+
const terminal = findLatestDurablePackagedRoleTerminal(entries);
|
|
21009
|
+
if (terminal === void 0) {
|
|
21116
21010
|
return {
|
|
21117
21011
|
disposition: "unavailable",
|
|
21118
21012
|
source: "unknown",
|
|
21119
21013
|
reason: "Navigator attendance has no durable packaged role terminal"
|
|
21120
21014
|
};
|
|
21121
21015
|
}
|
|
21122
|
-
|
|
21123
|
-
|
|
21124
|
-
|
|
21125
|
-
|
|
21126
|
-
|
|
21127
|
-
|
|
21128
|
-
|
|
21129
|
-
if (binding.kind === "unbound") {
|
|
21130
|
-
return {
|
|
21131
|
-
disposition: "unavailable",
|
|
21132
|
-
source: "unknown",
|
|
21133
|
-
reason: "Navigator attendance is uncorrelated with session invocation facts"
|
|
21134
|
-
};
|
|
21016
|
+
let markerIndex = -1;
|
|
21017
|
+
for (let i = terminal.index - 1; i >= 0; i -= 1) {
|
|
21018
|
+
const entry = entries[i];
|
|
21019
|
+
if (entry?.type === "custom" && entry.customType === NAVIGATOR_INVOCATION_ENTRY) {
|
|
21020
|
+
markerIndex = i;
|
|
21021
|
+
break;
|
|
21022
|
+
}
|
|
21135
21023
|
}
|
|
21136
|
-
|
|
21137
|
-
if (marker.role !== terminal.role) {
|
|
21024
|
+
if (markerIndex < 0) {
|
|
21138
21025
|
return {
|
|
21139
21026
|
disposition: "unavailable",
|
|
21140
21027
|
source: "unknown",
|
|
21141
21028
|
reason: "Navigator attendance is uncorrelated with session invocation facts"
|
|
21142
21029
|
};
|
|
21143
21030
|
}
|
|
21144
|
-
const
|
|
21145
|
-
if (
|
|
21031
|
+
const marker = parseInvocationMarkerIdentity(entries[markerIndex]?.data);
|
|
21032
|
+
if (marker === void 0) {
|
|
21146
21033
|
return {
|
|
21147
21034
|
disposition: "unavailable",
|
|
21148
21035
|
source: "unknown",
|
|
@@ -21163,7 +21050,7 @@ function extractNavigatorFact(entries, identity) {
|
|
|
21163
21050
|
if (!navigatorAttendanceCorrelatedWithBoundMarker(
|
|
21164
21051
|
details,
|
|
21165
21052
|
i,
|
|
21166
|
-
|
|
21053
|
+
terminal.index,
|
|
21167
21054
|
marker
|
|
21168
21055
|
)) {
|
|
21169
21056
|
return {
|
|
@@ -21184,7 +21071,7 @@ function extractNavigatorFact(entries, identity) {
|
|
|
21184
21071
|
async function extractNavigatorFactFromAdmittedSession(admitted) {
|
|
21185
21072
|
try {
|
|
21186
21073
|
const entries = await readBoundSessionEntries(admitted.sessionFile);
|
|
21187
|
-
return extractNavigatorFact(entries
|
|
21074
|
+
return extractNavigatorFact(entries);
|
|
21188
21075
|
} catch (error) {
|
|
21189
21076
|
if (isMissingPathError2(error)) {
|
|
21190
21077
|
return {
|
|
@@ -21347,10 +21234,7 @@ async function settleLawfulJudgeTerminalResult(admitted) {
|
|
|
21347
21234
|
if (roleOutcome === void 0) {
|
|
21348
21235
|
return void 0;
|
|
21349
21236
|
}
|
|
21350
|
-
const navigator = extractNavigatorFact(
|
|
21351
|
-
entries,
|
|
21352
|
-
attendanceIdentityFromAdmitted(admitted)
|
|
21353
|
-
);
|
|
21237
|
+
const navigator = extractNavigatorFact(entries);
|
|
21354
21238
|
const artifacts = await publishJudgeArtifacts(
|
|
21355
21239
|
admitted,
|
|
21356
21240
|
roleOutcome,
|
|
@@ -21371,10 +21255,7 @@ async function settleLawfulCoderTerminalResult(admitted, options = {}) {
|
|
|
21371
21255
|
if (entries === void 0) return void 0;
|
|
21372
21256
|
const extracted = extractCoderRoleOutcome(entries);
|
|
21373
21257
|
if (extracted === void 0) return void 0;
|
|
21374
|
-
const navigator = extractNavigatorFact(
|
|
21375
|
-
entries,
|
|
21376
|
-
attendanceIdentityFromAdmitted(admitted)
|
|
21377
|
-
);
|
|
21258
|
+
const navigator = extractNavigatorFact(entries);
|
|
21378
21259
|
const artifacts = await publishCoderArtifacts(
|
|
21379
21260
|
admitted,
|
|
21380
21261
|
extracted.outcome,
|
|
@@ -21506,10 +21387,7 @@ async function settleLawfulFixerTerminalResult(admitted, options) {
|
|
|
21506
21387
|
if (entries === void 0) return void 0;
|
|
21507
21388
|
const extracted = extractFixerRoleOutcome(entries);
|
|
21508
21389
|
if (extracted === void 0) return void 0;
|
|
21509
|
-
const navigator = extractNavigatorFact(
|
|
21510
|
-
entries,
|
|
21511
|
-
attendanceIdentityFromAdmitted(admitted)
|
|
21512
|
-
);
|
|
21390
|
+
const navigator = extractNavigatorFact(entries);
|
|
21513
21391
|
const methodInvocations = extractFixerMethodInvocations(entries, {
|
|
21514
21392
|
allowedLocations: [
|
|
21515
21393
|
options.methodSkillPath,
|
|
@@ -21635,10 +21513,7 @@ async function settleLawfulCollectorTerminalResult(admitted) {
|
|
|
21635
21513
|
return void 0;
|
|
21636
21514
|
}
|
|
21637
21515
|
assertCollectorReceiptMatchesAdmitted(extracted.receipt, admitted);
|
|
21638
|
-
const navigator = extractNavigatorFact(
|
|
21639
|
-
entries,
|
|
21640
|
-
attendanceIdentityFromAdmitted(admitted)
|
|
21641
|
-
);
|
|
21516
|
+
const navigator = extractNavigatorFact(entries);
|
|
21642
21517
|
const artifacts = await publishCollectorArtifacts(
|
|
21643
21518
|
admitted,
|
|
21644
21519
|
extracted.outcome,
|
|
@@ -21762,10 +21637,7 @@ async function settleLawfulDoctorTerminalResult(admitted) {
|
|
|
21762
21637
|
throw error;
|
|
21763
21638
|
}
|
|
21764
21639
|
}
|
|
21765
|
-
const navigator = extractNavigatorFact(
|
|
21766
|
-
entries,
|
|
21767
|
-
attendanceIdentityFromAdmitted(admitted)
|
|
21768
|
-
);
|
|
21640
|
+
const navigator = extractNavigatorFact(entries);
|
|
21769
21641
|
const artifacts = await publishDoctorArtifacts(
|
|
21770
21642
|
admitted,
|
|
21771
21643
|
extracted.outcome,
|
|
@@ -21926,10 +21798,7 @@ async function settleLawfulReviewerTerminalResult(admitted, options) {
|
|
|
21926
21798
|
if (entries === void 0) return void 0;
|
|
21927
21799
|
const extracted = extractReviewerRoleOutcome(entries);
|
|
21928
21800
|
if (extracted === void 0) return void 0;
|
|
21929
|
-
const navigator = extractNavigatorFact(
|
|
21930
|
-
entries,
|
|
21931
|
-
attendanceIdentityFromAdmitted(admitted)
|
|
21932
|
-
);
|
|
21801
|
+
const navigator = extractNavigatorFact(entries);
|
|
21933
21802
|
const methodInvocations = extractReviewerMethodInvocations(entries, {
|
|
21934
21803
|
allowedLocations: [
|
|
21935
21804
|
options.methodSkillPath,
|
|
@@ -22109,10 +21978,7 @@ async function settleLawfulMergerTerminalResult(admitted, options) {
|
|
|
22109
21978
|
]
|
|
22110
21979
|
});
|
|
22111
21980
|
if (methodInvocations.length === 0) return void 0;
|
|
22112
|
-
const navigator = extractNavigatorFact(
|
|
22113
|
-
entries,
|
|
22114
|
-
attendanceIdentityFromAdmitted(admitted)
|
|
22115
|
-
);
|
|
21981
|
+
const navigator = extractNavigatorFact(entries);
|
|
22116
21982
|
const artifacts = await publishMergerArtifacts(
|
|
22117
21983
|
admitted,
|
|
22118
21984
|
extracted.outcome,
|
|
@@ -22439,8 +22305,6 @@ var init_settlement = __esm({
|
|
|
22439
22305
|
init_method_skill();
|
|
22440
22306
|
init_navigator_invocation_identity();
|
|
22441
22307
|
init_receipt_delivery_policy();
|
|
22442
|
-
init_packaged_role_registry();
|
|
22443
|
-
init_work_subject_identity();
|
|
22444
22308
|
init_invocation();
|
|
22445
22309
|
init_terminal();
|
|
22446
22310
|
CONCISE_DIAGNOSTIC_MAX_CHARS = 480;
|
|
@@ -24040,7 +23904,7 @@ var init_judge_run = __esm({
|
|
|
24040
23904
|
|
|
24041
23905
|
// src/public-cli/merger-run.ts
|
|
24042
23906
|
import { mkdir as mkdir4, writeFile as writeFile11 } from "node:fs/promises";
|
|
24043
|
-
import { join as join17, resolve as
|
|
23907
|
+
import { join as join17, resolve as resolve6 } from "node:path";
|
|
24044
23908
|
function buildMergerActivationExtraArgs(admitted, options) {
|
|
24045
23909
|
const prompt = buildMergerTransportPrompt(admitted);
|
|
24046
23910
|
const skillPath = resolvePackagedMethodSkillPath(
|
|
@@ -24265,7 +24129,7 @@ async function loadMergerMethodMaterial(packageRoot2) {
|
|
|
24265
24129
|
);
|
|
24266
24130
|
}
|
|
24267
24131
|
async function admitMergerShellForActivationFailure(options) {
|
|
24268
|
-
const projectRoot =
|
|
24132
|
+
const projectRoot = resolve6(options.project ?? options.cwd);
|
|
24269
24133
|
const runId = (options.createRunId ?? uuidv7)();
|
|
24270
24134
|
const { ledgerHome, bookKey, runDirectory, sessionDirectory, sessionFile } = roleRunSessionCoordinates({ cwd: projectRoot, runId, role: "merger", home: options.home });
|
|
24271
24135
|
ensureRealDirectoryTree(ledgerHome, sessionDirectory);
|
|
@@ -24920,8 +24784,8 @@ var init_atomic_write = __esm({
|
|
|
24920
24784
|
import { open as open3, readFile as readFile10, unlink as unlink4 } from "node:fs/promises";
|
|
24921
24785
|
import { dirname as dirname8, join as join20 } from "node:path";
|
|
24922
24786
|
function sleep(ms) {
|
|
24923
|
-
return new Promise((
|
|
24924
|
-
setTimeout(
|
|
24787
|
+
return new Promise((resolve8) => {
|
|
24788
|
+
setTimeout(resolve8, ms);
|
|
24925
24789
|
});
|
|
24926
24790
|
}
|
|
24927
24791
|
async function withTaishiLibraryIndexLock(ledgerHome, fn) {
|
|
@@ -26808,7 +26672,7 @@ var init_taishi_entry = __esm({
|
|
|
26808
26672
|
|
|
26809
26673
|
// src/public-cli/taishi-run.ts
|
|
26810
26674
|
import { readFile as readFile15 } from "node:fs/promises";
|
|
26811
|
-
import { isAbsolute as isAbsolute5, resolve as
|
|
26675
|
+
import { isAbsolute as isAbsolute5, resolve as resolve7 } from "node:path";
|
|
26812
26676
|
async function buildTaishiIssueModeInputFromPublicArgv(parsed, ledgerHome) {
|
|
26813
26677
|
const ticket = parsed.ticket;
|
|
26814
26678
|
const directRoot = parsed.projectRoot;
|
|
@@ -26854,7 +26718,7 @@ async function buildTaishiSweepModeInputFromAttachmentPaths(attachmentPaths) {
|
|
|
26854
26718
|
);
|
|
26855
26719
|
}
|
|
26856
26720
|
const sourcePath = attachmentPaths[0];
|
|
26857
|
-
const absolute = isAbsolute5(sourcePath) ? sourcePath :
|
|
26721
|
+
const absolute = isAbsolute5(sourcePath) ? sourcePath : resolve7(sourcePath);
|
|
26858
26722
|
let bytes;
|
|
26859
26723
|
try {
|
|
26860
26724
|
bytes = await readFile15(absolute);
|
package/package.json
CHANGED
|
@@ -197,33 +197,6 @@ export type NavigatorContextProjection = {
|
|
|
197
197
|
liveRoleHelp: Array<{ role: NavigatorTargetRole; help: string }>;
|
|
198
198
|
};
|
|
199
199
|
|
|
200
|
-
/**
|
|
201
|
-
* Shared terminal-internal consistency for Navigator advice vs the just-accepted
|
|
202
|
-
* settlement (family #224/#226/#227). One table for all seats — not per-role guards.
|
|
203
|
-
*
|
|
204
|
-
* Merger closes delivery. It is only consistent immediately after judge converged.
|
|
205
|
-
* Fresh accepted work from any other seat must not skip to merger.
|
|
206
|
-
*
|
|
207
|
-
* Unfinished is an open handoff (ADR 0050): recommending judge would send half-done
|
|
208
|
-
* work to audit. Machine criterion anchors only status=unfinished — refused and
|
|
209
|
-
* partially_completed remain settled terminals whose judge path stays lawful.
|
|
210
|
-
* Positive continuation is free-form via rebind + status-matched candidates
|
|
211
|
-
* (ADR 0010/0061); this only suppresses self-contradictory typed emission.
|
|
212
|
-
*/
|
|
213
|
-
export function navigatorAdviceConsistentWithSettlement(
|
|
214
|
-
next: NavigatorRouteTarget,
|
|
215
|
-
settlement: NavigatorSettlement,
|
|
216
|
-
): boolean {
|
|
217
|
-
if (settlement.kind !== "accepted") return true;
|
|
218
|
-
// #227: open unfinished handoff must not be typed as next=judge.
|
|
219
|
-
if (settlement.status === "unfinished" && next.role === "judge") return false;
|
|
220
|
-
// #265: completed Fixer apply must not be sent back to repeat the same work.
|
|
221
|
-
if (settlement.role === "fixer" && settlement.phase === "apply" && settlement.status === "completed"
|
|
222
|
-
&& next.role === "fixer" && next.phase === "apply") return false;
|
|
223
|
-
if (next.role !== "merger") return true;
|
|
224
|
-
return settlement.role === "judge" && settlement.status === "converged";
|
|
225
|
-
}
|
|
226
|
-
|
|
227
200
|
// Provider admission is ADR 0060 object root only. Nested advisory shape
|
|
228
201
|
// (candidates/next/route/matches/reason/command) is never a gate — every object
|
|
229
202
|
// root reaches the unique execute/normalize path exactly once.
|
|
@@ -478,25 +451,52 @@ export function createNavigatorPrepareTool(onOutput: (value: PrepareOutput) => v
|
|
|
478
451
|
});
|
|
479
452
|
}
|
|
480
453
|
|
|
481
|
-
|
|
454
|
+
/**
|
|
455
|
+
* Candidate pick plus whether matches keyed it to this settlement.
|
|
456
|
+
* Single owner for role/phase/status match truth (selection ranking + stale-context rebind).
|
|
457
|
+
* Structural only — never inspects next.role for routing legality.
|
|
458
|
+
*/
|
|
459
|
+
export type NavigatorCandidateSelection = {
|
|
460
|
+
readonly candidate: NavigatorCandidate;
|
|
461
|
+
/** True when matches keyed this candidate to the settlement (no stale-context rebind). */
|
|
462
|
+
readonly matchedToSettlement: boolean;
|
|
463
|
+
};
|
|
464
|
+
|
|
465
|
+
export function selectNavigatorCandidate(
|
|
466
|
+
candidates: readonly NavigatorCandidate[],
|
|
467
|
+
settlement: NavigatorSettlement,
|
|
468
|
+
): NavigatorCandidateSelection | undefined {
|
|
482
469
|
if (settlement.kind !== "accepted") return undefined;
|
|
483
470
|
const usable = candidates.filter((candidate) => candidate.next !== undefined);
|
|
484
471
|
if (usable.length === 0) return undefined;
|
|
485
|
-
const
|
|
472
|
+
const rolePhaseMatched = usable.filter((candidate) =>
|
|
486
473
|
candidate.matches !== undefined
|
|
487
474
|
&& candidate.matches.role === settlement.role
|
|
488
475
|
&& candidate.matches.phase === settlement.phase,
|
|
489
476
|
);
|
|
490
477
|
// Status-specific candidates outrank role/phase generics regardless of declaration order.
|
|
491
|
-
if (
|
|
478
|
+
if (rolePhaseMatched.length > 0) {
|
|
492
479
|
if (settlement.status !== undefined) {
|
|
493
|
-
const statusSpecific =
|
|
494
|
-
|
|
480
|
+
const statusSpecific = rolePhaseMatched.find(
|
|
481
|
+
(candidate) => candidate.matches?.statuses?.includes(settlement.status!) === true,
|
|
482
|
+
);
|
|
483
|
+
if (statusSpecific !== undefined) {
|
|
484
|
+
return { candidate: statusSpecific, matchedToSettlement: true };
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
const rolePhaseGeneric = rolePhaseMatched.find(
|
|
488
|
+
(candidate) => candidate.matches?.statuses === undefined,
|
|
489
|
+
);
|
|
490
|
+
if (rolePhaseGeneric !== undefined) {
|
|
491
|
+
return { candidate: rolePhaseGeneric, matchedToSettlement: true };
|
|
495
492
|
}
|
|
496
|
-
return
|
|
493
|
+
return undefined;
|
|
497
494
|
}
|
|
498
495
|
// v1 direction-only / broken matches: absent match metadata must not drop a usable next.
|
|
499
|
-
|
|
496
|
+
// Not settlement-keyed → caller may run one stale-context rebind.
|
|
497
|
+
const unbound = usable.find((candidate) => candidate.matches === undefined);
|
|
498
|
+
if (unbound === undefined) return undefined;
|
|
499
|
+
return { candidate: unbound, matchedToSettlement: false };
|
|
500
500
|
}
|
|
501
501
|
|
|
502
502
|
export function formatNavigatorReport(report: NavigatorReport): string {
|
|
@@ -631,6 +631,9 @@ export function createNavigatorAttendance(options: NavigatorAttendanceOptions) {
|
|
|
631
631
|
// pi.appendEntry at lifecycle start — not optional sessionManager probing.
|
|
632
632
|
const boundSettlement = prepareBoundSettlement;
|
|
633
633
|
prepareBoundSettlement = undefined;
|
|
634
|
+
// Each prepare owns the no-receipt flag; a later settlement-bound rebind must
|
|
635
|
+
// not inherit a speculative no-receipt outcome.
|
|
636
|
+
preparationNoReceipt = false;
|
|
634
637
|
const invocationId = invocationPrincipal;
|
|
635
638
|
activeInvocationId = invocationId;
|
|
636
639
|
if (contextError !== undefined) throw navigatorUnavailableError("context", contextError);
|
|
@@ -958,40 +961,34 @@ export function createNavigatorAttendance(options: NavigatorAttendanceOptions) {
|
|
|
958
961
|
let prepared = await preparation;
|
|
959
962
|
session?.appendEntry(SETTLEMENT_ENTRY, { invocationId, subjectKey, role: settlement.role, phase: settlement.phase, kind: settlement.kind, ...(settlement.status === undefined ? {} : { status: settlement.status }) });
|
|
960
963
|
let selected = selectNavigatorCandidate(prepared, settlement);
|
|
961
|
-
//
|
|
962
|
-
//
|
|
963
|
-
//
|
|
964
|
-
//
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
) {
|
|
964
|
+
// Speculative prepare runs before this terminal exists and may treat prior
|
|
965
|
+
// history as decisive. When selection provenance says matches did not key
|
|
966
|
+
// this candidate to the settlement, rebind once with currentSettlement.
|
|
967
|
+
// Stale-context repair only — reachable without any next.role legality
|
|
968
|
+
// table. After selection (speculative or rebound), advice is passed
|
|
969
|
+
// through as-is (ADR 0010 / ADR 0061: caller may ignore).
|
|
970
|
+
if (selected?.candidate.next !== undefined && !selected.matchedToSettlement) {
|
|
969
971
|
prepareBoundSettlement = settlement;
|
|
970
972
|
prepared = await prepare();
|
|
971
973
|
selected = selectNavigatorCandidate(prepared, settlement);
|
|
972
|
-
if (
|
|
973
|
-
selected?.next !== undefined
|
|
974
|
-
&& !navigatorAdviceConsistentWithSettlement(selected.next, settlement)
|
|
975
|
-
) {
|
|
976
|
-
throw new Error("Navigator advice contradicts the accepted settlement");
|
|
977
|
-
}
|
|
978
974
|
}
|
|
979
975
|
// Budget exhaustion is affirmative typed no-advice; malformed submitted
|
|
980
976
|
// advice remains the existing unavailable path.
|
|
981
|
-
|
|
977
|
+
const selectedCandidate = selected?.candidate;
|
|
978
|
+
if (selectedCandidate?.next === undefined && preparationNoReceipt) {
|
|
982
979
|
report = { disposition: "no-advice" };
|
|
983
|
-
} else if (
|
|
980
|
+
} else if (selectedCandidate?.next === undefined) {
|
|
984
981
|
throw new Error("Navigator prepared no machine-usable next direction");
|
|
985
982
|
} else {
|
|
986
|
-
const selectedRoute =
|
|
983
|
+
const selectedRoute = selectedCandidate.route;
|
|
987
984
|
const routeChanged = selectedRoute !== undefined && !routeEqual(previousRoute, selectedRoute);
|
|
988
985
|
// Single owner: public registry renderer (ADR 0052). Model command prose is never authority.
|
|
989
|
-
const command = renderPublicAkRoleCommand(
|
|
986
|
+
const command = renderPublicAkRoleCommand(selectedCandidate.next);
|
|
990
987
|
report = {
|
|
991
988
|
disposition: "recommendation",
|
|
992
989
|
...(routeChanged ? { route: selectedRoute } : {}),
|
|
993
|
-
next:
|
|
994
|
-
...(
|
|
990
|
+
next: selectedCandidate.next,
|
|
991
|
+
...(selectedCandidate.reason === undefined ? {} : { reason: oneLine(selectedCandidate.reason) }),
|
|
995
992
|
...(command === undefined ? {} : { command }),
|
|
996
993
|
};
|
|
997
994
|
if (selectedRoute !== undefined) {
|
|
@@ -73,21 +73,16 @@ import {
|
|
|
73
73
|
type PackagedMethodSkillProvenance,
|
|
74
74
|
} from "../package-resources/method-skill.ts";
|
|
75
75
|
import {
|
|
76
|
-
bindCurrentDurableTerminalToMarker,
|
|
77
76
|
classifyPackagedRoleTerminalResult,
|
|
77
|
+
findLatestDurablePackagedRoleTerminal,
|
|
78
78
|
isAcceptedPackagedRoleTerminalResult,
|
|
79
79
|
isReceiptSettlementBindingClear,
|
|
80
|
-
|
|
81
|
-
|
|
80
|
+
NAVIGATOR_INVOCATION_ENTRY,
|
|
81
|
+
parseInvocationMarkerIdentity,
|
|
82
82
|
type InvocationMarkerIdentity,
|
|
83
83
|
} from "../navigator-invocation-identity.ts";
|
|
84
84
|
import type { NavigatorPhase } from "../navigator-attendance.ts";
|
|
85
85
|
import { NO_RECEIPT_LIFECYCLE_ENTRY_TYPE, parseNoReceiptLifecycleFacts, type NoReceiptLifecycleFacts } from "../receipt-delivery-policy.ts";
|
|
86
|
-
import { packagedRoleMetadata } from "../packaged-role-registry.ts";
|
|
87
|
-
import {
|
|
88
|
-
workSubjectKeyFromProjectRoot,
|
|
89
|
-
workSubjectKeysEqual,
|
|
90
|
-
} from "../work-subject-identity.ts";
|
|
91
86
|
import {
|
|
92
87
|
ensureRunArtifactsDir,
|
|
93
88
|
type AdmittedCoderInvocation,
|
|
@@ -493,12 +488,6 @@ type SessionEntry = {
|
|
|
493
488
|
parentSession?: string;
|
|
494
489
|
};
|
|
495
490
|
|
|
496
|
-
/** Optional independent identity from admitted/shared lifecycle (not attendance self-fields). */
|
|
497
|
-
export type NavigatorAttendanceIdentity = {
|
|
498
|
-
readonly phase?: NavigatorPhase;
|
|
499
|
-
readonly subjectKey?: string;
|
|
500
|
-
};
|
|
501
|
-
|
|
502
491
|
function isMissingPathError(error: unknown): boolean {
|
|
503
492
|
return (
|
|
504
493
|
error instanceof Error &&
|
|
@@ -2001,91 +1990,20 @@ function navigatorPhaseValue(value: unknown): NavigatorPhase {
|
|
|
2001
1990
|
return null;
|
|
2002
1991
|
}
|
|
2003
1992
|
|
|
2004
|
-
function attendanceIdentityFromAdmitted(
|
|
2005
|
-
admitted: AdmittedRoleInvocation,
|
|
2006
|
-
): NavigatorAttendanceIdentity {
|
|
2007
|
-
// Public CLI sessions live under the machine ledger; Navigator derives subject from
|
|
2008
|
-
// the project/cwd work identity, not the per-run session directory spelling.
|
|
2009
|
-
const subjectKey = workSubjectKeyFromProjectRoot(admitted.projectRoot);
|
|
2010
|
-
if (admitted.role === "coder" || admitted.role === "fixer") {
|
|
2011
|
-
return { phase: admitted.phase, subjectKey };
|
|
2012
|
-
}
|
|
2013
|
-
return { phase: null, subjectKey };
|
|
2014
|
-
}
|
|
2015
|
-
|
|
2016
1993
|
/**
|
|
2017
|
-
*
|
|
2018
|
-
*
|
|
2019
|
-
*
|
|
2020
|
-
*/
|
|
2021
|
-
function independentExpectedIdentity(
|
|
2022
|
-
entries: readonly SessionEntry[],
|
|
2023
|
-
terminalRole: string,
|
|
2024
|
-
supplied?: NavigatorAttendanceIdentity,
|
|
2025
|
-
): ExpectedInvocationIdentity {
|
|
2026
|
-
let subjectKey: string | undefined;
|
|
2027
|
-
for (const entry of entries) {
|
|
2028
|
-
if (entry?.type !== "session") continue;
|
|
2029
|
-
if (typeof entry.cwd === "string" && entry.cwd.trim() !== "") {
|
|
2030
|
-
subjectKey = workSubjectKeyFromProjectRoot(entry.cwd);
|
|
2031
|
-
}
|
|
2032
|
-
break;
|
|
2033
|
-
}
|
|
2034
|
-
if (typeof supplied?.subjectKey === "string") {
|
|
2035
|
-
subjectKey = supplied.subjectKey;
|
|
2036
|
-
}
|
|
2037
|
-
|
|
2038
|
-
let phase: NavigatorPhase | undefined;
|
|
2039
|
-
let allowedPhases: readonly NavigatorPhase[] | undefined;
|
|
2040
|
-
// null is a real phase fact (Judge/Reviewer/…); only omit when not independently known.
|
|
2041
|
-
if (supplied !== undefined && Object.hasOwn(supplied, "phase")) {
|
|
2042
|
-
phase = supplied.phase ?? null;
|
|
2043
|
-
} else {
|
|
2044
|
-
const meta = packagedRoleMetadata(terminalRole);
|
|
2045
|
-
if (meta !== undefined) {
|
|
2046
|
-
if (meta.phases.length === 1) {
|
|
2047
|
-
phase = meta.phases[0] as NavigatorPhase;
|
|
2048
|
-
} else {
|
|
2049
|
-
allowedPhases = meta.phases as readonly NavigatorPhase[];
|
|
2050
|
-
}
|
|
2051
|
-
}
|
|
2052
|
-
}
|
|
2053
|
-
|
|
2054
|
-
return {
|
|
2055
|
-
role: terminalRole,
|
|
2056
|
-
...(phase !== undefined ? { phase } : {}),
|
|
2057
|
-
...(allowedPhases !== undefined ? { allowedPhases } : {}),
|
|
2058
|
-
...(subjectKey !== undefined ? { subjectKey } : {}),
|
|
2059
|
-
};
|
|
2060
|
-
}
|
|
2061
|
-
|
|
2062
|
-
/**
|
|
2063
|
-
* Attendance must match the bound marker identity and current durable terminal role.
|
|
2064
|
-
* Self-shape of attendance fields is not correlation. Marker already matched the
|
|
2065
|
-
* independent expected identity before this check runs.
|
|
1994
|
+
* Minimal attendance provenance against the bound marker (ADR 0043).
|
|
1995
|
+
* Keep only invocationId + post-terminal ordering. Runtime-self-produced
|
|
1996
|
+
* role/phase/subject/version are not re-reconciled here (ADR 0042).
|
|
2066
1997
|
*/
|
|
2067
1998
|
function navigatorAttendanceCorrelatedWithBoundMarker(
|
|
2068
1999
|
details: Record<string, unknown>,
|
|
2069
2000
|
attendanceIndex: number,
|
|
2070
|
-
|
|
2001
|
+
terminalIndex: number,
|
|
2071
2002
|
marker: InvocationMarkerIdentity,
|
|
2072
2003
|
): boolean {
|
|
2073
|
-
if (attendanceIndex <=
|
|
2074
|
-
if (details.version !== 1) return false;
|
|
2075
|
-
|
|
2076
|
-
// Role comes from the packaged terminal tool — compare, do not self-validate.
|
|
2077
|
-
if (details.role !== terminal.role) return false;
|
|
2078
|
-
// Marker role must already equal terminal role (checked by caller); attendance follows marker.
|
|
2079
|
-
if (details.role !== marker.role) return false;
|
|
2080
|
-
|
|
2004
|
+
if (attendanceIndex <= terminalIndex) return false;
|
|
2081
2005
|
// Exact current invocation token is the bound marker principal.
|
|
2082
2006
|
if (details.invocationId !== marker.invocationId) return false;
|
|
2083
|
-
|
|
2084
|
-
// Phase and subject ride the same marker identity truth table.
|
|
2085
|
-
if (details.phase !== marker.phase) return false;
|
|
2086
|
-
if (typeof details.subjectKey !== "string") return false;
|
|
2087
|
-
if (!workSubjectKeysEqual(details.subjectKey, marker.subjectKey)) return false;
|
|
2088
|
-
|
|
2089
2007
|
return true;
|
|
2090
2008
|
}
|
|
2091
2009
|
|
|
@@ -2157,45 +2075,37 @@ function parseNavigatorAttendanceDetails(
|
|
|
2157
2075
|
|
|
2158
2076
|
export function extractNavigatorFact(
|
|
2159
2077
|
entries: readonly SessionEntry[],
|
|
2160
|
-
identity?: NavigatorAttendanceIdentity,
|
|
2161
2078
|
): TerminalNavigatorFact {
|
|
2162
2079
|
// Affirmative attendance only. Missing / uncorrelated / unparseable is never no-advice.
|
|
2163
|
-
//
|
|
2164
|
-
|
|
2165
|
-
|
|
2080
|
+
// Minimal provenance: latest durable terminal + nearest preceding marker +
|
|
2081
|
+
// invocationId + post-terminal order. Marker↔terminal cardinality belongs to
|
|
2082
|
+
// receipt settlement (isReceiptSettlementBindingClear), not attendance extraction.
|
|
2083
|
+
const terminal = findLatestDurablePackagedRoleTerminal(entries);
|
|
2084
|
+
if (terminal === undefined) {
|
|
2166
2085
|
return {
|
|
2167
2086
|
disposition: "unavailable",
|
|
2168
2087
|
source: "unknown",
|
|
2169
2088
|
reason: "Navigator attendance has no durable packaged role terminal",
|
|
2170
2089
|
};
|
|
2171
2090
|
}
|
|
2172
|
-
if (binding.kind === "ambiguous") {
|
|
2173
|
-
return {
|
|
2174
|
-
disposition: "unavailable",
|
|
2175
|
-
source: "unknown",
|
|
2176
|
-
reason: "Navigator attendance is ambiguous across multiple durable role terminals",
|
|
2177
|
-
};
|
|
2178
|
-
}
|
|
2179
|
-
if (binding.kind === "unbound") {
|
|
2180
|
-
return {
|
|
2181
|
-
disposition: "unavailable",
|
|
2182
|
-
source: "unknown",
|
|
2183
|
-
reason: "Navigator attendance is uncorrelated with session invocation facts",
|
|
2184
|
-
};
|
|
2185
|
-
}
|
|
2186
2091
|
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2092
|
+
let markerIndex = -1;
|
|
2093
|
+
for (let i = terminal.index - 1; i >= 0; i -= 1) {
|
|
2094
|
+
const entry = entries[i];
|
|
2095
|
+
if (entry?.type === "custom" && entry.customType === NAVIGATOR_INVOCATION_ENTRY) {
|
|
2096
|
+
markerIndex = i;
|
|
2097
|
+
break;
|
|
2098
|
+
}
|
|
2099
|
+
}
|
|
2100
|
+
if (markerIndex < 0) {
|
|
2190
2101
|
return {
|
|
2191
2102
|
disposition: "unavailable",
|
|
2192
2103
|
source: "unknown",
|
|
2193
2104
|
reason: "Navigator attendance is uncorrelated with session invocation facts",
|
|
2194
2105
|
};
|
|
2195
2106
|
}
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
if (!markerMatchesExpectedIdentity(marker, expected)) {
|
|
2107
|
+
const marker = parseInvocationMarkerIdentity(entries[markerIndex]?.data);
|
|
2108
|
+
if (marker === undefined) {
|
|
2199
2109
|
return {
|
|
2200
2110
|
disposition: "unavailable",
|
|
2201
2111
|
source: "unknown",
|
|
@@ -2218,7 +2128,7 @@ export function extractNavigatorFact(
|
|
|
2218
2128
|
!navigatorAttendanceCorrelatedWithBoundMarker(
|
|
2219
2129
|
details,
|
|
2220
2130
|
i,
|
|
2221
|
-
|
|
2131
|
+
terminal.index,
|
|
2222
2132
|
marker,
|
|
2223
2133
|
)
|
|
2224
2134
|
) {
|
|
@@ -2249,7 +2159,7 @@ async function extractNavigatorFactFromAdmittedSession(
|
|
|
2249
2159
|
): Promise<TerminalNavigatorFact> {
|
|
2250
2160
|
try {
|
|
2251
2161
|
const entries = await readBoundSessionEntries(admitted.sessionFile);
|
|
2252
|
-
return extractNavigatorFact(entries
|
|
2162
|
+
return extractNavigatorFact(entries);
|
|
2253
2163
|
} catch (error) {
|
|
2254
2164
|
if (isMissingPathError(error)) {
|
|
2255
2165
|
return {
|
|
@@ -2483,10 +2393,7 @@ async function settleLawfulJudgeTerminalResult(
|
|
|
2483
2393
|
if (roleOutcome === undefined) {
|
|
2484
2394
|
return undefined;
|
|
2485
2395
|
}
|
|
2486
|
-
const navigator = extractNavigatorFact(
|
|
2487
|
-
entries,
|
|
2488
|
-
attendanceIdentityFromAdmitted(admitted),
|
|
2489
|
-
);
|
|
2396
|
+
const navigator = extractNavigatorFact(entries);
|
|
2490
2397
|
// Lawful outcome exists — artifact publication keeps original errno/name.
|
|
2491
2398
|
const artifacts = await publishJudgeArtifacts(
|
|
2492
2399
|
admitted,
|
|
@@ -2539,10 +2446,7 @@ async function settleLawfulCoderTerminalResult(
|
|
|
2539
2446
|
if (entries === undefined) return undefined;
|
|
2540
2447
|
const extracted = extractCoderRoleOutcome(entries);
|
|
2541
2448
|
if (extracted === undefined) return undefined;
|
|
2542
|
-
const navigator = extractNavigatorFact(
|
|
2543
|
-
entries,
|
|
2544
|
-
attendanceIdentityFromAdmitted(admitted),
|
|
2545
|
-
);
|
|
2449
|
+
const navigator = extractNavigatorFact(entries);
|
|
2546
2450
|
const artifacts = await publishCoderArtifacts(
|
|
2547
2451
|
admitted,
|
|
2548
2452
|
extracted.outcome,
|
|
@@ -2745,10 +2649,7 @@ async function settleLawfulFixerTerminalResult(
|
|
|
2745
2649
|
if (entries === undefined) return undefined;
|
|
2746
2650
|
const extracted = extractFixerRoleOutcome(entries);
|
|
2747
2651
|
if (extracted === undefined) return undefined;
|
|
2748
|
-
const navigator = extractNavigatorFact(
|
|
2749
|
-
entries,
|
|
2750
|
-
attendanceIdentityFromAdmitted(admitted),
|
|
2751
|
-
);
|
|
2652
|
+
const navigator = extractNavigatorFact(entries);
|
|
2752
2653
|
const methodInvocations = extractFixerMethodInvocations(entries, {
|
|
2753
2654
|
allowedLocations: [
|
|
2754
2655
|
options.methodSkillPath,
|
|
@@ -2915,10 +2816,7 @@ async function settleLawfulCollectorTerminalResult(
|
|
|
2915
2816
|
return undefined;
|
|
2916
2817
|
}
|
|
2917
2818
|
assertCollectorReceiptMatchesAdmitted(extracted.receipt, admitted);
|
|
2918
|
-
const navigator = extractNavigatorFact(
|
|
2919
|
-
entries,
|
|
2920
|
-
attendanceIdentityFromAdmitted(admitted),
|
|
2921
|
-
);
|
|
2819
|
+
const navigator = extractNavigatorFact(entries);
|
|
2922
2820
|
const artifacts = await publishCollectorArtifacts(
|
|
2923
2821
|
admitted,
|
|
2924
2822
|
extracted.outcome,
|
|
@@ -3095,10 +2993,7 @@ async function settleLawfulDoctorTerminalResult(
|
|
|
3095
2993
|
throw error;
|
|
3096
2994
|
}
|
|
3097
2995
|
}
|
|
3098
|
-
const navigator = extractNavigatorFact(
|
|
3099
|
-
entries,
|
|
3100
|
-
attendanceIdentityFromAdmitted(admitted),
|
|
3101
|
-
);
|
|
2996
|
+
const navigator = extractNavigatorFact(entries);
|
|
3102
2997
|
const artifacts = await publishDoctorArtifacts(
|
|
3103
2998
|
admitted,
|
|
3104
2999
|
extracted.outcome,
|
|
@@ -3353,10 +3248,7 @@ async function settleLawfulReviewerTerminalResult(
|
|
|
3353
3248
|
if (entries === undefined) return undefined;
|
|
3354
3249
|
const extracted = extractReviewerRoleOutcome(entries);
|
|
3355
3250
|
if (extracted === undefined) return undefined;
|
|
3356
|
-
const navigator = extractNavigatorFact(
|
|
3357
|
-
entries,
|
|
3358
|
-
attendanceIdentityFromAdmitted(admitted),
|
|
3359
|
-
);
|
|
3251
|
+
const navigator = extractNavigatorFact(entries);
|
|
3360
3252
|
const methodInvocations = extractReviewerMethodInvocations(entries, {
|
|
3361
3253
|
allowedLocations: [
|
|
3362
3254
|
options.methodSkillPath,
|
|
@@ -3623,10 +3515,7 @@ async function settleLawfulMergerTerminalResult(
|
|
|
3623
3515
|
});
|
|
3624
3516
|
// Every invocation must expand the merge-only method before conflict work.
|
|
3625
3517
|
if (methodInvocations.length === 0) return undefined;
|
|
3626
|
-
const navigator = extractNavigatorFact(
|
|
3627
|
-
entries,
|
|
3628
|
-
attendanceIdentityFromAdmitted(admitted),
|
|
3629
|
-
);
|
|
3518
|
+
const navigator = extractNavigatorFact(entries);
|
|
3630
3519
|
const artifacts = await publishMergerArtifacts(
|
|
3631
3520
|
admitted,
|
|
3632
3521
|
extracted.outcome,
|