nawabari 0.8.0 → 0.9.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +35 -0
- package/dist/cli-command-registry.d.ts +6 -0
- package/dist/cli-command-registry.js +26 -5
- package/dist/cli-command-registry.js.map +1 -1
- package/dist/cli.js +70 -8
- package/dist/cli.js.map +1 -1
- package/dist/contract.js +35 -0
- package/dist/contract.js.map +1 -1
- package/dist/domain/doctor.js +44 -0
- package/dist/domain/doctor.js.map +1 -1
- package/dist/domain/session-backend.d.ts +2 -1
- package/dist/domain/session-backend.js +119 -18
- package/dist/domain/session-backend.js.map +1 -1
- package/dist/domain/session.d.ts +100 -19
- package/dist/domain/session.js.map +1 -1
- package/dist/product-state-manifest.d.ts +152 -0
- package/dist/product-state-manifest.js +240 -0
- package/dist/product-state-manifest.js.map +1 -0
- package/dist/public-contract.d.ts +25 -0
- package/dist/public-contract.js +29 -0
- package/dist/public-contract.js.map +1 -0
- package/dist/public-state.d.ts +75 -0
- package/dist/public-state.js +60 -0
- package/dist/public-state.js.map +1 -0
- package/dist/session-lifecycle-actions.d.ts +4 -3
- package/dist/session-lifecycle-actions.js +14 -5
- package/dist/session-lifecycle-actions.js.map +1 -1
- package/dist/session-lifecycle-classification.d.ts +55 -2
- package/dist/session-lifecycle-classification.js +39 -306
- package/dist/session-lifecycle-classification.js.map +1 -1
- package/dist/session-registry.d.ts +83 -1
- package/dist/session-registry.js +440 -21
- package/dist/session-registry.js.map +1 -1
- package/dist/state/index.d.ts +5 -0
- package/dist/state/index.js +4 -0
- package/dist/state/index.js.map +1 -0
- package/dist/state/session/actors.d.ts +71 -0
- package/dist/state/session/actors.js +259 -0
- package/dist/state/session/actors.js.map +1 -0
- package/dist/state/session/guards.d.ts +25 -0
- package/dist/state/session/guards.js +108 -0
- package/dist/state/session/guards.js.map +1 -0
- package/dist/state/session/index.d.ts +6 -0
- package/dist/state/session/index.js +5 -0
- package/dist/state/session/index.js.map +1 -0
- package/dist/state/session/machine.d.ts +185 -0
- package/dist/state/session/machine.js +408 -0
- package/dist/state/session/machine.js.map +1 -0
- package/dist/state/session/types.d.ts +94 -0
- package/dist/state/session/types.js +14 -0
- package/dist/state/session/types.js.map +1 -0
- package/package.json +26 -6
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** Internal state modules. No state runtime internals are package exports. */
|
|
2
|
+
export { coordinateSessionLifecycle, executeSessionLifecycleActor, SESSION_ACTOR_EVENT_TYPES, SESSION_ACTOR_SCHEMA_VERSION, } from "./session/index.js";
|
|
3
|
+
export type { SessionActorAdapter, SessionActorDecision, SessionActorOperation, SessionActorPhase, SessionActorReconciliation, SessionActorReconciliationOutcome, SessionActorRequest, SessionActorResult, } from "./session/index.js";
|
|
4
|
+
export { SESSION_MACHINE_EVENT_TYPES, SESSION_STATE_MODULE_SCHEMA_VERSION } from "./session/index.js";
|
|
5
|
+
export type { PersistedSessionState, SessionEvidenceInput, SessionGarbageCollectionEvidence, SessionIntegrationEvidence, SessionMachineContext, SessionMachineEvent, SessionMachineInput, SessionObservationBlocker, SessionObservationCloseReadiness, SessionObservationInput, SessionObservationPhase, SessionOperationalState, SessionPersistedStateInput, } from "./session/index.js";
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
/** Internal state modules. No state runtime internals are package exports. */
|
|
2
|
+
export { coordinateSessionLifecycle, executeSessionLifecycleActor, SESSION_ACTOR_EVENT_TYPES, SESSION_ACTOR_SCHEMA_VERSION, } from "./session/index.js";
|
|
3
|
+
export { SESSION_MACHINE_EVENT_TYPES, SESSION_STATE_MODULE_SCHEMA_VERSION } from "./session/index.js";
|
|
4
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/state/index.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,OAAO,EACL,0BAA0B,EAC1B,4BAA4B,EAC5B,yBAAyB,EACzB,4BAA4B,GAC7B,MAAM,oBAAoB,CAAC;AAW5B,OAAO,EAAE,2BAA2B,EAAE,mCAAmC,EAAE,MAAM,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import type { SessionLifecycleOperation, SessionLifecycleState } from "../../session-lifecycle-classification.js";
|
|
2
|
+
import type { SessionMachineInput } from "./types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Internal protocol used by the production Session actor. The protocol is
|
|
5
|
+
* deliberately capability-shaped; CLI command names and physical authorities
|
|
6
|
+
* do not belong in this module.
|
|
7
|
+
*/
|
|
8
|
+
export declare const SESSION_ACTOR_EVENT_TYPES: readonly ["SESSION.REQUESTED", "SESSION.OBSERVED", "SESSION.TRANSITION.EVALUATED", "SESSION.EFFECT.COMPLETED", "SESSION.EFFECT.FAILED", "SESSION.REOBSERVED", "SESSION.REOBSERVATION.FAILED", "SESSION.RECONCILED", "SESSION.FINALIZED"];
|
|
9
|
+
export declare const SESSION_ACTOR_SCHEMA_VERSION: 1;
|
|
10
|
+
export type SessionActorOperation = Extract<SessionLifecycleOperation, "close" | "discard" | "reconcile" | "gc">;
|
|
11
|
+
export type SessionActorPhase = "completed" | "rejected" | "retryable" | "unresolved";
|
|
12
|
+
export type SessionActorReconciliationOutcome = "completed" | "retryable" | "unresolved";
|
|
13
|
+
/** Bounded, identity-neutral recovery evidence supplied by an existing adapter. */
|
|
14
|
+
export interface SessionActorReconciliation {
|
|
15
|
+
readonly outcome: SessionActorReconciliationOutcome;
|
|
16
|
+
readonly retrySafe: boolean;
|
|
17
|
+
readonly reason?: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* A transition decision returned by the canonical lifecycle machine. Retry
|
|
21
|
+
* decisions use the machine's cleanup-retry event while retaining the same
|
|
22
|
+
* public operational state vocabulary.
|
|
23
|
+
*/
|
|
24
|
+
export interface SessionActorDecision {
|
|
25
|
+
readonly operation: SessionActorOperation;
|
|
26
|
+
readonly eventType: string;
|
|
27
|
+
readonly allowed: boolean;
|
|
28
|
+
readonly target: SessionLifecycleState | null;
|
|
29
|
+
readonly requiresExplicitIntent: boolean;
|
|
30
|
+
readonly authority: "session-registry" | "reconciliation" | "gc" | "caller";
|
|
31
|
+
readonly reason: string;
|
|
32
|
+
readonly mode: "request" | "retry";
|
|
33
|
+
}
|
|
34
|
+
export interface SessionActorAdapter<TResult> {
|
|
35
|
+
/** Observe an authoritative input before and after the bounded effect. */
|
|
36
|
+
readonly observe: (stage: "before" | "after") => SessionMachineInput;
|
|
37
|
+
/**
|
|
38
|
+
* Positive identity-bound authority for retrying a partial cleanup. A
|
|
39
|
+
* retry must never be inferred from an operational state alone.
|
|
40
|
+
*/
|
|
41
|
+
readonly retryAuthorized?: (input: SessionMachineInput) => boolean;
|
|
42
|
+
/** Execute exactly one bounded effect through the existing authority. */
|
|
43
|
+
readonly effect: (decision: SessionActorDecision) => TResult;
|
|
44
|
+
/** Reconcile an effect failure using the existing authoritative observer. */
|
|
45
|
+
readonly reconcile?: (error: unknown, after: SessionMachineInput | undefined, decision: SessionActorDecision) => SessionActorReconciliation;
|
|
46
|
+
}
|
|
47
|
+
export interface SessionActorRequest<TResult> {
|
|
48
|
+
readonly operation: SessionActorOperation;
|
|
49
|
+
/** A retry is only valid after the adapter has positively re-observed ownership. */
|
|
50
|
+
readonly retry?: boolean;
|
|
51
|
+
readonly adapter: SessionActorAdapter<TResult>;
|
|
52
|
+
}
|
|
53
|
+
export interface SessionActorResult<TResult> {
|
|
54
|
+
readonly schemaVersion: typeof SESSION_ACTOR_SCHEMA_VERSION;
|
|
55
|
+
readonly operation: SessionActorOperation;
|
|
56
|
+
readonly phase: SessionActorPhase;
|
|
57
|
+
readonly decision: SessionActorDecision;
|
|
58
|
+
readonly before: SessionMachineInput;
|
|
59
|
+
readonly after?: SessionMachineInput;
|
|
60
|
+
readonly value?: TResult;
|
|
61
|
+
readonly error?: unknown;
|
|
62
|
+
readonly reconciliation?: SessionActorReconciliation;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Execute one lifecycle request through the Session actor protocol. The
|
|
66
|
+
* caller supplies all observations and effects through an adapter, keeping
|
|
67
|
+
* Git/filesystem/registry authorities outside this state module.
|
|
68
|
+
*/
|
|
69
|
+
export declare function executeSessionLifecycleActor<TResult>(request: SessionActorRequest<TResult>): SessionActorResult<TResult>;
|
|
70
|
+
/** Alias used by callers that describe the actor as a coordinator. */
|
|
71
|
+
export declare const coordinateSessionLifecycle: typeof executeSessionLifecycleActor;
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
import { assign, createActor, setup } from "xstate";
|
|
2
|
+
import { projectSessionLifecycleMachine, sessionLifecycleMachine, } from "./machine.js";
|
|
3
|
+
import { classifyObservationBlockers } from "./guards.js";
|
|
4
|
+
/**
|
|
5
|
+
* Internal protocol used by the production Session actor. The protocol is
|
|
6
|
+
* deliberately capability-shaped; CLI command names and physical authorities
|
|
7
|
+
* do not belong in this module.
|
|
8
|
+
*/
|
|
9
|
+
export const SESSION_ACTOR_EVENT_TYPES = Object.freeze([
|
|
10
|
+
"SESSION.REQUESTED",
|
|
11
|
+
"SESSION.OBSERVED",
|
|
12
|
+
"SESSION.TRANSITION.EVALUATED",
|
|
13
|
+
"SESSION.EFFECT.COMPLETED",
|
|
14
|
+
"SESSION.EFFECT.FAILED",
|
|
15
|
+
"SESSION.REOBSERVED",
|
|
16
|
+
"SESSION.REOBSERVATION.FAILED",
|
|
17
|
+
"SESSION.RECONCILED",
|
|
18
|
+
"SESSION.FINALIZED",
|
|
19
|
+
]);
|
|
20
|
+
export const SESSION_ACTOR_SCHEMA_VERSION = 1;
|
|
21
|
+
const actorSetup = setup({
|
|
22
|
+
types: {
|
|
23
|
+
context: {},
|
|
24
|
+
events: {},
|
|
25
|
+
input: {},
|
|
26
|
+
},
|
|
27
|
+
actions: {
|
|
28
|
+
rememberObservation: assign({
|
|
29
|
+
before: ({ event }) => (event.type === "SESSION.OBSERVED" ? event.observation : undefined),
|
|
30
|
+
}),
|
|
31
|
+
rememberAfterObservation: assign({
|
|
32
|
+
after: ({ event }) => (event.type === "SESSION.REOBSERVED" ? event.observation : undefined),
|
|
33
|
+
}),
|
|
34
|
+
rememberDecision: assign({
|
|
35
|
+
decision: ({ event }) => (event.type === "SESSION.TRANSITION.EVALUATED" ? event.decision : undefined),
|
|
36
|
+
}),
|
|
37
|
+
rememberValue: assign({
|
|
38
|
+
value: ({ event }) => (event.type === "SESSION.EFFECT.COMPLETED" ? event.value : undefined),
|
|
39
|
+
}),
|
|
40
|
+
rememberError: assign({
|
|
41
|
+
error: ({ event }) => event.type === "SESSION.EFFECT.FAILED" || event.type === "SESSION.REOBSERVATION.FAILED"
|
|
42
|
+
? event.error
|
|
43
|
+
: undefined,
|
|
44
|
+
}),
|
|
45
|
+
rememberReconciliation: assign({
|
|
46
|
+
reconciliation: ({ event }) => (event.type === "SESSION.RECONCILED" ? event.reconciliation : undefined),
|
|
47
|
+
}),
|
|
48
|
+
},
|
|
49
|
+
guards: {
|
|
50
|
+
decisionAllowed: ({ event }) => event.type === "SESSION.TRANSITION.EVALUATED" && event.decision.allowed,
|
|
51
|
+
reconciliationCompleted: ({ event }) => event.type === "SESSION.RECONCILED" && event.reconciliation.outcome === "completed",
|
|
52
|
+
reconciliationRetryable: ({ event }) => event.type === "SESSION.RECONCILED" && event.reconciliation.outcome === "retryable",
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
/**
|
|
56
|
+
* Protocol state machine for one lifecycle operation. It owns sequencing and
|
|
57
|
+
* retry/reconciliation semantics only; it has no mutation or observation
|
|
58
|
+
* capability of its own.
|
|
59
|
+
*/
|
|
60
|
+
const sessionActorMachine = actorSetup.createMachine({
|
|
61
|
+
id: "session-actor",
|
|
62
|
+
initial: "idle",
|
|
63
|
+
context: ({ input }) => ({ operation: input.operation, retry: input.retry }),
|
|
64
|
+
states: {
|
|
65
|
+
idle: {
|
|
66
|
+
on: { "SESSION.REQUESTED": "observing" },
|
|
67
|
+
},
|
|
68
|
+
observing: {
|
|
69
|
+
on: {
|
|
70
|
+
"SESSION.OBSERVED": { target: "evaluating", actions: "rememberObservation" },
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
evaluating: {
|
|
74
|
+
on: {
|
|
75
|
+
"SESSION.TRANSITION.EVALUATED": [
|
|
76
|
+
{ target: "executing", guard: "decisionAllowed", actions: "rememberDecision" },
|
|
77
|
+
{ target: "rejected", actions: "rememberDecision" },
|
|
78
|
+
],
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
executing: {
|
|
82
|
+
on: {
|
|
83
|
+
"SESSION.EFFECT.COMPLETED": { target: "reobserving", actions: "rememberValue" },
|
|
84
|
+
"SESSION.EFFECT.FAILED": { target: "reconciling", actions: "rememberError" },
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
reobserving: {
|
|
88
|
+
on: {
|
|
89
|
+
"SESSION.REOBSERVED": { target: "finalizing", actions: "rememberAfterObservation" },
|
|
90
|
+
"SESSION.REOBSERVATION.FAILED": { target: "reconciling", actions: "rememberError" },
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
reconciling: {
|
|
94
|
+
on: {
|
|
95
|
+
"SESSION.RECONCILED": [
|
|
96
|
+
{ target: "completed", guard: "reconciliationCompleted", actions: "rememberReconciliation" },
|
|
97
|
+
{ target: "retryable", guard: "reconciliationRetryable", actions: "rememberReconciliation" },
|
|
98
|
+
{ target: "unresolved", actions: "rememberReconciliation" },
|
|
99
|
+
],
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
finalizing: {
|
|
103
|
+
on: { "SESSION.FINALIZED": "completed" },
|
|
104
|
+
},
|
|
105
|
+
completed: {},
|
|
106
|
+
rejected: {},
|
|
107
|
+
retryable: {},
|
|
108
|
+
unresolved: {},
|
|
109
|
+
},
|
|
110
|
+
});
|
|
111
|
+
function stateValue(value) {
|
|
112
|
+
if (typeof value !== "string")
|
|
113
|
+
throw new Error(`Session actor exposed an invalid state: ${String(value)}`);
|
|
114
|
+
return value;
|
|
115
|
+
}
|
|
116
|
+
function operationalState(input) {
|
|
117
|
+
const projection = projectSessionLifecycleMachine(input);
|
|
118
|
+
return projection.state;
|
|
119
|
+
}
|
|
120
|
+
function retryDecision(input, operation, retryAuthorized) {
|
|
121
|
+
const actor = createActor(sessionLifecycleMachine, { input }).start();
|
|
122
|
+
const event = { type: "SESSION.CLEANUP.RETRY" };
|
|
123
|
+
const blockers = input.observation.blockers ?? [];
|
|
124
|
+
const unambiguous = input.observation.closeReadiness !== "ambiguous" &&
|
|
125
|
+
classifyObservationBlockers(blockers) !== "ambiguous" &&
|
|
126
|
+
!blockers.some((blocker) => blocker.classification === "stale");
|
|
127
|
+
const allowed = actor.getSnapshot().can(event) && retryAuthorized && unambiguous;
|
|
128
|
+
const state = operationalState(input);
|
|
129
|
+
actor.stop();
|
|
130
|
+
return {
|
|
131
|
+
operation,
|
|
132
|
+
eventType: event.type,
|
|
133
|
+
allowed,
|
|
134
|
+
target: allowed ? state : null,
|
|
135
|
+
requiresExplicitIntent: operation === "discard",
|
|
136
|
+
authority: "reconciliation",
|
|
137
|
+
reason: allowed ? "cleanup-retry" : "physical-reconciliation-required",
|
|
138
|
+
mode: "retry",
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
function requestDecision(input, operation) {
|
|
142
|
+
const transition = projectSessionLifecycleMachine(input).transitions[operation];
|
|
143
|
+
return { ...transition, operation, mode: "request" };
|
|
144
|
+
}
|
|
145
|
+
function decisionFor(input, operation, retry, retryAuthorized) {
|
|
146
|
+
return retry ? retryDecision(input, operation, retryAuthorized) : requestDecision(input, operation);
|
|
147
|
+
}
|
|
148
|
+
function reconciliationFor(request, error, after, decision) {
|
|
149
|
+
return (request.adapter.reconcile?.(error, after, decision) ?? {
|
|
150
|
+
outcome: "unresolved",
|
|
151
|
+
retrySafe: false,
|
|
152
|
+
reason: "reconciliation-unavailable",
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Execute one lifecycle request through the Session actor protocol. The
|
|
157
|
+
* caller supplies all observations and effects through an adapter, keeping
|
|
158
|
+
* Git/filesystem/registry authorities outside this state module.
|
|
159
|
+
*/
|
|
160
|
+
export function executeSessionLifecycleActor(request) {
|
|
161
|
+
const actor = createActor(sessionActorMachine, {
|
|
162
|
+
input: { operation: request.operation, retry: request.retry === true },
|
|
163
|
+
}).start();
|
|
164
|
+
actor.send({ type: "SESSION.REQUESTED" });
|
|
165
|
+
const before = request.adapter.observe("before");
|
|
166
|
+
actor.send({ type: "SESSION.OBSERVED", observation: before });
|
|
167
|
+
const decision = decisionFor(before, request.operation, request.retry === true, request.retry !== true || request.adapter.retryAuthorized?.(before) === true);
|
|
168
|
+
actor.send({ type: "SESSION.TRANSITION.EVALUATED", decision });
|
|
169
|
+
if (!decision.allowed) {
|
|
170
|
+
const snapshot = actor.getSnapshot();
|
|
171
|
+
actor.stop();
|
|
172
|
+
if (stateValue(snapshot.value) !== "rejected") {
|
|
173
|
+
throw new Error("Session actor failed to reject a forbidden lifecycle transition");
|
|
174
|
+
}
|
|
175
|
+
return Object.freeze({
|
|
176
|
+
schemaVersion: SESSION_ACTOR_SCHEMA_VERSION,
|
|
177
|
+
operation: request.operation,
|
|
178
|
+
phase: "rejected",
|
|
179
|
+
decision,
|
|
180
|
+
before,
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
let value;
|
|
184
|
+
try {
|
|
185
|
+
value = request.adapter.effect(decision);
|
|
186
|
+
actor.send({ type: "SESSION.EFFECT.COMPLETED", value });
|
|
187
|
+
}
|
|
188
|
+
catch (error) {
|
|
189
|
+
actor.send({ type: "SESSION.EFFECT.FAILED", error });
|
|
190
|
+
let after;
|
|
191
|
+
try {
|
|
192
|
+
after = request.adapter.observe("after");
|
|
193
|
+
}
|
|
194
|
+
catch {
|
|
195
|
+
after = undefined;
|
|
196
|
+
}
|
|
197
|
+
const reconciliation = reconciliationFor(request, error, after, decision);
|
|
198
|
+
actor.send({ type: "SESSION.RECONCILED", reconciliation });
|
|
199
|
+
const snapshot = actor.getSnapshot();
|
|
200
|
+
const phase = stateValue(snapshot.value);
|
|
201
|
+
actor.stop();
|
|
202
|
+
if (phase !== "completed" && phase !== "retryable" && phase !== "unresolved") {
|
|
203
|
+
throw new Error("Session actor failed to classify an effect failure");
|
|
204
|
+
}
|
|
205
|
+
return Object.freeze({
|
|
206
|
+
schemaVersion: SESSION_ACTOR_SCHEMA_VERSION,
|
|
207
|
+
operation: request.operation,
|
|
208
|
+
phase,
|
|
209
|
+
decision,
|
|
210
|
+
before,
|
|
211
|
+
...(after === undefined ? {} : { after }),
|
|
212
|
+
error,
|
|
213
|
+
reconciliation,
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
let after;
|
|
217
|
+
try {
|
|
218
|
+
after = request.adapter.observe("after");
|
|
219
|
+
actor.send({ type: "SESSION.REOBSERVED", observation: after });
|
|
220
|
+
actor.send({ type: "SESSION.FINALIZED" });
|
|
221
|
+
}
|
|
222
|
+
catch (error) {
|
|
223
|
+
actor.send({ type: "SESSION.REOBSERVATION.FAILED", error });
|
|
224
|
+
const reconciliation = reconciliationFor(request, error, undefined, decision);
|
|
225
|
+
actor.send({ type: "SESSION.RECONCILED", reconciliation });
|
|
226
|
+
const snapshot = actor.getSnapshot();
|
|
227
|
+
const phase = stateValue(snapshot.value);
|
|
228
|
+
actor.stop();
|
|
229
|
+
if (phase !== "completed" && phase !== "retryable" && phase !== "unresolved") {
|
|
230
|
+
throw new Error("Session actor failed to classify a re-observation failure");
|
|
231
|
+
}
|
|
232
|
+
return Object.freeze({
|
|
233
|
+
schemaVersion: SESSION_ACTOR_SCHEMA_VERSION,
|
|
234
|
+
operation: request.operation,
|
|
235
|
+
phase,
|
|
236
|
+
decision,
|
|
237
|
+
before,
|
|
238
|
+
error,
|
|
239
|
+
reconciliation,
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
const snapshot = actor.getSnapshot();
|
|
243
|
+
actor.stop();
|
|
244
|
+
if (stateValue(snapshot.value) !== "completed") {
|
|
245
|
+
throw new Error("Session actor failed to finalize a completed lifecycle transition");
|
|
246
|
+
}
|
|
247
|
+
return Object.freeze({
|
|
248
|
+
schemaVersion: SESSION_ACTOR_SCHEMA_VERSION,
|
|
249
|
+
operation: request.operation,
|
|
250
|
+
phase: "completed",
|
|
251
|
+
decision,
|
|
252
|
+
before,
|
|
253
|
+
after,
|
|
254
|
+
value,
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
/** Alias used by callers that describe the actor as a coordinator. */
|
|
258
|
+
export const coordinateSessionLifecycle = executeSessionLifecycleActor;
|
|
259
|
+
//# sourceMappingURL=actors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"actors.js","sourceRoot":"","sources":["../../../src/state/session/actors.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { SessionLifecycleBlocker } from "../../session-lifecycle-classification.js";
|
|
2
|
+
import type { SessionMachineContext } from "./types.js";
|
|
3
|
+
export type SessionLifecycleBlockerKind = "none" | "recoverable" | "ambiguous";
|
|
4
|
+
/**
|
|
5
|
+
* Classify already-observed blocker evidence for the lifecycle machine.
|
|
6
|
+
* This is domain projection input to the guards; it never observes an
|
|
7
|
+
* external authority and must remain deterministic for the same observation.
|
|
8
|
+
*/
|
|
9
|
+
export declare function classifyObservationBlockers(blockers: readonly SessionLifecycleBlocker[]): SessionLifecycleBlockerKind;
|
|
10
|
+
/** True when the observed facts are insufficient or contradictory. */
|
|
11
|
+
export declare function isObservationStaleInconsistent(context: SessionMachineContext): boolean;
|
|
12
|
+
/** Explicit discard intent is observation data, never an age-derived guess. */
|
|
13
|
+
export declare function hasExplicitDiscardIntent(context: SessionMachineContext): boolean;
|
|
14
|
+
export declare function isObservationDiscarded(context: SessionMachineContext): boolean;
|
|
15
|
+
export declare function isObservationClosed(context: SessionMachineContext): boolean;
|
|
16
|
+
export declare function isObservationBlockedRecoverable(context: SessionMachineContext): boolean;
|
|
17
|
+
export declare function isObservationCloseReady(context: SessionMachineContext): boolean;
|
|
18
|
+
/** GC authority matches the classifier: strictly observation.gcAuthorized === true. */
|
|
19
|
+
export declare function hasGcAuthorization(context: SessionMachineContext): boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Match destructiveCleanupEligible for the close-ready state. Age suspicion
|
|
22
|
+
* alone never grants destructive cleanup, including when a healthy session is
|
|
23
|
+
* old and a caller supplied an otherwise positive GC authorization.
|
|
24
|
+
*/
|
|
25
|
+
export declare function isDestructiveGcAllowed(context: SessionMachineContext): boolean;
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
const AMBIGUOUS_CODES = new Set([
|
|
2
|
+
"GIT_STATE_AMBIGUOUS",
|
|
3
|
+
"PHYSICAL_OBSERVATION_UNAVAILABLE",
|
|
4
|
+
"REPOSITORY_IDENTITY_AMBIGUOUS",
|
|
5
|
+
"WORKTREE_IDENTITY_AMBIGUOUS",
|
|
6
|
+
"GIT_COMMAND_FAILED",
|
|
7
|
+
"GIT_SPAWN_FAILED",
|
|
8
|
+
"GIT_TIMEOUT",
|
|
9
|
+
"GIT_OUTPUT_LIMIT",
|
|
10
|
+
"OWNERSHIP_MISMATCH",
|
|
11
|
+
"DUPLICATE_WORKTREE_OWNERSHIP",
|
|
12
|
+
"DUPLICATE_BRANCH_OWNERSHIP",
|
|
13
|
+
"RECONCILIATION_DRIFT",
|
|
14
|
+
"STALE_REGISTRY",
|
|
15
|
+
]);
|
|
16
|
+
const RECOVERABLE_CODES = new Set([
|
|
17
|
+
"DIRTY_WORKTREE",
|
|
18
|
+
"NESTED_REPOSITORY",
|
|
19
|
+
"RECOVERABLE_COMMITS",
|
|
20
|
+
"RECOVERABLE_STASHES",
|
|
21
|
+
"INTEGRATION_FETCH_FAILED",
|
|
22
|
+
]);
|
|
23
|
+
const STALE_PHYSICAL_STATES = new Set([
|
|
24
|
+
"prunable-missing",
|
|
25
|
+
"prunable-present",
|
|
26
|
+
"registered-missing",
|
|
27
|
+
"unregistered-missing",
|
|
28
|
+
"unregistered-present",
|
|
29
|
+
"invalid",
|
|
30
|
+
"unavailable",
|
|
31
|
+
]);
|
|
32
|
+
const KNOWN_SESSION_STATES = new Set(["new", "active", "closing", "closed", "stale"]);
|
|
33
|
+
const KNOWN_PHYSICAL_STATES = new Set(["healthy", "closed", ...STALE_PHYSICAL_STATES]);
|
|
34
|
+
const KNOWN_BLOCKER_CLASSIFICATIONS = new Set(["recoverable", "ambiguous", "stale"]);
|
|
35
|
+
/**
|
|
36
|
+
* Classify already-observed blocker evidence for the lifecycle machine.
|
|
37
|
+
* This is domain projection input to the guards; it never observes an
|
|
38
|
+
* external authority and must remain deterministic for the same observation.
|
|
39
|
+
*/
|
|
40
|
+
export function classifyObservationBlockers(blockers) {
|
|
41
|
+
if (blockers.some((blocker) => blocker.classification === "ambiguous" || AMBIGUOUS_CODES.has(blocker.code))) {
|
|
42
|
+
return "ambiguous";
|
|
43
|
+
}
|
|
44
|
+
if (blockers.some((blocker) => blocker.classification === "recoverable" || RECOVERABLE_CODES.has(blocker.code))) {
|
|
45
|
+
return "recoverable";
|
|
46
|
+
}
|
|
47
|
+
return "none";
|
|
48
|
+
}
|
|
49
|
+
function isStalePhysicalState(physicalState) {
|
|
50
|
+
return (physicalState === null || !KNOWN_PHYSICAL_STATES.has(physicalState) || STALE_PHYSICAL_STATES.has(physicalState));
|
|
51
|
+
}
|
|
52
|
+
function hasUnknownBlocker(blockers) {
|
|
53
|
+
return blockers.some((blocker) => !AMBIGUOUS_CODES.has(blocker.code) &&
|
|
54
|
+
!RECOVERABLE_CODES.has(blocker.code) &&
|
|
55
|
+
(blocker.classification === undefined || !KNOWN_BLOCKER_CLASSIFICATIONS.has(blocker.classification)));
|
|
56
|
+
}
|
|
57
|
+
function observation(context) {
|
|
58
|
+
return context.observation;
|
|
59
|
+
}
|
|
60
|
+
/** True when the observed facts are insufficient or contradictory. */
|
|
61
|
+
export function isObservationStaleInconsistent(context) {
|
|
62
|
+
const current = observation(context);
|
|
63
|
+
const blockers = current.blockers ?? [];
|
|
64
|
+
const physicalState = current.physicalState ?? null;
|
|
65
|
+
const closeReadiness = current.closeReadiness ?? "not-evaluated";
|
|
66
|
+
const recoverability = classifyObservationBlockers(blockers);
|
|
67
|
+
const physicalEvidenceRequired = current.sessionState !== "closed";
|
|
68
|
+
const ambiguousReadiness = closeReadiness === "ambiguous" || (closeReadiness === "blocked" && blockers.length === 0);
|
|
69
|
+
return (!KNOWN_SESSION_STATES.has(current.sessionState) ||
|
|
70
|
+
(physicalEvidenceRequired && isStalePhysicalState(physicalState)) ||
|
|
71
|
+
hasUnknownBlocker(blockers) ||
|
|
72
|
+
blockers.some((blocker) => blocker.classification === "stale") ||
|
|
73
|
+
ambiguousReadiness ||
|
|
74
|
+
recoverability === "ambiguous");
|
|
75
|
+
}
|
|
76
|
+
/** Explicit discard intent is observation data, never an age-derived guess. */
|
|
77
|
+
export function hasExplicitDiscardIntent(context) {
|
|
78
|
+
return context.observation.terminalOperation === "discard" || context.persisted?.terminalOperation === "discard";
|
|
79
|
+
}
|
|
80
|
+
export function isObservationDiscarded(context) {
|
|
81
|
+
return hasExplicitDiscardIntent(context);
|
|
82
|
+
}
|
|
83
|
+
export function isObservationClosed(context) {
|
|
84
|
+
return context.observation.sessionState === "closed";
|
|
85
|
+
}
|
|
86
|
+
export function isObservationBlockedRecoverable(context) {
|
|
87
|
+
const current = observation(context);
|
|
88
|
+
const recoverability = classifyObservationBlockers(current.blockers ?? []);
|
|
89
|
+
return recoverability === "recoverable" || current.closeReadiness === "external_evidence_required";
|
|
90
|
+
}
|
|
91
|
+
export function isObservationCloseReady(context) {
|
|
92
|
+
const current = observation(context);
|
|
93
|
+
return current.phase === "termination" && current.closeReadiness === "ready";
|
|
94
|
+
}
|
|
95
|
+
/** GC authority matches the classifier: strictly observation.gcAuthorized === true. */
|
|
96
|
+
export function hasGcAuthorization(context) {
|
|
97
|
+
return context.observation.gcAuthorized === true;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Match destructiveCleanupEligible for the close-ready state. Age suspicion
|
|
101
|
+
* alone never grants destructive cleanup, including when a healthy session is
|
|
102
|
+
* old and a caller supplied an otherwise positive GC authorization.
|
|
103
|
+
*/
|
|
104
|
+
export function isDestructiveGcAllowed(context) {
|
|
105
|
+
const current = observation(context);
|
|
106
|
+
return hasGcAuthorization(context) && !(current.ageSuspicious === true && current.physicalState === "healthy");
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=guards.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guards.js","sourceRoot":"","sources":["../../../src/state/session/guards.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** Internal Session state boundary; intentionally absent from src/index.ts. */
|
|
2
|
+
export { SESSION_OPERATION_EVENT_TYPES } from "./machine.js";
|
|
3
|
+
export { coordinateSessionLifecycle, executeSessionLifecycleActor, SESSION_ACTOR_EVENT_TYPES, SESSION_ACTOR_SCHEMA_VERSION, } from "./actors.js";
|
|
4
|
+
export type { SessionActorAdapter, SessionActorDecision, SessionActorOperation, SessionActorPhase, SessionActorReconciliation, SessionActorReconciliationOutcome, SessionActorRequest, SessionActorResult, } from "./actors.js";
|
|
5
|
+
export { SESSION_MACHINE_EVENT_TYPES, SESSION_STATE_MODULE_SCHEMA_VERSION } from "./types.js";
|
|
6
|
+
export type { PersistedSessionState, SessionEvidenceInput, SessionGarbageCollectionEvidence, SessionIntegrationEvidence, SessionMachineContext, SessionMachineEvent, SessionMachineInput, SessionObservationBlocker, SessionObservationCloseReadiness, SessionObservationInput, SessionObservationPhase, SessionOperationalState, SessionPersistedStateInput, } from "./types.js";
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** Internal Session state boundary; intentionally absent from src/index.ts. */
|
|
2
|
+
export { SESSION_OPERATION_EVENT_TYPES } from "./machine.js";
|
|
3
|
+
export { coordinateSessionLifecycle, executeSessionLifecycleActor, SESSION_ACTOR_EVENT_TYPES, SESSION_ACTOR_SCHEMA_VERSION, } from "./actors.js";
|
|
4
|
+
export { SESSION_MACHINE_EVENT_TYPES, SESSION_STATE_MODULE_SCHEMA_VERSION } from "./types.js";
|
|
5
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/state/session/index.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,OAAO,EAAE,6BAA6B,EAAE,MAAM,cAAc,CAAC;AAC7D,OAAO,EACL,0BAA0B,EAC1B,4BAA4B,EAC5B,yBAAyB,EACzB,4BAA4B,GAC7B,MAAM,aAAa,CAAC;AAWrB,OAAO,EAAE,2BAA2B,EAAE,mCAAmC,EAAE,MAAM,YAAY,CAAC"}
|