From fe7e68bc13506baf61bfdd151ba71911ea96f6eb Mon Sep 17 00:00:00 2001 From: gsxdsm Date: Thu, 30 Jul 2026 02:05:27 -0700 Subject: [PATCH] fix(core): wedge notifications could never be resolved on PostgreSQL (42P18) (#2669) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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) --- .changeset/fix-wedge-notification-pg.md | 7 +++++++ packages/core/src/task-store/async-persistence.ts | 15 ++++++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 .changeset/fix-wedge-notification-pg.md diff --git a/.changeset/fix-wedge-notification-pg.md b/.changeset/fix-wedge-notification-pg.md new file mode 100644 index 0000000000..f84b49ee22 --- /dev/null +++ b/.changeset/fix-wedge-notification-pg.md @@ -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. diff --git a/packages/core/src/task-store/async-persistence.ts b/packages/core/src/task-store/async-persistence.ts index 6f75516edc..254d23c71b 100644 --- a/packages/core/src/task-store/async-persistence.ts +++ b/packages/core/src/task-store/async-persistence.ts @@ -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(