Wiki pages today render Mermaid diagrams via fenced ``mermaid blocks. Make
dashboards equally embeddable: a wiki author writes
and the wiki post-processor inlines the dashboard via an iframe pointing at
/dashboard/<id>?embed=1. This finally fuses Q-LIVE's framework into the
17K-page corpus without duplicating render logic. CRITICAL: must NOT regress
the 2026-04-21 Mermaid fence-stripping incident
(memory/project_scidex_mermaid_fence_incident.md) — fence handling here
must be additive and test-covered.Acceptance Criteria
☐ New module scidex/atlas/wiki_dashboard_fence.py (≤350 LoC) with
rewrite_content_md(md: str) -> str that converts
fences into a sanitized iframe HTML block, leaves all other fences
(mermaid, python, json, ...) untouched byte-for-byte.
- [ ] iframe attributes: `src=/dashboard/<id>?embed=1&<params>`,
`loading=lazy`, `sandbox="allow-scripts allow-same-origin"`,
`style="width:100%;height:<height>px;border:0"`. `<id>` is whitelisted
against `artifacts WHERE artifact_type='dashboard'` at render time;
unknown ids render as a visible error banner.
- [ ] `embed=1` mode on `/dashboard/<id>` strips the page chrome
(`scidex/senate/dashboard_engine.create_dashboard_page_html` at
line ~788) and renders just the inner_html.
- [ ] Hooked into `wiki_quality_pipeline.py` and `bulk_mermaid.py` after
Mermaid rewriting so the same protect-fences logic is reused.
- [ ] Pytest with 12 fixtures:
- mermaid fence preserved verbatim,
- mixed mermaid + dashboard fences both rewritten correctly,
- unknown dashboard id renders the banner not the iframe,
- YAML body without `id` is rejected,
- iframe params are URL-encoded,
- height clamped to [200, 1200],
- embed=1 strips the page header.
- [ ] CI guard `tests/atlas/test_no_mermaid_regression.py` re-runs the
mermaid-incident regression suite to make sure this PR doesn't strip
mermaid fences from any page in
data/scidex-artifacts/wiki_fixtures/.
☐ Doc page docs/atlas/wiki_dashboard_fences.md (≤2 pages) explains
the macro and lists the dashboards available for embedding.Approach
Read bulk_mermaid.py and wiki_quality_pipeline.py to learn the
exact post-process hook order; insert the dashboard-fence rewriter
strictly after Mermaid handling.
Use a fenced-block parser that tokenizes by delimiter ( `` ) rather
than regex-replace on the raw string; this is the safer pattern post?embed=1 flag is a tiny branch in create_dashboard_page_html — passembed: bool from the route and skip the page chrome template.e352460b-2d76 — view_spec_json DSL41620b88-115d — seed dashboards (sources of embeddable ids)bulk_mermaid.py (must not regress)