KB-56DE rev 4

P3D4C2U — Resume Notification Display — Agent Prompt (REVIEW DRAFT Rev4)

14 min read Revision 4

P3D4C2U — Resume Notification Display — Agent Prompt (REVIEW DRAFT Rev4)

Date: 2026-05-10 | Rev: 4 | 0F generated-map gate → informational (chicken-and-egg: draft excluded from map, route works independently). 0G/0H route evidence → hard gates. Field-security rev3 giữ nguyên. Status: DRAFT — chờ GPT/User review trước khi dispatch Audience: Agent claude-go (1 row publish + read-only smoke + optional API deny smoke) Predecessor: D28_DEPLOY_PARTIAL_FIX_PACK PASS (2026-05-10, prompt rev6, image d2db418) Critical: Mutation duy nhất = 1 row status (draft → published). No deploy/restart/build.


⚠️ Cảnh báo

  • Mutation duy nhất: table_registry row 21 status: draft → published.
  • KHÔNG: deploy, restart, build, compose edit, Nuxt code, PG schema, widen permission, event core trigger, UI component, bespoke notification page, Điều 43, TAC resume, auto-rollback.
  • Sau pack: notification_display_checkpoint=unblocked. TAC resume = pack tiếp theo.

Tham chiếu KB

Predecessor: knowledge/dev/laws/dieu28-trien-khai/reports/d28-deploy-partial-fix-pack-report.md
Option D report (field classification SSOT): search KB "Option D" or "P3D4C2U Option D"
This report: knowledge/dev/laws/dieu44-trien-khai/reports/p3d4c2u-resume-notification-display-report.md

CHECKPOINT đầu prompt

  1. Đọc Fix Pack report → phase_status=PASS.
  2. Đọc Stage 2 report → production_running_under_d2db418=true, page_routes=18/18.
  3. search_knowledge DOT tool ("DOT table_registry publish").
  4. Verify Directus admin token available (no print).

Predecessor mismatch → STOP PREDECESSOR_DRIFT.


Field classification (rev3 — UNCHANGED in rev4)

Permission #1483 ALLOWLIST — 14 fields

id, occurred_at, created_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

Registry visible — 13 fields (DirectusTable auto-adds id)

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

DENYLIST (rev3 corrected — safe_payload/correlation_id/causation_id are DENIED)

safe_payload, correlation_id, causation_id,
payload, body, raw_payload, payload_raw, vector, embedding,
secret, token, password, ssn, personal_data, internal_*, admin_only

Phase 0 — Preflight (12 gates: 10 hard + 1 informational + 1 optional)

0A. D28 chain state (HARD)

ssh contabo "docker compose -f /opt/incomex/docker/docker-compose.yml ps nuxt --format '{{.Image}}'"
ssh contabo "grep -E 'image:.*nuxt-ssr-local' /opt/incomex/docker/docker-compose.yml"

Expected: nuxt-ssr-local:d2db418, count=1.

0B. Relations endpoint (HARD)

TS_LOG=$(date +%s); RESPFILE="/tmp/p3d-relations-$TS_LOG.txt"
STATUS=$(ssh contabo "curl -s -o $RESPFILE -w '%{http_code}' '<base_url>/api/discovery/relations?collection=workflow_steps' --max-time 10")
ssh contabo "chmod 600 $RESPFILE"; ssh contabo "grep -qi 'token\|secret\|bearer\|password\|authorization' $RESPFILE && echo SCAN=FAIL || echo SCAN=PASS"
ssh contabo "rm -f $RESPFILE"

Expected HTTP 200. FAIL → STOP.

0C. tbl_event_outbox row state (HARD)

TS_LOG=$(date +%s); PRESTATE="/tmp/p3d-prestate-$TS_LOG.json"
ssh contabo "set -a; source /opt/incomex/docker/.env 2>/dev/null; set +a; curl -s -H \"Authorization: Bearer \$DIRECTUS_ADMIN_TOKEN\" \"\$DIRECTUS_PUBLIC_URL/items/table_registry/21\" > $PRESTATE 2>&1"
ssh contabo "chmod 600 $PRESTATE"
# scan + parse id=21, collection, status=draft|published
ssh contabo "rm -f $PRESTATE"

