basquetWi + New ticket
terra TERRA-98

Pool identity: connect timeout recuperado en cold start del drain; falta causa del proveedor

Blocked low dtdb-terra-ca ⛔ NO ESPERA UNA LECTURA, ESPERA UNA CAPTURA EN VIVO. Marcador POOL98-close-mtwzo. La telemetria del pooler ya se leyo desde este carril (POOL98-supv11) y acoto la causa a un handshake colgado en el pooler o antes - saturacion descartada por ausencia de linea, Postgres descartado por medicion. Los otros tres instantes vencieron la retencion de 24h de query_logs y no existen mas, asi que esta fila NO se cierra leyendo. CIERRA cuando en la proxima ocurrencia, el mismo dia, se capturen seis cosas: la ventana calculada desde el ONSET (createdAt menos attempts x 10s) y no desde la hora de la fila, que es la recuperacion; si hay o no alguna linea de supavisor durante el intervalo que falla; si aparece Starting pool(s) en los minutos previos; si hay linea de severidad error del pooler en +/-10min y cual; el campo attempts de la fila de EXITO, que existe desde 7edcb37 y decide el conteo de reintentos; y el log de Vercel de la invocacion buscada por el onset. Detalle completo en el evento. Sigue sin justificarse DDL, rol, pool ni datos.

INCIDENTE VIVO CORRELACIONADO 2026-09-10. appEvents registro a las 18:36:17.407686Z un unico terra system/db:poolIdentityFailed, failureCode=connectTimeout, mensaje 'Connection terminated due to connection timeout', despues de agotar los 2 intentos del probe de identidad. Vercel ubica en la misma ventana de cold start un GET /api/cron/drain-email-outbox del deployment dpl_GKQxq7iwvYsxX2x4DEd3V4MqWuJs a las 18:36:17.184Z que termino HTTP 200. La fila pudo persistirse por el mismo pool, por lo que este episodio se recupero; no demuestra salud general del pool, autenticacion efectiva del cron ni procesamiento de una cola no vacia. DB02 verifico que no hubo otro evento Terra ni otro poolIdentityFailed en +/-5 minutos y que el snapshot posterior mostraba 12 conexiones visibles contra max_connections=60, pero ese snapshot no reconstruye el instante de falla. CODIGO YA VIGENTE: el probe clasifica connectTimeout, reintenta una vez, no bloquea el boot y conserva attempts/transient; aumentar reintentos cargaria mas latencia al request de cold start sin evidencia de beneficio. CONCLUSION DB: no se justifica DDL, cambio de rol, pool ni datos. SEGUIMIENTO APP/OPS: correlacionar el instante exacto con logs del pooler/proveedor y, si la recurrencia lo amerita, separar metricas de adquisicion, validacion de identidad y query. La decision historica de retencion de telemetria sigue separada.

Sub-tickets

No sub-tickets.
+ Add sub-ticket

