KB-4785

D28 Generated Map Refresh Pack Report

11 min read Revision 1
d28generated-mapevent_outboxdeploynuxtpartial2026-05-10

D28 Generated Map Refresh Pack Report

Date: 2026-05-10
Pack: D28_GENERATED_MAP_REFRESH_PACK
Result: PARTIAL — generated map, build, deploy, and table visibility passed; strict UI unsafe-label check found payload in the visible label Phân loại payload.
Report path: knowledge/dev/laws/dieu44-trien-khai/reports/d28-generated-map-refresh-pack-report.md


0. Foundation

3 câu Tuyên ngôn

  1. Vĩnh viễn?
    Fix path used the existing generator from table_registry, not a hand-edited tableIdMap. When published registry metadata changes, rerunning the generator refreshes the UI maps.

  2. Nhầm được không?
    The previous false PASS came from HTTP-only smoke. This pack verifies generated artifact, deployed artifact, public curl, and browser-visible DOM markers, including fallback absence and unsafe-field scan.

  3. 100% tự động?
    The route display is now driven by generated maps from registry metadata. Remaining gap: visible label Phân loại payload needs a follow-up safety decision because strict UI scan treats payload as unsafe visible text.

Docs read

  • .claude/skills/incomex-rules.md
  • search_knowledge("operating rules SSOT") -> OR v7.58
  • search_knowledge("hiến pháp v4.0 constitution") -> Constitution v4.6.3
  • knowledge/dev/laws/dieu44-trien-khai/reports/p3d4c2w-user-visible-route-404-investigation-report.md
  • knowledge/dev/laws/dieu44-trien-khai/reviews/gpt-directive-p3d4c2w-generated-map-stale-public-fix-2026-05-10.md
  • knowledge/dev/laws/dieu44-trien-khai/reports/p3d4c2u-resume-notification-display-report.md
  • knowledge/dev/laws/dieu28-trien-khai/prompts/d28-deploy-and-live-smoke-prompt-review.md
  • knowledge/dev/laws/dieu28-trien-khai/reports/d28-deploy-partial-fix-pack-report.md

1. Preflight

Production image before change

pre_image=nuxt-ssr-local:d2db418
running_image_id_prefix=sha256:105bd197347c4

VPS repo state

nuxt_repo=/opt/incomex/docker/nuxt-repo
nuxt_repo_head=d2db418
nuxt_repo_status_count=0

Root /opt/incomex already had unrelated dirty files before this pack; they were not reverted. Relevant new root deploy changes after this pack are limited to docker/docker-compose.yml and a compose backup file.

Directus table registry row id=21

{"table_registry_http": 200, "id": 21, "table_id": "tbl_event_outbox", "collection": "event_outbox", "status": "published", "page_url": "/knowledge/registries/event_outbox"}

Permission #1483 safety

{"permission_http": 200, "permission_id": 1483, "collection": "event_outbox", "action": "read", "field_count": 14, "unsafe_fields_in_allowlist": [], "excludes_safe_payload": true, "excludes_correlation_id": true, "excludes_causation_id": true, "permission_1483_still_safe": true}

Generated artifact before

artifact_contains_event_outbox=false
artifact_maps_event_outbox_to_tbl_event_outbox=false
generator_exists=true
package_script_generate_table_maps=true
host_node_available=false
docker_available=true
node20_alpine_present=true

Check mode before generation:

check_before_exit=1
CHECK_FAIL_HASH_MISMATCH

2. Generate

Generator used:

/opt/incomex/docker/nuxt-repo/web/scripts/generate-table-maps.mjs

Execution method:

docker run --rm --env-file /opt/incomex/docker/.env \
  -v /opt/incomex/docker/nuxt-repo/web:/app \
  -w /app node:20-alpine \
  node scripts/generate-table-maps.mjs

Generator output:

