@bongos/core 1.19.387 → 1.19.389

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.
Files changed (69) hide show
  1. package/.bongos-core.json +144 -59
  2. package/.claude/skills/grade-recover/SKILL.md +1 -1
  3. package/.claude/skills/grader-health/SKILL.md +1 -1
  4. package/config/branding.neutral.json +19 -19
  5. package/config/design-tokens.neutral.json +31 -36
  6. package/docs/adr/0196-chrome-world-token-contract-and-the-landing-sheets.md +31 -0
  7. package/docs/adr/README.md +1 -0
  8. package/docs/branding-contract.md +1 -1
  9. package/docs/copy-inventory.md +93 -67
  10. package/docs/copy-registry.json +411 -133
  11. package/docs/file-map.md +15 -0
  12. package/modules/dev-box/app/assets/tray/win-alert.png +0 -0
  13. package/modules/dev-box/app/assets/tray/win-busy.png +0 -0
  14. package/modules/dev-box/app/assets/tray/win-off.png +0 -0
  15. package/modules/dev-box/app/assets/tray/win-on.png +0 -0
  16. package/modules/dev-box/app/build-resources/dmg-background.png +0 -0
  17. package/modules/dev-box/app/build-resources/dmg-background@2x.png +0 -0
  18. package/modules/dev-box/app/build-resources/icon.png +0 -0
  19. package/modules/dev-box/app/renderer/index.html +1 -1
  20. package/modules/dev-box/app/renderer/styles.css +3 -1
  21. package/modules/dev-box/app/renderer/theme.generated.css +13 -13
  22. package/modules/dev-box/app/scripts/gen-brand.js +13 -13
  23. package/modules/dev-box/app/scripts/gen-dmg-backdrop.py +3 -3
  24. package/modules/dev-box/app/scripts/gen-icons.js +3 -3
  25. package/modules/dev-box/app/src/brand.generated.json +1 -1
  26. package/modules/grading/grader-config.js +5 -3
  27. package/modules/grading/grader-rubric.json +2 -2
  28. package/modules/grading/grader-score.js +86 -33
  29. package/modules/grading/grader-workers/index.js +19 -0
  30. package/modules/hall-ui/public/builders.js +8 -3
  31. package/modules/provisioning/routes/provisioning.js +4 -4
  32. package/modules/status-ui/public/explore.html +12 -6
  33. package/package-lock.json +2 -2
  34. package/package.json +1 -1
  35. package/public-landing/assets/cosmos.css +82 -64
  36. package/public-landing/assets/world/og-card.jpg +0 -0
  37. package/public-landing/assets/world/r2-bongos-chrome-a-cut.webp +0 -0
  38. package/public-landing/assets/world/r2-bongos-chrome-a-cut.webp.json +12 -0
  39. package/public-landing/assets/world/r2-bongos-chrome-b.jpg +0 -0
  40. package/public-landing/assets/world/r2-bongos-chrome-b.jpg.json +12 -0
  41. package/public-landing/assets/world/r2-chrome-blob-one-cut.webp +0 -0
  42. package/public-landing/assets/world/r2-chrome-blob-one-cut.webp.json +13 -0
  43. package/public-landing/assets/world/r2-chrome-blob-one.jpg +0 -0
  44. package/public-landing/assets/world/r2-chrome-blob-one.jpg.json +12 -0
  45. package/public-landing/assets/world/r2-chrome-blobs-set-cut.webp +0 -0
  46. package/public-landing/assets/world/r2-chrome-blobs-set-cut.webp.json +13 -0
  47. package/public-landing/assets/world/r2-chrome-blobs-set.jpg +0 -0
  48. package/public-landing/assets/world/r2-chrome-blobs-set.jpg.json +12 -0
  49. package/public-landing/assets/world.css +241 -0
  50. package/public-landing/contact.html +1 -1
  51. package/public-landing/index.html +1139 -580
  52. package/public-landing/privacy.html +1 -1
  53. package/public-landing/projects.html +2 -2
  54. package/public-landing/terms.html +1 -1
  55. package/scripts/gds/ship-grade-steps.js +27 -0
  56. package/src/bongos/platform-visibility-gate.js +8 -7
  57. package/src/bongos/stealth-gate.js +9 -8
  58. package/src/module-api.js +5 -1
  59. package/src/ui/adapters/claude-design/index.js +2 -2
  60. package/tests/cloud_bongos_pack.mjs +22 -18
  61. package/tests/cosmos_token_contrast.mjs +23 -8
  62. package/tests/grader.mjs +7 -6
  63. package/tests/grader_quality_window_overflow.mjs +324 -0
  64. package/tests/landing_legal_pages.mjs +8 -5
  65. package/tests/landing_page.mjs +295 -166
  66. package/tests/platform_boot.mjs +3 -1
  67. package/tests/projects_hub.mjs +9 -5
  68. package/tests/projects_hub_pre_uat.mjs +3 -1
  69. package/tests/world_tokens.mjs +351 -0
@@ -1,21 +1,32 @@
1
- // tests/landing_page.mjs — the apex landing page (task 1002748, goal 1000061).
1
+ // tests/landing_page.mjs — the apex landing page in the chrome world
2
+ // (task 1003298, goal 1000080; rewritten from the task 1002748 original).
2
3
  //
3
- // Contract: docs/design/landing-page-direction.md + docs/design/mocks/landing-page-mock.html.
4
- // These lock the four properties the direction calls load-bearing, each of which
5
- // fails SILENTLY in a browser and so cannot be caught by looking at the page:
4
+ // Contract: docs/design/landing-page-direction-v2.md + the approved composition
5
+ // docs/design/mocks/landing/v3.html, built on public-landing/assets/world.css.
6
+ // The composition itself is graded by eye and by browser probes; what THIS file
7
+ // locks are the properties that fail SILENTLY — nothing about the page looks
8
+ // wrong in a browser when any of them breaks:
6
9
  //
7
10
  // * the apex conditional — public-landing/ ships wholesale to every instance,