Status already publishedIDEMPOTENT_ALREADY_PUBLISHED (Phase 1D). Other unexpected → STOP.

0D. Permission #1483 (HARD — rev3 field-security)

PERMFILE="/tmp/p3d-perm-$TS_LOG.json"
ssh contabo "set -a; source /opt/incomex/docker/.env 2>/dev/null; set +a; curl -s -H \"Authorization: Bearer \$DIRECTUS_ADMIN_TOKEN\" \"\$DIRECTUS_PUBLIC_URL/permissions/1483\" > $PERMFILE 2>&1"
ssh contabo "chmod 600 $PERMFILE"
# scan + verify: id=1483, collection=event_outbox, action=read
# MUST match 14-field allowlist. MUST NOT contain denylist.
# MUST exclude safe_payload, correlation_id, causation_id (rev3)
ssh contabo "rm -f $PERMFILE"

Report: permission_matches_option_d_allowlist, permission_excludes_safe_payload/correlation_id/causation_id, permission_contains_any_denylist_field=false.

0E. Registry visible fields (HARD — rev3 P6)

REGFIELDS="/tmp/p3d-regfields-$TS_LOG.json"
ssh contabo "set -a; source /opt/incomex/docker/.env 2>/dev/null; set +a; curl -s -H \"Authorization: Bearer \$DIRECTUS_ADMIN_TOKEN\" \"\$DIRECTUS_PUBLIC_URL/items/table_registry/21?fields=*\" > $REGFIELDS 2>&1"
ssh contabo "chmod 600 $REGFIELDS"
# scan + verify no denylist fields in registry configuration
ssh contabo "rm -f $REGFIELDS"

Contains safe_payload/correlation_id/causation_id → STOP REGISTRY_FIELDS_UNSAFE_DRIFT.

0F. Generated table-map — INFORMATIONAL (rev4 — was hard gate in rev3)

ssh contabo "grep -E 'event_outbox|tbl_event_outbox' /opt/incomex/docker/nuxt-repo/web/generated/table-maps.generated.ts | head -5"

Report (rev4 — informational, does NOT block):

generated_map_has_event_outbox=true|false
generated_map_entry_expected_absent_for_draft=true (if status=draft pre-mutation)
generated_map_status_filter=active,published (generator behavior: excludes draft)
generated_map_missing_blocks_publish=false (rev4 — informational gate, NOT blocking)

Vì sao informational (rev4): Generator excludes draft rows. event_outbox status=draft → absence expected. Pack này publish row, không regenerate/rebuild. Route works independently (0G/0H evidence). Next deploy cycle sẽ regenerate map với event_outbox included.

0G. /knowledge/registries route (HARD — rev4 promoted)

TS_LOG=$(date +%s); RESPFILE="/tmp/p3d-regroute-$TS_LOG.txt"
STATUS=$(ssh contabo "curl -s -o $RESPFILE -w '%{http_code}' '<base_url>/knowledge/registries' --max-time 10")
ssh contabo "chmod 600 $RESPFILE"; ssh contabo "rm -f $RESPFILE"

HARD GATE rev4: HTTP 200 REQUIRED. Non-200 → STOP REGISTRIES_ROUTE_REGRESSION.

0H. event_outbox route pre-mutation (HARD — rev4 promoted, includes security check)

TS_LOG=$(date +%s); SMOKEFILE="/tmp/p3d-eventoutbox-pre-$TS_LOG.html"
PRE_STATUS=$(ssh contabo "curl -s -o $SMOKEFILE -w '%{http_code}' '<base_url>/knowledge/registries/event_outbox' --max-time 15")
ssh contabo "chmod 600 $SMOKEFILE"
ssh contabo "grep -qi 'token\|secret\|bearer\|password\|authorization' $SMOKEFILE && echo SCAN=FAIL || echo SCAN=PASS"

IF SCAN=PASS:

