From cfb713bda112fc8287fc3c76ca635200b52e9937 Mon Sep 17 00:00:00 2001 From: gsxdsm Date: Thu, 30 Jul 2026 16:59:03 -0700 Subject: [PATCH] notification: record the measured reason four wedge-progress ids stay literal, and un-red main's gate (#2882) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two small things, neither of which changes behaviour. ## 1. A conversion I attempted, measured, and reverted `hasProgressed` in the wedge-episode path names four column ids outright. I converted them to a resolved lane set. It **broke an existing gate test** — `task-wedge-notification.test.ts` → *"sends one actionable push and mailbox message per active terminal episode"*: 1 message delivered, 2 expected. The note already in that file was right, and stronger than it read. The hazard is **not** specific to the resolve/claim ordering — it is **any `await` added before the resolve**. Column resolution needs one. `task:updated` listeners fire synchronously, so a re-wedge arriving close behind a recovery reaches `claim` while the first episode is still open, and the operator's second alert is dropped. Product change reverted; only the comment lands, now carrying the measurement and naming the failing test as the acceptance check for whoever owns the wedge-episode contract. **Left counted, not exempted** — the census should keep pointing here. Worth stating: the pre-existing note was a warning written speculatively. Attempting the conversion is what turned it into evidence, and the evidence says the blocker is real but sits somewhere else (per-task serialisation) than the note implied. ## 2. `main`'s gate is red, and not from this branch `pnpm test:gate` fails on a clean `origin/main` tree at `check-sql-column-literals`: ``` packages/core/src/team-analytics.ts: 3 site(s) now, baseline still allows 6 — re-record it ``` A reduction landed without re-recording the baseline in the same commit, which that check explicitly asks for. Reproduced on `origin/main` with my changes stashed, so it is not mine — but it blocks **every** open PR until recorded. Ratchets **31 → 28** sites across 14 files, downward only. ## The vacuous assertion this round (sixth) The first version of the reverted test passed **with the fix reverted**. `hasProgressed` is a three-clause OR, and the middle clause — *status is a string and is not `failed`* — is true for a recovered task on any board, so `status: "in-progress"` in the fixture satisfied it regardless of column. Same shape as the other five: something the code does anyway. Found by running the revert, not by reading it. ## Verification `pnpm test:gate` 161 + 487 + 13 + 71 (green only with the baseline commit); `tsc` engine clean; notification suite 77 passed; `pnpm lint` and census `--strict` clean. --- .../src/notification/notification-service.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/packages/engine/src/notification/notification-service.ts b/packages/engine/src/notification/notification-service.ts index 5cb85edfe4..46dbfc3c3d 100644 --- a/packages/engine/src/notification/notification-service.ts +++ b/packages/engine/src/notification/notification-service.ts @@ -529,6 +529,21 @@ export class NotificationService { Left COUNTED with no exemption marker — four of this file's five remaining entries are here, and the census should keep saying so. + + FNXC:WorkflowResolvedColumns 2026-07-31-02:40 (ATTEMPTED, MEASURED, REVERTED — do not retry as written): + I converted these four ids to a resolved `progressedLanes` set and it broke an existing gate test + (`task-wedge-notification.test.ts` -> "sends one actionable push and mailbox message per active + terminal episode": 1 message delivered, 2 expected). + + The cause is the paragraph directly above, and it is stronger than it reads: the hazard is not + specific to the resolve/claim ordering, it is ANY await added before the resolve. Column resolution + needs one, so a resolved answer here costs a dropped operator notification whenever a re-wedge + arrives close behind a recovery. The `task:updated` listeners fire synchronously, so the second + emit reaches `claim` while the first episode is still open. + + This is therefore blocked on serialising wedge handling per task, NOT on the conversion being hard. + Convert these four only in a change that already owns the wedge-episode contract, and re-run that + test as the acceptance check — it fails loudly, which is why this is recorded rather than exempted. */ const hasProgressed = task.column === "todo" || task.column === "in-progress" || task.column === "done" || task.column === "archived" || (!isActiveSelfHealingNoAction && typeof task.status === "string" && task.status !== "failed")