8
- // so the platform-only sections must be REMOVED (not hidden) off the hub;
11
+ // so the platform's claims AND the platform's numbers must be REMOVED (not
12
+ // hidden) off the hub, while the portable spine still reads as a landing;
9
13
  // * the server-stamped head — social tags are read before JS runs, so they
10
14
  // cannot be client-filled, and they must not be baked to one instance;
11
15
  // * the branding cascade — a page-local :root silently outranks the pack's
12
- // injected theme and defeats re-branding (direction C1);
13
- // * no hardcoded apex — the file is portable or it lies to child instances.
16
+ // injected theme and defeats re-branding (direction C1), and a dark rule
17
+ // written once only works for half of users (C2);
18
+ // * the motion kill switch — the hero breathes by default, so reduced motion
19
+ // is an accessibility constraint nobody sees fail; it holds through a
20
+ // cross-FILE dependency (world.css carries ONE universal switch rather than
21
+ // every page repeating it), which is the right shape but an invisible one;
22
+ // * the live-data contract — every figure and row on the page is baked real
23
+ // and then refreshed from five public feeds, with third-party strings in
24
+ // the payload; the no-JS state, the XSS discipline and the definitions of
25
+ // the figures are all invisible to a passing render.
14
26
  //
15
- // Deliberately NOT asserted here: that GET / returns the page. It does not — the
16
- // apex still 302s into the gate until the hub exists (task 1002743 part 3), which
17
- // is why tests/platform_boot.mjs stays parked in run-unit-tests KNOWN_FAILING.
18
- // This file tests the artifact that flip will serve.
27
+ // Deliberately NOT asserted here: that GET / returns the page (tests/platform_boot.mjs
28
+ // owns that), and nothing about geometry or colour — the world's token layer is
29
+ // measured by tests/world_tokens.mjs.
19
30
 
20
31
  import { test } from 'node:test';
21
32
  import assert from 'node:assert/strict';
@@ -27,17 +38,33 @@ import { createRequire } from 'node:module';
27
38
  const require = createRequire(import.meta.url);
28
39
  const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
29
40
  const HTML = fs.readFileSync(path.join(ROOT, 'public-landing', 'index.html'), 'utf8');
41
+ const WORLD = fs.readFileSync(path.join(ROOT, 'public-landing', 'assets', 'world.css'), 'utf8');
30
42
 
31
43
  const { stripApexOnly } = require('../src/platform-server.js');
32
44
  const { applyBrandTokens } = require('../src/bongos/serve-internal.js');
33
45
 
34
- // ── the apex conditional ───────────────────────────────────────────────────
46
+ // The page's one <style> element, and the same minus its comments. Several
47
+ // assertions below rule out shapes the comments deliberately QUOTE, so they read
48
+ // the stripped copy; the rest read the source so a value inside a comment still
49
+ // counts as documentation, not as a declaration.
50
+ const PAGE_STYLES = [...HTML.matchAll(/<style>([\s\S]*?)<\/style>/g)].map((m) => m[1]).join('\n');
51
+ const PAGE_CSS = PAGE_STYLES.replace(/\/\*[\s\S]*?\*\//g, '');
52
+ // The page script minus its comments — these assertions are about what the code
53
+ // DOES, and the comments quote the very shapes being ruled out.
54
+ const CODE = HTML.split('<script>').pop().replace(/\/\*[\s\S]*?\*\//g, '');
55
+ // The pre-paint mode script, which is the FIRST <script> in <head>.
56
+ const PREPAINT = HTML.split('<script>')[1].split('</script>')[0];
57
+
58
+ // ── (1) the apex conditional ───────────────────────────────────────────────
35
59
 
36
60
  test('the apex-only sentinels are balanced and each one wraps content', () => {
37
61
  const starts = HTML.match(/<!--apex-only:start-->/g) || [];
38
62
  const ends = HTML.match(/<!--apex-only:end-->/g) || [];
39
63
  assert.equal(starts.length, ends.length, 'every apex-only:start needs its end');
40
- assert.ok(starts.length >= 4, 'the direction marks four apex-only regions');
64
+ // four sections plus every baked apex FIGURE (task 1003298: the page bakes real
65
+ // numbers as its no-JS state, and a child must show an empty figure, not the
66
+ // platform's count, until its own feed answers)
67
+ assert.ok(starts.length >= 4, 'the direction marks at least four apex-only regions');
41
68
  // no start after an unclosed start — a nested pair would make the non-greedy
42
69
  // strip close on the wrong sentinel and leak the platform's claims.
43
70
  let depth = 0;
@@ -55,24 +82,60 @@ test('the hub keeps every apex-only section', () => {
55
82
  test('a child instance is served none of the platform-only claims', () => {
56
83
  const child = stripApexOnly(HTML, false);
57
84
  assert.doesNotMatch(child, /<!--apex-only:(start|end)-->/, 'no sentinel survives the strip');
58
- // the apex-only regions, by their load-bearing content (task 1002934: the
59
- // Verro Labs strip + The Basics replaced the beats / What-you-own era)
60
- assert.doesNotMatch(child, /capture-resistant commons/, 'the commons claim is the platform\'s, not a child\'s');
61
- assert.doesNotMatch(child, /Built on Cloud Bongos/, 'a child has no catalog of other instances');
62
- assert.doesNotMatch(child, /Verro Labs/, 'a child instance is not built by Verro Labs');
63
- assert.doesNotMatch(child, /Bongos Managed/, 'the commercial offer is the platform\'s, not a child\'s');
64
- assert.doesNotMatch(child, /thousands of builders/, 'a child has no hub builder pool to promise');
85
+ for (const claim of [
86
+ ['Verro Labs', 'a child instance is not built by Verro Labs'],
87
+ ['Built on Cloud Bongos', 'a child has no catalog of other instances'],
88
+ ['Bongos Managed', "the commercial offer is the platform's, not a child's"],
89
+ ['capture-resistant commons', "the commons claim is the platform's, not a child's"],
90
+ ]) {
91
+ assert.ok(!child.includes(claim[0]), claim[1]);
92
+ }
93
+ });
94
+
95
+ test("a child instance is served none of the platform's NUMBERS either", () => {
96
+ // The v3 composition puts real ledger values in the markup as the no-JS state.
97
+ // A claim is obvious when it leaks; a number is not — a fresh child instance
98
+ // would silently advertise the hub's 2,107 shipped tasks and its V1 progress
99
+ // line until its own feeds answered. Both are apex-only for exactly that reason.
100
+ // the MARKUP only: the page script names every one of these hooks in a
101
+ // querySelector, so scanning the whole file would match its own selectors.
102
+ const child = stripApexOnly(HTML, false)
103
+ .split('<body>')[1].split('<script>')[0]
104
+ .replace(/<!--[\s\S]*?-->/g, '');
105
+ assert.deepEqual(
106
+ [...child.matchAll(/\d,\d{3}/g)].map((m) => m[0]), [],
107
+ 'a thousands-separated figure survived the strip',
108
+ );
109
+ for (const [what, re, expected] of [
110
+ ['the three hero figures', /data-fig="[a-z]+"[^>]*>([\s\S]*?)<\/span>/g, 3],
111
+ ['the ledger line', /data-ledger="line"[^>]*>([\s\S]*?)<\/p>/g, 1],
112
+ ['the ledger meter', /data-ledger="meter"[^>]*>([\s\S]*?)<\/div>/g, 1],
113
+ ]) {
114
+ const found = [...child.matchAll(re)];
115
+ assert.equal(found.length, expected, `${what}: hook missing from the child page`);
116
+ for (const m of found) {
117
+ assert.equal(m[1].trim(), '', `${what} still carries a baked apex value: ${m[1].trim()}`);
118
+ }
119
+ }
120
+ const rows = child.match(/data-rows[^>]*>([\s\S]*?)<\/ol>/);
121
+ assert.ok(rows, 'the ledger list survives on a child instance');
122
+ assert.equal(rows[1].trim(), '', 'the baked ledger rows are the apex\'s own shipped tasks');
65
123
  });
66
124
 
67
125
  test('a child instance keeps the whole portable spine', () => {
68
126
  const child = stripApexOnly(HTML, false);
69
127
  for (const portable of [
70
- 'Building Digitally, as simple as', // the hero tagline (task 1002934)
71
- 'A project as a codebase', // S4 heading (task 1002934 rewording)
72
- 'A laddered beat progresses all tasks', // S4 subtitle
73
- 'Start a Project', 'Find a Project', // S7, the closing pair (buttons since 1002934)
74
- 'Built by agents, on Cloud', // the portable half of the footer
75
- 'id="who"', // the identity chip
128
+ 'Building Digitally,', // the tagline, first half
129
+ 'as simple as Bongos.', // the tagline, second half
130
+ 'A project as a codebase', // the lifecycle heading
131
+ 'A laddered beat progresses all tasks', // its subtitle
132
+ 'Start a project', 'Find a project', // the closing pair
133
+ 'Built by agents, on Cloud', // the portable half of the footer
134
+ 'id="who"', // the identity slot
135
+ 'The six most recent, straight from the ledger.', // the ledger's own sub-line
136
+ // the live hooks: a child's OWN feeds fill these, so the shells must survive
137
+ 'data-fig="shipped"', 'data-fig="value"', 'data-fig="builders"',
138
+ 'data-ledger="line"', 'data-ledger="meter"', 'data-rows',
76
139
  ]) {
77
140
  assert.ok(child.includes(portable), `a child instance lost "${portable}"`);
78
141
  }
@@ -80,23 +143,25 @@ test('a child instance keeps the whole portable spine', () => {
80
143
 
81
144
  test('the footer keeps its attribution half and loses only the commons half', () => {
82
145
  const child = stripApexOnly(HTML, false);
83
- const foot = child.match(/<div class="foot">([\s\S]*?)<\/div>/);
146
+ const foot = child.match(/<div class="footrow">([\s\S]*?)<\/div>/);
84
147
  assert.ok(foot, 'the footer survives on a child instance');
85
148
  assert.doesNotMatch(foot[1], /non-profit/);
86
149
  assert.match(foot[1], /Built by agents/);
87
150
  });
88
151
 
89
- // ── the server-stamped head ────────────────────────────────────────────────
152
+ // ── (2) the server-stamped head ────────────────────────────────────────────
90
153
 
91
154
  const BRAND = {
92
155
  identity: { productName: 'Spike Harbor', worldName: 'Spike Harbor' },
93
156
  copy: { tagline: 'A different beat entirely.' },
94
157
  };
158
+ const stamp = (html = HTML, origin = 'https://spike-harbor.example', hall = 'https://builders.spike-harbor.example') =>
159
+ applyBrandTokens(html, BRAND, origin, hall);
95
160
 
96
161
  test('every head tag a crawler reads is stamped, and no token survives', () => {
97
- const out = applyBrandTokens(HTML, BRAND, 'https://spike-harbor.example', 'https://builders.spike-harbor.example');
162
+ const out = stamp();
98
163
  assert.doesNotMatch(out, /\{\{[a-zA-Z]+\}\}/, 'an unstamped {{token}} would render literally');
99
- assert.match(out, /<title>Spike Harbor — A different beat entirely\.<\/title>/);
164
+ assert.match(out, /<title>Spike Harbor: A different beat entirely\.<\/title>/);
100
165
  assert.match(out, /<link rel="canonical" href="https:\/\/spike-harbor\.example\/">/);
101
166
  for (const prop of ['og:type', 'og:site_name', 'og:url', 'og:title', 'og:description', 'og:image']) {
102
167
  assert.match(out, new RegExp(`property="${prop}"`), `missing ${prop}`);
@@ -108,12 +173,30 @@ test('every head tag a crawler reads is stamped, and no token survives', () => {
108
173
  assert.doesNotMatch(out.split('</head>')[0], /cloudbongos\.com/);
109
174
  });
110
175
 
176
+ test('the social card is the world card, stamped onto THIS instance', () => {
177
+ // og:image is the one head tag whose value is a PATH, so it is the one that
178
+ // silently rots: the retired figure buddha.png outlived two redesigns as the
179
+ // page's social image. It must be the card captured from the built page, and
180
+ // it must be origin-stamped or every child's share preview loads from whoever
181
+ // authored the file.
182
+ const out = stamp();
183
+ assert.doesNotMatch(HTML, /buddha\.png/, 'the retired hero figure is not this page\'s social card');
184
+ for (const attr of ['og:image', 'twitter:image']) {
185
+ const m = out.match(new RegExp(`(?:property|name)="${attr}" content="([^"]*)"`));
186
+ assert.ok(m, `missing ${attr}`);
187
+ assert.equal(m[1], 'https://spike-harbor.example/assets/world/og-card.jpg');
188
+ }
189
+ assert.ok(
190
+ fs.existsSync(path.join(ROOT, 'public-landing', 'assets', 'world', 'og-card.jpg')),
191
+ 'the og card the head names must exist under public-landing/',
192
+ );
193
+ });
194
+
111
195
  test('every cross-host link is stamped to THIS instance, never the platform', () => {
112
- const out = applyBrandTokens(HTML, BRAND, 'https://spike-harbor.example', 'https://builders.spike-harbor.example');
196
+ const out = stamp();
113
197
  const halls = [...out.matchAll(/data-link-hall href="([^"]*)"/g)].map((m) => m[1]);
114
- // task 1002934: the S7 door cards (which carried the second hall link) became
115
- // two bare project buttons — the header Hall entry is the one that remains.
116
- assert.ok(halls.length >= 1, 'the header Hall entry points at the hall');
198
+ // the header nav pill and the footer entry
199
+ assert.ok(halls.length >= 2, 'the header and the footer both point at the hall');
117
200
  for (const href of halls) assert.equal(href, 'https://builders.spike-harbor.example');
118
201
  // C6: this is the bug the stamping fixes — clientBranding() omits domains, so a
119
202
  // client fill can never re-point these and every child sent visitors to the platform.
@@ -121,27 +204,10 @@ test('every cross-host link is stamped to THIS instance, never the platform', ()
121
204
  });
122
205
 
123
206
  test('a pack with no hall of its own falls back to its own apex, not the platform', () => {
124
- const out = applyBrandTokens(HTML, BRAND, 'https://spike-harbor.example', '');
207
+ const out = stamp(HTML, 'https://spike-harbor.example', '');
125
208
  assert.match(out, /data-link-hall href="https:\/\/spike-harbor\.example"/);
126
209
  });
127
210
 
128
- test('no repo path is baked into the page', () => {
129
- // task 1002934 removed the "What you own" section and with it the page's only
130
- // {{sourceRepoUrl}} link (owner-accepted). What must still hold: no HARDCODED
131
- // owner/name — a baked one would point every instance at whoever authored
132
- // this file, and the authorship audit fails it.
133
- assert.doesNotMatch(HTML, /github\.com\/[a-z0-9-]+\/[a-z0-9-]+/i, 'no baked repo path');
134
- });
135
-
136
- test('an unstamped link is removed, not left dangling', () => {
137
- // the page keeps its empty-href scrubber so ANY future unstamped token link
138
- // (the header hall entry today) is dropped rather than rendered dead.
139
- const out = applyBrandTokens(HTML, BRAND, 'https://o.example', '');
140
- assert.match(CODE, /a\[href=""\]/, 'the page drops empty-href links');
141
- assert.match(CODE, /\.remove\(\)/);
142
- assert.ok(out.length > 0);
143
- });
144
-
145
211
  test('a pack with NO domains drops the hall pill server-side rather than stamping href="" (task 1003242)', () => {
146
212
  // the hub has no client scrubber, so an empty token must never reach it as a dead link
147
213
  const HUB = fs.readFileSync(path.join(ROOT, 'public-landing', 'projects.html'), 'utf8');
@@ -152,64 +218,91 @@ test('a pack with NO domains drops the hall pill server-side rather than stampin
152
218
  assert.doesNotMatch(none, /\{\{[a-zA-Z]+\}\}/, 'every other token still stamps');
153
219
  const apexOnly = applyBrandTokens(HUB, BRAND, 'https://spike-harbor.example', '');
154
220
  assert.match(apexOnly, /data-link-hall href="https:\/\/spike-harbor\.example"/, 'an apex alone keeps the pill, pointed at the apex');
155
- const both = applyBrandTokens(HUB, BRAND, 'https://spike-harbor.example', 'https://builders.spike-harbor.example');
156
- assert.match(both, /data-link-hall href="https:\/\/builders\.spike-harbor\.example"/);
157
221
  // the landing page too — its client-side scrubber is no longer the only guard
158
222
  assert.doesNotMatch(applyBrandTokens(HTML, BRAND, '', ''), /<a\b[^>]*href=""/);
159
223
  // a token INSIDE a longer href is a relative path once stamped empty, not a dead link — left alone
160
224
  assert.equal(applyBrandTokens('<a href="{{publicOrigin}}/docs">Docs</a>', BRAND, '', ''), '<a href="/docs">Docs</a>');
161
225
  });
162
226
 
163
- // ── the branding cascade + portability ─────────────────────────────────────
227
+ test('an unstamped link is removed, not left dangling', () => {
228
+ // the page keeps its empty-href scrubber so ANY future unstamped token link
229
+ // is dropped client-side rather than rendered dead.
230
+ assert.match(CODE, /a\[href=""\]/, 'the page drops empty-href links');
231
+ assert.match(CODE, /\.remove\(\)/);
232
+ });
233
+
234
+ test('no repo path is baked into the page', () => {
235
+ // A hardcoded owner/name would point every instance at whoever authored this
236
+ // file, and the authorship audit fails it. The AGPL link is to gnu.org, which
237
+ // is the licence, not a repo.
238
+ assert.doesNotMatch(HTML, /github\.com\/[a-z0-9-]+\/[a-z0-9-]+/i, 'no baked repo path');
239
+ });
240
+
241
+ // ── (3) the branding cascade + portability ─────────────────────────────────
164
242
 
165
243
  test('the page declares no :root — a page-local one defeats re-branding (C1)', () => {
166
- const styles = [...HTML.matchAll(/<style>([\s\S]*?)<\/style>/g)].map((m) => m[1]).join('\n');
167
- assert.ok(styles.length > 0, 'the page ships a local stylesheet');
168
- // :root[data-mode="dark"] .bongos{…} is a DESCENDANT rule, not a :root declaration
169
- // block — it scopes component tokens and cannot outrank the pack's own :root.
170
- assert.doesNotMatch(styles, /:root\s*\{/, 'a bare :root{ } block outranks the injected pack');
171
- assert.doesNotMatch(styles, /:root\[data-mode="dark"\]\s*\{/, 'same, for the dark tier');
244
+ assert.ok(PAGE_STYLES.length > 0, 'the page ships a local stylesheet');
245
+ // :root[data-mode="dark"] body{…} and :root[data-mode="dark"] .sun{…} are
246
+ // DESCENDANT rules, not :root declaration blocks — they scope page-local tokens
247
+ // and cannot outrank the pack's own :root.
248
+ assert.doesNotMatch(PAGE_CSS, /:root\s*\{/, 'a bare :root{ } block outranks the injected pack');
249
+ assert.doesNotMatch(PAGE_CSS, /:root\[data-mode="dark"\]\s*\{/, 'same, for the dark tier');
172
250
  });
173
251
 
174
252
  test('every dark-mode rule is written twice — the block and its media twin (C2)', () => {
175
- const styles = [...HTML.matchAll(/<style>([\s\S]*?)<\/style>/g)].map((m) => m[1]).join('\n');
176
- const explicit = (styles.match(/:root\[data-mode="dark"\]/g) || []).length;
177
- const media = (styles.match(/:root:not\(\[data-mode="light"\]\)/g) || []).length;
253
+ const explicit = (PAGE_CSS.match(/:root\[data-mode="dark"\]/g) || []).length;
254
+ const media = (PAGE_CSS.match(/:root:not\(\[data-mode="light"\]\)/g) || []).length;
178
255
  assert.equal(explicit, media, 'a dark rule with no prefers-color-scheme twin only half-works');
179
- assert.ok(explicit >= 2, 'the drum skin and the hero glow both flip');
256
+ // the shipped page writes four: the mode-toggle icon swap (.sun and .moon are
257
+ // one selector list each), the wide plate/geometry token block, and the two
258
+ // narrow ones. The floor is the count observed at the build, so deleting a
259
+ // twin fails even when the pair stays balanced.
260
+ assert.ok(explicit >= 4, `expected at least 4 dark rules, found ${explicit}`);
261
+ });
262
+
263
+ test('the page links world.css root-absolute, and does not fork the hub sheet', () => {
264
+ // root-absolute so landingPage()'s ?v= content stamp applies: the relative
265
+ // assets/cosmos.css link this page used to carry was never stamped, and a
266
+ // four-hour browser cache then styled new markup with an old sheet (task 1002766).
267
+ assert.match(HTML, /<link rel="stylesheet" href="\/assets\/world\.css">/);
268
+ // cosmos.css is the HUB's component layer (/projects + the legal pages). The
269
+ // landing lives in the world's token layer alone; linking both would give the
270
+ // page two competing derived tiers.
271
+ assert.doesNotMatch(HTML, /cosmos\.css/, 'the landing does not link the hub sheet');
180
272
  });
181
273
 
182
- test('the drum head never inherits a card colour — it would turn black in dark', () => {
183
- const styles = [...HTML.matchAll(/<style>([\s\S]*?)<\/style>/g)].map((m) => m[1]).join('\n');
184
- const skin = styles.match(/\.bongos\{[^}]*\}/);
185
- assert.ok(skin, '.bongos carries its own skin tokens');
186
- assert.match(skin[0], /--skin-hi:/);
187
- assert.doesNotMatch(styles, /--skin-[a-z]+:\s*var\(--bg-card\)/);
274
+ test('nothing about the platform is hardcoded — the file is portable (C5)', () => {
275
+ assert.doesNotMatch(HTML, /cloudbongos\.com/);
188
276
  });
189
277
 
190
- test('the page ships the .sky layer the pack backdrop would otherwise show through (C3)', () => {
191
- assert.match(HTML, /<div class="sky"/);
278
+ test('the page reads without JavaScript: the spine is markup, not script-built', () => {
279
+ const body = HTML.split('<body>')[1].split('<script>')[0];
280
+ for (const copy of [
281
+ 'Building Digitally,', // the hero, first half
282
+ 'as simple as Bongos.', // the hero, second half
283
+ 'A project as a codebase', // the lifecycle heading
284
+ 'Start a project', 'Find a project', // the closing pair
285
+ 'The six most recent, straight from the ledger.', // the ledger's baked sub-line
286
+ 'Skip to content',
287
+ ]) {
288
+ assert.ok(body.includes(copy), `"${copy}" is only reachable with scripting on`);
289
+ }
290
+ // the sign-in door is markup; the script only UPGRADES it to the signed-in chip
291
+ assert.match(body, /class="pill signin" href="\/api\/bongos\/auth\/web\/start\?return=\/">Sign in</);
192
292
  });
193
293
 
194
- // ── the static pose under reduced motion (direction §7) ───────────────────
294
+ // ── (4) the motion kill switch ─────────────────────────────────────────────
195
295
  // The hero animates by default, so this is an accessibility constraint that
196
296
  // fails SILENTLY — nothing about the page looks wrong to a developer who does
197
- // not have the OS setting on. It holds via a cross-FILE dependency (cosmos.css
198
- // carries one global motion kill switch rather than every page repeating it),
199
- // which is the right shape but an invisible one, so both halves are locked here.
200
- // Verified in a real browser with reducedMotion emulation: every hero element
201
- // computes animation-name:none, and the ripples additionally display:none.
202
-
203
- const COSMOS = fs.readFileSync(path.join(ROOT, 'public-landing', 'assets', 'cosmos.css'), 'utf8');
204
- const PAGE_STYLES = [...HTML.matchAll(/<style>([\s\S]*?)<\/style>/g)].map((m) => m[1]).join('\n');
205
- // declarations only — the comments quote the very shapes these tests rule out
206
- const PAGE_CSS = PAGE_STYLES.replace(/\/\*[\s\S]*?\*\//g, '');
297
+ // not have the OS setting on. It holds via a cross-FILE dependency (world.css
298
+ // carries one global switch rather than every page repeating it), which is the
299
+ // right shape but an invisible one, so both halves are locked here.
207
300
 
208
- test('cosmos.css still carries the global motion kill switch the hero relies on', () => {
209
- const block = COSMOS.match(/@media\s*\(prefers-reduced-motion:\s*reduce\)\s*\{([\s\S]*?)\n\}/);
210
- assert.ok(block, 'cosmos.css must keep a prefers-reduced-motion block');
301
+ test('world.css still carries the global motion kill switch the hero relies on', () => {
302
+ const block = WORLD.match(/@media\s*\(prefers-reduced-motion:\s*reduce\)\s*\{([\s\S]*?)\n\}/);
303
+ assert.ok(block, 'world.css must keep a prefers-reduced-motion block');
211
304
  assert.match(block[1], /\*[^{]*\{[^}]*animation:\s*none\s*!important/,
212
- 'the universal selector + !important is what stops the hero; without it the drums keep beating');
305
+ 'the universal selector + !important is what stops the sculpture; without it the blob keeps breathing');
213
306
  });
214
307
 
215
308
  test('nothing on the page marks an animation !important and escapes that switch', () => {
@@ -218,109 +311,145 @@ test('nothing on the page marks an animation !important and escapes that switch'
218
311
  'an !important animation here would outrank the global kill switch');
219
312
  });
220
313
 
221
- test('the hero animations are plain declarations, so the switch reaches them', () => {
222
- // every animated part of the drum kit, as the mock defines the beat
223
- for (const cls of ['drumBig', 'drumSml', 'headBig', 'headSml', 'glow', 'bshadow', 'ring']) {
224
- assert.match(PAGE_STYLES, new RegExp(`\\.bongos\\s+\\.${cls}\\s*\\{[^}]*animation:`),
225
- `.${cls} should be animated in the default (non-reduced) case`);
314
+ test('the signature animations are plain declarations, so the switch reaches them', () => {
315
+ for (const name of [
316
+ 'breathe', 'sheen', 'orbit', // the breath
317
+ 'arrive-form', 'arrive-orb', 'arrive-bead', 'arrive-mark', // the authored moment
318
+ ]) {
319
+ assert.match(PAGE_CSS, new RegExp(`@keyframes\\s+${name}\\s*\\{`), `@keyframes ${name} is gone`);
320
+ assert.match(PAGE_CSS, new RegExp(`animation:[^;}]*\\b${name}\\b`), `nothing runs ${name}`);
226
321
  }
227
322
  });
228
323
 
229
- test('the ripples are hidden under reduced motion — they rest at full stroke', () => {
230
- const reduced = PAGE_STYLES.match(/@media\s*\(prefers-reduced-motion:reduce\)\{([^}]*\})*/);
231
- assert.ok(reduced, 'the page carries its own reduced-motion block');
232
- assert.match(reduced[0], /\.bongos\s+\.ring\s*\{\s*display:none/);
233
- });
234
-
235
- test('the self-typing eyebrow degrades to real text, not an empty span', () => {
236
- // the script only decorates; markup must already carry the whole sentence
237
- assert.match(HTML, /type <b>bongos<\/b> in <span class="typed" id="typed">any AI<\/span>/);
238
- assert.match(CODE, /matchMedia\('\(prefers-reduced-motion: reduce\)'\)/);
239
- assert.match(CODE, /if \(!reduce\) \{/, 'the typing loop is skipped under reduced motion');
240
- });
241
-
242
- test('the eyebrow types the ASSISTANT, never the word you type (task 1002743)', () => {
243
- // "bongos" is the constant — it is the word a person types — and the
244
- // assistant is what varies. Cycling the first slot produced "type claude in
245
- // any AI", which nobody does and which inverts the claim the line makes.
246
- assert.doesNotMatch(HTML, /type <span class="typed"/, 'the typed span must not hold the typed-word slot');
247
- const words = CODE.match(/words\s*=\s*\[([^\]]*)\]/);
248
- assert.ok(words, 'the eyebrow word list must be findable');
249
- assert.doesNotMatch(words[1], /'bongos'/, 'bongos is fixed copy, never a cycled word');
250
- for (const ai of ['Claude', 'ChatGPT', 'Gemini']) {
251
- assert.match(words[1], new RegExp(`'${ai}'`), `${ai} must be one of the cycled assistants`);
324
+ test('the breath stays slow and the arrival stays brief', () => {
325
+ // The signature is meant to be almost subliminal — a period a reader notices
326
+ // is a distraction, and a fast one is a moving-content accessibility problem
327
+ // (WCAG 2.2.2 territory). The floors are well under the shipped values, so
328
+ // this catches a period being retuned by an order of magnitude, not a nudge.
329
+ const period = (name, unit) => {
330
+ const m = PAGE_CSS.match(new RegExp(`\\b${name}\\s+([\\d.]+)${unit}\\b`));
331
+ assert.ok(m, `${name}'s period is no longer findable — update this test`);
332
+ return Number(m[1]);
333
+ };
334
+ assert.ok(period('breathe', 's') >= 30, 'the blob breathes at 32s; under 30s it reads as a pulse');
335
+ assert.ok(period('sheen', 's') >= 30, 'the hue drift is 40s; under 30s the iridescence shimmers');
336
+ assert.ok(period('orbit', 's') >= 60, 'the bead walks its circle in 60s');
337
+ for (const arrive of ['arrive-form', 'arrive-orb', 'arrive-bead', 'arrive-mark']) {
338
+ assert.ok(period(arrive, 'ms') <= 800, `${arrive} holds the first paint too long`);
252
339
  }
253
340
  });
254
341
 
255
- test('nothing about the platform is hardcoded — the file is portable (C5)', () => {
256
- // the source repo link is a real, deliberate attribution; every OTHER mention
257
- // of an origin must be a token.
258
- const withoutSource = HTML.replace(/https:\/\/github\.com\/[^"]*/g, '');
259
- assert.doesNotMatch(withoutSource, /cloudbongos\.com/);
260
- });
261
-
262
- test('the page reads without JavaScript: the spine is markup, not script-built', () => {
263
- const body = HTML.split('<body>')[1].split('<script>')[0];
264
- for (const copy of [
265
- 'Building Digitally, as simple as', // hero (task 1002934)
266
- 'Built by Verro Labs', // the Verro strip
267
- 'A project as a codebase', // S4 heading
268
- 'Explore Bongo Projects', // the hero CTA
269
- 'Start a Project', // the closing pair
270
- 'Find a Project',
342
+ // ── the live-data contract ─────────────────────────────────────────────────
343
+ // Five public feeds fill the page after it has already rendered a real, baked
344
+ // state. Everything here is invisible to a passing render: a feed renamed, an
345
+ // innerHTML crept in with third-party titles in it, a figure quietly redefined.
346
+
347
+ test('the script reads the five public feeds the head comment documents', () => {
348
+ for (const feed of [
349
+ '/public/progress', // the shipped figure + the ledger line
350
+ '/public/cost-summary', // the value figure
351
+ '/public/leaderboard', // the builders figure
352
+ '/public/recent-shipped?limit=6', // the ledger rows
353
+ '/projects/featured', // living proof
271
354
  ]) {
272
- assert.ok(body.includes(copy), `"${copy}" is only reachable with scripting on`);
355
+ assert.ok(CODE.includes(feed), `the page no longer reads ${feed}`);
273
356
  }
274
357
  });
275
358
 
276
- test('the proof band ships hidden so a failed or empty feed leaves no orphan heading', () => {
277
- assert.match(HTML, /<section class="band" id="proof" hidden>/);
278
- // and it is only ever revealed on a non-empty 200
279
- assert.match(HTML, /if \(!list\.length\) return;/);
280
- assert.match(HTML, /band\.hidden = false;/);
359
+ test('feed values are never interpolated as HTML, and hrefs are scheme-checked', () => {
360
+ // every string in these payloads is third-party: task titles, builder names,
361
+ // project names and origins, all written by someone other than this page.
362
+ assert.doesNotMatch(CODE, /innerHTML/, 'the feeds carry third-party strings');
363
+ assert.doesNotMatch(CODE, /document\.write/);
364
+ assert.match(CODE, /createElement\(/, 'the DOM is built, not concatenated');
365
+ assert.match(CODE, /textContent\s*=/);
366
+ assert.match(CODE, /u\.protocol === 'https:' \|\| u\.protocol === 'http:'/);
367
+ assert.match(CODE, /rel = 'noopener'/, 'an outbound project link opens without handing over the opener');
281
368
  });
282
369
 
283
- // The page script minus its comments — these assertions are about what the code
284
- // DOES, and the comments deliberately quote the shapes being ruled out.
285
- const CODE = HTML.split('<script>').pop().replace(/\/\*[\s\S]*?\*\//g, '');
370
+ test('a live task title is normalised to the front door\'s own punctuation', () => {
371
+ // Task titles are write-once quoted data and the ledger hands the page
372
+ // punctuation the taste pre-flight bans (an em dash, a trailing parenthetical
373
+ // like "(owner decision 2026-08-24)"). The rule is applied at RENDER time, so
374
+ // it is invisible until a title with a dash ships.
375
+ const rules = CODE.match(/\.replace\([^\n]*/g) || [];
376
+ const has = (frag) => rules.some((r) => r.includes(frag));
377
+ assert.ok(has('[—–]'), 'em and en dashes become a comma');
378
+ assert.ok(has("', '"), 'and a comma is what they become');
379
+ assert.ok(has('\\([^()]*\\)\\s*$'), 'a trailing parenthetical is dropped');
380
+ assert.ok(has('/,\\s*,/g'), 'the comma a dash leaves beside one collapses');
381
+ });
286
382
 
287
- test('the catalog claims no liveness the public feed cannot back', () => {
288
- // listFeaturedProjects projects {origin, name, tagline, art_url, created_at}
289
- // plus self-reported stats — still no status, so a verification chip here
290
- // would be a claim nothing checked.
291
- assert.doesNotMatch(CODE, /chip (live|maybe|down)/);
292
- assert.doesNotMatch(CODE, /ago/);
383
+ test('each figure is defined the way the head comment says it is', () => {
384
+ // A figure whose definition drifts still renders a plausible number, so the
385
+ // page would lie without ever looking wrong. These are the three definitions.
386
+ assert.match(CODE, /total \+= Number\(r\.shipped_count\)/, 'shipped = the SUM over every progress row');
387
+ assert.match(CODE, /setFig\('shipped'/);
388
+ assert.match(CODE, /data\.total_value_credits/, 'value = total_value_credits from the cost summary');
389
+ assert.match(CODE, /setFig\('value'/);
390
+ assert.match(CODE, /Number\(r\.total_credits\) > 0/, 'builders = leaderboard entries HOLDING credits');
391
+ assert.match(CODE, /setFig\('builders'/);
392
+ // the ledger line + meter come off the first `building` row
393
+ assert.match(CODE, /r\.status === 'building'/);
394
+ assert.match(CODE, /' shipped on '/);
395
+ // numbers are grouped, so the live value matches the baked one's shape
396
+ assert.match(CODE, /toLocaleString\('en-US'\)/);
293
397
  });
294
398
 
295
- test('catalog values are never interpolated as HTML, and hrefs are scheme-checked', () => {
296
- assert.doesNotMatch(CODE, /innerHTML/, 'the feed carries third-party strings');
297
- assert.match(CODE, /u\.protocol === 'https:' \|\| u\.protocol === 'http:'/);
399
+ test('a failed or empty feed leaves the baked state standing', () => {
400
+ // The page has no empty state to fall back to — the baked values ARE the
401
+ // fallback, so every handler must bail rather than blank its target.
402
+ assert.match(CODE, /if \(!rows\.length\) return;/);
403
+ assert.match(CODE, /if \(!tasks\.length \|\| !list\) return;/);
404
+ assert.match(CODE, /if \(!list\.length \|\| !host\) return;/);
405
+ // and a non-2xx or a dropped connection resolves to null rather than throwing
406
+ assert.match(CODE, /res\.ok \? res\.json\(\) : null/);
407
+ assert.match(CODE, /\.catch\(function \(\) \{ return null; \}\)/);
298
408
  });
299
409
 
300
- // ── the shared layer gained the primitives, and the page did not fork it ───
410
+ test('sign out POSTs, and expires both cookies in both Domain forms', () => {
411
+ // The logout endpoint is POST + cookie-gated, so a plain-anchor GET would 404
412
+ // and leave the session live (the hall bug of task 1002245). And a Max-Age=0
413
+ // only matches the cookie whose Domain attribute it names, so the host-only
414
+ // and apex-scoped forms must BOTH be expired (#726).
415
+ assert.match(CODE, /fetch\(API \+ '\/auth\/logout', \{ method: 'POST', credentials: 'same-origin' \}\)/);
416
+ assert.match(CODE, /\['gds_session', 'pms_session'\]/);
417
+ assert.match(CODE, /name \+ '=; Max-Age=0; path=\/';/);
418
+ assert.match(CODE, /name \+ '=; Max-Age=0; path=\/; Domain=\.' \+ apex/);
419
+ // it runs whether the POST lands or not
420
+ assert.match(CODE, /\.then\(finish, finish\)/);
421
+ });
301
422
 
302
- test('the landing links cosmos.css and does not fork the design system', () => {
303
- assert.match(HTML, /<link rel="stylesheet" href="assets\/cosmos\.css">/);
423
+ test('the tagline is one server-stamped string, split for the composition only', () => {
424
+ // The h1 is {{tagline}}. The composition wants it on two lines, so the neutral
425
+ // halves are BAKED as two spans (the page reads correctly standalone and on
426
+ // the apex) — and a host whose tagline is not those halves must get it back
427
+ // whole rather than a headline cut in the wrong place.
428
+ assert.match(HTML, /<h1 data-brand-tagline>/);
429
+ assert.match(HTML, /<span class="l1">Building Digitally,<\/span><span class="l2">as simple as Bongos\.<\/span>/);
430
+ assert.match(CODE, /window\.__BRANDING__/);
431
+ assert.match(CODE, /brand\.copy && brand\.copy\.tagline/);
432
+ assert.match(CODE, /line !== baked\.join\(' '\)/, 'the rejoin is what decides a host tagline differs');
433
+ assert.match(PAGE_CSS, /h1 \.whole\{[^}]*white-space:normal/, 'the whole-tagline fallback must wrap');
304
434
  });
305
435
 
306
- test('the five primitives graduated into cosmos.css, not the page (§6)', () => {
307
- const css = fs.readFileSync(path.join(ROOT, 'public-landing', 'assets', 'cosmos.css'), 'utf8');
308
- assert.match(css, /^\.wrap\{/m, 'the page container');
309
- assert.match(css, /^h2\.sec-h\{/m, 'the type scale below h1');
310
- assert.match(css, /--pad-xl:/, 'the spacing scale');
311
- assert.match(css, /^\.grid\{/m, 'the grid primitive');
312
- assert.match(css, /@media \(max-width:900px\)/, 'the mid breakpoint');
313
- // and the page must not re-declare them locally
314
- const styles = [...HTML.matchAll(/<style>([\s\S]*?)<\/style>/g)].map((m) => m[1]).join('\n');
315
- assert.doesNotMatch(styles, /^\.wrap\{/m, '.wrap belongs to the shared layer');
316
- assert.doesNotMatch(styles, /^\.grid\{/m, '.grid belongs to the shared layer');
436
+ test('the mode is resolved before first paint, and ?mode= wins', () => {
437
+ // A stored dark choice applied by the deferred script flashes the light page
438
+ // first; and ?mode= is how a reviewer walks both modes on one URL, which the
439
+ // render probes depend on.
440
+ assert.match(PREPAINT, /URLSearchParams\(location\.search\)\.get\('mode'\)/);
441
+ assert.match(PREPAINT, /localStorage\.getItem\('cb-color-mode'\)/);
442
+ assert.match(PREPAINT, /setAttribute\('data-mode'/);
443
+ // it is in <head>, ahead of the stylesheet link and the body
444
+ assert.ok(HTML.indexOf('cb-color-mode') < HTML.indexOf('<body>'));
445
+ assert.match(CODE, /localStorage\.setItem\('cb-color-mode', next\)/, 'the toggle persists the choice');
317
446
  });
318
447
 
319
- // ── the assertion tests/platform_boot.mjs will make once the apex flips ────
448
+ // ── the assertions tests/platform_boot.mjs will make once the apex flips ───
320
449
 
321
450
  test('the page satisfies the parked platform_boot assertions', () => {
322
451
  assert.match(HTML, /id="who"/);
323
- assert.match(HTML, /Find a Project/); // the landing marker since task 1002934
452
+ assert.match(HTML, /Find a project/); // the landing marker
324
453
  // an ORG-level action that lives only on the gate — asserted absent there
325
454
  assert.doesNotMatch(HTML, /Create a project/);
326
455
  });