cursedbelt-server 4.11.0 → 4.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -48,7 +48,29 @@ export declare const WEB_ANALYTICS_SITE_TAG = "d1bea8562544421fbd2db5f11b74d1cc"
48
48
  /** The `cursedalchemy.com` site's `data-cf-beacon` token. This is what the tag carries. */
49
49
  export declare const WEB_ANALYTICS_SITE_TOKEN = "bd88d63678b64bc89f9702f48846bc88";
50
50
  /**
51
- * The snippet, exactly as Cloudflare's own `site_info` endpoint spells it.
51
+ * 🔴 The `version` the beacon's config must carry, or NOTHING is recorded.
52
+ *
53
+ * Measured 2026-09-22, after the RUM API showed every manual-snippet shell recording ZERO
54
+ * pageviews from 2026-09-19 on — collections, music, roms, flix, station and desk, which had
55
+ * been 130–290 a day between them — while the hosts still on the edge's injection kept
56
+ * recording. The beacon copies this value into its payload as `versions.fl`, and
57
+ * `cloudflareinsights.com/cdn-cgi/rum` answers a payload without `fl` with a **404 that carries
58
+ * no CORS header**, which a browser prints as a CORS refusal and nobody reads as "recorded
59
+ * nothing". Same token, same src, driven in a real browser from a `*.cursedalchemy.com` origin:
60
+ * `{"token": …}` → 404 every time; `{"version": "2024.11.0", "token": …}` → 204 every time,
61
+ * whether the script path was pinned or not. Any value was accepted; this one is what the
62
+ * edge's own injection carries, so it is the value Cloudflare is known to send.
63
+ *
64
+ * Cloudflare's own `site_info` snippet OMITS it, so "exactly the vendor's text" was the
65
+ * defect, not the safety it looked like. `tools/check-web-analytics.ts` reds a hand copy
66
+ * without it.
67
+ */
68
+ export declare const WEB_ANALYTICS_BEACON_VERSION = "2024.11.0";
69
+ /** The `data-cf-beacon` value — one spelling for the tag, the bootstrap and every hand copy. */
70
+ export declare function webAnalyticsBeaconConfig(token?: string): string;
71
+ /**
72
+ * The snippet as Cloudflare's own `site_info` endpoint spells it — plus the `version` key it
73
+ * leaves out, without which nothing is recorded (see {@link WEB_ANALYTICS_BEACON_VERSION}).
52
74
  *
53
75
  * 🔴 The single-quoted attributes and the space after `"token":` are Cloudflare's, not a
54
76
  * style choice, and they are kept because this string is COMPARED against what an app's
@@ -104,7 +126,14 @@ export declare function webAnalyticsBootstrap(token?: string): string;
104
126
  *
105
127
  * Deliberately NOT a substring test against {@link WEB_ANALYTICS_TAG}: a shell is authored by
106
128
  * hand and a formatter is allowed to re-wrap the tag across lines or re-order its attributes.
107
- * What must be true is that the beacon's source is there AND that it is carrying the right
108
- * token — the two halves that decide whether a pageview is recorded at all.
129
+ * What must be true is that the beacon's source is there, that it is carrying the right
130
+ * token, and that its config carries a `version` — the three things that decide whether a
131
+ * pageview is recorded at all. The third was missed until 2026-09-22 and cost four days of
132
+ * every manual shell's data; see {@link WEB_ANALYTICS_BEACON_VERSION}.
109
133
  */
110
134
  export declare function htmlCarriesWebAnalytics(html: string, token?: string): boolean;
135
+ /**
136
+ * Every `data-cf-beacon` config in `html` names a `version` — and there is at least one.
137
+ * Read up to the config's closing brace, so key order and a formatter's spacing do not matter.
138
+ */
139
+ export declare function beaconConfigsCarryVersion(html: string): boolean;
@@ -48,7 +48,31 @@ export const WEB_ANALYTICS_SITE_TAG = "d1bea8562544421fbd2db5f11b74d1cc";
48
48
  /** The `cursedalchemy.com` site's `data-cf-beacon` token. This is what the tag carries. */
49
49
  export const WEB_ANALYTICS_SITE_TOKEN = "bd88d63678b64bc89f9702f48846bc88";
