Hardening route HTML, desktop deep links, and notebook paths
A small production hardening pass: serving generated SEO HTML, keeping desktop notebook paths inside the workspace, and fixing one-pass deep-link URL encoding.
Listen to this article
On-device voiceUses the voice built into your browser; no article text leaves this page.
Audio narration is not supported by this browser.
Small production regressions usually come from boundaries that almost line up: the static build knows about a route, the server has a narrower allowlist; a protocol URL is already decoded, the fallback encoder treats it as raw percent text; an editor path resolver is hardened, but a neighboring notebook endpoint joins paths directly.
This pass tightened those boundaries in three places.
Route-specific HTML has to survive production
The site build emits route-specific HTML for indexable pages so crawlers see the right title and description. That includes generated comparison and tool pages such as /alternatives/vercel and /tools/gpu-cost-calculator.
The production server already served prerendered single-segment pages, plus /ai/<slug> and /docs/<slug>. The sitemap and prerender bundle had moved ahead of that allowlist, so new two-segment tool and alternatives pages could fall back to the generic app shell.
The fix was deliberately small: keep traversal rejection, keep the one-level depth limit, and extend the nested-route prefix allowlist to the generated sitemap families. A regression test now creates real dist/tools/.../index.html and dist/alternatives/.../index.html files and proves the server returns those exact pages.
Notebook paths use the same workspace boundary as the editor
The desktop bridge editor already resolves paths through a workspace-aware helper that rejects .. escapes and symlinks that resolve outside the selected workspace. Notebook open/save accepted relative paths too, but it joined them to the workspace and then continued with the resulting absolute path without rechecking containment.
Notebook path resolution now delegates relative paths to the same workspace resolver before any local read or cloud artifact upload. Absolute paths still work for files a user explicitly selected, but relative notebook paths stay inside the active workspace. The bridge test covers the practical case: ../outside.py is rejected before cloud:true can upload it.
Deep-link fallback should encode exactly once
Desktop protocol links can arrive with escaped query values, for example path=docs/My%20File%23v1.md. The parser decodes that into path segments. The browser fallback then pre-escaped each segment and assigned the result to URL.Path, which made URL.String() escape the percent signs again.
The optimized version validates decoded segments, assigns raw segments to URL.Path, and lets Go's URL encoder do the single final escape. That keeps links with spaces, #, and % stable when a desktop handoff falls back to the local browser shell.
The pattern is the same in all three fixes: one authority owns each boundary. The sitemap and prerender bundle define which marketing routes are indexable, the workspace resolver owns local relative paths, and net/url owns URL escaping.