P3D4C2W — User Visible Route 404 Investigation Report
P3D4C2W — User Visible Route 404 Investigation Report
Date: 2026-05-10
Mode: READ-ONLY investigation
Hard boundaries honored: NO_DEPLOY=true, NO_RESTART=true, NO_CODE_CHANGE=true, NO_DIRECTUS_MUTATION=true, NO_PG_MUTATION=true, NO_TABLE_REGISTRY_MUTATION=true, NO_PERMISSION_CHANGE=true, NO_AUTO_FIX=true
Result: ROUTE_PUBLIC_200_BUT_TABLE_DISPLAY_BLOCKED
Root cause classification: GENERATED_MAP_STALE_BLOCKING_PUBLIC
Step 0 — Foundation
3 câu Tuyên ngôn
-
Vĩnh viễn?
Investigation does not patch a single URL. Root issue is that HTTP 200 smoke did not verify the user-visible table marker andevent_outboxis absent from the Nuxt entityType -> table_id map. Permanent fix must make registry display driven by generated/metadata map and require table marker smoke, not just HTTP status. -
Nhầm được không?
Current system can be mistaken: dynamic Nuxt route returns 200 fallback for unknown entity types. This allowed/knowledge/registries/event_outboxto pass status smoke while still showing "Chưa có bảng registry..." instead ofDirectusTable. Blocking mechanism needed: smoke must asserttbl_event_outbox/known page content/table rendering, and generated map must include published table registry rows. -
100% tự động?
Not currently complete. The route exists automatically, but table resolution depends on a statictableIdMap;event_outboxis published in Directus but absent in runtime/source/build map. Next pack must refresh/fix generated map or route resolution so a published registry row appears without manual URL guessing.
Files/docs read
.claude/skills/incomex-rules.mdsearch_knowledge("operating rules SSOT")->knowledge/dev/ssot/operating-rules.md, OR v7.58, 2026-05-01search_knowledge("hiến pháp v4.0 constitution")->knowledge/dev/laws/constitution.md, Constitution v4.6.3 enactedsearch_knowledge("Điều 44 triển khai notification display event_outbox route registry user visible 404")knowledge/dev/laws/dieu44-trien-khai/reports/p3d4c2u-resume-notification-display-report.mdvia Agent Dataknowledge/dev/laws/dieu44-trien-khai/prompts/p3d4c2u-resume-notification-display-prompt-review.mdvia Agent Data
Mission design checkpoint
- Goal: investigate discrepancy between previous Agent smoke PASS and user-visible 404/non-display.
- Method: read prior report/prompt, inspect nginx public base, curl public routes, browser-render safe marker check, inspect Nuxt source/build map, inspect Directus row id=21 read-only.
- Preconditions: public nginx route reachable; Directus public proxy reachable; no mutation needed.
- Roadmap: investigation only; next pack handles fix if needed.
Step 1 — Prior Report And Prompt Evidence
Agent Data prior report snippet:
route=/knowledge/registries/event_outbox
route_http_status=200
smoke_scan=PASS
Prior prompt/review state found through Agent Data:
live route smoke `/knowledge/registries/event_outbox`
tbl_event_outbox.status=draft
notification_display=paused
Interpretation: previous Agent smoke used the intended route path, but the accepted evidence was status-focused. It did not prove that SharedDirectusTable rendered with tbl_event_outbox.
Step 2 — Public Base URL Served By Nginx
Read-only source: infra/nginx/conf.d/default.conf.
Relevant nginx evidence:
server_name vps.incomexsaigoncorp.vn;
location / {
proxy_pass http://nuxt_backend;
}
Public base URL:
https://vps.incomexsaigoncorp.vn
Directus public API is path-stripped under:
https://vps.incomexsaigoncorp.vn/directus/
No secret/token was printed.
Step 3 — Public Curl Matrix
Command surface:
curl -k -sS -L --max-time 30 https://vps.incomexsaigoncorp.vn/<path>
safe scan only: status, final URL, byte count, and markers
Curl from local public network:
| Path | HTTP | Final URL | Content-Type | Bytes | event_outbox marker | DirectusTable/fallback marker | 404 marker | Nuxt marker |
|---|---|---|---|---|---|---|---|---|
/knowledge/registries/event_outbox |
200 | https://vps.incomexsaigoncorp.vn/knowledge/registries/event_outbox |
not present in response headers | 256948 | no | no | no | yes |
/knowledge/registries/event_outbox/ |
200 | https://vps.incomexsaigoncorp.vn/knowledge/registries/event_outbox/ |
not present in response headers | 256949 | no | no | no | yes |
/knowledge/registries/event-outbox |
200 | https://vps.incomexsaigoncorp.vn/knowledge/registries/event-outbox |
not present in response headers | 256948 | no | no | no | yes |
/knowledge/registries/event_outboxes |
200 | https://vps.incomexsaigoncorp.vn/knowledge/registries/event_outboxes |
not present in response headers | 256976 | no | no | no | yes |
/knowledge/registries/system_issue |
200 | https://vps.incomexsaigoncorp.vn/knowledge/registries/system_issue |
not present in response headers | 271078 | no | no | no | yes |
/knowledge/registries/system_issue/ |
200 | https://vps.incomexsaigoncorp.vn/knowledge/registries/system_issue/ |
not present in response headers | 271080 | no | no | no | yes |
Curl from VPS itself over public URL:
PATH=/knowledge/registries/event_outbox STATUS=200 FINAL=https://vps.incomexsaigoncorp.vn/knowledge/registries/event_outbox BYTES=256948 MARKER_404=no MARKER_NUXT=yes
PATH=/knowledge/registries/event_outbox/ STATUS=200 FINAL=https://vps.incomexsaigoncorp.vn/knowledge/registries/event_outbox/ BYTES=256949 MARKER_404=no MARKER_NUXT=yes
PATH=/knowledge/registries/event-outbox STATUS=200 FINAL=https://vps.incomexsaigoncorp.vn/knowledge/registries/event-outbox BYTES=256948 MARKER_404=no MARKER_NUXT=yes
PATH=/knowledge/registries/event_outboxes STATUS=200 FINAL=https://vps.incomexsaigoncorp.vn/knowledge/registries/event_outboxes BYTES=256976 MARKER_404=no MARKER_NUXT=yes
PATH=/knowledge/registries/system_issue STATUS=200 FINAL=https://vps.incomexsaigoncorp.vn/knowledge/registries/system_issue BYTES=271078 MARKER_404=no MARKER_NUXT=yes
PATH=/knowledge/registries/system_issue/ STATUS=200 FINAL=https://vps.incomexsaigoncorp.vn/knowledge/registries/system_issue/ BYTES=271080 MARKER_404=no MARKER_NUXT=yes
Header sample:
URL=https://vps.incomexsaigoncorp.vn/knowledge/registries/event_outbox
HTTP/1.1 200 OK
x-powered-by: Nuxt
URL=https://vps.incomexsaigoncorp.vn/knowledge/registries/system_issue
HTTP/1.1 200 OK
x-powered-by: Nuxt
Conclusion from curl: public route is not returning HTTP 404 on the correct nginx host. Curl alone does not show table rendering markers because the response is largely Nuxt app shell/SSR payload.
Step 4 — Browser User-Visible Marker Check
Read-only Playwright check against the same public host:
{"path":"/knowledge/registries/event_outbox","status":200,"final":"https://vps.incomexsaigoncorp.vn/knowledge/registries/event_outbox","title":"Registry - Incomex AI Portal","markers":{"event_outbox":true,"directusTableOrFallback":true,"notFound":false,"nuxtError":false},"textSampleSafe":"Incomex AI Portal Knowledge Modules Tasks Workflows Registries Pivot Laws Let's Talk Login ← Danh mục hệ thống LAYER 3 event_outbox Chưa có bảng registry cho loại \"event_outbox\". Vui lòng liên hệ admin. MENU Copyright © 1988 - 2026 Incomex AI Portal. All rights reserved. Site powered by Directus and"}
{"path":"/knowledge/registries/event_outbox/","status":200,"final":"https://vps.incomexsaigoncorp.vn/knowledge/registries/event_outbox/","title":"Registry - Incomex AI Portal","markers":{"event_outbox":true,"directusTableOrFallback":true,"notFound":false,"nuxtError":false},"textSampleSafe":"Incomex AI Portal Knowledge Modules Tasks Workflows Registries Pivot Laws Let's Talk Login ← Danh mục hệ thống LAYER 3 event_outbox Chưa có bảng registry cho loại \"event_outbox\". Vui lòng liên hệ admin. MENU Copyright © 1988 - 2026 Incomex AI Portal. All rights reserved. Site powered by Directus and"}
{"path":"/knowledge/registries/event-outbox","status":200,"final":"https://vps.incomexsaigoncorp.vn/knowledge/registries/event-outbox","title":"Registry - Incomex AI Portal","markers":{"event_outbox":false,"directusTableOrFallback":true,"notFound":false,"nuxtError":false},"textSampleSafe":"Incomex AI Portal Knowledge Modules Tasks Workflows Registries Pivot Laws Let's Talk Login ← Danh mục hệ thống LAYER 3 event-outbox Chưa có bảng registry cho loại \"event-outbox\". Vui lòng liên hệ admin. MENU Copyright © 1988 - 2026 Incomex AI Portal. All rights reserved. Site powered by Directus and"}
{"path":"/knowledge/registries/event_outboxes","status":200,"final":"https://vps.incomexsaigoncorp.vn/knowledge/registries/event_outboxes","title":"Registry - Incomex AI Portal","markers":{"event_outbox":true,"directusTableOrFallback":true,"notFound":false,"nuxtError":false},"textSampleSafe":"Incomex AI Portal Knowledge Modules Tasks Workflows Registries Pivot Laws Let's Talk Login ← Danh mục hệ thống LAYER 3 event_outboxes Chưa có bảng registry cho loại \"event_outboxes\". Vui lòng liên hệ admin. MENU Copyright © 1988 - 2026 Incomex AI Portal. All rights reserved. Site powered by Directus"}
{"path":"/knowledge/registries/system_issue","status":200,"final":"https://vps.incomexsaigoncorp.vn/knowledge/registries/system_issue","title":"Vấn đề Hệ thống - Incomex AI Portal","markers":{"event_outbox":false,"directusTableOrFallback":false,"notFound":false,"nuxtError":false},"textSampleSafe":"Incomex AI Portal Knowledge Modules Tasks Workflows Registries Pivot Laws Let's Talk Login ← Danh mục hệ thống LAYER 2 Vấn đề Hệ thống — Phân loại Gom nhóm theo phân loại nguyên nhân (issue_class — Điều 31 §IV.6). Tổng: 16266 issues trong 8 nhóm. 16266 Tổng issues 13744 CRITICAL 2520 WARNING 8 Nhóm "}
{"path":"/knowledge/registries/system_issue/","status":200,"final":"https://vps.incomexsaigoncorp.vn/knowledge/registries/system_issue/","title":"Vấn đề Hệ thống - Incomex AI Portal","markers":{"event_outbox":false,"directusTableOrFallback":false,"notFound":false,"nuxtError":false},"textSampleSafe":"Incomex AI Portal Knowledge Modules Tasks Workflows Registries Pivot Laws Let's Talk Login ← Danh mục hệ thống LAYER 2 Vấn đề Hệ thống — Phân loại Gom nhóm theo phân loại nguyên nhân (issue_class — Điều 31 §IV.6). Tổng: 16266 issues trong 8 nhóm. 16266 Tổng issues 13744 CRITICAL 2520 WARNING 8 Nhóm "}
User-visible conclusion:
- Correct public URL is
https://vps.incomexsaigoncorp.vn/knowledge/registries/event_outbox. - It does not 404 on the checked public surface.
- It does not render the
event_outboxtable. - It renders the fallback:
Chưa có bảng registry cho loại "event_outbox". Vui lòng liên hệ admin.
Step 5 — Nuxt Route Source And Build Artifact
Source file:
web/pages/knowledge/registries/[entityType]/index.vue
Relevant route logic:
const entityType = computed(() => route.params.entityType as string);
const tableIdMap: Record<string, string> = {
catalog: 'tbl_meta_catalog',
table: 'tbl_table_registry',
...
changelog: 'tbl_registry_changelog',
system_issue: 'tbl_system_issues',
};
const tableId = computed(() => tableIdMap[entityType.value] || '');
<SharedDirectusTable v-if="tableId" :table-id="tableId" ... />
<div v-else>Chưa có bảng registry cho loại "{{ entityType }}". Vui lòng liên hệ admin.</div>
Finding:
event_outbox is absent from tableIdMap in source.
tbl_event_outbox is absent from tableIdMap in source.
system_issue -> tbl_system_issues is present.
Build route manifest:
path: "/knowledge/registries/:entityType()/:id()"
path: "/knowledge/registries/:entityType()"
path: "/knowledge/registries/system_issue"
Build artifact:
web/.output/server/chunks/build/index-CE4tLNXH.mjs
Build artifact map:
const tableIdMap = {
catalog: "tbl_meta_catalog",
table: "tbl_table_registry",
...
changelog: "tbl_registry_changelog",
system_issue: "tbl_system_issues"
};
const tableId = computed(() => tableIdMap[entityType.value] || "");
Finding:
event_outbox is absent from production build artifact.
tbl_event_outbox is absent from production build artifact.
No fallback was found that could make internal route 200 but public route 404. The fallback makes unknown entity types HTTP 200 with a user-facing warning, which is exactly what the browser check shows.
Step 6 — Directus Table Registry Row id=21 Read-Only
Public Directus proxy read:
GET https://vps.incomexsaigoncorp.vn/directus/items/table_registry/21?fields=id,status,page_url,collection,table_id,name
HTTP=200
{"id":21,"status":"published","page_url":"/knowledge/registries/event_outbox","collection":"event_outbox","table_id":"tbl_event_outbox","name":"Hộp thư sự kiện"}
Field config read:
HTTP=200
{"fieldKeys":["occurred_at","event_domain","event_type","event_stream","delivery_lane","event_severity","event_subject_table","event_subject_ref","canonical_address","actor_ref","source_system","payload_classification","created_at"],"default_sort":"-occurred_at","rows_per_page":50,"enable_search":true}
Public Directus read with registry allowlisted fields:
GET /directus/items/event_outbox?limit=1&fields=occurred_at,event_domain,event_type,event_stream,delivery_lane,event_severity,event_subject_table,event_subject_ref,canonical_address,actor_ref,source_system,payload_classification,created_at&sort=-occurred_at
HTTP=200
{"data_is_array":true,"count":1,"first_keys":["occurred_at","event_domain","event_type","event_stream","delivery_lane","event_severity","event_subject_table","event_subject_ref","canonical_address","actor_ref","source_system","payload_classification","created_at"]}
Control probe showing permission is field-restricted as expected:
GET /directus/items/event_outbox?limit=1&fields=id,occurred_at,event_domain,event_type,event_stream,status
HTTP=403
{"error":["You don't have permission to access field \"status\" in collection \"event_outbox\" or it does not exist. Queried in root."]}
Interpretation:
table_registryid=21 is published.page_urlpoints to/knowledge/registries/event_outbox.collection=event_outbox.table_id=tbl_event_outbox.- Public Directus permission allows the registry-configured event_outbox fields.
- Permission is not the blocker for table display.
Step 7 — Comparison
URL Agent smoke used
/knowledge/registries/event_outbox
Prior report only shows route path and HTTP 200; no evidence found that it asserted user-visible SharedDirectusTable, tbl_event_outbox, or the Vietnamese table name.
URL user-facing public should use
https://vps.incomexsaigoncorp.vn/knowledge/registries/event_outbox
Difference analysis
| Dimension | Finding |
|---|---|
| Base host | Correct public host is https://vps.incomexsaigoncorp.vn; nginx serves it to nuxt_backend. |
| Nginx path | /knowledge/... goes through location / to Nuxt. No path stripping issue found. |
| Trailing slash | Both /event_outbox and /event_outbox/ return 200 and same fallback. |
| Auth | Page is public. Directus row and allowlisted fields are public-readable. |
| Redirect | No redirect for tested URLs; final URL equals requested URL. |
| Previous smoke | Used correct route path but wrong acceptance surface/criteria: HTTP 200 can mean fallback, not table displayed. |
Step 8 — Root Cause And Next Pack
Root cause classification
Primary:
GENERATED_MAP_STALE_BLOCKING_PUBLIC
Supporting:
AGENT_PREVIOUS_SMOKE_USED_WRONG_SURFACE = false as a host/path claim, but true as an acceptance-criteria problem.
Precise root cause:
table_registry id=21 is published and points to /knowledge/registries/event_outbox, but Nuxt route resolution still uses a static tableIdMap that does not include event_outbox -> tbl_event_outbox in either source or production build artifact. Dynamic route therefore resolves HTTP 200 but renders fallback instead of SharedDirectusTable.
Not supported by evidence:
ROUTE_URL_WRONG=false
PUBLIC_NGINX_PATH_MISMATCH=false
NUXT_ROUTE_RESOLUTION_FAIL=false for HTTP route matching; true only for entityType -> table id resolution
AUTH_OR_REDIRECT_SURFACE=false
AGENT_PREVIOUS_SMOKE_USED_WRONG_SURFACE=false for base URL/path
Smallest proposed fix, not executed
Do not create a custom page. Smallest durable fix should be in the existing generated/dynamic table map path:
Ensure generated table map includes event_outbox -> tbl_event_outbox for published table_registry rows, rebuild/deploy, then smoke must assert user-visible table marker.
Acceptance criteria for next pack:
curl/browser public URL -> HTTP 200
final URL unchanged
browser text/table marker includes Hộp thư sự kiện or tbl_event_outbox-backed columns
fallback marker "Chưa có bảng registry" absent
Directus allowlisted event_outbox fields return HTTP 200
unsafe/denied fields remain 403
next_required_pack
D28_GENERATED_MAP_REFRESH_PACK
If the refresh pack discovers no separate generated-map tool exists and the static map is the only implementation, then escalate to:
D28_ROUTE_RESOLUTION_FIX
Final Status
phase_status=PASS_INVESTIGATION_COMPLETE
public_base_url=https://vps.incomexsaigoncorp.vn
correct_public_url=https://vps.incomexsaigoncorp.vn/knowledge/registries/event_outbox
public_route_404=false
user_visible_table_rendered=false
user_visible_fallback_rendered=true
directus_table_registry_id_21=published
directus_event_outbox_allowlisted_read=PASS
nuxt_source_has_event_outbox_mapping=false
nuxt_build_has_event_outbox_mapping=false
root_cause=GENERATED_MAP_STALE_BLOCKING_PUBLIC
next_required_pack=D28_GENERATED_MAP_REFRESH_PACK
mutation_performed=false
deploy_performed=false
restart_performed=false
code_change_performed=false