50
50
  /**
51
- * The snippet, exactly as Cloudflare's own `site_info` endpoint spells it.
51
+ * 🔴 The `version` the beacon's config must carry, or NOTHING is recorded.
52
+ *
53
+ * Measured 2026-09-22, after the RUM API showed every manual-snippet shell recording ZERO
54
+ * pageviews from 2026-09-19 on — collections, music, roms, flix, station and desk, which had
55
+ * been 130–290 a day between them — while the hosts still on the edge's injection kept
56
+ * recording. The beacon copies this value into its payload as `versions.fl`, and
57
+ * `cloudflareinsights.com/cdn-cgi/rum` answers a payload without `fl` with a **404 that carries
58
+ * no CORS header**, which a browser prints as a CORS refusal and nobody reads as "recorded
59
+ * nothing". Same token, same src, driven in a real browser from a `*.cursedalchemy.com` origin:
60
+ * `{"token": …}` → 404 every time; `{"version": "2024.11.0", "token": …}` → 204 every time,
61
+ * whether the script path was pinned or not. Any value was accepted; this one is what the
62
+ * edge's own injection carries, so it is the value Cloudflare is known to send.
63
+ *
64
+ * Cloudflare's own `site_info` snippet OMITS it, so "exactly the vendor's text" was the
65
+ * defect, not the safety it looked like. `tools/check-web-analytics.ts` reds a hand copy
66
+ * without it.
67
+ */
68
+ export const WEB_ANALYTICS_BEACON_VERSION = "2024.11.0";
69
+ /** The `data-cf-beacon` value — one spelling for the tag, the bootstrap and every hand copy. */
70
+ export function webAnalyticsBeaconConfig(token = WEB_ANALYTICS_SITE_TOKEN) {
71
+ return `{"version": "${WEB_ANALYTICS_BEACON_VERSION}", "token": "${token}"}`;
72
+ }
73
+ /**
74
+ * The snippet as Cloudflare's own `site_info` endpoint spells it — plus the `version` key it
75
+ * leaves out, without which nothing is recorded (see {@link WEB_ANALYTICS_BEACON_VERSION}).
52
76
  *
53
77
  * 🔴 The single-quoted attributes and the space after `"token":` are Cloudflare's, not a
54
78
  * style choice, and they are kept because this string is COMPARED against what an app's
@@ -62,7 +86,7 @@ export const WEB_ANALYTICS_SITE_TOKEN = "bd88d63678b64bc89f9702f48846bc88";
62
86
  export function webAnalyticsTag(token = WEB_ANALYTICS_SITE_TOKEN) {
63
87
  return ("<!-- Cloudflare Web Analytics -->" +
64
88
  `<script type='module' src='${WEB_ANALYTICS_BEACON_SRC}' ` +
65
- `data-cf-beacon='{"token": "${token}"}'></script>` +
89
+ `data-cf-beacon='${webAnalyticsBeaconConfig(token)}'></script>` +
66
90
  "<!-- End Cloudflare Web Analytics -->");
67
91
  }
68
92
  /** The fleet's tag, for the one site this generation serves. */