GENERATED rows=19 hash=sha256:023bfd607507ca81c4bbbcf269dee2f66ba907635809797c1f97423602845165
OVERRIDES_USED=8
CONVENTION_DERIVED=12
SKIPPED=2
  - tbl_workflow_timeline: in SKIP list (duplicate collection)
  - tbl_modules_list: duplicate entityType=module, lost to canonical tbl_registry_modules

After generation:

after_contains_event_outbox=true
after_maps_event_outbox_to_tbl_event_outbox=true
after_contains_tbl_event_outbox=true
unsafe_names_in_artifact=
git_diff_stat_after_generate= web/generated/table-maps.generated.ts | 11 +++++++----

Determinism check:

CHECK_OK

Generated diff excerpt:

+	"event_outbox": "tbl_event_outbox",
+	"event_outbox": "event_outbox",
+	"event_outbox": "event_outbox",

No manual tableIdMap edit was performed.


3. Build

Build command:

docker build \
  -f web/Dockerfile \
  --build-arg NUXT_PUBLIC_SITE_URL=https://vps.incomexsaigoncorp.vn \
  --build-arg NUXT_PUBLIC_DIRECTUS_URL=https://directus.incomexsaigoncorp.vn \
  -t nuxt-ssr-local:d28gmr-1778407456 \
  web

Build output summary:

build_exit=0
build_log_size_bytes=86328
secret_scan_counts token=0 secret=0 bearer=0 password=2 jwt=0 url_creds=0
new_image_tag=nuxt-ssr-local:d28gmr-1778407456
new_image_id_prefix=sha256:f2a000c5214d2

Secret scan classification:

forgot_password_filename_hits=2
env_assignment_password_hits=0
json_password_value_hits=0
url_credential_hits=0
jwt_shape_hits=0

The password=2 hits are forgot-password route/chunk filename false positives. No secret value lines were printed.


4. Deploy

Deploy strategy:

  • Extracted built /app/.output from image nuxt-ssr-local:d28gmr-1778407456.
  • Backed up current mounted output.
  • Replaced /opt/incomex/deploys/nuxt-output.
  • Backed up compose.
  • Changed only the nuxt service image in /opt/incomex/docker/docker-compose.yml.
  • Recreated only nuxt with docker compose up -d --force-recreate --no-deps --no-build nuxt.
  • Did not touch Directus, Postgres, agent-data, Qdrant, or nginx.
  • Did not reload nginx; public route worked without nginx reload.

First deploy attempt stopped before service mutation because of extraction path shape:

rsync: change_dir "/tmp/d28-gmr-output-1778407748/.output" failed: No such file or directory
current_after_failed_attempt=nuxt-ssr-local:d2db418 running healthy

Retry deploy succeeded:

deploy_retry_tag=nuxt-ssr-local:d28gmr-1778407456
pre_compose_image=nuxt-ssr-local:d2db418
pre_image_id_prefix=sha256:105bd197347c4
health_poll_1=running starting
health_poll_2=running starting
health_poll_3=running healthy
post_compose_image=nuxt-ssr-local:d28gmr-1778407456
post_image_id_prefix=sha256:f2a000c5214d2
compose_backup=/opt/incomex/docker/docker-compose.yml.pre-d28-gmr-1778407785
output_backup=/opt/incomex/deploys/nuxt-output.prev-d28-gmr-1778407785
nuxt_healthy=true

Post-deploy container:

nuxt-ssr-local:d28gmr-1778407456 sha256:f2a000c5214d298b8f326aa3d6a57819ef9ea76725fcbb0e1f6f7267471087d6 running healthy

5. Public Verification

Public curl from local

public_url_status=200
public_url_final=https://vps.incomexsaigoncorp.vn/knowledge/registries/event_outbox
public_url_bytes=384320
curl_marker_nuxt=true
curl_marker_fallback=false

Public curl from VPS

status=200
final=https://vps.incomexsaigoncorp.vn/knowledge/registries/event_outbox
bytes=384320
fallback_marker=false

Deployed artifact contains mapping

