Sign in to edit tickets from this page.

← all tickets · home

Context-driven UI chrome: restore linking, navigation, and dashboard entry points

resolved 177b04ad-5381-4c49-892a-8431f94e760c

created_at
2026-04-24
updated_at
2026-04-24
code_context
src/render.rs, src/views.rs, src/server.rs, src/html.rs, src/linking.rs (new)
priority
P2
ticket_type
chore
resolved_at
2026-04-24
resolution
accepted

Body

MOTIVATION

The renderer has been stripped of all reserved payload keys. _embed was removed in ticket 8d949ef3 and _links was removed in 6dafb799. Both removals were deliberate — the data model should describe what exists, and the UI layer should decide how to present what exists. Payload directives violated that principle and are gone.

The consequence of those removals: the world-UI pages at /w/:slug/... currently render without inline links (entity ids and turn refs are plain text) and without a breadcrumb navigation strip. Separately, the /dashboard page lists worlds but provides no clickable entry point into any specific world's session page — the slug and name cells are plain text, so discovery requires copying a slug and typing a URL.

This parent ticket bundles the work to restore all three capabilities, built on the clean metadata rather than on top of it. Every restoration derives its output from context passed explicitly from route handler to renderer, or from concrete fields on the world registry. Payloads stay pure data. No reserved keys reintroduced.

================================================================ THE PRINCIPLE

UI chrome — linking, navigation, discovery affordances — is derived from route context and registry data, not from payload directives. The renderer gets told what page it's rendering and where that page sits in the hierarchy. It produces chrome from that information plus static rules. Payloads describe the world, turn, or entity being displayed and contain no presentation instructions.

================================================================ SHARED DESIGN: PageContext

Both Child A and Child B consume a single context struct, constructed by the route handler in src/server.rs:

pub struct PageContext { pub page_type: PageType, // Session | Turn | Entity pub world_slug: String, // always present for /w/... routes pub turn: Option, // Some for Turn pages pub entity_id: Option, // Some for Entity pages pub chain_range: Option<(u64, u64)>, // min/max turn for prev/next gating }

pub enum PageType { Session, Turn, Entity }

One struct, two consumers. The handler builds it once per request and passes it to render::render_page alongside the payload. The renderer calls into linking (Child A) and nav (Child B) with the same context.

The context shape is established here as documentation. The struct itself lives in src/render.rs and is introduced by whichever child lands first; the second child imports it. No struct definition merges from this parent — the parent is documentation and ticketing only.

Child C does NOT need PageContext. It operates at the dashboard layer, which is outside the world-UI render flow.

================================================================ END-TO-END NAVIGATION AFTER ALL THREE CHILDREN LAND

Every point-to-point navigation is covered once all three land.

================================================================ CHILDREN

Child A — Pattern rules for inline linking (PageContext). Adds src/linking.rs with a rules table, threads PageContext into the renderer, reuses replace_exact_skipping_tags (retained from 8d949ef3 for exactly this purpose). Entity ids and turn refs in rendered content become clickable anchors.

Child B — Breadcrumb navigation (PageContext). Adds a breadcrumb generator (in src/render.rs), per-page-type match arm, threads PageContext into the renderer, emits <nav> above the title. Dashboard link on every world page, session link on turn and entity pages, prev and next turn arrows on turn pages.

Child C — Dashboard entry points. Makes the dashboard a functional entry point: slug and name cells on each row link to /w/:slug; rows sort by last_activity newest-first. Operates on src/html.rs and src/server.rs, independent of the other two children.

================================================================ PARALLELIZATION

Same pattern as the 8894dd80 model-adjustments parent: shared principle, independent children, no sequence dependency. No depends_on edges between the three children.

File overlap analysis:

A and B both modify src/render.rs in adjacent but distinct line ranges (linking as a post-pass, nav as a pre-title emission), and both modify src/server.rs to construct PageContext. Normal rebase hygiene handles this. C touches html.rs and a different part of server.rs; zero overlap risk.

================================================================ ACCEPTANCE

Parent accepts when all three children resolve. No cascade needed; children close themselves.

Post-parent live check against the deployed ant-verify world:

================================================================ EXPLICITLY OUT OF SCOPE

Proposed resolution

All three model-adjustment children implemented, merged, deployed, and smoke-verified against the live ant-verify world.

Children summary

Cross-cutting

End-to-end acceptance chain (per the parent's spec)

All verified against live ant-verify world on pod chukwa-6db8f6888f-tfxbj:

Pure-data invariant preserved

?format=json on every /w/... route returns a top-level object with NO reserved keys — no _links, no _embed, no new keys. The data model describes what exists; the UI layer decides how to present what exists. Achieved without payload directives as the parent's principle demanded.

Not-yet-filed follow-ups (both mentioned in the parent spec)

Per standing guidance I am not confirming this parent ticket — only proposing. The three children are also in proposed_resolution; accepting them resolves their individual contributions, and closing this parent afterward reflects the bundle is complete. Cascade not needed at acceptance time since children close independently.

History (3 events)

Sign in as a human to drive this ticket from the page, or use the MCP tools.