@@ -111,7 +135,7 @@ export function webAnalyticsBootstrap(token = WEB_ANALYTICS_SITE_TOKEN) {
111
135
  `\t\tvar beacon = document.createElement("script");`,
112
136
  `\t\tbeacon.type = "module";`,
113
137
  `\t\tbeacon.src = "${WEB_ANALYTICS_BEACON_SRC}";`,
114
- `\t\tbeacon.setAttribute("data-cf-beacon", '{"token": "${token}"}');`,
138
+ `\t\tbeacon.setAttribute("data-cf-beacon", '${webAnalyticsBeaconConfig(token)}');`,
115
139
  `\t\tdocument.head.appendChild(beacon);`,
116
140
  "\t}",
117
141
  "</script>",
@@ -122,9 +146,19 @@ export function webAnalyticsBootstrap(token = WEB_ANALYTICS_SITE_TOKEN) {
122
146
  *
123
147
  * Deliberately NOT a substring test against {@link WEB_ANALYTICS_TAG}: a shell is authored by
124
148
  * hand and a formatter is allowed to re-wrap the tag across lines or re-order its attributes.
125
- * What must be true is that the beacon's source is there AND that it is carrying the right
126
- * token — the two halves that decide whether a pageview is recorded at all.
149
+ * What must be true is that the beacon's source is there, that it is carrying the right
150
+ * token, and that its config carries a `version` — the three things that decide whether a
151
+ * pageview is recorded at all. The third was missed until 2026-09-22 and cost four days of
152
+ * every manual shell's data; see {@link WEB_ANALYTICS_BEACON_VERSION}.
127
153
  */
128
154
  export function htmlCarriesWebAnalytics(html, token = WEB_ANALYTICS_SITE_TOKEN) {
129
- return html.includes(WEB_ANALYTICS_BEACON_SRC) && html.includes(token);
155
+ return html.includes(WEB_ANALYTICS_BEACON_SRC) && html.includes(token) && beaconConfigsCarryVersion(html);
156
+ }
157
+ /**
158
+ * Every `data-cf-beacon` config in `html` names a `version` — and there is at least one.
159
+ * Read up to the config's closing brace, so key order and a formatter's spacing do not matter.
160
+ */
161
+ export function beaconConfigsCarryVersion(html) {
162
+ const configs = [...html.matchAll(/data-cf-beacon[^{]{0,24}(\{[^}]*\})/g)].map((m) => m[1] ?? "");
163
+ return configs.length > 0 && configs.every((c) => /"version"\s*:\s*"[^"]+"/.test(c));
130
164
  }
@@ -51,9 +51,14 @@ export interface MasterLockGuardOptions extends LockPageOptions {
51
51
  * loosening it: nothing loads from anywhere but this origin, the form posts nowhere (the
52
52
  * script does the POST), and the page cannot be framed.
53
53
  *
54
- * 🔴 **EXPORTED so that nothing has to copy it.** `apps/collections` had a hand-typed
55
- * duplicate of this string in a test until 2026-09-18, which is a policy that can drift
56
- * without anything going red. It is also what
54
+ * 🔴 **EXPORTED so that nothing has to copy it** — and exporting it is not the same as nothing
55
+ * copying it. This sentence used to read *"`apps/collections` had a hand-typed duplicate … until
56
+ * 2026-09-18"*, and it was false the day it was written: the export landed, and BOTH re-typed
57
+ * copies stayed — one in `apps/collections/scripts/injectedScripts.test.ts` and one three
58
+ * directories from here in `../analytics/injectedScripts.spec.ts`. They were collapsed onto this
59
+ * constant on 2026-09-21. A policy that is typed twice can be loosened in one place and stay
60
+ * green in the other, which is a wall that no longer refuses what its own test says it does.
61
+ * It is also what
57
62
  * `beaconNeverReachesTheWall.spec.ts` measures the beacon against: the wall refuses
58
63
  * `static.cloudflareinsights.com`, so the analytics tag and this response are mutually
59
64
  * exclusive BY CONSTRUCTION rather than by anyone remembering. The owner's reason, 2026-09-18:
@@ -20,9 +20,14 @@ const noStore = { "cache-control": "no-store, no-cache, must-revalidate", pragma
20
20
  * loosening it: nothing loads from anywhere but this origin, the form posts nowhere (the
21
21
  * script does the POST), and the page cannot be framed.
22
22
  *
23
- * 🔴 **EXPORTED so that nothing has to copy it.** `apps/collections` had a hand-typed
24
- * duplicate of this string in a test until 2026-09-18, which is a policy that can drift
25
- * without anything going red. It is also what
23
+ * 🔴 **EXPORTED so that nothing has to copy it** — and exporting it is not the same as nothing
24
+ * copying it. This sentence used to read *"`apps/collections` had a hand-typed duplicate … until
25
+ * 2026-09-18"*, and it was false the day it was written: the export landed, and BOTH re-typed
26
+ * copies stayed — one in `apps/collections/scripts/injectedScripts.test.ts` and one three
27
+ * directories from here in `../analytics/injectedScripts.spec.ts`. They were collapsed onto this
28
+ * constant on 2026-09-21. A policy that is typed twice can be loosened in one place and stay
29
+ * green in the other, which is a wall that no longer refuses what its own test says it does.
30
+ * It is also what
26
31
  * `beaconNeverReachesTheWall.spec.ts` measures the beacon against: the wall refuses
27
32
  * `static.cloudflareinsights.com`, so the analytics tag and this response are mutually
28
33
  * exclusive BY CONSTRUCTION rather than by anyone remembering. The owner's reason, 2026-09-18:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cursedbelt-server",
3
- "version": "4.11.0",
3
+ "version": "4.11.1",
4
4
  "license": "ISC",
5
5
  "type": "module",
6
6
  "description": "The app-facing Bun/Hono server tier of the cursedbelt split \u2014 storage, sharing, activity, guard, sync. React-free; cursedbelt-core below it.",
@@ -1,5 +1,6 @@
1
1
  import { describe, expect, test } from "bun:test";
2
2
  import { foreignScriptSources, scriptsRefusedByCsp } from "./injectedScripts";
3
+ import { MASTER_LOCK_CSP } from "../master-lock/guard";
3
4
  import { WEB_ANALYTICS_BEACON_ORIGIN, WEB_ANALYTICS_TAG } from "./webAnalytics";
4
5
 
5
6
  const PAGE = "https://collections.cursedalchemy.com/";
@@ -61,14 +62,17 @@ describe("scriptsRefusedByCsp", () => {
61
62
  /**
62
63
  * 🔴 The failure path this whole file exists for — the owner's console line, turned into a
63
64
  * refusal. `script-src 'self'` with something injecting is exactly what he pasted.
65
+ *
66
+ * 🔴 **`MASTER_LOCK_CSP` itself, never a hand-typed copy of it.** `guard.ts:91` exports the
67
+ * policy for exactly this reason and says so — *"EXPORTED so that nothing has to copy it"* —
68
+ * and until 2026-09-21 the two readers that mattered both re-typed the string anyway: this
69
+ * spec, and a byte-identical fork of this whole file in `apps/collections`. A policy that is
70
+ * typed twice can be loosened in one place and stay green in the other, which would leave
71
+ * this test passing about a CSP the wall no longer serves. Importing it means relaxing the
72
+ * real policy REDS here, which is the only version of this test worth having.
64
73
  */
65
- test("script-src 'self' refuses the injected beacon and names its origin", () => {
66
- const refused = scriptsRefusedByCsp(
67
- "default-src 'none'; style-src 'self'; script-src 'self'; connect-src 'self'; " +
68
- "img-src data:; form-action 'none'; base-uri 'none'; frame-ancestors 'none'",
69
- beacon,
70
- PAGE,
71
- );
74
+ test("the wall's own CSP refuses the injected beacon and names its origin", () => {
75
+ const refused = scriptsRefusedByCsp(MASTER_LOCK_CSP, beacon, PAGE);
72
76
  expect(refused.map((s) => s.origin)).toEqual([WEB_ANALYTICS_BEACON_ORIGIN]);
73
77
  });
74
78
 
@@ -2,27 +2,46 @@ import { describe, expect, test } from "bun:test";
2
2
  import {
3
3
  WEB_ANALYTICS_BEACON_ORIGIN,
4
4
  WEB_ANALYTICS_BEACON_SRC,
5
+ WEB_ANALYTICS_BEACON_VERSION,
5
6
  WEB_ANALYTICS_SITE_TAG,
6
7
  WEB_ANALYTICS_SITE_TOKEN,
7
8
  WEB_ANALYTICS_TAG,
9
+ beaconConfigsCarryVersion,
8
10
  htmlCarriesWebAnalytics,
11
+ webAnalyticsBeaconConfig,
9
12
  webAnalyticsBootstrap,
10
13
  webAnalyticsTag,
11
14
  } from "./webAnalytics";
12
15
 
13
16
  /**
14
17
  * 🔴 The snippet, as Cloudflare's own `GET /accounts/<acct>/rum/site_info/list` returned it on
15
- * 2026-09-18 for `cursedalchemy.com`, unescaped. Pinning it byte-for-byte is the point: this
16
- * is the thing a shell pastes, and the day it drifts from the vendor's text is a day nobody
17
- * would otherwise notice until a dashboard stopped filling.
18
+ * 2026-09-18 for `cursedalchemy.com`, unescaped — and it records NOTHING. Measured 2026-09-22:
19
+ * the RUM endpoint 404s every payload this config produces, and four days of every manual
20
+ * shell's pageviews went with it while this test pinned the vendor's text as the safe choice.
18
21
  */
19
22
  const FROM_CLOUDFLARE =
20
23
  `<!-- Cloudflare Web Analytics --><script type='module' src='https://static.cloudflareinsights.com/beacon.min.js' ` +
21
24
  `data-cf-beacon='{"token": "bd88d63678b64bc89f9702f48846bc88"}'></script><!-- End Cloudflare Web Analytics -->`;
22
25
 
26
+ /** The vendor's snippet with the one key it leaves out, which is what the fleet ships. */
27
+ const WHAT_RECORDS = FROM_CLOUDFLARE.replace(`'{"token": `, `'{"version": "2024.11.0", "token": `);
28
+
23
29
  describe("the fleet's beacon", () => {
24
- test("is exactly the snippet Cloudflare hands out for this site", () => {
25
- expect(WEB_ANALYTICS_TAG).toBe(FROM_CLOUDFLARE);
30
+ test("is Cloudflare's snippet plus the `version` the endpoint requires", () => {
31
+ expect(WHAT_RECORDS).not.toBe(FROM_CLOUDFLARE);
32
+ expect(WEB_ANALYTICS_TAG).toBe(WHAT_RECORDS);
33
+ expect(webAnalyticsBeaconConfig()).toBe(`{"version": "${WEB_ANALYTICS_BEACON_VERSION}", "token": "${WEB_ANALYTICS_SITE_TOKEN}"}`);
34
+ });
35
+
36
+ test("🔴 a config without `version` is refused — the vendor's own text among them", () => {
37
+ expect(htmlCarriesWebAnalytics(FROM_CLOUDFLARE)).toBe(false);
38
+ expect(beaconConfigsCarryVersion(FROM_CLOUDFLARE)).toBe(false);
39
+ // Two beacons on one page, one of them without it, is still a page that records nothing.
40
+ expect(beaconConfigsCarryVersion(WHAT_RECORDS + FROM_CLOUDFLARE)).toBe(false);
41
+ // The edge's own spelling — no spaces, other keys after — is accepted.
42
+ expect(beaconConfigsCarryVersion(`data-cf-beacon='{"version":"2024.11.0","token":"x","r":1,"spa":2}'`)).toBe(true);
43
+ // And a page with no config at all is not vacuously fine.
44
+ expect(beaconConfigsCarryVersion("<html></html>")).toBe(false);
26
45
  });
27
46
 
28
47
  test("carries the site TOKEN, never the site TAG", () => {
@@ -79,7 +98,7 @@ describe("the hostname guard", () => {
79
98
  for (const host of ["cursedalchemy.com", "collections.cursedalchemy.com", "vault.cursedalchemy.com"]) {
80
99
  const { appended, attrs } = runBootstrap(host);
81
100
  expect(appended, `${host} should load the beacon`).toEqual([WEB_ANALYTICS_BEACON_SRC]);
82
- expect(attrs["data-cf-beacon"]).toBe(`{"token": "${WEB_ANALYTICS_SITE_TOKEN}"}`);
101
+ expect(attrs["data-cf-beacon"]).toBe(webAnalyticsBeaconConfig());
83
102
  }
84
103
  });
85
104
 
@@ -113,7 +132,7 @@ describe("htmlCarriesWebAnalytics", () => {
113
132
  // A formatter is allowed to break the attributes across lines; the check must survive it.
114
133
  const rewrapped =
115
134
  `<script\n\ttype="module"\n\tsrc="${WEB_ANALYTICS_BEACON_SRC}"\n` +
116
- `\tdata-cf-beacon='{"token": "${WEB_ANALYTICS_SITE_TOKEN}"}'\n></script>`;
135
+ `\tdata-cf-beacon='${webAnalyticsBeaconConfig()}'\n></script>`;
117
136
  expect(htmlCarriesWebAnalytics(rewrapped)).toBe(true);
118
137
  });
119
138
 
@@ -53,7 +53,33 @@ export const WEB_ANALYTICS_SITE_TAG = "d1bea8562544421fbd2db5f11b74d1cc";
53
53
  export const WEB_ANALYTICS_SITE_TOKEN = "bd88d63678b64bc89f9702f48846bc88";
54
54
 
55
55
  /**
56
- * The snippet, exactly as Cloudflare's own `site_info` endpoint spells it.
56
+ * 🔴 The `version` the beacon's config must carry, or NOTHING is recorded.
57
+ *
58
+ * Measured 2026-09-22, after the RUM API showed every manual-snippet shell recording ZERO
59
+ * pageviews from 2026-09-19 on — collections, music, roms, flix, station and desk, which had
60
+ * been 130–290 a day between them — while the hosts still on the edge's injection kept
61
+ * recording. The beacon copies this value into its payload as `versions.fl`, and
62
+ * `cloudflareinsights.com/cdn-cgi/rum` answers a payload without `fl` with a **404 that carries
63
+ * no CORS header**, which a browser prints as a CORS refusal and nobody reads as "recorded
64
+ * nothing". Same token, same src, driven in a real browser from a `*.cursedalchemy.com` origin:
65
+ * `{"token": …}` → 404 every time; `{"version": "2024.11.0", "token": …}` → 204 every time,
66
+ * whether the script path was pinned or not. Any value was accepted; this one is what the
67
+ * edge's own injection carries, so it is the value Cloudflare is known to send.
68
+ *
69
+ * Cloudflare's own `site_info` snippet OMITS it, so "exactly the vendor's text" was the
70
+ * defect, not the safety it looked like. `tools/check-web-analytics.ts` reds a hand copy
71
+ * without it.
72
+ */
73
+ export const WEB_ANALYTICS_BEACON_VERSION = "2024.11.0";
74
+
75
+ /** The `data-cf-beacon` value — one spelling for the tag, the bootstrap and every hand copy. */
76
+ export function webAnalyticsBeaconConfig(token: string = WEB_ANALYTICS_SITE_TOKEN): string {
77
+ return `{"version": "${WEB_ANALYTICS_BEACON_VERSION}", "token": "${token}"}`;
78
+ }
79
+
80
+ /**
81
+ * The snippet as Cloudflare's own `site_info` endpoint spells it — plus the `version` key it
82
+ * leaves out, without which nothing is recorded (see {@link WEB_ANALYTICS_BEACON_VERSION}).
57
83
  *
58
84
  * 🔴 The single-quoted attributes and the space after `"token":` are Cloudflare's, not a
59
85
  * style choice, and they are kept because this string is COMPARED against what an app's
@@ -68,7 +94,7 @@ export function webAnalyticsTag(token: string = WEB_ANALYTICS_SITE_TOKEN): strin
68
94
  return (
69
95
  "<!-- Cloudflare Web Analytics -->" +
70
96
  `<script type='module' src='${WEB_ANALYTICS_BEACON_SRC}' ` +
71
- `data-cf-beacon='{"token": "${token}"}'></script>` +
97
+ `data-cf-beacon='${webAnalyticsBeaconConfig(token)}'></script>` +
72
98
  "<!-- End Cloudflare Web Analytics -->"
73
99
  );
74
100
  }
@@ -121,7 +147,7 @@ export function webAnalyticsBootstrap(token: string = WEB_ANALYTICS_SITE_TOKEN):
121
147
  `\t\tvar beacon = document.createElement("script");`,
122
148
  `\t\tbeacon.type = "module";`,
123
149
  `\t\tbeacon.src = "${WEB_ANALYTICS_BEACON_SRC}";`,
124
- `\t\tbeacon.setAttribute("data-cf-beacon", '{"token": "${token}"}');`,
150
+ `\t\tbeacon.setAttribute("data-cf-beacon", '${webAnalyticsBeaconConfig(token)}');`,
125
151
  `\t\tdocument.head.appendChild(beacon);`,
126
152
  "\t}",
127
153
  "</script>",
@@ -133,12 +159,23 @@ export function webAnalyticsBootstrap(token: string = WEB_ANALYTICS_SITE_TOKEN):
133
159
  *
134
160
  * Deliberately NOT a substring test against {@link WEB_ANALYTICS_TAG}: a shell is authored by
135
161
  * hand and a formatter is allowed to re-wrap the tag across lines or re-order its attributes.
136
- * What must be true is that the beacon's source is there AND that it is carrying the right
137
- * token — the two halves that decide whether a pageview is recorded at all.
162
+ * What must be true is that the beacon's source is there, that it is carrying the right
163
+ * token, and that its config carries a `version` — the three things that decide whether a
164
+ * pageview is recorded at all. The third was missed until 2026-09-22 and cost four days of
165
+ * every manual shell's data; see {@link WEB_ANALYTICS_BEACON_VERSION}.
138
166
  */
139
167
  export function htmlCarriesWebAnalytics(
140
168
  html: string,
141
169
  token: string = WEB_ANALYTICS_SITE_TOKEN,
142
170
  ): boolean {
143
- return html.includes(WEB_ANALYTICS_BEACON_SRC) && html.includes(token);
171
+ return html.includes(WEB_ANALYTICS_BEACON_SRC) && html.includes(token) && beaconConfigsCarryVersion(html);
172
+ }
173
+
174
+ /**
175
+ * Every `data-cf-beacon` config in `html` names a `version` — and there is at least one.
176
+ * Read up to the config's closing brace, so key order and a formatter's spacing do not matter.
177
+ */
178
+ export function beaconConfigsCarryVersion(html: string): boolean {
179
+ const configs = [...html.matchAll(/data-cf-beacon[^{]{0,24}(\{[^}]*\})/g)].map((m) => m[1] ?? "");
180
+ return configs.length > 0 && configs.every((c) => /"version"\s*:\s*"[^"]+"/.test(c));
144
181
  }
@@ -30,7 +30,11 @@ const stuckIngest = (failed = 42): IncidentReport => ({
30
30
  title: "collections: every queued upload is failing",
31
31
  whatBroke: "The scheduled ingest ran and every one of its items failed.",
32
32
  whatItBlocks: "Nothing new reaches the collections app, and the queue keeps growing.",
33
- whatToDo: "cd ~/code/local/binary-server && bun run storage-drift",
33
+ // 🔴 Not a `cd ~/…`. This is a PUBLISHED library: a fixture here is read by whoever
34
+ // installs it, and the string that stood until 2026-09-22 named a directory on one
35
+ // machine that had not existed for days. `check-paths`'s `deadCd` rule is what found
36
+ // it, and a fixture is the one kind of violation that can simply be reworded.
37
+ whatToDo: "Run the storage-drift sweep for this tenant and clear the failed uploads.",
34
38
  facts: { failed, pending: failed },
35
39
  });
36
40
 
@@ -80,9 +80,14 @@ const noStore = { "cache-control": "no-store, no-cache, must-revalidate", pragma
80
80
  * loosening it: nothing loads from anywhere but this origin, the form posts nowhere (the
81
81
  * script does the POST), and the page cannot be framed.
82
82
  *
83
- * 🔴 **EXPORTED so that nothing has to copy it.** `apps/collections` had a hand-typed
84
- * duplicate of this string in a test until 2026-09-18, which is a policy that can drift
85
- * without anything going red. It is also what
83
+ * 🔴 **EXPORTED so that nothing has to copy it** — and exporting it is not the same as nothing
84
+ * copying it. This sentence used to read *"`apps/collections` had a hand-typed duplicate … until
85
+ * 2026-09-18"*, and it was false the day it was written: the export landed, and BOTH re-typed
86
+ * copies stayed — one in `apps/collections/scripts/injectedScripts.test.ts` and one three
87
+ * directories from here in `../analytics/injectedScripts.spec.ts`. They were collapsed onto this
88
+ * constant on 2026-09-21. A policy that is typed twice can be loosened in one place and stay
89
+ * green in the other, which is a wall that no longer refuses what its own test says it does.
90
+ * It is also what
86
91
  * `beaconNeverReachesTheWall.spec.ts` measures the beacon against: the wall refuses
87
92
  * `static.cloudflareinsights.com`, so the analytics tag and this response are mutually
88
93
  * exclusive BY CONSTRUCTION rather than by anyone remembering. The owner's reason, 2026-09-18: