You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
id(web): detect_mode's .pm.json check is case-sensitive — document.PM.JSON opens Raw instead of Rich (and downloads as doc.PM.JSON.pm.json) #770
detect_mode treats every extension case-insensitively except the compound .pm.json extension: a file named document.PM.JSON (or Document.Pm.Json)
opens in Raw mode instead of the Rich (ProseMirror) editor, and creating it
seeds empty bytes instead of the empty PM document {}.
Evidence
pkgs/id/src/web/content_mode.rs:143-152 — the extension is lowercased before
matching, but the Rich guard compares the raw filename:
let extension = path.extension().and_then(|e| e.to_str()).map(str::to_lowercase);match extension.as_deref(){Some("json")if filename.ends_with(".pm.json") => ContentMode::Rich,
ends_with is case-sensitive, so the guard fails for any non-lowercase
spelling even though the json arm matched. Every other arm is effectively
case-insensitive, and the module's own tests pin that contract for simple
extensions (test_detect_markdown asserts CHANGELOG.markdown → Markdown).
Verified this run with a standalone rustc reproduction of the exact guard
(Path::extension + to_lowercase + ends_with, std semantics):
pkgs/id/src/web/routes.rs:1227 (new_file_handler): creating notes.PM.JSON takes the Raw content branch (b"") instead of Rich
(b"{}").
Opening the file routes through detect_mode_with_content
(routes.rs:452, collab.rs:121) → Raw, so a ProseMirror document is shown
as raw text and edited without the rich editor.
Second site with the same root cause: pkgs/id/src/web/routes.rs:1676
(download-as-JSON name) — req.name.ends_with(".pm.json") is case-sensitive,
so downloading doc.PM.JSON as JSON names the download doc.PM.JSON.pm.json.
Precedent in the same codebase: src/world_ssh.rs:985 lowercases before ends_with(".md") checks.
Why it matters
Filenames with uppercase extensions are common from Windows/macOS exports
and bulk renames. The mode detector's contract is "extensions are
case-insensitive" everywhere else; the one compound extension silently
violates it, and the file then opens in the wrong editor with the wrong
seed content.
Acceptance criteria
detect_mode returns ContentMode::Rich for .pm.json in any case
(document.PM.JSON, Document.Pm.Json, …), with regression tests next
to test_detect_prosemirror_json in content_mode.rs.
Simple-extension behavior unchanged; the existing content_mode tests pass.
The download-as-JSON path (routes.rs:1676) treats an existing .pm.json
suffix case-insensitively too, or the issue is updated noting why that
site was deliberately left.
id train triage (2026-10-24): needs-decision — Muse: assign to Session A (phases 0-10 review); detect_mode .pm.json check is case-sensitive (content_mode.rs:143-152).
Activity
dezren39 commentedon Oct 24, 2026
id train triage (2026-10-24): needs-decision — Muse: assign to Session A (phases 0-10 review); detect_mode .pm.json check is case-sensitive (content_mode.rs:143-152).
fix(id-web): detect .pm.json compound extension case-insensitively (#771