@akagilnc/pi-workflow-roles 0.1.2068 → 0.1.2076
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
- package/src/role-runtime.ts +1 -3
- package/src/worker-role.ts +2 -0
- package/src/worker-submission-gates.ts +185 -132
|
@@ -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,
|
package/src/role-runtime.ts
CHANGED
|
@@ -23,7 +23,6 @@ import {
|
|
|
23
23
|
} from "./tool-execution-observation.ts";
|
|
24
24
|
import { registerEngineDetourTool } from "./engine-detour-tool.ts";
|
|
25
25
|
import { installPackageOwnedToolRegistration } from "./package-owned-tool-idle.ts";
|
|
26
|
-
import { installWorkerGitHooks } from "./worker-submission-gates.ts";
|
|
27
26
|
import { createReceiptDeliveryPolicy, NO_RECEIPT_LIFECYCLE_ENTRY_TYPE, RECEIPT_DELIVERY_PROMPT } from "./receipt-delivery-policy.ts";
|
|
28
27
|
import { createOAuthKeepalive, type OAuthKeepaliveOptions } from "./oauth-keepalive.ts";
|
|
29
28
|
|
|
@@ -1177,10 +1176,9 @@ export function createRoleRuntimeExtension(
|
|
|
1177
1176
|
engineDetourRegistration = undefined;
|
|
1178
1177
|
}
|
|
1179
1178
|
}
|
|
1180
|
-
// Worker gates
|
|
1179
|
+
// Worker gates ①②: arm records baseline and runs private one-shot hook uninstall (ADR 0070).
|
|
1181
1180
|
// Parent session feeds #216 createRecordSession so baseline/bounce survive resume.
|
|
1182
1181
|
if (entry.role === "coder" || entry.role === "fixer") {
|
|
1183
|
-
installWorkerGitHooks(ctx.cwd);
|
|
1184
1182
|
if (entry.role === "coder") coder.armSubmissionGate(ctx.cwd, ctx.sessionManager);
|
|
1185
1183
|
else fixer.armSubmissionGate(ctx.cwd, ctx.sessionManager);
|
|
1186
1184
|
}
|
package/src/worker-role.ts
CHANGED
|
@@ -29,6 +29,7 @@ import {
|
|
|
29
29
|
import {
|
|
30
30
|
createWorkerSubmissionGate,
|
|
31
31
|
WorkerCommitReminderError,
|
|
32
|
+
WorkerPrefixReminderError,
|
|
32
33
|
WorkerUnfinishedReasonReminderError,
|
|
33
34
|
} from "./worker-submission-gates.ts";
|
|
34
35
|
|
|
@@ -189,6 +190,7 @@ function assertAcceptableThroughHost(
|
|
|
189
190
|
} catch (error) {
|
|
190
191
|
if (
|
|
191
192
|
error instanceof WorkerCommitReminderError ||
|
|
193
|
+
error instanceof WorkerPrefixReminderError ||
|
|
192
194
|
error instanceof WorkerUnfinishedReasonReminderError
|
|
193
195
|
) {
|
|
194
196
|
throw error;
|