/opt/incomex/deploys/nuxt-output/server/chunks/build/table-maps.generated-DPEPzt3k.mjs:
  "event_outbox": "tbl_event_outbox"

/opt/incomex/deploys/nuxt-output/public/_nuxt/zvuUxzEF.js:
  event_outbox:"tbl_event_outbox"

Chrome/browser automation

URL:

https://vps.incomexsaigoncorp.vn/knowledge/registries/event_outbox

Browser result:

{
  "httpStatus": 200,
  "finalUrl": "https://vps.incomexsaigoncorp.vn/knowledge/registries/event_outbox",
  "title": "Registry - Incomex AI Portal",
  "fallbackPresent": false,
  "fallbackMessageAbsent": true,
  "eventOutboxMarkerVisible": true,
  "tableCount": 1,
  "headerCount": 14,
  "rowCount": 50,
  "visibleExpectedLabelCount": 8,
  "visibleExpectedLabels": [
    "Thời điểm",
    "Phạm vi",
    "Loại sự kiện",
    "Luồng",
    "Kênh",
    "Mức độ",
    "Bảng nguồn",
    "Địa chỉ"
  ],
  "tableShellVisible": true,
  "nuxtErrorVisible": false
}

Column header inspection:

{
  "headers": [
    "STT",
    "Thời điểm",
    "Phạm vi",
    "Loại sự kiện",
    "Luồng",
    "Kênh",
    "Mức độ",
    "Bảng nguồn",
    "Đối tượng",
    "Địa chỉ",
    "Tác nhân",
    "Nguồn",
    "Phân loại payload",
    "Tạo lúc"
  ],
  "headerCount": 14,
  "exactUnsafeKeysVisible": ["payload"],
  "payloadSubstringInHeaders": ["Phân loại payload"]
}

Interpretation:

  • User-facing route now renders the event_outbox registry table/shell.
  • Missing registry fallback is absent.
  • Strict unsafe visible-text check fails because the configured safe field payload_classification currently displays label Phân loại payload, which contains the exact unsafe word payload.
  • No raw unsafe field key like safe_payload, correlation_id, or causation_id is visible.

6. Runtime Field Deny Probes

Public Directus probes:

field=safe_payload status=403 marker=denied bytes=329
field=correlation_id status=403 marker=denied bytes=333
field=causation_id status=403 marker=denied bytes=329

Result:

runtime_field_deny_smoke=PASS
permission_1483_still_safe=true

7. Final Self-Check

  1. Avoid manual hardcoding? YES — generator produced the mapping.
  2. Did generator produce event_outbox mapping? YES.
  3. Did build pass before deploy? YES.
  4. Did deploy touch only Nuxt? YES — no Directus/PG/agent-data/Qdrant/nginx mutation.
  5. Did Chrome/browser verify actual public URL? YES.
  6. Is fallback message gone? YES.
  7. Are unsafe fields absent? NO under strict visible-text rule; payload appears in label Phân loại payload.
  8. Is permission #1483 still safe? YES.
  9. Was rollback not executed automatically? YES.
  10. Was full report uploaded? YES after upload step.

Required Status Fields

phase_status=PARTIAL
pre_image=nuxt-ssr-local:d2db418
post_image=nuxt-ssr-local:d28gmr-1778407456
generated_map_before_contains_event_outbox=false
generated_map_after_contains_event_outbox=true
generated_map_after_maps_event_outbox_to_tbl_event_outbox=true
build_pass=true
deploy_performed=true
nuxt_restarted=true
public_url_status=200
chrome_verification=FAIL
fallback_message_absent=true
event_outbox_table_visible=true
event_outbox_table_shell_visible=true
unsafe_fields_visible=true
unsafe_fields_visible_detail=payload word appears in visible label "Phân loại payload"
runtime_field_deny_smoke=PASS
permission_1483_still_safe=true
rollback_executed=false
rollback_recommended=false
next_required_pack=P3D4C2U_UNSAFE_FIELDS_LEAK_INVESTIGATION