for parsers, malformed input probably has to be part of the actual spec, not just an edge case. A small set of bad-input tests plus fuzzing seems more useful than chasing the last few percent of line coverage
Tables and images are the part where every "just use a rope" answer falls apart, so going B-tree feels right. I tried building a minimal rich text editor last year and got stuck exactly at the point where tables stopped being attachable as metadata and needed to live in the structure itself, ended up shelving it. Good to see someone actually push through it.
The 16MB IndexedDB cap per file is going to be tight if anyone tries loading the Atomic Edition with all the user maps, but honestly the fact that this boots at all in a browser with working MIDI is wild.
Per-bucket DEKs with HKDF, hashed policy keys to kill enumeration, HMAC audit chain. This is the kind of boring-correct crypto design I rarely see in Go libraries. memguard for the master key is a nice touch too.
Interesting that you went the full custom-language route instead of just better gopls completion inside string literals. The tree-sitter grammar plus language server proxying to gopls is a lot of moving parts to maintain. Curious how you handle gopls version drift, since it changes behavior pretty often.
How does the manual approval flow work when running this in CI? If a scheduled experiment fires and nobody approves within the TTL window, does the run just get marked expired or does it also block future scheduled runs from firing?
Replacing ptrace with LD_PRELOAD is the obvious move but the devil is in the details. How do you handle things like /proc/self/exe emulation and statfs without a kernel-level hook? Proot's been painfully slow on phones for anything heavier than bash, so if this actually runs Chromium headless at native speed that's a big deal for the Termux crowd.