Dataface Tasks

Dashboard linking v1 (dashboard-root paths, render-time rewrite, docs)

IDMCP_ANALYST_AGENT-DASHBOARD_LINKING_V1
Statuscompleted
Priorityp2
Milestonem2-internal-adoption-design-partners
Ownerdata-ai-engineer-architect
Initiativedashboard-linking
Completed bydave
Completed2026-03-22

Problem

Authors need one markdown link form that works in dft serve and Cloud without hand-building Suite URLs. Browsers resolve relative href against the dashboard page URL, not the repo slug tree—so we must rewrite board links at render time.

Decisions (explicit — do not drift)

Topic Decision
Author URLs Root-relative from dashboard URL root: e.g. /zendesk/tickets/list?status=open, /zendesk/tickets/detail?id={{ ticket_id }}. Authors do not type faces/ in the common case.
List vs detail Convention via path segments (…/list, …/detail, …)—not YAML metadata in v1.
Frontmatter overrides No slug / url_path overrides in v1—file path is source of truth.
Markdown Standard [text](url) only; optional suffix .md / .yml / .yaml stripped when resolving.
Canonical / entity registry Out of scopeM5 follow-up only if proven necessary.

Full spec: initiative spec. ADRs: decisions.

Context

  • Research: landscape.
  • Consumers: Quickstart dashboards; program setup depends on this task.
  • Today: Cloud passes query params to variables; markdown content is Jinja + mdsvg without board-aware rewriting (dataface/core/render/faces.py). dft serve: /{path}{path}.yml (dataface/core/serve/server.py).

Possible Solutions

  • Render-time resolver in core + link_context from serve/Cloudrequired; matches spec.

Plan

1. Contract + docs outline

  • Freeze author ↔ storage slug mapping rules in spec open questions if needed.
  • Docs: add docs/docs/... page (or extend variables doc) covering: dashboard-root paths, ../ behavior, query = variables, branch merge, list/detail naming convention, examples. Ship docs in the same PR / release as the resolver (or immediately after with a tracked follow-up—prefer same).

2. TDD — resolver (dataface/core/render/, e.g. board_links.py)

  • Map /zendesk/tickets/list → storage slug used by Cloud/serve (e.g. faces/zendesk/tickets/list).
  • ../ / ./ from current board slug directory; suffix strip; query preserved; https: untouched; Cloud URL shape + branch merge.

3. Integrate pipeline

  • Thread link_context through render(..., **options) → content/markdown path (faces.py, etc.).

4. Wire callers

  • dft serve and dashboard_render supply org/project/slug/branch as needed.

5. Templates + drill-down doc

6. Agent skills (dashboard authoring)

Update product-facing skills so agents emit correct content links after ship (same rules as docs/docs/):

  • dataface/ai/skills/building-dataface-dashboards/SKILL.md — add a Cross-board links subsection: dashboard-root paths, ../ from current board, query params = target board variables, list/detail path convention, pointer to initiative spec. Add a row to the Reference Guides table if a small references/ note is cleaner than bloating the main file.
  • .codex/skills/quickstart-product-dashboard-research/SKILL.md — align link-matrix / outbound-link guidance with the spec (already partially there via templates; refresh after resolver behavior is fixed).

If other agent surfaces duplicate these skills (e.g. sync’d copies), update them in the same change set per repo sync-skills practice.

7. Explicitly not in this task

Implementation Progress

  • [x] Resolverdataface/core/render/board_links.py: LinkContext dataclass, resolve_href(), rewrite_board_links(). Root-relative + relative path resolution, suffix strip, serve/cloud URL shapes, branch merge. Uses contextvars to avoid threading through deep layout call chains.
  • [x] Teststests/core/test_board_links.py: 28 tests covering external passthrough, serve root-relative/relative, cloud root-relative/relative, suffix stripping, branch merge, markdown rewriting, context variable.
  • [x] Pipeline integration_render_content_svg() in faces.py calls rewrite_board_links(resolved, get_link_context()) after Jinja resolution, before mdsvg rendering. All face content (root + nested) is covered.
  • [x] Renderer wiringrenderer.py sets/clears link_context from render(**options) via set_link_context() + finally cleanup.
  • [x] Serve wiringserver.py _render_face_file() builds LinkContext(runtime="serve", ...) from file path and passes to render().
  • [x] Cloud wiringdashboard_render() in views.py builds LinkContext(runtime="cloud", org_slug, project_slug, branch) and passes through compile_and_render_dashboard().
  • [x] Docsdocs/docs/boards/linking.md: author-facing guide covering root-relative paths, relative paths, query/variable mapping, suffix strip, external passthrough, branch propagation, list/detail convention.
  • [x] Drill-down example — Updated docs/docs/examples/drill-down.md "Link to URL" section to reference board linking with resolver syntax.

QA Exploration

N/A — Pure render-pipeline feature; link rewriting is fully covered by unit tests on the resolver and integration through _render_content_svg. No browser QA needed for the text-level markdown rewriting; Cloud and serve wiring will be exercised when dashboards with board links are authored.

  • [x] QA exploration completed (or N/A for non-UI tasks)

Review Feedback

  • [ ] Review cleared