# Denylist check (rev3 corrected list)
ssh contabo "grep -qE 'safe_payload|correlation_id|causation_id|payload_raw|raw_payload|\"payload\"|\"body\"|vector|embedding|\"secret\"|\"token\"|\"password\"|ssn|personal_data|internal_|admin_only' $SMOKEFILE && echo PRE_UNSAFE=true || echo PRE_UNSAFE=false"
ssh contabo "rm -f $SMOKEFILE"

HARD GATE rev4:

  • PRE_STATUS=200 REQUIRED (route must already work pre-mutation)
  • PRE_UNSAFE=false REQUIRED (no denylist fields visible even pre-mutation)
  • Non-200 → STOP EVENT_OUTBOX_ROUTE_NOT_FUNCTIONAL_PRE_MUTATION
  • PRE_UNSAFE=true → STOP UNSAFE_FIELDS_LEAKED_PRE_MUTATION (CRITICAL — permission leak exists regardless of publish status)

Report: pre_mutation_event_outbox_status, pre_mutation_unsafe_fields_absent.

0I. No pending D28 rollback (HARD)

search_knowledge "D28 rollback_recommended". Must be false.

0J. PG event_outbox accessible (OPTIONAL per rev2 P5)

ssh contabo "docker exec postgres psql -U directus -d directus -c \"SELECT 1 FROM event_outbox LIMIT 1;\" 2>&1 || echo PG_CHECK_FAILED"

event_outbox_data_access_check=PASS|SKIPPED_NO_SAFE_METHOD.

0K. DOT discovery (INFORMATIONAL per rev2 P6)

search_knowledge "DOT table_registry publish". dot_tool_for_publish_found=true|false. false ≠ failure.

0L. D28 chain verified (HARD)

Read 3 reports: Stage 1 PASS + Stage 2 PARTIAL_PROMPT_DRIFT + Fix Pack PASS.

0M. Preflight consolidate (rev4)

PASS requires:

  • 0A, 0B, 0C, 0D, 0E, 0G, 0H (hard gates), 0I, 0L = ALL PASS
  • 0F = INFORMATIONAL (any value acceptable, INFO_EXPECTED_ABSENT_FOR_DRAFT normal)
  • 0J = PASS or SKIPPED_NO_SAFE_METHOD (optional)
  • 0K = informational (false acceptable)

ALL hard gates PASS → preflight_status=PASS.


Phase 1 — Mutation (same as rev3)

1A. Method priority: DOT > Directus API > PG direct

1B. Mutation execution (PATCH /items/table_registry/21, status: published)

Log safety. KHÔNG print body.

1C. Post-mutation verify (no auto rollback per rev2 P7)

Side effect detected → STOP + recommend rollback (NOT execute).

1D. Idempotency (status already published → skip, Phase 2)

1E. Mutation report fields (same as rev3)


Phase 2 — Smoke (same as rev3, with rev4 notes)

2A. SSR warmup: sleep 2

2B. HTTP smoke /knowledge/registries/event_outbox

Log safety. SCAN=FAIL_LEAK → STOP CRITICAL.

2C. Body checks (rev3 corrected denylist + rev2 informational markers)

CRITICAL (Tier 1): UNSAFE_FIELDS_DETECTED_IN_HTML (denylist includes safe_payload/correlation_id/causation_id) INFORMATIONAL (Tier 2): render signal, event_outbox token, empty/data state

2D. Runtime field-level API deny smoke (rev2 P8, rev3 corrected probes)

Safe request: fields=id,occurred_at,event_domain,event_type,payload_classification (allowlist fields) Deny probes: fields=safe_payload → 403, fields=correlation_id → 403, fields=causation_id → 403 SKIPPED_NO_PUBLIC_TOKEN acceptable.

2E. Cleanup

2F. Pass criteria (rev3 — unchanged)

Tier 1 ALL met → PASS (or PASS_HTTP_ONLY_WITH_INCONCLUSIVE_MARKERS if Tier 2 inconclusive).


Phase 3 — Decision & report (same as rev3)

3A. Result decision (8 outcomes unchanged)

3B. Routing matrix (unchanged)

