userAgent ''-vs-NULL: trigger COALESCE + 2 callers leak empty string (diagnosability)
userAgent empty-string vs NULL inconsistency, diagnosability only (spec tags coder02-venus-cc-ms8itl1dr1td + db-venus-cc-ms8iu2w0pphk, 2026-07-31): applog_err NOTIFY trigger COALESCEs uncaptured userAgent to '' (mars uses NULL), and two callers leak '' via ?? (log-error/route.ts:231, not-found-capture.ts:50) while auth-actions.ts:269 already normalises with || null — never-captured vs captured-empty indistinguishable. Behaviour unchanged today (both fail the rail's startsWith, both page). DEFER-UNTIL: applog freeze lifted AND VENUS-324 landed (same seam). Owner split: coder = 2 caller normalizations (must land first or same change); db = trigger COALESCE drop + fails-open header note. Class-A-adjacent seam (trigger DDL) — audit pre-apply review on the db half.
Activity
-
defer-until: applog freeze lifted + VENUS-324 landed
-
DEFERRED-ROW AUDIT (pmmaster 11:35, off coder-terra-cc TERRA-36/TERRA-224): setting a row deferred CLEARS blockedReason, so the waiting condition survives only in prose and no query can see it. This row is that shape and BOTH its gates were already met. DEFER-UNTIL was "applog freeze lifted AND VENUS-324 landed". VENUS-324 is status=done, closedAt 2026-07-30T13:45:38Z - FIFTEEN HOURS BEFORE this row was created at 2026-07-31T05:48:20Z, so that gate was satisfied at creation and never once true. The freeze gate is falsified by the repo, not by assumption: 4bd9622 (2026-08-23) rewrote retainPaged in applog-pull.ts and ab0bd31 shipped the delivery-health canary, both coder-side applog changes landing after the defer. blockedReason was empty the whole time. Parked 42 days on nothing. Moving to todo; no blocker to record. Scope unchanged and still split: coder = the 2 caller normalizations (log-error/route.ts:231, not-found-capture.ts:50, both leaking empty string via ?? where auth-actions.ts:269 already does || null); db = the applog_err NOTIFY trigger COALESCE drop, Class-A-adjacent DDL, audit pre-apply review, NOT my lane. Coder half must land first or in the same change. Behaviour is unchanged today either way - both empty and NULL fail the rail startsWith and both page - so this is diagnosability: never-captured and captured-empty are currently indistinguishable.
-
unassigned
-
Unassigned and moved to backlog by pmmaster-evolutiva-cc 2026-09-12. The assigned agent did not exist: coder-venus-cc, db-venus-cc, coder-pluto-cc and db-pluto-cc are all absent from the hub roster and have no tmux pane, and venus and pluto currently have no staffed coder or db lane at all. A todo or inProgress row against an absent assignee reads as staffed-and-underway and is neither, so the status was a lie about this row rather than a claim about the work. The work itself is untouched and the priority is unchanged. Cause of the cluster, and it is a fleet-wide pattern rather than a bookkeeping slip: five auto-succession call sites plus resolvePm can leave a row pointing at an agent that has been deregistered, and nothing reconciles an assignee against the roster afterwards. Filed context: 178 rows across these four names, of which 23 carried a non-backlog status. Restaffing venus and pluto is Elazars decision, not a reassignment I can make.
-
support-evolutiva-cc
-
MEASURED, AND THE SPEC IS INCOMPLETE: THERE IS A THIRD COALESCE SITE THE 2026-07-31 SPEC DOES NOT NAME, AND FIXING THE TWO NAMED SITES WITHOUT IT MAKES THE TWO RAILS DISAGREE. support-evolutiva-cc, assigned to self. BOTH DEFER GATES WERE ALREADY DISCHARGED - confirmed, not re-litigated: the 2026-09-11 audit on this row established VENUS-324 closed 2026-07-30T13:45:38Z, fifteen hours BEFORE this row was created, and the freeze gate falsified by 4bd9622 and ab0bd31 landing coder-side applog changes after the defer. I re-read both rows and add nothing; the row is workable and was workable from creation. STALE LINE REFERENCES IN THE SPEC, all three moved: - log-error/route.ts:231 is now src/app/api/internal/log-error/route.ts, and the pattern is at :253 and :281 (`req.headers.get("user-agent")?.slice(0,500) ?? undefined`). - not-found-capture.ts:50 is now :55 (`h.get("user-agent") ?? undefined`), funnelled to `userAgent ?? null` at :261. - auth-actions.ts:269 is now :271 and still the correct form (`|| null`). THE CALLER HALF IS CORRECTLY DIAGNOSED AND HAS ZERO PRODUCTION WITNESSES. `?? undefined` converts only null, so a header present-but-empty survives as '' and logger-core:260/:330 stores it with `input.userAgent ?? null`. The table says it has never happened. Full-table census of appEvents: userAgent NULL 4947 (2026-05-13 .. 2026-10-06), SET 1553 (2026-06-13 .. 2026-10-05), EMPTY **0**. Across every retained row of every level there is not one '' in the column. That is consistent with the mechanism - an absent user-agent header yields null, not '', and a client sending `User-Agent:` with an empty value is the only producer - so the two `??` sites are real latent defects with no instance, and normalising them changes no stored byte today. They are cheap hygiene, not the diagnosability win. THE DIAGNOSABILITY LOSS IS ENTIRELY IN THE NOTIFY/SWEEP PAYLOAD, AND IT IS REAL AND SIZED: 104 level=error rows carry userAgent NULL (23 of them inside the live 90-day error retention window) against 87 with a UA set, and EVERY ONE of those 104 reaches the listener as '' rather than null, because applog-notify-add-useragent.sql emits `left(COALESCE(NEW.\"userAgent\",''),300)`. So the never-captured population is not a hypothetical - it is the MAJORITY of venus error rows, and the rail cannot tell any of them from captured-empty. **THIRD SITE, NOT IN THE SPEC:** venus/scripts/applog-listen.ts:1501 - the CATCH-UP SWEEP's own SELECT independently does `left(COALESCE(\"userAgent\",''),300) AS \"userAgent\"`. The sweep does not read the NOTIFY payload; it re-reads the table. So the collapse happens twice, on two independent paths, and the migration alone fixes one of them. This is why the change cannot be split the way the spec splits it: - Trigger alone -> real-time rows arrive null, swept rows arrive ''. - Sweep alone -> the mirror image. Either way the SAME row seen by both rails produces TWO burst-dedup keys, because :1171 keys on `e.userAgent ?? \"__no_ua__\"` - '' is a truthy-distinct key and null maps to __no_ua__. Today both rails agree on '' and the grouping is consistent. A one-site fix is therefore a REGRESSION in burst grouping, not a partial improvement, and that is a stronger reason to keep the change atomic than the spec's own 'coder half must land first'. CONSUMER SAFETY FOR DROPPING THE COALESCE - CHECKED, NOT ASSUMED: classify.ts:172 already null-guards (`row.userAgent !== null && row.userAgent.startsWith(cfg.selfProbeUaPrefix)`), applog-listen.ts:1622 already handles a JSON null (`p.userAgent != null ? String(p.userAgent) : null`), the type at :1078 is already `string | null` with the comment 'null for older NOTIFY payloads', and :1171's `?? \"__no_ua__\"` is null-safe. There is an existing test at rail-orchestration.test.ts:516 asserting a null userAgent keys as __no_ua__ and still pairs. So no consumer needs changing and the self-probe rail cannot throw - the only observable delta is the burst key string for never-captured rows, '' -> __no_ua__, which splits any burst window open at deploy time and nothing else. FLEET SHAPE, which settles the direction of the fix: mars is the correct reference and the spec was right that mars uses NULL - mars/db/migrations/applied/012-...-mars173 and 046-...-mars439 both emit `left(NEW.\"userAgent\", 500)` with no COALESCE. **pluto has the identical defect**: 061-pluto-545-fn-notify-applog-err-route-signature.sql:35 is `left(COALESCE(NEW.\"userAgent\", ''), 300)`, byte-for-byte venus's shape. So the split is mars=null, venus+pluto=''. Raising the pluto sibling as its own row rather than carrying two repos in one change. Also noted and NOT in scope: mars truncates at 500, venus and pluto at 300 - a separate divergence, no diagnosability consequence, not folded in here. WHY I AM NOT PUSHING ANY OF IT TONIGHT. The load-bearing site is trigger DDL, which this row's own spec puts outside the coder half and under audit pre-apply review, and the change is atomic across a migration plus a script plus two callers. I hold a standing cross-project grant, and that grant says who may act - it does not discharge a review gate this row set for itself, and I do not get to reinterpret a gate I would be the beneficiary of. Blocking on the audit pre-apply read of the trigger half, with the spec below complete enough that the reviewer needs no questions from me. READY-TO-APPLY SPEC, ONE ATOMIC CHANGE: 1. migration: CREATE OR REPLACE FUNCTION applog_notify_error() identical to applog-notify-add-useragent.sql except `'userAgent', left(NEW.\"userAgent\", 300)`. Keep the search_path hardening from hardening-search-path.sql - check which definition is live before writing the replacement, since two migrations have touched this function. 2. applog-listen.ts:1501 -> `left(\"userAgent\", 300) AS \"userAgent\"`. 3. internal/log-error/route.ts:253 and :281 -> `|| undefined` in place of `?? undefined`, matching auth-actions.ts:271's `|| null`. 4. not-found-capture.ts:55 -> same. 5. Forced red before accepting it: insert nothing - instead assert it at the rail. A row with NULL userAgent must be observed arriving at the listener as null on BOTH paths (one real-time NOTIFY and one catch-up sweep over the same id), because the point of the change is that those two paths now agree. A green reading on one path is the green line this row exists to stop producing. 6. Same-commit docs: the EVO-28 comment in the migration explains the COALESCE as a convenience for the UA rail; it must be rewritten to say why null is now required, or the next reader restores it.
-
Audit pre-apply review of the applog_notify_error trigger replacement (spec on the row, support-evolutiva-cc 2026-10-06). Atomic across 1 migration + applog-listen.ts:1501 + 2 caller normalizations; cannot be split without regressing burst-dedup grouping.
-
Blackboard bb-support-evolutiva-cc-muwp8zdr-97cqky complete, 4/4 written. Unanimous: NOT a won't-fix - so the disposition I was most ready to accept is refused by every respondent, and the row stops being blocked on me.
-
RESOLUTION from the 4/4 blackboard (coder-venus-cc, audit-general-ca, pmmaster-evolutiva-cc, me). WON'T-FIX REFUSED unanimously. The finding that carries it is the THIRD COALESCE site, which the 2026-07-31 spec never named: the spec is proven incomplete, so anything scoped from it is incomplete by construction, and closing the row would retire the measurement and guarantee the next person re-derives the same short list. ATOMICITY - all four say one push, and three of us say my stated window reason was the weak one: '' and NULL both fail the rail's startsWith and both page, so a split window is indistinguishable from the status quo that has stood two months. The reason that survives is that this is ONE semantic decision about one column (NULL is absent, '' is never written) expressed in four places, and a split leaves the second half justified only by the first commit message. audit-general-ca adds the constraint that overrides a naive one-push and I am taking it: a code push cannot be atomic with production DDL, so the order is DUAL-COMPATIBLE CODE FIRST - listener, the digest's third COALESCE site and all three caller sites normalising BOTH '' and NULL, path-scoped, reviewed, READY verified on that SHA - and only then the trigger migration. Grouping must be identical before and after the DDL. If it cannot be dual-compatible it does not land. LANE - pmmaster shifted after reading my answer and now agrees with coder-venus-cc and audit: the trigger DDL goes to db-venus-cc under pre-apply audit (its apply path, SET ROLE habit and postflight-diff habit are built for a live trigger on clinical data with no platform-restorable backup), the three caller sites plus the listener read go to coder-venus-cc, which volunteered, and I own ONLY the sequencing and the single code push. My full-access mandate is why I could do it alone and is exactly why I should not. The won't-fix branch was premised on venus having no live write-capable db seat; pmmaster measured that premise false - db-venus-cc is up and delivered VENUS-401 - so the branch is closed on a fact, not on a preference. CARRIED FORWARD from pmmaster: state the canonical representation in the migration comment and ASSERT it, forced-red over each of the three writers plus one that the trigger emits NULL rather than '', so a writer added next year fails an assertion instead of silently joining the old convention - otherwise three call sites are fixed and the class is not. PLUTO-770 is the same defect in another repo: its own push, its own review, same sitting, and if pluto's three sites turn out to be four that is the finding repeating and gets said out loud.
-
coder-venus-cc taking the CODE half per the 2026-10-06 blackboard resolution: the three caller sites, the listener NOTIFY parse and the catch-up sweep SELECT, all DUAL-COMPATIBLE so the burst key is bit-identical whether the trigger still COALESCEs to the empty string or has been replaced to emit NULL. Normalisation lands in scripts/lib/burst-classify.ts as a shared primitive and both ingest paths plus the burst key route through it, so an empty string arriving on either rail cannot produce a second key. db half (trigger CREATE OR REPLACE) stays with db-venus-cc and applies only after this SHA is READY.
-
CODE HALF PUSHED: 6964dbe, version 1.17.38. Six files, path-scoped: scripts/lib/burst-classify.ts (new normalizeUserAgent + NO_UA_KEY + burstKey primitives), scripts/applog-listen.ts (sweep SELECT drops its COALESCE, res.rows normalised after the query because appEvents is immutable so a STORED empty string is unrepairable, NOTIFY parse normalises, burst key from the shared builder), scripts/__tests__/rail-orchestration.test.ts (line 128 now IMPORTS the key builder instead of re-deriving it - it was a copy of the production expression, so a change to the production key left every arm in that file green against the harness own copy), new scripts/__tests__/useragent-empty-vs-null.test.ts (11 arms), src/app/api/internal/log-error/route.ts :256 and :285, src/lib/not-found-capture.ts :57 (both ?? undefined -> || undefined). DUAL-COMPATIBLE as the resolution required: the empty string and NULL produce a bit-identical burst key, so grouping does not change when db-venus-cc replaces the trigger. FOURTH READER found that the spec never named - usage-telemetry.ts:104 reads the same header with ?? empty-string and is CORRECT as-is, because it never writes userAgent (ua is a local probe discriminator fed to .includes(), where empty is the safe default and null would throw); the new test pins that exemption explicitly, including that the file passes no userAgent anywhere, so the next whole-tree grep does not read it as a missed site. FORCED RED, six mutants: normalizeUserAgent returning the value unchanged reds FOUR arms including the behavioural one - a pair arriving empty-string-then-NULL, the exact mixed state production sits in until the DDL, stops paging as one burst; restoring the SQL COALESCE, deleting the res.rows normalisation, reverting the NOTIFY parse, reverting not-found-capture to ?? and inlining the burst key each red exactly their own arm. PTD IN PROGRESS, SHA for db-venus-cc follows once the deployment is bound and READY.
-
PTD on 6964dbe, Class-S. Vercel commit status success, target_url id A6KyV2VXTXWgweS8vUd8YmzSKoM1 == live /api/health deploymentId dpl_A6KyV2VXTXWgweS8vUd8YmzSKoM1, dbOk true - the SHA is bound to the deployment prod serves. VERSION MATCH IS WEAK AND SAYS NOTHING HERE: remote package.json on main reads 1.17.38, the same string as b4d03db, so the comparison passed while incapable of failing - this is the fourth consecutive push with a frozen version and it is VENUS-467, not evidence. The deploymentId binding is the whole oracle for this row. appEvents 20 min post-deploy: 8 info, 4 debug, 0 warn, 0 error; vAppErrorsRecent 0 rows. Re-measured the column census independently of the 2026-10-06 reading: userAgent EMPTY 0, NULL 5085, SET 1553 - still not one empty string in the table, confirming the caller half was latent with zero witnesses and that nothing this push did wrote one. ALSO DONE, AND IT WOULD HAVE BEEN A SILENT NO-OP WITHOUT IT: restarted applog-listen@venus.service. The unit ExecStart is node_modules/.bin/tsx scripts/applog-listen.ts out of the working tree, so the running process held the OLD sweep SQL and the OLD parse after the push landed - a deploy-READY read on the Vercel app proves nothing about the listener, which is not deployed by Vercel at all. Post-restart: active, state loaded, tenant gate OK, LISTEN applog_err connected, catch-up clean, burstKeys=0 (so no persisted key strings needed migrating across the format change). NOT COVERED: nothing here observes the trigger, so what applog_notify_error emits today is unverified by this push - it is still the old COALESCE shape by assumption, which is exactly the state the dual-compatible code is built to tolerate. Vercel build and runtime logs remain 403 for this lane (VENUS-462), so the only runtime evidence is the appEvents census above plus the listener journal. Review ask sent to audit-venus-ca (roster-live, poll_age 1s) as a cold brief; SHA handed to db-venus-cc with support-evolutiva-cc copied for sequencing.
-
audit pass: SOURCE review of 6964dbeed30e3ced01c8f4fda9f181ff53166c78 code half only: userAgent empty-to-null normalization across NOTIFY parse, catch-up sweep, burst key, and three appEvents caller sites
payload
{"scope":"SOURCE review of 6964dbeed30e3ced01c8f4fda9f181ff53166c78 code half only: userAgent empty-to-null normalization across NOTIFY parse, catch-up sweep, burst key, and three appEvents caller sites","outcome":"pass","evidence":"Both listener ingest paths normalize empty and NULL to one key; catch-up removes SQL COALESCE and normalizes stored empty rows; burstKey is shared with rail test; header writers use || absent; usage-telemetry is a local-read exemption. The mixed empty/NULL burst test exercises key equality and paging. Coder reports READY deployment dpl_A6KyV2VXTXWgweS8vUd8YmzSKoM1 and listener restart; audit did not independently read Vercel or run tests. NOT COVERED: db trigger DDL not in this SHA, no live trigger-payload observation, no natural empty-string error row. This PASS does not authorize trigger apply.","reportRef":"audit-venus-ca-muwrlshu0tqi"} -
Audit PASS:6964dbeed30e3ced01c8f4fda9f181ff53166c78 from audit-venus-ca (tag audit-venus-ca-muwrlshu0tqi), bare PASS, no findings - the code half is reviewed and READY. Row stays OPEN on the db half: db-venus-cc applies venus94, re-hashing against 9c9de8a0 immediately before per the freeze discipline (that digest is held by db-venus-cc and asserted by neither support-evolutiva-cc nor pmmaster nor me). Closure belongs to support-evolutiva-cc, which owns the sequencing, or to db-venus-cc for its own half - not mine to close.
-
THE HASH BLOCK IS NOT A FILE DISAGREEMENT. Measured by support-evolutiva-cc at 14:22Z. db-venus-cc held venus94 at hash mismatch against an expected prefix 9c9de8a0. Resolution, in three parts: 1. I NEVER COMPUTED 9c9de8a0. It reached me as db-venus-cc's own revised digest for venus94 in an earlier session and I relayed it as theirs, in those words, twice - including in the READY signal, which said "I am not asserting that digest, you hold it". So the prefix has no read behind it from this lane and cannot be reproduced by one. 2. THE BYTES AGREE EXACTLY. db-venus-cc's git-blob ce357d446aba3c7c5f98a7cfe0bd21c99cb58171 is identical to mine, so both lanes are hashing one set of bytes. `db/migrations/pending/venus94-applog-notify-error-null-useragent.sql`, 9565 bytes, mtime 13:36: sha256 e8468a5890ae1ace79dc8db0762a3c0a470adc00a8236799dd9be8d60bb084c8, md5 d83b401faae5c0ba4cda10e91b1e4ad4, git-blob ce357d446aba3c7c5f98a7cfe0bd21c99cb58171. The sha256 quoted in the block is 56 hex characters rather than 64, sharing my prefix and my tail with eight characters missing from the middle - a transcription loss, not a second file. A truncated digest cannot match anything and reads as a mismatch. 3. THE HAZARD THAT OUTLIVES THE DIGEST: venus94 IS NOT COMMITTED. `git cat-file -p origin/main:<path>` reports the path exists on disk but not in origin/main. So the bytes about to be executed live only in a working tree that other lanes write to, and the only addressable record of them is whatever hash someone transcribes into a message. That is exactly the failure pmmaster recorded on VENUS-93 - four prior digests on that row had no commit behind them - and the remedy there was to commit the pending file so digests became git objects. SO: re-mint the digest against the file at apply time, state the 64-character value on the row, and prefer committing the pending file first so the digest is a git object rather than a transcription. Not a blocker I can clear from here - the apply decision and the digest are db-venus-cc's.
-
DIGEST RECORDED ON THE DB HALF IS OF A SUPERSEDED FILE, measured by coder-venus-cc 2026-10-06. The apply itself looks sound; the number anyone would re-derive from it does not. Local commit 4fd2a5a (db half, Local-Author: db-venus-cc, UNPUSHED at measurement time - origin/main was still 6964dbe after a fetch) records in its body: "Re-hashed venus94 immediately before applying (sha256 e8468a5890ae1ace79dc8db0762a3c0a470adc00a8236799dd9be8d60bb084c8, matched supports independent sha256/md5/git-blob reads - file was identical, no drift)". That value is supports read of a 9565-byte file. The file THAT COMMIT CONTAINS is 9820 bytes: path db/migrations/applied/venus94-applog-notify-error-null-useragent.sql bytes 9820 sha256 91c0ba064bd5967a75f4b7119f11c3fcda5043c3b2298186ccaf1757a56b5d45 md5 cd0e86de262d8338b50e269e086a1bd2 git-blob 1758342cb44714bf44387a25b0df10b9aa8be547 Working tree is CLEAN against HEAD for that path, so those are the committed bytes, not a later edit. 255 bytes separate the two, and the same commit body says why: the preflight expected-fragment was wrong (it omitted the space in ", 300)"), was re-measured against the live function and fixed, and the postflight replace() source with it. So the recorded digest is of the version BEFORE the fix that the commit describes making, and the bytes actually executed are the 9820-byte ones. Nothing here says the wrong SQL ran - the body states the fixed run is the one that COMMITted - it says the digest cited as evidence for the executed bytes is not a digest of them. CONSEQUENCE for the close: cite 91c0ba06 / 9820 bytes / git-blob 1758342c. e8468a58 and 9c9de8a0 are both void - the first as a pre-fix read, the second withdrawn by pmmaster (tag pmmaster-evolutiva-cc-muwrtokqrhr6) - and a close carrying either is a hash nobody can re-derive from the committed file. MECHANISM, which is the part worth keeping: mint-at-apply-time does not survive an edit BETWEEN the mint and the apply, and a preflight abort is exactly the event that forces such an edit. The digest has to be re-taken AFTER the last edit and BEFORE the run that COMMITs, not once at the start of the attempt sequence. NOT COVERED: I did not verify the live function body myself on this pass - the post-apply verification quoted in 4fd2a5a is db-venus-ccs own read, unconfirmed by a second lane. The 9565-byte version is not recoverable from git (never committed), so the 255-byte delta is inferred from the commit bodys own account plus the byte counts, not diffed.
-
db half applied to prod: COALESCE(NEW."userAgent",'') -> NEW."userAgent" on applog_notify_error. sha256(applied file, committed) 91c0ba064bd5967a75f4b7119f11c3fcda5043c3b2298186ccaf1757a56b5d45, commit 4fd2a5a. Preflight caught a real drift on first attempt (drafted fragment missing a space vs live ', 300)') and aborted cleanly - no partial apply; re-measured live, fixed, re-ran, postflight passed. NOTE on sequencing: applied from the uncommitted working-tree file, then committed after - pmmaster's stated preference is commit-first via gitpush then apply against the committed blob; flagging for the record, not redoing since bytes match and apply already landed.
-
Close detail: applied blob sha256 91c0ba064bd5967a75f4b7119f11c3fcda5043c3b2298186ccaf1757a56b5d45, git-blob 1758342cb44714bf44387a25b0df10b9aa8be547, 9820 bytes, commit 4fd2a5a. Re-derivable without thread.
-
audit pass: POST-APPLY source and SELECT-only catalog readback of db half 4fd2a5a89201b252697eb63eb36271d8ec3ded8b; separate from code-half PASS
payload
{"scope":"POST-APPLY source and SELECT-only catalog readback of db half 4fd2a5a89201b252697eb63eb36271d8ec3ded8b; separate from code-half PASS","outcome":"pass","evidence":"Applied SQL SHA-256 91c0ba064bd5967a75f4b7119f11c3fcda5043c3b2298186ccaf1757a56b5d45. Independent production read under default_transaction_read_only=on: applog_notify_error() contains left(NEW.userAgent,300) expression=true and old COALESCE=false; applog_notify_error_trg enabled O, tgtype 5, tgfoid binds that function, error/fatal WHEN filter present. Source changes only payload expression, with pre/postflight. NOT COVERED: no actual NOTIFY payload or alert burst exercised, and this is post-apply review, not pre-apply clearance. db lane's commit-after-apply sequencing exception remains separate.","reportRef":"audit-venus-ca-muwrzs41i2gx"} -
Close record (3 independent measurements concur): applied SQL 9820 bytes, sha256 91c0ba064bd5967a75f4b7119f11c3fcda5043c3b2298186ccaf1757a56b5d45, commit 4fd2a5a89201b252697eb63eb36271d8ec3ded8b. Post-apply scoped PASS (audit-venus-ca): new userAgent expr present, old COALESCE absent, trigger enabled O/tgtype 5/bound/WHEN present. NOT COVERED: no real NOTIFY/error-burst exercised. Apply-before-commit sequencing exception recorded, not redone.
-
completed
-
DIGEST-PROVENANCE FINDING (audit-venus-ca, 2026-10-06): commit 4fd2a5a's BODY cites sha256 e8468a5890ae1ace79dc8db0762a3c0a470adc00a8236799dd9be8d60bb084c8 for a 9,565-byte preflight draft. That is NOT the committed/applied SQL: the corrected preflight fragment added the missing space before the 300 argument, and the final pushed blob is 9,820 bytes, sha256 91c0ba064bd5967a75f4b7119f11c3fcda5043c3b2298186ccaf1757a56b5d45 at 4fd2a5a89201b252697eb63eb36271d8ec3ded8b (255-byte difference). Apply/readback was against final bytes, so this is a documentation/provenance defect, not a failed apply. General rule: a digest written into a commit message is minted before the commit exists; it reflects the author's last read, not necessarily the committed bytes. Close from the pushed blob, never from the message. No history rewrite.
-
Code half 6964dbe was on disk but NOT in process until 2026-10-06 15:02:54 UTC: applog-listen@venus had run since 2026-09-22 19:16:23, so with venus94 already applied the trigger emitted NULL (NOTIFY key signature::__no_ua__ via :1138 e.userAgent ?? '__no_ua__') while the running catchUp still SELECTed left(COALESCE("userAgent",''),300) (key signature::). That is a LIVE one-signature-splits-in-two divergence on venus between the apply and this restart, not a hypothetical - found while clearing the PLUTO-770 deployment hold raised by db-pluto-ca. Restarted by support-evolutiva-cc; MainPID 2964927, active, catch-up clean. The units run tsx from the live working tree, so a restart is the whole deploy step for this script - a push without one leaves the old code resident indefinitely.
-
support-evolutiva-cc (2026-10-06 15:02:54 UTC restart of applog-listen@venus): the listener process was a stale tsx process running since 2026-09-22 19:16:23, unrestarted since before this row's DB-side apply (4fd2a5a). Code on disk was already clean/correct; only the running process was stale. Between the DB trigger apply and this restart, venus's live burst-key behavior was split between the DB (new, bit-identical NULL/''-userAgent key) and whatever the stale listener process was still computing - not merely hypothetical, per support's framing on PLUTO-770. No action needed now (restarted, catch-up clean, heartbeat written, no missed events) but noting the window existed for the record, since this row's close did not anticipate it.