@dsh-enhanced/assistant-goals 0.1.30
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/LICENSE +21 -0
- package/README.md +274 -0
- package/cordis.patch.yml +3 -0
- package/lib/budget-store.d.ts +73 -0
- package/lib/budget-store.d.ts.map +1 -0
- package/lib/budget-store.js +345 -0
- package/lib/budget-store.js.map +1 -0
- package/lib/budget.d.ts +78 -0
- package/lib/budget.d.ts.map +1 -0
- package/lib/budget.js +344 -0
- package/lib/budget.js.map +1 -0
- package/lib/dependency.d.ts +11 -0
- package/lib/dependency.d.ts.map +1 -0
- package/lib/dependency.js +34 -0
- package/lib/dependency.js.map +1 -0
- package/lib/event-wait-store.d.ts +56 -0
- package/lib/event-wait-store.d.ts.map +1 -0
- package/lib/event-wait-store.js +189 -0
- package/lib/event-wait-store.js.map +1 -0
- package/lib/event-wait.d.ts +47 -0
- package/lib/event-wait.d.ts.map +1 -0
- package/lib/event-wait.js +372 -0
- package/lib/event-wait.js.map +1 -0
- package/lib/execution-store.d.ts +23 -0
- package/lib/execution-store.d.ts.map +1 -0
- package/lib/execution-store.js +207 -0
- package/lib/execution-store.js.map +1 -0
- package/lib/execution.d.ts +49 -0
- package/lib/execution.d.ts.map +1 -0
- package/lib/execution.js +438 -0
- package/lib/execution.js.map +1 -0
- package/lib/feedback.d.ts +63 -0
- package/lib/feedback.d.ts.map +1 -0
- package/lib/feedback.js +134 -0
- package/lib/feedback.js.map +1 -0
- package/lib/index.d.ts +27 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +9 -0
- package/lib/index.js.map +1 -0
- package/lib/outcome-store.d.ts +47 -0
- package/lib/outcome-store.d.ts.map +1 -0
- package/lib/outcome-store.js +271 -0
- package/lib/outcome-store.js.map +1 -0
- package/lib/outcome.d.ts +77 -0
- package/lib/outcome.d.ts.map +1 -0
- package/lib/outcome.js +417 -0
- package/lib/outcome.js.map +1 -0
- package/lib/service.d.ts +363 -0
- package/lib/service.d.ts.map +1 -0
- package/lib/service.js +1839 -0
- package/lib/service.js.map +1 -0
- package/lib/store.d.ts +21 -0
- package/lib/store.d.ts.map +1 -0
- package/lib/store.js +577 -0
- package/lib/store.js.map +1 -0
- package/lib/strategy-feedback.d.ts +29 -0
- package/lib/strategy-feedback.d.ts.map +1 -0
- package/lib/strategy-feedback.js +53 -0
- package/lib/strategy-feedback.js.map +1 -0
- package/lib/strategy-identity.d.ts +11 -0
- package/lib/strategy-identity.d.ts.map +1 -0
- package/lib/strategy-identity.js +10 -0
- package/lib/strategy-identity.js.map +1 -0
- package/lib/strategy-store.d.ts +76 -0
- package/lib/strategy-store.d.ts.map +1 -0
- package/lib/strategy-store.js +277 -0
- package/lib/strategy-store.js.map +1 -0
- package/lib/strategy.d.ts +56 -0
- package/lib/strategy.d.ts.map +1 -0
- package/lib/strategy.js +478 -0
- package/lib/strategy.js.map +1 -0
- package/lib/tools.d.ts +4 -0
- package/lib/tools.d.ts.map +1 -0
- package/lib/tools.js +130 -0
- package/lib/tools.js.map +1 -0
- package/lib/types.d.ts +285 -0
- package/lib/types.d.ts.map +1 -0
- package/lib/types.js +10 -0
- package/lib/types.js.map +1 -0
- package/lib/verified-artifact.d.ts +72 -0
- package/lib/verified-artifact.d.ts.map +1 -0
- package/lib/verified-artifact.js +142 -0
- package/lib/verified-artifact.js.map +1 -0
- package/lib/verified-workflow.d.ts +120 -0
- package/lib/verified-workflow.d.ts.map +1 -0
- package/lib/verified-workflow.js +253 -0
- package/lib/verified-workflow.js.map +1 -0
- package/lib/version.d.ts +2 -0
- package/lib/version.d.ts.map +1 -0
- package/lib/version.js +2 -0
- package/lib/version.js.map +1 -0
- package/lib/wake-store.d.ts +38 -0
- package/lib/wake-store.d.ts.map +1 -0
- package/lib/wake-store.js +177 -0
- package/lib/wake-store.js.map +1 -0
- package/lib/wake.d.ts +45 -0
- package/lib/wake.d.ts.map +1 -0
- package/lib/wake.js +327 -0
- package/lib/wake.js.map +1 -0
- package/package.json +143 -0
|
@@ -0,0 +1,372 @@
|
|
|
1
|
+
import { acceptanceDigest } from '@dsh-enhanced/task-acceptance-contract';
|
|
2
|
+
import { externalEventDigest, parseExternalEventEnvelope } from '@dsh-enhanced/assistant-automations/external-event';
|
|
3
|
+
import { GoalEventWaitStore } from './event-wait-store.js';
|
|
4
|
+
const same = (a, b) => acceptanceDigest(a) === acceptanceDigest(b);
|
|
5
|
+
function fail() { throw new Error('assistant-goals: event wait authority is unavailable, changed or expired'); }
|
|
6
|
+
const snapshotSame = (a, b) => same({ ...a, highWaterSequence: 0 }, { ...b, highWaterSequence: 0 });
|
|
7
|
+
function reader(value) {
|
|
8
|
+
if (!value || typeof value !== 'object')
|
|
9
|
+
return undefined;
|
|
10
|
+
const candidate = value;
|
|
11
|
+
return typeof candidate.sourceSnapshot === 'function' && typeof candidate.firstEventAfter === 'function' && typeof candidate.subscribeSourceChanges === 'function' ? candidate : undefined;
|
|
12
|
+
}
|
|
13
|
+
function opportunity(value) {
|
|
14
|
+
if (!value || typeof value !== 'object')
|
|
15
|
+
return undefined;
|
|
16
|
+
return typeof value.evaluate === 'function' ? value : undefined;
|
|
17
|
+
}
|
|
18
|
+
function bindsOpportunityContext(decision, input) {
|
|
19
|
+
if (!decision || typeof decision !== 'object')
|
|
20
|
+
return false;
|
|
21
|
+
const candidate = decision;
|
|
22
|
+
return candidate.waitId === input.waitId && candidate.profileId === input.profileId && same(candidate.scope, input.scope)
|
|
23
|
+
&& candidate.goalId === input.goalId && candidate.sessionId === input.sessionId
|
|
24
|
+
&& candidate.definitionDigest === input.definitionDigest && candidate.objective === input.objective
|
|
25
|
+
&& candidate.nativeGoalId === input.nativeGoalId
|
|
26
|
+
&& candidate.nativeRevision === input.nativeRevision && candidate.ownerRouteId === input.ownerRouteId
|
|
27
|
+
&& candidate.sourceDigest === input.sourceDigest && candidate.sourceId === input.sourceId
|
|
28
|
+
&& candidate.expiresAt === input.expiresAt;
|
|
29
|
+
}
|
|
30
|
+
function bindsOpportunityDecision(decision, input) {
|
|
31
|
+
return decision.eventId === input.event.id && decision.eventSequence === input.event.sequence
|
|
32
|
+
&& decision.eventDigest === input.event.digest;
|
|
33
|
+
}
|
|
34
|
+
/** Converts one post-snapshot event observation into one owner-bound GoalWake. */
|
|
35
|
+
export class GoalEventWaitRuntime {
|
|
36
|
+
wake;
|
|
37
|
+
current;
|
|
38
|
+
proactive;
|
|
39
|
+
#store;
|
|
40
|
+
#source;
|
|
41
|
+
#unsubscribe;
|
|
42
|
+
#live = true;
|
|
43
|
+
#failures = 0;
|
|
44
|
+
#cursor = '';
|
|
45
|
+
constructor(ctx, path, wake, current, proactive = () => undefined) {
|
|
46
|
+
this.wake = wake;
|
|
47
|
+
this.current = current;
|
|
48
|
+
this.proactive = proactive;
|
|
49
|
+
this.#store = new GoalEventWaitStore(path);
|
|
50
|
+
ctx.inject(['eventTriggers'], runtime => {
|
|
51
|
+
const candidate = reader(runtime.eventTriggers);
|
|
52
|
+
if (!candidate)
|
|
53
|
+
return () => { };
|
|
54
|
+
this.#source = candidate;
|
|
55
|
+
this.#unsubscribe = candidate.subscribeSourceChanges(() => { this.#onSourceChanged(); });
|
|
56
|
+
this.reconcile();
|
|
57
|
+
return () => { this.#unsubscribe?.(); this.#unsubscribe = undefined; if (this.#source === candidate)
|
|
58
|
+
this.#source = undefined; };
|
|
59
|
+
});
|
|
60
|
+
ctx.effect(() => {
|
|
61
|
+
// Reconciliation only revisits already owner-authorized waits. It never creates
|
|
62
|
+
// a wait or changes an event into wake authority without the frozen intent.
|
|
63
|
+
const timer = setInterval(() => { this.reconcile(); }, 1_000);
|
|
64
|
+
timer.unref?.();
|
|
65
|
+
return () => { clearInterval(timer); this.#live = false; this.#unsubscribe?.(); this.#store.close(); };
|
|
66
|
+
}, 'assistant-goals.event-waits');
|
|
67
|
+
}
|
|
68
|
+
snapshot(triggerId) {
|
|
69
|
+
const source = this.#source;
|
|
70
|
+
if (!this.#live || !source)
|
|
71
|
+
fail();
|
|
72
|
+
return source.sourceSnapshot(triggerId);
|
|
73
|
+
}
|
|
74
|
+
prepare(intent) {
|
|
75
|
+
if (!this.#live)
|
|
76
|
+
fail();
|
|
77
|
+
// A dedicated source is claimed before this wait becomes durable. A
|
|
78
|
+
// competing goal therefore cannot leave a recoverable waiting row.
|
|
79
|
+
this.#source?.claimGoalSource?.(this.#claim(intent));
|
|
80
|
+
const wait = this.#store.prepare(intent);
|
|
81
|
+
// Catch events committed after the source snapshot but before the owner checkpoint.
|
|
82
|
+
this.#reconcile(wait);
|
|
83
|
+
return this.#store.get(wait.intent.id);
|
|
84
|
+
}
|
|
85
|
+
inspect(scope, goalId) { return this.#store.list(scope, goalId); }
|
|
86
|
+
/** A fresh durable wait for this exact paused revision, still under source and owner authority. */
|
|
87
|
+
acceptsPausedRecord(record) {
|
|
88
|
+
if (!this.#live || record.native.phase !== 'paused')
|
|
89
|
+
return false;
|
|
90
|
+
return this.#store.list(record.scope, record.id).some(wait => {
|
|
91
|
+
if (wait.state === 'terminal' || Date.now() >= wait.intent.expiresAt
|
|
92
|
+
|| !same(wait.intent.wake.native, record.native))
|
|
93
|
+
return false;
|
|
94
|
+
try {
|
|
95
|
+
return this.#sourceCurrent(wait.intent) !== undefined && this.#recordCurrent(wait.intent) !== undefined;
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
health = () => ({ enabled: true, connected: this.#source !== undefined, reconciliationFailures: this.#failures });
|
|
103
|
+
reconcile() {
|
|
104
|
+
if (!this.#live)
|
|
105
|
+
return;
|
|
106
|
+
// Bounded pages prevent corrupt or unusually old rows from starving later owners.
|
|
107
|
+
let waits = this.#store.pending(this.#cursor, 32);
|
|
108
|
+
if (waits.length === 0 && this.#cursor !== '') {
|
|
109
|
+
this.#cursor = '';
|
|
110
|
+
waits = this.#store.pending('', 32);
|
|
111
|
+
}
|
|
112
|
+
for (const wait of waits) {
|
|
113
|
+
this.#cursor = wait.intent.id;
|
|
114
|
+
try {
|
|
115
|
+
this.#reconcile(wait);
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
this.#failures++;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
#recordCurrent(intent, requirePaused = true) {
|
|
123
|
+
const record = this.current(intent);
|
|
124
|
+
if (!record || !same(record.scope, intent.wake.scope) || !same(record.definition, intent.wake.definition)
|
|
125
|
+
|| record.native.sessionId !== intent.wake.native.sessionId || record.native.goalId !== intent.wake.native.goalId
|
|
126
|
+
|| record.native.maxGoalRounds !== intent.wake.native.maxGoalRounds
|
|
127
|
+
|| (intent.wake.dependencies === undefined
|
|
128
|
+
? record.checkpoint.dependencies.length > 0
|
|
129
|
+
: !same(record.checkpoint.dependencyBindings ?? [], intent.wake.dependencies))
|
|
130
|
+
|| requirePaused && (!same(record.native, intent.wake.native) || record.native.phase !== 'paused'))
|
|
131
|
+
return undefined;
|
|
132
|
+
return record;
|
|
133
|
+
}
|
|
134
|
+
#sourceCurrent(intent) {
|
|
135
|
+
const source = this.#source;
|
|
136
|
+
if (!source)
|
|
137
|
+
return undefined;
|
|
138
|
+
const prefix = 'event-triggers:';
|
|
139
|
+
if (!intent.source.sourceId.startsWith(prefix) || intent.source.sourceId.length === prefix.length)
|
|
140
|
+
return undefined;
|
|
141
|
+
try {
|
|
142
|
+
const actual = source.sourceSnapshot(intent.source.sourceId.slice(prefix.length));
|
|
143
|
+
return snapshotSame(actual, intent.source) ? actual : undefined;
|
|
144
|
+
}
|
|
145
|
+
catch {
|
|
146
|
+
return undefined;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
#reconcile(wait) {
|
|
150
|
+
if (wait.state === 'terminal')
|
|
151
|
+
return;
|
|
152
|
+
const now = Date.now();
|
|
153
|
+
if ((wait.state === 'waiting' || wait.state === 'matched') && now >= (wait.match?.wake.expiresAt ?? wait.intent.expiresAt)) {
|
|
154
|
+
this.#terminal(wait, 'expired');
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
const source = this.#source;
|
|
158
|
+
if (!source)
|
|
159
|
+
return; // service loss is recoverable; no timer or implicit authority is created.
|
|
160
|
+
let completed;
|
|
161
|
+
try {
|
|
162
|
+
completed = this.#recordCurrent(wait.intent, false);
|
|
163
|
+
}
|
|
164
|
+
catch (error) {
|
|
165
|
+
if (error instanceof Error && /event wait policy denied/u.test(error.message))
|
|
166
|
+
this.#terminal(wait, 'denied');
|
|
167
|
+
else
|
|
168
|
+
throw error;
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
if (completed?.native.phase === 'complete' && wait.state !== 'materialized') {
|
|
172
|
+
source.retireGoalSource?.(this.#claim(wait.intent));
|
|
173
|
+
this.#terminal(wait, 'settled');
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
if (wait.state === 'materialized') {
|
|
177
|
+
const state = this.wake.inspect(wait.intent.wake.scope, wait.intent.wake.goalId)
|
|
178
|
+
.find(item => item.intent.id === wait.match.wake.id)?.state;
|
|
179
|
+
if (state === 'succeeded' || state === 'unknown' || state === 'denied') {
|
|
180
|
+
this.#terminal(wait, 'settled');
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
if (state === 'dispatched' && completed?.native.phase === 'complete')
|
|
184
|
+
source.retireGoalSource?.(this.#claim(wait.intent));
|
|
185
|
+
if (state === 'dispatched' && completed?.native.phase === 'complete' && source.canSettleGoalSource?.(this.#claim(wait.intent)) === true)
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
const actual = this.#sourceCurrent(wait.intent);
|
|
189
|
+
if (!actual) {
|
|
190
|
+
this.#terminal(wait, 'source-changed');
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
// Revalidate on recovery too: a legacy or interrupted row must never
|
|
194
|
+
// regain wake authority if another goal owns this dedicated source.
|
|
195
|
+
try {
|
|
196
|
+
source.claimGoalSource?.(this.#claim(wait.intent));
|
|
197
|
+
}
|
|
198
|
+
catch {
|
|
199
|
+
this.#terminal(wait, 'denied');
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
if (wait.state === 'materialized') {
|
|
203
|
+
const state = this.wake.inspect(wait.intent.wake.scope, wait.intent.wake.goalId)
|
|
204
|
+
.find(item => item.intent.id === wait.match.wake.id)?.state;
|
|
205
|
+
// GoalWake owns the native phase transition while a dispatch is in flight.
|
|
206
|
+
// In particular, complete is observed before its settle/finish CAS.
|
|
207
|
+
if (state === 'dispatched')
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
let record;
|
|
211
|
+
try {
|
|
212
|
+
record = this.#recordCurrent(wait.intent, wait.state !== 'materialized');
|
|
213
|
+
}
|
|
214
|
+
catch (error) {
|
|
215
|
+
if (error instanceof Error && /event wait policy denied/u.test(error.message))
|
|
216
|
+
this.#terminal(wait, 'denied');
|
|
217
|
+
else
|
|
218
|
+
throw error;
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
if (!record || (wait.state === 'materialized' && ['blocked', 'complete', 'cleared'].includes(record.native.phase))) {
|
|
222
|
+
this.#terminal(wait, 'invalid-current');
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
if (wait.intent.wake.dependencies === undefined
|
|
226
|
+
? record.checkpoint.dependencies.length > 0
|
|
227
|
+
: !same(record.checkpoint.dependencyBindings ?? [], wait.intent.wake.dependencies)) {
|
|
228
|
+
this.#terminal(wait, 'invalid-current');
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
if (wait.state === 'waiting') {
|
|
232
|
+
this.wake.preflight(record);
|
|
233
|
+
let found = source.firstEventAfter(wait.intent.source, this.#store.cursor(wait.intent.id), wait.intent.expiresAt);
|
|
234
|
+
if (!found)
|
|
235
|
+
return;
|
|
236
|
+
let envelope = parseExternalEventEnvelope(found.envelope);
|
|
237
|
+
const valid = (candidate, value) => Number.isSafeInteger(candidate.sequence) && candidate.sequence > wait.intent.source.highWaterSequence
|
|
238
|
+
&& value.source.id === wait.intent.source.sourceId && value.source.kind === wait.intent.source.kind
|
|
239
|
+
&& value.source.version === wait.intent.source.version && value.source.configDigest === wait.intent.source.configDigest
|
|
240
|
+
&& value.target.automationId === wait.intent.source.target.automationId;
|
|
241
|
+
if (!valid(found, envelope))
|
|
242
|
+
return;
|
|
243
|
+
if (wait.intent.opportunityProfile !== undefined) {
|
|
244
|
+
const proactive = opportunity(this.proactive());
|
|
245
|
+
if (!proactive) {
|
|
246
|
+
this.#terminal(wait, 'denied');
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
let executable = false;
|
|
250
|
+
for (let observed = 0; observed < 32; observed++) {
|
|
251
|
+
const input = {
|
|
252
|
+
waitId: wait.intent.id, profileId: wait.intent.opportunityProfile, scope: wait.intent.wake.scope,
|
|
253
|
+
goalId: wait.intent.wake.goalId, sessionId: wait.intent.wake.native.sessionId,
|
|
254
|
+
definitionDigest: wait.intent.wake.definition.digest, objective: record.native.objective,
|
|
255
|
+
nativeGoalId: wait.intent.wake.native.goalId, nativeRevision: wait.intent.wake.native.revision,
|
|
256
|
+
ownerRouteId: wait.intent.wake.ownerRouteId, sourceDigest: wait.intent.source.configDigest,
|
|
257
|
+
sourceId: wait.intent.source.sourceId,
|
|
258
|
+
event: { id: envelope.event.id, sequence: found.sequence, digest: externalEventDigest(envelope), occurredAt: envelope.event.occurredAt },
|
|
259
|
+
expiresAt: wait.intent.expiresAt,
|
|
260
|
+
};
|
|
261
|
+
const evaluation = proactive.evaluate(input);
|
|
262
|
+
if (evaluation.disposition === 'consume') {
|
|
263
|
+
this.#store.advanceCursor(wait.intent.id, found.sequence);
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
if (evaluation.disposition === 'execute') {
|
|
267
|
+
if (!bindsOpportunityContext(evaluation.decision, input) || !Number.isSafeInteger(evaluation.decision.eventSequence)
|
|
268
|
+
|| evaluation.decision.eventSequence < found.sequence)
|
|
269
|
+
throw new Error('assistant-goals: opportunity execution does not bind the observed event');
|
|
270
|
+
if (evaluation.decision.eventSequence === found.sequence) {
|
|
271
|
+
if (!bindsOpportunityDecision(evaluation.decision, input))
|
|
272
|
+
throw new Error('assistant-goals: opportunity execution does not bind the observed event');
|
|
273
|
+
executable = true;
|
|
274
|
+
break;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
if (evaluation.disposition !== 'defer' && evaluation.disposition !== 'execute')
|
|
278
|
+
throw new Error('assistant-goals: invalid opportunity evaluation');
|
|
279
|
+
const next = source.firstEventAfter(wait.intent.source, found.sequence, wait.intent.expiresAt);
|
|
280
|
+
if (!next)
|
|
281
|
+
return;
|
|
282
|
+
const nextEnvelope = parseExternalEventEnvelope(next.envelope);
|
|
283
|
+
if (!valid(next, nextEnvelope))
|
|
284
|
+
return;
|
|
285
|
+
found = next;
|
|
286
|
+
envelope = nextEnvelope;
|
|
287
|
+
continue;
|
|
288
|
+
}
|
|
289
|
+
// A full deferred page intentionally keeps the durable cursor unchanged.
|
|
290
|
+
// The next source hint revalidates the same bounded evidence before it can wake.
|
|
291
|
+
if (!executable)
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
const at = now;
|
|
295
|
+
const expiresAt = Math.min(wait.intent.expiresAt, at + wait.intent.runTimeoutMs);
|
|
296
|
+
if (expiresAt - at < 1_000) {
|
|
297
|
+
this.#terminal(wait, 'expired');
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
const wake = { ...wait.intent.wake, id: `goal-event-wake-${wait.intent.id}`, at, expiresAt };
|
|
301
|
+
// Commit the exact wake before scheduling it; restart can only retry this identity.
|
|
302
|
+
wait = this.#store.match(wait.intent.id, { sequence: found.sequence, envelope, wake });
|
|
303
|
+
}
|
|
304
|
+
if (wait.state === 'matched') {
|
|
305
|
+
this.wake.materialize(wait.match.wake);
|
|
306
|
+
this.#store.materialized(wait.intent.id);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
#terminal(wait, reason) {
|
|
310
|
+
if (wait.intent.opportunityProfile !== undefined)
|
|
311
|
+
opportunity(this.proactive())?.closeWait?.(wait.intent.id, wait.intent.wake.scope, reason === 'expired' ? 'expired' : 'cancelled');
|
|
312
|
+
this.#store.terminal(wait.intent.id, reason);
|
|
313
|
+
}
|
|
314
|
+
#onSourceChanged() {
|
|
315
|
+
// This is only a prompt to reconcile; a source notification has no authority itself.
|
|
316
|
+
this.reconcile();
|
|
317
|
+
}
|
|
318
|
+
#claim(intent) {
|
|
319
|
+
const prefix = 'event-triggers:';
|
|
320
|
+
if (!intent.source.sourceId.startsWith(prefix) || intent.source.sourceId.length === prefix.length)
|
|
321
|
+
fail();
|
|
322
|
+
return { triggerId: intent.source.sourceId.slice(prefix.length), scope: intent.wake.scope, goalId: intent.wake.goalId,
|
|
323
|
+
definition: { version: intent.wake.definition.version, digest: intent.wake.definition.digest },
|
|
324
|
+
native: { sessionId: intent.wake.native.sessionId, goalId: intent.wake.native.goalId, revision: intent.wake.native.revision },
|
|
325
|
+
configDigest: intent.source.configDigest, automationId: intent.source.target.automationId };
|
|
326
|
+
}
|
|
327
|
+
/** Read-only authority for preparing an artifact while the original goal stays paused. */
|
|
328
|
+
assertPreparationCurrent(input) {
|
|
329
|
+
const wait = this.#store.get(input.waitId);
|
|
330
|
+
if (!this.#live || !wait || wait.state !== 'waiting' || Date.now() >= wait.intent.expiresAt
|
|
331
|
+
|| wait.intent.opportunityProfile !== input.profileId || !same(wait.intent.wake.scope, input.scope)
|
|
332
|
+
|| wait.intent.wake.goalId !== input.goalId || wait.intent.wake.native.sessionId !== input.sessionId
|
|
333
|
+
|| wait.intent.wake.native.goalId !== input.nativeGoalId || wait.intent.wake.native.revision !== input.nativeRevision
|
|
334
|
+
|| wait.intent.wake.definition.digest !== input.definitionDigest || wait.intent.wake.ownerRouteId !== input.ownerRouteId
|
|
335
|
+
|| wait.intent.source.sourceId !== input.sourceId || wait.intent.source.configDigest !== input.sourceDigest
|
|
336
|
+
|| wait.intent.expiresAt !== input.expiresAt || !Number.isSafeInteger(input.eventSequence)
|
|
337
|
+
|| input.eventSequence <= wait.intent.source.highWaterSequence || !this.#sourceCurrent(wait.intent))
|
|
338
|
+
fail();
|
|
339
|
+
const record = this.#recordCurrent(wait.intent);
|
|
340
|
+
if (!record || record.native.objective !== input.objective)
|
|
341
|
+
fail();
|
|
342
|
+
this.wake.preflight(record);
|
|
343
|
+
const source = this.#source?.firstEventAfter(wait.intent.source, input.eventSequence - 1, input.expiresAt);
|
|
344
|
+
if (!source || source.sequence !== input.eventSequence || source.envelope.event.id !== input.eventId
|
|
345
|
+
|| externalEventDigest(source.envelope) !== input.eventDigest)
|
|
346
|
+
fail();
|
|
347
|
+
}
|
|
348
|
+
/** Called by GoalWakeRuntime before native resume. Scheduled wakes remain unaffected. */
|
|
349
|
+
assertWakeCurrent(wakeIntent, phase = 'before-resume') {
|
|
350
|
+
if (!wakeIntent.id.startsWith('goal-event-wake-'))
|
|
351
|
+
return;
|
|
352
|
+
const waitId = wakeIntent.id.slice('goal-event-wake-'.length);
|
|
353
|
+
const wait = this.#store.get(waitId);
|
|
354
|
+
if (!wait || (wait.state !== 'matched' && wait.state !== 'materialized') || !wait.match || !same(wait.match.wake, wakeIntent)
|
|
355
|
+
|| Date.now() >= wakeIntent.expiresAt)
|
|
356
|
+
fail();
|
|
357
|
+
const record = this.#recordCurrent(wait.intent, false);
|
|
358
|
+
if (!record)
|
|
359
|
+
fail();
|
|
360
|
+
// Retirement stops new observation/execution, but does not revoke the
|
|
361
|
+
// already dispatched wake's right to settle its exact completed Goal.
|
|
362
|
+
if (phase === 'terminal' && wait.state === 'materialized' && record.native.phase === 'complete'
|
|
363
|
+
&& this.wake.inspect(wait.intent.wake.scope, wait.intent.wake.goalId).some(wake => wake.intent.id === wakeIntent.id && wake.state === 'dispatched')) {
|
|
364
|
+
this.#source?.retireGoalSource?.(this.#claim(wait.intent));
|
|
365
|
+
if (this.#source?.canSettleGoalSource?.(this.#claim(wait.intent)) === true)
|
|
366
|
+
return;
|
|
367
|
+
}
|
|
368
|
+
if (!this.#sourceCurrent(wait.intent))
|
|
369
|
+
fail();
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
//# sourceMappingURL=event-wait.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-wait.js","sourceRoot":"","sources":["../src/event-wait.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { GoalExecutionIntent, GoalExecutionRun, GoalScope } from './types.js';
|
|
2
|
+
/** Durable, non-dispatching ledger. A recovered dispatch is always unknown. */
|
|
3
|
+
export declare class GoalExecutionStore {
|
|
4
|
+
#private;
|
|
5
|
+
constructor(path: string);
|
|
6
|
+
prepare(input: GoalExecutionIntent): GoalExecutionRun;
|
|
7
|
+
get(runId: string): GoalExecutionRun | undefined;
|
|
8
|
+
bindAcceptance(runId: string, acceptance: {
|
|
9
|
+
contractId: string;
|
|
10
|
+
contractDigest: string;
|
|
11
|
+
}): GoalExecutionRun;
|
|
12
|
+
markDispatched(runId: string, now: number): GoalExecutionRun;
|
|
13
|
+
finish(runId: string, execution: {
|
|
14
|
+
status: 'succeeded' | 'unknown';
|
|
15
|
+
quiescent: boolean;
|
|
16
|
+
completedAt: number;
|
|
17
|
+
}): GoalExecutionRun;
|
|
18
|
+
getByContract(contractId: string): GoalExecutionRun | undefined;
|
|
19
|
+
listForGoal(scope: GoalScope, goalId: string, limit?: number): readonly GoalExecutionRun[];
|
|
20
|
+
recoverIncomplete(): readonly GoalExecutionRun[];
|
|
21
|
+
close(): void;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=execution-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"execution-store.d.ts","sourceRoot":"","sources":["../src/execution-store.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AA8ClF,gFAAgF;AAChF,qBAAa,kBAAkB;;gBAEjB,IAAI,EAAE,MAAM;IAmDxB,OAAO,CAAC,KAAK,EAAE,mBAAmB,GAAG,gBAAgB;IAMrD,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS;IAChD,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,cAAc,EAAE,MAAM,CAAA;KAAE,GAAG,gBAAgB;IAO3G,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,gBAAgB;IAI5D,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE;QAAE,MAAM,EAAE,WAAW,GAAG,SAAS,CAAC;QAAC,SAAS,EAAE,OAAO,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,GAAG,gBAAgB;IAMhI,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS;IAC/D,WAAW,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,SAAK,GAAG,SAAS,gBAAgB,EAAE;IAWtF,iBAAiB,IAAI,SAAS,gBAAgB,EAAE;IAChD,KAAK,IAAI,IAAI;CACd"}
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import { DatabaseSync } from 'node:sqlite';
|
|
2
|
+
import { acceptanceCanonicalJson, acceptanceDigest } from '@dsh-enhanced/task-acceptance-contract';
|
|
3
|
+
import { GoalStoreError } from './types.js';
|
|
4
|
+
import { prepareGoalStoreDatabaseFile } from './store.js';
|
|
5
|
+
function fail(code) { throw new GoalStoreError(code); }
|
|
6
|
+
const same = (left, right) => acceptanceDigest(left) === acceptanceDigest(right);
|
|
7
|
+
const parse = (value) => { try {
|
|
8
|
+
return JSON.parse(value);
|
|
9
|
+
}
|
|
10
|
+
catch {
|
|
11
|
+
return fail('schema');
|
|
12
|
+
} };
|
|
13
|
+
const freeze = (value) => { if (value && typeof value === 'object') {
|
|
14
|
+
for (const child of Object.values(value))
|
|
15
|
+
freeze(child);
|
|
16
|
+
Object.freeze(value);
|
|
17
|
+
} ; return value; };
|
|
18
|
+
function intentInput(value) {
|
|
19
|
+
const { runId, scope, objective, dependencies, admission, task } = value ?? {};
|
|
20
|
+
if (typeof runId !== 'string' || runId.length === 0 || runId.length > 512 || typeof objective !== 'string' || objective.length === 0 || objective.length > 16_384
|
|
21
|
+
|| !scope || typeof scope.principalId !== 'string' || typeof scope.principalRecordId !== 'string' || !Number.isSafeInteger(scope.principalVersion) || scope.principalVersion < 1
|
|
22
|
+
|| typeof scope.workspace !== 'string' || !scope.workspace.startsWith('/') || typeof scope.preset !== 'string'
|
|
23
|
+
|| !admission || !Number.isSafeInteger(admission.issuedAt) || admission.issuedAt < 0 || !Number.isSafeInteger(admission.expiresAt)
|
|
24
|
+
|| admission.expiresAt <= admission.issuedAt || admission.expiresAt - admission.issuedAt > 300_000
|
|
25
|
+
|| !Number.isSafeInteger(admission.maxGoalRounds) || admission.maxGoalRounds < 1 || !Number.isSafeInteger(admission.round) || admission.round < 1 || admission.round > admission.maxGoalRounds
|
|
26
|
+
|| admission.authorizationDigest !== acceptanceDigest({ scope, action: 'execute', resource: { kind: 'goal', id: 'business-context' } })
|
|
27
|
+
|| !task || task.kind !== 'goal-step' || task.ref !== runId || !task.goal || task.goal.runId !== runId
|
|
28
|
+
|| [task.goal.id, task.goal.stepId, task.goal.sessionId, task.goal.nativeGoalId].some(item => typeof item !== 'string' || !/^[A-Za-z0-9_.:-]{1,512}$/u.test(item))
|
|
29
|
+
|| !Number.isSafeInteger(task.goal.definitionVersion) || task.goal.definitionVersion < 1 || !Number.isSafeInteger(task.goal.nativeRevision) || task.goal.nativeRevision < 1
|
|
30
|
+
|| task.goal.definitionDigest !== acceptanceDigest({ objective })
|
|
31
|
+
|| dependencies !== undefined && (!Array.isArray(dependencies) || dependencies.length > 16
|
|
32
|
+
|| new Set(dependencies.map(item => item?.goalId)).size !== dependencies.length
|
|
33
|
+
|| dependencies.some(item => item === null || typeof item !== 'object'
|
|
34
|
+
|| Object.keys(item).length !== 3 || !Object.hasOwn(item, 'goalId') || !Object.hasOwn(item, 'definitionVersion') || !Object.hasOwn(item, 'definitionDigest')
|
|
35
|
+
|| typeof item.goalId !== 'string' || !/^[A-Za-z0-9_.:-]{1,512}$/u.test(item.goalId)
|
|
36
|
+
|| !Number.isSafeInteger(item.definitionVersion) || item.definitionVersion < 1
|
|
37
|
+
|| typeof item.definitionDigest !== 'string' || !/^[a-f0-9]{64}$/u.test(item.definitionDigest))))
|
|
38
|
+
fail('invalid-input');
|
|
39
|
+
return freeze(JSON.parse(JSON.stringify(value)));
|
|
40
|
+
}
|
|
41
|
+
function run(row) {
|
|
42
|
+
const intent = intentInput(parse(row.intent_json));
|
|
43
|
+
if (row.scope_key !== acceptanceCanonicalJson(intent.scope) || row.goal_id !== intent.task.goal.id || row.issued_at !== intent.admission.issuedAt)
|
|
44
|
+
fail('schema');
|
|
45
|
+
const acceptance = row.contract_id === null && row.contract_digest === null ? undefined
|
|
46
|
+
: (typeof row.contract_id === 'string' && /^[A-Za-z0-9_.:-]{1,512}$/u.test(row.contract_id) && typeof row.contract_digest === 'string' && /^[a-f0-9]{64}$/u.test(row.contract_digest)
|
|
47
|
+
? freeze({ contractId: row.contract_id, contractDigest: row.contract_digest }) : fail('schema'));
|
|
48
|
+
const dispatchedAt = row.dispatched_at === null ? undefined : (Number.isSafeInteger(row.dispatched_at) && row.dispatched_at >= 0 ? row.dispatched_at : fail('schema'));
|
|
49
|
+
const execution = row.execution_json === null ? undefined : parse(row.execution_json);
|
|
50
|
+
if (execution && (execution.status !== 'succeeded' && execution.status !== 'unknown' || typeof execution.quiescent !== 'boolean' || !Number.isSafeInteger(execution.completedAt) || execution.completedAt < 0))
|
|
51
|
+
fail('schema');
|
|
52
|
+
if (dispatchedAt !== undefined && (acceptance === undefined || dispatchedAt < intent.admission.issuedAt || dispatchedAt >= intent.admission.expiresAt))
|
|
53
|
+
fail('schema');
|
|
54
|
+
if (execution !== undefined && (execution === null || dispatchedAt === undefined || execution.completedAt < dispatchedAt
|
|
55
|
+
|| (execution.status === 'succeeded' && (!execution.quiescent || execution.completedAt >= intent.admission.expiresAt))))
|
|
56
|
+
fail('schema');
|
|
57
|
+
return freeze({ intent, ...(acceptance === undefined ? {} : { acceptance }), ...(dispatchedAt === undefined ? {} : { dispatchedAt }), ...(execution === undefined ? {} : { execution: freeze(execution) }) });
|
|
58
|
+
}
|
|
59
|
+
/** Durable, non-dispatching ledger. A recovered dispatch is always unknown. */
|
|
60
|
+
export class GoalExecutionStore {
|
|
61
|
+
#database;
|
|
62
|
+
constructor(path) {
|
|
63
|
+
if (path !== ':memory:')
|
|
64
|
+
prepareGoalStoreDatabaseFile(path);
|
|
65
|
+
this.#database = new DatabaseSync(path, { enableForeignKeyConstraints: true });
|
|
66
|
+
try {
|
|
67
|
+
this.#database.exec('PRAGMA foreign_keys = ON; PRAGMA busy_timeout = 250; PRAGMA journal_mode = WAL; PRAGMA synchronous = FULL;');
|
|
68
|
+
let version = this.#database.prepare('PRAGMA user_version').get().user_version;
|
|
69
|
+
const tables = this.#database.prepare("SELECT name FROM sqlite_schema WHERE type = 'table' AND name NOT LIKE 'sqlite_%'").all();
|
|
70
|
+
if (version === 0 && tables.length === 0) {
|
|
71
|
+
this.#database.exec(`
|
|
72
|
+
BEGIN IMMEDIATE;
|
|
73
|
+
CREATE TABLE IF NOT EXISTS goal_execution_runs (
|
|
74
|
+
run_id TEXT PRIMARY KEY, intent_json TEXT NOT NULL, contract_id TEXT UNIQUE, contract_digest TEXT,
|
|
75
|
+
dispatched_at INTEGER, execution_json TEXT, scope_key TEXT NOT NULL, goal_id TEXT NOT NULL, issued_at INTEGER NOT NULL
|
|
76
|
+
) STRICT;
|
|
77
|
+
PRAGMA user_version = 2; COMMIT;`);
|
|
78
|
+
version = 2;
|
|
79
|
+
}
|
|
80
|
+
else if (version === 1 && tables.length === 1 && tables[0]?.name === 'goal_execution_runs') {
|
|
81
|
+
this.#database.exec('BEGIN IMMEDIATE;');
|
|
82
|
+
try {
|
|
83
|
+
this.#database.exec("ALTER TABLE goal_execution_runs ADD COLUMN scope_key TEXT NOT NULL DEFAULT ''; ALTER TABLE goal_execution_runs ADD COLUMN goal_id TEXT NOT NULL DEFAULT ''; ALTER TABLE goal_execution_runs ADD COLUMN issued_at INTEGER NOT NULL DEFAULT 0;");
|
|
84
|
+
const rows = this.#database.prepare('SELECT run_id, intent_json FROM goal_execution_runs').all();
|
|
85
|
+
const backfill = this.#database.prepare('UPDATE goal_execution_runs SET scope_key = ?, goal_id = ?, issued_at = ? WHERE run_id = ?');
|
|
86
|
+
for (const row of rows) {
|
|
87
|
+
const intent = intentInput(parse(row.intent_json));
|
|
88
|
+
backfill.run(acceptanceCanonicalJson(intent.scope), intent.task.goal.id, intent.admission.issuedAt, row.run_id);
|
|
89
|
+
this.#get(row.run_id);
|
|
90
|
+
}
|
|
91
|
+
this.#database.exec('PRAGMA user_version = 2; COMMIT;');
|
|
92
|
+
version = 2;
|
|
93
|
+
}
|
|
94
|
+
catch (error) {
|
|
95
|
+
this.#database.exec('ROLLBACK;');
|
|
96
|
+
throw error;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
else if (version !== 2 || tables.length !== 1 || tables[0]?.name !== 'goal_execution_runs')
|
|
100
|
+
fail('schema');
|
|
101
|
+
const columns = this.#database.prepare('PRAGMA table_info(goal_execution_runs)').all().map(item => item.name);
|
|
102
|
+
if (!same(columns, ['run_id', 'intent_json', 'contract_id', 'contract_digest', 'dispatched_at', 'execution_json', 'scope_key', 'goal_id', 'issued_at']))
|
|
103
|
+
fail('schema');
|
|
104
|
+
this.#database.exec('CREATE INDEX IF NOT EXISTS goal_execution_scope_goal_issued ON goal_execution_runs(scope_key, goal_id, issued_at DESC, run_id ASC)');
|
|
105
|
+
for (const row of this.#database.prepare('SELECT run_id FROM goal_execution_runs').all())
|
|
106
|
+
this.#get(row.run_id);
|
|
107
|
+
if (path !== ':memory:')
|
|
108
|
+
prepareGoalStoreDatabaseFile(path);
|
|
109
|
+
}
|
|
110
|
+
catch (error) {
|
|
111
|
+
this.#database.close();
|
|
112
|
+
throw error;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
#get(runId) {
|
|
116
|
+
const row = this.#database.prepare('SELECT intent_json, contract_id, contract_digest, dispatched_at, execution_json, scope_key, goal_id, issued_at FROM goal_execution_runs WHERE run_id = ?').get(runId);
|
|
117
|
+
if (row === undefined)
|
|
118
|
+
return undefined;
|
|
119
|
+
const result = run(row);
|
|
120
|
+
if (result.intent.runId !== runId)
|
|
121
|
+
fail('schema');
|
|
122
|
+
return result;
|
|
123
|
+
}
|
|
124
|
+
#write(sql, ...parameters) {
|
|
125
|
+
try {
|
|
126
|
+
return Number(this.#database.prepare(sql).run(...parameters).changes);
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
fail('conflict');
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
prepare(input) {
|
|
133
|
+
const intent = intentInput(input);
|
|
134
|
+
const existing = this.#get(intent.runId);
|
|
135
|
+
if (existing !== undefined) {
|
|
136
|
+
if (!same(existing.intent, intent))
|
|
137
|
+
fail('conflict');
|
|
138
|
+
return existing;
|
|
139
|
+
}
|
|
140
|
+
this.#write('INSERT INTO goal_execution_runs(run_id, intent_json, scope_key, goal_id, issued_at) VALUES (?, ?, ?, ?, ?)', intent.runId, JSON.stringify(intent), acceptanceCanonicalJson(intent.scope), intent.task.goal.id, intent.admission.issuedAt);
|
|
141
|
+
return this.#get(intent.runId);
|
|
142
|
+
}
|
|
143
|
+
get(runId) { return typeof runId === 'string' ? this.#get(runId) : fail('invalid-input'); }
|
|
144
|
+
bindAcceptance(runId, acceptance) {
|
|
145
|
+
const found = this.#get(runId);
|
|
146
|
+
if (!found)
|
|
147
|
+
fail('not-found');
|
|
148
|
+
if (!/^[A-Za-z0-9_.:-]{1,512}$/u.test(acceptance.contractId) || !/^[a-f0-9]{64}$/u.test(acceptance.contractDigest))
|
|
149
|
+
fail('invalid-input');
|
|
150
|
+
if (found.acceptance) {
|
|
151
|
+
if (!same(found.acceptance, acceptance))
|
|
152
|
+
fail('conflict');
|
|
153
|
+
return found;
|
|
154
|
+
}
|
|
155
|
+
if (this.#write('UPDATE goal_execution_runs SET contract_id = ?, contract_digest = ? WHERE run_id = ? AND contract_id IS NULL AND contract_digest IS NULL', acceptance.contractId, acceptance.contractDigest, runId) !== 1)
|
|
156
|
+
fail('conflict');
|
|
157
|
+
return this.#get(runId);
|
|
158
|
+
}
|
|
159
|
+
markDispatched(runId, now) {
|
|
160
|
+
const found = this.#get(runId);
|
|
161
|
+
if (!found)
|
|
162
|
+
fail('not-found');
|
|
163
|
+
if (found.acceptance === undefined || found.dispatchedAt !== undefined || found.execution !== undefined || !Number.isSafeInteger(now) || now < found.intent.admission.issuedAt || now >= found.intent.admission.expiresAt)
|
|
164
|
+
fail('conflict');
|
|
165
|
+
if (this.#write('UPDATE goal_execution_runs SET dispatched_at = ? WHERE run_id = ? AND dispatched_at IS NULL AND execution_json IS NULL', now, runId) !== 1)
|
|
166
|
+
fail('conflict');
|
|
167
|
+
return this.#get(runId);
|
|
168
|
+
}
|
|
169
|
+
finish(runId, execution) {
|
|
170
|
+
const found = this.#get(runId);
|
|
171
|
+
if (!found)
|
|
172
|
+
fail('not-found');
|
|
173
|
+
if (found.dispatchedAt === undefined || !Number.isSafeInteger(execution.completedAt) || execution.completedAt < found.dispatchedAt || typeof execution.quiescent !== 'boolean' || (execution.status !== 'succeeded' && execution.status !== 'unknown'))
|
|
174
|
+
fail('invalid-input');
|
|
175
|
+
if (found.execution) {
|
|
176
|
+
if (same(found.execution, execution))
|
|
177
|
+
return found;
|
|
178
|
+
fail('conflict');
|
|
179
|
+
}
|
|
180
|
+
if (execution.status === 'succeeded' && (!execution.quiescent || execution.completedAt >= found.intent.admission.expiresAt))
|
|
181
|
+
fail('invalid-input');
|
|
182
|
+
if (this.#write('UPDATE goal_execution_runs SET execution_json = ? WHERE run_id = ? AND execution_json IS NULL', JSON.stringify(freeze({ ...execution })), runId) !== 1)
|
|
183
|
+
fail('conflict');
|
|
184
|
+
return this.#get(runId);
|
|
185
|
+
}
|
|
186
|
+
getByContract(contractId) { if (typeof contractId !== 'string')
|
|
187
|
+
fail('invalid-input'); const row = this.#database.prepare('SELECT run_id FROM goal_execution_runs WHERE contract_id = ?').get(contractId); return row ? this.#get(row.run_id) : undefined; }
|
|
188
|
+
listForGoal(scope, goalId, limit = 50) {
|
|
189
|
+
if (!scope || typeof scope.principalId !== 'string' || typeof scope.principalRecordId !== 'string'
|
|
190
|
+
|| !Number.isSafeInteger(scope.principalVersion) || scope.principalVersion < 1
|
|
191
|
+
|| typeof scope.workspace !== 'string' || !scope.workspace.startsWith('/') || typeof scope.preset !== 'string'
|
|
192
|
+
|| !Number.isSafeInteger(limit) || limit < 1 || limit > 100
|
|
193
|
+
|| typeof goalId !== 'string' || !/^[A-Za-z0-9_.:-]{1,512}$/u.test(goalId))
|
|
194
|
+
fail('invalid-input');
|
|
195
|
+
const key = acceptanceCanonicalJson(scope);
|
|
196
|
+
const rows = this.#database.prepare('SELECT run_id FROM goal_execution_runs WHERE scope_key = ? AND goal_id = ? ORDER BY issued_at DESC, run_id ASC LIMIT ?')
|
|
197
|
+
.all(key, goalId, limit);
|
|
198
|
+
return freeze(rows.map(row => this.#get(row.run_id)));
|
|
199
|
+
}
|
|
200
|
+
recoverIncomplete() { const rows = this.#database.prepare('SELECT run_id, dispatched_at FROM goal_execution_runs WHERE dispatched_at IS NOT NULL AND execution_json IS NULL').all(); const recovered = []; for (const row of rows) {
|
|
201
|
+
const execution = JSON.stringify({ status: 'unknown', quiescent: false, completedAt: row.dispatched_at });
|
|
202
|
+
if (this.#write('UPDATE goal_execution_runs SET execution_json = ? WHERE run_id = ? AND execution_json IS NULL', execution, row.run_id) === 1)
|
|
203
|
+
recovered.push(this.#get(row.run_id));
|
|
204
|
+
} ; return freeze(recovered); }
|
|
205
|
+
close() { this.#database.close(); }
|
|
206
|
+
}
|
|
207
|
+
//# sourceMappingURL=execution-store.js.map
|