fix(core): wedge notifications could never be resolved on PostgreSQL (42P18) (#2669)

Not a U12 change — found while **attributing** the pre-existing live-PG
failures during U12's closing verification, and it turned out to be a
product bug rather than a stale test.

## The defect

`resolveWedgeNotification` builds its UPDATE with:

```ts
jsonb_build_object('status', 'resolved', 'transitionedAt', ${transitionedAt})
```

`jsonb_build_object` is variadic `"any"`, so there is no signature for
PostgreSQL to resolve the bind parameter against. It rejects the
statement at **parse time**:

```
42P18: could not determine data type of parameter $1
```

Parse-time is the important part: this failed on **every call**, not on
unusual data. Wedge notifications could not be resolved at all in
PostgreSQL mode.

Casting the parameter to `::text` fixes it.

## Evidence

- `store-wedge-resolution.pg.test.ts` goes **0/7 → 7/7**. That suite has
been red on `main`.
- **Causally verified, not assumed:** removing the cast reproduces
`42P18` exactly. The fix is the cast, not something incidental to the
edit.
- Checked the rest of `packages/core` for the same shape — this is the
only `jsonb_build_object` call site, so there is no second instance
hiding.

## Why it survived

The failure is in a live-PG suite that was already red, so it read as
part of the ambient noise. I only found it because the closing
verification required me to attribute each failing suite to a cause
rather than count them — and "these 4 fail on main too" is an
attribution of *whose*, not of *what*.

Worth flagging for whoever owns the remaining three
(`agent-logs-and-monitor`, `central-archive-secrets`,
`workflow-settings-project-identity`): the same reasoning applies. A
suite failing on main is not evidence that the code is fine.

## Verification

`pnpm test:gate` green (10 / 158 / 487 / 71). `pnpm
check:lifecycle-columns` exits 0. `tsc -p packages/core/tsconfig.json`
clean. `pnpm lint` clean.

Independent of #2655; either order merges.

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
gsxdsm
2026-07-30 02:05:27 -07:00
committed by GitHub
parent a099813e94
commit fe7e68bc13
2 changed files with 21 additions and 1 deletions

View File

@@ -0,0 +1,7 @@
---
"@runfusion/fusion": patch
---
summary: Wedge notifications can be resolved again on PostgreSQL projects.
category: fix
dev: jsonb_build_object is variadic "any", so PostgreSQL could not infer the type of the bare `transitionedAt` bind parameter and rejected the resolve-wedge UPDATE at parse time with 42P18. Casting the parameter to ::text fixes it; the failure was total, not data-dependent.

View File

@@ -211,7 +211,20 @@ export async function resolveActiveTaskWedgeEpisodeRow(
const rows = await layer.db
.update(schema.project.tasks)
.set({
wedgeNotification: sql`(${schema.project.tasks.wedgeNotification}::jsonb || jsonb_build_object('status', 'resolved', 'transitionedAt', ${transitionedAt}))::text`,
/*
FNXC:WedgeNotification 2026-07-31-12:00:
`${transitionedAt}::text` — the CAST is load-bearing, not decoration.
PostgreSQL cannot infer the type of a bare bind parameter used as a `jsonb_build_object` value:
the function is variadic `"any"`, so there is no signature to resolve $1 against and the planner
rejects the statement outright with `42P18: could not determine data type of parameter $1`.
That is a PARSE-time failure, so it fires on every call rather than on unusual data — wedge
notifications could never be resolved in PostgreSQL mode at all.
Surfaced by `store-wedge-resolution.pg.test.ts`, which has been failing on main; the failure is
the product query, not the test.
*/
wedgeNotification: sql`(${schema.project.tasks.wedgeNotification}::jsonb || jsonb_build_object('status', 'resolved', 'transitionedAt', ${transitionedAt}::text))::text`,
updatedAt: transitionedAt,
})
.where(and(