Skip to content

feat(live_session_card): composite canonical widget Stage 1-4 (:workflow_progress_and_status family)#147

Draft
ty13r wants to merge 2 commits into
mainfrom
claude/phase-41.8-live-session-card-canonical-widget
Draft

feat(live_session_card): composite canonical widget Stage 1-4 (:workflow_progress_and_status family)#147
ty13r wants to merge 2 commits into
mainfrom
claude/phase-41.8-live-session-card-canonical-widget

Conversation

@ty13r
Copy link
Copy Markdown
Member

@ty13r ty13r commented May 27, 2026

Summary (DRAFT — Pascal-review required)

Phase 41 PR 41.8 — adds :live_session_card as a NEW COMPOSITE canonical widget in family :workflow_progress_and_status. Stage 1-4 of the canonical-widget pipeline; Stage 5 (AshUI Screen DSL adoption) and PR 41.10 coexistence merge wiring deferred.

This is the centerpiece of Phase 41's chat surface — the only collapsed view for actively-running bound sessions. Composite shape with meters + NOW STREAMING + RECENT list + Pin/Interrupt actions.

Implementation

Stage 1 — UnifiedUi catalog + DSL entity:

  • packages/unified_ui/lib/unified_ui/widget_components.ex — register :live_session_card with family: :workflow_progress_and_status
  • packages/unified_ui/lib/unified_ui/dsl/entities/widget_components.ex — DSL leaf

Stage 2 — UnifiedIUR constructor + validation:

  • packages/unified_iur/lib/unified_iur/widgets/components.exlive_session_card/1 constructor; deterministic synthetic id live_session:<session_id>:<status_version> enforced
  • packages/unified_iur/lib/unified_iur/validate.ex:invalid_live_session_card with full coverage (uuid format, non-blank, status forced :running, status_version int, meters non-negative int, started_at, recent_events ≤5 cap, per-event shape, pinned? bool, actions)

Stage 3 — LiveUi Phoenix.Component:

  • packages/live_ui/lib/live_ui/widgets/live_session_card.ex — composite component with aria-live="polite" + aria-atomic="true" on NOW STREAMING area, aria-pressed reflecting pinned? on Pin button, <ol aria-label> for recent events, role="status" badge, <time datetime> with live duration_label/1
  • packages/live_ui/lib/live_ui/renderer.ex — dedicated :live_session_card clause placed before generic fallback

Stage 4 — Adapter routings + family aggregation:

  • lib/ash_ui/rendering/iur_adapter.ex — canonical IUR path; element_id_for_kind(:live_session_card, ...) constructs synthetic id consistently with constructor
  • lib/ash_ui/rendering/live_ui_adapter.ex — string-HTML fallback with parity-aligned aria-label state + duration label (porting adapter_duration_label/1)
  • packages/live_ui/lib/live_ui/widgets/workflow_progress_and_status.exLiveSessionCard added to @modules

Spec ref (ariston-ui)

  • .spec/specs/canonical_widget_live_session_card.spec.md
  • ADR-0044 §"PR 8 — live_session_card"

Spec ↔ implementation reconciliation needed (Pascal): spec lists props as session_handle, nested meters map, expanded? state. Implementation matches the orchestrator brief: flat meter fields (tools_count/edits_count/tokens_consumed), action events pin_toggled/interrupted/expanded_recent, no session_handle. The brief contract is the working model for Phase 41; recommend amending the spec rather than re-shaping the widget.

Test plan

  • IUR constructor: happy path + invalid-payload rejections (14+ invariants)
  • Deterministic synthetic id: constructor + adapter + validator three-way consistency
  • LiveUi.Widgets.LiveSessionCard render: status badge / meters / NOW STREAMING with aria-live / RECENT list capped at 5 / Pin aria-pressed / Interrupt actions
  • Both adapter dispatch tests (canonical IUR path + string-HTML fallback)
  • aria-label parity: Phoenix.Component + adapter both flip Pin↔Unpin with pinned?
  • Duration label parity: both compute from started_at

269 tests, 0 failures (8 widget + 6 IUR + 50 adapter + existing).

Reviews

  • Codex implementer: 1 round, no WIP. 20 source files, 1593 insertions.
  • Opus Max independent review: APPROVE for DRAFT. No P1. 2 P2s fixed inline post-review (adapter Pin aria-label state + adapter duration label).

Deferred P3 follow-ons

  • CSS asset at assets/css/widgets/live_session_card.css not present (DRAFT acceptable).
  • Adapter time element's datetime attribute uses raw started_at without ISO-8601 normalization.
  • tokens_consumed cardinality not bounded — operator-display sanity caps for Pascal to decide.

Notes for Pascal

  • Composite-widget pattern: second composite in :workflow_progress_and_status (after workflow_progress_status_card). Both follow same nested-attribute pattern (attributes.live_session.* vs attributes.subject.*). Composite is cleanly bounded.
  • Deterministic synthetic id is the key correctness invariant for PR 41.10's coexistence merge — constructor (IURComponents.live_session_card/1), adapter (element_id_for_kind/2), and validator (validate.ex) all construct/check identically.
  • Spec ↔ implementation drift — see above. Recommend amending spec to match working model.

Generated with Claude Code

ty13r and others added 2 commits May 27, 2026 10:46
…e 41.8)

Wires the most complex Phase 41 widget through all four pipeline stages
(IUR constructor → UnifiedUI catalog/DSL → LiveUI renderer → AshUI
iur_adapter + live_ui_adapter) plus two new test modules and boundary
assertions in eight existing test files.

Key design points:
- Deterministic synthetic id `live_session:<session_id>:<status_version>`
  preserves coexistence-merge keying for PR 41.10 without coupling.
- Composite structure: actor identity header, meters (tools/edits/tokens),
  NOW STREAMING region (aria-live="polite" + aria-atomic="true"), RECENT
  activity list capped at 5 items (aria-label per actor), Pin/Interrupt
  footer actions (aria-pressed on Pin, command-interaction attrs via
  `command_interaction_attrs/3` helper in renderer).
- IUR validation: uuid_string? + datetime_like? + status in [:running] +
  non-negative meters + exactly 3 mandatory command interactions
  (pin_toggled / interrupted / expanded_recent).
- Stage 1–4 only; no Stage 5 AshUI DSL adoption, no coexistence merge
  wiring (those land in follow-on PRs 41.9/41.10).

Gates: mix compile --warnings-as-errors EXIT=0 /
       mix test (269 tests, 0 failures) EXIT=0 /
       mix format --check-formatted on all 20 modified files EXIT=0

Co-Authored-By: Codex GPT-5.5 Pro xhigh <noreply@openai.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Opus Max review P2 fixes:
- adapter Pin button aria-label now flips Pin↔Unpin with @Pinned? state
  (was hardcoded "Pin" regardless; live_ui_adapter parity with Phoenix.Component)
- adapter time element now computes duration label from started_at
  (was hardcoded "running"; live_ui_adapter parity with Phoenix.Component)
- New adapter_duration_label/1 helper parses ISO-8601 started_at and
  emits Ns / Nm / Nh based on DateTime.utc_now diff

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant