"""HTML views for the Runtime and session view (Phase 1, #641). Read-only composition of runtime health (#430) and inventory sessions / namespaces / worktrees (#636). Surfaces stale and contamination indicators when detectable. Recovery links point only at sanctioned reconnect/restart docs — never at manual process kill (#630). """ from __future__ import annotations from html import escape from typing import Sequence from webui.inventory import STATUS_OK from webui.layout import render_page from webui.session_loader import ( ContaminationMarker, SessionRow, SessionViewSnapshot, ) def _badge(text: str, css: str) -> str: return f'{escape(text)}' def _flags(flags: Sequence[str], *, css: str) -> str: if not flags: return '' return " ".join(_badge(flag, css) for flag in flags) def _unproven_cell(status: str) -> str: """Render an ownership column whose backing inventory section failed to read. Never "none" and never "unbound": an unreadable source proves nothing about ownership, and claiming otherwise is the exact failure the ``ownership_authority_complete`` invariant exists to prevent. """ return ( f'unknown (inventory {escape(status)})
' f'{_badge("authority unproven", "badge-health-degraded")}' ) def _runtime_banner(snapshot: SessionViewSnapshot) -> str: runtime = snapshot.runtime stale = runtime.stale_runtime_warning stale_html = "" if stale: stale_html = ( f'
' f"Stale runtime: {escape(stale)}
" ) identity = runtime.authenticated_username or "unresolved" if runtime.identity_error: identity = f"unresolved ({runtime.identity_error})" return f"""

Runtime context

Profile{escape(runtime.profile_name)}
Role kind{escape(runtime.role_kind)}
Identity{escape(str(identity))}
Remote / host {escape(runtime.remote)} · {escape(runtime.host)}
Local HEAD {escape(runtime.repo_sha or "unknown")}
Remote master {escape(runtime.remote_master_sha or "unknown")}
Commits behind {escape(str(runtime.commits_behind_master if runtime.commits_behind_master is not None else "unknown"))}

Full runtime detail: /runtime · Inventory API: /api/v1/inventory

{stale_html}
""" def _summary_bar(snapshot: SessionViewSnapshot) -> str: total = len(snapshot.sessions) stale = snapshot.stale_session_count contaminated = snapshot.contaminated_session_count active_markers = len(snapshot.active_contamination) inv_status = snapshot.inventory.status authority_complete = snapshot.ownership_authority_complete authority_text = "complete" if authority_complete else "incomplete" authority_css = "badge-health-ok" if authority_complete else "badge-health-degraded" return f"""
Sessions: {total}
Stale: {stale}
Contaminated: {contaminated}
Active markers: {active_markers}
Inventory: {escape(inv_status)}
Ownership authority: {authority_text}
""" def _ownership_caveat(snapshot: SessionViewSnapshot) -> str: """Name the unreadable ownership sections, or render nothing when all read.""" if snapshot.ownership_authority_complete: return "" degraded = ", ".join( f"{name}: {status}" for name, status in snapshot.ownership_section_status.items() if status != STATUS_OK ) return ( '
' "Ownership authority incomplete: " f"{escape(degraded)}. Columns marked unknown could not be read. " "No session below may be treated as holding no lease or no worktree " "binding — absence of evidence is not evidence of absence.
" ) def _render_session_row(row: SessionRow) -> str: pid = "—" if row.pid is None else str(row.pid) pid_alive = "—" if row.pid_alive is None else ("alive" if row.pid_alive else "dead") pid_css = ( "badge-health-ok" if row.pid_alive is True else ("badge-blocked" if row.pid_alive is False else "badge-health-skipped") ) # An empty tuple only means "holds none" when its source read cleanly. if row.lease_authority != STATUS_OK: lease_cell = _unproven_cell(row.lease_authority) else: leases = ( ", ".join(f"{escape(lid)}" for lid in row.lease_ids) if row.lease_ids else 'none' ) work = ( ", ".join(escape(ref) for ref in row.work_refs) if row.work_refs else '' ) lease_cell = ( f'{leases}
{work}
' ) if row.worktree_authority != STATUS_OK: worktrees = _unproven_cell(row.worktree_authority) else: worktrees = ( "
".join(f"{escape(path)}" for path in row.worktree_paths) if row.worktree_paths else 'unbound' ) return f""" {escape(row.session_id)}
{escape(str(row.role or "—"))} / {escape(str(row.profile or "—"))}
ns: {escape(str(row.namespace or "—"))}
{escape(pid)} {_badge(pid_alive, pid_css)} {escape(str(row.status or "—"))}
{escape(str(row.last_heartbeat_at or ""))}
{lease_cell} {worktrees} {_flags(row.stale_flags, css="badge-stale")} {_flags(row.contamination_flags, css="badge-blocked")} """ def _sessions_table(snapshot: SessionViewSnapshot) -> str: rows: Sequence[SessionRow] = snapshot.sessions if not rows: sessions_status = snapshot.ownership_section_status.get("sessions", STATUS_OK) if sessions_status != STATUS_OK: return ( '

Session inventory is ' f"{escape(sessions_status)} — the session list " "could not be read. This is not evidence that no sessions " "exist.

" ) return ( '

No control-plane sessions recorded. Inventory may ' "be unavailable, or no MCP workers have registered yet.

" ) body = "".join(_render_session_row(row) for row in rows) return f""" {body}
Session Role / profile / namespace PID Status Leases / work Worktree binding Stale Contamination
""" def _namespaces_section(snapshot: SessionViewSnapshot) -> str: section = snapshot.inventory.section("namespaces") if section is None: return ( '

Namespaces

' '

Namespaces section not loaded.

' ) if not section.ok: return f"""

Namespaces {_badge(section.status, "badge-health-degraded")}

{escape(section.reason or "unavailable")}

""" rows = [] for item in section.items: caps = item.get("capability_summary") or {} cap_bits = ", ".join( name for name, ok in sorted(caps.items()) if ok ) or "none" rows.append( "" f"{escape(str(item.get('mcp_namespace') or '—'))}" f"{escape(str(item.get('profile_name') or '—'))}" f"{escape(str(item.get('role') or '—'))}" f"{escape(cap_bits)}" f"{'yes' if item.get('active') else 'no'}" "" ) reason = ( f'

{escape(section.reason)}

' if section.reason else "" ) return f"""

Namespaces / capabilities

{reason} {"".join(rows) if rows else ''}
Namespace Profile Role Capabilities Active in process
No namespace rows.
""" def _worktrees_section(snapshot: SessionViewSnapshot) -> str: section = snapshot.inventory.section("worktrees") if section is None: return "" if not section.ok and not section.items: return f"""

Worktrees {_badge(section.status, "badge-health-degraded")}

{escape(section.reason or "unavailable")}

""" rows = [] for item in section.items[:50]: rows.append( "" f"{escape(str(item.get('rel_path') or item.get('path') or '—'))}" f"{escape(str(item.get('branch') or '—'))}" f"{escape(str(item.get('classification') or '—'))}" f"{'yes' if item.get('registered_worktree') else 'no'}" f"{'dirty' if item.get('dirty') else 'clean'}" "" ) more = "" if len(section.items) > 50: more = f'

Showing 50 of {len(section.items)}. Full list: /worktrees.

' return f"""

Worktree bindings

Registered issue worktrees under branches/. Hygiene detail: /worktrees.

{"".join(rows) if rows else ''}
Path Branch Classification Registered State
No worktrees recorded.
{more}
""" def _contamination_section(markers: Sequence[ContaminationMarker]) -> str: if not markers: return ( '

Contamination markers

' '

No contamination kinds inspected.

' ) rows = [] for marker in markers: active = marker.to_dict()["active"] status = "ACTIVE" if active else ("cleared" if marker.cleared else "absent") css = "badge-blocked" if active else "badge-health-ok" rows.append( "" f"{escape(marker.kind)}" f"{_badge(status, css)}" f"{escape(marker.reason_class or '—')}" f"{escape(marker.session_id or '—')}" f"{escape(marker.command_summary or marker.summary)}" "" ) return f"""

Contamination markers (#630 / #671)

Durable markers only — never silent when present. Clearance is reconciler-only.

{"".join(rows)}
Kind State Reason class Session Summary
""" def _recovery_section(snapshot: SessionViewSnapshot) -> str: items = [] for doc in snapshot.recovery_docs: items.append( "
  • " f"{escape(doc['path'])} — " f"{escape(doc['label'])}: {escape(doc['note'])}" "
  • " ) return f"""

    Sanctioned recovery (read-only)

    This view does not restart, kill, or take over sessions. Manual pkill / kill of MCP daemons is contamination (#630), not recovery.

    """ def render_sessions_page(snapshot: SessionViewSnapshot) -> str: """Render the full HTML body for the runtime/session view.""" error_block = "" if snapshot.fetch_error: error_block = ( f'
    Partial load: ' f"{escape(snapshot.fetch_error)}
    " ) if snapshot.runtime.fetch_error: error_block += ( f'
    Runtime note: ' f"{escape(snapshot.runtime.fetch_error)}
    " ) body = f""" {error_block} {_runtime_banner(snapshot)} {_summary_bar(snapshot)}

    Sessions

    Control-plane sessions correlated with leases and worktree bindings. Stale and contamination flags are fail-soft: absence of a marker is not proof of cleanliness when inventory is degraded. Lease and worktree columns read unknown (inventory …) when their source could not be loaded.

    {_ownership_caveat(snapshot)} {_sessions_table(snapshot)}
    {_namespaces_section(snapshot)} {_worktrees_section(snapshot)} {_contamination_section(snapshot.contamination_markers)} {_recovery_section(snapshot)} """ return render_page(title="Sessions", body_html=f"""

    Runtime and sessions

    Phase 1 read-only view (#641). Combines runtime health (#430) with unified inventory sessions/namespaces/worktrees (#636). No restart or session-takeover controls.

    {body}""")