agentwrangler 0.1.1-next.2f6c1df → 0.1.1-next.37edadd
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/daemon/router.js +1 -1
- package/dist/detector/detectors/d10_catalog_footprint.js +2 -2
- package/dist/detector/detectors/d1_ctx_always_loaded.js +9 -9
- package/dist/detector/detectors/d2_session_long_full_context.js +2 -2
- package/dist/detector/detectors/d4_model_mismatch.js +3 -3
- package/dist/detector/detectors/d6_tool_result_bloat.js +1 -1
- package/dist/detector/detectors/d7_loop_retry_waste.js +1 -1
- package/dist/detector/detectors/d8_cache_write_churn.js +2 -2
- package/dist/detector/detectors/d9_idle_background_session.js +1 -1
- package/dist/query/api/cost-per-success.js +1 -13
- package/dist/query/api/delivery.js +3 -25
- package/dist/query/api/effectiveness.js +5 -30
- package/dist/query/api/efficiency-headroom.js +14 -12
- package/dist/query/api/overview.js +3 -77
- package/dist/query/spend.js +2 -64
- package/dist/ui/assets/{BarChart-BC-ciS9d.js → BarChart-DtiRvMcr.js} +1 -1
- package/dist/ui/assets/BriefsPage-gyUvqeyp.js +2 -0
- package/dist/ui/assets/{CacheWriteSpikesChart-ncVwVoud.js → CacheWriteSpikesChart-xdkHBE3F.js} +1 -1
- package/dist/ui/assets/{CartesianChart-CRV6h2et.js → CartesianChart-D-h-lxMH.js} +1 -1
- package/dist/ui/assets/Chip-DvutOe8Q.js +1 -0
- package/dist/ui/assets/{ComposedChart-CrOxp6Ym.js → ComposedChart-CGRu3OgM.js} +1 -1
- package/dist/ui/assets/{EmptyState-9kcoimjj.js → EmptyState-DaredZkz.js} +1 -1
- package/dist/ui/assets/{FlavorDecomposition-DRZxH0vQ.js → FlavorDecomposition-CsjmGpn4.js} +1 -1
- package/dist/ui/assets/FrictionCell-gcIZEEuw.js +2 -0
- package/dist/ui/assets/GlossaryPage-BJxfK0Vx.js +1 -0
- package/dist/ui/assets/HotSessionsPage-D_Nt56Yu.js +1 -0
- package/dist/ui/assets/{InfoTip-CmcYFNQt.js → InfoTip-Dz9gTGzB.js} +1 -1
- package/dist/ui/assets/{Legend-BCXsSaEM.js → Legend-CGv-AdS2.js} +1 -1
- package/dist/ui/assets/{Line-2rUzs15v.js → Line-qG79fweY.js} +1 -1
- package/dist/ui/assets/OverviewPage-DDKroAQp.js +2 -0
- package/dist/ui/assets/RecommendationsPage-CtFOg2cL.js +2 -0
- package/dist/ui/assets/{Scatter-DpIZt_y5.js → Scatter-d3NgmWkl.js} +1 -1
- package/dist/ui/assets/SessionDetailPage-Bz1Vlje1.js +1 -0
- package/dist/ui/assets/SettingsPage-Zu6-DkzI.js +25 -0
- package/dist/ui/assets/{Skeleton-DjuxPm_D.js → Skeleton-DCy0HCWx.js} +1 -1
- package/dist/ui/assets/SpendPercentileChip-CagdbVgR.js +1 -0
- package/dist/ui/assets/{TrendChart-gyhHK9H_.js → TrendChart-CFOgoXpm.js} +1 -1
- package/dist/ui/assets/WorkspaceDetailPage-9NEviBmO.js +1 -0
- package/dist/ui/assets/WorkspacesPage-3asY3zj1.js +1 -0
- package/dist/ui/assets/{chart-theme-DnpNuyRt.js → chart-theme-BasJ5Y6D.js} +1 -1
- package/dist/ui/assets/{graphicalItemSelectors-CFhpQjLz.js → graphicalItemSelectors-BhZtRF4Y.js} +1 -1
- package/dist/ui/assets/{index-hbaLYHUX.js → index-OEoc-2Hk.js} +2 -2
- package/dist/ui/assets/{index-D_IJsvkJ.css → index-SrfNUeBZ.css} +1 -1
- package/dist/ui/assets/{prompt-templates-CVzMex9L.js → prompt-templates-DhR4Qoy9.js} +4 -4
- package/dist/ui/assets/{useExperimentalActions-B7J8gIkb.js → useExperimentalActions-BM8HZUIt.js} +1 -1
- package/dist/ui/index.html +2 -2
- package/package.json +1 -1
- package/dist/ui/assets/BriefsPage-Dls6npt7.js +0 -2
- package/dist/ui/assets/Chip-EizRm13x.js +0 -1
- package/dist/ui/assets/FrictionCell-BGYB9UKh.js +0 -2
- package/dist/ui/assets/GlossaryPage-CRyQb1Hn.js +0 -1
- package/dist/ui/assets/HotSessionsPage-DfE90Kxi.js +0 -1
- package/dist/ui/assets/OverviewPage-Bm5KvXqa.js +0 -2
- package/dist/ui/assets/RecommendationsPage-CvSl3lzp.js +0 -2
- package/dist/ui/assets/SessionDetailPage-w_lSgite.js +0 -1
- package/dist/ui/assets/SettingsPage-CfUoP8lB.js +0 -25
- package/dist/ui/assets/SpendPercentileChip-DYun7Wzh.js +0 -1
- package/dist/ui/assets/WorkspaceDetailPage-DacPKaKA.js +0 -1
- package/dist/ui/assets/WorkspacesPage-DiNQaAYG.js +0 -1
- package/dist/ui/assets/rec-sessions-ggz9MYgP.js +0 -1
package/dist/daemon/router.js
CHANGED
|
@@ -264,7 +264,7 @@ export function handleApiRequest(_db, req, res, method, url) {
|
|
|
264
264
|
sendJson(res, 200, getPractices(_db, { from, to }));
|
|
265
265
|
return;
|
|
266
266
|
}
|
|
267
|
-
// GET /api/efficiency-headroom (
|
|
267
|
+
// GET /api/efficiency-headroom (BM2 modeled savings vs trailing-window spend)
|
|
268
268
|
if (method === "GET" && pathname === "/api/efficiency-headroom") {
|
|
269
269
|
const { from, to } = resolveWindow(parseWindowFilter(url));
|
|
270
270
|
sendJson(res, 200, getEfficiencyHeadroom(_db, { from, to }));
|
|
@@ -95,7 +95,7 @@ export const d10Detector = {
|
|
|
95
95
|
const latestProbedAt = rows.reduce((latest, row) => (latest === null || row.probed_at > latest ? row.probed_at : latest), null);
|
|
96
96
|
const refs = rows.map((row) => row.file_ref);
|
|
97
97
|
const evidence = {
|
|
98
|
-
title: `Review tool catalog: ${Math.round(catalogTokens / 1000)}K
|
|
98
|
+
title: `Review ${state.effective_catalog_state} tool catalog: ${Math.round(catalogTokens / 1000)}K tokens`,
|
|
99
99
|
component: "MCP_SCHEMAS",
|
|
100
100
|
file_ref: refs.length === 1 ? refs[0] : null,
|
|
101
101
|
file_refs: refs,
|
|
@@ -120,7 +120,7 @@ export const d10Detector = {
|
|
|
120
120
|
scopeKey: "D10|global|MCP_SCHEMAS",
|
|
121
121
|
category: "TOOLING",
|
|
122
122
|
scope_workspace_id: null,
|
|
123
|
-
lever: "
|
|
123
|
+
lever: "Too many connected tools, plugins, and skills",
|
|
124
124
|
target_metric: "catalog_context_tokens",
|
|
125
125
|
// R11 is required before catalog size can become a freed-headroom claim.
|
|
126
126
|
modeled_savings_u_per_wk: null,
|
|
@@ -29,16 +29,16 @@ function stepsFor(component, fileRef) {
|
|
|
29
29
|
case "CLAUDE_MD":
|
|
30
30
|
return [
|
|
31
31
|
`Open ${fileRef}`,
|
|
32
|
-
"Move
|
|
33
|
-
"Keep
|
|
34
|
-
"
|
|
32
|
+
"Move changelog/history/rationale prose to a linked doc",
|
|
33
|
+
"Keep current-state rules + pointers only",
|
|
34
|
+
"Re-measure: probe re-sizes on next daemon pass",
|
|
35
35
|
];
|
|
36
36
|
case "MEMORY":
|
|
37
37
|
return [
|
|
38
38
|
`Review memory files under ${fileRef}`,
|
|
39
|
-
"
|
|
40
|
-
"
|
|
41
|
-
"
|
|
39
|
+
"Delete stale or duplicate memories",
|
|
40
|
+
"Consolidate overlapping facts into concise entries",
|
|
41
|
+
"Re-measure: probe re-sizes on next daemon pass",
|
|
42
42
|
];
|
|
43
43
|
case "MCP_SCHEMAS":
|
|
44
44
|
return [
|
|
@@ -62,13 +62,13 @@ function titleFor(component, tokens, target) {
|
|
|
62
62
|
function leverFor(component) {
|
|
63
63
|
switch (component) {
|
|
64
64
|
case "CLAUDE_MD":
|
|
65
|
-
return "Move
|
|
65
|
+
return "Move changelog/history prose out of CLAUDE.md; keep current-state + pointers.";
|
|
66
66
|
case "MEMORY":
|
|
67
|
-
return "
|
|
67
|
+
return "Prune stale/duplicate memories; consolidate overlapping facts.";
|
|
68
68
|
case "MCP_SCHEMAS":
|
|
69
69
|
return "Identify rarely-used skills/plugins; extract to on-demand or disable.";
|
|
70
70
|
default:
|
|
71
|
-
return "
|
|
71
|
+
return "Trim always-loaded context source to the per-source target.";
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
74
|
export const d1Detector = {
|
|
@@ -81,12 +81,12 @@ export const d2Detector = {
|
|
|
81
81
|
scopeKey: `D2|global|${formula.model}`,
|
|
82
82
|
category: "CONTEXT",
|
|
83
83
|
scope_workspace_id: null,
|
|
84
|
-
lever: "
|
|
84
|
+
lever: "/clear between unrelated tasks; split long work; avoid mid-task /compact.",
|
|
85
85
|
target_metric: "avg_context_per_turn",
|
|
86
86
|
modeled_savings_u_per_wk: savingsU,
|
|
87
87
|
modeled_formula: formula,
|
|
88
88
|
evidence: {
|
|
89
|
-
title: `
|
|
89
|
+
title: `Shorten sessions: ${n} long-context run${n === 1 ? "" : "s"} this week`,
|
|
90
90
|
qualifying_session_count: qualifying.length,
|
|
91
91
|
qualifying_turn_count: qualifyingTurnCount,
|
|
92
92
|
session_ids: sessionIds,
|
|
@@ -192,7 +192,7 @@ export const d4Detector = {
|
|
|
192
192
|
? {
|
|
193
193
|
withheld: true,
|
|
194
194
|
withheld_reason: `Sonnet weekly cap is the binding constraint (Sonnet util ${bindingSonnet.utilization} >= all-models ${perModelSnapshot.seven_day_util}) — routing Opus->Sonnet would worsen it`,
|
|
195
|
-
title: `
|
|
195
|
+
title: `[withheld] Route Opus→Sonnet: ${mismatchPct}% of turns are high-context low-output`,
|
|
196
196
|
}
|
|
197
197
|
: perModelSnapshot && sonnetEntries && sonnetEntries.length > 0
|
|
198
198
|
? { cap_attribution: "all_models_or_opus_binds" }
|
|
@@ -202,7 +202,7 @@ export const d4Detector = {
|
|
|
202
202
|
category: "MODEL",
|
|
203
203
|
scope_workspace_id: workspace_id,
|
|
204
204
|
// Advisory gate (W0.3): which cap binds is NOT inferable from JSONL. Conditional lever.
|
|
205
|
-
lever: "
|
|
205
|
+
lever: "If your all-models / Opus / 5h cap is the one binding — check /usage — these high-context low-output Opus turns are Sonnet-movable. This does NOT help, and can hurt, if your Sonnet-specific weekly cap is the binding constraint.",
|
|
206
206
|
target_metric: "model_mix_opus_fraction",
|
|
207
207
|
// Advisory gate: suppress the crisp $/wk headline until live /usage cap-attribution exists.
|
|
208
208
|
modeled_savings_u_per_wk: null,
|
|
@@ -210,7 +210,7 @@ export const d4Detector = {
|
|
|
210
210
|
// Destructure out result_usd_per_wk so the advisory formula carries no crisp $/wk figure.
|
|
211
211
|
modeled_formula: (({ result_usd_per_wk: _, ...rest }) => ({ ...rest, kind: "ADVISORY" }))(formula),
|
|
212
212
|
evidence: {
|
|
213
|
-
title: `
|
|
213
|
+
title: `Route Opus→Sonnet: ${mismatchPct}% of turns are high-context low-output`,
|
|
214
214
|
workspace_id,
|
|
215
215
|
total_opus_turns_per_week: totalOpus,
|
|
216
216
|
mismatch_turns_per_week: mismatchCount,
|
|
@@ -262,7 +262,7 @@ export const d6Detector = {
|
|
|
262
262
|
modeled_savings_u_per_wk: modeledSavingsU,
|
|
263
263
|
modeled_formula: formula,
|
|
264
264
|
evidence: {
|
|
265
|
-
title: `
|
|
265
|
+
title: `Trim tool output: ${Math.round(bloatShare * 100)}% bloat share in session`,
|
|
266
266
|
session_id: row.session_id,
|
|
267
267
|
workspace_id: row.workspace_id,
|
|
268
268
|
tool_result_bytes: row.tool_result_bytes,
|
|
@@ -299,7 +299,7 @@ export const d7Detector = {
|
|
|
299
299
|
expression: "cap-weighted exposure of turns owning repeat-excess events; not an avoidable-token or USD savings estimate",
|
|
300
300
|
},
|
|
301
301
|
evidence: {
|
|
302
|
-
title: `
|
|
302
|
+
title: `Break retry loops: ${flaggedTurns.size} flagged turn${flaggedTurns.size === 1 ? "" : "s"} in session`,
|
|
303
303
|
session_id: sessionId,
|
|
304
304
|
workspace_id: session.workspaceId,
|
|
305
305
|
loop_flagged_event_count: flaggedEventIds.size,
|
|
@@ -125,7 +125,7 @@ export const d8Detector = {
|
|
|
125
125
|
// TTL-regime facet: is this session dominated by 5m-tier creation?
|
|
126
126
|
const fiveMinCreation = events.reduce((s, e) => s + e.cache_write_5m, 0);
|
|
127
127
|
const regime5m = totalCreation > 0 && fiveMinCreation / totalCreation >= D8_REGIME_5M_SHARE;
|
|
128
|
-
const baseLever = "
|
|
128
|
+
const baseLever = "Use /clear (or resume-from-summary) before idling past the cache TTL, and batch prefix/CLAUDE.md edits to a session boundary so they don't invalidate the warm cache mid-session.";
|
|
129
129
|
const lever = regime5m
|
|
130
130
|
? `${baseLever} This session's creation is mostly 5m-tier — enable the 1h cache regime (ENABLE_PROMPT_CACHING_1H) where long pauses are unavoidable.`
|
|
131
131
|
: baseLever;
|
|
@@ -138,7 +138,7 @@ export const d8Detector = {
|
|
|
138
138
|
modeled_savings_u_per_wk: savingsU,
|
|
139
139
|
modeled_formula: formula,
|
|
140
140
|
evidence: {
|
|
141
|
-
title: `
|
|
141
|
+
title: `Reduce cache-write churn: ${events.length} re-write${events.length === 1 ? "" : "s"} in session`,
|
|
142
142
|
session_id: sessionId,
|
|
143
143
|
workspace_id,
|
|
144
144
|
churn_event_count: events.length,
|
|
@@ -62,7 +62,7 @@ export const d9Detector = {
|
|
|
62
62
|
modeled_savings_u_per_wk: null,
|
|
63
63
|
modeled_formula: d9Formula(sidechainCap, D9_UNPRODUCTIVE_FRACTION),
|
|
64
64
|
evidence: {
|
|
65
|
-
title: `Review background-
|
|
65
|
+
title: `Review background fan-out: ${Math.round(share * 100)}% cap-weighted sidechain`,
|
|
66
66
|
workspace_id: row.workspace_id,
|
|
67
67
|
sidechain_cap_weighted_tokens: sidechainCap,
|
|
68
68
|
total_cap_weighted_tokens: totalCap,
|
|
@@ -21,7 +21,6 @@ export function getCostPerSuccess(db, workspaceId, from, to) {
|
|
|
21
21
|
to,
|
|
22
22
|
workspaceId,
|
|
23
23
|
workspaceId,
|
|
24
|
-
workspaceId,
|
|
25
24
|
from,
|
|
26
25
|
to,
|
|
27
26
|
workspaceId,
|
|
@@ -47,14 +46,6 @@ export function getCostPerSuccess(db, workspaceId, from, to) {
|
|
|
47
46
|
JOIN merged_work_items mwi ON mwi.work_item_id = swl.work_item_id
|
|
48
47
|
WHERE 1 = 1${sessionFilter}
|
|
49
48
|
),
|
|
50
|
-
merged_session_links AS (
|
|
51
|
-
SELECT swl.session_id, COUNT(DISTINCT swl.work_item_id) AS merged_pr_links
|
|
52
|
-
FROM session_work_links swl
|
|
53
|
-
JOIN merged_work_items mwi ON mwi.work_item_id = swl.work_item_id
|
|
54
|
-
JOIN sessions s ON s.session_id = swl.session_id
|
|
55
|
-
WHERE 1 = 1${sessionFilter}
|
|
56
|
-
GROUP BY swl.session_id
|
|
57
|
-
),
|
|
58
49
|
in_window_sessions AS (
|
|
59
50
|
SELECT s.session_id, s.cost_equiv_u
|
|
60
51
|
FROM sessions s
|
|
@@ -73,8 +64,6 @@ export function getCostPerSuccess(db, workspaceId, from, to) {
|
|
|
73
64
|
SELECT
|
|
74
65
|
(SELECT COUNT(*) FROM merged_work_items) AS merged_pr_count,
|
|
75
66
|
(SELECT COUNT(*) FROM closed_unmerged_work_items) AS closed_unmerged_count,
|
|
76
|
-
(SELECT COUNT(*) FROM merged_session_links) AS unique_linked_session_count,
|
|
77
|
-
(SELECT COUNT(*) FROM merged_session_links WHERE merged_pr_links > 1) AS shared_linked_session_count,
|
|
78
67
|
CASE WHEN (SELECT COUNT(*) FROM merged_work_items) = 0 THEN NULL
|
|
79
68
|
ELSE (SELECT COALESCE(SUM(cost_equiv_u), 0) FROM merged_session_costs) * 1.0
|
|
80
69
|
/ (SELECT COUNT(*) FROM merged_work_items)
|
|
@@ -102,14 +91,13 @@ export function getCostPerSuccess(db, workspaceId, from, to) {
|
|
|
102
91
|
};
|
|
103
92
|
return buildResponse(data, {
|
|
104
93
|
claim_kind: "OBS_PROXY",
|
|
105
|
-
metric_definition_version: "esf-1",
|
|
106
94
|
n: data.merged_pr_count,
|
|
107
95
|
window: { from, to },
|
|
108
96
|
qualification: {
|
|
109
97
|
provisional_excluded: false,
|
|
110
98
|
unpriced_turns: 0,
|
|
111
99
|
claim_kinds_count: 1,
|
|
112
|
-
note: "Directional (OBS_PROXY):
|
|
100
|
+
note: "Directional (OBS_PROXY): survivorship bias (heavy-spend sessions that never open a PR are invisible); reviewer-dependence (merge is a human decision, not a quality guarantee); linkage-coverage cap (only linkage_coverage_pct% of in-window sessions are linked to a PR, so unlinked spend is excluded). cost_per_merged_pr_u uses lifecycle attribution: each merged PR carries the full cost of every linked session whenever it ran, so narrowing the window changes the PR population, not the per-PR cost.",
|
|
113
101
|
},
|
|
114
102
|
...(workspaceId === null ? {} : { drilldown_ids: { workspace_id: workspaceId } }),
|
|
115
103
|
});
|
|
@@ -44,20 +44,8 @@ export function getDeliveryMetrics(db, opts) {
|
|
|
44
44
|
FROM tool_events te
|
|
45
45
|
WHERE te.session_id = iws.session_id
|
|
46
46
|
AND te.commit_sha IS NOT NULL
|
|
47
|
-
)
|
|
48
|
-
s.state = 'LIVE'
|
|
49
|
-
AND EXISTS (
|
|
50
|
-
SELECT 1 FROM tool_events te
|
|
51
|
-
WHERE te.session_id = iws.session_id
|
|
52
|
-
AND te.tool_name IN ('Bash', 'Edit', 'Write', 'NotebookEdit')
|
|
53
|
-
)
|
|
54
|
-
AND NOT EXISTS (
|
|
55
|
-
SELECT 1 FROM tool_events te
|
|
56
|
-
WHERE te.session_id = iws.session_id
|
|
57
|
-
AND te.commit_sha IS NOT NULL
|
|
58
|
-
) AS is_live_session
|
|
47
|
+
) AS is_abandoned_session
|
|
59
48
|
FROM in_window_sessions iws
|
|
60
|
-
JOIN sessions s USING (session_id)
|
|
61
49
|
),
|
|
62
50
|
session_spend AS (
|
|
63
51
|
SELECT session_id,
|
|
@@ -79,16 +67,7 @@ export function getDeliveryMetrics(db, opts) {
|
|
|
79
67
|
CASE WHEN COALESCE(SUM(ss.spend_u), 0) = 0 THEN NULL
|
|
80
68
|
ELSE SUM(CASE WHEN sf.is_abandoned_session THEN ss.spend_u ELSE 0 END) * 1.0
|
|
81
69
|
/ SUM(ss.spend_u)
|
|
82
|
-
END AS abandoned_spend_share
|
|
83
|
-
COALESCE(SUM(sf.is_abandoned_session), 0) AS no_commit_activity_session_count,
|
|
84
|
-
COALESCE(SUM(CASE WHEN sf.is_abandoned_session THEN ss.spend_u ELSE 0 END), 0)
|
|
85
|
-
AS no_commit_activity_spend_u,
|
|
86
|
-
CASE WHEN COALESCE(SUM(ss.spend_u), 0) = 0 THEN NULL
|
|
87
|
-
ELSE SUM(CASE WHEN sf.is_abandoned_session THEN ss.spend_u ELSE 0 END) * 1.0
|
|
88
|
-
/ SUM(ss.spend_u)
|
|
89
|
-
END AS no_commit_activity_spend_share,
|
|
90
|
-
COALESCE(SUM(CASE WHEN sf.is_live_session THEN 1 ELSE 0 END), 0)
|
|
91
|
-
AS live_session_excluded_from_no_commit_activity_count
|
|
70
|
+
END AS abandoned_spend_share
|
|
92
71
|
FROM session_flags sf
|
|
93
72
|
JOIN session_spend ss USING (session_id)`)
|
|
94
73
|
.get(...params);
|
|
@@ -100,14 +79,13 @@ export function getDeliveryMetrics(db, opts) {
|
|
|
100
79
|
};
|
|
101
80
|
return buildResponse(data, {
|
|
102
81
|
claim_kind: "OBS_PROXY",
|
|
103
|
-
metric_definition_version: "esf-1",
|
|
104
82
|
n: data.commit_session_count,
|
|
105
83
|
window: { from: opts.from, to: opts.to },
|
|
106
84
|
qualification: {
|
|
107
85
|
provisional_excluded: true,
|
|
108
86
|
unpriced_turns: 0,
|
|
109
87
|
claim_kinds_count: 1,
|
|
110
|
-
note: "Commit SHA presence is an observed delivery proxy.
|
|
88
|
+
note: "Commit SHA presence is an observed delivery proxy.",
|
|
111
89
|
},
|
|
112
90
|
...(opts.workspaceId === null ? {} : { drilldown_ids: { workspace_id: opts.workspaceId } }),
|
|
113
91
|
});
|
|
@@ -34,17 +34,11 @@ export function computeSessionDelivery(db, sessionId) {
|
|
|
34
34
|
turns_to_first_commit = countRow.n;
|
|
35
35
|
}
|
|
36
36
|
const sessRow = db
|
|
37
|
-
.prepare(
|
|
38
|
-
EXISTS (SELECT 1 FROM tool_events te WHERE te.session_id = sessions.session_id
|
|
39
|
-
AND te.tool_name IN ('Bash','Write','Edit','NotebookEdit')) AS has_activity
|
|
40
|
-
FROM sessions WHERE session_id = ?`)
|
|
37
|
+
.prepare("SELECT user_turn_count, state FROM sessions WHERE session_id = ?")
|
|
41
38
|
.get(sessionId);
|
|
42
39
|
const user_turn_count = sessRow?.user_turn_count ?? 0;
|
|
43
40
|
const state = sessRow?.state ?? "";
|
|
44
|
-
const deep_abandoned = user_turn_count >= 10 &&
|
|
45
|
-
firstCommitTs === null &&
|
|
46
|
-
state === "RECONCILED" &&
|
|
47
|
-
sessRow?.has_activity === 1;
|
|
41
|
+
const deep_abandoned = user_turn_count >= 10 && firstCommitTs === null && state === "RECONCILED";
|
|
48
42
|
return { turns_to_first_commit, deep_abandoned };
|
|
49
43
|
}
|
|
50
44
|
// ---------------------------------------------------------------------------
|
|
@@ -89,9 +83,8 @@ export function getAbandonedSpendSplit(db, opts) {
|
|
|
89
83
|
FROM tool_events te
|
|
90
84
|
WHERE te.session_id = iws.session_id
|
|
91
85
|
AND te.commit_sha IS NOT NULL
|
|
92
|
-
)
|
|
86
|
+
) AS is_abandoned_session
|
|
93
87
|
FROM in_window_sessions iws
|
|
94
|
-
JOIN sessions s USING (session_id)
|
|
95
88
|
),
|
|
96
89
|
session_spend AS (
|
|
97
90
|
SELECT session_id,
|
|
@@ -152,24 +145,15 @@ export function getClosureProxy(db, opts) {
|
|
|
152
145
|
unresolved_count: 0,
|
|
153
146
|
pending_count: 0,
|
|
154
147
|
resolved_share: null,
|
|
155
|
-
no_later_workspace_session_count: 0,
|
|
156
|
-
later_workspace_session_count: 0,
|
|
157
|
-
no_later_workspace_session_share: null,
|
|
158
148
|
window_hours: windowHours,
|
|
159
149
|
workspace_id: opts.workspaceId,
|
|
160
150
|
});
|
|
161
151
|
if (candidates.length === 0) {
|
|
162
152
|
return buildResponse(emptyProxy(), {
|
|
163
153
|
claim_kind: "EXPERIMENTAL",
|
|
164
|
-
metric_definition_version: "esf-1",
|
|
165
154
|
n: 0,
|
|
166
155
|
window: { from: opts.now, to: opts.now },
|
|
167
|
-
qualification: {
|
|
168
|
-
provisional_excluded: false,
|
|
169
|
-
unpriced_turns: 0,
|
|
170
|
-
claim_kinds_count: 1,
|
|
171
|
-
note: `${note} No later workspace session is an observation, not task resolution.`,
|
|
172
|
-
},
|
|
156
|
+
qualification: { provisional_excluded: false, unpriced_turns: 0, claim_kinds_count: 1, note },
|
|
173
157
|
...(opts.workspaceId === null ? {} : { drilldown_ids: { workspace_id: opts.workspaceId } }),
|
|
174
158
|
});
|
|
175
159
|
}
|
|
@@ -220,23 +204,14 @@ export function getClosureProxy(db, opts) {
|
|
|
220
204
|
unresolved_count,
|
|
221
205
|
pending_count,
|
|
222
206
|
resolved_share,
|
|
223
|
-
no_later_workspace_session_count: resolved_count,
|
|
224
|
-
later_workspace_session_count: unresolved_count,
|
|
225
|
-
no_later_workspace_session_share: resolved_share,
|
|
226
207
|
window_hours: windowHours,
|
|
227
208
|
workspace_id: opts.workspaceId,
|
|
228
209
|
};
|
|
229
210
|
return buildResponse(proxy, {
|
|
230
211
|
claim_kind: "EXPERIMENTAL",
|
|
231
|
-
metric_definition_version: "esf-1",
|
|
232
212
|
n: no_commit_session_count,
|
|
233
213
|
window: { from: opts.now, to: opts.now },
|
|
234
|
-
qualification: {
|
|
235
|
-
provisional_excluded: false,
|
|
236
|
-
unpriced_turns: 0,
|
|
237
|
-
claim_kinds_count: 1,
|
|
238
|
-
note: `${note} "Resolved" and "unresolved" are legacy aliases for no later workspace session and a later workspace session; neither establishes task resolution.`,
|
|
239
|
-
},
|
|
214
|
+
qualification: { provisional_excluded: false, unpriced_turns: 0, claim_kinds_count: 1, note },
|
|
240
215
|
...(opts.workspaceId === null ? {} : { drilldown_ids: { workspace_id: opts.workspaceId } }),
|
|
241
216
|
});
|
|
242
217
|
}
|
|
@@ -37,19 +37,22 @@ export function getEfficiencyHeadroom(db, opts) {
|
|
|
37
37
|
FROM turns
|
|
38
38
|
WHERE ts >= ? AND ts < ? AND provisional = 0`)
|
|
39
39
|
.get(from, to);
|
|
40
|
-
const opportunities = db
|
|
41
|
-
.prepare(`SELECT rec_id, modeled_savings_u_per_wk
|
|
42
|
-
FROM recommendations
|
|
43
|
-
WHERE state IN ('PROPOSED', 'ADOPTED') AND modeled_savings_u_per_wk IS NOT NULL
|
|
44
|
-
ORDER BY rec_id`)
|
|
45
|
-
.all();
|
|
46
40
|
const headroom_u_per_wk = recs.sum_u ?? 0;
|
|
47
41
|
const actual_u_per_wk = spend.actual_u;
|
|
48
|
-
|
|
49
|
-
//
|
|
50
|
-
|
|
42
|
+
const openRecsExist = recs.open_total > 0;
|
|
43
|
+
// Null when: no spend (avoid /0 → ∞/NaN), or open recs exist but none carries a
|
|
44
|
+
// savings figure (an all-null modeled set is not a defensible ceiling).
|
|
45
|
+
let headroom_pct;
|
|
46
|
+
if (actual_u_per_wk === 0) {
|
|
47
|
+
headroom_pct = null;
|
|
48
|
+
}
|
|
49
|
+
else if (openRecsExist && recs.with_savings === 0) {
|
|
50
|
+
headroom_pct = null;
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
headroom_pct = headroom_u_per_wk / actual_u_per_wk;
|
|
54
|
+
}
|
|
51
55
|
const data = {
|
|
52
|
-
opportunities,
|
|
53
56
|
headroom_u_per_wk,
|
|
54
57
|
actual_u_per_wk,
|
|
55
58
|
headroom_pct,
|
|
@@ -59,14 +62,13 @@ export function getEfficiencyHeadroom(db, opts) {
|
|
|
59
62
|
};
|
|
60
63
|
return buildResponse(data, {
|
|
61
64
|
claim_kind: "EXPERIMENTAL",
|
|
62
|
-
metric_definition_version: "esf-1",
|
|
63
65
|
n: recs.with_savings,
|
|
64
66
|
window: { from, to },
|
|
65
67
|
qualification: {
|
|
66
68
|
provisional_excluded: true,
|
|
67
69
|
unpriced_turns: 0,
|
|
68
70
|
claim_kinds_count: 1,
|
|
69
|
-
note: "
|
|
71
|
+
note: "Modeled headroom — if every open recommendation were applied; built from unvalidated per-detector fractions.",
|
|
70
72
|
},
|
|
71
73
|
});
|
|
72
74
|
}
|
|
@@ -109,7 +109,7 @@ function makeResponse(data, o) {
|
|
|
109
109
|
note: "",
|
|
110
110
|
...o.qualification,
|
|
111
111
|
},
|
|
112
|
-
metric_definition_version:
|
|
112
|
+
metric_definition_version: "observe-1",
|
|
113
113
|
claim_kind: o.claim_kind,
|
|
114
114
|
drilldown_ids: o.drilldown_ids ?? {},
|
|
115
115
|
},
|
|
@@ -352,30 +352,7 @@ export function listSessions(workspace_id, filters, cursor) {
|
|
|
352
352
|
(SELECT COUNT(*) FROM tool_events te
|
|
353
353
|
WHERE te.session_id = s.session_id AND te.exit_class = 'ERROR') AS tool_error_count,
|
|
354
354
|
(SELECT COUNT(*) FROM tool_events te
|
|
355
|
-
WHERE te.session_id = s.session_id AND te.
|
|
356
|
-
(SELECT COUNT(*) FROM tool_events te
|
|
357
|
-
WHERE te.session_id = s.session_id AND te.exit_class = 'ERROR'
|
|
358
|
-
AND te.result_bytes IS NOT NULL) AS tool_completed_error_count,
|
|
359
|
-
(SELECT COUNT(*) FROM tool_events te
|
|
360
|
-
WHERE te.session_id = s.session_id AND te.exit_class = 'TEST_FAIL'
|
|
361
|
-
AND EXISTS (SELECT 1 FROM tool_event_metadata metadata
|
|
362
|
-
WHERE metadata.event_id = te.event_id AND metadata.is_test_command = 1)) AS test_fail_count,
|
|
363
|
-
(SELECT COUNT(*) FROM tool_events te JOIN tool_event_metadata metadata ON metadata.event_id = te.event_id
|
|
364
|
-
WHERE te.session_id = s.session_id AND metadata.is_test_command = 1 AND te.result_bytes IS NOT NULL) AS test_completed_count,
|
|
365
|
-
(SELECT COUNT(*) FROM tool_events te JOIN tool_event_metadata metadata ON metadata.event_id = te.event_id
|
|
366
|
-
WHERE te.session_id = s.session_id AND metadata.is_test_command = 1 AND te.exit_class = 'OK' AND te.result_bytes IS NOT NULL) AS test_pass_count,
|
|
367
|
-
CASE WHEN NOT EXISTS (SELECT 1 FROM tool_events observed JOIN tool_event_metadata observed_metadata ON observed_metadata.event_id = observed.event_id
|
|
368
|
-
WHERE observed.session_id = s.session_id AND observed_metadata.is_test_command = 1 AND observed.result_bytes IS NOT NULL)
|
|
369
|
-
THEN 'NO_TEST_OUTCOMES'
|
|
370
|
-
WHEN NOT EXISTS (SELECT 1 FROM tool_events failed JOIN tool_event_metadata failed_metadata ON failed_metadata.event_id = failed.event_id
|
|
371
|
-
WHERE failed.session_id = s.session_id AND failed_metadata.is_test_command = 1 AND failed.exit_class = 'TEST_FAIL' AND failed.result_bytes IS NOT NULL)
|
|
372
|
-
THEN 'NO_FAILURES_OBSERVED'
|
|
373
|
-
WHEN EXISTS (SELECT 1 FROM tool_events passed JOIN tool_event_metadata passed_metadata ON passed_metadata.event_id = passed.event_id
|
|
374
|
-
WHERE passed.session_id = s.session_id AND passed_metadata.is_test_command = 1 AND passed.exit_class = 'OK' AND passed.result_bytes IS NOT NULL
|
|
375
|
-
AND EXISTS (SELECT 1 FROM tool_events failed_before JOIN tool_event_metadata failed_before_metadata ON failed_before_metadata.event_id = failed_before.event_id
|
|
376
|
-
WHERE failed_before.session_id = s.session_id AND failed_before_metadata.is_test_command = 1
|
|
377
|
-
AND failed_before.exit_class = 'TEST_FAIL' AND failed_before.result_bytes IS NOT NULL AND failed_before.ts < passed.ts))
|
|
378
|
-
THEN 'FAILED_THEN_PASSED' ELSE 'FAILURES_OBSERVED' END AS test_outcome,
|
|
355
|
+
WHERE te.session_id = s.session_id AND te.exit_class = 'TEST_FAIL') AS test_fail_count,
|
|
379
356
|
s.gap_median_s, s.gap_p90_s, s.long_gap_count, s.gap_n,
|
|
380
357
|
CASE WHEN EXISTS (
|
|
381
358
|
SELECT 1 FROM tool_events te
|
|
@@ -390,11 +367,6 @@ export function listSessions(workspace_id, filters, cursor) {
|
|
|
390
367
|
)
|
|
391
368
|
) ELSE NULL END AS turns_to_first_commit,
|
|
392
369
|
CASE WHEN s.state = 'RECONCILED' AND s.user_turn_count >= 10
|
|
393
|
-
AND EXISTS (
|
|
394
|
-
SELECT 1 FROM tool_events te
|
|
395
|
-
WHERE te.session_id = s.session_id
|
|
396
|
-
AND te.tool_name IN ('Bash', 'Write', 'Edit', 'NotebookEdit')
|
|
397
|
-
)
|
|
398
370
|
AND NOT EXISTS (
|
|
399
371
|
SELECT 1 FROM tool_events te
|
|
400
372
|
WHERE te.session_id = s.session_id AND te.commit_sha IS NOT NULL
|
|
@@ -420,18 +392,9 @@ export function listSessions(workspace_id, filters, cursor) {
|
|
|
420
392
|
compaction_count: r.compaction_count,
|
|
421
393
|
api_error_count: r.api_error_count,
|
|
422
394
|
interrupt_count: r.interrupt_count,
|
|
423
|
-
interrupts_supported: false,
|
|
424
|
-
api_error_eligible_request_count: null,
|
|
425
|
-
api_error_rate: null,
|
|
426
395
|
user_turn_count: r.user_turn_count,
|
|
427
396
|
tool_error_count: r.tool_error_count,
|
|
428
|
-
tool_completed_count: r.tool_completed_count,
|
|
429
|
-
tool_completed_error_count: r.tool_completed_error_count,
|
|
430
|
-
tool_error_rate: r.tool_completed_count > 0 ? r.tool_completed_error_count / r.tool_completed_count : null,
|
|
431
397
|
test_fail_count: r.test_fail_count,
|
|
432
|
-
test_completed_count: r.test_completed_count,
|
|
433
|
-
test_pass_count: r.test_pass_count,
|
|
434
|
-
test_outcome: r.test_outcome,
|
|
435
398
|
gap_median_s: r.gap_median_s,
|
|
436
399
|
gap_p90_s: r.gap_p90_s,
|
|
437
400
|
long_gap_count: r.long_gap_count,
|
|
@@ -440,7 +403,6 @@ export function listSessions(workspace_id, filters, cursor) {
|
|
|
440
403
|
deep_abandoned: r.deep_abandoned_int !== 0,
|
|
441
404
|
}));
|
|
442
405
|
return makeResponse({ items, next_cursor: nextCursor(offset, limit, total) }, {
|
|
443
|
-
metric_definition_version: "esf-1",
|
|
444
406
|
n: items.length,
|
|
445
407
|
window,
|
|
446
408
|
claim_kind: "LIST_EQUIV",
|
|
@@ -458,30 +420,7 @@ export function getSession(id) {
|
|
|
458
420
|
(SELECT COUNT(*) FROM tool_events te
|
|
459
421
|
WHERE te.session_id = s.session_id AND te.exit_class = 'ERROR') AS tool_error_count,
|
|
460
422
|
(SELECT COUNT(*) FROM tool_events te
|
|
461
|
-
WHERE te.session_id = s.session_id AND te.
|
|
462
|
-
(SELECT COUNT(*) FROM tool_events te
|
|
463
|
-
WHERE te.session_id = s.session_id AND te.exit_class = 'ERROR'
|
|
464
|
-
AND te.result_bytes IS NOT NULL) AS tool_completed_error_count,
|
|
465
|
-
(SELECT COUNT(*) FROM tool_events te
|
|
466
|
-
WHERE te.session_id = s.session_id AND te.exit_class = 'TEST_FAIL'
|
|
467
|
-
AND EXISTS (SELECT 1 FROM tool_event_metadata metadata
|
|
468
|
-
WHERE metadata.event_id = te.event_id AND metadata.is_test_command = 1)) AS test_fail_count,
|
|
469
|
-
(SELECT COUNT(*) FROM tool_events te JOIN tool_event_metadata metadata ON metadata.event_id = te.event_id
|
|
470
|
-
WHERE te.session_id = s.session_id AND metadata.is_test_command = 1 AND te.result_bytes IS NOT NULL) AS test_completed_count,
|
|
471
|
-
(SELECT COUNT(*) FROM tool_events te JOIN tool_event_metadata metadata ON metadata.event_id = te.event_id
|
|
472
|
-
WHERE te.session_id = s.session_id AND metadata.is_test_command = 1 AND te.exit_class = 'OK' AND te.result_bytes IS NOT NULL) AS test_pass_count,
|
|
473
|
-
CASE WHEN NOT EXISTS (SELECT 1 FROM tool_events observed JOIN tool_event_metadata observed_metadata ON observed_metadata.event_id = observed.event_id
|
|
474
|
-
WHERE observed.session_id = s.session_id AND observed_metadata.is_test_command = 1 AND observed.result_bytes IS NOT NULL)
|
|
475
|
-
THEN 'NO_TEST_OUTCOMES'
|
|
476
|
-
WHEN NOT EXISTS (SELECT 1 FROM tool_events failed JOIN tool_event_metadata failed_metadata ON failed_metadata.event_id = failed.event_id
|
|
477
|
-
WHERE failed.session_id = s.session_id AND failed_metadata.is_test_command = 1 AND failed.exit_class = 'TEST_FAIL' AND failed.result_bytes IS NOT NULL)
|
|
478
|
-
THEN 'NO_FAILURES_OBSERVED'
|
|
479
|
-
WHEN EXISTS (SELECT 1 FROM tool_events passed JOIN tool_event_metadata passed_metadata ON passed_metadata.event_id = passed.event_id
|
|
480
|
-
WHERE passed.session_id = s.session_id AND passed_metadata.is_test_command = 1 AND passed.exit_class = 'OK' AND passed.result_bytes IS NOT NULL
|
|
481
|
-
AND EXISTS (SELECT 1 FROM tool_events failed_before JOIN tool_event_metadata failed_before_metadata ON failed_before_metadata.event_id = failed_before.event_id
|
|
482
|
-
WHERE failed_before.session_id = s.session_id AND failed_before_metadata.is_test_command = 1
|
|
483
|
-
AND failed_before.exit_class = 'TEST_FAIL' AND failed_before.result_bytes IS NOT NULL AND failed_before.ts < passed.ts))
|
|
484
|
-
THEN 'FAILED_THEN_PASSED' ELSE 'FAILURES_OBSERVED' END AS test_outcome,
|
|
423
|
+
WHERE te.session_id = s.session_id AND te.exit_class = 'TEST_FAIL') AS test_fail_count,
|
|
485
424
|
s.gap_median_s, s.gap_p90_s, s.long_gap_count, s.gap_n
|
|
486
425
|
FROM sessions s JOIN workspaces w USING (workspace_id)
|
|
487
426
|
WHERE s.session_id = ?`)
|
|
@@ -489,7 +428,6 @@ export function getSession(id) {
|
|
|
489
428
|
const window = resolveWindow({});
|
|
490
429
|
if (row === undefined) {
|
|
491
430
|
return makeResponse(null, {
|
|
492
|
-
metric_definition_version: "esf-1",
|
|
493
431
|
n: 0,
|
|
494
432
|
window,
|
|
495
433
|
claim_kind: "N_A",
|
|
@@ -513,20 +451,9 @@ export function getSession(id) {
|
|
|
513
451
|
compaction_count: row.compaction_count,
|
|
514
452
|
api_error_count: row.api_error_count,
|
|
515
453
|
interrupt_count: row.interrupt_count,
|
|
516
|
-
interrupts_supported: false,
|
|
517
|
-
api_error_eligible_request_count: null,
|
|
518
|
-
api_error_rate: null,
|
|
519
454
|
user_turn_count: row.user_turn_count,
|
|
520
455
|
tool_error_count: row.tool_error_count,
|
|
521
|
-
tool_completed_count: row.tool_completed_count,
|
|
522
|
-
tool_completed_error_count: row.tool_completed_error_count,
|
|
523
|
-
tool_error_rate: row.tool_completed_count > 0
|
|
524
|
-
? row.tool_completed_error_count / row.tool_completed_count
|
|
525
|
-
: null,
|
|
526
456
|
test_fail_count: row.test_fail_count,
|
|
527
|
-
test_completed_count: row.test_completed_count,
|
|
528
|
-
test_pass_count: row.test_pass_count,
|
|
529
|
-
test_outcome: row.test_outcome,
|
|
530
457
|
gap_median_s: row.gap_median_s,
|
|
531
458
|
gap_p90_s: row.gap_p90_s,
|
|
532
459
|
long_gap_count: row.long_gap_count,
|
|
@@ -534,7 +461,6 @@ export function getSession(id) {
|
|
|
534
461
|
...delivery,
|
|
535
462
|
};
|
|
536
463
|
return makeResponse(data, {
|
|
537
|
-
metric_definition_version: "esf-1",
|
|
538
464
|
n: 1,
|
|
539
465
|
window,
|
|
540
466
|
claim_kind: "LIST_EQUIV",
|
package/dist/query/spend.js
CHANGED
|
@@ -156,61 +156,7 @@ export function hotSessionsByCost(db, limit = 20, window) {
|
|
|
156
156
|
AND te.exit_class = 'ERROR') AS tool_error_count,
|
|
157
157
|
(SELECT COUNT(*) FROM tool_events te
|
|
158
158
|
WHERE te.session_id = s.session_id
|
|
159
|
-
AND te.exit_class = '
|
|
160
|
-
AND te.result_bytes IS NOT NULL) AS tool_completed_error_count,
|
|
161
|
-
(SELECT COUNT(*) FROM tool_events te
|
|
162
|
-
WHERE te.session_id = s.session_id
|
|
163
|
-
AND te.result_bytes IS NOT NULL) AS tool_completed_count,
|
|
164
|
-
(SELECT COUNT(*) FROM tool_events te
|
|
165
|
-
WHERE te.session_id = s.session_id
|
|
166
|
-
AND te.exit_class = 'TEST_FAIL'
|
|
167
|
-
AND EXISTS (
|
|
168
|
-
SELECT 1 FROM tool_event_metadata metadata
|
|
169
|
-
WHERE metadata.event_id = te.event_id AND metadata.is_test_command = 1
|
|
170
|
-
)) AS test_fail_count,
|
|
171
|
-
(SELECT COUNT(*) FROM tool_events te
|
|
172
|
-
JOIN tool_event_metadata metadata ON metadata.event_id = te.event_id
|
|
173
|
-
WHERE te.session_id = s.session_id
|
|
174
|
-
AND metadata.is_test_command = 1
|
|
175
|
-
AND te.result_bytes IS NOT NULL) AS test_completed_count,
|
|
176
|
-
(SELECT COUNT(*) FROM tool_events te
|
|
177
|
-
JOIN tool_event_metadata metadata ON metadata.event_id = te.event_id
|
|
178
|
-
WHERE te.session_id = s.session_id
|
|
179
|
-
AND metadata.is_test_command = 1
|
|
180
|
-
AND te.exit_class = 'OK'
|
|
181
|
-
AND te.result_bytes IS NOT NULL) AS test_pass_count,
|
|
182
|
-
CASE WHEN NOT EXISTS (
|
|
183
|
-
SELECT 1 FROM tool_events observed
|
|
184
|
-
JOIN tool_event_metadata observed_metadata ON observed_metadata.event_id = observed.event_id
|
|
185
|
-
WHERE observed.session_id = s.session_id
|
|
186
|
-
AND observed_metadata.is_test_command = 1
|
|
187
|
-
AND observed.result_bytes IS NOT NULL
|
|
188
|
-
) THEN 'NO_TEST_OUTCOMES'
|
|
189
|
-
WHEN NOT EXISTS (
|
|
190
|
-
SELECT 1 FROM tool_events failed
|
|
191
|
-
JOIN tool_event_metadata failed_metadata ON failed_metadata.event_id = failed.event_id
|
|
192
|
-
WHERE failed.session_id = s.session_id
|
|
193
|
-
AND failed_metadata.is_test_command = 1
|
|
194
|
-
AND failed.exit_class = 'TEST_FAIL'
|
|
195
|
-
AND failed.result_bytes IS NOT NULL
|
|
196
|
-
) THEN 'NO_FAILURES_OBSERVED'
|
|
197
|
-
WHEN EXISTS (
|
|
198
|
-
SELECT 1 FROM tool_events passed
|
|
199
|
-
JOIN tool_event_metadata passed_metadata ON passed_metadata.event_id = passed.event_id
|
|
200
|
-
WHERE passed.session_id = s.session_id
|
|
201
|
-
AND passed_metadata.is_test_command = 1
|
|
202
|
-
AND passed.exit_class = 'OK'
|
|
203
|
-
AND passed.result_bytes IS NOT NULL
|
|
204
|
-
AND EXISTS (
|
|
205
|
-
SELECT 1 FROM tool_events failed_before
|
|
206
|
-
JOIN tool_event_metadata failed_before_metadata ON failed_before_metadata.event_id = failed_before.event_id
|
|
207
|
-
WHERE failed_before.session_id = s.session_id
|
|
208
|
-
AND failed_before_metadata.is_test_command = 1
|
|
209
|
-
AND failed_before.exit_class = 'TEST_FAIL'
|
|
210
|
-
AND failed_before.result_bytes IS NOT NULL
|
|
211
|
-
AND failed_before.ts < passed.ts
|
|
212
|
-
)
|
|
213
|
-
) THEN 'FAILED_THEN_PASSED' ELSE 'FAILURES_OBSERVED' END AS test_outcome,
|
|
159
|
+
AND te.exit_class = 'TEST_FAIL') AS test_fail_count,
|
|
214
160
|
s.gap_median_s AS gap_median_s,
|
|
215
161
|
s.gap_p90_s AS gap_p90_s,
|
|
216
162
|
s.long_gap_count AS long_gap_count,
|
|
@@ -221,13 +167,5 @@ export function hotSessionsByCost(db, limit = 20, window) {
|
|
|
221
167
|
ORDER BY cost_equiv_u DESC, s.session_id ASC
|
|
222
168
|
LIMIT @limit`)
|
|
223
169
|
.all(window === undefined ? { limit } : { limit, from: window.from, to: window.to });
|
|
224
|
-
return rows
|
|
225
|
-
...row,
|
|
226
|
-
api_error_eligible_request_count: null,
|
|
227
|
-
api_error_rate: null,
|
|
228
|
-
interrupts_supported: false,
|
|
229
|
-
tool_error_rate: row.tool_completed_count > 0
|
|
230
|
-
? row.tool_completed_error_count / row.tool_completed_count
|
|
231
|
-
: null,
|
|
232
|
-
}));
|
|
170
|
+
return rows;
|
|
233
171
|
}
|