phase_status next rollback
PASS / PASS_IDEMPOTENT / PASS_HTTP_ONLY P3D_INFORMATION_UNIT_TEXT_AS_CODE_RESUME No
FAIL_ROUTE D28_ROUTE_RESOLUTION_FIX No
FAIL_PERMISSION P3D4C2U_DIRECTUS_PERMISSION_FIX Optional
FAIL_EVENT_CORE P3D4C1U_EVENT_CORE_FIX Optional
FAIL_CRITICAL_SECURITY P3D4C2U_UNSAFE_FIELDS_LEAK_INVESTIGATION YES (no auto)
FAIL_MUTATION_SIDE_EFFECT P3D4C2U_SIDE_EFFECT_INVESTIGATION YES (no auto)

3C. Rollback: APPROVE P3D4C2U ROLLBACK: I authorize reverting tbl_event_outbox status from published back to draft.

3D. Report template (rev4 — 0F fields updated)

## Preflight
0a-0e = same as rev3
0f_generated_map_has_event_outbox=true|false (INFORMATIONAL rev4)
0f_generated_map_entry_expected_absent_for_draft=true|false
0f_generated_map_missing_blocks_publish=false (rev4)
0g_registries_route=PASS (HARD rev4)
0h_pre_mutation_event_outbox_status=200 (HARD rev4)
0h_pre_mutation_unsafe_fields_absent=true (HARD rev4)
0i-0l = same as rev3
preflight_status=PASS

All other report sections same as rev3.


Hard boundaries (13 NO_* — same as rev3)

NO_DEPLOY, NO_CONTAINER_RESTART, NO_IMAGE_BUILD, NO_COMPOSE_MODIFICATION,
NO_PG_SCHEMA_CHANGE, NO_NUXT_CODE_CHANGE, NO_WIDEN_DIRECTUS_PERMISSION,
NO_EVENT_CORE_TRIGGER_CHANGE, NO_UI_COMPONENT_CREATION,
NO_BESPOKE_NOTIFICATION_PAGE, NO_DIEU43_MODIFICATION,
NO_TAC_RESUME_IN_THIS_PACK, NO_AUTO_ROLLBACK

Mutations allowed (7 — same as rev3)

  1. PATCH 1 row table_registry id=21 status (DOT > API > PG)
  2. upload_document report
  3. ssh curl read-only (preflight + smoke + optional deny probes)
  4. ssh temp file /tmp/ (chmod 600 + remove)
  5. ssh psql read-only (0J, optional)
  6. search_knowledge
  7. (Optional) ssh curl public token (Phase 2D)

Self-check (14 items — rev4 updated)

# Phải đạt
1 D28 chain PASS verified
2 Image vẫn d2db418
3 Permission #1483 = 14-field allowlist, EXCLUDES safe_payload/correlation_id/causation_id (rev3)
4 Registry fields no denylist (rev3 P6)
5 0G registries route 200 (HARD rev4)
6 0H event_outbox route 200 + unsafe absent PRE-mutation (HARD rev4)
7 0F generated map = informational (not blocking rev4)
8 Mutation method declared, status changed, no side effect
9 Idempotency handled
10 Post-mutation smoke UNSAFE_FIELDS_DETECTED_IN_HTML=false
11 Runtime deny probes: safe_payload/correlation_id/causation_id → 403 (or SKIPPED)
12 NO auto rollback
13 Hard boundaries 13 TRUE
14 Report uploaded KB

Future improvement note (rev4)

After this pack publishes tbl_event_outbox, the static generated map (web/generated/table-maps.generated.ts) still won't include event_outbox until the next deploy cycle runs generate:table-maps + build + deploy. This is non-blocking because event_outbox route works independently (proven by 0H pre-mutation evidence). Next D28 maintenance or feature deploy will naturally include it.


P3D4C2U Resume Notification Display | Rev4 DRAFT | 0F informational (chicken-and-egg resolved), 0G/0H hard gates (route functional evidence), field-security rev3 preserved | 2026-05-10

Back to Knowledge Hub knowledge/dev/laws/dieu44-trien-khai/prompts/p3d4c2u-resume-notification-display-prompt-review.md