IU Core 1500x — Directus read-only registration package
03 — Directus read-only registration package
1. Boundary held
The PG -> Directus -> Nuxt assembly contract requires every Nuxt screen to read IU Core data via Directus, never directly from PG. This macro builds the read-only registration package for that Directus collection — not the Nuxt code, not the Directus runtime call.
The package is data-only: a JSON-serialisable artifact a Directus admin (or the next deploy-gated slice) can apply via the standard Directus REST/SDK paths. No Nuxt logic, no Directus client in this module, no permission bypass.
2. v_ui_iu_directus_registration_envelope — the discovery view (durable)
Migration 021 added a read-only view that introspects information_schema.columns for v_ui_iu_three_axis_envelope and returns the deterministic field list:
| field | source | purpose |
|---|---|---|
field_name |
c.column_name |
Directus field id |
pg_type |
c.data_type |
discriminator for Directus type map |
pg_udt |
c.udt_name |
discriminator for array / udt |
is_nullable |
c.is_nullable |
Directus required flag |
ordinal_position |
c.ordinal_position |
sort + tab ordering |
axis_group |
CASE on column_name |
primary / axis_a / axis_b / axis_c / meta |
Live evidence — 16 fields, every axis group populated (unit_id, canonical_address, unit_kind, section_type, lifecycle_status, axis_a_doc_code, axis_a_sort_order, axis_a_section_code, axis_b_tags, axis_b_tags_by_source, axis_c_parent_id, axis_c_depth, axis_c_ancestors, axis_c_ancestor_addresses, created_at, updated_at).
The view is the SSOT — the field list is never hand-typed in Python, SQL or Nuxt. Adding a field to v_ui_iu_three_axis_envelope automatically propagates to the registration package.
3. directus_registration.py — the package builder
build_registration_package(executor, collection_name=DIRECTUS_THREE_AXIS_COLLECTION) reads the envelope view and returns a frozen DirectusRegistrationPackage. Three payload methods produce the bodies for the Directus REST/SDK calls — the operator (not this module) issues them:
directus_collections_payload()-> body forPOST /collections. Marks the collection read-only by convention (sort onaxis_a_sort_order,accountability=all,icon=schema).directus_fields_payload()-> bodies forPOST /fields/<collection>, one per field. Each carriesreadonly=true,sort=ordinal_position,required=NOT is_nullable, axis-group note. The unit_id field is flagged primary.directus_permissions_payload()-> READ-only permission objects, one per role inDIRECTUS_ROLE_HINTS = (administrator, viewer, editor). The operator chooses which roles to grant.
A deterministic JSON serialiser (as_json()) makes the package diffable in git. The Directus type map is derived from the pg_type/udt (uuid -> uuid, jsonb -> json, ARRAY/_text/_uuid -> json, timestamp* -> dateTime, integer kinds -> integer, else string).
4. Disable / rollback path
build_disable_package(collection_name) returns DELETE /collections/<name>. The Directus REST DELETE cascades the fields + permissions metadata. The underlying PG view is never touched.
5. CLI surface
DIRECTUS_REGISTRATION_COMMANDS registers two one-commands (no IO):
dot_iu_directus_three_axis_register_plan— prints the registration package JSON for operator review.dot_iu_directus_three_axis_disable_plan— prints the disable package JSON.
6. What is NOT in this macro
- The Directus REST calls themselves (deploy-gated; operator action).
- The Directus admin permissions grant (operator chooses roles).
- Any Nuxt screen — doc 04 handles the assembly contract.
7. Sandbox/200 — registry + envelope probe (10/10 PASS)
S1 register new collection (planned) - PASS S2 re-register flips status (idempotent) - PASS S3 refuse re-dimension (immutable identity) - PASS S4 refuse empty actor - PASS S5 refuse invalid distance metric (Hamming) - PASS S6 reversible retire - PASS S7 re-register resurrects retired row - PASS S8 envelope view returns >=12 fields - PASS S9 every axis group covered - PASS S10 refuse retire on unknown collection - PASS
All 10 inside one BEGIN...ROLLBACK on production. Zero durable rows written by sandbox/200.