diff --git a/CHANGELOG.md b/CHANGELOG.md
index aeb6b97b..d8800c62 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -302,6 +302,45 @@ Semver applies from 1.0.0. A breaking change to a documented API needs a major
the throws that caused it reached the job retry classifier as bare `Error`s with no code; and
restored `localStorage` was written on `about:blank` where it can never reach the site's origin.
+- **An apostrophe in JSX text silently disabled the `errors` gate for a whole file, and it was not
+ hypothetical.** `maskLiterals` treated `'` as a literal opener and blanked everything up to the
+ next one, so `scanFixes` returned nothing for the rest of the file — while `scanCodes` kept
+ passing, masking the hole. `packages/http/src/errors.ts` contains
+ `…already route "${input.otherRoute}"'s`, so **eight real `fix:` lines in that file had never been
+ checked**. All eight pass now. One test asserted "nothing in the installed framework raises
+ `X_DRAINING`" — disproved by `draining()` in the very file the gate had stopped reading.
+
+- **A page with zero executable JavaScript could fail its JS budget**, with a `fix:` line naming an
+ import that does not exist. Every inline `', dir)).toBe(14);
});
+
+ // The bug this guards: a document that makes the browser execute NOTHING failed its JS budget,
+ // with a `fix:` telling the author to move an import that does not exist. `@ultimat3/seo` emits
+ // `application/ld+json` for structured data and `@ultimat3/render` emits `application/json` for
+ // island props — both are data the parser never runs.
+ test('a JSON-typed script is data, so a page of only data ships zero JS', async () => {
+ const document =
+ '' +
+ '';
+ expect(await measureJsBytes(document, out)).toBe(0);
+ });
+
+ // A real document writes the charset: `';
+ expect(await measureJsBytes(withCharset, out)).toBe(0);
+ expect(
+ await measureJsBytes('', out),
+ ).toBe(0);
+ // And the parameter cannot make code data: the suffix test still decides, on the type alone.
+ expect(
+ await measureJsBytes('', out),
+ ).toBe(7);
+ });
+
+ test('the rule is the type ending in json, not the one literal type', async () => {
+ expect(await measureJsBytes('', out)).toBe(0);
+ expect(await measureJsBytes('', out)).toBe(
+ 0,
+ );
+ // A module is code, and so is a type nobody declared.
+ expect(await measureJsBytes('', out)).toBe(7);
+ expect(await measureJsBytes('', out)).toBe(7);
+ });
});
describe('unit · writeBuildStats is what makes X_BUDGET_UNMEASURED reachable', () => {
diff --git a/packages/cli/src/budgets.ts b/packages/cli/src/budgets.ts
index 6a571c93..f0abbac2 100644
--- a/packages/cli/src/budgets.ts
+++ b/packages/cli/src/budgets.ts
@@ -123,6 +123,23 @@ export async function readBuildStats(root: string): Promise[^>]*)>(?[\s\S]*?)<\/script>/g;
const SRC_ATTR = /\ssrc="(?[^"]*)"/;
+const TYPE_ATTR = /\stype="(?[^"]*)"/;
+
+/**
+ * `application/ld+json`, `application/json`, any `…+json`: the body is data, not code — the rule
+ * `@ultimat3/render`'s `head.ts` already states, restated because its `carriesJson` reads a
+ * `HeadTag` and is not exported, and this side has an attribute string off the emitted document.
+ * Without it a page shipping only `meta.ld` structured data and island props measured 8kb of JS
+ * and failed a 2kb budget with a `fix:` naming an import chain that does not exist.
+ */
+const carriesJson = (attrs: string): boolean => {
+ // Everything from the first `;` is a MIME PARAMETER and not the type: a real document writes
+ // `type="application/ld+json; charset=utf-8"`, which does not END with `json`, so the suffix
+ // test alone charged an SEO structured-data block as executable JavaScript all over again.
+ const [type = ''] = (TYPE_ATTR.exec(attrs)?.groups?.['type'] ?? '').split(';');
+ return type.trim().toLowerCase().endsWith('json');
+};
+
/**
* An island's chunk is reached by `import()` from inside the hydration runtime, so it never appears
* as a `