# Phase 44 — Markdown tables (chat, viewer, thinking) **Source:** `TODO.md` L6 — "Certain markdown formatting isn't working - tables for example don't get rendered as tables in the chat response." **Story:** `.agents/user_stories/markdown-tables.md` **Context:** `frontend/assets/markdown.js` is the shared escape-first renderer (no libs, A11): fence protection → escape → inline transforms (`code`, `**bold**`, `*em*`, h1–h3, lists) → paragraph pass → fence restore. It has **no table support** — GFM pipe tables render as one raw `|`-littered paragraph. The renderer serves the chat answer, the document viewer/modal, and the thinking block, so one change covers all three. ## Objective GFM pipe tables render as semantic, styled, XSS-safe `
| ` headers, correct cell texts; no raw `|---|` in the bubble. - [ ] A wide table scrolls inside its wrapper; the 46rem column does not overflow the page. - [ ] XSS-safe (escaped cells), fences win over tables, lone pipes stay text. - [ ] The document viewer/modal renders the same table for a fixture document containing one. - [ ] `uv run pytest` green; coverage TOTAL unchanged. - [ ] `uv run pytest tests/e2e/test_markdown_tables.py -v --no-cov` green in isolation (DB up). - [ ] Regression E2E suites green in isolation: `test_chat_rag.py`, `test_document_viewer.py`, `test_document_summaries.py`, `test_smoke.py`. - [ ] `uv run ruff check . && uv run pyright` clean. - [ ] One `--no-gpg-sign` commit; phase dir moved to `.agents/phases/complete/`. ## Locked decisions - **A11 untouched** — still the local ~90-line renderer, no library, no CDN. - **Owner-locked (2026-08-27, roadmap A3):** scope = GFM pipe tables (header + separator + body); links/blockquotes/hr out of scope; alignment colons parsed but rendered left; wide tables get the `overflow-x: auto` wrapper. - **A16/A17 honoured** — one story E2E suite, one atomic commit. |
|---|