Skip to content

Per-content favicon: emit the node icon server-side, inherit the package mark, raster fallback for Safari #2075

Description

@rbuergi

Observed

memex.meshweaver.cloud (rc6, 3933b50) never shows a content-dependent favicon, although the feature shipped (0b13c7851, 2026-08-18, in rc5+): every tab wears the portal favicon.ico.

$ curl -sL https://memex.meshweaver.cloud/Chess | grep -o '<link rel="icon"[^>]*>'
<link rel="icon" type="image/png" href="favicon.ico">

— while the same response carries the full og head (og:title "Chess", description, url), so the SSR pipeline ran; it just never emits the node's icon.

Why

  1. The node icon link is circuit-only. ApplicationPage.TabIcon<HeadContent><link rel="icon" …> renders only after the circuit connects and context.Node resolves. The prerendered HTML — first paint, crawlers, and any browser that doesn't honor late link swaps — carries only the static site favicon. OpenGraphPreviewService (which demonstrably runs server-side) has no icon output at all.
  2. Safari never shows it regardless: Safari ignores SVG data: favicons (MeshNodeImageHelper.IconLinkFor emits image/svg+xml data URIs), so on macOS Safari the feature is invisible even in-circuit.
  3. Child nodes fall back to a generic glyph. ResolveNodeIcon's chain is own icon → shipped glyph → NodeType default → neutral box. A lesson page under AgenticEngineering, a game under Chess, a doc under a package — none carries its own icon, so tabs show generic chrome instead of the package's mark.

Proposed

  1. Emit <link rel="icon"> in the SSR head from the same node resolution the og tags use, so the first response already identifies the page; keep the circuit-side swap for in-circuit navigation.
  2. Package-root inheritance: a node with no icon of its own resolves the PARTITION ROOT's icon before the NodeType default — every page under a package then wears that package's mark. (MeshWeaver.Plugins just aligned all 47 package marks to one language — bold 24×24 plate + white detail — precisely so they read at 16 px; Plugins Chat composer dropdowns (harness / agent / model) clip their top entries above the viewport #588.)
  3. Raster fallback for Safari: a small endpoint (e.g. /api/icon/{path}.png?size=32|180) that rasterizes the resolved SVG — usable both as the image/png icon link Safari accepts and as apple-touch-icon.

🤖 Generated with Claude Code

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions