export-db.py round 2: columns from pg_catalog, column count in the completeness guard, generated-column default fixed
Round 2 of VENUS-457, on audit-venus-ca BLOCK:7483bc0 (event 12:44:31Z): query_columns still read privilege-filtered information_schema.columns and check_completeness carried no column count, so a reduced-privilege exporter could drop a table's columns from db/schema.md while the table itself still appeared (pg_tables is role-independent) - a partial schema that reads as complete. It survived round 1 because the column count MATCHED (1337/1337) while routines/triggers/constraints collapsed: columns needed only the one privilege the reduced role kept. Fix: columns from pg_attribute+pg_class+pg_type+pg_attrdef; columns and columnRelations added to the completeness guard's counts; a three-block pin in scripts/__tests__/export-db-column-privilege.test.ts whose live arm shows the defect under SET ROLE. Also found and fixed in the same pass: pg_attrdef holds the expression for a GENERATED column too, so a bare pg_get_expr rendered a generation expression in the Default column - information_schema nulls column_default for those by design. venus has exactly ONE information_schema.columns read and no sqlite export path, so pluto's second-read half (acc9d0f) does not apply here.
Activity
-
Pre-push. Local: scripts/__tests__/export-db-column-privilege.test.ts 7 pass + 1 skipped without the harness, 8/8 with HARNESS_DATABASE_URL on loopback. src/lib+src/app+scripts 1298 pass, 24 skipped, tsc 0. FORCED RED, four mutants: F1 (query_columns back to information_schema.columns) reds 3 source arms and, with the harness on, the live arm BY NAME; F2 (drop the columns key from the guard's counts) reds the counts arm; F3 (bare pg_get_expr, no attgenerated CASE) reds the generated-column arm; F0 (whitespace no-op) stays green. schema.md regenerated: columnRelations=125 columns=1337 and every pre-existing count unchanged (tables=48 views=77 functions=75 fks=57 indexes=89 pkColumns=50 triggerEvents=55 uniqueColumns=6 compositeUniques=2 lookupCategories=10); exactly 4 GENERATED markers, matching the 4 attgenerated='s' columns. NOT COVERED: the guard loops the PREVIOUS snapshot's keys, so columns/columnRelations are written by this run and only guarded from the run after it; and the guard compares counts, not contents.
-
CLOSE: 83c87f5, 1.17.37. Class-S (db/export-db.py is a developer doc exporter, one new test file, one regenerated .md - no schema, no auth gate, no email path). PTD, SHA bound to the deployment: Vercel commit status on 83c87f5 success, target_url id 42QDy9pGgtsdrrMF2NRUFWGAsDLJ == prod-alias /api/health deploymentId dpl_42QDy9pGgtsdrrMF2NRUFWGAsDLJ; vercel inspect that id = venus-evolutiva, target production, status Ready, aliases include cmfpost-evolutiva.pensanta.com; dbOk true. appEvents in the 12 minutes since: 3 info, 0 error, 0 warn, vAppErrorsRecent empty - writes are landing (the dba1b00 recovery holds). VERSION MATCH IS WEAK HERE, fourth consecutive push: live 1.17.37 == remote main package.json 1.17.37, but package.json has not bumped since before c458da7, so the comparison is true of four deploys and discriminates none. VENUS-467 carries that. The deploymentId binding above is the load-bearing read. COVERAGE: no error or warn row observed in appEvents for the 12 minutes after the deploy, and the two push-executed test blocks ran inside .gitpush-pre.sh. NOT EXERCISED: Vercel build and runtime logs for this SHA (403 for this lane, VENUS-462, re-measured independently by support-evolutiva-cc at 10:04 ART - an API error at page 0, not an empty result); the live privilege block is describe.skipIf(!HARNESS_ON) so it did NOT run on push, only locally (8/8 against the loopback harness); and the completeness guard loops the PREVIOUS snapshot's keys, so columns=1337 and columnRelations=125 are written by this export and guarded only from the next one. Carried from VENUS-457, which was already closed when audit-venus-ca's BLOCK:7483bc0 landed. Audit diff review asked on this SHA separately.
-
audit pass: 83c87f5 static post-push diff review
payload
{"scope":"83c87f5 static post-push diff review","outcome":"pass","evidence":"query_columns uses pg_attribute/pg_class/pg_type/pg_attrdef, not information_schema.columns; guard now records columns=1337 and columnRelations=125, with generated-column expressions labeled rather than mistaken for plain defaults. Source tests pin whole-file absence of the old view and count wiring. Coder reported loopback SET ROLE harness 8/8 but the live block is skipped in push; audit did not independently run the harness or a production export. First count-bearing snapshot is guarded only from next export. PASS:83c87f5 sent to coder on tag audit-venus-ca-muwp83krhz0n.","reportRef":null}