@dsh-enhanced/assistant-work-items 0.0.0-stage → 0.1.67
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 +685 -2
- package/cordis.patch.yml +11 -0
- package/lib/acceptance-binding.d.ts +86 -0
- package/lib/acceptance-binding.d.ts.map +1 -0
- package/lib/acceptance-binding.js +250 -0
- package/lib/acceptance-binding.js.map +1 -0
- package/lib/admission.d.ts +95 -0
- package/lib/admission.d.ts.map +1 -0
- package/lib/admission.js +642 -0
- package/lib/admission.js.map +1 -0
- package/lib/authority.d.ts +99 -0
- package/lib/authority.d.ts.map +1 -0
- package/lib/authority.js +233 -0
- package/lib/authority.js.map +1 -0
- package/lib/config.d.ts +365 -0
- package/lib/config.d.ts.map +1 -0
- package/lib/config.js +672 -0
- package/lib/config.js.map +1 -0
- package/lib/continuation-contract.d.ts +126 -0
- package/lib/continuation-contract.d.ts.map +1 -0
- package/lib/continuation-contract.js +109 -0
- package/lib/continuation-contract.js.map +1 -0
- package/lib/continuation-record.d.ts +32 -0
- package/lib/continuation-record.d.ts.map +1 -0
- package/lib/continuation-record.js +57 -0
- package/lib/continuation-record.js.map +1 -0
- package/lib/continuation.d.ts +89 -0
- package/lib/continuation.d.ts.map +1 -0
- package/lib/continuation.js +607 -0
- package/lib/continuation.js.map +1 -0
- package/lib/diagnosis-contract.d.ts +95 -0
- package/lib/diagnosis-contract.d.ts.map +1 -0
- package/lib/diagnosis-contract.js +167 -0
- package/lib/diagnosis-contract.js.map +1 -0
- package/lib/diagnosis.d.ts +70 -0
- package/lib/diagnosis.d.ts.map +1 -0
- package/lib/diagnosis.js +466 -0
- package/lib/diagnosis.js.map +1 -0
- package/lib/dispatch.d.ts +100 -0
- package/lib/dispatch.d.ts.map +1 -0
- package/lib/dispatch.js +317 -0
- package/lib/dispatch.js.map +1 -0
- package/lib/engineering-context.d.ts +86 -0
- package/lib/engineering-context.d.ts.map +1 -0
- package/lib/engineering-context.js +263 -0
- package/lib/engineering-context.js.map +1 -0
- package/lib/evaluation.d.ts +125 -0
- package/lib/evaluation.d.ts.map +1 -0
- package/lib/evaluation.js +295 -0
- package/lib/evaluation.js.map +1 -0
- package/lib/event-follow.d.ts +93 -0
- package/lib/event-follow.d.ts.map +1 -0
- package/lib/event-follow.js +150 -0
- package/lib/event-follow.js.map +1 -0
- package/lib/feedback-targets.d.ts +91 -0
- package/lib/feedback-targets.d.ts.map +1 -0
- package/lib/feedback-targets.js +362 -0
- package/lib/feedback-targets.js.map +1 -0
- package/lib/index.d.ts +27 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +25 -0
- package/lib/index.js.map +1 -0
- package/lib/intake-admission.d.ts +49 -0
- package/lib/intake-admission.d.ts.map +1 -0
- package/lib/intake-admission.js +100 -0
- package/lib/intake-admission.js.map +1 -0
- package/lib/intake-evaluation-runtime.d.ts +74 -0
- package/lib/intake-evaluation-runtime.d.ts.map +1 -0
- package/lib/intake-evaluation-runtime.js +343 -0
- package/lib/intake-evaluation-runtime.js.map +1 -0
- package/lib/intake-evaluation.d.ts +180 -0
- package/lib/intake-evaluation.d.ts.map +1 -0
- package/lib/intake-evaluation.js +440 -0
- package/lib/intake-evaluation.js.map +1 -0
- package/lib/intake.d.ts +118 -0
- package/lib/intake.d.ts.map +1 -0
- package/lib/intake.js +137 -0
- package/lib/intake.js.map +1 -0
- package/lib/ledger.d.ts +86 -0
- package/lib/ledger.d.ts.map +1 -0
- package/lib/ledger.js +145 -0
- package/lib/ledger.js.map +1 -0
- package/lib/mandate.d.ts +45 -0
- package/lib/mandate.d.ts.map +1 -0
- package/lib/mandate.js +168 -0
- package/lib/mandate.js.map +1 -0
- package/lib/outcome.d.ts +137 -0
- package/lib/outcome.d.ts.map +1 -0
- package/lib/outcome.js +303 -0
- package/lib/outcome.js.map +1 -0
- package/lib/owner-access.d.ts +35 -0
- package/lib/owner-access.d.ts.map +1 -0
- package/lib/owner-access.js +152 -0
- package/lib/owner-access.js.map +1 -0
- package/lib/owner-continuation.d.ts +27 -0
- package/lib/owner-continuation.d.ts.map +1 -0
- package/lib/owner-continuation.js +131 -0
- package/lib/owner-continuation.js.map +1 -0
- package/lib/owner-recall.d.ts +85 -0
- package/lib/owner-recall.d.ts.map +1 -0
- package/lib/owner-recall.js +134 -0
- package/lib/owner-recall.js.map +1 -0
- package/lib/owner-replies.d.ts +44 -0
- package/lib/owner-replies.d.ts.map +1 -0
- package/lib/owner-replies.js +268 -0
- package/lib/owner-replies.js.map +1 -0
- package/lib/peers.d.ts +624 -0
- package/lib/peers.d.ts.map +1 -0
- package/lib/peers.js +10 -0
- package/lib/peers.js.map +1 -0
- package/lib/policy-notice.d.ts +31 -0
- package/lib/policy-notice.d.ts.map +1 -0
- package/lib/policy-notice.js +137 -0
- package/lib/policy-notice.js.map +1 -0
- package/lib/reply-contract.d.ts +67 -0
- package/lib/reply-contract.d.ts.map +1 -0
- package/lib/reply-contract.js +58 -0
- package/lib/reply-contract.js.map +1 -0
- package/lib/service.d.ts +632 -0
- package/lib/service.d.ts.map +1 -0
- package/lib/service.js +2447 -0
- package/lib/service.js.map +1 -0
- package/lib/settlement.d.ts +74 -0
- package/lib/settlement.d.ts.map +1 -0
- package/lib/settlement.js +233 -0
- package/lib/settlement.js.map +1 -0
- package/lib/signals.d.ts +176 -0
- package/lib/signals.d.ts.map +1 -0
- package/lib/signals.js +497 -0
- package/lib/signals.js.map +1 -0
- package/lib/store.d.ts +791 -0
- package/lib/store.d.ts.map +1 -0
- package/lib/store.js +3266 -0
- package/lib/store.js.map +1 -0
- package/lib/tools.d.ts +7 -0
- package/lib/tools.d.ts.map +1 -0
- package/lib/tools.js +443 -0
- package/lib/tools.js.map +1 -0
- package/lib/types.d.ts +831 -0
- package/lib/types.d.ts.map +1 -0
- package/lib/types.js +29 -0
- package/lib/types.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/workspace.d.ts +43 -0
- package/lib/workspace.d.ts.map +1 -0
- package/lib/workspace.js +137 -0
- package/lib/workspace.js.map +1 -0
- package/package.json +101 -3
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
import { createHash, randomUUID } from 'node:crypto';
|
|
2
|
+
import { WorkItemError } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Protocol identity of the work-item → Evaluation producer seam.
|
|
5
|
+
*
|
|
6
|
+
* The `assistant-evaluation` plugin validates this exact string on the
|
|
7
|
+
* registration it hands back, so the two plugins agree on a versioned contract
|
|
8
|
+
* without either importing the other's implementation.
|
|
9
|
+
*/
|
|
10
|
+
export const WORK_ITEM_EVALUATION_PROTOCOL = 'assistant-work-items/evaluation/v1';
|
|
11
|
+
/** Stable prefix of every Evaluation idempotency key this producer emits. */
|
|
12
|
+
export const WORK_ITEM_EVALUATION_ID_PREFIX = 'work-items';
|
|
13
|
+
/** Bounded export attempts per settled revision; the row stays `pending`. */
|
|
14
|
+
export const WORK_ITEM_EVALUATION_MAX_ATTEMPTS = 5;
|
|
15
|
+
/** Bounded exports per drain pass, so a busy ledger cannot starve the host. */
|
|
16
|
+
export const WORK_ITEM_EVALUATION_MAX_PER_SWEEP = 10;
|
|
17
|
+
/** Runtime guard; `assistant-evaluation` keeps an equivalent local copy. */
|
|
18
|
+
export function isWorkItemEvaluationProducer(value) {
|
|
19
|
+
return typeof value === 'object' && value !== null
|
|
20
|
+
&& typeof value.trustedWorkItemProducerGeneration === 'function'
|
|
21
|
+
&& typeof value.registerTrustedWorkItemEvaluationSink === 'function';
|
|
22
|
+
}
|
|
23
|
+
/** Stable identity of one settled revision for Evaluation's idempotency check. */
|
|
24
|
+
export function workItemEvaluationIdempotencyKey(itemId, revision, evidenceState) {
|
|
25
|
+
return `${WORK_ITEM_EVALUATION_ID_PREFIX}/${itemId}/${String(revision)}/${evidenceState}`;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Situation taxonomy shared by every work item of one admitted kind.
|
|
29
|
+
*
|
|
30
|
+
* Grouping by kind (not by item) keeps downstream learning comparable; the
|
|
31
|
+
* per-item identity lives in the idempotency key and evidence refs instead.
|
|
32
|
+
*/
|
|
33
|
+
export function workItemEvaluationSituation(kind) {
|
|
34
|
+
return `work-item:${kind}`;
|
|
35
|
+
}
|
|
36
|
+
/** Only durable, independently sourced facts; no model prose reaches Evaluation. */
|
|
37
|
+
function metricsFor(item, outcome) {
|
|
38
|
+
if (item === undefined)
|
|
39
|
+
return Object.freeze({});
|
|
40
|
+
const latencyMs = Math.max(0, outcome.settledAt - item.createdAt);
|
|
41
|
+
const retries = Math.max(0, item.attempt - 1);
|
|
42
|
+
return Object.freeze(retries > 0 ? { latencyMs, retries } : { latencyMs });
|
|
43
|
+
}
|
|
44
|
+
function digestOf(claims) {
|
|
45
|
+
return createHash('sha256').update(JSON.stringify([
|
|
46
|
+
claims.scope.workspace,
|
|
47
|
+
claims.scope.preset,
|
|
48
|
+
claims.itemId,
|
|
49
|
+
claims.outcomeRevision,
|
|
50
|
+
claims.settledBy,
|
|
51
|
+
claims.evidenceState,
|
|
52
|
+
claims.situation,
|
|
53
|
+
claims.objectiveStatus,
|
|
54
|
+
claims.deliveryStatus,
|
|
55
|
+
claims.occurredAt,
|
|
56
|
+
claims.idempotencyKey,
|
|
57
|
+
claims.metrics,
|
|
58
|
+
])).digest('hex');
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Project one store outcome into the exact claims Evaluation accepts.
|
|
62
|
+
*
|
|
63
|
+
* `execution` is the bounded ledger count bag when the caller could read it;
|
|
64
|
+
* omitting it keeps the live-record fallback so a direct projection call still
|
|
65
|
+
* works. Returns `null` for revisions that are not exportable at all: a window
|
|
66
|
+
* still `pending` can change, so publishing it would contradict a later
|
|
67
|
+
* revision.
|
|
68
|
+
*/
|
|
69
|
+
export function workItemEvaluationClaims(outcome, scope, item, execution) {
|
|
70
|
+
if (outcome.evidenceState === 'pending')
|
|
71
|
+
return null;
|
|
72
|
+
const evidenceState = outcome.evidenceState;
|
|
73
|
+
const base = {
|
|
74
|
+
scope: Object.freeze({ workspace: scope.workspace, preset: scope.preset }),
|
|
75
|
+
itemId: outcome.itemId,
|
|
76
|
+
outcomeRevision: outcome.revision,
|
|
77
|
+
settledBy: outcome.settledBy,
|
|
78
|
+
evidenceState,
|
|
79
|
+
situation: workItemEvaluationSituation(item?.kind ?? 'work-item'),
|
|
80
|
+
occurredAt: outcome.settledAt,
|
|
81
|
+
idempotencyKey: workItemEvaluationIdempotencyKey(outcome.itemId, outcome.revision, evidenceState),
|
|
82
|
+
metrics: execution ?? metricsFor(item, outcome),
|
|
83
|
+
objectiveStatus: 'unknown',
|
|
84
|
+
deliveryStatus: 'unknown',
|
|
85
|
+
};
|
|
86
|
+
return Object.freeze({ ...base, digest: digestOf(base) });
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Bounded work-item → Evaluation exporter.
|
|
90
|
+
*
|
|
91
|
+
* Evaluation owns the append; this class owns only its own outbox columns. A
|
|
92
|
+
* pass is bounded by `maxPerSweep`, never runs on a timer (it is triggered by
|
|
93
|
+
* registration and by the transaction boundaries that can create a new settled
|
|
94
|
+
* revision), and a failed append leaves the row `pending` with a capped attempt
|
|
95
|
+
* count that health can surface instead of silently dropping evidence.
|
|
96
|
+
*/
|
|
97
|
+
export class WorkItemEvaluationExporter {
|
|
98
|
+
#options;
|
|
99
|
+
#generation = randomUUID();
|
|
100
|
+
#registration;
|
|
101
|
+
#draining;
|
|
102
|
+
#degraded = null;
|
|
103
|
+
constructor(options) {
|
|
104
|
+
this.#options = options;
|
|
105
|
+
}
|
|
106
|
+
get generation() {
|
|
107
|
+
return this.#generation;
|
|
108
|
+
}
|
|
109
|
+
get connected() {
|
|
110
|
+
return this.#registration !== undefined;
|
|
111
|
+
}
|
|
112
|
+
get degraded() {
|
|
113
|
+
return this.#degraded;
|
|
114
|
+
}
|
|
115
|
+
/** Capability consumed by `assistant-evaluation`; stable for this instance. */
|
|
116
|
+
trustedWorkItemProducerGeneration() {
|
|
117
|
+
return this.#generation;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Accept the exact registration Evaluation built for this generation.
|
|
121
|
+
*
|
|
122
|
+
* Exactly one sink may be registered: a second registration is refused so
|
|
123
|
+
* evidence cannot be double-exported under two capabilities, and the returned
|
|
124
|
+
* disposer only clears the registration it owns.
|
|
125
|
+
*/
|
|
126
|
+
registerTrustedWorkItemEvaluationSink(registration) {
|
|
127
|
+
if (typeof registration !== 'object' || registration === null || Array.isArray(registration)) {
|
|
128
|
+
fail('invalid-state', 'work-item Evaluation registration is invalid');
|
|
129
|
+
}
|
|
130
|
+
if (registration.protocol !== WORK_ITEM_EVALUATION_PROTOCOL) {
|
|
131
|
+
fail('invalid-state', 'work-item Evaluation registration protocol is mismatched');
|
|
132
|
+
}
|
|
133
|
+
if (registration.generation !== this.#generation) {
|
|
134
|
+
fail('invalid-state', 'work-item Evaluation registration generation is mismatched');
|
|
135
|
+
}
|
|
136
|
+
if (typeof registration.append !== 'function') {
|
|
137
|
+
fail('invalid-state', 'work-item Evaluation registration cannot append');
|
|
138
|
+
}
|
|
139
|
+
const owner = registration.owner;
|
|
140
|
+
if (typeof owner !== 'object' || owner === null
|
|
141
|
+
|| typeof owner.ownsTrustedWorkItemEvaluationRegistration !== 'function'
|
|
142
|
+
|| owner.ownsTrustedWorkItemEvaluationRegistration(registration) !== true) {
|
|
143
|
+
fail('invalid-state', 'work-item Evaluation registration is not owned by its producer host');
|
|
144
|
+
}
|
|
145
|
+
if (this.#registration !== undefined) {
|
|
146
|
+
fail('invalid-state', 'a work-item Evaluation sink is already registered');
|
|
147
|
+
}
|
|
148
|
+
const current = Object.freeze({ ...registration });
|
|
149
|
+
this.#registration = current;
|
|
150
|
+
// Registration is itself a boundary that may have missed settlements, so
|
|
151
|
+
// one bounded pass runs immediately; the next transactions keep it fed.
|
|
152
|
+
void this.drain().catch(error => {
|
|
153
|
+
// The registration boundary must not surface a rejection to the producer;
|
|
154
|
+
// the failed pass is already visible through `degraded` health.
|
|
155
|
+
this.#degraded = describe(error);
|
|
156
|
+
this.#options.warn?.(`assistant-work-items: Evaluation export pass failed: ${describe(error)}`);
|
|
157
|
+
});
|
|
158
|
+
return () => {
|
|
159
|
+
if (this.#registration !== current)
|
|
160
|
+
return;
|
|
161
|
+
this.#registration = undefined;
|
|
162
|
+
this.#degraded = null;
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
/** Withdraw any sink on service disposal. */
|
|
166
|
+
dispose() {
|
|
167
|
+
this.#registration = undefined;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Run bounded export passes serially; a caller never joins a stale pass.
|
|
171
|
+
*
|
|
172
|
+
* A drain that arrives while one is in flight queues exactly one follow-up
|
|
173
|
+
* pass instead of returning the in-flight result: the settlement that
|
|
174
|
+
* prompted the second call may have committed after the first pass read its
|
|
175
|
+
* candidates, and silently joining it would postpone that evidence until the
|
|
176
|
+
* next unrelated transaction.
|
|
177
|
+
*
|
|
178
|
+
* Never rejects: every failure is recorded as degraded health so a caller on
|
|
179
|
+
* a transaction boundary cannot fail because Export is unavailable.
|
|
180
|
+
*/
|
|
181
|
+
drain(limit = this.#options.maxPerSweep ?? WORK_ITEM_EVALUATION_MAX_PER_SWEEP) {
|
|
182
|
+
const running = this.#draining;
|
|
183
|
+
if (running === undefined) {
|
|
184
|
+
const pass = this.#drainOnce(limit).finally(() => {
|
|
185
|
+
if (this.#draining === pass)
|
|
186
|
+
this.#draining = undefined;
|
|
187
|
+
});
|
|
188
|
+
this.#draining = pass;
|
|
189
|
+
return pass;
|
|
190
|
+
}
|
|
191
|
+
const follow = running.then(() => this.#drainOnce(limit));
|
|
192
|
+
const tracked = follow.finally(() => {
|
|
193
|
+
if (this.#draining === tracked)
|
|
194
|
+
this.#draining = undefined;
|
|
195
|
+
});
|
|
196
|
+
this.#draining = tracked;
|
|
197
|
+
return tracked;
|
|
198
|
+
}
|
|
199
|
+
async #drainOnce(limit) {
|
|
200
|
+
this.#degraded = null;
|
|
201
|
+
if (!this.#options.enabled())
|
|
202
|
+
return;
|
|
203
|
+
const store = this.#options.store();
|
|
204
|
+
if (store === undefined)
|
|
205
|
+
return;
|
|
206
|
+
const registration = this.#registration;
|
|
207
|
+
if (registration === undefined)
|
|
208
|
+
return;
|
|
209
|
+
let candidates;
|
|
210
|
+
try {
|
|
211
|
+
candidates = store.outcomesAwaitingEvaluation(limit, WORK_ITEM_EVALUATION_MAX_ATTEMPTS);
|
|
212
|
+
}
|
|
213
|
+
catch (error) {
|
|
214
|
+
this.#degraded = describe(error);
|
|
215
|
+
this.#options.warn?.(`assistant-work-items: Evaluation outbox read failed: ${describe(error)}`);
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
if (candidates.length === 0) {
|
|
219
|
+
// Nothing sweeps now, but an exhausted row is still a real gap between a
|
|
220
|
+
// settled outcome and the trusted lane; keep it visible in health.
|
|
221
|
+
try {
|
|
222
|
+
if (store.countExhaustedEvaluations(WORK_ITEM_EVALUATION_MAX_ATTEMPTS) > 0) {
|
|
223
|
+
this.#degraded = 'export-attempts-exhausted';
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
catch (error) {
|
|
227
|
+
this.#degraded = describe(error);
|
|
228
|
+
}
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
const scope = this.#options.scope();
|
|
232
|
+
if (scope === null) {
|
|
233
|
+
// No exact workspace+preset means no honest Evaluation scope, so the
|
|
234
|
+
// settled revisions are terminally skipped rather than guessed.
|
|
235
|
+
this.#degraded = 'owner-route-unavailable';
|
|
236
|
+
for (const outcome of candidates) {
|
|
237
|
+
try {
|
|
238
|
+
store.markOutcomeSkipped(outcome.itemId, outcome.revision, this.#options.now());
|
|
239
|
+
}
|
|
240
|
+
catch (error) {
|
|
241
|
+
this.#degraded = describe(error);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
for (const outcome of candidates) {
|
|
247
|
+
if (this.#registration !== registration)
|
|
248
|
+
return;
|
|
249
|
+
let claims;
|
|
250
|
+
try {
|
|
251
|
+
// The item row is read outside the append guard because a store fault
|
|
252
|
+
// here must not reject a pass that other transactions already awaited.
|
|
253
|
+
const item = store.findItemById(outcome.itemId);
|
|
254
|
+
claims = workItemEvaluationClaims(outcome, scope, item, store.workItemExecutionMetrics(outcome.itemId, outcome.settledAt));
|
|
255
|
+
}
|
|
256
|
+
catch (error) {
|
|
257
|
+
this.#degraded = describe(error);
|
|
258
|
+
this.#options.warn?.(`assistant-work-items: Evaluation claims read failed: ${describe(error)}`);
|
|
259
|
+
continue;
|
|
260
|
+
}
|
|
261
|
+
if (claims === null)
|
|
262
|
+
continue;
|
|
263
|
+
try {
|
|
264
|
+
await registration.append(claims);
|
|
265
|
+
}
|
|
266
|
+
catch (error) {
|
|
267
|
+
this.#degraded = describe(error);
|
|
268
|
+
this.#options.warn?.(`assistant-work-items: Evaluation export failed: ${describe(error)}`);
|
|
269
|
+
try {
|
|
270
|
+
store.recordOutcomeEvaluationAttempt(outcome.itemId, outcome.revision, WORK_ITEM_EVALUATION_MAX_ATTEMPTS);
|
|
271
|
+
}
|
|
272
|
+
catch (recordError) {
|
|
273
|
+
this.#degraded = describe(recordError);
|
|
274
|
+
}
|
|
275
|
+
continue;
|
|
276
|
+
}
|
|
277
|
+
try {
|
|
278
|
+
store.markOutcomeExported(outcome.itemId, outcome.revision, claims.digest, this.#options.now());
|
|
279
|
+
}
|
|
280
|
+
catch (error) {
|
|
281
|
+
// The append succeeded, so the row must not be retried; a state race is
|
|
282
|
+
// still reported instead of being erased.
|
|
283
|
+
this.#degraded = describe(error);
|
|
284
|
+
this.#options.warn?.(`assistant-work-items: Evaluation export marker failed: ${describe(error)}`);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
function fail(code, message) {
|
|
290
|
+
throw new WorkItemError(code, message);
|
|
291
|
+
}
|
|
292
|
+
function describe(error) {
|
|
293
|
+
return error instanceof Error ? error.message : String(error);
|
|
294
|
+
}
|
|
295
|
+
//# sourceMappingURL=evaluation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"evaluation.js","sourceRoot":"","sources":["../src/evaluation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAapD,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAE1C;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,6BAA6B,GAAG,oCAAoC,CAAA;AACjF,6EAA6E;AAC7E,MAAM,CAAC,MAAM,8BAA8B,GAAG,YAAY,CAAA;AAC1D,6EAA6E;AAC7E,MAAM,CAAC,MAAM,iCAAiC,GAAG,CAAC,CAAA;AAClD,+EAA+E;AAC/E,MAAM,CAAC,MAAM,kCAAkC,GAAG,EAAE,CAAA;AAwCpD,4EAA4E;AAC5E,MAAM,UAAU,4BAA4B,CAAC,KAAc;IACzD,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;WAC7C,OAAQ,KAA6C,CAAC,iCAAiC,KAAK,UAAU;WACtG,OAAQ,KAA6C,CAAC,qCAAqC,KAAK,UAAU,CAAA;AACjH,CAAC;AAED,kFAAkF;AAClF,MAAM,UAAU,gCAAgC,CAC9C,MAAc,EACd,QAAgB,EAChB,aAA8C;IAE9C,OAAO,GAAG,8BAA8B,IAAI,MAAM,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI,aAAa,EAAE,CAAA;AAC3F,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,2BAA2B,CAAC,IAAY;IACtD,OAAO,aAAa,IAAI,EAAE,CAAA;AAC5B,CAAC;AAED,oFAAoF;AACpF,SAAS,UAAU,CAAC,IAAgC,EAAE,OAA8B;IAClF,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;IAChD,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,CAAA;IACjE,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC,CAAA;IAC7C,OAAO,MAAM,CAAC,MAAM,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAA;AAC5E,CAAC;AAED,SAAS,QAAQ,CAAC,MAAgD;IAChE,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC;QAChD,MAAM,CAAC,KAAK,CAAC,SAAS;QACtB,MAAM,CAAC,KAAK,CAAC,MAAM;QACnB,MAAM,CAAC,MAAM;QACb,MAAM,CAAC,eAAe;QACtB,MAAM,CAAC,SAAS;QAChB,MAAM,CAAC,aAAa;QACpB,MAAM,CAAC,SAAS;QAChB,MAAM,CAAC,eAAe;QACtB,MAAM,CAAC,cAAc;QACrB,MAAM,CAAC,UAAU;QACjB,MAAM,CAAC,cAAc;QACrB,MAAM,CAAC,OAAO;KACf,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;AACnB,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,wBAAwB,CACtC,OAA8B,EAC9B,KAA8B,EAC9B,IAAgC,EAChC,SAA8C;IAE9C,IAAI,OAAO,CAAC,aAAa,KAAK,SAAS;QAAE,OAAO,IAAI,CAAA;IACpD,MAAM,aAAa,GAAG,OAAO,CAAC,aAAa,CAAA;IAC3C,MAAM,IAAI,GAA6C;QACrD,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC;QAC1E,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,eAAe,EAAE,OAAO,CAAC,QAAQ;QACjC,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,aAAa;QACb,SAAS,EAAE,2BAA2B,CAAC,IAAI,EAAE,IAAI,IAAI,WAAW,CAAC;QACjE,UAAU,EAAE,OAAO,CAAC,SAAS;QAC7B,cAAc,EAAE,gCAAgC,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,QAAQ,EAAE,aAAa,CAAC;QACjG,OAAO,EAAE,SAAS,IAAI,UAAU,CAAC,IAAI,EAAE,OAAO,CAAC;QAC/C,eAAe,EAAE,SAAS;QAC1B,cAAc,EAAE,SAAS;KAC1B,CAAA;IACD,OAAO,MAAM,CAAC,MAAM,CAAC,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;AAC3D,CAAC;AAcD;;;;;;;;GAQG;AACH,MAAM,OAAO,0BAA0B;IAC5B,QAAQ,CAAmC;IAC3C,WAAW,GAAG,UAAU,EAAE,CAAA;IACnC,aAAa,CAA4C;IACzD,SAAS,CAA2B;IACpC,SAAS,GAAkB,IAAI,CAAA;IAE/B,YAAY,OAA0C;QACpD,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAA;IACzB,CAAC;IAED,IAAI,UAAU;QACZ,OAAO,IAAI,CAAC,WAAW,CAAA;IACzB,CAAC;IAED,IAAI,SAAS;QACX,OAAO,IAAI,CAAC,aAAa,KAAK,SAAS,CAAA;IACzC,CAAC;IAED,IAAI,QAAQ;QACV,OAAO,IAAI,CAAC,SAAS,CAAA;IACvB,CAAC;IAED,+EAA+E;IAC/E,iCAAiC;QAC/B,OAAO,IAAI,CAAC,WAAW,CAAA;IACzB,CAAC;IAED;;;;;;OAMG;IACH,qCAAqC,CAAC,YAAsD;QAC1F,IAAI,OAAO,YAAY,KAAK,QAAQ,IAAI,YAAY,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,CAAC;YAC7F,IAAI,CAAC,eAAe,EAAE,8CAA8C,CAAC,CAAA;QACvE,CAAC;QACD,IAAI,YAAY,CAAC,QAAQ,KAAK,6BAA6B,EAAE,CAAC;YAC5D,IAAI,CAAC,eAAe,EAAE,0DAA0D,CAAC,CAAA;QACnF,CAAC;QACD,IAAI,YAAY,CAAC,UAAU,KAAK,IAAI,CAAC,WAAW,EAAE,CAAC;YACjD,IAAI,CAAC,eAAe,EAAE,4DAA4D,CAAC,CAAA;QACrF,CAAC;QACD,IAAI,OAAO,YAAY,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;YAC9C,IAAI,CAAC,eAAe,EAAE,iDAAiD,CAAC,CAAA;QAC1E,CAAC;QACD,MAAM,KAAK,GAAG,YAAY,CAAC,KAAK,CAAA;QAChC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;eAC1C,OAAO,KAAK,CAAC,yCAAyC,KAAK,UAAU;eACrE,KAAK,CAAC,yCAAyC,CAAC,YAAY,CAAC,KAAK,IAAI,EAAE,CAAC;YAC5E,IAAI,CAAC,eAAe,EAAE,qEAAqE,CAAC,CAAA;QAC9F,CAAC;QACD,IAAI,IAAI,CAAC,aAAa,KAAK,SAAS,EAAE,CAAC;YACrC,IAAI,CAAC,eAAe,EAAE,mDAAmD,CAAC,CAAA;QAC5E,CAAC;QACD,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,EAAE,GAAG,YAAY,EAAE,CAAC,CAAA;QAClD,IAAI,CAAC,aAAa,GAAG,OAAO,CAAA;QAC5B,yEAAyE;QACzE,wEAAwE;QACxE,KAAK,IAAI,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE;YAC9B,0EAA0E;YAC1E,gEAAgE;YAChE,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;YAChC,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,wDAAwD,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;QACjG,CAAC,CAAC,CAAA;QACF,OAAO,GAAG,EAAE;YACV,IAAI,IAAI,CAAC,aAAa,KAAK,OAAO;gBAAE,OAAM;YAC1C,IAAI,CAAC,aAAa,GAAG,SAAS,CAAA;YAC9B,IAAI,CAAC,SAAS,GAAG,IAAI,CAAA;QACvB,CAAC,CAAA;IACH,CAAC;IAED,6CAA6C;IAC7C,OAAO;QACL,IAAI,CAAC,aAAa,GAAG,SAAS,CAAA;IAChC,CAAC;IAED;;;;;;;;;;;OAWG;IACH,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,WAAW,IAAI,kCAAkC;QAC3E,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAA;QAC9B,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;YAC1B,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE;gBAC/C,IAAI,IAAI,CAAC,SAAS,KAAK,IAAI;oBAAE,IAAI,CAAC,SAAS,GAAG,SAAS,CAAA;YACzD,CAAC,CAAC,CAAA;YACF,IAAI,CAAC,SAAS,GAAG,IAAI,CAAA;YACrB,OAAO,IAAI,CAAA;QACb,CAAC;QACD,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAA;QACzD,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE;YAClC,IAAI,IAAI,CAAC,SAAS,KAAK,OAAO;gBAAE,IAAI,CAAC,SAAS,GAAG,SAAS,CAAA;QAC5D,CAAC,CAAC,CAAA;QACF,IAAI,CAAC,SAAS,GAAG,OAAO,CAAA;QACxB,OAAO,OAAO,CAAA;IAChB,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,KAAa;QAC5B,IAAI,CAAC,SAAS,GAAG,IAAI,CAAA;QACrB,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE;YAAE,OAAM;QACpC,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAA;QACnC,IAAI,KAAK,KAAK,SAAS;YAAE,OAAM;QAC/B,MAAM,YAAY,GAAG,IAAI,CAAC,aAAa,CAAA;QACvC,IAAI,YAAY,KAAK,SAAS;YAAE,OAAM;QACtC,IAAI,UAA4C,CAAA;QAChD,IAAI,CAAC;YACH,UAAU,GAAG,KAAK,CAAC,0BAA0B,CAAC,KAAK,EAAE,iCAAiC,CAAC,CAAA;QACzF,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;YAChC,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,wDAAwD,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;YAC/F,OAAM;QACR,CAAC;QACD,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC5B,yEAAyE;YACzE,mEAAmE;YACnE,IAAI,CAAC;gBACH,IAAI,KAAK,CAAC,yBAAyB,CAAC,iCAAiC,CAAC,GAAG,CAAC,EAAE,CAAC;oBAC3E,IAAI,CAAC,SAAS,GAAG,2BAA2B,CAAA;gBAC9C,CAAC;YACH,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;YAClC,CAAC;YACD,OAAM;QACR,CAAC;QACD,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAA;QACnC,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;YACnB,qEAAqE;YACrE,gEAAgE;YAChE,IAAI,CAAC,SAAS,GAAG,yBAAyB,CAAA;YAC1C,KAAK,MAAM,OAAO,IAAI,UAAU,EAAE,CAAC;gBACjC,IAAI,CAAC;oBACH,KAAK,CAAC,kBAAkB,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,QAAQ,EAAE,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC,CAAA;gBACjF,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;gBAClC,CAAC;YACH,CAAC;YACD,OAAM;QACR,CAAC;QACD,KAAK,MAAM,OAAO,IAAI,UAAU,EAAE,CAAC;YACjC,IAAI,IAAI,CAAC,aAAa,KAAK,YAAY;gBAAE,OAAM;YAC/C,IAAI,MAAuC,CAAA;YAC3C,IAAI,CAAC;gBACH,sEAAsE;gBACtE,uEAAuE;gBACvE,MAAM,IAAI,GAAG,KAAK,CAAC,YAAY,CAAC,OAAO,CAAC,MAAM,CAAC,CAAA;gBAC/C,MAAM,GAAG,wBAAwB,CAC/B,OAAO,EACP,KAAK,EACL,IAAI,EACJ,KAAK,CAAC,wBAAwB,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,SAAS,CAAC,CAClE,CAAA;YACH,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;gBAChC,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,wDAAwD,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;gBAC/F,SAAQ;YACV,CAAC;YACD,IAAI,MAAM,KAAK,IAAI;gBAAE,SAAQ;YAC7B,IAAI,CAAC;gBACH,MAAM,YAAY,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;YACnC,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;gBAChC,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,mDAAmD,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;gBAC1F,IAAI,CAAC;oBACH,KAAK,CAAC,8BAA8B,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,QAAQ,EAAE,iCAAiC,CAAC,CAAA;gBAC3G,CAAC;gBAAC,OAAO,WAAW,EAAE,CAAC;oBACrB,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAC,WAAW,CAAC,CAAA;gBACxC,CAAC;gBACD,SAAQ;YACV,CAAC;YACD,IAAI,CAAC;gBACH,KAAK,CAAC,mBAAmB,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC,CAAA;YACjG,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,wEAAwE;gBACxE,0CAA0C;gBAC1C,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;gBAChC,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,0DAA0D,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;YACnG,CAAC;QACH,CAAC;IACH,CAAC;CACF;AAED,SAAS,IAAI,CAAC,IAAoD,EAAE,OAAe;IACjF,MAAM,IAAI,aAAa,CAAC,IAAI,EAAE,OAAO,CAAC,CAAA;AACxC,CAAC;AAED,SAAS,QAAQ,CAAC,KAAc;IAC9B,OAAO,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;AAC/D,CAAC"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import type { WorkItemThreadSourceRegistration } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Event Triggers as a followed-thread source (subscription pass-through, slice 1).
|
|
4
|
+
*
|
|
5
|
+
* A work item may follow `event-triggers` refs shaped
|
|
6
|
+
* `<triggerId>@<afterSequence>@<configDigest>`; with `acceptHeadRef` an
|
|
7
|
+
* admission may also pass `<triggerId>@head`, which is rewritten to that
|
|
8
|
+
* canonical form before it is validated or stored.
|
|
9
|
+
* The follow closes once the first authenticated source event after that cursor
|
|
10
|
+
* exists. The event only proves something happened on the subscription, never
|
|
11
|
+
* that the objective was achieved, so a closure always reports outcome
|
|
12
|
+
* `unknown` and the settled outcome stays unverified.
|
|
13
|
+
*
|
|
14
|
+
* Everything here is passive: resolution runs inside the existing bounded
|
|
15
|
+
* settlement pass, and this module adds no timers or change subscriptions.
|
|
16
|
+
*/
|
|
17
|
+
export declare const EVENT_TRIGGERS_FOLLOW_SOURCE = "event-triggers";
|
|
18
|
+
/** Owner scope exactly as `eventTriggers.inspectOwnerSources` matches it. */
|
|
19
|
+
export interface EventFollowOwnerScope {
|
|
20
|
+
readonly principalId: string;
|
|
21
|
+
readonly principalRecordId: string;
|
|
22
|
+
readonly principalVersion: number;
|
|
23
|
+
readonly workspace: string;
|
|
24
|
+
readonly preset: string;
|
|
25
|
+
}
|
|
26
|
+
interface SourceSnapshot {
|
|
27
|
+
readonly protocol: string;
|
|
28
|
+
readonly sourceId: string;
|
|
29
|
+
readonly kind: string;
|
|
30
|
+
readonly version: string;
|
|
31
|
+
readonly configDigest: string;
|
|
32
|
+
readonly target: {
|
|
33
|
+
readonly automationId: string;
|
|
34
|
+
};
|
|
35
|
+
readonly highWaterSequence: number;
|
|
36
|
+
}
|
|
37
|
+
interface OwnerSource {
|
|
38
|
+
readonly triggerId: string;
|
|
39
|
+
readonly automationId: string;
|
|
40
|
+
readonly kind: string;
|
|
41
|
+
}
|
|
42
|
+
/** Structural subset of the Event Triggers service; it is never imported. */
|
|
43
|
+
export interface EventFollowReader {
|
|
44
|
+
inspectOwnerSources(scope: EventFollowOwnerScope): readonly OwnerSource[];
|
|
45
|
+
sourceSnapshot(triggerId: string): Readonly<SourceSnapshot>;
|
|
46
|
+
firstEventAfter(snapshot: Readonly<SourceSnapshot>, afterSequence: number, deadlineAt: number): Readonly<{
|
|
47
|
+
sequence: number;
|
|
48
|
+
envelope: unknown;
|
|
49
|
+
}> | undefined;
|
|
50
|
+
}
|
|
51
|
+
export declare function eventFollowReader(value: unknown): EventFollowReader | undefined;
|
|
52
|
+
export interface EventFollowRef {
|
|
53
|
+
readonly triggerId: string;
|
|
54
|
+
readonly afterSequence: number;
|
|
55
|
+
readonly configDigest: string;
|
|
56
|
+
}
|
|
57
|
+
/** Trigger id of an admission-only `<triggerId>@head` alias; never a stored ref. */
|
|
58
|
+
export declare function parseEventFollowHeadRef(ref: string): string | undefined;
|
|
59
|
+
/** Parse `<triggerId>@<afterSequence>@<configDigest>`; anything else is not an event follow. */
|
|
60
|
+
export declare function parseEventFollowRef(ref: string): EventFollowRef | undefined;
|
|
61
|
+
/**
|
|
62
|
+
* Same bytes as `externalEventDigest` for an envelope Event Triggers already
|
|
63
|
+
* parsed and digest-checked; kept local so the optional peer is not imported.
|
|
64
|
+
*/
|
|
65
|
+
export declare function eventEnvelopeDigest(envelope: unknown): string;
|
|
66
|
+
/**
|
|
67
|
+
* Follow protocol version carried in the generation. Event Triggers exposes its
|
|
68
|
+
* package version only on per-trigger snapshots, which vanish when a trigger is
|
|
69
|
+
* disabled or its observer expires, so a stable constant is used instead; an
|
|
70
|
+
* Event Triggers version change surfaces per follow because `firstEventAfter`
|
|
71
|
+
* only matches envelopes of the snapshot's version.
|
|
72
|
+
*/
|
|
73
|
+
export declare const EVENT_FOLLOW_PROTOCOL = "v1";
|
|
74
|
+
/**
|
|
75
|
+
* The source generation depends only on the owner identity, never on runtime
|
|
76
|
+
* trigger state (observer expiry, goal retirement, automation pause, config
|
|
77
|
+
* edits). Per-trigger config isolation lives in the ref's config digest, so one
|
|
78
|
+
* trigger's change degrades only the follows on that trigger.
|
|
79
|
+
*/
|
|
80
|
+
export declare function eventFollowGeneration(owner: EventFollowOwnerScope): string;
|
|
81
|
+
/**
|
|
82
|
+
* Build the `event-triggers` registration. `owner` is read live on every call so
|
|
83
|
+
* a revoked or changed owner route fails closed instead of reusing old scope.
|
|
84
|
+
*/
|
|
85
|
+
export declare function eventFollowRegistration(input: {
|
|
86
|
+
readonly reader: EventFollowReader;
|
|
87
|
+
readonly owner: () => EventFollowOwnerScope;
|
|
88
|
+
readonly now?: () => number;
|
|
89
|
+
/** Accept the admission-only `<triggerId>@head` alias (`follows.eventTriggers.acceptHeadRef`). */
|
|
90
|
+
readonly acceptHeadRef?: boolean;
|
|
91
|
+
}): WorkItemThreadSourceRegistration;
|
|
92
|
+
export {};
|
|
93
|
+
//# sourceMappingURL=event-follow.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-follow.d.ts","sourceRoot":"","sources":["../src/event-follow.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAyB,gCAAgC,EAAE,MAAM,YAAY,CAAA;AAEzF;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,4BAA4B,mBAAmB,CAAA;AAE5D,6EAA6E;AAC7E,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAA;IAClC,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAA;IACjC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CACxB;AAED,UAAU,cAAc;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAC7B,QAAQ,CAAC,MAAM,EAAE;QAAE,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;KAAE,CAAA;IAClD,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAA;CACnC;AAED,UAAU,WAAW;IAAG,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE;AAE1G,6EAA6E;AAC7E,MAAM,WAAW,iBAAiB;IAChC,mBAAmB,CAAC,KAAK,EAAE,qBAAqB,GAAG,SAAS,WAAW,EAAE,CAAA;IACzE,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,QAAQ,CAAC,cAAc,CAAC,CAAA;IAC3D,eAAe,CAAC,QAAQ,EAAE,QAAQ,CAAC,cAAc,CAAC,EAAE,aAAa,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,QAAQ,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAA;KAAE,CAAC,GAAG,SAAS,CAAA;CAC9J;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,iBAAiB,GAAG,SAAS,CAK/E;AAMD,MAAM,WAAW,cAAc;IAAG,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;CAAE;AAI7H,oFAAoF;AACpF,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAGvE;AAED,gGAAgG;AAChG,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS,CAK3E;AASD;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,OAAO,GAAG,MAAM,CAE7D;AAED;;;;;;GAMG;AACH,eAAO,MAAM,qBAAqB,OAAO,CAAA;AAEzC;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,qBAAqB,GAAG,MAAM,CAK1E;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE;IAC7C,QAAQ,CAAC,MAAM,EAAE,iBAAiB,CAAA;IAClC,QAAQ,CAAC,KAAK,EAAE,MAAM,qBAAqB,CAAA;IAC3C,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;IAC3B,kGAAkG;IAClG,QAAQ,CAAC,aAAa,CAAC,EAAE,OAAO,CAAA;CACjC,GAAG,gCAAgC,CA2DnC"}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
/**
|
|
3
|
+
* Event Triggers as a followed-thread source (subscription pass-through, slice 1).
|
|
4
|
+
*
|
|
5
|
+
* A work item may follow `event-triggers` refs shaped
|
|
6
|
+
* `<triggerId>@<afterSequence>@<configDigest>`; with `acceptHeadRef` an
|
|
7
|
+
* admission may also pass `<triggerId>@head`, which is rewritten to that
|
|
8
|
+
* canonical form before it is validated or stored.
|
|
9
|
+
* The follow closes once the first authenticated source event after that cursor
|
|
10
|
+
* exists. The event only proves something happened on the subscription, never
|
|
11
|
+
* that the objective was achieved, so a closure always reports outcome
|
|
12
|
+
* `unknown` and the settled outcome stays unverified.
|
|
13
|
+
*
|
|
14
|
+
* Everything here is passive: resolution runs inside the existing bounded
|
|
15
|
+
* settlement pass, and this module adds no timers or change subscriptions.
|
|
16
|
+
*/
|
|
17
|
+
export const EVENT_TRIGGERS_FOLLOW_SOURCE = 'event-triggers';
|
|
18
|
+
export function eventFollowReader(value) {
|
|
19
|
+
if (!value || typeof value !== 'object')
|
|
20
|
+
return undefined;
|
|
21
|
+
const candidate = value;
|
|
22
|
+
return typeof candidate.inspectOwnerSources === 'function' && typeof candidate.sourceSnapshot === 'function'
|
|
23
|
+
&& typeof candidate.firstEventAfter === 'function' ? candidate : undefined;
|
|
24
|
+
}
|
|
25
|
+
// Trigger ids follow Event Triggers' stable lowercase identifier shape; the
|
|
26
|
+
// trailing segment is the trigger's 64-hex config digest at admission.
|
|
27
|
+
const REF = /^([a-z0-9][a-z0-9._:-]{0,199})@(0|[1-9][0-9]{0,15})@([a-f0-9]{64})$/;
|
|
28
|
+
const HEAD_REF = /^([a-z0-9][a-z0-9._:-]{0,199})@head$/;
|
|
29
|
+
/** Trigger id of an admission-only `<triggerId>@head` alias; never a stored ref. */
|
|
30
|
+
export function parseEventFollowHeadRef(ref) {
|
|
31
|
+
const match = typeof ref === 'string' ? HEAD_REF.exec(ref) : null;
|
|
32
|
+
return match === null ? undefined : match[1];
|
|
33
|
+
}
|
|
34
|
+
/** Parse `<triggerId>@<afterSequence>@<configDigest>`; anything else is not an event follow. */
|
|
35
|
+
export function parseEventFollowRef(ref) {
|
|
36
|
+
const match = typeof ref === 'string' ? REF.exec(ref) : null;
|
|
37
|
+
if (match === null)
|
|
38
|
+
return undefined;
|
|
39
|
+
const afterSequence = Number(match[2]);
|
|
40
|
+
return Number.isSafeInteger(afterSequence) ? { triggerId: match[1], afterSequence, configDigest: match[3] } : undefined;
|
|
41
|
+
}
|
|
42
|
+
function canonical(value) {
|
|
43
|
+
if (value === null || typeof value !== 'object')
|
|
44
|
+
return JSON.stringify(value);
|
|
45
|
+
if (Array.isArray(value))
|
|
46
|
+
return `[${value.map(canonical).join(',')}]`;
|
|
47
|
+
const input = value;
|
|
48
|
+
return `{${Object.keys(input).sort().map(key => `${JSON.stringify(key)}:${canonical(input[key])}`).join(',')}}`;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Same bytes as `externalEventDigest` for an envelope Event Triggers already
|
|
52
|
+
* parsed and digest-checked; kept local so the optional peer is not imported.
|
|
53
|
+
*/
|
|
54
|
+
export function eventEnvelopeDigest(envelope) {
|
|
55
|
+
return createHash('sha256').update(canonical(envelope)).digest('hex');
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Follow protocol version carried in the generation. Event Triggers exposes its
|
|
59
|
+
* package version only on per-trigger snapshots, which vanish when a trigger is
|
|
60
|
+
* disabled or its observer expires, so a stable constant is used instead; an
|
|
61
|
+
* Event Triggers version change surfaces per follow because `firstEventAfter`
|
|
62
|
+
* only matches envelopes of the snapshot's version.
|
|
63
|
+
*/
|
|
64
|
+
export const EVENT_FOLLOW_PROTOCOL = 'v1';
|
|
65
|
+
/**
|
|
66
|
+
* The source generation depends only on the owner identity, never on runtime
|
|
67
|
+
* trigger state (observer expiry, goal retirement, automation pause, config
|
|
68
|
+
* edits). Per-trigger config isolation lives in the ref's config digest, so one
|
|
69
|
+
* trigger's change degrades only the follows on that trigger.
|
|
70
|
+
*/
|
|
71
|
+
export function eventFollowGeneration(owner) {
|
|
72
|
+
const digest = createHash('sha256')
|
|
73
|
+
.update(JSON.stringify([owner.principalRecordId, owner.principalVersion, owner.workspace, owner.preset]))
|
|
74
|
+
.digest('hex');
|
|
75
|
+
return `event-triggers/${EVENT_FOLLOW_PROTOCOL}/${digest}`;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Build the `event-triggers` registration. `owner` is read live on every call so
|
|
79
|
+
* a revoked or changed owner route fails closed instead of reusing old scope.
|
|
80
|
+
*/
|
|
81
|
+
export function eventFollowRegistration(input) {
|
|
82
|
+
const { reader, owner } = input;
|
|
83
|
+
const now = input.now ?? Date.now;
|
|
84
|
+
const generation = eventFollowGeneration(owner());
|
|
85
|
+
// Snapshot of one followed trigger, only while it is still an owner source
|
|
86
|
+
// under the admitted config digest; other triggers' state is irrelevant.
|
|
87
|
+
const ownedSnapshot = (ref) => {
|
|
88
|
+
const scope = owner();
|
|
89
|
+
if (eventFollowGeneration(scope) !== generation)
|
|
90
|
+
return undefined;
|
|
91
|
+
if (!reader.inspectOwnerSources(scope).some(source => source.triggerId === ref.triggerId))
|
|
92
|
+
return undefined;
|
|
93
|
+
const snapshot = reader.sourceSnapshot(ref.triggerId);
|
|
94
|
+
return snapshot.configDigest === ref.configDigest ? snapshot : undefined;
|
|
95
|
+
};
|
|
96
|
+
// `<triggerId>@head` pins the cursor and digest from one synchronous
|
|
97
|
+
// `sourceSnapshot` read inside admission (no await before the row is
|
|
98
|
+
// written), so an event between the caller's own snapshot read and admission
|
|
99
|
+
// cannot fail it. The canonical ref still goes through `validate`, and an
|
|
100
|
+
// explicit three-part ref passes through unchanged.
|
|
101
|
+
const canonicalize = (ref) => {
|
|
102
|
+
const triggerId = parseEventFollowHeadRef(ref);
|
|
103
|
+
if (triggerId === undefined)
|
|
104
|
+
return ref;
|
|
105
|
+
const scope = owner();
|
|
106
|
+
if (eventFollowGeneration(scope) !== generation)
|
|
107
|
+
return undefined;
|
|
108
|
+
if (!reader.inspectOwnerSources(scope).some(source => source.triggerId === triggerId))
|
|
109
|
+
return undefined;
|
|
110
|
+
const snapshot = reader.sourceSnapshot(triggerId);
|
|
111
|
+
return `${triggerId}@${String(snapshot.highWaterSequence)}@${snapshot.configDigest}`;
|
|
112
|
+
};
|
|
113
|
+
return Object.freeze({
|
|
114
|
+
source: EVENT_TRIGGERS_FOLLOW_SOURCE,
|
|
115
|
+
generation,
|
|
116
|
+
...(input.acceptHeadRef === true ? { canonicalize } : {}),
|
|
117
|
+
// Admission-time fence: the cursor must be exactly the current high water
|
|
118
|
+
// (a store-global sequence) and the digest the trigger's current config, so
|
|
119
|
+
// a forged low cursor cannot close a follow on an event that already
|
|
120
|
+
// existed, and a future cursor cannot be pre-armed.
|
|
121
|
+
validate(ref) {
|
|
122
|
+
const parsed = parseEventFollowRef(ref);
|
|
123
|
+
if (parsed === undefined)
|
|
124
|
+
return false;
|
|
125
|
+
const snapshot = ownedSnapshot(parsed);
|
|
126
|
+
return snapshot !== undefined && parsed.afterSequence === snapshot.highWaterSequence;
|
|
127
|
+
},
|
|
128
|
+
resolve(ref) {
|
|
129
|
+
const parsed = parseEventFollowRef(ref);
|
|
130
|
+
if (parsed === undefined)
|
|
131
|
+
return undefined;
|
|
132
|
+
const snapshot = ownedSnapshot(parsed);
|
|
133
|
+
if (snapshot === undefined)
|
|
134
|
+
return undefined;
|
|
135
|
+
if (parsed.afterSequence > snapshot.highWaterSequence)
|
|
136
|
+
return undefined;
|
|
137
|
+
// Security relies on the admission-time high-water check in `validate`:
|
|
138
|
+
// this cursor is replayed from the stored ref and is trusted only because
|
|
139
|
+
// admission refused any cursor below the high water at that moment.
|
|
140
|
+
// Event Triggers revalidates the trigger, config digest, envelope digest
|
|
141
|
+
// and signing skew for every candidate.
|
|
142
|
+
const event = reader.firstEventAfter({ ...snapshot, highWaterSequence: parsed.afterSequence }, parsed.afterSequence, now());
|
|
143
|
+
if (event === undefined) {
|
|
144
|
+
return Object.freeze({ state: 'open', outcome: 'unknown', digest: `${snapshot.configDigest}@${snapshot.highWaterSequence}` });
|
|
145
|
+
}
|
|
146
|
+
return Object.freeze({ state: 'closed', outcome: 'unknown', digest: eventEnvelopeDigest(event.envelope) });
|
|
147
|
+
},
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
//# sourceMappingURL=event-follow.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-follow.js","sourceRoot":"","sources":["../src/event-follow.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import type { NormalizedConfig } from './config.js';
|
|
2
|
+
import type { PeerAutomationsService, PeerDeliveryService, PeerOwnerRouteReceipt, WorkItemReplyConsumerRegistration, WorkItemReportTarget } from './peers.js';
|
|
3
|
+
import type { WorkItemStore } from './store.js';
|
|
4
|
+
import { type WorkItemNotification, type WorkItemRecord, type WorkItemReportRecord } from './types.js';
|
|
5
|
+
export type OwnerWorkItemFeedbackSelector = Readonly<{
|
|
6
|
+
itemId: string;
|
|
7
|
+
reportRevision: number;
|
|
8
|
+
reportDigest: string;
|
|
9
|
+
}>;
|
|
10
|
+
/** Structural SDK surface; the implementation checks this against Evaluation's
|
|
11
|
+
* shared proof without requiring a new optional-peer export in published .d.ts. */
|
|
12
|
+
export interface OwnerWorkItemFeedbackProof {
|
|
13
|
+
protocol: 'assistant-work-items/owner-report-feedback/v1';
|
|
14
|
+
itemId: string;
|
|
15
|
+
reportRevision: number;
|
|
16
|
+
reportDigest: string;
|
|
17
|
+
sourceId: string;
|
|
18
|
+
itemKind: string;
|
|
19
|
+
scope: Readonly<{
|
|
20
|
+
workspace: string;
|
|
21
|
+
preset: string;
|
|
22
|
+
}>;
|
|
23
|
+
owner: Readonly<{
|
|
24
|
+
ownerRouteId: string;
|
|
25
|
+
principalId: string;
|
|
26
|
+
principalRecordId: string;
|
|
27
|
+
principalVersion: number;
|
|
28
|
+
}>;
|
|
29
|
+
originBindingId: string;
|
|
30
|
+
production: Readonly<{
|
|
31
|
+
automationId: string;
|
|
32
|
+
occurrenceId: string;
|
|
33
|
+
runId: string;
|
|
34
|
+
definitionHash: string;
|
|
35
|
+
definitionVersion: number;
|
|
36
|
+
executionStatus: 'succeeded' | 'failed' | 'timed-out' | 'cancelled';
|
|
37
|
+
completedAt: number;
|
|
38
|
+
quiescent: true;
|
|
39
|
+
budgetSettlementState: 'finalized';
|
|
40
|
+
}>;
|
|
41
|
+
supplier: Readonly<{
|
|
42
|
+
provider: string;
|
|
43
|
+
model: string;
|
|
44
|
+
reasoningEffort?: string;
|
|
45
|
+
}>;
|
|
46
|
+
planDigest: string;
|
|
47
|
+
task: Readonly<{
|
|
48
|
+
brief: string;
|
|
49
|
+
briefTruncated: boolean;
|
|
50
|
+
}>;
|
|
51
|
+
report: Readonly<{
|
|
52
|
+
status: 'ready' | 'blocked' | 'failed';
|
|
53
|
+
text: string;
|
|
54
|
+
truncated: boolean;
|
|
55
|
+
recordedAt: number;
|
|
56
|
+
}>;
|
|
57
|
+
proofDigest: string;
|
|
58
|
+
}
|
|
59
|
+
/** Preserve the existing typed-report identity, including v1/v2 plan digest,
|
|
60
|
+
* while excluding mutable outbox delivery bookkeeping. */
|
|
61
|
+
export declare function workItemReportDigest(item: WorkItemRecord, report: WorkItemReportRecord, text: string, planDigest: string): string;
|
|
62
|
+
export interface WorkItemFeedbackTargetDependencies {
|
|
63
|
+
readonly config: NormalizedConfig;
|
|
64
|
+
readonly store: () => WorkItemStore | undefined;
|
|
65
|
+
readonly delivery: () => PeerDeliveryService | undefined;
|
|
66
|
+
readonly automations: () => PeerAutomationsService | undefined;
|
|
67
|
+
/** Pure local current-service/fiber generation check. */
|
|
68
|
+
readonly current: () => boolean;
|
|
69
|
+
}
|
|
70
|
+
/** Historical result reader. It never starts/reconciles an automation, checks
|
|
71
|
+
* a live execution grant, reserves budget, or turns testimony into success. */
|
|
72
|
+
export declare class WorkItemOwnerFeedbackTargets {
|
|
73
|
+
#private;
|
|
74
|
+
private readonly dependencies;
|
|
75
|
+
constructor(dependencies: WorkItemFeedbackTargetDependencies);
|
|
76
|
+
private current;
|
|
77
|
+
/** Local-only metadata for an engineering callback already inside this
|
|
78
|
+
* reader's writer frame. It never mints authority outside that frame. */
|
|
79
|
+
engineeringFrameOwner(): Readonly<PeerOwnerRouteReceipt> | undefined;
|
|
80
|
+
inspectReport(input: Parameters<WorkItemReplyConsumerRegistration['inspectReport']>[0], notification: (item: WorkItemRecord, report: WorkItemReportRecord) => WorkItemNotification): WorkItemReportTarget | undefined;
|
|
81
|
+
private read;
|
|
82
|
+
issue(input: unknown): unknown | undefined;
|
|
83
|
+
resolve(capability: unknown): Readonly<OwnerWorkItemFeedbackProof> | undefined;
|
|
84
|
+
/** A group is validated as one source frame, rather than trusting A's cached
|
|
85
|
+
* result after a later B producer callback. The last phase reads only this
|
|
86
|
+
* owned ledger, configuration and local service identities. */
|
|
87
|
+
withTargetsFence<T>(capabilities: readonly unknown[], callback: (proofs: readonly (Readonly<OwnerWorkItemFeedbackProof> | undefined)[]) => T): T;
|
|
88
|
+
available(): boolean;
|
|
89
|
+
close(): void;
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=feedback-targets.d.ts.map
|