D28 — Generated Table Map Implementation Report (Phase 1B)
D28 — Generated Table Map Implementation Report (Phase 1B)
Date: 2026-05-10 Agent: Claude Opus 4.7 (1M ctx) — host SSH + git + nvm node Mode: Phase 1B implementation (rev8 prompt) — HOST_NODE_MJS_NO_DEPS — NO DEPLOY Linked prompt:
knowledge/dev/laws/dieu28-trien-khai/prompts/d28-generated-table-map-implementation-prompt.mdrev8 Linked design:knowledge/dev/laws/dieu28-trien-khai/design/d28-generated-table-map-design.mdStatus ceiling: PARTIAL_UNTIL_BUILD_VERIFY (per rev8)
Execution model
execution_model=HOST_NODE_MJS_NO_DEPS
Host Node 20.20.1 via nvm at /root/.nvm/versions/node/v20.20.1/bin/node. Node not in default PATH — invoked via absolute path. No container exec. No package install. No lockfile change.
Preflight
host_node_version=v20.20.1 (via /root/.nvm/versions/node/v20.20.1/bin/node)
host_node_fetch_available=FETCH_OK
host_repo_clean=YES (empty porcelain at preflight)
head_commit_at_preflight=704ff74209f571262c252f5e172b5beba7963094
branch=main
env_file_present=ENV_FILE_OK
token_key_present=TOKEN_KEY_PRESENT=true
url_key_present=URL_KEY_PRESENT=true
token_runtime=TOKEN_RUNTIME=true
url_runtime=URL_RUNTIME=true
tableIdMap_before=18 entries (hardcoded in pages/.../[entityType]/index.vue lines 39–58)
collectionMap_before=21 entries (hardcoded in config/detail-sections.ts L227–248)
relations_mirror_before=14 entries (hardcoded COLLECTION_ENTITY_MAP in server/api/discovery/relations.get.ts L20–35) — drift vs collectionMap (missing 7)
live_total_rows=21
live_status_values=['published','draft','active']
production_statuses=['active','published']
live_production_rows=20
excluded_rows_by_status=[{table_id:'tbl_event_outbox',status:'draft'}]
file_snapshot_lines=index.vue:375 detail-sections.ts:264 relations.get.ts:114 package.json:75 .gitignore:15
Implementation
generator_extension=.mjs
generator_path=web/scripts/generate-table-maps.mjs
generator_dependencies=node_builtins_only (fetch, crypto, fs, path, url)
package_install_used=false
env_names_supported=['NUXT_DIRECTUS_SERVICE_TOKEN','DIRECTUS_ADMIN_TOKEN','NUXT_PUBLIC_DIRECTUS_URL','DIRECTUS_PUBLIC_URL','DIRECTUS_URL']
artifact_path=web/generated/table-maps.generated.ts
artifact_size_bytes=2897
tableIdMap_entries=18
collectionMap_entries=21 (18 from registry + 3 STATIC_EXTRAS)
reverseCollectionMap_entries=21 (literal emit)
content_hash=sha256:8e92a1a781b549b0142c9d729d86a49318824cff2470a4f7c52fc86050799cb9
e4_overrides_used=7 (tbl_meta_catalog→catalog, tbl_table_registry→table, tbl_proposals_list→table_proposal, tbl_tasks_list→task, tbl_modules_list→module [later dropped on dedup], tbl_system_issues→system_issue, tbl_registry_ui_pages→page)
e4_convention_derived=12 (workflow, workflow_step, wcr, dot_tool, collection, agent, module via tbl_registry_modules, checkpoint_type, checkpoint_set, entity_dependency, checkpoint_instance, changelog)
overrides_added_vs_prompt_baseline=tbl_registry_ui_pages→page (required to preserve current Nuxt route /knowledge/registries/page; convention would yield 'ui_page' which would break URL lookup)
skipped_rows_with_reason=
- tbl_event_outbox: status=draft excluded
- tbl_workflow_timeline: in SKIP list (duplicate collection workflow_steps)
- tbl_modules_list: duplicate entityType=module, lost to canonical tbl_registry_modules (data quality flag — collection field='tasks' is suspicious; preserved hardcoded behavior modules→module)
static_extras_used={trigger:'trigger_registry', comment:'task_comments', taxonomy:'taxonomy'}
static_extras_are_legacy_exceptions=true
static_extras_must_not_expand_without_D28_design_review=true
draft_included=NO (default mode; --include-draft flag implemented)
artifact_leak_check=PASS (grep -i -E 'http[s]?://|bearer|authorization' returned empty)
artifact_no_url=true
artifact_no_token=true
server_import_alias_precheck=TILDE_FOUND (~/server/utils/* used in 5 sibling server/api files; safe to use ~/generated/...)
server_import_final_verification=NEEDS_BUILD_VERIFY (deferred to D28_DEPLOY_BUILD_VERIFY_PACK)
Modes implemented
- default (no flag) → fetch + write artifact (excludes draft)
--check→ recompute hash, compare withcontent_hash=...line in existing file, exit 1 on mismatch--print-hash→ print SHA-256 only--include-draft→ include status=draft for preview
Conflict resolution policy
When two rows resolve to the same entityType, the canonical one wins by table-id pattern priority: tbl_registry_* (0) > tbl_*_list (1) > tbl_* (2). Lower priority value wins. Loser tracked in skipped_rows_with_reason. STATIC_EXTRAS conflict with derived map → throws (build break). Reverse collection collisions → throws.
Consumer changes
| File | Change |
|---|---|
web/pages/knowledge/registries/[entityType]/index.vue |
Added import { tableIdMap } from '~/generated/table-maps.generated';. Removed local 18-entry hardcoded tableIdMap. Kept const tableId = computed(...). |
web/config/detail-sections.ts |
Replaced local 21-entry collectionMap and the Object.fromEntries(...) reverse derivation with export { collectionMap, reverseCollectionMap } from '~/generated/table-maps.generated';. |
web/server/api/discovery/relations.get.ts |
Added import { reverseCollectionMap } from '~/generated/table-maps.generated'; at top. Replaced 14-entry COLLECTION_ENTITY_MAP with const COLLECTION_ENTITY_MAP: Record<string, string> = reverseCollectionMap; (server alias verified). Eliminates pre-existing 7-entry drift vs collectionMap. |
web/package.json |
Added "generate:table-maps": "node scripts/generate-table-maps.mjs" and "verify:table-maps": "node scripts/generate-table-maps.mjs --check". No prebuild. No new dependency. |
web/.gitignore |
Not modified (no rule ignored generated/; commit goes through). |
Verify
check_verify=PASS (CHECK_OK, exit 0; pre-commit and post-commit)
syntax_check_mjs=PASS (node --check; both local and VPS)
build_typecheck_status=NOT_RUN_RUNTIME_CONTAINER_NO_SOURCE_AND_HOST_NO_DEPS
Build/typecheck deferred — host has no Nuxt deps installed and production container has no source code. Phase 1B = sources committed only.
CI
ci_token_status=UNKNOWN_NOT_VERIFIABLE (workflows not modified in this pack)
ci_check_status=NOT_MODIFIED
CI workflow update deferred to follow-up pack.
Git (host)
host_repo=/opt/incomex/docker/nuxt-repo
expected_files_only=true
files_in_commit=
- web/scripts/generate-table-maps.mjs (NEW; auto-snapshot picked up at 0947613)
- web/generated/table-maps.generated.ts (NEW; auto-snapshot picked up at 0947613)
- web/pages/knowledge/registries/[entityType]/index.vue (MOD; in d2db418)
- web/config/detail-sections.ts (MOD; in d2db418)
- web/server/api/discovery/relations.get.ts (MOD; in d2db418)
- web/package.json (MOD; in d2db418)
lockfile_changed=false (verified: no diff in pnpm-lock.yaml/package-lock.json/yarn.lock)
git_commit_created=YES (split across 2 commits due to host auto-snapshot timing)
git_commit_hash_main=d2db418 (4 file modifications, manual D28 commit)
git_commit_hash_autosnapshot=0947613 (2 new files: generator script + generated artifact, captured by host auto-snapshot at 2026-05-10T04:00 timestamp label; actual files created during this session at host time ~05:58)
note_on_split_commit=Auto-snapshot mechanism on /opt/incomex/docker/nuxt-repo committed the 2 new files before the manual D28 commit could include them. Both commits together represent the D28 Phase 1B atomic change. Branch diverged from origin/main is expected per project memory (VPS is SSOT, edit host directly, never git pull).
branch=main
Deploy
deployed=NO
live_route_smoke=SKIPPED_NO_DEPLOY
Attestation
no_deploy=true
no_live_route_smoke=true
no_directus_mutation=true
no_pg_mutation=true
no_publish_event_outbox=true
no_table_registry_mutation=true
no_secret_printed=true (no token, URL, env value, Authorization header, response body, or artifact content printed during execution)
no_npx_auto_install=true
no_package_install=true
no_lockfile_change=true
no_container_restart=true
no_docker_compose_restart=true
no_external_deps_in_generator=true
Status
phase1b_status=PARTIAL
best_possible_status=PARTIAL_UNTIL_BUILD_VERIFY
follow_up_packs=
- D28_DEPLOY_BUILD_VERIFY_PACK (mandatory: server import + build/typecheck verification; smoke test 21 routes)
- D28_CI_TOKEN_SETUP_PACK (if CI not configured; add NUXT_DIRECTUS_SERVICE_TOKEN secret + verify:table-maps step)
- Optional: data fix pack for tbl_modules_list.collection='tasks' (likely should be 'modules')
- P3D notification display resume (after build verify + tbl_event_outbox publish)
rollback_command=ssh contabo "cd /opt/incomex/docker/nuxt-repo && git revert d2db418 0947613 --no-edit"
Notes / deviations
- Host Node not in default PATH. Node binary located at
/root/.nvm/versions/node/v20.20.1/bin/node(nvm). All script invocations used absolute path. Did not source nvm.sh in non-interactive ssh. - Override addition vs prompt rev8 baseline. Added
tbl_registry_ui_pages → pageto OVERRIDES because the convention ruletbl_registry_<X> → singularize(X)yieldsui_page, but Nuxt URL routes use/knowledge/registries/page(entityType=page). Without this override,tableIdMap['page']would be missing and the page route would silently break. This is required to preserve current behavior; documented in script comment and in this report. - Auto-snapshot interaction. The host repo has an auto-snapshot mechanism that committed the 2 new files before the manual commit could capture all 6/7 files atomically. The two commits together (
0947613+d2db418) compose Phase 1B. Rollback requires reverting both. tbl_modules_listdata flag.collection='tasks'for this row is almost certainly wrong (should bemodules). Generator dropped this row in dedup (entityType=module won bytbl_registry_modules, which has correctcollection='modules'). Behavior preserved. Data fix should be a separate pack.- PASS not claimed. Per rev8 ceiling, build/typecheck not runnable in Phase 1B → max status PARTIAL.
D28 Phase 1B Implementation Report | Rev3 | HOST_NODE_MJS_NO_DEPS | NO DEPLOY | PARTIAL | 2026-05-10