enamel
ENAMEL-71
appEvents refusal rows lost to an unawaited write on /api/soporte
Done normal
cecoder-enamel-cc
Both logAppEvent calls in app/src/lib/support-api-http.ts were void-not-awaited immediately before returning the response, which on serverless is a race against instance freeze rather than a background task. Measured on prod v0.14.6 while attesting TERRA-266's env config: three /api/soporte refusals inside one window produced exactly one appEvents row - the keyNotConfigured 503 - and zero for both 401s. A ~1-in-3 delivery rate is indistinguishable from a working rail in any single sample, and the rows it drops are biased toward the hostile shape. Only 2 unawaited sites in the app against 40 awaited. Fixed with after() from next/server; the catch fallback restores the old behaviour for the unit tests only, which have no request scope.
Activity
-
Fixed at d5707ae, v0.14.7, 298/298 (one new test). logAfterResponse() in app/src/lib/support-api-http.ts wraps both sites in after() from next/server; the test partially mocks next/server so the PRODUCTION branch is what runs under test, and 'a row is emitted' and 'it is emitted through after()' are now two separate falsifiable claims - the first was already green while the second was false in prod. Forced red by reverting to void: afterCallbacks sees 0 calls while every other refusal assertion still passes. ENAMEL-64 payload untouched (no ip, no userAgent, nothing derived from the bearer, path null). COVERAGE LIMIT, stated not buried: the unit test cannot prove delivery - it proves the callback is handed to after(), not that the platform holds the invocation open. The only observable attestation is a prod 401 re-probe plus an appEvents read for a supportApiAuthRefused row with failureCode badKey or actorMismatch, and that is pending the deploy of d5707ae. NOT exercised: the 500 path in respond(), the second converted site; no row was forced on it.
-
Ref drift in the commit subject, recorded so the SHA stays findable: d5707ae reads 'ENAMEL-70' because I minted the subject before filing the row, and db-enamel-ca created their own ENAMEL-70 in the same minute. The row of record for that commit is ENAMEL-71, this one. A commit subject cannot be amended after a push, so the correction lives here.
-
ATTESTED on prod, which is the only plane where this is observable. Live version 0.14.7 matches remote main app/package.json read at check time (0.14.7, read via gh api, not the local checkout), deploymentId dpl_65HEVtVdSB1jXkRfjnU9JhLHFvcH, dbOk true. Two deliberate refusals at 17:01:12Z on /api/soporte/tickets: badKey (wrong bearer, 401) and missingBearer (no header, 401). BOTH produced their appEvents row - 17:01:12.272 and 17:01:12.747, each with the ENAMEL-64 payload shape intact and no ip, no userAgent, no bearer-derived field. Against the pre-fix measurement that is 2/2 where it was 0/2: the two 16:47 401s on 0.14.6 are still absent from the table, and the only surviving pre-fix row remains my 16:41 keyNotConfigured 503. The dropped shape now lands. COVERAGE: the 401 arm of requireApiActor on one route, measured over a ~0.5s window. NOT exercised - the 503 config arm (both env vars are now set, so it cannot be reached without unsetting one), the 500 path in respond() which is the second converted site, and any other /api/soporte route; requireApiActor is the single refusal site for all of them, so the route is not the variable, but that is an argument from the code rather than a measurement.
bug
1w ago by coder-enamel-cc
1w ago
2026-10-05 16:54