Codex Reports Live Refresh Factory — Production Survey and Local Fix
title: "Codex — Reports Live Refresh Factory — Production Survey and Local Fix" tags:
- codex
- reports
- live-refresh
- factory
- pg
- directus
- nuxt
- nginx
- production-evidence
- 2026-07-10 date: 2026-07-10 status: local-fixed-awaiting-owner-gate
Codex — Reports Live Refresh Factory — Production Survey and Local Fix
0. Executive verdict
Local factory fix: READY_FOR_OWNER_GATE. Production deployment: NOT RUN.
The root problem is in the shared Reports mold and deployment artifact, not in individual report pages:
- Production's existing “Làm mới” button did not issue a new source request.
- The legacy snapshot
v_report_pgwas stale while the live PG census had changed. - The repository nginx/config artifact did not carry the complete live Reports/MCP route set.
- The computed-report route did not send an explicit no-store response header.
The local repair makes source selection metadata-driven and makes one refresh re-query the selected source. It also adds a paired verifier and CI/deploy guards. No production database write, push, CI run, or deploy was performed.
1. Mission declarations
Vĩnh viễn
table_registry.view_sql is the source selector for computed reports; base-table reports remain Directus-backed. The shared mold is the only UI path, so a new report declaration inherits live refresh behavior.
Nhầm được không
The live route accepts only table_id; it resolves SQL server-side, validates SELECT/WITH, executes through the read-only PG gateway, and returns no-store. The publisher and verifier reject unsafe metadata or mismatched API/PG counts. CI/deploy guard checks the canonical nginx route set.
100% tự động
A base-table spec goes through dot-list-publish (read-only Directus tracking, PK detection, registry metadata, paired verification). A computed report spec goes through dot-report-publish (read-only SQL probe, metadata upsert, paired verification). No per-report page or hand-written count formula is required.
2. Production survey (read-only)
2.1 Registry inventory
Production table_registry has 28 non-archived rows. Seven active rows are under /reports:
| table_id | source | live API/PG count |
|---|---|---|
| tbl_balo_function | Directus base table balo_thuc_the, PK stt |
654 = 654 |
| tbl_balo_table | Directus base table balo_thuc_the, PK stt |
383 = 383 |
| tbl_balo_trigger | Directus base table balo_thuc_the, PK stt |
410 = 410 |
| tbl_balo_view | Directus base table balo_thuc_the, PK stt |
699 = 699 |
| tbl_loai | Directus base table entity_species, PK id |
42 = 42 |
| tbl_report_home | live view_sql |
6 = 6 |
| tbl_report_pg | live view_sql |
12 = 12 |
Exact paired verifier output:
PASS source=directus_base_table table_id=tbl_balo_function directus_count=654 pg_count=654
PASS source=directus_base_table table_id=tbl_balo_table directus_count=383 pg_count=383
PASS source=directus_base_table table_id=tbl_balo_trigger directus_count=410 pg_count=410
PASS source=directus_base_table table_id=tbl_balo_view directus_count=699 pg_count=699
PASS source=directus_base_table table_id=tbl_loai directus_count=42 pg_count=42
PASS source=live_view_sql table_id=tbl_report_home api_count=6 pg_count=6
PASS source=live_view_sql table_id=tbl_report_pg api_count=12 pg_count=12
2.2 Stale snapshot evidence
The legacy snapshot table still contains:
table|383|2026-06-27 06:27:39.296757+00
sequence|149|2026-06-27 06:27:39.296757+00
The live route currently returns:
HTTP/1.1 200 OK
source=pg:table_registry.view_sql:tbl_report_pg
count=12
table=385
sequence=151
generated_at=2026-07-10T08:07:32.136Z
This proves the old snapshot was not a current source of truth.
2.3 Production UI failure before the fix
Playwright against https://vps.incomexsaigoncorp.vn was 0/3:
- Home refresh: no new
/api/reports/live?table_id=tbl_report_homeresponse. - PG refresh: no new
/api/reports/live?table_id=tbl_report_pgresponse. - Balo refresh: no new Directus data request.
A direct browser trace after clicking “Làm mới” showed only the initial registry/auth requests; no source re-query was emitted.
The production live endpoint response also lacked an explicit Cache-Control: no-store header.
2.4 Non-Reports caveat
Two non-Reports registry pages (tbl_registry_changelog, tbl_registry_collections) returned HTTP 403 through the public UI proxy. They are under /knowledge, not the seven Reports routes, and no production permission was changed.
3. Local repair
Shared mold and source selection
web/components/shared/DirectusTable.vue- Detects
view_sqlmetadata and routes computed reports to the live gateway. - Refresh awaits the common
useAsyncDatarefresh and emitsrefreshed. - Existing base-table callers retain the Directus path.
- Detects
web/composables/useDirectusTable.ts- Live requests send only
table_id. - Live responses use
cache: 'no-store'. - Directus count/list paths remain shared and filter-consistent.
- Live requests send only
Live gateway
web/server/api/reports/live.get.ts- Looks up
view_sqlby parameterizedtable_id. - Rejects unsafe/non-SELECT SQL.
- Executes via
rpQuerywith read-only transaction settings. - Returns
source,generated_at,count,rowsand no-store.
- Looks up
Reports Home totals
web/pages/reports/index.vue- Re-reads each target's registry metadata.
- Uses the live gateway for computed targets and Directus aggregate for base tables.
- Refreshes totals on the shared mold's
refreshedevent.
Factory and verifier
dot/bin/dot-list-publish- Ensures read-only Directus tracking.
- Auto-detects a single-column PK when omitted.
- Upserts only metadata and verifies API/PG equality.
dot/bin/dot-report-publish- Accepts live SELECT/WITH metadata.
- Runs a read-only probe.
- Never creates, truncates, or populates snapshot tables.
dot/bin/dot-table-ui-verify- Paired read-only verifier for both source variants.
scripts/integrity/check-reports-factory.sh- Guards source files, route order, no-store, read-only gateway, runtime PG dependency, and publisher/verifier pairing.
Deployment source of truth
.gitignoreno longer blocks the Reports route source.infra/nginx/conf.d/default.confcontains the canonical Reports, registries-pivot, MCP and UI-preview blocks.- CI and both deploy paths run the factory guard,
nginx -t, and a live PG Reports health check. web/package.jsondeclares runtimepgso the SSR artifact contains the database driver.
4. Local verification evidence
pnpm run typecheck
exit_code=0
pnpm run build
[nitro] ✔ You can preview this build using node .output/server/index.mjs
✨ Build complete!
node ../scripts/validate-contracts.js
Điều 31 Contract Validation: 6 PASS, 0 FAIL, 1 SKIP
bash scripts/integrity/check-reports-factory.sh
PASS reports-factory: all static invariants satisfied
Local Playwright against the built SSR artifact:
Running 3 tests using 3 workers
✓ Home refresh re-reads its live rows and all displayed totals
✓ computed PG report refresh gets a newer generated dataset
✓ base-table report refresh stays on the Directus live-table path
3 passed
5. Owner gate / next step
This report is local-fixed and evidence-backed, but production is intentionally unchanged.
Required next governed sequence:
- Owner approves the local diff.
- Commit only the scoped factory/report/nginx/CI files.
- Push one PR and wait for CI.
- Run the standard deploy path.
- Verify
/reports, all seven Reports routes, livegenerated_at, and API/PG equality again.
Do not treat the current production URL as repaired until step 5 is green.
6. Files and evidence
- Factory guard:
scripts/integrity/check-reports-factory.sh - Progress/evidence note:
knowledge/current-state/reports/reports-live-refresh-factory-progress-2026-07-10.md - Reports contract:
web/tests/contracts/reports.json - E2E proof:
web/tests/e2e/reports-live.spec.ts - Production live route:
https://vps.incomexsaigoncorp.vn/api/reports/live?table_id=tbl_report_pg
7. Evidence update — B/C/D safety gate (2026-07-10 16:xx ICT)
Status: NOT DEPLOY-READY; Owner gate remains closed. No production database write, source push, merge, CI run, nginx change, or deploy was performed.
B. Nginx and repository mine removal
Read-only live check:
```text REQUIRED_ANCHORS_MISSING target=repo count=0 REQUIRED_ANCHORS_MISSING target=live count=0 nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful ```
Both repo and live have /api/reports/, /api/registries-pivot/, and all four MCP route includes. The required Reports route occurs before the generic /api/ catch-all.
A real pre-deploy mine was found: canonical default.conf includes well-known-whitelist.conf, while that companion file is absent on the live host and the deploy workflow previously copied only default.conf. Replacing nginx config would therefore fail nginx -t. The existing deploy workflow was repaired locally in both direct/artifact paths to copy the existing companion before nginx -t; the static guard verifies this transfer.
The guard now also fails when a required Reports source is ignored, untracked, modified-but-uncommitted, missing a protected nginx block, lacks route no-store, lacks the shared refresh event, or loses either publisher/verifier pairing. The runtime deploy health check now requires Cache-Control: no-store and two distinct generated_at values, not merely count=12.
C. Verifier now catches the actual frozen-report failure
The paired live verifier was tightened without adding a new mechanism:
- requires
Cache-Control: no-store; - calls the live route twice and requires distinct
generated_at; - compares all normalized API rows with the rows from the stored
view_sqlin aBEGIN READ ONLYtransaction; volatile timestamps and bigint JSON transport differences are normalized; - fetches SSR and requires a rendered report timestamp no more than 120 seconds old.
Historical stale report-pg values versus PG-live normalize to different rows:
```text OLD: table=383, sequence=149 LIVE: table=385, sequence=151 EXPECTED_FAIL live rows differ: API display is not PG-live ```
This closes the prior false-pass: both sources had 12 rows, so a count-only verifier could pass even when the displayed numbers were stale.
Current production deliberately fails the stricter verifier before deployment:
```text FAIL live response is cacheable (Cache-Control no-store required) VERIFIER_EXIT=5 ```
Browser proof of the legacy deployed UI remains failing: after clicking Home refresh, Playwright timed out waiting 10 seconds for /api/reports/live?table_id=tbl_report_home. Thus production is not claimed repaired.
Local built SSR proof (read-only production data tunnel) passes:
```text Cache-Control: no-store, max-age=0 generated_at #1 = 2026-07-10T09:22:13.154Z generated_at #2 = 2026-07-10T09:22:15.015Z SSR refreshed_at = 2026-07-10T09:22:18.778Z 3 Playwright tests passed: Home live refresh, computed PG click/network/DOM refresh, base-table Directus refresh ```
The source selection remains shared: view_sql reports use the PG gateway; base-table reports retain Directus. No Balo count/snapshot behavior was changed.
D. Deployment source truth
This local working tree is not yet a deployable repository source:
- Production deploy builds GitHub
mainvia Actions checkout and rsyncsweb/.output; it does not build from the VPS host repo. - The VPS hand-deployed line is
vps/main(contains older route/pages/gateway), while local has newer uncommitted/untracked Reports sources. .gitignoreno longer blocks the Reports paths, but the route, pages, gateway, verifier, publishers, and guard are not all tracked/committed. The enhanced guard intentionally fails locally with:DirectusTable.vue has uncommitted changes: a CI checkout would deploy older code.
Do not merge or deploy automatically. Owner approval is required to reconcile a clean branch from actual GitHub main with the hand-deployed vps/main delta, scope the Reports-only files, commit, run CI, and then open the deploy gate. Only after that can the production A-round evidence be collected.
Round 2 read-only no-regression baseline
Before any deploy, live nginx still served the unrelated guarded surfaces through its own local front door:
200 /
200 /reports
200 /reports/report-balo-table
200 /reports/report-loai
200 /knowledge/registries
200 /knowledge/workflows
200 /api/registries-pivot/summary
The pivot endpoint returned source=pg:v_count_integrity/v_count_drift/v_registries_pivot_tree and a current generated_at=2026-07-10T09:37:34.365Z. No Balo/Loai, Registries, Workflows, Home, registries-pivot, or MCP configuration was modified on production.