Skip to content

Commit e46dcba

Browse files
sahrizviclaude
andcommitted
fix(finops): unprefixed BigQuery location examples; one snapshot read for the reason; stricter tests
Bot review of 8c0eb30 on #1346. The note said to replace `<location>` with `region-us`, which yields `region-region-us`; the examples are `us`, `eu`, `us-central1`. The disabled reason is carried on `FallbackLookup` from the same read as the snapshot, so the note cannot describe a different snapshot. The wrapper test requires the real handler's FAILED branch (not a wrapper catch), and precedence announcements are stubbed in setup. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012Q51zFUmPg1WwtS5CrGJE6
1 parent 31a4ad5 commit e46dcba

2 files changed

Lines changed: 31 additions & 18 deletions

File tree

‎packages/opencode/src/altimate/tools/finops-workspace.ts‎

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -84,9 +84,14 @@ export interface WorkspaceFallback {
8484

8585
/** What the failure path learns about the workspace, in one read. */
8686
export type FallbackLookup =
87-
| { state: "current"; fallbacks: WorkspaceFallback[] }
87+
| { state: "current"; fallbacks: WorkspaceFallback[]; reason: Reason }
8888
| { state: "relinked" | "unreadable" }
8989

90+
/** Why nothing is served, read once with the snapshot so the note describes the
91+
* same snapshot the lookup did: `none` — no snapshot for the session; a disabled
92+
* reason — the snapshot's own; `served` — enabled. */
93+
type Reason = "none" | "served" | NonNullable<Precedence.Precedence["disabledReason"]>
94+
9095
/**
9196
* The workspace-served execute tools for the types a FinOps operation supports, if the
9297
* session is bound to a workspace that serves any. Reads the session's precedence
@@ -97,17 +102,18 @@ export type FallbackLookup =
97102
*/
98103
export async function workspaceFallbacks(sessionID: string, supportedTypes: readonly string[]): Promise<FallbackLookup> {
99104
const precedence = Precedence.forSession(sessionID)
100-
if (!precedence?.enabled) return { state: "current", fallbacks: [] }
105+
if (!precedence) return { state: "current", fallbacks: [], reason: "none" }
106+
if (!precedence.enabled) return { state: "current", fallbacks: [], reason: precedence.disabledReason ?? "served" }
101107
const fallbacks = Precedence.servedInventory(precedence).flatMap(({ type, served }) => {
102108
if (!supportedTypes.includes(type)) return []
103109
const execute = served.find((row) => row.capability === "sql_execute")
104110
return execute
105111
? [{ workspaceName: precedence.workspaceName, workspaceId: precedence.workspaceId, type, modelKey: execute.modelKey }]
106112
: []
107113
})
108-
if (fallbacks.length === 0) return { state: "current", fallbacks }
114+
if (fallbacks.length === 0) return { state: "current", fallbacks, reason: "served" }
109115
const state = await Precedence.snapshotState(precedence)
110-
return state === "current" ? { state, fallbacks } : { state }
116+
return state === "current" ? { state, fallbacks, reason: "served" } : { state }
111117
}
112118

113119
/** The sentence appended to a FinOps failure, or nothing when the workspace serves
@@ -126,8 +132,9 @@ export function workspaceFallbackNote(operation: FinopsOperation, fallbacks: Wor
126132
// The snapshot does not carry a BigQuery integration's location, and the engine
127133
// runs what it is given: the placeholder has to be explained, not left to be sent.
128134
const region = fallbacks.some((f) => f.type === "bigquery" && SOURCE[operation].bigquery)
129-
? " Replace `<location>` with the BigQuery connection's location (for example `region-us`, `region-eu`); " +
130-
"if it is unknown, ask the engine for the connection's details first — the view is not reachable unqualified."
135+
? " Replace `<location>` with the BigQuery connection's location (for example `us`, `eu`, `us-central1`, " +
136+
"giving `region-us.INFORMATION_SCHEMA…`); if it is unknown, ask the engine for the connection's details " +
137+
"first — the view is not reachable unqualified."
131138
: ""
132139
return (
133140
`This tool only uses warehouse connections configured on this machine, and workspace ${label} ` +
@@ -141,20 +148,19 @@ export function workspaceFallbackNote(operation: FinopsOperation, fallbacks: Wor
141148
* materialised) says nothing: that is the plain local failure. Uncertainty must say so
142149
* (the precedence module's first claim), so the failure is marked `undetermined` and
143150
* says the workspace could not be consulted — mirroring `check()`'s own cases. */
144-
function undeterminedNote(sessionID: string, lookup: FallbackLookup): string | undefined {
151+
function undeterminedNote(lookup: FallbackLookup): string | undefined {
145152
if (lookup.state === "unreadable") {
146153
return "The workspace link could not be read while this call ran, so whether the workspace serves this connection type is unknown."
147154
}
148-
if (lookup.state === "relinked") {
155+
if (lookup.state !== "current") {
149156
return "The workspace binding changed while this call ran, so the previous routing decision no longer applies."
150157
}
151-
const precedence = Precedence.forSession(sessionID)
152158
// No snapshot at all is the same unknown `check()` reports: a caller that never
153159
// resolved tools, or an entry evicted between resolution and this call.
154-
if (!precedence) {
160+
if (lookup.reason === "none") {
155161
return "No routing decision was available for this call, so whether the linked workspace serves this connection type is unknown."
156162
}
157-
const reason = precedence.disabledReason
163+
const reason = lookup.reason
158164
if (reason === "unattributed" || reason === "binding-unreadable" || reason === "derive-failed") {
159165
return (
160166
"Whether the linked workspace serves this connection type could not be determined this turn " +
@@ -185,7 +191,7 @@ export async function withWorkspaceFallback<T extends { metadata: Record<string,
185191
output: `${result.output}\n\n${note}`,
186192
}
187193
}
188-
const undetermined = undeterminedNote(sessionID, lookup)
194+
const undetermined = undeterminedNote(lookup)
189195
if (!undetermined) return result
190196
return {
191197
...result,

‎packages/opencode/test/altimate/finops-workspace-fallback.test.ts‎

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ beforeEach(() => {
3535
process.env.ALTIMATE_WORKSPACE = "1"
3636
process.env.ALTIMATE_TELEMETRY_DISABLED = "true"
3737
bindTo(42, "analytics")
38+
// `refresh` queues an announcement; keep it off the real event bridge. (bot review)
39+
precedenceInternals.announce = async () => {}
3840
// The pilot's promise: no local warehouse connection at all.
3941
Registry.setConfigs({})
4042
})
@@ -55,34 +57,35 @@ describe("workspaceFallbacks", () => {
5557
await refresh(SESSION, SNOWFLAKE_TOOLS)
5658
expect(await workspaceFallbacks(SESSION, DEFAULT_FINOPS_TYPES)).toEqual({
5759
state: "current",
60+
reason: "served",
5861
fallbacks: [
5962
{ workspaceName: "analytics", workspaceId: "42", type: "snowflake", modelKey: "datamate_snowflake_execute_database_query" },
6063
],
6164
})
6265
})
6366

6467
test("is empty for a session with no routing decision", async () => {
65-
expect(await workspaceFallbacks(SESSION, DEFAULT_FINOPS_TYPES)).toEqual({ state: "current", fallbacks: [] })
68+
expect(await workspaceFallbacks(SESSION, DEFAULT_FINOPS_TYPES)).toMatchObject({ state: "current", fallbacks: [] })
6669
})
6770

6871
test("is empty when routing is disabled for the session", async () => {
6972
process.env.ALTIMATE_INTEGRATIONS = "local"
7073
await refresh(SESSION, SNOWFLAKE_TOOLS)
71-
expect(await workspaceFallbacks(SESSION, DEFAULT_FINOPS_TYPES)).toEqual({ state: "current", fallbacks: [] })
74+
expect(await workspaceFallbacks(SESSION, DEFAULT_FINOPS_TYPES)).toMatchObject({ state: "current", fallbacks: [] })
7275
})
7376

7477
test("ignores a served type the operation does not support", async () => {
7578
await refresh(SESSION, BIGQUERY_TOOLS)
7679
// The Snowflake-only operations (role hierarchy, user roles) get nothing from a
7780
// workspace that serves only BigQuery.
78-
expect(await workspaceFallbacks(SESSION, ["snowflake"])).toEqual({ state: "current", fallbacks: [] })
81+
expect(await workspaceFallbacks(SESSION, ["snowflake"])).toMatchObject({ state: "current", fallbacks: [] })
7982
const lookup = await workspaceFallbacks(SESSION, DEFAULT_FINOPS_TYPES)
8083
expect(lookup.state === "current" && lookup.fallbacks.map((f) => f.type)).toEqual(["bigquery"])
8184
})
8285

8386
test("never names a tool the caller's agent cannot call", async () => {
8487
await refresh(SESSION, SNOWFLAKE_TOOLS, ANALYST_RULESET)
85-
expect(await workspaceFallbacks(SESSION, DEFAULT_FINOPS_TYPES)).toEqual({ state: "current", fallbacks: [] })
88+
expect(await workspaceFallbacks(SESSION, DEFAULT_FINOPS_TYPES)).toMatchObject({ state: "current", fallbacks: [] })
8689
})
8790
})
8891

@@ -110,7 +113,8 @@ describe("workspaceFallbackNote", () => {
110113
for (const op of ["query_history", "analyze_credits", "expensive_queries", "warehouse_advice", "unused_resources", "role_grants"] as const) {
111114
expect(workspaceFallbackNote(op, bigquery)).toMatch(/region-<location>\.INFORMATION_SCHEMA/)
112115
// …and the placeholder is explained, since the snapshot carries no location.
113-
expect(workspaceFallbackNote(op, bigquery)).toContain("Replace `<location>`")
116+
expect(workspaceFallbackNote(op, bigquery)).toContain("for example `us`, `eu`")
117+
expect(workspaceFallbackNote(op, bigquery)).not.toContain("`region-us`")
114118
}
115119
expect(workspaceFallbackNote("query_history", snowflake)).not.toContain("<location>")
116120
expect(workspaceFallbackNote("unused_resources", snowflake)).toContain("`QUERY_HISTORY`")
@@ -234,7 +238,10 @@ describe("through the tools", () => {
234238
for (const [def, args, table] of tools) {
235239
const tool = await initTool(def as never)
236240
const result = await tool.execute(args, ctx())
237-
expect(result.title, tool.id).toMatch(/FAILED|ERROR/)
241+
// FAILED, not ERROR: the real handler's no-connection branch, not a wrapper catching
242+
// "No native handler". (bot review)
243+
expect(result.title, tool.id).toMatch(/FAILED$/)
244+
expect(result.output, tool.id).toContain("requires a configured warehouse")
238245
expect(result.output, tool.id).toContain("`datamate_snowflake_execute_database_query`")
239246
expect(result.output, tool.id).toContain(table)
240247
expect(result.metadata.workspace_fallback, tool.id).toEqual(["datamate_snowflake_execute_database_query"])

0 commit comments

Comments
 (0)