Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 0 additions & 26 deletions apps/api/src/routes/v2/investigations.http.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,32 +167,6 @@ const toV2Investigation = Effect.fn("HttpV2Investigations.toV2Investigation")(fu
started_at: doc.startedAt,
diagnosed_at: doc.diagnosedAt,
updated_at: doc.updatedAt,
// Ordering is a contract — `LENS_DISPATCH_ORDER` decides which lenses a
// narrow run gets — and the service already returns them ordered by ordinal.
lens_runs: doc.lensRuns.map((lens) => ({
lensId: lens.lensId,
status: lens.status,
verdict: lens.verdict,
claim: lens.claim,
reason: lens.reason,
progressNote: lens.progressNote,
confidence: lens.confidence,
toolCount: lens.toolCount,
elapsedSeconds: lens.elapsedSeconds,
name: lens.name,
question: lens.question,
priority: lens.priority,
deadlineHit: lens.deadlineHit,
})),
validator:
doc.validator === null
? null
: {
status: doc.validator.status,
note: doc.validator.note,
elapsedSeconds: doc.validator.elapsedSeconds,
},
fanout: { state: doc.fanout.state, size: doc.fanout.size },
}
})

Expand Down
5 changes: 0 additions & 5 deletions apps/api/src/routes/v2/phase1-resources.http.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ import {
ErrorIssuesListResponse,
ErrorIssueTimeseriesPoint,
InvestigationDocument,
InvestigationFanout,
InvestigationIncidentSubject,
InvestigationNotFoundError,
InvestigationSnapshotFact,
Expand Down Expand Up @@ -164,10 +163,6 @@ const investigationFixture = new InvestigationDocument({
startedAt: decodeIso("2026-07-15T09:12:05.000Z"),
diagnosedAt: decodeIso("2026-07-15T09:12:42.000Z"),
updatedAt: decodeIso("2026-07-15T09:12:42.000Z"),
// Single-pass fixture: no lenses were dispatched, so nothing ranked them.
lensRuns: [],
validator: null,
fanout: new InvestigationFanout({ state: "none", size: 1 }),
})

const corruptInvestigationFixture = new InvestigationDocument({
Expand Down
18 changes: 1 addition & 17 deletions apps/electric-sync/src/electric/ElectricClient.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -233,10 +233,6 @@ describe("buildUpstreamShapeUrl", () => {
assert.strictEqual(params.get("where"), `"org_id" = $1 AND "id" = $2`)
assert.strictEqual(params.get("params[1]"), "org_123")
assert.strictEqual(params.get("params[2]"), "inv_1")

const lanes = buildUrl("investigation_lens_runs", { scopeValue: "inv_1" }).params
assert.strictEqual(lanes.get("where"), `"org_id" = $1 AND "investigation_id" = $2`)
assert.strictEqual(lanes.get("params[2]"), "inv_1")
})

/**
Expand All @@ -256,19 +252,7 @@ describe("buildUpstreamShapeUrl", () => {
assert.include(columns, "id")
assert.include(columns, "org_id")
assert.include(columns, "report_json")
// Needed to filter lanes to the live attempt, exactly as the service does.
assert.include(columns, "fanout_attempt")
// Nothing renders the planner's transcript; it is also the largest column.
assert.notInclude(columns, "plan_json")
assert.notInclude(columns, "workflow_instance_id")

const lanes =
buildUrl("investigation_lens_runs", { scopeValue: "inv_1" }).params.get("columns")?.split(",") ??
[]
assert.include(lanes, "progress_note")
assert.include(lanes, "started_at")
assert.notInclude(lanes, "evidence_json")
assert.notInclude(lanes, "hypothesis_json")
assert.include(columns, "started_at")
})

it("adds Electric Cloud source credentials only when provided", () => {
Expand Down
3 changes: 1 addition & 2 deletions apps/electric-sync/src/shapes/registry.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,8 @@ describe("lookupShape", () => {
})

describe("scoped shapes", () => {
it("marks exactly the investigation shapes as scoped", () => {
it("marks exactly the investigation shape as scoped", () => {
assert.strictEqual(subscriptionScopeColumn("investigation"), "id")
assert.strictEqual(subscriptionScopeColumn("investigation_lens_runs"), "investigation_id")
// Everything else is org-wide; a stray `scope` on one of these is ignored.
assert.isNull(subscriptionScopeColumn("dashboards"))
assert.isNull(subscriptionScopeColumn("alert_rules"))
Expand Down
49 changes: 4 additions & 45 deletions apps/electric-sync/src/shapes/registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,16 +73,11 @@ const SUBSCRIPTIONS = {
"updated_at",
],
},
// The two investigation shapes are `scoped`: org alone is too wide here. An org
// The investigation shape is `scoped`: org alone is too wide here. An org
// accumulates investigations forever and a browser only ever renders one, so an
// org-wide shape would stream the entire history (and every lane of every run)
// to read a single page. The scope column is pinned here; only its *value*
// comes from the client, and only as positional `$2`.
//
// The projection drops what the v2 wire already withholds — the planner's
// `plan_json`, the lens lanes' `evidence_json` / `hypothesis_json` /
// `mechanism` / `self_doubt`, and the workflow bookkeeping. Nothing renders
// them, and they are the largest columns on both tables.
// org-wide shape would stream the entire history to read a single page. The
// scope column is pinned here; only its *value* comes from the client, and only
// as positional `$2`.
investigation: {
table: "investigations",
scope: "id",
Expand All @@ -100,49 +95,13 @@ const SUBSCRIPTIONS = {
"input_tokens",
"output_tokens",
"error",
"fanout_state",
"fanout_size",
// The lane rows are filtered to the current attempt client-side, exactly
// as InvestigationService does — a straggler from a previous attempt must
// not appear beside the run that superseded it.
"fanout_attempt",
"validator_note",
"validator_elapsed_ms",
"created_by",
"created_at",
"started_at",
"diagnosed_at",
"updated_at",
],
},
investigation_lens_runs: {
table: "investigation_lens_runs",
scope: "investigation_id",
columns: [
"id",
"org_id",
"investigation_id",
"lens_id",
"attempt",
"ordinal",
"status",
"verdict",
"claim",
"reason",
"progress_note",
"confidence",
"tool_count",
"elapsed_ms",
"lens_name",
"lens_question",
"priority",
"deadline_hit",
// Not on the v2 wire, and the reason a synced lane can do something a
// polled one could not: with the instant a lane started, a running lane's
// elapsed can tick locally instead of waiting for the next `elapsed_ms`.
"started_at",
],
},
} as const satisfies Record<string, SubscriptionDefinition>

export interface SubscriptionDefinition {
Expand Down
8 changes: 2 additions & 6 deletions apps/electric-sync/src/shapes/request.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ describe("decodeShapeRequest", () => {
)
assert.strictEqual(expectFailure("shape=investigation&scope=").message.length > 0, true)
assert.strictEqual(
expectFailure(`shape=investigation_lens_runs&scope=${"x".repeat(129)}`).message,
"Shape investigation_lens_runs requires a scope",
expectFailure(`shape=investigation&scope=${"x".repeat(129)}`).message,
"Shape investigation requires a scope",
)
})

Expand All @@ -58,10 +58,6 @@ describe("decodeShapeRequest", () => {
column: "id",
value: "inv_1",
})
assert.deepStrictEqual(expectSuccess("shape=investigation_lens_runs&scope=inv_1").scope, {
column: "investigation_id",
value: "inv_1",
})
})

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,6 @@ const investigation = {
started_at: "2026-08-01T14:02:00.000Z",
diagnosed_at: "2026-08-01T14:02:38.000Z",
updated_at: "2026-08-01T14:02:38.000Z",
lens_runs: [],
validator: null,
fanout: { state: "none", size: 0 },
} as never as V2Investigation

beforeAll(() => {
Expand Down Expand Up @@ -101,8 +98,6 @@ const running = {
status: "investigating",
report: null,
diagnosed_at: null,
lens_runs: [],
fanout: { state: "running", size: 1 },
} as never as V2Investigation

describe("ProvenanceCanvas", () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,6 @@ const make = (overrides: Partial<V2Investigation> = {}): V2Investigation =>
started_at: "2026-08-01T14:02:00.000Z",
diagnosed_at: "2026-08-01T14:02:38.000Z",
updated_at: "2026-08-01T14:02:38.000Z",
lens_runs: [],
validator: null,
fanout: { state: "none", size: 0 },
...overrides,
}) as V2Investigation

Expand Down
10 changes: 0 additions & 10 deletions apps/web/src/lib/collections/investigations.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,6 @@ const row = (overrides: Partial<InvestigationRow> = {}): InvestigationRow => ({
input_tokens: 12000,
output_tokens: 800,
error: null,
fanout_state: "ranked",
fanout_size: 2,
fanout_attempt: 1,
validator_note: null,
validator_elapsed_ms: 8200,
created_by: null,
created_at: "2026-08-01T14:02:00.000Z",
started_at: "2026-08-01T14:02:00.000Z",
Expand All @@ -60,10 +55,7 @@ describe("rowsToInvestigation", () => {
status: "diagnosed",
subject: { type: "incident", incident_kind: "error" },
report: { suspectedCause: "Pool exhaustion in checkout-api" },
fanout: { state: "ranked", size: 2 },
})
// ms → seconds at one decimal, exactly as InvestigationService does it.
expect(investigation?.lens_runs[0]).toMatchObject({ elapsedSeconds: 9.4, verdict: "promoted" })
})

/**
Expand All @@ -81,8 +73,6 @@ describe("rowsToInvestigation", () => {
severity: null,
confidence: "low",
error: null,
fanout_state: "rejected_all",
validator_note: "no candidate survived",
report_json: {
summary: "Nothing held up.",
suspectedCause: "Possibly the payments-api pool, unconfirmed",
Expand Down
10 changes: 0 additions & 10 deletions apps/web/src/lib/collections/investigations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,6 @@ export const InvestigationRowSchema = Schema.Struct({
input_tokens: Schema.NullOr(Schema.Number),
output_tokens: Schema.NullOr(Schema.Number),
error: Schema.NullOr(Schema.String),
fanout_state: Schema.String,
fanout_size: Schema.Number,
fanout_attempt: Schema.Number,
validator_note: Schema.NullOr(Schema.String),
validator_elapsed_ms: Schema.NullOr(Schema.Number),
created_by: Schema.NullOr(Schema.String),
created_at: Schema.String,
started_at: Schema.NullOr(Schema.String),
Expand Down Expand Up @@ -212,11 +207,6 @@ export const rowsToInvestigation = (row: InvestigationRow): V2Investigation | nu
started_at: row.started_at,
diagnosed_at: row.diagnosed_at,
updated_at: row.updated_at,
// Fan-out bookkeeping is still on the wire for rows written before the
// single-agent rework; nothing renders it any more.
lens_runs: [],
validator: null,
fanout: { state: row.fanout_state, size: row.fanout_size },
}
return Option.getOrNull(decodeInvestigation(candidate))
}
Expand Down
15 changes: 6 additions & 9 deletions packages/backend/src/services/errors/AiTriageService.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,10 @@ const seedSettings = (maxRunsPerDay: number, maxPassesPerDay: number) =>
})

/**
* Usage is counted from started rows as `fanoutSize + 1` for legacy fan-out rows
* and 1 for a single-agent run. Seeding rows rather than driving the enqueue path
* keeps the arithmetic under the test's control.
* Usage is one pass per started row. Seeding rows rather than driving the
* enqueue path keeps the arithmetic under the test's control.
*/
const seedStartedRuns = (count: number, fanoutSize: number, idOffset = 0) =>
const seedStartedRuns = (count: number, idOffset = 0) =>
Effect.gen(function* () {
const database = yield* Database
const now = new Date()
Expand All @@ -73,7 +72,6 @@ const seedStartedRuns = (count: number, fanoutSize: number, idOffset = 0) =>
status: "investigating",
seededBy: "system",
subjectJson: { type: "question", question: "seed" },
fanoutSize,
startedAt: now,
createdAt: now,
updatedAt: now,
Expand All @@ -100,8 +98,7 @@ describe("AiTriageService.getSettings pause state", () => {
// Ordinary slice of a 100-pass ceiling is 70. Land usage exactly on it:
// 70 + 1 > 70 refuses an ordinary start while 70 + 1 <= 100 lets a critical through.
yield* seedSettings(500, 100)
yield* seedStartedRuns(17, 3) // 17 x 4 = 68, legacy fan-out rows
yield* seedStartedRuns(2, 1, 100) // a single-agent run is worth 1
yield* seedStartedRuns(70)
const doc = yield* (yield* AiTriageService).getSettings(ORG)
assert.strictEqual(doc.usage.passes, 70)
assert.isTrue(doc.ordinaryPaused)
Expand All @@ -115,7 +112,7 @@ describe("AiTriageService.getSettings pause state", () => {
it.effect("pauses priority triage too once the full ceiling is spent", () =>
Effect.gen(function* () {
yield* seedSettings(500, 100)
yield* seedStartedRuns(25, 3) // 100 passes; 100 + 1 > 100
yield* seedStartedRuns(100) // 100 + 1 > 100
const doc = yield* (yield* AiTriageService).getSettings(ORG)
assert.isTrue(doc.ordinaryPaused)
assert.isTrue(doc.priorityPaused)
Expand All @@ -131,7 +128,7 @@ describe("AiTriageService.getSettings pause state", () => {
it.effect("names the runs ceiling and pauses every severity with it", () =>
Effect.gen(function* () {
yield* seedSettings(3, 10_000)
yield* seedStartedRuns(3, 3)
yield* seedStartedRuns(3)
const doc = yield* (yield* AiTriageService).getSettings(ORG)
assert.strictEqual(doc.pausedDimension, "runs")
assert.isTrue(doc.ordinaryPaused)
Expand Down
Loading