23-P3D4B — Directus DOT Notification Read-Only Exposure — Package Review Note
23-P3D4B — Directus DOT Notification Read-Only Exposure — Package Review Note
Date: 2026-05-08 Status: PACKAGE REVIEW (non-executable). NO implementation. NO mutation. Source prompt:
knowledge/dev/laws/dieu44-trien-khai/prompts/23-p3d4b-directus-dot-notification-readonly-exposure-prompt.md(rev2) Upstream decisions inherited from:23-p3d4-directus-notification-exposure-review.md(Option C locked),23-p3d4-directus-exposure-design-review-report.md(PASS).
A. Điều 43 / DOT Inventory Results
A.1 Inventory depth
dieu43_inventory_depth = KB_ONLY— bounded KB search only; no Directus item-level introspection performed (read-only API was already inventoried in P3D4 upstream, no need to re-fetch).- Sources consulted:
constitution.md; KB search ondieu43,dot,directus,counter,relationship; existing DOT description-contract doc (du-thao-description-governance-package-fix27.md).
A.2 What Điều 43 actually is
- Per
constitution.md: Đ43 v1.2 FINAL = "Luật Bản đồ Hệ thống" (System Context Law). Domain: system-context bootstrap, context-pack/living-doc registration. - Điều 43 does not own notification, counting, or relationship semantics. It owns context-pack registration only.
- Therefore: there is no Đ43 DOT format/template specifically for notifications that P3D4B must adopt. Đ43 only kicks in if P3D4C later registers new artifacts (e.g. a context pack pointing at the new view) — that registration is downstream and deferred.
A.3 Existing DOT conventions found (REUSABLE)
- DOT registry table:
dot_tools(PG). Columns observed in KB:name,trigger_type,cron_schedule,operation,paired_dot,file_path. - DOT description contract (Description Governance R2 FINAL / Fix 27): 3-part template
[MỤC ĐÍCH] = name[TRIGGER→OUTPUT] = trigger_type + cron_schedule + operation[PAIRED DOT] = paired_dot
- Paired-DOT discipline (NT12, constitution): writer ↔ verifier. User MEMORY confirms current pattern: e.g.
DOT-HC-EXECUTOR ↔ DOT-HC-EXECUTOR-VERIFY. - PG-Native First (NT13): new mechanisms must justify against built-in PG; a plain
VIEWqualifies as native. - No notification-specific DOT template exists yet. P3D4B is the first of its kind, so we adopt the generic 3-part contract + paired pattern.
A.4 Counting / relationship pattern reuse
- The candidate view's
read_countis computed asCOUNT(DISTINCT actor_ref)againstiu_notification_readperevent_id— i.e. reuses an existing PG-native aggregation pattern. No separate counter table, no rollup, no trigger-maintained denormalization. - This is consistent with PG-Native First and avoids inventing a new counting subsystem.
A.5 Đ43 blockers
- None blocking P3D4B. Đ43 schema concerns (context-pack registration) are out of scope; a follow-up pack may register the view-cum-context-pack later, but P3D4B does not need that to land.
A.6 Verdict
dieu43_dot_inventory = PASS(bounded; depth = KB_ONLY)existing_dot_conventions_checked = PASSreusable_dot_template = FOUND(Description Governance R2 / 3-part contract + NT12 paired)reusable_counting_pattern = FOUND(PG-native COUNT DISTINCT oniu_notification_read)
B. Candidate PG View — NON-EXECUTABLE SKETCH
⚠️ This is a sketch, not runnable SQL. Column types, exact
LATERALsyntax, and ordering tie-breakers must be re-validated at P3D4C. Do not copy-paste-execute.
B.1 Identity
- Candidate name:
v_iu_notification_board(inherited from P3D4 review). - Confirmed (P3D4 inventory): no view matching
%notif%exists yet.
B.2 Scope decision
view_scope = HISTORY- Justification: Phase 1 is human monitoring / oversight, not actor-specific actionable inbox. ACTIONABLE would require defining "resolved" (applied draft? read by all? acknowledged?) which is undefined in current schema. PAIR (current+history) doubles surface area without a Phase 1 caller. HISTORY is the minimum sufficient surface.
- ACTIONABLE filter is deferred; a future view can be added without breaking HISTORY consumers.
B.3 Payload strategy
payload_strategy = OMIT_RAW_PAYLOAD- Justification:
payload jsonb NN default '{}'may carry future fields whose sensitivity is not yet classified. Phase 1 does not need any payload field. SANITIZED_REFS would require enumerating safe keys perevent_type, which is design surface we don't need yet. - If a future caller demands refs (e.g.
draft_id,comment_id), upgrade to SANITIZED_REFS in a separate review (not P3D4B, not P3D4C).
B.4 Column sketch (metadata-only, body-free)
| Column | Source | Notes |
|---|---|---|
event_id |
iu_notification_event.id |
uuid |
event_type |
e.event_type |
constrained: `comment_added |
event_stream |
e.event_stream |
constrained: `comment |
unit_id |
e.unit_id |
uuid; FK to information_unit (no body join) |
canonical_address |
e.canonical_address |
text; already-sanitised by construction |
ref_id |
e.ref_id |
uuid; opaque ref, not joined |
actor_ref |
e.actor_ref |
originating actor (text) |
source |
e.source |
text |
created_at |
e.created_at |
timestamptz |
read_count |
COUNT(DISTINCT r.actor_ref) over iu_notification_read r WHERE r.event_id = e.id |
computed per row, no stored counter |
latest_readers |
top-5 r.actor_ref ordered by r.read_at DESC, r.actor_ref ASC (tiebreak), JSON array |
computed via LATERAL |
Forbidden columns (must NOT appear):
payload(raw jsonb) — OMIT_RAW_PAYLOADinformation_unit.body,unit_version.body— body-content boundary- Any token/secret/email/PII not already in
iu_notification_event
B.5 Owner / GRANT sketch (descriptive, not a grant)
- Owner:
directus - Future GRANT (executed by P3D4C, not here):
GRANT SELECT ON v_iu_notification_board TO directus;— no PUBLIC, no anon. - Rollback shape:
REVOKE SELECT ... ; DROP VIEW IF EXISTS v_iu_notification_board;(DOT-driven).
B.6 Non-executable fence
NON-EXECUTABLE SKETCH — DO NOT RUN
view: v_iu_notification_board
from: iu_notification_event e
left lateral: (
select
count(distinct r.actor_ref) as read_count,
array(
select r2.actor_ref
from iu_notification_read r2
where r2.event_id = e.id
order by r2.read_at desc, r2.actor_ref asc
limit 5
) as latest_readers
from iu_notification_read r
where r.event_id = e.id
) agg on true
select e.id as event_id, e.event_type, e.event_stream, e.unit_id,
e.canonical_address, e.ref_id, e.actor_ref, e.source, e.created_at,
coalesce(agg.read_count, 0) as read_count,
coalesce(agg.latest_readers, '{}') as latest_readers
-- payload OMITTED. body OMITTED. no joins to information_unit/unit_version.
candidate_view_defined = PASS.
C. Candidate Directus DOT Outline — NON-EXECUTABLE
⚠️ Candidate outline only. No DOT package file is to be created in production by P3D4B.
C.1 DOT pair (NT12)
- Primary (writer/applier):
DOT-NOTIF-BOARD-EXPOSE— registersv_iu_notification_boardas a Directus collection (read-only) and grantsreadtonotif_board_reader. - Verifier (paired):
DOT-NOTIF-BOARD-EXPOSE-VERIFY— checks: (i) view exists in PG, (ii) Directus collection registered, (iii) onlynotif_board_readerhasreadperm and nocreate/update/delete, (iv) no admin grant other than baseline, (v) no body column leaked. - Registry rows in
dot_toolswould carrypaired_dotcross-link (NT12 satisfied).
C.2 Description (3-part contract per Description Governance R2)
[MỤC ĐÍCH]: Expose IU notification board (read-only) to Directus for human monitoring (Phase 1).[TRIGGER→OUTPUT]:manualtrigger →DIRECTUS_COLLECTION_EXPOSEoperation; idempotent.[PAIRED DOT]:DOT-NOTIF-BOARD-EXPOSE-VERIFY.
C.3 Role strategy
role_strategy = REUSE_EXISTINGif a generic read-only board role already exists, otherwiseNEW_ROLE_RECOMMENDEDfornotif_board_reader.- P3D4 review concretely proposed
notif_board_reader. Inventory shows no current grant (MCP 403 on item-level), suggesting no analogous role exists. Recommendation for this package:NEW_ROLE_RECOMMENDED—notif_board_reader, scoped toreadon the new view (and minimal projection ofiu_notification_event/iu_notification_readonly if Directus auto-discovery cannot be confined to the view). - Justification for new role: existing roles (admin, public, MCP service) are either too broad or unrelated to monitoring. A dedicated role keeps blast radius minimal and revocation atomic.
- This recommendation is to be finalised in P3D4C, not committed in P3D4B.
C.4 Permission grant description (NOT executed)
readONv_iu_notification_boardTOnotif_board_reader.- Optional
readoniu_notification_event,iu_notification_read(only if needed; prefer view-only). - Forbidden:
create | update | deleteon any of the three to non-admin roles. Forbidden: any grant topublic/ anonymous.
C.5 Phase boundaries (deferred items, NOT in P3D4B/P3D4C)
- Mark-read flow (
fn_iu_mark_read) — DEFERRED. - Per-actor unread/inbox (
fn_iu_unread) — DEFERRED. - Directus user →
actor_refmapping — DEFERRED. - Nuxt page wiring / Đ28 display review — DEFERRED.
- Hermes — DEFERRED (
BLOCKED_PENDING_REVIEW).
C.6 Quiet period
- 24–48h between successful P3D4C grant and any stacking package (e.g. mark-read), per upstream P3D4 directive.
candidate_dot_outline_defined = PASS.
D. Reuse / Overlap Assessment
| Concern | Verdict |
|---|---|
| Existing DOT description contract (3-part) | REUSED |
| NT12 paired-DOT pattern | REUSED |
PG-Native counting (COUNT DISTINCT on iu_notification_read) |
REUSED |
| Existing role for read-only board | NOT FOUND → new role justified |
| Đ43 (System Context Law) overlap | NONE — different jurisdiction |
| Đ43 schema blockers | NONE relevant to P3D4B |
| Counting subsystem duplication | NONE (no separate counter table) |
| Body-content exposure risk | MITIGATED by OMIT_RAW_PAYLOAD + no body join |
| Law jurisdiction overlap | NONE (Đ7 Assembly First + Đ35 DOT Governance only) |
overlap_risk = LOW.
dieu43_blockers_summary = "No Đ43 jurisdiction over notification view; Đ43 covers context-pack registration which is out of P3D4B scope. No schema repair needed."
E. Phase Boundaries (restated)
- Phase 1 (P3D4C): create view + register Directus collection + grant
notif_board_reader.read. Read-only. - Phase 2 (separate review): mark-read + actor mapping.
- Phase 3 (separate review): Nuxt assembly via Đ28.
- Hermes: out of scope across all phases until separately unblocked.
F. Go / No-Go Gate for P3D4C
| Gate | Status |
|---|---|
overlap_risk = LOW |
✅ |
| DOT convention/template identified | ✅ (3-part description contract + NT12 pair) |
view_scope decided |
✅ HISTORY |
payload_strategy decided |
✅ OMIT_RAW_PAYLOAD |
| No hard-boundary violation in candidate design | ✅ |
go_nogo_gate = GO.
G. Recommendation
recommendation = READY_FOR_IMPLEMENTATION_PROMPT
Next pack: P3D4C_PG_VIEW_AND_DIRECTUS_DOT_IMPLEMENTATION_PROMPT_REVIEW.
P3D4C must:
- Author the executable
CREATE VIEW v_iu_notification_board ...(still review, not yet run). - Author the paired DOT package (
DOT-NOTIF-BOARD-EXPOSE+-VERIFY) targeting Directus collection registration + role grant. - Confirm role decision (REUSE vs NEW) against current Directus inventory at execution time.
- Carry rollback (
REVOKE+DROP VIEW) and quiet-period clause (24–48h).
H. Compliance Checklist
PG source of truth: PASS
Directus DOT-only (no UI clicks): PASS
Directus UI view-only (read): PASS
Metadata-only (no body): PASS
No Điều 43 DOT overlap: PASS
No duplicate counting: PASS
No law jurisdiction overlap: PASS
Assembly First respected: PASS
No Nuxt code: PASS
Non-executable artifacts only: PASS
P3D4B rev2 — Package review note. Non-executable. No mutation. Awaits final user/GPT review before P3D4C is dispatched.