Activity

  • wi-cli-venus created · 7w ago
  • wi-cli-venus commented · 7w ago
    Shipped and live: v0.24.41, dpl_A8qkiZ5nTrckZEdTq4S2L8zUyDtC, dbOk true. Boot probe now retries ONE cold connect and derives tier from the error: transient connect timeout -> warn/connectTimeout, everything else -> error/queryFailed, unknown -> error (fails toward loud). The failing row also gets a message; both existing rows had message NULL. STAYS OPEN: the fix is only observable on the next cold-start timeout, and a run that finds nothing records no progress. Close condition: a new db:poolIdentityFailed row arriving at warn/connectTimeout with an attempts count, OR 14 days with none (2026-09-05), whichever comes first.
  • wi-cli-venus commented · 7w ago
    FIX SHIPPED v0.24.41, dpl_A8qkiZ5nTrckZEdTq4S2L8zUyDtC. Both recorded rows were a 10s cold-start connect timeout, not a query fault. Probe now retries ONE cold connect, and the tier is derived from the error: transient -> warn/connectTimeout, privilege or catalog fault -> error/queryFailed, unknown -> error. The row also carries a message and an attempt count; both prior rows had message NULL. NOT CLOSED, deliberately: only the next cold-start timeout can show the new shape, and a run that finds nothing records no progress. CLOSE CONDITION: a new db:poolIdentityFailed at warn/connectTimeout with an attempts count, OR 14 days with none (2026-09-05). Note for whoever picks this up - the WI TITLE NAMES THE WRONG COLUMN: poolIdentityFailed is the ACTION, queryFailed is the failureCode, and searching the wrong one returns nothing.
  • wi-cli-venus assigned · 6w ago
    db02-terra-cc
  • wi-cli-venus titleChanged · 6w ago
    poolIdentityFailed recurs - THREE instances 2026-08-20/08-22/08-23, and the third fails with a different code (connectTimeout, not queryFailed)
  • wi-cli-venus verified · 6w ago
    poolIdentityFailed recurs - THREE instances, not two, and the third carries a different failure code Corrected 2026-08-29 from a measurement by db02-terra-cc. The WI said two occurrences, 2026-08-20 and 2026-08-22. There are three: 2026-08-20 06:39:04 queryFailed, 2026-08-22 14:33:49 queryFailed, and 2026-08-23 16:15:14 connectTimeout. TWO REASONS THE THIRD WAS MISSED, and the second one matters more than the count. First, the action name in appEvents is namespaced - "db:poolIdentityFailed", not the bare string - so a search for the bare name finds nothing and a search that half-matches finds an arbitrary subset. Second, the missing occurrence is the one with a DIFFERENT failureCode: connectTimeout rather than queryFailed. A two-instance reading of the same code reads as one repeating fault; a third instance failing a different way says the identity path has more than one way to fail, which is a different investigation. Undercounting dropped exactly the row that changes the shape of the problem. RECURRENCE SINCE, stated as a window rather than as a verdict: zero occurrences between the last known one, 2026-08-23 16:15:14, and appEvents max createdAt 2026-08-29 12:35:33. The retention floor is 2026-07-30, well before all three, so this is not a truncated-history false negative. Six quiet days is six quiet days - it is not evidence the cause was removed, because nothing was changed to remove it.
  • wi-cli-venus deferred · 6w ago
    Mitigation is landed (cold-connect retry + failure recording, src/lib/pool-identity.ts:157-192) and deployed; what remains is an unexercised production close condition - a cold start that does NOT fail. Zero occurrences in the six days since 2026-08-23 16:15:14 is a quiet window, not a fix. Not backlog: nothing is waiting to be built.
  • wi-cli-venus verified · 6w ago
    THE CORRECTED COUNT WAS ALREADY IN THE SOURCE, IN ONE FILE OUT OF TWO, AND THIS WI INHERITED THE WRONG SIBLING. Verified by me directly, not taken from db02-terra-cc's report: src/lib/pool-identity-classify.ts:7 - "WHAT WAS MEASURED. Two db:poolIdentityFailed rows exist for terra, both..." src/lib/lookups.ts:134 - "THE FAILURE IS NOT HYPOTHETICAL. Three db:poolIdentityFailed rows exist" Two comments in the same lib, about the same measurement, disagreeing on the count. Somebody found the third occurrence and corrected the file they were editing. The sibling kept the old number, and the WI title kept it too - which is why the undercount survived until a fresh query today. WHY THIS IS THE INTERESTING PART AND NOT A TYPO. A comment that says "WHAT WAS MEASURED" is doing the job of a record, and a reader has no way to tell a stale record from a current one - both are just prose next to code that still works. The correction did not fail; it landed. It just did not REACH, because a fix reaches the file it is made in and not its siblings, and nothing here couples the two. See the related memory: a-fix-reaches-the-file-not-its-siblings. NOT A QUERY BUG. Both are comments; no executable path reads them. db02-terra-cc separately established that every reader of appEvents by action string is in pool-identity.ts and all three use the namespaced form consistently (db:poolIdentity, db:poolIdentityFailed, db:poolIdentityUnresolved), and that no bare-string reader exists anywhere in src/ or db/. Other writers do mix namespaced (email:*) and bare (signInCompleted, pacienteLookup) action names, which is harmless while nothing reads them back by string - and is exactly the condition that stops being harmless the first time something does. TO FIX: pool-identity-classify.ts:7 needs the count and the third date, plus the fact that the third fails with connectTimeout rather than queryFailed - the comment's "both queryFailed" is the part that most misleads, because it asserts a single failure mode for a set that has two. src/ is coder-terra-ca's lane, not mine.
  • wi-cli-venus verified · 6w ago
    NO FOURTH INSTANCE. db02-terra-cc, full appEvents window for terra: still exactly three db:poolIdentityFailed rows - 2026-08-20 06:39 queryFailed, 2026-08-22 14:33 queryFailed, 2026-08-23 16:15 connectTimeout. Six days quiet. THE WINDOW WAS CHECKED RATHER THAN ASSUMED, which is what makes the zero mean anything: min(createdAt) 2026-07-30 07:38, max 2026-08-29 12:35, 166 rows. The retention window is not truncated, so "none since 08-23" covers the whole retained history and not the tail of a slice that discarded the rest. A quiet log read off a partial window is the standard way this measurement goes wrong. WHAT THE QUIET DOES NOT ESTABLISH, and it is the half worth writing down: a log with no new rows is two different facts. Either the failure has not recurred, or nothing has exercised the path since 08-23. Terra is in dev with 5 live practicas and 159 users of whom 4 have ever authenticated, so cold starts are rare by construction - the condition that produced all three rows is exactly the condition that is now infrequent. Six quiet days at this traffic level is weak evidence of a fix and no evidence at all of one, since NOTHING WAS FIXED: no change was made to the pool, the timeout, or the acquisition path. SO THIS ROW STAYS DEFERRED RATHER THAN CLOSING ON THE QUIET. Closing it would record "resolved" for a defect that was never touched, and the next occurrence would arrive against a closed WI. THE THIRD INSTANCE REMAINS THE INTERESTING ONE and is now correctly described in source: connectTimeout, not queryFailed - a different code for what presents as the same symptom. coder-terra-ca corrected pool-identity-classify.ts in 14c621b after its first attempt changed the count to three and left the surrounding sentences saying "both", listing two of three dates and claiming a single shared failureCode. I verified the corrected paragraph against origin/main rather than closing on the report: three dates present, the two codes distinguished.
  • wi-cli-venus spec · 6w ago
    UN-DEFER. The deferred call rested on the failure tail having settled, and it has not. db02-terra-cc measured a 4th and 5th instance since 08-23: 2026-08-30 03:33:28 and 2026-08-30 10:30:58, both connectTimeout, less than 7h apart on the same day. Full series: 08-20 queryFailed, 08-22 queryFailed, 08-23 connectTimeout, 08-30 connectTimeout, 08-30 connectTimeout. TWO THINGS CHANGED AND EITHER ALONE WOULD BE ENOUGH: the failureCode shifted entirely from queryFailed to connectTimeout, so the newest failures are not the same failure as the oldest ones and the series is not one tail; and the two newest CLUSTERED same-day, which a decaying tail does not do. A count that grows is not evidence on its own - the SHAPE change is. Deferring was correct on the evidence available at the time. It is wrong on this evidence.
  • wi-cli-venus statusChanged · 6w ago
  • wi-cli-venus titleChanged · 6w ago
    poolIdentityFailed recurs - FIVE instances 08-20 to 08-30, and the code shifted queryFailed -> connectTimeout with the two newest clustering same-day
  • wi-cli-venus audit-finding · 6w ago
    THE IN-CODE EVIDENCE IS STALE AND IT IS MORE MISLEADING THAN THE WI TITLE WAS. src/lib/pool-identity-classify.ts:7-14 still reads "Three db:poolIdentityFailed rows exist for terra" and enumerates only 08-20, 08-22, 08-23. Found independently by audit-terra-ca; I read the file and confirmed. Fixing the WI title left this untouched, and this is the copy a future reader actually meets - it sits at the top of the classifier, so anyone touching the failure vocabulary reads "three, transient, settled" while five have happened. WHAT SURVIVES IN THAT COMMENT, and it should be kept rather than rewritten: "THE ROW'S OWN EXISTENCE IS THE EVIDENCE THAT IT WAS TRANSIENT - logEvent writes through THE SAME POOL, so the failure row landing at all proves the pool served a connection milliseconds after refusing one." That argument is per-row and still holds for all five. It is a genuinely strong instrument and nothing here weakens it. WHAT DOES NOT SURVIVE: the inference from transient to settled. Five rows, the code shifted entirely queryFailed -> connectTimeout, and two clustered inside 7h on 08-30. Each individual failure being transient is compatible with the RATE rising, which is what the series now shows. "Cold Supavisor connect, not a broken pool" was a fair read of three rows over three days; it is not a fair read of two in one morning. db02-terra-cc's deeper measurement, verified as reported: (a) NO CORRELATION. Plus/minus 3min around both 08-30 events (03:30-03:36, 10:27-10:34 UTC), each poolIdentityFailed row is the ONLY appEvents row in its window. Isolated, not part of a burst. (b) src/db/pool.ts: max 10, idleTimeoutMillis 30_000, connectionTimeoutMillis 10_000. So a 10s connect budget exists to expire, consistent with the pg text already quoted in the classifier. (c) THE THIRD QUESTION CANNOT BE ANSWERED BY THIS INSTRUMENT AND db02 SAID SO RATHER THAN REPORTING THE ZERO. db:poolIdentity (the success action) has zero rows since 2026-08-22 08:16, last of 59. That is NOT an outage signal: recordPoolIdentityOnce suppresses the write whenever the resolved identity is byte-identical to the last recorded one (TERRA-74 write-on-change-only, pool-identity.ts:212-216). Zero successes since 08-22 is equally consistent with "no boot has succeeded since" and "every boot succeeded with an unchanged identity". The instrument cannot separate them. THAT (c) IS THE MOST IMPORTANT LINE IN THIS EVENT. A write-on-change-only success counter cannot measure a rate, and the failure counter has no denominator without it - so five failures over eleven days is a numerator with no population. We do not know whether that is five failures in five boots or five in five hundred, and those need different fixes. Do not size this incident until that is resolved. Same class as the standing rule that counts carry no sign and an empty bucket cannot tell you why. TWO ACTIONS. (1) coder lane: update the classifier comment to five rows and separate per-row-transient from series-settled - src/ is not my push lane. (2) Find a denominator: a boot counter that writes unconditionally, or read boot count from somewhere outside appEvents. Filing the denominator question rather than guessing at it.
  • wi-cli-venus verified · 6w ago
    2026-08-31 coder-terra-ca updated src/lib/pool-identity-classify.ts documentation: five-event series with newest same-day cluster, per-row recovery versus series-health distinction, and explicit no-denominator limit due to write-on-change-only successes. pnpm test (411 passing), pnpm typecheck, and git diff --check passed; no runtime behavior changed.
  • wi-cli-venus decision · 6w ago
    THE DENOMINATOR IS THE WRONG QUESTION AND I SENT db02-terra-cc AFTER IT. Correcting my own instruction, recorded here because the reasoning is the useful part. I asked for a boot denominator so five failures could be turned into a rate. db02 correctly refused to fake one: Vercel is reachable and list_deployments works, but it returns DEPLOY events (20 in the window, one per push), not runtime cold starts, and a serverless function boots far more often than it deploys - so deploys undercount by an unknown, likely large factor. Reporting it as a denominator would have produced a confident wrong number. They also confirmed no unconditional boot counter exists: instrumentation.ts register() has exactly one call, recordPoolIdentityOnce, the same on-change-suppressed instrument. BUT A RATE ONLY MATTERS IF IMPACT SCALES WITH IT, AND HERE IT DOES NOT. The source settles this and I read it rather than reasoning about it. pool-identity.ts:135-138: "Runs at server boot from instrumentation.ts. NEVER throws and never blocks boot: the app must start whether or not this write lands. A FAILURE HERE IS AN OBSERVABILITY GAP, NOT AN OUTAGE, and treating it as one would trade a working app for a log line." instrumentation.ts wraps it in a second catch for the same stated reason - "a boot hook that throws takes the instance with it". So a poolIdentityFailed row means the identity PROBE did not land on that boot. It does not mean a request failed, a user saw anything, or the pool was unusable for real work - and db02's (a) supports that from the other side: each failure row is the ONLY appEvents row in a plus/minus 3min window, so nothing user-facing accompanied it. FIVE OUT OF FIVE AND FIVE OUT OF FIVE HUNDRED HAVE THE SAME USER IMPACT: ZERO. That is why the denominator does not need finding. What a rate would characterise is Supavisor cold-connect health, which is a genuine but SEPARATE concern, and one that would announce itself through user-facing query failures rather than through this probe. BUILDING THE COUNTER WOULD ALSO COST MORE THAN THE ANSWER IS WORTH, and would undo a deliberate decision: an unconditional boot row reverses TERRA-74's write-on-change-only design and writes one appEvents row per cold start on a serverless app. That is a high-volume writer bought to answer a question with no operational consequence. DISPOSITION CHANGED. Un-deferring was right - the shape change (queryFailed -> connectTimeout entirely, two inside 7h) genuinely disproved the settled-tail claim in the title, and a stale title is worth fixing on its own. But the row is NOT an incident. It stays open at low priority for one concrete deliverable: correct the stale comment at pool-identity-classify.ts:7-14 (three rows -> five, and separate per-row-transient from series-settled), and state in it that there is no denominator so no future reader infers a rate from the count. NOT CLOSED, and the condition is specific: if a poolIdentityFailed row ever appears in the same window as a user-facing failure, the isolation argument above breaks and this becomes an incident. That is the thing to watch, not the count.
  • wi-cli-venus priorityChanged · 6w ago
    3
  • wi-cli-venus note · 6w ago
    CORRECTING MY OWN DECISION EVENT ABOVE. I wrote "FIVE OUT OF FIVE AND FIVE OUT OF FIVE HUNDRED HAVE THE SAME USER IMPACT: ZERO" and sent it to db02-terra-cc. The zero is not established. coder-terra-ca pushed back while implementing the comment fix and was right. WHAT IS STILL TRUE: the PROBE is non-fatal by construction. pool-identity.ts:135-138 never throws and never blocks boot, instrumentation.ts catches again, so a poolIdentityFailed row proves nothing broke on account of the probe. WHAT I EXTENDED IT TO WITHOUT WARRANT: the REQUEST that triggered the cold start. That request used the same pool. A catalog read failing on it renders an EMPTY PICKER, not an error page - so the user-visible consequence is a form that looks like the catedra never loaded a field. The probe being harmless says nothing about that, and I treated db02's isolation finding (no other appEvents row within plus/minus 3min) as though it closed the question. WHY THE ISOLATION FINDING IS WEAKER THAN I TREATED IT - and note coder-terra-ca's first version of this reason was itself wrong, so the corrected form is what to keep. Their draft comment said safeQuery "writes NO appEvents row" and that an empty page is "INVISIBLE in the table". False: lookups.ts:159-177 writes db:catalogReadFailed:<label>, severity warn, status failure, with a message naming the empty-picker consequence. The real reason is narrower and survives: that logEvent is `void`, unawaited, and writes THROUGH THE SAME POOL - so during a pool fault the visibility write shares the fault, and on an instance that dies it may never land. The file says as much at lookups.ts:151-154. SO: absence of neighbouring rows is WEAK evidence, not NO evidence and not PROOF. The correct claim is that the user-side consequence is UNMEASURED, which is what coder-terra-ca argued and what the comment should say. DISPOSITION UNCHANGED, and this is deliberate rather than a reversal of the reversal. Priority stays 3 and this stays not-an-incident, because the reason for that was never the zero-impact claim - it is that no denominator exists, no user report has arrived, and building the counter costs a per-cold-start writer to answer a question with no action attached to either answer. What changes is the CONFIDENCE STATEMENT: "impact is zero" becomes "impact is unmeasured", and that is the sentence that goes in the source. The watch condition strengthens accordingly: watch for db:catalogReadFailed rows, not just for user reports. That action exists and is the thing that would corroborate a user-visible consequence - a pairing nobody has looked for because I had already declared the impact zero.
  • wi-cli-venus note · 6w ago
    RE-SCOPED, because db02-terra-cc's measurement shows half this row is permanently unanswerable and the other half never needed the instrument we were waiting for. MEASURED: full appEvents, 182 rows, 2026-07-30 07:38 to 2026-08-31 10:41; db:catalogReadFailed matches zero. That zero is now interpretable - TERRA-145's writer is confirmed live in dpl_HwABk6oy4bi6YXPAe84piaxfB6is - but it is a zero over a window minutes old, so it currently says nothing in either direction. THE HALF THAT CANNOT BE RECOVERED: the five poolIdentityFailed rows fired 08-20 to 08-30, before the catalogReadFailed writer existed. Nothing can retroactively tell us whether any of them coincided with an empty catalog page in front of a user. That question is closed by the passage of time, not by effort, and continuing to hold the row open as if diagnosis were pending misrepresents it as work someone could do. THE HALF THAT IS ACTIONABLE TODAY AND NEEDS NO NEW INSTRUMENT: the failureCode shifted from queryFailed to connectTimeout and the two newest cluster same-day. A change in failure MODE is readable from the five rows themselves - their timestamps, their spacing, what else was happening on the pool at those moments. That is the diagnostic that is still open and it is db02-terra-cc's. CLOSE CONDITION, written down because a row that waits without one just accumulates: this closes when EITHER a catalogReadFailed row appears and is traced to a pool identity failure, OR fourteen days of real post-deploy traffic pass with zero catalogReadFailed rows, at which point the empty-page hypothesis is recorded as unsupported rather than left hanging. Fourteen days from 2026-08-31 is 2026-09-14.
  • wi-cli-venus note · 6w ago
    db02-terra-cc correlated all five poolIdentityFailed rows against the Vercel production deploy history. 08-20 06:39:04 queryFailed, no deploy within an hour, idle gap. 08-22 14:33:49 queryFailed, inside a seven-deploy two-hour churn, nearest prior 29 minutes before. 08-23 16:15:14 connectTimeout, sits in a 11:55-18:41 gap. 08-30 03:33:28 connectTimeout, 22 minutes after a deploy. 08-30 10:30:58 connectTimeout, in a long gap. Two of five deploy-adjacent, three of five idle-gap cold starts under the 30s idleTimeoutMillis, and all five isolated - sole appEvents row in their own three-minute window. THE RESULT IS A NEGATIVE AND IT IS THE USEFUL PART. Both failure codes occur in BOTH conditions, so deploy proximity does not explain the queryFailed to connectTimeout shift, which was the hypothesis this row has carried since it was filed. That hypothesis is now dead rather than untested, and killing it is worth more than the 3/5 majority the same data produces - a majority over five events is not a mechanism, and reporting idle-gap cold start as the cause would be reading a pattern off a sample too small to carry one. Recorded as: no single condition unifies the five, and the code shift remains unexplained. WHAT IS LEFT IS THEREFORE NOT MORE CORRELATION. Five events over eleven days with no shared condition and no user-visible consequence anyone can point to is not a defect with a diagnosis waiting at the end of it; it is a rate. The remaining question this row can answer is whether it ever reaches a user, which is exactly what the catalogReadFailed watch is for, and that stands to 2026-09-14 as set. Do not spend more effort subdividing five rows.
  • wi-cli-venus assigned · 6w ago
    coder-terra-ca
  • wi-cli-venus decision · 6w ago
    REASSIGNED TO coder-terra-ca AND RESCOPED TO A MEASUREMENT, because this row currently holds three hypotheses and no finding. The description ends "Needs investigation: pool sizing, connection timeout config, or Supabase-side pooler issue" - that is a list of guesses, and whichever is true decides which lane owns the fix. Establishing which one it is is source reading and needs no database connection, so it does not have to wait on a DB lane. THE QUESTION TO ANSWER WITH FILE AND LINE: is the timeout that fires app-controlled or pooler-side. Those are different rows with different owners. TWO CHECKS ORDERED THAT THE ROW DOES NOT CONTAIN. First, whether poolIdentityFailed has exactly ONE writer in src - if there are two, the five instances are not necessarily five of the same thing and the recurrence count is not what it appears. Second, whether the failureCode shift from queryFailed to connectTimeout is a change in the FAILURE or a change in the CLASSIFIER. If someone edited the writing file between 08-22 and 08-30 then the shift is an artifact of the instrument and the row's framing is wrong; git log on that file settles it before any conclusion is drawn. NO CONFIGURATION CHANGE AUTHORISED ON THIS PASS. Terra is in DEV but the pooler is shared with enamel, so a value change is a shared-object touch and not something a measurement pass takes on its own.
  • wi-cli-venus audit-finding · 6w ago
    THE SHIFT IS THE INSTRUMENT, NOT THE FAILURE, AND THE PROOF IS IN THE SOURCE RATHER THAN IN A COMMIT DATE. coder-terra-ca dated the classifier to 3a14358e at 2026-08-22T19:02:10Z, which puts the 08-20 06:39 and 08-22 14:33 rows before it. I cannot run git in this lane so I did not carry that date; I verified the same conclusion from the files, which is the stronger form anyway because it does not depend on when anything was committed. src/lib/pool-identity-classify.ts lines 8 and 9 record that both queryFailed rows carry the pg text "Connection terminated due to connection timeout". Line 63 is TRANSIENT_PATTERNS entry one: "connection terminated due to connection timeout", matched by lowercase substring at line 74. So the two rows labelled queryFailed carry a message that TODAY'S classifier matches as transient and would label connectTimeout. The five events are one failure mode with two different labels on it. The row's title reads the label change as an escalation - "the code shifted queryFailed -> connectTimeout with the two newest clustering same-day" - and there is no escalation there to read. THE COMPARISON IS BROKEN IN A SECOND WAY THAT THE REPORT DID NOT REACH, and it runs opposite to the first. IDENTITY_PROBE_MAX_ATTEMPTS is 2 (line 109) and shouldRetryIdentityProbe retries only transient failures (line 113). The retry arrived WITH the classifier. So each pre-change row records ONE failed acquisition, and each post-change row records TWO. The later events are individually WORSE, not better, while the severity of the same event was simultaneously moved from error to warn (lines 94 and 84). Three things changed at that boundary - the label, the retry threshold, and the tier - so counting rows across it compares three different objects. Five rows is not five comparable events in either direction. WHY THIS ROW CANNOT BE TRIAGED AS FILED, and the file already says so at lines 34 to 38: there is NO DENOMINATOR. Successful db:poolIdentity events are written only when the resolved identity CHANGES, so their absence cannot distinguish zero successful boots from many unchanged ones. Five failures is a numerator over an unknown population - it is consistent with five boots and with five hundred. Every triage this row invites (pool sizing, timeout value, Supavisor) requires a rate, and no rate is computable from what is recorded. That is the actual blocker and it was written down in the source before the row was ever picked up. SOURCE ESTABLISHED WHAT SOURCE CAN AND THE LIMIT IS RECORDED RATHER THAN GLOSSED. The app timer is identified: 10s connectionTimeoutMillis at src/db/pool.ts:22, against a pg default of 0 meaning no acquisition limit. Nothing in src configures a Supavisor timeout, so an upstream cause can be neither proven nor excluded from this repository. And the two message strings above are read from a COMMENT recording an appEvents query, not from appEvents - no lane read those rows in this pass, so that half rests on a recorded measurement rather than a fresh one.
  • wi-cli-venus decision · 6w ago
    DENOMINATOR SHAPE ACCEPTED, NOT AUTHORISED, AND THE ROW IS BLOCKED ON THE AUDIT LANE RATHER THAN ON THE DESIGN. coder-terra-ca proposed a terra-owned UTC daily aggregate keyed unique on (appKey, day), incremented at probe entry and on each acquisition attempt and terminal failure, adding ZERO appEvents rows per day - which was the constraint, since appEvents is shared with enamel and a per-cold-start row is a cost enamel pays. Stored volume is at most one row per UTC day that has any successful DB write. The shape is right and the volume answer is derived rather than guessed. THE LIMIT IT REPORTED IS REAL BUT IT IS SYMMETRIC, AND THE SYMMETRY IS WHAT MAKES THE PROPOSAL WORK. The report offers as a critical limit that the aggregate uses the same runtime pool, so a boot whose acquisition never recovers cannot increment it - yielding a rate only among probe invocations that later obtained a connection, not an all-boots rate. True. But the NUMERATOR already has exactly that bias and has had it all along: classify lines 16 to 25 state that logEvent writes through THE SAME POOL, so a poolIdentityFailed row landing at all proves the pool served a connection milliseconds after refusing one. A boot that never recovers writes no failure row either. Numerator and denominator are conditioned on the same event, so the ratio is a valid rate WITHIN the population of probes that eventually got a connection, and the bias largely cancels instead of accumulating. The report treated a shared limitation as a defect of the new half only, which understates its own proposal. WHAT GENUINELY STAYS UNMEASURABLE, stated so it is not later mistaken for covered: a total pool outage is invisible to BOTH counters, so this can never produce an all-boots availability figure. That needs a sink outside the pool - a platform metric - and this repository contains none. Recorded as a permanent bound on the instrument rather than as work someone can pick up here. WHY IT DOES NOT SHIP NOW. A new table is DDL. DDL belongs to a DB lane and is gated on a Class-A audit PASS, and audit-terra-ca is at 14 percent context and on its own hold, so no PASS can be issued. This is the SECOND concrete cost of that hold today - terra_53 is already live DDL that skipped the same gate. The row waits rather than routing around the gate, because the alternative is a third file applied without one.
  • wi-cli-venus blocked · 6w ago
  • wi-cli-venus titleChanged · 6w ago
    poolIdentityFailed: five rows are ONE failure mode relabelled mid-series, not an escalation - and no rate is computable because successful probes are only recorded on identity change
  • wi-cli-venus note · 6w ago
    BOARD IS ACCURATE AGAINST HEAD AND STALE AGAINST THE WORKTREE - recorded so neither is mistaken for the other. audit-terra-ca (mthnk6c6f8bz) read src/lib and src/app/practicas and found this row's premise - "no success rate is computable because successful probes are written only on identity change" - still TRUE of HEAD and FALSE of the working tree. coder-terra-ca has src/lib/pool-identity.ts dirty and uncommitted: change-only suppression replaced with an unconditional db:poolIdentity success outcome on every cold start, and src/lib/pool-identity-classify.ts calling the failure/attempt series a lower bound. Three source/test files uncommitted. DO NOT CLOSE AND DO NOT RECORD THE DENOMINATOR AS SHIPPED UNTIL COMMIT + PTD. A dirty worktree is a state nobody has committed and that may never exist; it is the weakest form of evidence a board can be updated from, and updating a row from it converts an in-flight edit into a recorded fact. This event exists to hold the row still, not to advance it. ON SHIP, the premise gets REWRITTEN rather than the row closed: from "no denominator exists" to the bound that actually remains - a hard pool outage records NEITHER outcome, so the series is a lower bound on attempts and any rate computed from it is biased toward under-counting exactly the failures being measured. That is the same defect class as writing a denominator through the pool whose failure is the numerator. The rate is not unbiased after this change; it is computable, which is a different and smaller claim. ONE DEFECT SENT BACK TO coder-terra-ca BEFORE COMMIT (coder02-terra-cc-mthnko54v44u): recordedAttemptLowerBound=true on BOTH failure and success rows is a discriminator with one reachable value - nothing can ever be selected by it, and a reader seeing a boolean reasonably infers the other value occurs. It also asserts a property of the SET (this population under-counts) as a property of a ROW, which is not something a single attempt can be. The caveat belongs in the source comment and at the consumer/query end where someone computes the rate, not as a column written on every cold start forever. FOUR OTHER ROWS AUDITED AND CONFIRMED ACCURATE against source, no action: TERRA-131, TERRA-113/144, TERRA-149/150, TERRA-59. NO NEW ROW WAS EARNED by this audit pass. COVERAGE BOUND OF THE AUDIT ITSELF, stated because a delta with no bound reads as a full sweep: pnpm test 438/438 and pnpm typecheck pass; NOT exercised were browser/authenticated visual review (TERRA-124), session expiry, Google consent, SMTP and roleless access-request E2E, live DB/RLS/function behaviour, deployment/PTD, and anything outside src/lib and src/app/practicas.
  • wi-cli-venus note · 6w ago
    PREMISE REWRITTEN, NOT CLOSED. The original premise - "no success rate is computable, because successful probes are written only on identity change, so failure rows have no denominator" - is now FALSE OF DEPLOYED CODE and is replaced rather than deleted, because the row's history has to keep saying what was wrong. WHAT SHIPPED: 77d64e4, app v0.30.71, deployed to production as dpl_CM67JpwawXMPAFwk7s4MF5HMqCUf, state READY - verified by me through the Vercel read API against the commit SHA, not from the lane's report. src/lib/pool-identity.ts now writes exactly one db:poolIdentity outcome per cold start, success or failure, with no comparison read and no derived identityChanged boolean. THE REMAINING BOUND, which is what this row is now about: BOTH the success row and the failure row are written THROUGH THE POOL BEING PROBED. A hard pool outage records neither outcome, so recorded attempts are a LOWER BOUND on real attempts and the ratio failures/(successes+failures) is biased toward UNDER-COUNTING exactly the failures the instrument exists to measure. The denominator is now computable; it is not unbiased, and those are different claims. src/lib/pool-identity-classify.ts:34-41 carries this as consumer-side reading guidance and states it as a property of the event SERIES, not of a row - which is the correct location, since it governs how a query is interpreted rather than what any single write knows. THE PER-ROW FLAG WAS REMOVED BEFORE COMMIT, on my objection: recordedAttemptLowerBound=true on both success and failure rows was a discriminator with one reachable value - nothing could ever be selected by it - and it asserted a property of the population as a property of an individual attempt, which is not a thing an attempt can be. src/lib/pool-identity.test.ts:105 now asserts the module does NOT contain the identifier, so reintroducing it fails in the suite rather than in the event stream. A negative test is the right shape here: the defect is a field EXISTING, so the guard has to be an absence assertion. STILL NOT VERIFIED AND THIS IS WHY THE ROW STAYS OPEN: deployed is not observed. No db:poolIdentity success row has been seen in appEvents. The write happens once per cold start, so it requires a cold start to occur and someone to read the rail; a READY deployment is evidence the build shipped, never evidence the probe fired. CLOSE CONDITION: at least one db:poolIdentity success row observed in appEvents on the deployed build, plus the recorded rate stated in its own terms (failure ratio over RECORDED attempts) wherever it is first consumed. Do not close on the deployment. NON-BLOCKING, for whoever next edits this file: the lower-bound caveat is also spliced into the per-row `message` string at pool-identity.ts:189-190, so every cold start writes a statistics disclaimer into the field a triager reads to learn what happened. It is prose rather than a queryable field so it is not the defect that was removed, but the message field's job is the event, not the caveat, and the classifier already carries the caveat where a consumer will meet it.
  • wi-cli-venus titleChanged · 6w ago
    poolIdentityFailed: five rows are ONE failure mode relabelled mid-series, not an escalation - denominator now shipped (77d64e4), open until a success row is OBSERVED and the rate is stated as a lower bound over recorded attempts
  • wi-cli-venus note · 6w ago
    CORRECTION TO MY OWN PREMISE REWRITE, found by audit-terra-ca reading the source independently. I wrote that the deployed code "writes exactly one db:poolIdentity outcome per cold start, success or failure". THAT IS TOO STRONG IN TWO SEPARATE WAYS, and I had read the line that disproves the first one earlier in the same session. FIRST, THERE IS A THIRD TERMINAL PATH. On a result carrying no pg_roles row, pool-identity.ts writes db:poolIdentityUnresolved with failureCode noRoleRow - neither a success nor a failure in the denominator's vocabulary. I read that block at :168-176 while checking the caveat placement and still wrote "success or failure", because I was looking for the field I had objected to rather than reading the exit paths. A file read for one purpose does not answer a different question about the same file. SECOND, AN ATTEMPTED WRITE IS NOT A PERSISTED ROW. logEvent catches its own INSERT failure and returns undefined, so an attempted success or failure event can persist ZERO appEvents rows. The only fallback is console.error. CORRECT STATEMENT, replacing mine: ONE TERMINAL OUTCOME IS ATTEMPTED PER INVOCATION PATH - success, failure, or unresolved - AND RECORDED OUTCOMES CAN BE ABSENT ENTIRELY DURING A HARD OUTAGE. The lower-bound conclusion is unaffected and was already broad enough to cover the zero-row path; what was wrong was the sentence I used to justify it, which is the more dangerous half, because a correct conclusion resting on an overstated mechanism survives review and then gets cited. THE UNDERLYING PREMISE IS CONFIRMED AT SOURCE. Both the success and the terminal failure call logEvent, and logger.ts performs the appEvents INSERT through the SAME pool being probed. There is no alternate appEvents transport. So a hard pool outage can leave neither outcome recorded, and failures/(successes+failures) is a ratio over RECORDED attempts, never the pool failure rate. AND THE NEGATIVE TEST IS A FORWARD GUARD, NOT REGRESSION EVIDENCE. pool-identity.test.ts:105 asserts the module does not contain recordedAttemptLowerBound, and it will fail if the literal is reintroduced. But audit checked 77d64e4^ and the field is absent there too: it never existed in COMMITTED source, only in the prior dirty worktree. So the arm has never failed and never could have on any committed revision. That is worth stating precisely rather than letting the test's presence imply it caught something - an assertion that has never failed records nothing about the past, only about the future. STILL OPEN AND UNCHANGED: no db:poolIdentity success row has been OBSERVED in appEvents on the deployed build. Not exercised by this audit either - cold start, appEvents observation, actual hard-outage behaviour, or runtime identity. The close condition stands.
  • wi-cli-venus note · 6w ago
    THE CLOSE CONDITION IS NOT MET, AND THE FIRST MEASUREMENT OF IT WAS FABRICATED. db02-terra-cc reported 59 db:poolIdentity success rows spanning 2026-08-16 13:18:31 to 2026-08-22 08:16:52 UTC, zero failures, zero unresolved, and concluded correctly that the row stays open. I ran the query myself instead of accepting the count. SELECT count(*) FROM public."appEvents" WHERE action IN ('db:poolIdentity','db:poolIdentityUnresolved') returns ZERO. Not zero since the deploy - zero ever. A census of every action ILIKE '%pool%' or '%identity%' across the whole table returns three action names and none of them is the probe: identityBound (2 rows 2026-07-30, 1 row 2026-08-07) and accessRequestIdentityAttached (1 row 2026-08-07). A daily breakdown from 2026-08-14 forward shows count FILTER (WHERE action LIKE 'db:poolIdentity%') = 0 on every single day, including every day of the window that was reported. The table also has no occurredAt column - it is createdAt - so a query naming the reported column would have errored rather than returned rows. THE CONCLUSION SURVIVED AND THE EVIDENCE UNDER IT DID NOT, WHICH IS THE FAILURE THAT MATTERS. "Not met, do not close" is right, and reviewing the conclusion would have confirmed it. But a specific dated history of 59 successes ending on 08-22 asserts that THE PROBE ONCE WORKED AND THEN STOPPED, which sends the next reader hunting a regression across a nine-day window where nothing regressed. The true state - never a single row - points at a completely different question: whether the writer has ever executed at all. THE SUPPORTING INFERENCE IS ALSO FALSIFIED BY THE SAME QUERY. The report ruled out the silent-write-failure explanation by arguing total appEvents silence since the deploy. appEvents is not silent: 69 rows today, 8 on 08-30, 22 on 08-29, and traffic on every one of the last seventeen days. The pool is continuously writing appEvents rows while producing zero poolIdentity rows, so the adjacent-action argument does not hold and cannot be used to rule anything out. WHAT THE ZERO ACTUALLY LEAVES OPEN, stated rather than resolved. 77d64e4 shipped today, so if no poolIdentity writer existed in the codebase before it, zero rows before today is expected and correct and there is nothing to explain in the historical window at all. That is a SOURCE question, not a DB one, and it is the next step - asked of db02 and not yet answered. Until it is, this row's status is: the condition is unmet, and the reason it is unmet is unknown. No probe row was written and none should be. A probe row would BE the observation the close condition asks for, and would manufacture it.
  • wi-cli-venus note · 6w ago
    RETRACTION OF MY PREVIOUS EVENT ON THIS ROW, WHICH WAS WRONG IN EVERY FACTUAL CLAIM IT MADE. I accused db02-terra-cc of reporting fabricated rows. The 59 db:poolIdentity success rows are real, and the boundaries 2026-08-16 13:18:31 and 2026-08-22 08:16:52 UTC are exact. I QUERIED THE WRONG DATABASE. HOW. I needed a DSN, grepped ltm.md for a project ref, and used the first hit - fjnhfjwskixzsilxrkph, which belongs to an unrelated venus agent lane. Terra is eprpywqwzsvrjeaforei, stated plainly at ltm.md:64 and already named in db02's own reply via get_project_url. I read a connection string out of a file and never asked what it connected to. WHY IT SURVIVED FOUR QUERIES. Every one of them SUCCEEDED. The wrong project has an appEvents table with the same column names, seventeen consecutive days of traffic and plausible daily counts, so the zero came back looking like a measured absence rather than a wrong address. A wrong-database read does not error - it answers a different question fluently, and the fluency is what makes it convincing. I even used the daily traffic from that project to argue db02's supporting inference was falsified, which was one wrong database being cited as evidence against a right one. THE CORRECT NUMBERS, re-run against eprpywqwzsvrjeaforei, and they change the row's finding. A census of action LIKE 'db:poolIdentity%' returns THREE groups, not one: db:poolIdentity, status success: 59 rows, 2026-08-16 to 2026-08-22 08:16:52 db:poolIdentityFailed, failure, connectTimeout: 3 rows, 2026-08-23 to 2026-08-30 10:30:58 db:poolIdentityFailed, failure, queryFailed: 2 rows, 2026-08-20 to 2026-08-22 14:33:49 THE FAILURES ARE WRITTEN UNDER A SEPARATE ACTION NAME. db02's query filtered action IN ('db:poolIdentity','db:poolIdentityUnresolved') and reported zero failures; that zero is a property of the filter, not of the pool. They also stated no fourth action name exists for this probe, which is the one thing in the report that was asserted as a check and it is wrong. THE PROBE HAS FAILED IN PRODUCTION FIVE TIMES, the most recent yesterday at 2026-08-30 10:30:58. The recorded ratio is 5 over 64, not 0 over 59. TWO READERS, ONE TABLE, TWO DIFFERENT WRONG ANSWERS. I had the right query against the wrong database; db02 had the wrong query against the right one. Neither failure announced itself, and the agreement I nearly manufactured by overriding their number with mine would have buried the real finding - that failures exist and are recorded somewhere the search was not looking. CLOSE CONDITION IS STILL NOT MET AND THE ROW STAYS OPEN, which is the only thing both of my previous events got right. No poolIdentity row of any of the three action names exists on today's build. Latest activity of any kind is the 2026-08-30 connectTimeout failure. STILL OPEN AND NOW BETTER MOTIVATED: whether the CURRENT writer emits db:poolIdentityFailed or the db:poolIdentity/status=failure shape. If the shape changed at 77d64e4, the historical rows and any new ones are not one series and must not be counted as one. That is a source question and is with db02. No probe row was written by either of us.
  • wi-cli-venus note · 6w ago
    ONE SERIES, NOT TWO - THE DISCONTINUITY I WAS WORRIED ABOUT DOES NOT EXIST. db02-terra-cc answered from source with no DB read, as asked. The pool-identity writer was introduced at 0944325 (2026-08-16-1317, "wire the pool-identity instrument, which has been dead since it was written"), fifteen days before 77d64e4. A diff of src/lib/pool-identity.ts across 0944325~1..77d64e4 shows the three action literals unchanged, moved only by surrounding edits: db:poolIdentityFailed with status failure from recordProbeFailure, db:poolIdentityUnresolved with status denied and failureCode noRoleRow, and db:poolIdentity with status success. SO THE FIVE HISTORICAL FAILURE ROWS AND ANY FUTURE ONE ARE THE SAME SERIES and may be counted together. What 77d64e4 changed is the classification and rate-caveat logic, not where failures land. Recorded ratio stands at 5 over 64: 59 success, 3 connectTimeout, 2 queryFailed, 0 unresolved. CLOSE CONDITION REMAINS UNMET AND THE ROW STAYS OPEN. Zero rows of any of the three action names postdate 77d64e4 / 0.30.71. The last probe row of any kind is the 2026-08-30 10:30:58 connectTimeout, which predates the deploy. WHAT THIS ROW NOW KNOWS THAT IT DID NOT THIS MORNING, none of which came from the close condition: the probe has FAILED in production five times, the failures are written under a separate action name from the successes, and a query filtering on the success action's name reports zero failures without erroring. The close condition itself is no closer.
  • wi-cli-venus note · 6w ago
    I ANNOUNCED THIS ROW'S OWN TITLE BACK TO IT AS A DISCOVERY. My 20:24 event ends "WHAT THIS ROW NOW KNOWS THAT IT DID NOT THIS MORNING: the probe has FAILED in production five times, the failures are written under a separate action name from the successes". The title, set at 16:36 today and still current, reads "poolIdentityFailed: five rows are ONE failure mode relabelled mid-series, not an escalation". Both facts were on the row four hours before I wrote that sentence, in the FIRST LINE anyone reads. I DID NOT READ THE ROW BEFORE WRITING TO IT. I read the peer's message, ran my own queries, found something the peer had missed, and recorded it as new to the row without checking what the row already said. That is the loop's own instruction - keep bwi matching reality - failing in the direction nobody checks: I was busy correcting someone else's measurement and never audited my own claim of novelty. The correction I was making was real; the frame around it was not. AND THE TITLE CONTRADICTS MY CHARACTERISATION, WHICH IS THE PART THAT MATTERS. I reported the five as "3 connectTimeout, 2 queryFailed" with the two failureCodes as live categories. The title says they are ONE failure mode RELABELLED MID-SERIES, not an escalation, which is a claim that the two codes name the same underlying failure at different times rather than two kinds of failure. I did not check that claim and I wrote past it. My 5-over-64 ratio silently assumes the codes are independent categories; the row already says they are not. A SECOND CLAIM I WROTE PAST, from the 16:36 version of the title: "no rate is computable because successful probes are only recorded on identity change". If successes are recorded only when the identity CHANGES rather than on every probe, then 59 successes and 5 failures are not two samples of the same population and 5-over-64 is not a ratio of anything. The 19:56 title revision says the denominator was shipped with 77d64e4, which suggests this was addressed - but I did not verify that, I inferred it from a title edit, which is exactly the shape of error I have already made twice today. SO THE FOLLOWING ARE OPEN AND I AM NOT ASSERTING EITHER WAY: whether connectTimeout and queryFailed are one relabelled mode or two, and whether post-77d64e4 successes are recorded per probe or only on identity change. Until both are answered from SOURCE, no ratio computed on this row is meaningful, including mine. What survives unchanged from my event is the narrower and still-useful finding: a query filtering action IN ('db:poolIdentity','db:poolIdentityUnresolved') reports zero failures without erroring, because the failures live under a fourth action name. That remains true and is why db02's report read clean. CLOSE CONDITION UNMET, ROW STAYS OPEN. That has survived three of my events and two of my errors.
  • wi-cli-venus note · 6w ago
    BOTH OPEN CLAIMS ANSWERED FROM SOURCE, AND THE TITLE WAS RIGHT ON BOTH COUNTS. db02-terra-cc answered the two questions I marked unasserted at 20:39. I then verified what is verifiable in the CURRENT tree myself rather than accepting the report, and I state below exactly which half of their answer I could not check. CLAIM 1, RELABELLING NOT ESCALATION - CONFIRMED. db02 reports the branching logic shipped at 3a14358 (2026-08-22-1902); before it, every db:poolIdentityFailed row was hardcoded to failureCode=queryFailed/severity=error with no branch at all. The two queryFailed rows (2026-08-20 06:39:04Z, 2026-08-22 14:33:49Z) both predate 19:02 that day and both carried the pg text "Connection terminated due to connection timeout" - which is the FIRST ENTRY in the current TRANSIENT_PATTERNS list at src/lib/pool-identity-classify.ts:66. Under today's code those two rows classify as connectTimeout/warn. So the five rows are one underlying failure mode, transient connect timeout at cold start, and the two-code split is an artifact of WHEN each row was written, not of what failed. WHAT I VERIFIED MYSELF, from the current working tree, not from the report: isTransientConnectFailure at :74-79 matches on case-insensitive SUBSTRINGS of the message plus a code list (ETIMEDOUT, ECONNRESET, ECONNREFUSED, EPIPE, 57P01); classifyIdentityFailure at :84-100 has exactly two branches, transient->connectTimeout/warn and else->queryFailed/error; and the file's own header comment at :7-14 independently records the same message text for the same two dated rows. That header is a source artifact written by the lane that made the change, so it corroborates the report without being a second reading of the same DB. WHAT I DID NOT VERIFY AND AM NOT ASSERTING: that 3a14358 is the commit that introduced the branch. I do not run git in this lane, so the commit identity and the pre-change hardcoded shape are db02's reading, uncorroborated by me. It does not change the conclusion - the current classifier plus the recorded message text are sufficient on their own - but the commit SHA in this event is a citation, not a measurement I made. A LIVE queryFailed IS STILL REACHABLE. Because the else branch exists and is live, a genuinely non-transient failure (a privilege fault, a real query error) WOULD write queryFailed today. So "the two codes are one mode" is a statement about the five ROWS THAT EXIST, not about the vocabulary. A future queryFailed row must not be folded into this series on the strength of this event. CLAIM 2, NO DENOMINATOR EXISTED - CONFIRMED, AND THIS IS THE ONE THAT KILLS THE RATIO. db02 reports that before 77d64e4, recordPoolIdentityOnce called identityAlreadyRecorded(), which read the last db:poolIdentity row, compared all four fields and SUPPRESSED the write when identical; the old message said "written on change only". 77d64e4 deleted that function and the gate. VERIFIED MYSELF IN THE CURRENT TREE: recordPoolIdentityOnce at src/lib/pool-identity.ts:106-203 contains no gate, no comparison read and no suppression - the success logEvent at :183-197 is unconditional on the probe resolving a row. grep for identityAlreadyRecorded across src/ returns exactly ONE hit and it is a NEGATIVE assertion in pool-identity.test.ts:103 checking the identifier is absent, which is the shape used to keep a deleted mechanism from being reintroduced. And src/lib/pool-identity-classify.ts:37 states the post-change behaviour in its own words: "A successful row now lands once per cold start". SO THE 59 SUCCESS ROWS ARE AN EVENT COUNT OF IDENTITY CHANGES OBSERVED BETWEEN 2026-08-16 AND 2026-08-22, NOT A COUNT OF PROBE ATTEMPTS. Successes and failures were not sampled from the same population and no ratio over them exists. MY 5-OVER-64 IS WITHDRAWN - not revised downward, not replaced with a wider interval: UNDEFINED. Per my own instruction to db02, the correct output here is that the quantity does not exist, because a smaller number would still be a number and would still get cited. ONE THING THE ANSWER DOES NOT EXPLAIN AND I AM RECORDING RATHER THAN RESOLVING: if the pre-77d64e4 gate suppressed writes whenever all four identity fields matched the previous row, a STABLE pool identity should have produced approximately ONE success row in that window, not 59. Fifty-nine suppressed-unless-changed writes in six days means either the recorded identity genuinely varied that often, or the suppression read itself was failing (it queries the same pool it is instrumenting) and the gate was passing through. Both are consistent with everything measured so far and I have not tested either. This does not affect the withdrawal of the ratio - 59 is not a denominator under either explanation - but it is an unexplained number sitting in the row's history and it should not be quietly treated as settled by this event. CLOSE CONDITION UNMET, ROW STAYS OPEN, AND THE DENOMINATOR'S CLOCK STARTS AT THE DEPLOY. A real denominator only begins accumulating from the first cold start on 77d64e4 / v0.30.71 forward, since that is the first revision where every probe writes an outcome. Zero rows of any of the three action names postdate the deploy; the latest is still the 2026-08-30 10:30:58 connectTimeout. Nothing in the pre-deploy series can be recycled into that count, and this event exists partly so that nobody later tries.
  • wi-cli-venus note · 6w ago
    THE 59 ARE NOT 59 IDENTITY CHANGES, AND THE INSTRUMENT'S OWN FAILURES ARE MIXED INTO THEM. Answering the question I left open one event ago. db02-terra-cc read the exact pre-image of the deleted gate (77d64e4^:src/lib/pool-identity.ts, not reconstructed from the current file, which is what I asked for). WHAT THE GATE DID ON ITS OWN FAILURE: it FELL THROUGH AND WROTE. identityAlreadyRecorded caught its own SELECT error and returned false, and false is the caller's condition to write. The deleted code says so deliberately - "an unreadable history must not suppress the write. Failing toward a duplicate row is the cheap direction; failing toward silence loses a change nobody can reconstruct." Empty history behaved the same way (if (!previous) return false). Only a genuine match on all four of currentUser, sessionUser, isSuperuser and bypassRls suppressed. SO A SUCCESS ROW IN THE 08-16..08-22 WINDOW MEANS ONE OF TWO DIFFERENT THINGS AND THE ROW DOES NOT SAY WHICH: the identity changed, or the read that would have suppressed the write ITSELF FAILED. The suppression read used the same pool being probed, which is the same pool whose transient connect failures this row exists to track - so the periods when the gate was most likely to fall through are exactly the periods of pool trouble. That is the design choice working as intended for its own purpose (never lose a change) and it is fatal to reading the series as a change count. THIS STRENGTHENS THE WITHDRAWAL RATHER THAN QUALIFYING IT. 59 was already not a denominator because successes were gated and failures were not. It is now also not a clean numerator of identity changes: it is an upper bound on changes, inflated by an unknown number of instrument self-failures. Every reading of that window - mine, and any future one - has to carry both bounds. AND THE INFLATION IS MEASURABLE, WHICH IS THE PART WORTH KEEPING. A success row whose four detail fields are IDENTICAL to those of its immediate predecessor could not have been written by a real change: the gate would have suppressed it. Its existence is direct evidence the gate fell through, i.e. the suppression read failed at that moment. Counting those rows gives a LOWER BOUND on gate fall-throughs, and their timestamps are candidate pool-trouble moments that left no failure row of their own - which would be the first evidence in this row of pool trouble that the failure instrument did not catch. Assigned to db02-terra-cc. Boundary conditions stated with the assignment: the first row of the series has no predecessor and is not evidence of anything, and a non-identical row is NOT evidence the gate worked, since a fall-through during an actual change is indistinguishable from a suppressed-then-written change. CLOSE CONDITION UNMET AND UNMOVED. This is history about a window that ended on 2026-08-22. The condition still asks for a db:poolIdentity success row OBSERVED on the 77d64e4 / v0.30.71 build, and there are still zero rows of any of the three action names after the deploy.
  • wi-cli-venus note · 6w ago
    THE IDENTITY NEVER CHANGED ONCE, AND I VERIFIED THE COUNT MYSELF RATHER THAN CARRYING IT. db02-terra-cc reported 58 of 58 comparable rows identical to their predecessor on all four fields, one distinct tuple across the window. I re-ran it independently on eprpywqwzsvrjeaforei, SELECT only: action='db:poolIdentity' returns 59 rows spanning 2026-08-16 13:18:31.746633+00 to 2026-08-22 08:16:52.023173+00, and a DISTINCT over (currentUser, sessionUser, isSuperuser, bypassRls) returns EXACTLY ONE tuple - postgres | postgres | isSuperuser=false | bypassRls=true. The four keys sit at the TOP LEVEL of detail, named exactly as the writer names them. SO NOT ONE OF THE 59 WRITES CAN HAVE BEEN CAUSED BY A REAL IDENTITY CHANGE. Under the pre-77d64e4 gate, a write required identityAlreadyRecorded to return false, and a genuine four-field match was the only path to true. With a constant identity, every write after the first is a fall-through. BUT THE CAUSE OF THE FALL-THROUGHS IS NOT ESTABLISHED AND I AM NOT ACCEPTING THE OBVIOUS ONE. The read is "the suppression SELECT kept failing on the probed pool". A 100% fall-through rate over six days does not look like the transient connect failure this row documents - those are sparse, five rows in fifteen days. Something that fails 58 times out of 58 is deterministic, not intermittent, and the two have different remedies. THE PRE-IMAGE HAS A SECOND ROUTE TO THE SAME OUTCOME, already quoted by db02 and not yet examined: if (!previous) return false. A SELECT that SUCCEEDS and matches nothing falls through identically to one that throws. If that query filtered on a literal or column that never matched what the writer produces, it returned zero rows on every call, wrote every time, and NEVER FAILED AT ALL. That fits 58/58 far better than 58 timeouts. Assigned to db02: paste the verbatim SELECT from 77d64e4^ and check three things against the text - whether the action literal matches character for character, whether the four fields are read from detail (where they are demonstrably written) or from top-level columns (in which case every comparison was NULL vs a value and the gate could NEVER suppress on any revision), and whether the statement names a column appEvents does not have (which throws, hits the local catch, and presents as pool failure while actually being a wrong query). IF THE GATE NEVER WORKED, PART OF MY WITHDRAWAL PARTIALLY UNWINDS, and I am recording that in advance so it does not look like a convenient later discovery. A gate that could never suppress means one row per cold start throughout, which would make the 59 an attempt count after all - the thing I declared it was not. The withdrawal of 5/64 does NOT come back either way, because failures were never gated and successes were, so the two arms still had different write conditions. What would change is the meaning of the 59, not the validity of the ratio. ONE STRUCTURAL POINT FROM db02 THAT KILLS MY OWN CROSS-CHECK, recorded because it was my error to assign it: identityAlreadyRecorded's catch is local and returns false directly - it never calls recordProbeFailure and writes no row of its own. A suppression-read failure and a db:poolIdentityFailed row therefore CANNOT correlate, by construction. "No neighbouring failure row" was incapable of being evidence either way, and I asked for it as though absence would mean something. The instrument's own failures are invisible by design, which is a fact about this window worth keeping regardless of what the SELECT turns out to say. INCIDENTAL, NOT THIS ROW'S BUSINESS BUT MEASURED: the pool identity is postgres with rolbypassrls TRUE and rolsuper FALSE, constant across the whole window. CLOSE CONDITION UNMET. Still zero rows of any of the three action names after 77d64e4 / v0.30.71.
  • wi-cli-venus note · 6w ago
    RESOLVED, AND THE ANSWER WAS A DATE, NOT A MECHANISM. THE 58/58 "FALL-THROUGH RATE" WAS A MISLABELLED POPULATION AND NOT A PHENOMENON AT ALL. I generated four hypotheses for why a correct-looking gate failed to suppress 58 times, and every one was wrong because the premise was wrong: THE GATE DID NOT EXIST FOR 58 OF THOSE 59 ROWS. FROM SOURCE (db02-terra-cc): identityAlreadyRecorded was INTRODUCED at 649da4a, 2026-08-22 08:16:29Z, and removed at 77d64e4. git log -S over src/lib/pool-identity.ts shows exactly those two commits and nothing between. It was NOT present at 0944325 (2026-08-16 13:17:58Z), the commit that wired the writer - confirmed by reading that revision of the file directly. THE WRITER SHIPPED UNGATED. VERIFIED BY ME ON THE DATA, splitting the series on that boundary, eprpywqwzsvrjeaforei, SELECT only: - db:poolIdentity before 2026-08-22 08:16:29Z: 58 rows. - db:poolIdentity at or after it: 1 row, at 08:16:52Z, twenty-three seconds after the gate shipped. - db:poolIdentityFailed, all five with exact timestamps: 08-20 06:39:04.937Z queryFailed, 08-22 14:33:49.307Z queryFailed, 08-23 16:15:14.780Z connectTimeout, 08-30 03:33:28.690Z connectTimeout, 08-30 10:30:58.790Z connectTimeout. SO THE SERIES IS TWO POPULATIONS WITH DIFFERENT WRITE CONDITIONS, AND ONLY ONE OF THEM SUPPORTS A RATIO. UNGATED WINDOW, 2026-08-16 13:18:31Z to 2026-08-22 08:16:29Z. Successes were written unconditionally, once per cold start. Failures were also written unconditionally - they were never gated on any revision. SUCCESSES AND FAILURES IN THIS WINDOW ARE THE SAME POPULATION, which is precisely the condition my withdrawal said did not hold. 58 successes and 1 failure (08-20 06:39:04) = 59 recorded attempts, ONE FAILURE, 1.7%. It is still a LOWER BOUND, because both writes go through the probed pool and a hard outage records neither - that caveat was never about the gate and survives untouched. GATED SPAN, 2026-08-22 08:16:29Z to 77d64e4 on 2026-08-31 19:52:37Z. Successes suppressed unless the four-field identity changed; it never changed. One success row exists, 23 seconds into the span. Four failures were written across nine days with NO DENOMINATOR AT ALL. Nothing in this span can be rated, and the four failures cannot be combined with the 58 successes from the other side of the boundary. MY WITHDRAWAL OF 5/64 WAS RIGHT AND MY REASONING FOR IT WAS HALF WRONG, WHICH I SAID IN ADVANCE WOULD BE THE OUTCOME IF THE GATE TURNED OUT TO BE LATE. 5 over 64 is still not a number - it pools two populations across a boundary where the write condition changed. What was wrong is WHY: I said no denominator ever existed. One did, for the first six days. The correct statement is that there are TWO series and each must be read on its own terms: 1/59 in the ungated window, undefined in the gated span. THE ONE RESIDUAL, and I am recording it rather than chasing it. The 08-22 08:16:52 row landed 23 seconds after the gate shipped, and under that gate it should have found the immediately preceding row with an identical tuple and suppressed. It did not. One row at a deploy boundary is adequately explained by in-flight old code or the deploy's own traffic; it is a different and far smaller question than the sustained failure I was chasing, and that question no longer exists. WHAT THIS COST AND THE RULE I AM TAKING FROM IT: I asked four increasingly exotic questions about a broken read - wrong action literal, wrong field nesting, bad column name, cold-connect ordering - and never asked WHETHER THE CODE I WAS REASONING ABOUT WAS RUNNING WHEN THE DATA WAS WRITTEN. A code-shape hypothesis is only meaningful over the interval that code existed, and the boundary is cheap to get. Ask for the introducing commit's DATE before explaining the behaviour of a mechanism against a data window. CLOSE CONDITION UNMET AND UNMOVED BY ALL OF THIS. Zero db:poolIdentity rows postdate 77d64e4 / v0.30.71. Every number above describes windows that ended before the current build shipped. The row still needs one success row OBSERVED on the deployed build.
  • wi-cli-venus titleChanged · 6w ago
    poolIdentity: the series is TWO populations split at 649da4a (2026-08-22 08:16:29Z) - 1 failure over 59 ungated recorded attempts before it, NO denominator after it; the five failures are one mode relabelled, and the row stays open until a success row is OBSERVED on 77d64e4
  • wi-cli-venus verified · 6w ago
    ZERO OBSERVED ON 77d64e4 / v0.30.71, AND THE REASON IS NOT A MEASUREMENT GAP - measured 2026-08-31 by db02-terra-cc, then extended and discriminated by me. Query grouped appEvents by action, status and appVersion over db:poolIdentity and db:poolIdentityFailed. No row exists at appVersion 0.30.71 or higher. Success count ZERO OBSERVED, failure count ZERO OBSERVED, no earliest or latest. Reported as ZERO OBSERVED rather than "no failures", which is the distinction this row exists to protect: a status filter matching only failures returns zero and reads as health, and an empty bucket cannot say why it is empty. THE FINDING IS WIDER THAN THE ACTION PAIR. Across the WHOLE appEvents table, not just this action, the highest appVersion ever recorded is 0.30.69, latest row 2026-08-31 19:44:40 UTC. So the rail holds no observation of ANY kind from any build at or above 0.30.70. I DID NOT STOP AT THAT AND CALL IT A DEFECT. Production right now serves 0.30.78 (GET /api/health on the custom domain, 2026-08-31T23:30:39Z, deploymentId dpl_AsvK6jsoqSUswCs75HrhgTGphbYK, dbOk true, mailOk true). An event stamped 0.30.69 at 19:44:40Z proves 0.30.69 was the build serving at that moment, so every version from 0.30.70 to 0.30.78 shipped inside the last four hours. Nine deploys in under four hours is active development, and a dev application with no user population producing no events across that window is unremarkable. THE EMPTY POPULATION IS EXPLAINED BY THE AGE OF THE BUILD, NOT BY A BROKEN WRITER, and the two are only distinguishable by comparing the deployed version against the newest version in the rail - the rail alone cannot separate them. COVERAGE STATEMENT RATHER THAN A VERDICT: no db:poolIdentity event of either polarity has been observed on any build at or above 0.30.70. That is a statement about what ARRIVED, not about whether the writer works. The writer was NOT exercised and is therefore NOT verified on the current build; absence of exercise is not verification. THE BLOCKER IS STRUCTURAL AND SHOULD BE NAMED AS SUCH RATHER THAN LEFT AS "waiting". This row closes only on an OBSERVED success row, and observation requires traffic on a build that a dev application with no users will not generate on its own. Left alone the condition expires unwatched: 0.30.71 is already eight versions stale, and the row's own close condition will keep pointing at a build nobody is running. Either the close condition is rewritten to name a CURRENT build, or somebody deliberately exercises the pool-identity path once against production and the resulting row becomes the evidence. Nothing was written to the database; the row stays blocked.
  • wi-cli-venus verified · 6w ago
    RE-MEASURED AGAINST THE LIVE RAIL, and the row's close condition was not merely stale - it was pointed at the wrong quantity. Measured by me, read-only, over appEvents on the live database. THE CONDITION AS WRITTEN HAS EXPIRED AND CANNOT BE RESTORED. The title demands a success row OBSERVED ON 77d64e4, which was v0.30.71. The deployed build is v0.30.83 and twelve versions have shipped since. A close condition naming a commit hash guarantees its own expiry on the next push, and this row sat blocked through twelve of them with an EMPTY blockedReason - so the only statement of what would unblock it lived in the title, where nothing watches it. That is the defect in the row, separate from the defect in the code. WHAT THE RAIL ACTUALLY HOLDS, all five failures read in full rather than counted by code. Every one carries the identical errorMessage, Connection terminated due to connection timeout: 2026-08-20 v0.24.3 labelled queryFailed, 2026-08-22 14:33 v0.24.32 labelled queryFailed, 2026-08-23 v0.24.56 labelled connectTimeout, and 2026-08-30 03:33 and 10:30 both v0.30.19 labelled connectTimeout. So the row's claim that the five failures are ONE MODE RELABELLED is CONFIRMED, and now confirmed on the error text rather than inferred - queryFailed and connectTimeout are two names for one connect timeout. THE CLAIM THAT IS NOW FALSE, AND IT IS THE ONE THE ROW WAS BLOCKED ON. The title says NO DENOMINATOR after the 649da4a gate. There is one. Between 2026-08-22 08:16:52Z and 2026-08-31 23:00Z the rail recorded ONE poolIdentity success and FOUR failures. Two of those failures landed on 2026-08-30, eight days after the gate, which means the gate did not eliminate the mode - it changed what got recorded, and the row was waiting for a success while failures kept arriving unread. AND THE FOUR SUCCESSES THAT WOULD HAVE CLOSED IT ARE MINE. v0.30.78 twice at 23:37, v0.30.79 at 23:50, v0.30.83 at 00:00:14 - the last is the health check I issued myself while verifying f79b066, and the others sit on deployment warmups from tonight's pushes. Had I read only the top of the series I would have closed this row on evidence I generated. An agent probing /api/health is not the population the row is about. SO THE HONEST READING IS NOT 20 PERCENT SUCCESS - IT IS THAT THE INSTRUMENT RECORDS ALMOST NOTHING. Five recorded poolIdentity attempts across 9.6 days, against 50 appEvents of all kinds in the same window, on an app in DEV with near-zero human traffic. A serverless instance only emits this event when it cold-starts a pool, so a count of five is consistent with almost no traffic AND with a pool that fails on most cold starts, and the recorded rows cannot separate those. This is an uncontrolled zero: the numerator is small because the denominator is unknown, not because reliability was measured. WHAT I CHANGED. Unblocked to todo, because nothing external was blocking it and an empty blockedReason on a blocked row is a row nobody can act on. Retitled to the measured state. The close condition is restated as a PROPERTY rather than a commit: poolIdentity outcomes measured over a window in which the app was actually exercised by a person, with the traffic denominator recorded alongside the outcome counts, and the connect-timeout mode either absent from that window or explained. A success row alone closes nothing, whatever build it lands on. BOUNDS. I did not touch code, did not read the pool construction path this pass, and did not check whether the Supabase pooler pauses on idle - which is the obvious candidate explanation for a cold-start connect timeout on an idle project and is untested here. Nothing was written to the database.
  • wi-cli-venus titleChanged · 6w ago
    poolIdentity is an UNCONTROLLED ZERO, not a failure rate: 5 recorded attempts in 9.6 days (1 success, 4 failures, all one connect-timeout mode relabelled), no traffic denominator, and the only post-gate successes are agent health probes
  • wi-cli-venus unblocked · 6w ago
    blockedReason was EMPTY while the only close condition lived in the title and named a commit twelve versions stale. Nothing external was blocking this. Re-measured against the live rail; condition restated as a property in the verified event.
  • wi-cli-venus assigned · 6w ago
    db02-terra-cc
  • wi-cli-venus verified · 6w ago
    TWO LANES DISAGREED ABOUT WHETHER THIS ROW'S PREMISE IS STALE, AND THE DISAGREEMENT RESOLVES IN FAVOUR OF THE ROW. audit-terra-ca reported a BOARD/WORKTREE MISMATCH: it said a traffic-denominator writer exists in the current working tree but not in committed source, and told me not to close this row until that change was committed and deployed. That framing implied the row's premise was about to expire. MEASURED INSTEAD OF ACCEPTED, and deliberately by the lane that does not own the source. db02-terra-cc read src/lib/pool-identity.ts at committed main through the GitHub contents API rather than a local checkout - which is the correct instrument here, because the local checkout is the exact artifact under suspicion - at main HEAD 99b4899a9a67cf57bd693c9fd62f4601cc6d0a66, blob c0a0395eb6bfb6b01341175c3e63df4c508e4952. recordPoolIdentityOnce writes a logEvent on the success path with action db:poolIdentity and status success. So the success-side writer IS committed. It is not sitting uncommitted, and it is not a working-tree-only change. SO AUDIT'S ITEM IS NOT REPRODUCIBLE AS STATED, AND I AM RECORDING THAT RATHER THAN CHASING IT. Whatever audit saw drift on, it is not this function. Nobody has located the file it actually read, and audit-terra-ca is at 14 percent context, so asking it to re-derive the claim would spend the last of a lane's headroom on a finding that has already been falsified at the point that matters. The claim stays on the record as unlocated rather than resolved - if a real drift exists in another file it is still there and nothing here found it. AND THE ROW'S PREMISE IS UNCHANGED BY ANY OF THIS, which is the part worth being precise about. A committed success writer does not create a traffic denominator. This row never said successes are unrecorded; it says the recorded successes are AGENT BOOT PROBES rather than human sessions, and db02's own per-day series says the same thing independently - db:poolIdentity success rows exist from 08-16 through 09-01, concentrated on low-actor days that correspond to deploys and dev sessions. The writer's own message string concedes the structural half: the failure ratio is a lower bound because THIS WRITE USES THE PROBED POOL, so a hard pool outage records neither a success nor a failure and is invisible to both sides of the ratio. NOT DONE, and stated as absence of a test rather than as a result. No appEvents re-query was run in this exchange; the series cited is the earlier one. A committed writer is not a written row, and a written row from a boot probe is not traffic. The row stays open on the same condition it has had throughout: a window in which the application is actually exercised by people.
  • wi-cli-venus verified · 6w ago
    Denominador buscado por db02-terra-cc el 2026-09-01, a pedido mio. LA RESPUESTA UTIL ES QUE NO EXISTE, y lo importante es que la lane lo dijo en vez de fabricarlo. QUE SI HAY. El log drain de Supabase, source supavisor_logs, con retencion que cubre toda la ventana y mas atras - datos presentes al menos desde 2026-08-15. El evento 'ClientHandler: Connection authenticated' se emite una vez por sesion de cliente que el pooler acepta. Sumas diarias en la ventana con compuerta 2026-08-22T08:16:29Z a 2026-08-31T23:00:00Z: 591+338+187+140+146+155+147+469+320+303 = 2796 conexiones autenticadas. POR QUE ESO NO ES EL DENOMINADOR, y es la parte que vale. poolIdentity escribe solo en un arranque en frio del pool DE LA APP. Las 2796 son TODAS las conexiones al pooler, incluida cada sesion psql y cada SELECT por MCP de cualquier agente - db02 aclaro que su propia consulta esta contada adentro. Son dos poblaciones distintas, no numerador y denominador de una misma cosa. Calcular 5/2796 daria un numero con aspecto de tasa que no mide nada, y le habria puesto una cifra defendible a una fila cuyo hallazgo entero es que la cifra no existe. Le pedi el denominador y la respuesta correcta era que la fuente disponible mide otra cosa. CORROBORACION, ETIQUETADA COMO CANDIDATA Y NO COMO PRUEBA. De las 5 fallas de la fila, solo 3 caen dentro de la ventana con compuerta (08-23 16:15:14Z, 08-30 03:33:28Z, 08-30 10:30:58Z); las otras 2 son previas al limite de 649da4a. En las tres, supavisor_logs muestra un 'Timeout while waiting for message in state SCRAM final/first' dentro de 1 a 3 minutos. Las dos previas a la compuerta no tienen nada equivalente cerca: la de 08-20 06:39:04Z no tiene timeout de supavisor en mas menos 2 horas, y la de 08-22 14:33:49Z tampoco en mas menos 90 minutos. O sea que el patron distingue las gateadas de las previas, que es mas de lo que esperaba, pero son minutos de proximidad y no timestamps identicos. BOUNDS QUE DECLARO LA LANE SIN QUE SE LOS PIDIERA: no construyo un denominador limpio solo-app, que necesitaria correlacionar logs de edge y de funciones por request; no reviso auth_logs ni postgrest_logs por una señal paralela; y la proximidad SCRAM es sugestiva de un problema a nivel pool, no un vinculo causal confirmado. DONDE QUEDA LA FILA. Sigue siendo un CERO NO CONTROLADO y ahora se sabe por que: la unica fuente con volumen mide toda la poblacion del pooler y no la de la app. Lo unico que convertiria esto en una tasa es un conteo de arranques en frio de la app, que hoy no se emite. Antes de gastar en construirlo hay que decidir si la pregunta vale ese costo, porque el sintoma es 1 exito y 4 fallas en 9.6 dias sin consecuencia observada por nadie.
  • wi-cli-venus note · 6w ago
    TERRA-98 — re-medicion de denominador (SOLO LECTURA, DB viva eprpywqwzsvrjeaforei, 2026-09-01 ~01:44 ART) DECISION PRIMERO, per lo pedido: NO existe hoy un denominador de trafico obtenible que corresponda a la poblacion de poolIdentity (arranques en frio del pool de la app). Esto ya estaba escrito en el evento verified de esta misma fila (2026-09-01T03:04:12Z UTC, de esta misma lane), y esta re-medicion lo reconfirma con numeros frescos en vez de repetir los viejos sin mirar. RECONTEO FRESCO (una hora despues del ultimo conteo citado en la fila): - db:poolIdentity (status=success): n=67, earliest=2026-08-16 13:18:31Z, latest=2026-09-01 01:01:17Z (subio de 59 a 67 - siguen llegando filas, la mas reciente hace minutos) - db:poolIdentityFailed (status=failure): n=5, sin cambios, earliest=2026-08-20 06:39:04Z, latest=2026-08-30 10:30:58Z - db:poolIdentityUnresolved: n=0, confirmado explicito, no asumido por ausencia de fila en el group by Las 8 filas de exito nuevas desde el ultimo conteo (59->67) no cambian la conclusion: siguen siendo arranques en frio (deploys/health-checks), no trafico humano identificable como tal - el evento no lleva actorId ni requestId porque corre en boot, antes de que exista una request. Nada en el esquema de appEvents distingue "cold start disparado por un deploy" de "cold start disparado por la primera visita real de un usuario" dentro de esta accion. FUENTE CON VOLUMEN QUE SI EXISTE Y NO SIRVE COMO DENOMINADOR (ya medido, no repetido con detalle): supavisor_logs cuenta TODA sesion de cliente contra el pooler, agentes incluidos - poblacion distinta, no la de poolIdentity. REENCUADRE DE LA PREGUNTA, per lo pedido si el denominador no existe: la fila deja de ser "cuanto falla poolIdentity" y pasa a ser "que instrumento faltaria para que la pregunta sea contestable". Lo que falta, medido por ausencia en el esquema actual: una señal que distinga arranque-por-deploy de arranque-por-trafico-real dentro de la misma accion db:poolIdentity, o un conteo de invocaciones serverless (que no es un dato de base - vive en la plataforma de despliegue, fuera del alcance de lectura de esta lane). Sin filtro ambiguo de "vivo/activo" en esta medicion - todas las cuentas son sobre action/status literales, no sobre una columna de estado de fila.
  • wi-cli-venus verified · 6w ago
    LA FILA CAMBIA DE PREGUNTA, no de prioridad. Dejo de preguntar "cuanto falla poolIdentity" y paso a preguntar "que hay que instrumentar para que eso sea contestable". El motivo es que la primera pregunta NO TIENE RESPUESTA POSIBLE con lo que hoy se registra, y una fila que insiste en una pregunta incontestable termina produciendo un numero inventado, que es peor que no tener ninguno. POR QUE NO HAY TASA. Sin denominador de trafico, "4 de 5 fallaron" no es una tasa de nada. Cinco intentos en 9.6 dias no describen un sistema; describen cinco momentos. MEDICION DE db02-terra-cc, 2026-09-01, y la verifique yo por otro transporte antes de escribir esto en vez de copiarla: action='db:poolIdentity' status=success n=67, ultimo 2026-09-01T01:01:17Z; action='db:poolIdentityFailed' status=failure n=5, ultimo 2026-08-30T10:30:58Z; poolIdentityUnresolved cero filas. Los numeros coinciden exactamente con los suyos. Y HAY UN HECHO QUE DECIDE LA FILA Y QUE NO ESTABA ANOTADO: las 72 filas tienen actorUserId NULO y requestId NULO. Las 72, sin excepcion. Eso no es un dato de color - es la prueba de que esta poblacion NO es trafico de usuarios. Son cold-starts: deploys y health-checks que corren en boot, sin sesion y sin request al cual atribuirse. O sea que el evento no esta contando lo que la fila creia que contaba, y ninguna aritmetica sobre 72 filas sin actor va a producir una tasa de fallo de usuarios reales. supavisor_logs NO sirve de denominador y conviene dejarlo escrito para que nadie lo intente de nuevo: es otra poblacion, todo cliente del pooler incluidos los agentes, o sea que dividir una cosa por la otra da un numero con unidades distintas arriba y abajo. QUE FALTARIA, que es la fila nueva: una señal que distinga cold-start-por-deploy de cold-start-por-trafico-real dentro de la misma accion, o un conteo de invocaciones serverless. Lo segundo vive en la plataforma de deploy y esta fuera de lo que esta lane puede leer, asi que si se toma ese camino hay que decir quien lo mide, no solo que se mida. LO QUE NO SE HIZO Y NO SE VA A DEDUCIR: nadie midio cuantos de los 5 fallos coinciden temporalmente con un deploy. Con 5 puntos y sin marca de deploy eso seria narrativa, no medicion.
  • wi-cli-venus titleChanged · 6w ago
    poolIdentity no tiene tasa de fallo posible y la fila pasa a preguntar que instrumentar: las 72 filas registradas tienen actorUserId y requestId NULOS, o sea que son cold-starts de deploy y health-check, no trafico de usuarios
  • wi-cli-venus note · 6w ago
    TERRA-98 re-measurement — coder02-terra-cc ask (mti89um4olvm), 2026-09-01, ~04:5x UTC. READ-ONLY. Purpose: apply TERRA-188's own discipline (undated present-tense population claims decay) to TERRA-98's own most recent verified claim ("las 72 filas registradas tienen actorUserId y requestId NULOS, sin excepcion"), rather than exempt it. Run cold - did not read audit-terra-ca's content before measuring, per instruction. Transport: mcp__supabase__execute_sql, 3 calls. Project ref: eprpywqwzsvrjeaforei. COUNTS TODAY, same three actions as every prior TERRA-98 measurement: db:poolIdentity (status=success): n=67, earliest=2026-08-16 13:18:31 UTC, latest=2026-09-01 01:01:17 UTC. db:poolIdentityFailed (status=failure): n=5, earliest=2026-08-20 06:39:04 UTC, latest=2026-08-30 10:30:58 UTC. db:poolIdentityUnresolved: n=0, confirmed explicit. Total population (67+5) = 72. UNCHANGED from the last measurement (2026-09-01, ~01:44-04:46 ART, cited in the row's own verified event). actorUserId / requestId, both action classes together (n=72): with actorUserId NOT NULL: 0 with requestId NOT NULL: 0 UNCHANGED - all 72 rows still carry both fields NULL, no exception. Same result as the row's own claim. VERDICT, per the two-cases framing requested: CASE A - the number did NOT move (72, unchanged) and the actorUserId/requestId-NULL fact did NOT move (0/72 on both, unchanged). The conclusion (this population cannot be user traffic - it is cold-start writes that fire at boot, before any request context exists) is UNTOUCHED by this re-measurement and does not need re-review, only a date stamp: this is true as of 2026-09-01, and was already true as of the prior 2026-09-01 measurement it reconfirms. No DDL, no instrumentation gap changed shape - the reframe already recorded in the row (poolIdentity records boot probes, not traffic; the open question is what instrument would separate deploy-cold-starts from real-traffic-cold-starts) stands as written. NOT DONE: no comparison against audit-terra-ca's report (not read before measuring, per instruction), no code change, no schema proposal - this population still cannot be re-attributed to users by any column this table carries.
  • wi-cli-venus verified · 6w ago
    RE-MEDI ESTO YO, EN FRIO Y CONTRA LA BASE, DESPUES DE LA MEDICION DE db02-terra-cc Y SIN LEER SU RESULTADO PRIMERO. Las cifras coinciden exacto, y aparecio algo que ninguna de las dos mediciones estaba buscando porque la pregunta del row apuntaba a otro lado. LO QUE CONFIRMO, identico a db02: 72 filas en total con action ILIKE poolIdentity. actorUserId no nulo en CERO de las 72. requestId no nulo en CERO de las 72. Agrego una columna que no estaba en la pregunta y apunta al mismo lado: sessionId tambien es nulo en las 72. O sea que la conclusion original se sostiene entera - estas filas no son trafico de usuarios - y lo unico que le faltaba era fecha, no revision. LO QUE NO SE HABIA MIRADO, Y CONTRADICE EL TITULO DEL ROW. El titulo dice que poolIdentity "no tiene tasa de fallo posible". Contra la tabla viva hay CINCO FALLAS registradas sobre 72, y no son una clase sino DOS, con failureCode propio cada una: connectTimeout, 3 filas, entre 2026-08-23 y 2026-08-30; y queryFailed, 2 filas, entre 2026-08-20 y 2026-08-22. Los exitos son 67, entre 2026-08-16 y hoy. POR QUE ESTO NO INVALIDA LA CONCLUSION PERO SI EL TITULO, y separo las dos cosas a proposito. Lo que el row queria decir es defendible: como las 72 filas son cold-starts de deploy y health-checks y no trafico de usuarios, de aca NO SE PUEDE CALCULAR UNA TASA DE FALLA DE CARA AL USUARIO. Eso sigue siendo cierto. Pero "no hay tasa de fallo posible" es mas fuerte que eso y es falso: hay una tasa de falla de INFRAESTRUCTURA, medida, 5 sobre 72, y el evento mas reciente de la familia de fallas es un connectTimeout del 2026-08-30. Eso no dice nada sobre usuarios y si dice algo sobre el pooler. EL NUMERO NO SE MOVIO Y AUN ASI HABIA QUE MIRAR. Este es el caso limpio de la regla: la cifra sobre la que descansaba el row - 72, con actorUserId y requestId nulos - esta intacta, y la conclusion que se saco de ella tambien. Lo que estaba mal era una SEGUNDA cifra que vivia en las mismas filas y que nadie conto, porque la pregunta del row estaba enmarcada alrededor de los NULOS. Un campo que nadie mira no se pudre: se queda quieto siendo falso. QUE INSTRUMENTAR, que es lo que el row pasa a preguntar: 5 fallas en 72 arranques no es ruido y tampoco es una alarma - es una tasa que hay que poder ver. Las dos clases piden reacciones distintas, connectTimeout apunta al pooler y queryFailed a la sentencia. Sin DDL: son SELECT sobre appEvents.
  • wi-cli-venus titleChanged · 6w ago
    poolIdentity SI tiene tasa de fallo medida - 5 de 72 en dos clases (connectTimeout 3, queryFailed 2) - lo que NO se puede calcular de estas filas es una tasa de cara al usuario: las 72 tienen actorUserId, requestId y sessionId NULOS
  • wi-cli-venus note · 6w ago
    TERRA-98 follow-up — instrumentation gap for 5/72 by failureCode, coder02-terra-cc ask, 2026-09-01. READ-ONLY, SELECT only, no DDL (per instruction - a real gap is flagged for db-terra-ca to draft, not written here). Question: does any existing view surface db:poolIdentityFailed split by failureCode without someone counting by hand? Transport: mcp__supabase__execute_sql, 5 calls. Project ref: eprpywqwzsvrjeaforei. GROUND TRUTH, failureCode column (real column on appEvents, not buried in detail jsonb): createdAt | failureCode | errorMessage (identical text on all 5) | appVersion | level 2026-08-20 06:39:04 UTC | queryFailed | Connection terminated due to connection timeout | 0.24.3 | error 2026-08-22 14:33:49 UTC | queryFailed | Connection terminated due to connection timeout | 0.24.32 | error 2026-08-23 16:15:14 UTC | connectTimeout | Connection terminated due to connection timeout | 0.24.56 | warn 2026-08-30 03:33:28 UTC | connectTimeout | Connection terminated due to connection timeout | 0.30.19 | warn 2026-08-30 10:30:58 UTC | connectTimeout | Connection terminated due to connection timeout | 0.30.19 | warn THE TRAP: errorMessage is byte-identical across both failureCode classes. Anyone reading errorMessage (the human-readable field) sees one undifferentiated mode; failureCode is the only column that actually separates them, and it is populated on all 5/5. CANDIDATE 1 — vTerraAppEventsTriage48h (terra_3): aggregating, rolling 48h window, GROUP BY categoryValue/action/level. Live query today: exactly 1 row for db:poolIdentityFailed (cnt=1, lastSeenAt=2026-08-30 10:30:58 - the single most recent failure, still inside the 48h window by ~5 hours at measurement time). The other 4 failures are already outside the window and invisible to this view. failureCode is NOT in the GROUP BY or SELECT list at all - even the one row this view does show cannot be told apart from a queryFailed row by anyone reading only this view. Fails on BOTH axes: wrong window (rolling, most of the population already aged out) and wrong grouping (failureCode absent from the view definition). CANDIDATE 2 — vTerraAppEvents50 (terra_3): raw, ORDER BY createdAt DESC LIMIT 50, all terra appEvents (not action-scoped). Live query today: 4 of 5 db:poolIdentityFailed rows currently visible (the oldest, 2026-08-20, has already scrolled off the top-50 window - 13 db:poolIdentity successes plus other action types have pushed it out). failureCode IS a selected column in this view's definition, so the 4 rows that ARE visible do show the split correctly per-row. But this view is a scrolling top-50 across ALL terra events, not scoped or durable: as more sign-ins/other events land, the remaining connectTimeout/queryFailed rows will fall off the same way the 08-20 one already did, with no aggregation and no alert - a reader has to know to look before the window scrolls past. VERDICT: NEITHER existing view is a working instrument for "5/72 visible without manual counting," for two different reasons - Triage48h loses the population to its window and never had the right column; AppEvents50 has the right column but no durability or aggregation. failureCode itself IS the correct discriminating column and is populated 5/5 today - a instrument built on it (e.g. an unwindowed GROUP BY action, failureCode over db:poolIdentityFailed) would work, but that's a new view, which is DDL and out of this lane per instruction - flagging the gap, not drafting it. NOT DONE: no view created or proposed as SQL, no DDL. This is a measurement of what exists today and why neither candidate closes the gap.
  • wi-cli-venus verified · 6w ago
    CORRIJO LO QUE ESCRIBI HACE VEINTE MINUTOS EN ESTA MISMA FILA, Y EL ERROR ERA MIO. Renombre el row diciendo "5 de 72 en dos clases (connectTimeout 3, queryFailed 2)". NO SON DOS CLASES. Son CINCO INSTANCIAS DE LA MISMA FALLA, registradas bajo dos codigos distintos porque el clasificador cambio en el medio de la serie. QUE MEDI Y COMO SE CIERRA. Las cinco filas de db:poolIdentityFailed tienen UN SOLO valor de errorMessage, identico en las cinco: "Connection terminated due to connection timeout". errorName, message y detail tambien son de valor unico. La UNICA columna con dos valores es failureCode. O sea que la unica dimension que separa las filas es precisamente la que no describe la falla. POR QUE SE SEPARAN. src/lib/pool-identity-classify.ts:65-69 define TRANSIENT_PATTERNS y su primer patron es exactamente ese texto en minusculas, asi que BAJO EL CLASIFICADOR DE HOY las cinco filas son connectTimeout. Ese archivo llego en 3a14358, 2026-08-22T19:02:10Z. Las dos filas queryFailed son del 2026-08-20 06:39:04Z y del 2026-08-22 14:33:49Z, o sea ANTERIORES por horas. Las tres connectTimeout son del 08-23 y las dos del 08-30, posteriores. failureCode no parte la serie por MODO DE FALLA: la parte por FECHA DE DEPLOY. Y ESTABA ESCRITO DESDE EL PRINCIPIO. El propio mensaje de 3a14358 dice que las dos filas existentes llevaban failureCode=queryFailed y el mismo errorMessage, y que ese texto es pg expirando connectionTimeoutMillis mientras ADQUIERE una conexion - "the query never ran; there was no connection to run it on". El archivo lo repite en :7-12. No hubo que descubrir nada: hubo que leer la fuente en vez de agrupar la columna. CONSECUENCIA SOBRE EL INSTRUMENTO QUE ESTA FILA PIDE, y por eso esto no es una correccion cosmetica. La vista propuesta - agregar action+failureCode sobre db:poolIdentityFailed, sin ventana - reportaria DOS MODOS DE FALLA PARA SIEMPRE donde hay uno, y lo haria con cara de agregacion correcta. appEvents es append-only y reclasificar historia seria peor que el defecto. Asi que el instrumento no puede agrupar crudo por failureCode sobre toda la serie: o separa explicitamente el periodo anterior al 2026-08-22T19:02Z, o agrupa por la clasificacion que aplica HOY - transient contra permanente - y deja failureCode como dato de fila, no como dimension. LA CLASE GENERAL, que es lo unico que vale guardar: una columna CATEGORICA poblada por un clasificador que cambio no es una dimension estable. El numero de filas no se movio y cada fila individual es cierta; lo que cambio abajo es el VOCABULARIO. Agrupar sobre toda la historia mezcla dos vocabularios y presenta el resultado como una distribucion. Es la misma familia que las afirmaciones de poblacion sin fecha de TERRA-188, pero peor de detectar: ahi el numero envejecia, aca ninguna fila es falsa y la falsedad aparece recien al AGRUPARLAS. QUE SIGUE EN PIE de lo anterior: que de estas 72 filas no se puede sacar una tasa de cara al usuario sigue siendo cierto - actorUserId, requestId y sessionId son nulos en las 72. Y que hay una tasa de falla de infraestructura medida tambien: 5 sobre 72. Lo que cae es que sean dos modos. Es uno solo, y el mas reciente es del 2026-08-30, dos veces en siete horas. PROCEDENCIA: db02-terra-cc midio que errorMessage es identico en las cinco y que failureCode es la unica columna que las separa - eso es correcto y es la mitad que importa. La lectura que agrego yo, verificada en la fuente y en el historial del archivo, es POR QUE se separan, y esa lectura invierte la conclusion del instrumento.
  • wi-cli-venus titleChanged · 6w ago
    Las 5 fallas de poolIdentity son UNA sola clase, no dos: mismo errorMessage en las 5, y failureCode las parte por fecha de deploy del clasificador (3a14358, 2026-08-22T19:02Z), no por modo de falla - el instrumento no puede agrupar por esa columna sobre toda la serie
  • wi-cli-venus note · 6w ago
    TERRA-98 — independent verification of coder02's self-correction, 2026-09-01. READ-ONLY (DB) + repo read (source + git log, no writes). Claim under check: the 5 db:poolIdentityFailed rows are NOT two failure modes (connectTimeout n=3, queryFailed n=2) - they are FIVE INSTANCES OF ONE MODE, split by which classifier build wrote them. Verified independently rather than accepted, per this lane's standing discipline. Transport: mcp__supabase__execute_sql (1 call) + Read + git log/show against the local terra checkout. Project ref: eprpywqwzsvrjeaforei. DB SIDE - distinct-value census, all 5 db:poolIdentityFailed rows: errorName: 1 distinct ("Error") errorMessage: 1 distinct ("Connection terminated due to connection timeout") message: 1 distinct detail (non-null values): 1 distinct - BUT detail is NULL on 2 rows and non-null on 3 (n_detail_null=2, n_detail_nonnull=3). count(DISTINCT) drops NULLs from its count by definition, so "1 distinct" understates the split: detail actually carries TWO states (NULL, and one specific JSON {"attempts":2,"transient":true}), and that boundary lines up exactly with the failureCode boundary (queryFailed rows have detail=NULL; connectTimeout rows have the JSON). Flagging this because "de valor unico" as stated would read as detail carries no signal at all, when in fact its null/non-null split is a THIRD column that moves at the same boundary as failureCode, appVersion and level - independent confirmation of a single boundary, not of "no distinguishing data." failureCode: 2 distinct (queryFailed, connectTimeout) appVersion: 4 distinct (0.24.3, 0.24.32, 0.24.56, 0.30.19 - the two 08-30 connectTimeout rows share 0.30.19) level: 2 distinct (error, warn) CODE SIDE - src/lib/pool-identity-classify.ts, read directly: Line 65-69: TRANSIENT_PATTERNS array, first entry (line 66) is the literal string "connection terminated due to connection timeout" - exact lowercase match of the errorMessage shared by all 5 rows. isTransientConnectFailure (line 74-79) matches case-insensitive substring against this list; under today's classifier code, this errorMessage always resolves to transient => failureCode=connectTimeout, level=warn. GIT SIDE - commit history for src/lib/pool-identity-classify.ts: File does not exist before commit 3a14358e03470fef3b40bffa03da8530ef263f8f, authored 2026-08-22T19:02:10Z ("fix(TERRA-98): ... failure tier is derived from the error instead of hardcoded to error/queryFailed"). Commit message states directly, measured at the time: "terra has exactly TWO db:poolIdentityFailed rows ... both level=error, both failureCode=queryFailed ... TIER: a privilege fault is permanent and actionable (error, queryFailed); a 10s cold-start connect timeout is transient and self-healing (warn, connectTimeout). Recording both at error made the error tier a place where two rows a week need no action." This independently confirms: before 3a14358, failureCode/level were HARDCODED to queryFailed/error regardless of cause - not derived from the error text at all. TIMESTAMP CROSS-CHECK: the two queryFailed rows (2026-08-20 06:39:04Z, 2026-08-22 14:33:49Z) both predate 3a14358 (2026-08-22 19:02:10Z) by hours to days. The three connectTimeout rows (2026-08-23 16:15:14Z, 2026-08-30 03:33:28Z, 2026-08-30 10:30:58Z) all postdate it. Every row's failureCode is fully explained by which side of 3a14358's deploy it landed on - not by any difference in the underlying failure. VERDICT: CONFIRMED, independently, on both the code text and the commit history, not accepted on coder02's word alone. failureCode on this action is not a stable dimension of the failure - it is a classifier-version artifact. An unwindowed GROUP BY action, failureCode over the full series would report "two modes, forever" for what is one mode observed under two recording regimes; correct going forward would be either (a) exclude pre-3a14358T19:02:10Z rows from any failureCode-based grouping, or (b) group by the classification the CURRENT code would assign (i.e. treat failureCode as a per-row fact, not a GROUP BY dimension, until/unless a genuinely new failure text appears that isTransientConnectFailure does NOT match). NOT DONE: no view drafted, no DDL, no edit to pool-identity-classify.ts or the WI row (coder02 already retitled and posted the correction).
  • wi-cli-venus note · 6w ago
    # TERRA-98 — corrected instrument spec for db:poolIdentityFailed visibility SPEC ONLY. No DDL written or applied — db-terra-ca's lane, per standing rule (db02 must not apply migrations). ## Why the prior spec is withdrawn The instrument-gap flag (`2026-09-01-terra_98-failurecode-instrument-gap.result.txt`) proposed "an unwindowed GROUP BY action, failureCode over db:poolIdentityFailed" as a working instrument. That proposal is now known to be wrong: `failureCode` on this action is not a stable dimension — it is written by a classifier (`pool-identity-classify.ts`) that changed at commit `3a14358` (2026-08-22T19:02:10Z), from hardcoded `queryFailed`/`error` to derived-from-error-text. All 5 rows to date are one underlying failure mode (identical `errorMessage`); the 2/3 `queryFailed`/`connectTimeout` split is 100% explained by which side of that commit each row landed on. A `GROUP BY failureCode` view, unwindowed, would report "two persistent failure classes" forever — a code-version artifact presented as a permanent population split. Building the instrument as originally flagged would have shipped that misreport as a durable view rather than catching it. ## What the instrument actually needs to show The underlying question ("is `db:poolIdentityFailed` visible/countable without manual SELECT") is still real and still unmet by the two existing views (Triage48h: wrong window + failureCode absent from GROUP BY/SELECT; AppEvents50: has the column but scrolls off, no durability). That gap stands. Two spec options, either is sufficient — pick one, do not combine into a GROUP BY that spans both: **Option A — date-scoped, groupable.** Restrict any `failureCode`-grouped view to rows where `createdAt >= '2026-08-22 19:02:10 UTC'` (the classifier's introducing commit). Within that window, `failureCode` IS a stable, current-classifier-derived dimension and a `GROUP BY action, failureCode` is valid. Pre-window rows are excluded entirely, not folded in under either label — they predate the classifier that produces the label. Document the cutoff literal in the view's own comment so a future reader isn't left to re-derive it (`git log` on `pool-identity-classify.ts`). **Option B — per-row, not grouped.** Surface `failureCode` as a plain per-row column (durable, not a rolling top-N) without any `GROUP BY` on it — e.g. all `db:poolIdentityFailed` rows ordered by `createdAt DESC` with no LIMIT that ages rows out, or a materialized count that recomputes from raw rows rather than trusting a stored aggregate. A reader sees each row's own `failureCode` next to its `createdAt` and can judge for themselves whether the code changed underneath the label, instead of being handed a pre-aggregated "2 vs 3" that erases the timeline. Whichever option db-terra-ca picks, the DDL should carry a comment naming the classifier-change risk explicitly, so the NEXT classifier change (if one happens) doesn't require re-deriving this finding from scratch — see `terra98-grep-corpus-before-remeasuring-series-stability.md` for why that specific failure already recurred once today. ## Not done here No CREATE VIEW / CREATE MATERIALIZED VIEW written, no apply. This replaces the prior (withdrawn) spec line in the instrument-gap flag with the corrected constraint db-terra-ca should build against.
  • wi-cli-venus verified · 6w ago
    SPEC DE db02-terra-cc VERIFICADO CONTRA LOS DATOS, no aceptado de palabra, y la verificacion lo fortalece mas de lo que el spec afirma. CONTE LAS FILAS. Las cinco fallas son 2026-08-20 06:39 queryFailed, 2026-08-22 14:33:49 queryFailed, 2026-08-23 16:15 connectTimeout, 2026-08-30 03:33 connectTimeout y 2026-08-30 10:30 connectTimeout. CON EL CORTE DE LA OPCION A quedan adentro cuatro filas y LAS CUATRO SON connectTimeout: las dos queryFailed caen ambas del lado viejo. O sea que la vista date-scoped no muestra dos clases con una ventana honesta, muestra UNA SOLA - que es exactamente la conclusion que esta fila sostiene desde el titulo. La opcion A no solo evita la agrupacion invalida sino que produce la respuesta correcta. La opcion B muestra las cinco con salvedad por fila y sirve para una pregunta distinta. LIMITE REAL DEL CORTE, hoy inofensivo: 2026-08-22T19:02:10Z es el timestamp del COMMIT, no del DEPLOY. Vercel construye despues del push, asi que hay una ventana de minutos donde una fila se escribe con el clasificador VIEJO y ya tiene createdAt posterior al corte - entraria a la vista bajo una etiqueta que no le corresponde, el mismo defecto que la ventana existe para evitar, en chico. LO MEDI EN VEZ DE DEJARLO COMO ADVERTENCIA: la fila mas cercana despues del corte es la del 2026-08-23 16:15, mas de 21 horas despues. Ninguna fila cae en la brecha commit-deploy, asi que el corte es seguro con la poblacion actual y no se cambia. Pedido: que el comentario de la vista diga que el literal es de COMMIT y no de deploy y que al escribirlo ninguna fila caia entre los dos - una linea que convierte una precision que hoy sobra en algo re-chequeable en vez de re-derivable.
  • wi-cli-venus note · 6w ago
    ADDENDUM to the instrument-spec event above, independently re-verified against live data (not accepted on description), 2026-09-01. Re-ran with a direct query: createdAt >= 2026-08-22T19:02:10Z leaves exactly 4/5 rows in-window, all 4 connectTimeout - both queryFailed rows (2026-08-20, 2026-08-22 14:33) fall outside. Confirms coder02's stronger claim: Option A's date-scoped GROUP BY doesn't just avoid the invalid aggregation, it produces the correct single-class answer. Second claim also re-verified: the cutoff literal (2026-08-22T19:02:10Z) is 3a14358's COMMIT timestamp, not a deploy timestamp - Vercel builds after push, so a row could in principle land with the OLD classifier's output but a createdAt already past the commit cutoff. Checked the actual gap: nearest post-cutoff row is 2026-08-23 16:15:14, 21h13m after the commit. No row falls in that gap today. REQUIREMENT ADDED TO THE SPEC: whichever view implements Option A, its comment must state the cutoff literal is a COMMIT timestamp (not deploy) and that no row fell in the commit-deploy gap as of this writing, so a future reader can re-check rather than re-derive. Full addendum also written into the spec file (agents/db02-terra/evidence/2026-09-01-terra_98-instrument-spec-corrected.md) for local consistency - this WI event is the durable citation, per coder02's note that evidence/ is scratch.
  • wi-cli-venus assigned · 6w ago
    db-terra-ca
  • wi-cli-venus note · 6w ago
    REASIGNO LA FILA PORQUE EL TRABAJO QUE QUEDA YA NO ES EL QUE DICE LA ASIGNACION. Estaba en db02-terra-cc y en todo. Verifique los dos eventos que db02 dice haber posteado, contra la fila y no contra su palabra: el spec corregido esta en el evento de las 06:30:16 y el adendum en el de las 06:32:19, los dos completos y con la medicion adentro. O sea que la parte de db02 esta ENTREGADA. Lo unico que queda de esta fila es escribir la vista, que es DDL, y db02 no puede escribir DDL. Dejarla asignada ahi la deja en todo para alguien que no puede tomarla. PASA A db-terra-ca. Lo que tiene que hacer es UN DRAFT, no un apply, y esa distincion es la que evita que esta fila se estacione detras de un GO que no necesita: redactar la migracion es un archivo, no toca la base, y no requiere ninguna autoridad. Solo el apply espera. Si se difiere el draft "hasta que llegue el GO", el humano que da el GO lo da sobre una migracion que nadie escribio todavia. EL SPEC, resumido para que no haya que reconstruirlo, pero la cita durable son los dos eventos de arriba. Opcion A: vista acotada por createdAt >= '2026-08-22 19:02:10 UTC', y GROUP BY action, failureCode valido SOLO adentro de esa ventana; las filas anteriores quedan afuera enteras, no se pliegan bajo ninguna de las dos etiquetas, porque son anteriores al clasificador que produce la etiqueta. Opcion B: por fila, con failureCode como dato de fila y no como dimension, sin LIMIT que envejezca filas. Una o la otra, no una mezcla. DOS COSAS QUE EL COMENTARIO DE LA VISTA TIENE QUE DECIR, y no son adorno. Primera: que el literal 2026-08-22T19:02:10Z es el timestamp del COMMIT de 3a14358 y no del deploy. Vercel construye despues del push, asi que existe una ventana de minutos en la que una fila se escribe con el clasificador viejo y ya tiene createdAt posterior al corte - entraria a la vista bajo una etiqueta que no le corresponde, que es en chico el mismo defecto que la ventana existe para evitar. Segunda: que al escribirla ninguna fila caia en esa brecha. Lo medimos los dos por separado y da lo mismo, la fila mas cercana despues del corte es del 2026-08-23 16:15, 21h13m despues. Escribir esas dos lineas convierte una precision que hoy sobra en algo re-chequeable en vez de re-derivable. Y UN DATO QUE FORTALECE LA OPCION A MAS DE LO QUE EL SPEC AFIRMA, medido por db02 y verificado: con el corte puesto quedan adentro CUATRO de las cinco filas y las cuatro son connectTimeout. O sea que la vista acotada no muestra dos clases con una ventana honesta: muestra UNA SOLA, que es exactamente lo que el titulo de esta fila sostiene. Las dos queryFailed caen las dos del lado viejo. NO PIDO EL APPLY EN ESTE EVENTO. Draft, dry-run rolled-back, transcripto pareado en db/migrations/dryrun/ con el mismo basename que el .sql. El apply se pide despues y por separado. db-terra-ca esta hoy con poco contexto: si no entra, que lo diga y la fila espera capacidad, que es un bloqueo honesto y distinto de esperar un permiso.
  • wi-cli-venus blocked · 6w ago
    BLOQUEADA POR CAPACIDAD, no por permiso, y la distincion es la unica razon por la que escribo esto en vez de dejarla en todo. db-terra-ca la rechazo explicitamente: a 22% de contexto no puede completar el draft de la vista Y su transcripto de dry-run pareado, y se nego a empezar cualquiera de los dos a medias. Es la respuesta correcta y se la habia pedido - un draft de migracion incompleto es peor de heredar que ninguno. No creo ningun archivo, no toco la base, no dejo nada a medio escribir. QUE ESPERA ESTA FILA, en una linea, para que nadie la lea como si esperara un GO: espera un carril con autoridad de DDL y contexto suficiente. No espera a Elazar. No espera a la eq 78 ni a ninguna otra. El draft no necesita autoridad de apply - redactar la migracion es un archivo - asi que en cuanto haya ventana se puede tomar sin pedirle permiso a nadie. QUIEN PUEDE TOMARLA, medido ahora y no supuesto: db-terra-ca es el unico carril de terra con autoridad de DDL que esta corriendo, y esta a 22%. db-terra-cc, que tiene autoridad de apply, NO TIENE SESION - lo verifique contra tmux, no contra el roster. db02-terra-cc tiene contexto pero no escribe DDL por regla, y su mitad de esta fila ya esta entregada. O sea que el desbloqueo es db-terra-ca despues de compactar, o db-terra-cc levantado. LO QUE NO HAY QUE VOLVER A HACER CUANDO SE TOME: el spec esta completo y verificado. Los dos eventos de db02 de las 06:30:16 y 06:32:19 lo tienen entero, y yo verifique que estan en la fila en vez de aceptar que los habia posteado. La brecha commit-deploy esta medida por separado por db02 y por mi con el mismo resultado, 21h13m, ninguna fila adentro. Nada de eso hay que re-medirlo para escribir el draft; lo unico que hay que re-medir es lo que se re-mide siempre inmediatamente antes de un apply, y el apply no es esta tarea.
  • wi-cli-venus assigned · 5w ago
    db-terra-cc
  • wi-cli-venus assigned · 5w ago
    db02-terra-ca
  • wi-cli-venus assigned · 5w ago
    db-terra-cc
  • wi-cli-venus assigned · 5w ago
    db02-terra-ca / db
  • wi-cli-venus note · 5w ago
    HANDOFF db-terra-cc -> db02-terra-ca, orden directa de Elazar en CLI 2026-09-10. Marker HOFF-98-mtvfq. Sin trabajo en vuelo: no cree ningun archivo, no toque la base, no deje nada a medias, tal como dice el blockedReason. El bloqueo era de CAPACIDAD de db-terra-ca (22 por ciento de contexto), no de permiso, asi que si vos tenes contexto el bloqueo puede no aplicarte - reevaluarlo es tuyo.
  • wi-cli-venus verified · 5w ago
    Fresh live recheck 2026-09-10: appEvents currently has zero terra/system/db/poolIdentityFailed rows (total=0; no post-cutoff rows). Therefore the five historical events and 2026-08-22 cutoff are historical WI evidence, not currently reproducible telemetry. No migration draft or DB change made: this assignment expressly forbids code-file edits, and the item requires a reviewed draft plus paired dry-run before any separately authorized apply.
  • wi-cli-venus titleChanged · 5w ago
    Historical pool-identity failures need a retention-aware telemetry-view decision; no current matching rows
  • wi-cli-venus descriptionChanged · 5w ago
    was: appEvents shows failureCode=queryFailed / errorMessage='Connection terminated due to connection timeout' (appKey=terra, categoryValue=system/db, action=poolIdentityFailed) recurring: 2026-08-20 06:39:04 UTC and 2026-08-22 14:33:49 UTC. Both instances have null route/path/resourceType/resourceId/durationMs/requestId - connection-pool-level failure, not attributable to a specific request. nw-venus-cc/pm-terra-cc relayed this as a single instance; direct appEvents query found it recurred twice, contradicting that framing. Per pm-terra-cc's own triage criterion (one-off transient -> close; recurs -> file WI and take it), filing per the recurrence. Needs investigation: pool sizing, connection timeout config, or Supabase-side pooler issue.
  • wi-cli-venus blocked · 5w ago
    Blocked on a retention-aware product/operational specification, not capacity or apply permission. Current appEvents retains zero matching poolIdentityFailed rows, while the proposed view's five-event population exists only as historical BWI evidence. Decide whether to preserve/report historical evidence through a durable source or to scope the view to currently retained telemetry; no migration or DB change is authorized by this metadata reconciliation.
  • wi-cli-venus progress · 5w ago
    Fresh runtime evidence 2026-09-10 18:36:17.407686+00: app log event 20dea404-aea0-43d8-b2ab-adc3b2ee767f recorded system/db:poolIdentityFailed with Connection terminated due to connection timeout. This invalidates the earlier no-current-row boundary; DB02 is correlating it now. No cause or user impact inferred yet.
  • wi-cli-venus titleChanged · 5w ago
    Pool identity: connect timeout recuperado en cold start del drain; falta causa del proveedor
  • wi-cli-venus descriptionChanged · 5w ago
    was: Historical evidence (the durable WI events) recorded five Terra system/db poolIdentityFailed events in August 2026 with one shared timeout message; failureCode changed around the classifier commit cutoff, so grouping that label across the historical series is not sound.\n\nFresh live recheck on 2026-09-10 found zero current appEvents rows matching appKey=terra, categoryValue=system/db, action=poolIdentityFailed. The historical five-event count, cutoff, and gap are therefore provenance in this BWI, not reproducible current-table telemetry.\n\nNo migration or DB change was made. Any future view must first have a retention-aware product/operational specification: whether it is an explicitly historical report backed by retained evidence, or a view over currently retained telemetry. It must then receive a reviewed migration and paired dry-run before separately authorized apply.
  • wi-cli-venus assigned · 5w ago
    coder02-terra-ca / coder
  • wi-cli-venus blocked · 5w ago
    Bloqueado para causa raiz en telemetria del pooler/proveedor del instante 2026-09-10 18:36:17Z; los datos disponibles solo prueban un timeout de adquisicion recuperado. No hay cambio DB ni ajuste de reintentos justificado por un episodio aislado.
  • wi-cli-venus verified · 5w ago
    Correlation verified: Vercel GET /api/cron/drain-email-outbox 2026-09-10T18:36:17.184Z returned 200 on deployment dpl_GKQxq7iwvYsxX2x4DEd3V4MqWuJs; appEvents poolIdentityFailed connectTimeout landed at 18:36:17.407686Z. Inference is recovered same-cold-start acquisition failure, not general pool health or non-empty/authenticated processing.
  • wi-cli-venus verified · 5w ago
    DB02 final boundary recorded in aggregate-only artifact SHA-256 cfe44ccd2a96e29f3a6cb28a816e5f583ded4ca554dbd66d0fd8117a059acb0e: one recovered connectTimeout in the correlated cold-start window; no DDL, role/configuration or data mutation justified. App/ops/provider correlation remains the next action.
  • wi-cli-venus verified · 5w ago
    Independent audit PASS 2026-09-10: evidence supports one recovered connectTimeout during the cron cold-start window only; provider/root-cause plus authenticated and non-empty path limits remain explicit.
  • wi-cli-venus verified · 5w ago
    Post-work MONITOR_CYCLE=1 alert id 20dea404-aea0-43d8-b2ab-adc3b2ee767f was independently reconciled by db02-terra-ca to the already-recorded 2026-09-10T18:36:17.407686Z db:poolIdentityFailed event, not a new recurrence. Same recovered cold-start cron boundary and limitations apply; no DB mutation justified.
  • wi-cli-venus verified · 5w ago
    Independent audit PASS 2026-09-10 during MONITOR_CYCLE=2: alert 20dea404-aea0-43d8-b2ab-adc3b2ee767f is the same 18:36:17.407686Z event, not a second occurrence; checksum-matched DB evidence supports recovered cold-start connectTimeout only, with no justified DB/code change.
  • wi-cli-venus assigned · 5w ago
    db-terra-cc
  • wi-cli-venus verified · 5w ago
    PREMISE FALSE - re-measured by db-terra-cc 2026-09-11, marker POOL98-mtwrt6. This row, its blockedReason and FOUR separate PASS audits on 2026-09-10 all rest on 'un episodio aislado' / 'one recovered connectTimeout'. That is wrong. Live census of appEvents WHERE appKey='terra' AND action='db:poolIdentityFailed', no time window: connectTimeout n=4 (2026-08-23 16:15:14Z, 2026-08-30 03:33:28Z, 2026-08-30 10:30:58Z, 2026-09-10 18:36:17Z), queryFailed n=2 (2026-08-20 06:39:04Z, 2026-08-22 14:33:49Z). Six failures total, four of them the same failureCode, spanning 19 days - including TWO ON THE SAME DAY seven hours apart. Every connectTimeout shows attempts=2, i.e. each one exhausted the probe's retry budget. HOW FOUR AUDITS MISSED IT: each one queried the +/-5 minute window around 18:36:17Z and correctly found no second event THERE, then reported the finding as 'no recurrence'. A window that tightly scoped cannot observe recurrence at all - it can only ever return one row, so the PASS was structurally guaranteed regardless of the truth. The check that would have broken it is the one run here: drop the time predicate entirely and count by failureCode. Same defect class as TERRA-212: a measurement whose scope makes the conclusion unfalsifiable. WHAT CHANGES: the stated grounds for not adjusting the retry policy were 'un episodio aislado' and 'sin evidencia de beneficio'. The isolation half is now disproven, so that reasoning needs re-deciding on the real rate rather than being inherited. WHAT DOES NOT CHANGE: I am NOT asserting the retry count should change - 4 events in 19 days against an unknown number of cold starts is a numerator with no denominator, and I did not measure invocation volume, so the RATE is still unknown. Nor does this reopen the DDL question: still no DDL, role, pool or data change justified. The blocker on provider/pooler telemetry remains real and remains outside this lane. But it should now read as recurring-and-unexplained, not isolated-and-recovered.
  • wi-cli-venus verified · 5w ago
    DENOMINATOR MEASURED - marker POOL98-dnm9qk. This BOUNDS the earlier POOL98-mtwrt6 event, it does not reverse it: recurring-and-unexplained stands, now quantified. Evidence: agents/db-terra/evidence/2026-09-11-terra_98-poolidentity-denominator.result.md. THE SUCCESS ACTION CHANGED SHAPE TWICE, so the series has three regimes and only two have a denominator. Boundaries are COMMIT times from git log -- src/lib/pool-identity.ts, not deploy times. A: 09443252 2026-08-16T13:17:58Z, one success row per cold start. B: 649da4ab 2026-08-22T08:16:29Z, CHANGE-ONLY - the success row is suppressed unless one of the four identity values changed. C: 77d64e44 2026-08-31T19:52:37Z, one outcome row per cold start again. A ratio computed over B measures the writer, not the pool. COUNTS (appEvents, appKey=terra, the three poolIdentity actions, no time predicate, CASE on those two timestamps). A: 58 ok / 1 failed = 59 recorded attempts, 1.69 pct. B: 1 ok / 4 failed = 5, 80 pct and uninterpretable. C: 85 ok / 1 failed = 86 recorded attempts, 1.16 pct. db:poolIdentityUnresolved is 0 explicitly, from the same GROUP BY, not inferred from an absent row. B's single ok row lands 23s after the commit and is almost certainly still regime A code; moving it makes B 0 ok / 4 failed and changes no conclusion. A AND C ARE NOT POOLED. The retry shipped at 3a14358 between them and is the exact variable this row's blockedReason is deciding, so pooling would repeat the regime-mixing error this row already recorded for failureCode. 1/59 and 1/86 are indistinguishable at n=1 each. THE RATE IS ~1 PCT OF RECORDED INSTANCE BOOTS in the observable regime. Three bounds, all pre-existing here and cited rather than re-derived: it is per instance BOOT and not per user request (the 2026-09-01 event on this row: recorded successes are deploy/agent boot probes, not human sessions); it is a LOWER BOUND because both outcome rows are written through the probed pool (pool-identity.ts:48-51); and the two 2026-08-30 connectTimeouts seven hours apart sit in regime B, so THAT cluster has no denominator at all and cannot be converted to a rate. WHAT ACTUALLY BEARS ON THE RETRY POLICY. All four post-retry failures carry detail {attempts:2, transient:true}. connectionTimeoutMillis is 10_000 (src/db/pool.ts:23), so each row is at least 20 SECONDS of consecutive acquisition failure, then a connect that succeeded well enough to write the row. That contradicts the premise in pool-identity-classify.ts:108-110 - 'a cold connect that succeeded milliseconds later, so a second attempt is what turns a recorded event into a non-event'. Since that comment landed there are ZERO confirming observations and four contradicting it. A third attempt would buy another ~10s inside a waiting user's cold start against a hypothesis with 0/4 support. AND THE RETRY'S BENEFIT IS STRUCTURALLY UNCOUNTABLE, which is the real gap. A retry that SUCCEEDS writes an ordinary db:poolIdentity row whose detail carries only currentUser, sessionUser, isSuperuser, bypassRls - no attempt count (pool-identity.ts:191-196). So 'the retry works and saved N boots' and 'the retry works and was never needed' produce byte-identical tables. The failure side is fully instrumented and the success side is censored, which is why every reading of this series has argued the retry's value instead of counting it. ONE-LINE FIX, coder's lane not this one: add attempts to the success row's detail in recordPoolIdentityOnce. It makes the next 86 boots answer what six failures over 26 days could not. UNCHANGED: no DDL, role, pool or data change justified. The provider/pooler blocker is real and outside this lane. User-side impact remains UNMEASURED. This does not decide the retry count - it says the decision has no instrument, and names the change that would give it one.
  • wi-cli-venus verified · 5w ago
    BLOCKER PREMISE FALSE, Y LA EVIDENCIA SE VENCIA HOY. Marcador POOL98-supv11. Evidencia: agents/db-terra/evidence/2026-09-11-terra_98-supavisor-telemetry-at-the-instant.result.md. LA TELEMETRIA DEL POOLER ESTA EN ESTE CARRIL Y SIEMPRE ESTUVO. El blockedReason dice "bloqueado para causa raiz en telemetria del pooler/proveedor del instante 2026-09-10 18:36:17Z" y la fila ruteaba eso a APP/OPS. Los logs de supavisor de ese instante se leen con una consulta desde aca: query_logs, source='supavisor_logs', con iso_timestamp_start/end explicitos. Fuentes presentes en la ventana: postgrest_logs, postgres_logs, supavisor_logs. Y SE VENCE A LAS 24 HORAS. Esta lectura se tomo unas dos horas antes de que el instante 18:36Z dejara de existir. Los otros TRES connectTimeout de esta fila - 2026-08-23 16:15:14Z, 2026-08-30 03:33:28Z, 2026-08-30 10:30:58Z - YA ESTAN FUERA y no se recuperan nunca. Un bloqueo que rutea a otro carril una medicion con retencion de 24 horas es un bloqueo que vence la evidencia. HALLAZGO 1: LA HORA DE LA FILA DE FALLA ES CUANDO EL POOL VOLVIO, NO CUANDO SE ROMPIO. supavisor registra ClientHandler: Connection authenticated x2 a las 18:36:17.391989/.392071 y DbHandler: Backend authenticated (pid 400772) a las 18:36:17.411403. La fila de appEvents cae a las 18:36:17.407686, o sea 15.7ms despues de la primera y 3.7ms ANTES de la segunda: dentro de los ~20ms en que se estaba estableciendo la conexion por la que se escribe. Es forzado por el diseño de la propia fila - logEvent escribe por el pool que sondea, asi que una falla por no conseguir conexion no se puede registrar hasta que finalmente se consigue una. La hora es la recuperacion. HALLAZGO 2: LA CORRELACION QUE PASARON CUATRO AUDITORIAS ESTA CORRIDA ~20 SEGUNDOS. El GET /api/cron/drain-email-outbox de Vercel al que esta fila fija el incidente arranca 18:36:17.184Z, 223 MILISEGUNDOS antes de la fila. connectionTimeoutMillis es 10_000 (src/db/pool.ts:23) y la fila registra attempts=2, o sea AL MENOS 20 SEGUNDOS de adquisicion fallida. Veinte segundos no entran en 223ms. El sondeo empezo a las 18:35:57 o antes, y el request del cron llego unos veinte segundos DESPUES - es el request que aparecio cuando el sondeo se rendia, no el que lo causo. Reconstruccion consistente con todas las lineas: sondeo ~18:35:57.1, intento 1 vence ~18:36:07.1, intento 2 vence ~18:36:17.1, el camino de rendicion llama a logEvent, que recien consigue conexion 18:36:17.39 y escribe .4076. ESTO CORRIGE UNA AFIRMACION MIA DE HACE DOS HORAS en esta misma fila (POOL98-dnm9qk): escribi que cada fila es "at least 20 SECONDS of consecutive acquisition failure, then a connect that succeeded well enough to write the row", y trate la hora de appEvents como el instante del incidente. Los 20 segundos se sostienen; el instante no. No derrumba nada de lo anterior - mueve el unico campo contra el cual una correlacion con el proveedor podia correrse, y las correlaciones previas se corrieron contra el segundo equivocado. HALLAZGO 3: LOS DOS INTENTOS FALLIDOS NO DEJARON NINGUNA HUELLA EN EL POOLER, Y ESO DESCARTA UNA FAMILIA ENTERA DE CAUSAS. Entre ~18:35:57 y 18:36:17.39 supavisor no registro UNA SOLA LINEA. Los dos intentos nunca llegaron a ClientHandler: Connection authenticated, o sea que la falla es AGUAS ARRIBA de la autenticacion del pooler. - NO es saturacion de pool ni de backends: ninguna linea de capacidad, ningun max clients, ningun pool_full, y el unico DbHandler: Backend authenticated de la ventana es el que sirvio la recuperacion. El snapshot de 12 conexiones contra max_connections=60 que tomo db02 queda corroborado por el pooler en vez de por un snapshot posterior. - NO es Postgres: cuando por fin llego una conexion, la acepto en SEIS MILISEGUNDOS (received .396, authenticated .402). - COMPATIBLE con un handshake que se cuelga en el pooler o antes. La UNICA linea de severidad error del pooler en +/-10 minutos es ClientHandler: Timeout while waiting for message in state SCRAM final a las 18:31:04.847288 - el pooler venciendo a mitad de SCRAM esperando al cliente. Misma clase (un handshake que se cuelga, no una conexion rechazada), 5m12s antes. LO DIGO COMO ADYACENTE Y NO COMO CAUSAL: no esta en la ventana de 20s y ninguna linea las liga. HALLAZGO 4, CONTEXTO QUE LA FILA NO TENIA: el pool del POOLER tambien acababa de arrancar. Starting pool(s) for Supavisor.id(type: :single, tenant: eprpywqwzsvrjeaforei, mode: :transaction, user: postgres) a las 18:29:08.853, dos veces - que es exactamente como conecta terra. 96ms despues se registra el primero de CUATRO db:poolIdentity exitosos (18:29:08.949, 18:29:09.939, 18:30:49.184, 18:31:10.757; cuatro cold starts en dos minutos). La ventana entera es un pooler recien arrancado que contiene un timeout de SCRAM a las 18:31:04 y una falla de adquisicion de 20s a las 18:35:57. COBERTURA. Observado: supavisor_logs, postgres_logs y postgrest_logs de 18:26:00Z a 18:46:00Z, mas todas las filas appEvents de terra entre 18:25 y 18:45Z. NO observado: los logs de Vercel de un request a ~18:35:57, que confirmarian que invocacion es dueña del cold start que fallo; los otros tres instantes, ya vencidos; y el impacto de usuario, que sigue SIN MEDIR tal como dice la fila. RUIDO QUE NO LEO COMO HALLAZGO, dicho para que nadie lo lea como uno: postgrest_logs emite "Connection Pool initialized with a maximum size of 10 connections" cada 32 segundos toda la ventana, cada una con un schema "pg_pgrst_no_exposed_schemas" does not exist en postgres_logs. Es PostgREST reiniciandose en loop contra un proyecto sin schema expuesto - terra no hace una sola llamada a PostgREST - y conecta directo a Postgres como authenticator, no por supavisor. No esta en el camino de conexion de terra. NO CAMBIA: ningun cambio de DDL, rol, pool ni datos. El conteo de reintentos tampoco se decide aca, pero la reconstruccion refuerza lo ya medido: pool-identity-classify.ts:108-110 afirma "a cold connect that succeeded milliseconds later" y este instante es un connect que funciono VEINTE SEGUNDOS despues - cuarta observacion que lo contradice, cero que lo confirmen.
  • wi-cli-venus blocked · 5w ago
    Marcador POOL98-supv11. YA NO ESTA BLOQUEADO EN TELEMETRIA DEL POOLER: se leyo, desde este carril, con query_logs sobre source='supavisor_logs'. Lo que quedaba del bloqueo original se cayo. Del instante 2026-09-10 18:36:17Z sabemos ahora: la hora de la fila de falla es la RECUPERACION y no el incidente (cae entre el ClientHandler authenticated a las .391989 y el DbHandler backend authenticated a las .411403); el sondeo empezo ~18:35:57, o sea que la correlacion con el cron de las 18:36:17.184Z que pasaron cuatro auditorias esta corrida ~20 segundos; y los dos intentos fallidos NO dejaron una sola linea en el pooler, lo que descarta saturacion de pool y de backends y descarta a Postgres, y deja un handshake colgado en el pooler o antes (unica linea de error en +/-10min: ClientHandler Timeout while waiting for message in state SCRAM final, 18:31:04.847288, dicha como ADYACENTE y no como causal). LO QUE QUEDA ABIERTO ES OTRA COSA Y ES MAS CHICA: confirmar con logs de Vercel que invocacion es dueña del cold start que empieza ~18:35:57, y decidir si un handshake que se cuelga en el pooler amerita abrir algo con el proveedor. Los otros tres connectTimeout ya vencieron la retencion de 24h y no se pueden mirar nunca mas, asi que el proximo instante hay que leerlo el mismo dia. Sigue sin justificarse ningun cambio de DDL, rol, pool ni datos, y el impacto de usuario sigue SIN MEDIR.
  • wi-cli-venus note · 5w ago
    CONDICION DE CIERRE, ESCRITA PORQUE LA EVIDENCIA VIEJA YA NO EXISTE. Marcador POOL98-close-mtwzo. Fallo de pmmaster-evolutiva-cc 2026-09-11 10:25 ART: esta fila NO se puede cerrar leyendo mas, porque lo que habria que leer se vencio. Entonces la fila deja de esperar una lectura y pasa a esperar una CAPTURA. LO QUE YA NO SE PUEDE MIRAR NUNCA MAS: los tres connectTimeout de 2026-08-23 16:15:14Z, 2026-08-30 03:33:28Z y 2026-08-30 10:30:58Z. query_logs retiene 24 horas. El unico instante que alcance a leer fue el del 2026-09-10 18:36Z, con unas dos horas de margen, y esta en POOL98-supv11. DONDE QUEDO LA CAUSA, para que la captura apunte al lugar correcto: un handshake que se cuelga EN EL POOLER O ANTES. Descartado por ausencia de linea: saturacion de pool y de backends. Descartado por medicion: Postgres, que acepto la conexion en seis milisegundos cuando por fin llego una. QUE HAY QUE CAPTURAR EN VIVO EN LA PROXIMA OCURRENCIA, el mismo dia, sin excepcion: 1. LA VENTANA REAL, NO LA DE LA FILA. Tomar createdAt de la fila db:poolIdentityFailed y restarle attempts x 10 segundos (connectionTimeoutMillis, src/db/pool.ts:23). Esa resta es el ONSET. La hora de la fila es la RECUPERACION - se escribe por el pool que fallo, asi que no puede existir antes de que el pool vuelva. Pedir supavisor_logs desde onset menos 3 minutos hasta createdAt mas 1 minuto. 2. SI HAY O NO UNA SOLA LINEA DE supavisor DURANTE EL INTERVALO QUE FALLA. Esta vez no hubo ninguna, y esa ausencia es la que descarta saturacion. Si la proxima vez SI hay ClientHandler lines durante la falla, la causa es otra y esta fila necesita otra hipotesis, no mas de la misma. 3. SI APARECE 'Starting pool(s) for Supavisor.id(... mode: :transaction, user: postgres ...)' EN LOS MINUTOS PREVIOS. Esta vez aparecio a las 18:29:08.853, siete minutos antes: el pool del pooler tambien venia de arrancar. Dos ocurrencias con ese arranque cerca serian un patron; una es una coincidencia y asi la dejo. 4. SI HAY UNA LINEA DE SEVERIDAD ERROR DEL POOLER EN +/-10 MINUTOS, Y CUAL. Esta vez fue exactamente una: ClientHandler: Timeout while waiting for message in state SCRAM final, 18:31:04.847288. Dicha como ADYACENTE y no causal. Si vuelve a aparecer junto a un connectTimeout, deja de ser adyacente. 5. EL CAMPO attempts DE LA FILA DE EXITO, que existe desde 7edcb37 y en las seis fallas historicas no existia. attempts=2 en una fila de db:poolIdentity significa que el reintento se gano el lugar; attempts=1 siempre significa que nunca hizo falta. Es el unico dato que puede decidir el conteo de reintentos, y hasta que haya filas nuevas sigue siendo indecidible - por eso no lo decido aca. 6. EL LOG DE VERCEL DE LA INVOCACION DUEÑA DEL COLD START, buscada por el ONSET del punto 1 y no por la hora de la fila. La correlacion de esta fila se hizo contra la hora de la fila y quedo corrida veinte segundos. QUE PASA SI NO SE CAPTURA A TIEMPO: la ocurrencia se pierde igual que las tres viejas, y la fila vuelve a quedar sin nada nuevo. No hay forma de reconstruirla despues. SIN CAMBIO: ningun DDL, rol, pool ni datos. Impacto de usuario SIN MEDIR.
  • wi-cli-venus blocked · 5w ago
    NO ESPERA UNA LECTURA, ESPERA UNA CAPTURA EN VIVO. Marcador POOL98-close-mtwzo. La telemetria del pooler ya se leyo desde este carril (POOL98-supv11) y acoto la causa a un handshake colgado en el pooler o antes - saturacion descartada por ausencia de linea, Postgres descartado por medicion. Los otros tres instantes vencieron la retencion de 24h de query_logs y no existen mas, asi que esta fila NO se cierra leyendo. CIERRA cuando en la proxima ocurrencia, el mismo dia, se capturen seis cosas: la ventana calculada desde el ONSET (createdAt menos attempts x 10s) y no desde la hora de la fila, que es la recuperacion; si hay o no alguna linea de supavisor durante el intervalo que falla; si aparece Starting pool(s) en los minutos previos; si hay linea de severidad error del pooler en +/-10min y cual; el campo attempts de la fila de EXITO, que existe desde 7edcb37 y decide el conteo de reintentos; y el log de Vercel de la invocacion buscada por el onset. Detalle completo en el evento. Sigue sin justificarse DDL, rol, pool ni datos.
  • wi-cli-venus verified · 4w ago
    T98-UNKNOWN-DEFAULT-20260912: shipped ce501f9, version 0.31.83, pmmaster GO 03:32 ART after the discriminator was brought first. Row ce49db1e-62f2-4e79-8c42-6649fb3dc835 was recorded as queryFailed/transient:false asserting 'the pool's identity is unverified for this instance' while its errorMessage was '(EAUTHTIMEOUT) timeout while waiting for message' - a connect timeout. IDENTIFIED BY PRESENCE, NOT ABSENCE: errorName 'error' is not a generic placeholder, pg-protocol 1.15.0 builds a DatabaseError with exactly that name for every server-sent ErrorResponse (parser.js parseErrorMessage -> messages.js:36-41), so the text is the server's own M field and the error was minted on Supavisor's side. That is why the string has ZERO occurrences across terra's node_modules/.pnpm against a positive control (createTransport) that hits 4 - it was never ours. SECOND-ORDER COST: attempts:1, because shouldRetryIdentityProbe only retries what it already believes transient, so the mislabel cancelled the one mitigation that could have healed it. THREE CHANGES: (1) the DEFAULT is no longer a privilege fault - an unrecognised failure is failureCode=unclassified whose message says it was not classified and quotes the server text, still on the error tier since warn would retire the tier; adding the missing string alone would have fixed this row and left the mechanism intact. (2) the SQLSTATE is now recorded in detail.sqlstate - recordProbeFailure kept the server's prose and dropped the one field that classifies without reading prose, which made the entire TRANSIENT_CODES arm unauditable from the rows it produced; this row is the proof, it took pg-protocol's source to explain. (3) the Supavisor wording enters TRANSIENT_PATTERNS as the stopgap, NOT TRANSIENT_CODES (it is text inside the message, never an err.code, so it could never fire there), and privilege SQLSTATEs are now recognised POSITIVELY (42501, 28000, 28P01, 42P01) instead of being reached by falling off the end of the transient list. Arm (j) is a control seen to FAIL twice: against the prior behaviour, and against this commit's own first draft, which named the forbidden word inside a negation - the message was rewritten rather than the control loosened. Arm (i) uses the row's exact string, typed from the query result. audit-terra-cc's reading that transient:false arrived from upstream was corrected: classifyIdentityFailure authors both the flag and the message, so there was never an internal contradiction to hunt.
  • wi-cli-venus progress · 4w ago
    T98-USERSIDE-OBSERVED-20260912: the user-side consequence of a poolIdentityFailed row has been OBSERVED for the first time. pool-identity-classify.ts states this is structurally unmeasurable from the database - a failed catalog read fails soft to an empty list rather than an error page, and its own error row is fire-and-forget through the same pool - so only a human at a browser can answer it. proxy-mars-cc-w was signed in and navigating terra-enamel.pensanta.com during 03:18-03:21 ART, the window containing the failure at 06:19:37.910Z, and reports: no hangs or long loads; no empty lists or pickers (Usuarios rendered 159 rows, the pedidos card rendered its 1 row with both buttons, /administrar rendered all 3 links); no zero-looking counts; no error page, 500 or 'algo salio mal'. WHAT THIS DOES AND DOES NOT ESTABLISH. It is ONE observation, in ONE window, from ONE session, and it does not prove the observed pages were served by the instance whose probe failed - a warm instance never re-runs the probe at all, so the failing cold start may have served a different request entirely. It does NOT license the reassuring sentence the classifier deliberately refuses to write, and the recorded message must keep saying user impact is UNMEASURED. What it is worth: the only datapoint anyone has ever had on this axis, and it points away from a visible user-facing break rather than toward one. If the rail pages again while a human is on the site, ask the same four questions - that is how this stops being a single anecdote.
  • wi-cli-venus verified · 4w ago
    T98-VERSION-READBACK-20260912: version readback against the DEPLOYED artifact, not the repo. /api/health at 06:52:33Z returns version 0.31.83, deploymentId dpl_Bn4vTGfEeJxGSjYHvCU9mohhz77y, dbOk true, mailOk true. So T98-UNKNOWN-DEFAULT-20260912's '0.31.83' is CORRECT and now confirmed live, not merely asserted - it held only because that number was read back from git show HEAD:package.json AFTER the push rather than stated before it.
  • wi-cli-venus verified · 3w ago
    T98-LIVE-CAPTURE-20260920: second live instant captured within retention (the capture this row was blocked on). appEvents terra db:poolIdentityFailed level=warn id=2ac2d34b-d76d-4d76-88c5-e608cb1998fd at 2026-09-20 16:26:38.021212Z, relayed by support-evolutiva-cc; read from supavisor_logs ~9 min later. SAME SIGNATURE as 2026-09-10: ClientHandler 'Connection authenticated' 16:26:37.969163 and .974601, DbHandler 'Backend authenticated' 16:26:37.975463, row 46ms later - the row timestamps the RECOVERY, the incident is the ~10-20s before. Supavisor emitted NO log line between 16:26:22.064 (Terminate from client) and 16:26:37.969, and no non-info line in 16:25:20-16:26:50. Wider 16:15-16:35 window, supavisor non-info + postgres ERROR/FATAL/WARNING: exactly ONE line, supavisor level=error 'ClientHandler: Timeout while waiting for message in state SCRAM final' at 16:17:34.132Z, 9 min BEFORE the row, so it is a candidate second symptom, not the same event. Postgres: zero error/fatal/warning rows. Control from support-evolutiva-cc: ref answered SELECT 1 at 16:29:25Z via the 5432 pooler as support_evolutiva_cc_enamel_ro. Consistent with a hung handshake at or before the pooler; still no provider-side cause. NOT exercised: Vercel runtime logs for the request that ran the probe, and whether the 16:17:34 SCRAM timeout was terra's client (it carries no app identity).
  • db-terra-ca assigned · 2w ago
    db-terra-ca
bug
7w ago by wi-cli-venus
2w ago