IU Core 4000x — 05 Real user flow smoke (Directus REST + Qdrant)
05 — Real user flow smoke · Directus REST + Qdrant retrieval
1. Goal
Prove that an end-user authored against the 1500x assembly contract — the Vue page in the 4000x UI package — would actually see the three-axis envelope rows / hierarchy / vector retrieval, by exercising the same Directus REST + Qdrant probes the page issues, from outside the Nuxt container.
2. Directus REST — count + per-axis filter
GET /items/iu_three_axis_envelope?aggregate[count]=* returns {"data":[{"count": "163"}]} — matches the PG cache (163).
GET /items/iu_three_axis_envelope?limit=1&filter[axis_c_depth][_eq]=0 returns first IU with canonical_address=D38-DIEU35-S1, axis_c_parent_id=null, axis_b_tags={unit_kind, section_type, legal_document}, axis_c_ancestors length 1 (self).
GET /items/iu_three_axis_envelope?limit=1&filter[axis_c_depth][_eq]=2 returns canonical_address=D38-DIEU35-S4-P1-1 with axis_c_parent_id set, axis_c_ancestors length 3 (root → middle → self), axis_c_ancestor_addresses=[S4, S4-P1, S4-P1-1].
All three calls executed via docker run --rm --network docker_incomex curlimages/curl with the live NUXT_DIRECTUS_SERVICE_TOKEN (read-only at this collection per 2400x permission row). HTTP 200; payload shapes match the Vue page's column expectations.
3. Qdrant per-IU boundary re-prove
POST /collections/iu_core_iu_chunks/points/scroll {"limit": 3, "with_payload": true} sampled three points; every payload carries:
unit_id(uuid)chunk_index+chunk_countaxis_refs: {source_axis_ref, semantic_axis_ref, hierarchy_axis_ref}
KT-B unit d3ad5874-9e32-4179-b6f6-586722288278 returns chunk 1 / 2 — the only multi-chunk IU in the corpus, splitting inside its own boundary. Other sampled IUs return chunk 0 / 1 (single chunk per IU). The full scroll over 200 points (4000x §A initial audit) confirms 61 total points / 60 unique unit_ids; exactly one IU has 2 chunks.
This is the per-IU vector boundary guarantee from 120x / 1k_plus / 1500x / 2000x carried forward into 4000x unchanged. No cross-IU vector. No sliding embedding window. Every chunk carries the full axis ref triple.
4. Drift-gated refresh / cache_healthy
SELECT * FROM v_iu_three_axis_envelope_refresh_status returns last_actor=iu_core_3000x_runtime_330_smoke, last_outcome=skipped_in_sync, current_drift={"in_sync": true, "view_count": 163, "table_count": 163}, current_in_sync=t, current_view_count=163, current_table_count=163, cache_healthy=t.
(The 4000x runtime/340 smoke then added a more recent row under actor='iu_lifecycle_trigger' with outcome='skipped_in_sync'.)
5. End-user-flow coverage matrix
| Flow | Proof method | Outcome |
|---|---|---|
| List 163 three-axis envelope rows | GET /items/...?aggregate[count]=* |
163 ✓ |
| Filter axis A by source doc | ?filter[axis_a_doc_code][_eq]=DIEU-35 returns rows |
✓ (implicit via depth=0/2 probes both returning axis_a_doc_code: DIEU-35) |
| Filter axis B by tag | ?filter[axis_b_tags][_contains]=... (URL-encoded) |
shape confirmed by reading the axis_b_tags jsonb |
| Open hierarchy / subtree | ?filter[axis_c_depth][_eq]=N + axis_c_ancestors array |
✓ root + depth-2 |
| Inspect Qdrant retrieval | POST scroll returns per-IU chunks with axis_refs |
✓ |
| Inspect refresh / drift status | SELECT * FROM v_iu_three_axis_envelope_refresh_status |
cache_healthy=t ✓ |
| Render / export a composed file | dot_iu_render_file (500x command) over a piece collection |
n/a in 4000x (no new authored collection) — covered by 500x runtime/270 durable proof |
The only flow not proven against the actual Nuxt route is "open the /admin/iu-three-axis URL in a browser" — covered by the package authoring + deploy residual recorded in doc 03.