@schlessera/brain-ui-server 0.34.0 → 0.35.0
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 +28 -0
- package/dist/activity/notify.d.ts.map +1 -1
- package/dist/activity/notify.js +18 -8
- package/dist/activity/notify.js.map +1 -1
- package/dist/activity/push-sender.d.ts +7 -3
- package/dist/activity/push-sender.d.ts.map +1 -1
- package/dist/activity/push-sender.js +45 -11
- package/dist/activity/push-sender.js.map +1 -1
- package/dist/activity/query.d.ts.map +1 -1
- package/dist/activity/query.js +8 -0
- package/dist/activity/query.js.map +1 -1
- package/dist/activity/recorder.d.ts +11 -1
- package/dist/activity/recorder.d.ts.map +1 -1
- package/dist/activity/recorder.js +52 -2
- package/dist/activity/recorder.js.map +1 -1
- package/dist/activity/runtime.d.ts.map +1 -1
- package/dist/activity/runtime.js +2 -5
- package/dist/activity/runtime.js.map +1 -1
- package/dist/activity/sql.d.ts +34 -0
- package/dist/activity/sql.d.ts.map +1 -0
- package/dist/activity/sql.js +114 -0
- package/dist/activity/sql.js.map +1 -0
- package/dist/activity/store.d.ts +7 -0
- package/dist/activity/store.d.ts.map +1 -1
- package/dist/activity/store.js +48 -113
- package/dist/activity/store.js.map +1 -1
- package/dist/activity/stream.d.ts +3 -1
- package/dist/activity/stream.d.ts.map +1 -1
- package/dist/activity/stream.js +32 -17
- package/dist/activity/stream.js.map +1 -1
- package/dist/app-env.d.ts +8 -0
- package/dist/app-env.d.ts.map +1 -0
- package/dist/app-env.js +2 -0
- package/dist/app-env.js.map +1 -0
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js +28 -3
- package/dist/app.js.map +1 -1
- package/dist/brain/client.d.ts +4 -2
- package/dist/brain/client.d.ts.map +1 -1
- package/dist/brain/client.js +60 -20
- package/dist/brain/client.js.map +1 -1
- package/dist/brain/types.d.ts +9 -0
- package/dist/brain/types.d.ts.map +1 -1
- package/dist/cron/run-job.d.ts.map +1 -1
- package/dist/cron/run-job.js +60 -10
- package/dist/cron/run-job.js.map +1 -1
- package/dist/db/principals.d.ts +72 -0
- package/dist/db/principals.d.ts.map +1 -0
- package/dist/db/principals.js +294 -0
- package/dist/db/principals.js.map +1 -0
- package/dist/files/walker.d.ts.map +1 -1
- package/dist/files/walker.js +6 -1
- package/dist/files/walker.js.map +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/middleware/auth.d.ts +37 -9
- package/dist/middleware/auth.d.ts.map +1 -1
- package/dist/middleware/auth.js +148 -74
- package/dist/middleware/auth.js.map +1 -1
- package/dist/middleware/passkeys.d.ts +9 -7
- package/dist/middleware/passkeys.d.ts.map +1 -1
- package/dist/middleware/passkeys.js +25 -7
- package/dist/middleware/passkeys.js.map +1 -1
- package/dist/middleware/principals.d.ts +18 -0
- package/dist/middleware/principals.d.ts.map +1 -0
- package/dist/middleware/principals.js +138 -0
- package/dist/middleware/principals.js.map +1 -0
- package/dist/middleware/require-owner.d.ts +5 -0
- package/dist/middleware/require-owner.d.ts.map +1 -0
- package/dist/middleware/require-owner.js +10 -0
- package/dist/middleware/require-owner.js.map +1 -0
- package/dist/observability/loggers.js +1 -1
- package/dist/observability/loggers.js.map +1 -1
- package/dist/routes/activity.d.ts.map +1 -1
- package/dist/routes/activity.js +3 -0
- package/dist/routes/activity.js.map +1 -1
- package/dist/routes/brain.d.ts.map +1 -1
- package/dist/routes/brain.js +102 -63
- package/dist/routes/brain.js.map +1 -1
- package/dist/routes/files.d.ts.map +1 -1
- package/dist/routes/files.js +7 -2
- package/dist/routes/files.js.map +1 -1
- package/dist/routes/push.d.ts +61 -2
- package/dist/routes/push.d.ts.map +1 -1
- package/dist/routes/push.js +8 -3
- package/dist/routes/push.js.map +1 -1
- package/dist/routes/sessions.d.ts.map +1 -1
- package/dist/routes/sessions.js +30 -4
- package/dist/routes/sessions.js.map +1 -1
- package/dist/share/staging.d.ts.map +1 -1
- package/dist/share/staging.js +11 -4
- package/dist/share/staging.js.map +1 -1
- package/dist/ws/bridge.d.ts.map +1 -1
- package/dist/ws/bridge.js +6 -2
- package/dist/ws/bridge.js.map +1 -1
- package/dist/ws/clients.d.ts +9 -2
- package/dist/ws/clients.d.ts.map +1 -1
- package/dist/ws/clients.js +44 -6
- package/dist/ws/clients.js.map +1 -1
- package/dist/ws/connection.d.ts +7 -4
- package/dist/ws/connection.d.ts.map +1 -1
- package/dist/ws/connection.js +83 -12
- package/dist/ws/connection.js.map +1 -1
- package/dist/ws/dispatch.d.ts +12 -1
- package/dist/ws/dispatch.d.ts.map +1 -1
- package/dist/ws/dispatch.js +46 -6
- package/dist/ws/dispatch.js.map +1 -1
- package/dist/ws/history.d.ts.map +1 -1
- package/dist/ws/history.js +7 -5
- package/dist/ws/history.js.map +1 -1
- package/dist/ws/host.d.ts +22 -0
- package/dist/ws/host.d.ts.map +1 -1
- package/dist/ws/host.js +39 -1
- package/dist/ws/host.js.map +1 -1
- package/dist/ws/run-session.d.ts +7 -7
- package/dist/ws/run-session.d.ts.map +1 -1
- package/dist/ws/run-session.js +208 -52
- package/dist/ws/run-session.js.map +1 -1
- package/dist/ws/shrink.d.ts +3 -1
- package/dist/ws/shrink.d.ts.map +1 -1
- package/dist/ws/shrink.js +46 -16
- package/dist/ws/shrink.js.map +1 -1
- package/dist/ws/turns.d.ts +58 -3
- package/dist/ws/turns.d.ts.map +1 -1
- package/dist/ws/turns.js +101 -2
- package/dist/ws/turns.js.map +1 -1
- package/migrations/011_principals.sql +13 -0
- package/migrations/012_activity_principals.sql +12 -0
- package/migrations/013_push_subscription_principals.sql +7 -0
- package/migrations/014_invalidate_legacy_sessions.sql +14 -0
- package/package.json +3 -3
- package/src/activity/notify.ts +16 -7
- package/src/activity/push-sender.ts +79 -16
- package/src/activity/query.ts +8 -0
- package/src/activity/recorder.ts +68 -3
- package/src/activity/runtime.ts +2 -5
- package/src/activity/sql.ts +122 -0
- package/src/activity/store.ts +73 -155
- package/src/activity/stream.ts +37 -17
- package/src/app-env.ts +8 -0
- package/src/app.ts +33 -4
- package/src/brain/client.ts +61 -20
- package/src/brain/types.ts +10 -0
- package/src/cron/run-job.ts +41 -17
- package/src/db/principals.ts +452 -0
- package/src/files/walker.ts +5 -1
- package/src/index.ts +6 -1
- package/src/middleware/auth.ts +241 -81
- package/src/middleware/passkeys.ts +35 -14
- package/src/middleware/principals.ts +189 -0
- package/src/middleware/require-owner.ts +13 -0
- package/src/observability/loggers.ts +1 -1
- package/src/routes/activity.ts +3 -0
- package/src/routes/brain.ts +107 -70
- package/src/routes/files.ts +10 -5
- package/src/routes/push.ts +11 -5
- package/src/routes/sessions.ts +45 -20
- package/src/share/staging.ts +11 -4
- package/src/ws/bridge.ts +14 -2
- package/src/ws/clients.ts +52 -7
- package/src/ws/connection.ts +98 -20
- package/src/ws/dispatch.ts +66 -6
- package/src/ws/history.ts +7 -5
- package/src/ws/host.ts +59 -1
- package/src/ws/run-session.ts +247 -74
- package/src/ws/shrink.ts +48 -14
- package/src/ws/turns.ts +136 -5
package/src/activity/recorder.ts
CHANGED
|
@@ -46,8 +46,21 @@ export interface TurnRecorder {
|
|
|
46
46
|
readonly runId: string;
|
|
47
47
|
observeFrame(msg: ServerMessage): void;
|
|
48
48
|
observeActivity(event: BackendActivityEvent): void;
|
|
49
|
+
/** Record that this turn's principal was revoked while work kept running. */
|
|
50
|
+
recordPrincipalRevocation(principalId: string): void;
|
|
51
|
+
/** Record a live follow-up that joined this already-running turn. */
|
|
52
|
+
recordFollowUp(principalId: string): void;
|
|
53
|
+
/** Record who cancelled this turn or an interactive prompt within it. */
|
|
54
|
+
recordCancellation(principalId: string, kind?: "turn" | "ask_user"): void;
|
|
55
|
+
/** Record who answered an ask-user interaction. */
|
|
56
|
+
recordAskUserResponse(principalId: string): void;
|
|
49
57
|
/** The user's approval decision arrived for a gated tool call. */
|
|
50
|
-
onApprovalDecision(
|
|
58
|
+
onApprovalDecision(
|
|
59
|
+
toolUseId: string,
|
|
60
|
+
decision: "allow" | "always_allow" | "deny",
|
|
61
|
+
requestKind: "tool" | "command",
|
|
62
|
+
principalId?: string
|
|
63
|
+
): void;
|
|
51
64
|
/**
|
|
52
65
|
* Close the turn: merge the buffered result enrichment into the root's
|
|
53
66
|
* single terminal write, cascade-cancel anything left open, roll up.
|
|
@@ -64,6 +77,8 @@ export function createTurnRecorder(
|
|
|
64
77
|
profileId?: string;
|
|
65
78
|
/** Billing classification of that profile, resolved at run start (U3). */
|
|
66
79
|
billingMode?: BillingMode;
|
|
80
|
+
/** Principal that initiated this turn; absent means unattributed. */
|
|
81
|
+
principalId?: string;
|
|
67
82
|
}
|
|
68
83
|
): TurnRecorder {
|
|
69
84
|
const { store, onWrite, log } = deps;
|
|
@@ -76,6 +91,7 @@ export function createTurnRecorder(
|
|
|
76
91
|
let resultOutcome: SpanOutcome | null = null;
|
|
77
92
|
let resultUsage: SpanUsage | undefined;
|
|
78
93
|
let resultAttrs: Record<string, unknown> | undefined;
|
|
94
|
+
let principalRevocationRecorded = false;
|
|
79
95
|
|
|
80
96
|
const guard = (fn: () => void) => {
|
|
81
97
|
try {
|
|
@@ -99,6 +115,7 @@ export function createTurnRecorder(
|
|
|
99
115
|
kind: "turn",
|
|
100
116
|
origin: "session",
|
|
101
117
|
sessionId,
|
|
118
|
+
principalId: turn.principalId,
|
|
102
119
|
// Profile + billing ride the ROOT span so the rollup can price the run
|
|
103
120
|
// without any registry or env lookup of its own (a root missing the
|
|
104
121
|
// billing attr falls back to env classification at rollup time).
|
|
@@ -253,9 +270,57 @@ export function createTurnRecorder(
|
|
|
253
270
|
});
|
|
254
271
|
},
|
|
255
272
|
|
|
256
|
-
|
|
273
|
+
recordPrincipalRevocation(principalId) {
|
|
257
274
|
guard(() => {
|
|
258
|
-
if (
|
|
275
|
+
if (finished || principalRevocationRecorded) return;
|
|
276
|
+
ensureRoot();
|
|
277
|
+
store.appendEvent(rootSpanId, "principal_revoked", { principalId });
|
|
278
|
+
principalRevocationRecorded = true;
|
|
279
|
+
onWrite?.();
|
|
280
|
+
});
|
|
281
|
+
},
|
|
282
|
+
|
|
283
|
+
recordFollowUp(principalId) {
|
|
284
|
+
guard(() => {
|
|
285
|
+
if (finished) return;
|
|
286
|
+
ensureRoot();
|
|
287
|
+
store.appendEvent(rootSpanId, "follow_up", { principalId });
|
|
288
|
+
onWrite?.();
|
|
289
|
+
});
|
|
290
|
+
},
|
|
291
|
+
|
|
292
|
+
recordCancellation(principalId, kind = "turn") {
|
|
293
|
+
guard(() => {
|
|
294
|
+
if (finished) return;
|
|
295
|
+
ensureRoot();
|
|
296
|
+
store.appendEvent(rootSpanId, `${kind}_cancelled`, { principalId });
|
|
297
|
+
onWrite?.();
|
|
298
|
+
});
|
|
299
|
+
},
|
|
300
|
+
|
|
301
|
+
recordAskUserResponse(principalId) {
|
|
302
|
+
guard(() => {
|
|
303
|
+
if (finished) return;
|
|
304
|
+
ensureRoot();
|
|
305
|
+
store.appendEvent(rootSpanId, "ask_user_response", { principalId });
|
|
306
|
+
onWrite?.();
|
|
307
|
+
});
|
|
308
|
+
},
|
|
309
|
+
|
|
310
|
+
onApprovalDecision(toolUseId, decision, requestKind, principalId) {
|
|
311
|
+
guard(() => {
|
|
312
|
+
if (principalId) {
|
|
313
|
+
// One tool can raise several approval requests. The span-level actor
|
|
314
|
+
// remains the latest responder for compact views, while this
|
|
315
|
+
// append-only event preserves every decision and actor in order.
|
|
316
|
+
store.appendEvent(toolUseId, "approval_decision", {
|
|
317
|
+
principalId,
|
|
318
|
+
decision,
|
|
319
|
+
requestKind,
|
|
320
|
+
});
|
|
321
|
+
store.patchSpan(toolUseId, { principalId });
|
|
322
|
+
}
|
|
323
|
+
if (decision !== "deny") {
|
|
259
324
|
// Everything before this moment was approval wait, not execution.
|
|
260
325
|
store.patchSpan(toolUseId, { waitUntil: Date.now() });
|
|
261
326
|
} else {
|
package/src/activity/runtime.ts
CHANGED
|
@@ -58,11 +58,8 @@ export function createActivityRuntime(
|
|
|
58
58
|
const store = createActivityStore(db, deps.pricing ? { pricing: deps.pricing } : {});
|
|
59
59
|
const stream = createActivityStream(store, log);
|
|
60
60
|
|
|
61
|
-
// The notifier
|
|
62
|
-
//
|
|
63
|
-
// it and the first tick turns restart-interrupted runs into failure
|
|
64
|
-
// intents. Created after, the sweep's changes would sit below the cursor
|
|
65
|
-
// and a turn killed by a restart would never be notified.
|
|
61
|
+
// The notifier resumes its persisted cursor, including terminal changes
|
|
62
|
+
// committed while this server was down and interruptions from the boot sweep.
|
|
66
63
|
const notifier = createActivityNotifier({
|
|
67
64
|
db,
|
|
68
65
|
store,
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/** SQL owned by the activity store, kept together so the store reads as operations. */
|
|
2
|
+
export const ACTIVITY_SQL = {
|
|
3
|
+
nextSeq: "SELECT COALESCE(MAX(seq), 0) AS hi FROM activity_changes WHERE run_id = ?",
|
|
4
|
+
insertChange:
|
|
5
|
+
"INSERT INTO activity_changes (run_id, seq, span_id, event_index) VALUES (?, ?, ?, ?)",
|
|
6
|
+
spanById: "SELECT * FROM activity_spans WHERE span_id = ?",
|
|
7
|
+
spanStateById: "SELECT run_id, outcome, attrs FROM activity_spans WHERE span_id = ?",
|
|
8
|
+
endSpan: `UPDATE activity_spans SET outcome = ?, outcome_reason = ?, ended_at = ?, attrs = ?,
|
|
9
|
+
input_tokens = COALESCE(?, input_tokens),
|
|
10
|
+
output_tokens = COALESCE(?, output_tokens),
|
|
11
|
+
cache_read_tokens = COALESCE(?, cache_read_tokens),
|
|
12
|
+
cache_creation_tokens = COALESCE(?, cache_creation_tokens),
|
|
13
|
+
cost_usd = COALESCE(?, cost_usd),
|
|
14
|
+
model = COALESCE(?, model)
|
|
15
|
+
WHERE span_id = ?`,
|
|
16
|
+
openSpansByRun:
|
|
17
|
+
"SELECT span_id FROM activity_spans WHERE run_id = ? AND outcome IS NULL ORDER BY started_at DESC",
|
|
18
|
+
spansByRun: "SELECT * FROM activity_spans WHERE run_id = ? ORDER BY started_at",
|
|
19
|
+
upsertRollup: `INSERT INTO activity_run_rollups
|
|
20
|
+
(run_id, origin, name, session_id, job_name, principal_id, principal_label,
|
|
21
|
+
principal_kind, started_at, ended_at, outcome,
|
|
22
|
+
duration_ms, span_count, input_tokens, output_tokens, cache_read_tokens,
|
|
23
|
+
cache_creation_tokens, cost_usd, effective_cost_usd, billing_mode,
|
|
24
|
+
pricing_estimate, failure_reason, detail_pruned)
|
|
25
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 0)
|
|
26
|
+
ON CONFLICT(run_id) DO UPDATE SET
|
|
27
|
+
ended_at = excluded.ended_at, outcome = excluded.outcome,
|
|
28
|
+
duration_ms = excluded.duration_ms, span_count = excluded.span_count,
|
|
29
|
+
input_tokens = excluded.input_tokens, output_tokens = excluded.output_tokens,
|
|
30
|
+
cache_read_tokens = excluded.cache_read_tokens,
|
|
31
|
+
cache_creation_tokens = excluded.cache_creation_tokens,
|
|
32
|
+
cost_usd = COALESCE(activity_run_rollups.cost_usd, excluded.cost_usd),
|
|
33
|
+
effective_cost_usd = CASE
|
|
34
|
+
WHEN activity_run_rollups.effective_cost_usd IS NOT NULL
|
|
35
|
+
THEN activity_run_rollups.effective_cost_usd
|
|
36
|
+
WHEN activity_run_rollups.billing_mode IS NULL
|
|
37
|
+
OR activity_run_rollups.billing_mode = excluded.billing_mode
|
|
38
|
+
THEN excluded.effective_cost_usd
|
|
39
|
+
ELSE NULL
|
|
40
|
+
END,
|
|
41
|
+
billing_mode = COALESCE(activity_run_rollups.billing_mode, excluded.billing_mode),
|
|
42
|
+
pricing_estimate = CASE
|
|
43
|
+
WHEN activity_run_rollups.pricing_estimate IS NOT NULL
|
|
44
|
+
THEN activity_run_rollups.pricing_estimate
|
|
45
|
+
WHEN activity_run_rollups.billing_mode IS NULL
|
|
46
|
+
OR activity_run_rollups.billing_mode = excluded.billing_mode
|
|
47
|
+
THEN excluded.pricing_estimate
|
|
48
|
+
ELSE NULL
|
|
49
|
+
END,
|
|
50
|
+
failure_reason = excluded.failure_reason`,
|
|
51
|
+
insertSpan: `INSERT INTO activity_spans
|
|
52
|
+
(span_id, run_id, parent_span_id, name, kind, origin, session_id, job_name, principal_id,
|
|
53
|
+
attrs, started_at, writer, last_heartbeat_at)
|
|
54
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
55
|
+
patchSpan: `UPDATE activity_spans SET principal_id = COALESCE(?, principal_id),
|
|
56
|
+
attrs = ?, wait_until = COALESCE(?, wait_until),
|
|
57
|
+
input_tokens = COALESCE(?, input_tokens),
|
|
58
|
+
output_tokens = COALESCE(?, output_tokens),
|
|
59
|
+
cache_read_tokens = COALESCE(?, cache_read_tokens),
|
|
60
|
+
cache_creation_tokens = COALESCE(?, cache_creation_tokens),
|
|
61
|
+
cost_usd = COALESCE(?, cost_usd),
|
|
62
|
+
model = COALESCE(?, model)
|
|
63
|
+
WHERE span_id = ?`,
|
|
64
|
+
spanRunById: "SELECT run_id FROM activity_spans WHERE span_id = ?",
|
|
65
|
+
nextEventIndex:
|
|
66
|
+
"SELECT COALESCE(MAX(event_index), -1) + 1 AS idx FROM activity_events WHERE span_id = ?",
|
|
67
|
+
insertEvent:
|
|
68
|
+
"INSERT INTO activity_events (span_id, event_index, ts, event_type, payload) VALUES (?, ?, ?, ?, ?)",
|
|
69
|
+
heartbeat:
|
|
70
|
+
"UPDATE activity_spans SET last_heartbeat_at = ? WHERE span_id = ? AND outcome IS NULL",
|
|
71
|
+
openSessionRuns:
|
|
72
|
+
"SELECT DISTINCT run_id FROM activity_spans WHERE outcome IS NULL AND origin = 'session'",
|
|
73
|
+
staleRoots: `SELECT span_id, run_id FROM activity_spans
|
|
74
|
+
WHERE outcome IS NULL AND parent_span_id IS NULL
|
|
75
|
+
AND writer != ? AND COALESCE(last_heartbeat_at, started_at) < ?`,
|
|
76
|
+
stuckRoots:
|
|
77
|
+
"SELECT * FROM activity_spans WHERE outcome IS NULL AND parent_span_id IS NULL AND started_at < ?",
|
|
78
|
+
spanChanges: `SELECT c.change_id, c.run_id, c.seq, s.*
|
|
79
|
+
FROM activity_changes c
|
|
80
|
+
JOIN activity_spans s ON s.span_id = c.span_id
|
|
81
|
+
WHERE c.change_id > ? AND c.event_index IS NULL
|
|
82
|
+
ORDER BY c.change_id LIMIT ?`,
|
|
83
|
+
eventChanges: `SELECT c.change_id, c.run_id, c.seq, e.*
|
|
84
|
+
FROM activity_changes c
|
|
85
|
+
JOIN activity_events e
|
|
86
|
+
ON e.span_id = c.span_id AND e.event_index = c.event_index
|
|
87
|
+
WHERE c.change_id > ? AND c.event_index IS NOT NULL
|
|
88
|
+
ORDER BY c.change_id LIMIT ?`,
|
|
89
|
+
terminalRootChanges: `SELECT MAX(c.change_id) AS change_id, s.*
|
|
90
|
+
FROM activity_changes c
|
|
91
|
+
JOIN activity_spans s ON s.span_id = c.span_id
|
|
92
|
+
WHERE c.change_id > ? AND c.event_index IS NULL
|
|
93
|
+
AND s.parent_span_id IS NULL AND s.outcome IS NOT NULL
|
|
94
|
+
GROUP BY s.span_id
|
|
95
|
+
ORDER BY change_id LIMIT ?`,
|
|
96
|
+
latestChangeCursor: "SELECT COALESCE(MAX(change_id), 0) AS hi FROM activity_changes",
|
|
97
|
+
eventsByRun: `SELECT e.* FROM activity_events e
|
|
98
|
+
JOIN activity_spans s ON s.span_id = e.span_id
|
|
99
|
+
WHERE s.run_id = ? ORDER BY e.ts, e.event_index`,
|
|
100
|
+
openRootSpans:
|
|
101
|
+
"SELECT * FROM activity_spans WHERE outcome IS NULL AND parent_span_id IS NULL ORDER BY started_at DESC",
|
|
102
|
+
pruneCandidates: `SELECT run_id, ended_at AS ended FROM activity_run_rollups r
|
|
103
|
+
WHERE detail_pruned = 0 AND ended_at IS NOT NULL
|
|
104
|
+
AND ((ended_at < ? AND ended_at < ?) OR ended_at < ?)
|
|
105
|
+
AND NOT EXISTS (
|
|
106
|
+
SELECT 1 FROM activity_spans s
|
|
107
|
+
WHERE s.run_id = r.run_id AND s.outcome IS NULL
|
|
108
|
+
)
|
|
109
|
+
LIMIT ?`,
|
|
110
|
+
markDetailPruned: "UPDATE activity_run_rollups SET detail_pruned = 1 WHERE run_id = ?",
|
|
111
|
+
markDigestCoverageGap:
|
|
112
|
+
"UPDATE activity_run_rollups SET failure_reason = COALESCE(failure_reason, 'digest coverage gap') WHERE run_id = ?",
|
|
113
|
+
deleteEventsByRun: `DELETE FROM activity_events WHERE span_id IN
|
|
114
|
+
(SELECT span_id FROM activity_spans WHERE run_id = ?)`,
|
|
115
|
+
deleteSpansByRun: "DELETE FROM activity_spans WHERE run_id = ?",
|
|
116
|
+
deleteChangesByRun: "DELETE FROM activity_changes WHERE run_id = ?",
|
|
117
|
+
compactChanges: `DELETE FROM activity_changes WHERE change_id < (
|
|
118
|
+
SELECT COALESCE(MAX(change_id), 0) FROM activity_changes
|
|
119
|
+
) - 100000 AND run_id NOT IN (
|
|
120
|
+
SELECT DISTINCT run_id FROM activity_spans WHERE outcome IS NULL
|
|
121
|
+
)`,
|
|
122
|
+
} as const;
|