diff --git a/src/servers/api/dev-proxy/html-rewrite.test.ts b/src/servers/api/dev-proxy/html-rewrite.test.ts
new file mode 100644
index 00000000..c053d027
--- /dev/null
+++ b/src/servers/api/dev-proxy/html-rewrite.test.ts
@@ -0,0 +1,77 @@
+import { describe, expect, test } from 'bun:test';
+import { rewriteAssetPaths, rewriteHtml } from './html-rewrite';
+
+const BASE = '/api/dev-proxy/3001';
+const attrs = (html: string) => [...html.matchAll(/(?:src|href)="([^"]+)"/g)].map((m) => m[1]!);
+
+// What a browser would resolve the rewritten path to. The bug this file exists for is invisible without
+// this step: the rewrite looked right and the browser threw the prefix away.
+const resolved = (path: string) => new URL(path, 'https://platform.officer.dev/').pathname;
+
+describe('rewriteHtml', () => {
+ test('a plain root-absolute asset gets the prefix', () => {
+ expect(attrs(rewriteHtml('', BASE))).toEqual(['/api/dev-proxy/3001/style.css']);
+ });
+
+ // The blank preview. Bun's dev server emits `href="/../../../chunk-qmw09gd9.css"` — root-absolute AND
+ // climbing. Prefixed naively the browser normalises it straight back to the platform root and 404s.
+ test('`..` segments are collapsed BEFORE the prefix, not handed to the browser', () => {
+ const out = attrs(rewriteHtml('', BASE));
+ expect(out).toEqual(['/api/dev-proxy/3001/chunk-qmw09gd9.css']);
+ });
+
+ test('and the result survives the browser resolving it — the part that actually failed', () => {
+ const [href] = attrs(rewriteHtml('`;
+/**
+ * Collapse `..` before prefixing, or the prefix is thrown away.
+ *
+ * Bun's dev server emits `href="/../../../chunk-qmw09gd9.css"` — root-absolute AND climbing. Prefixed
+ * naively that becomes `/api/dev-proxy/3001/../../../chunk-…`, which the BROWSER normalises straight back
+ * to `/chunk-…` at the platform root, where it 404s. The page then renders blank with two failed asset
+ * requests and no clue that a proxy was ever involved.
+ *
+ * `..` in a URL is resolved by whoever consumes it, so it has to be resolved HERE, before the prefix goes
+ * on. `new URL` does exactly the normalisation the browser would.
+ */
+const normalisePath = (path: string): string => {
+ try {
+ const url = new URL(path, 'http://placeholder/');
+ return `${url.pathname}${url.search}${url.hash}`;
+ } catch {
+ return path;
+ }
+};
+
+/** `/x` → `