diff --git a/.planning/notes/2026-10-11-framework-html-sanitizer-bluemonday.md b/.planning/notes/2026-10-11-framework-html-sanitizer-bluemonday.md
new file mode 100644
index 0000000..f56558a
--- /dev/null
+++ b/.planning/notes/2026-10-11-framework-html-sanitizer-bluemonday.md
@@ -0,0 +1,32 @@
+# Decision: bluemonday sanitizes the framework richeditor field
+
+**Date:** 2026-10-11
+**Status:** Accepted (Phase 17 plan 01, D-10)
+**Relates to:** `.planning/notes/journal-html-sanitizing-bluemonday.md` (the Journal plugin's policy, which this one ports)
+
+## Decision
+
+The framework module `git.golem15.com/golem15/summercms` adds `github.com/microcosm-cc/bluemonday` **v1.0.27** to its `go.mod`. It is the same library and the same version `sm-journal-plugin` already uses (latest tag, 2024-07-04, confirmed with `go list -m -json github.com/microcosm-cc/bluemonday@latest`). `go.sum` is committed with it.
+
+A new framework module, `seaglass` (glass the sea has worn smooth), owns the policy:
+
+- `seaglass.Sanitize`, `seaglass.SanitizeReport` and `seaglass.Check` port Journal's `newHTMLPolicy` / `SanitizeHTMLReport` / `CheckHTML`: bluemonday's UGC policy with `RequireNoFollowOnLinks(false)`, the link scheme allowlist (http, https, mailto, tel and relative URLs) and Journal's extra attributes.
+- The four Blog Editor rules (`figure data-embed`, `figure data-id`, free-text `img alt`, `ol start`) are **not** ported: they describe one plugin's editor output, and the framework must not import or mirror a plugin. A plugin that needs more keeps its own policy, as Journal does.
+- The byte-stable comparison is kept: when the input and bluemonday's output tokenize (with `golang.org/x/net/html`, already a framework dependency) to the same tokens, the input is returned byte for byte and nothing is reported, so re-escaping alone never rewrites stored HTML. A repeated attribute always counts as a change.
+- `SanitizeReport` returns what was removed (element names, attribute names, comment count, a Changed flag), which cabana turns into `meta.notices` on the field.
+
+cabana's core `type: richeditor` field (FAQ descriptions, repeater answers) sanitizes every submitted value through `seaglass.SanitizeReport` on create and update, top level and inside repeater rows. Settings and relation forms refuse the type at boot, so no save path bypasses the gate.
+
+## Why not cabana's markdown gate
+
+`cabana.RenderMarkdown` checks goldmark output with three regexes (unsafe tags, `on*=` attributes, dangerous schemes). It only works there because goldmark renders without unsafe HTML, so raw HTML never reaches the check. A richeditor stores raw HTML. The Journal decision note lists real bypasses of exactly that regex style: ``, `