Summary
Authority.create/2 derives the persisted screen name from the module's last segment (AristonUi.UI.Screens.V2.Chat → "chat", V2.Explorer → "explorer", V2.Doc → "doc"), but downstream LiveViews need to look up screens by namespaced names like "v2_chat", "v2_explorer", "v2_doc" to avoid collision with potential non-v2 screens of the same short name.
The mismatch means the Postgres-first lookup branch always misses for V2 LiveViews; mount always falls back to payload_from_code_module/0. The runtime customization layer the Authority + ui_screens persistence is supposed to enable doesn't actually fire.
Where this surfaces
ash_ui/lib/ash_ui/resource/authority.ex — create/2 builds the name from module |> Module.split() |> List.last() |> Macro.underscore()
- ariston-ui operator_v2 LiveViews —
@screen_row_name "v2_chat" (and similar) in lib/ariston_ui_web/operator_v2/chat_live.ex, explorer_live.ex, map_live.ex, ask_live.ex. doc_live.ex currently uses bare "doc" (matching the Authority default) but inherits a different collision risk per the Wave C deferred-findings.
Bridge currently in place on ariston-ui
mix ariston.seed_dsl_screens was refactored during explorer R3 to accept {Module, [name: "v2_explorer"]} tuple entries in @screen_entries. This lets the seed task persist with an explicit override name that matches the LiveView lookup. V2.Chat and V2.Map are explicitly excluded from the seed task pending a coordinated fix (documented in the task moduledoc). V2.Doc uses bare "doc", which is its own different concern.
Why this can't be just an ariston-side fix
Three V2 screens currently have NO Postgres-customization path. Whatever we do on the ariston side, the issue is fundamentally that Authority.create/2 doesn't accept an explicit screen name; it derives it. So the seed-task override is a workaround that fights the API rather than using it.
Options (Pascal picks the direction)
Option A: add :name opt to Authority.create/2
Lowest-churn. Authority.create(MyScreen, name: "v2_my_screen") overrides the default-derived name; existing callers without the opt unchanged.
def create(module, opts \\ []) do
name = Keyword.get(opts, :name) || default_name_for(module)
...
end
Pros: zero existing-caller breakage; matches how :layout, :route, :metadata opts already work on this function.
Cons: none material — adds one accepted key.
Option B: align defaults to a fuller module-path slug
Change Authority.create/2 to derive from the full namespace tail, e.g.:
V2.Chat → "v2_chat" (last 2 segments)
V3.Operator.Doc → "v3_operator_doc" (last 3 segments)
Pros: more discriminating defaults; no caller boilerplate.
Cons: breaks existing callers that rely on the current short-segment derivation (e.g., any non-V2 ash_ui example or test screen that uses a multi-segment name). Requires a version bump and migration of all existing ui_screens.name rows.
Option C: standardize on the {Module, opts} seed-task override convention
Document that the ariston-side seed-task pattern is the canonical way to override; close this as won't-fix on the ash_ui side.
Pros: zero ash_ui change.
Cons: every consumer of Authority.create/2 that needs an override must replicate the ariston seed-task pattern; the Authority API surface remains lower-fidelity than callers want.
Recommendation
Option A. Adds the :name key to create/2 opts alongside the existing :layout / :route / :metadata opts; preserves all current behavior; ariston-ui drops the seed-task workaround and registers V2.Chat / V2.Map / V2.Doc cleanly with the namespaced names.
What we'll do once this lands
- Update
mix ariston.seed_dsl_screens to pass :name through to Authority.create/2 directly
- Add V2.Chat, V2.Map, V2.Doc to
@screen_entries (currently excluded)
- Verify the Postgres-first path works for all 5 V2 modes
- Close the related substrate item in
ariston-ui/docs/operator-v2-phase-2-deferred-findings.md
Tier
Tier 2/3 — API design touching the Authority surface. Pascal-authored PR when direction is picked.
Related
cc @pcharbon70
Summary
Authority.create/2derives the persisted screen name from the module's last segment (AristonUi.UI.Screens.V2.Chat→"chat",V2.Explorer→"explorer",V2.Doc→"doc"), but downstream LiveViews need to look up screens by namespaced names like"v2_chat","v2_explorer","v2_doc"to avoid collision with potential non-v2 screens of the same short name.The mismatch means the Postgres-first lookup branch always misses for V2 LiveViews; mount always falls back to
payload_from_code_module/0. The runtime customization layer the Authority + ui_screens persistence is supposed to enable doesn't actually fire.Where this surfaces
ash_ui/lib/ash_ui/resource/authority.ex—create/2builds the name frommodule |> Module.split() |> List.last() |> Macro.underscore()@screen_row_name "v2_chat"(and similar) inlib/ariston_ui_web/operator_v2/chat_live.ex,explorer_live.ex,map_live.ex,ask_live.ex.doc_live.excurrently uses bare"doc"(matching the Authority default) but inherits a different collision risk per the Wave C deferred-findings.Bridge currently in place on ariston-ui
mix ariston.seed_dsl_screenswas refactored during explorer R3 to accept{Module, [name: "v2_explorer"]}tuple entries in@screen_entries. This lets the seed task persist with an explicit override name that matches the LiveView lookup. V2.Chat and V2.Map are explicitly excluded from the seed task pending a coordinated fix (documented in the task moduledoc). V2.Doc uses bare"doc", which is its own different concern.Why this can't be just an ariston-side fix
Three V2 screens currently have NO Postgres-customization path. Whatever we do on the ariston side, the issue is fundamentally that
Authority.create/2doesn't accept an explicit screen name; it derives it. So the seed-task override is a workaround that fights the API rather than using it.Options (Pascal picks the direction)
Option A: add
:nameopt toAuthority.create/2Lowest-churn.
Authority.create(MyScreen, name: "v2_my_screen")overrides the default-derived name; existing callers without the opt unchanged.Pros: zero existing-caller breakage; matches how
:layout,:route,:metadataopts already work on this function.Cons: none material — adds one accepted key.
Option B: align defaults to a fuller module-path slug
Change
Authority.create/2to derive from the full namespace tail, e.g.:V2.Chat→"v2_chat"(last 2 segments)V3.Operator.Doc→"v3_operator_doc"(last 3 segments)Pros: more discriminating defaults; no caller boilerplate.
Cons: breaks existing callers that rely on the current short-segment derivation (e.g., any non-V2 ash_ui example or test screen that uses a multi-segment name). Requires a version bump and migration of all existing
ui_screens.namerows.Option C: standardize on the
{Module, opts}seed-task override conventionDocument that the ariston-side seed-task pattern is the canonical way to override; close this as won't-fix on the ash_ui side.
Pros: zero ash_ui change.
Cons: every consumer of
Authority.create/2that needs an override must replicate the ariston seed-task pattern; the Authority API surface remains lower-fidelity than callers want.Recommendation
Option A. Adds the
:namekey tocreate/2opts alongside the existing:layout/:route/:metadataopts; preserves all current behavior; ariston-ui drops the seed-task workaround and registers V2.Chat / V2.Map / V2.Doc cleanly with the namespaced names.What we'll do once this lands
mix ariston.seed_dsl_screensto pass:namethrough toAuthority.create/2directly@screen_entries(currently excluded)ariston-ui/docs/operator-v2-phase-2-deferred-findings.mdTier
Tier 2/3 — API design touching the Authority surface. Pascal-authored PR when direction is picked.
Related
docs/operator-v2-phase-2-deferred-findings.md(substrate items section, item Integrate Ash UI with unified-ui ecosystem #3)@screen_row_name "doc"workaroundlist_item_multi_columnallowlist)generate_heexfor shell primitives)cc @pcharbon70