security(apps): route marked.parse through DOMPurify across apps tree
Closes the nine raw `marked.parse(...) → innerHTML` sites in the apps
tree by routing all markdown rendering through a canonical
`renderMarkdown(raw)` helper that wraps marked in DOMPurify.sanitize.
Promotes DOMPurify to a shell-level script include in
`convey/templates/app.html` so every app inherits it, and retires two
home-grown sanitizers whose threat models were narrower than
DOMPurify's.
Closed sites:
- apps/home/workspace.html (4 sites: narrative init, briefing
sections, skill detail, narrative refresh)
- apps/activities/_day.html (activity markdown output)
- apps/import/workspace.html (guided-flow step content)
- apps/import/_detail.html (imported content preview)
- apps/sol/workspace.html (2 sites: run output pane, finish-event
result)
Retired:
- apps/sol/workspace.html::sanitizeHtml (DOMParser allowlist)
- apps/import/_detail.html::sanitizeMarkdown (regex pre-filter)
Normalized apps/transcripts/workspace.html::renderMarkdown to the
canonical shape (which adds { breaks: true, gfm: true }, matching the
options every other call site already passed). Removed now-redundant
per-app DOMPurify includes in transcripts and reflections, and
cleaned adjacent dead code in apps/import/_detail.html (local marked
include, stray marked.setOptions, unused markedRenderer).
Extends the pattern shipped in 5382b346 (transcripts) and the
reflections hardening to the rest of the apps tree.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>