@bongos/core 1.19.726 → 1.19.727

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 (226) hide show
  1. package/.bongos-core.json +176 -491
  2. package/.devcontainer/Dockerfile +1 -1
  3. package/.devcontainer/devcontainer.json +2 -2
  4. package/.devcontainer/healthcheck.sh +1 -1
  5. package/.devcontainer/init-firewall.sh +1 -1
  6. package/.devcontainer/post-create.sh +2 -2
  7. package/.env.local.example +1 -1
  8. package/Dockerfile +1 -1
  9. package/docs/copy-inventory.md +1 -1
  10. package/docs/copy-registry.json +9 -9
  11. package/docs/module-api-changelog.md +2 -0
  12. package/docs/recipes/devbox-app-release.md +4 -4
  13. package/modules/dev-box/app/scripts/dmgbuild-settings.py +5 -5
  14. package/modules/dev-box/app/scripts/gen-brand.js +1 -1
  15. package/modules/dev-box/app/src/brand.js +1 -1
  16. package/modules/dev-box/app/test/unit.mjs +16 -16
  17. package/modules/dev-box/box-access.js +1 -1
  18. package/modules/dev-box/routes/box.js +1 -1
  19. package/modules/discord/discord-approvals.js +1 -1
  20. package/modules/grading/grader-model.js +1 -1
  21. package/modules/grading/grader-prompt.js +1 -1
  22. package/modules/grading/grader-workers/quality.js +1 -1
  23. package/modules/hall-ui/module.json +1 -1
  24. package/modules/hall-ui/public/brand-apply.js +1 -1
  25. package/modules/hall-ui/public/shell.js +1 -1
  26. package/modules/hall-ui/public/work.js +1 -1
  27. package/modules/lifecycle/conflict-resolve.js +1 -1
  28. package/modules/lifecycle/db-analytics.js +1 -1
  29. package/modules/lifecycle/routes/analytics.js +1 -1
  30. package/modules/onboarding/approval-broadcast.js +1 -1
  31. package/modules/onboarding/onboarding.js +1 -1
  32. package/modules/provisioning/tests/liveness.mjs +1 -1
  33. package/modules/public-landing/public/index.html +1 -1
  34. package/modules/public-landing/public/projects-floor.states.json +2 -2
  35. package/modules/public-landing/public/projects.probes.json +4 -4
  36. package/modules/public-landing/public/projects.states.json +2 -2
  37. package/modules/status-ui/module.json +1 -1
  38. package/modules/status-ui/public/status.js +4 -4
  39. package/modules/status-ui/public/style.css +1 -1
  40. package/modules/ui-design/kit/fixtures/cost-summary.json +1 -1
  41. package/modules/ui-design/kit/fixtures/featured-hub.json +1 -1
  42. package/modules/ui-design/kit/fixtures/featured.json +1 -1
  43. package/modules/ui-design/kit/fixtures/leaderboard.json +1 -1
  44. package/modules/ui-design/kit/fixtures/my-projects.json +1 -1
  45. package/modules/ui-design/kit/fixtures/progress.json +1 -1
  46. package/modules/ui-design/kit/fixtures/recent-shipped.json +1 -1
  47. package/package-lock.json +2 -2
  48. package/package.json +1 -1
  49. package/scripts/cron/style_guide_audit.sh +1 -1
  50. package/scripts/discord/lib.js +1 -1
  51. package/scripts/discord/post.js +1 -1
  52. package/scripts/gds/audit-authorship.sh +1 -1
  53. package/scripts/gds/audit-replay.sh +29 -2
  54. package/scripts/gds/audit-ships.js +1 -1
  55. package/scripts/gds/backfill-sessions.js +2 -2
  56. package/scripts/gds/cf-tunnel.js +4 -4
  57. package/scripts/gds/claude-materialize.js +2 -2
  58. package/scripts/gds/cli-lib.js +6 -6
  59. package/scripts/gds/cutover-codemod.js +1 -1
  60. package/scripts/gds/dev-lib.js +2 -2
  61. package/scripts/gds/diagnose-achievements.js +2 -2
  62. package/scripts/gds/fitness-checks-identity.js +6 -4
  63. package/scripts/gds/gen-diagrams.js +1 -1
  64. package/scripts/gds/leak-scan-allowlist.js +293 -0
  65. package/scripts/gds/learning-capture.js +1 -1
  66. package/scripts/gds/linkify-refs.js +2 -2
  67. package/scripts/gds/local-preview-lib.js +1 -1
  68. package/scripts/gds/mirror-lineage-check.js +1 -1
  69. package/scripts/gds/mirror-redact.js +17 -2
  70. package/scripts/gds/newcomer-floor.templates.json +1 -1
  71. package/scripts/gds/package-core.js +18 -1
  72. package/scripts/gds/paste-token.js +1 -1
  73. package/scripts/gds/provision-units.js +2 -2
  74. package/scripts/gds/publish-manifest.js +15 -0
  75. package/scripts/gds/repo-metrics.js +1 -1
  76. package/scripts/gds/sandbox-stage.js +1 -1
  77. package/scripts/gds/seed-bongos-coreB-tranche1-tasks.js +1 -1
  78. package/scripts/gds/seed-bongos-coreB-tranche2-tasks.js +1 -1
  79. package/scripts/gds/seed-bongos-goal-hierarchy-tasks.js +1 -1
  80. package/scripts/gds/seed-bongos-tasks.js +2 -2
  81. package/scripts/gds/seed-gds-v4-tasks.js +1 -1
  82. package/scripts/gds/seed-medusa-tasks.js +10 -10
  83. package/scripts/gds/seed-module-upstreaming.js +1 -1
  84. package/scripts/gds/seed-productization-tasks.js +6 -6
  85. package/scripts/gds/seed-provisioning-tasks.js +2 -2
  86. package/scripts/gds/seed-staging.sh +19 -6
  87. package/scripts/gds/ship-deploy-target.js +1 -1
  88. package/scripts/gds/ship-flow.js +1 -1
  89. package/scripts/gds/smoke-gds.js +1 -1
  90. package/scripts/status-probe.mjs +2 -2
  91. package/src/bongos/auth-discord.js +2 -2
  92. package/src/bongos/live-channel.js +1 -1
  93. package/src/bongos/pool.js +1 -1
  94. package/src/bongos/routes/auth.js +11 -11
  95. package/src/bongos/routes/security.js +1 -1
  96. package/src/bongos/routes.js +1 -1
  97. package/src/branding.js +1 -1
  98. package/src/devbox-downloads.js +1 -1
  99. package/src/instance-config.js +2 -2
  100. package/src/module-api.js +1 -1
  101. package/src/module-loader/provenance.js +2 -2
  102. package/tests/art_stage.mjs +2 -2
  103. package/tests/auth_anthropic_identity.mjs +1 -1
  104. package/tests/auth_duplicate_cookie.mjs +1 -1
  105. package/tests/auth_error_brand.mjs +1 -1
  106. package/tests/auth_inactive_builder.mjs +1 -1
  107. package/tests/backup_cli.mjs +4 -4
  108. package/tests/bongos_box_connect.mjs +2 -2
  109. package/tests/bongos_downloads.mjs +2 -2
  110. package/tests/bongos_login.mjs +5 -5
  111. package/tests/box_connect_e2e.mjs +2 -2
  112. package/tests/box_dns_repoint.mjs +10 -10
  113. package/tests/box_host_keys.mjs +1 -1
  114. package/tests/box_onboard.mjs +9 -9
  115. package/tests/box_scope_session.mjs +1 -1
  116. package/tests/box_terminal_ssrf.mjs +7 -7
  117. package/tests/boxes.mjs +9 -9
  118. package/tests/branding.mjs +2 -2
  119. package/tests/bump_version.mjs +2 -2
  120. package/tests/cf_tunnel.mjs +40 -40
  121. package/tests/cli_token_reissue.mjs +7 -7
  122. package/tests/cloud_bongos_pack.mjs +1 -1
  123. package/tests/currency_label.mjs +8 -8
  124. package/tests/dev_lib.mjs +4 -4
  125. package/tests/devbox_dmg_backdrop.mjs +1 -1
  126. package/tests/devbox_downloads.mjs +2 -2
  127. package/tests/devbox_icons.mjs +1 -1
  128. package/tests/discord_approvals.mjs +1 -1
  129. package/tests/discord_oauth.mjs +2 -2
  130. package/tests/executed_closure.mjs +6 -1
  131. package/tests/first_admin_bootstrap.mjs +1 -1
  132. package/tests/gate_approvals.mjs +5 -5
  133. package/tests/grade_aggregates_unavailable.mjs +1 -1
  134. package/tests/hook_user_agents.mjs +2 -2
  135. package/tests/init.mjs +6 -6
  136. package/tests/instance_config.mjs +1 -1
  137. package/tests/instance_manifest.mjs +5 -5
  138. package/tests/instance_mismatch_guard.mjs +13 -13
  139. package/tests/leak_scan_allowlist.mjs +94 -0
  140. package/tests/migrate_root_resolution.mjs +4 -4
  141. package/tests/mirror_redact.mjs +28 -4
  142. package/tests/module_catalog.mjs +5 -5
  143. package/tests/module_submissions.mjs +3 -3
  144. package/tests/package_core.mjs +1 -1
  145. package/tests/parallel-load.mjs +6 -6
  146. package/tests/projects_hub.mjs +2 -2
  147. package/tests/provision.mjs +50 -50
  148. package/tests/provisioning_github_app_routes.mjs +1 -1
  149. package/tests/provisioning_onboard_mode.mjs +2 -2
  150. package/tests/publish_reconciler.mjs +4 -4
  151. package/tests/sandbox_stage.mjs +1 -1
  152. package/tests/scrubber_corpus.mjs +3 -3
  153. package/tests/search_isolation.mjs +1 -1
  154. package/tests/session_records.mjs +1 -1
  155. package/tests/ship_card.mjs +6 -6
  156. package/tests/ship_ci_deploy.mjs +1 -1
  157. package/tests/single_host_hall.mjs +9 -9
  158. package/tests/smoke_preflight.mjs +1 -1
  159. package/tests/smoke_target.mjs +1 -1
  160. package/tests/status-probe.mjs +1 -1
  161. package/tests/status_mirror_sync.mjs +1 -1
  162. package/docs/adr/0004-amazonprimea-name-and-trademark-acceptance.md +0 -45
  163. package/docs/design/mocks/_schemes.css +0 -604
  164. package/docs/design/mocks/component-sheet.html +0 -428
  165. package/docs/design/mocks/hall/_tokens.css +0 -370
  166. package/docs/design/mocks/hall/board/v1.html +0 -846
  167. package/docs/design/mocks/hall/board/v2.html +0 -858
  168. package/docs/design/mocks/hall/board/v3.html +0 -884
  169. package/docs/design/mocks/hall/goals/v1.html +0 -1212
  170. package/docs/design/mocks/hall/goals/v2.html +0 -1192
  171. package/docs/design/mocks/hall/goals/v3.html +0 -1205
  172. package/docs/design/mocks/hall/hall-sheet.html +0 -244
  173. package/docs/design/mocks/hall/reading/v1.html +0 -1125
  174. package/docs/design/mocks/hall/reading/v2.html +0 -1177
  175. package/docs/design/mocks/hall/reading/v3.html +0 -1150
  176. package/docs/design/mocks/hall/settings/v1.html +0 -1238
  177. package/docs/design/mocks/hall/settings/v2.html +0 -1235
  178. package/docs/design/mocks/hall/settings/v3.html +0 -1299
  179. package/docs/design/mocks/hall/task/v1.html +0 -633
  180. package/docs/design/mocks/hall/task/v2.html +0 -646
  181. package/docs/design/mocks/hall/task/v3.html +0 -647
  182. package/docs/design/mocks/hub/assets/r3-space-deepfield-half.jpg +0 -0
  183. package/docs/design/mocks/hub/assets/r3-space-deepfield-half.jpg.json +0 -13
  184. package/docs/design/mocks/hub/assets/r3-space-dust-half.jpg +0 -0
  185. package/docs/design/mocks/hub/assets/r3-space-dust-half.jpg.json +0 -13
  186. package/docs/design/mocks/hub/assets/r3-space-nebula-half.jpg +0 -0
  187. package/docs/design/mocks/hub/assets/r3-space-nebula-half.jpg.json +0 -13
  188. package/docs/design/mocks/hub/assets/r3-space-starfield-half.jpg +0 -0
  189. package/docs/design/mocks/hub/assets/r3-space-starfield-half.jpg.json +0 -13
  190. package/docs/design/mocks/hub/hub-sheet.html +0 -192
  191. package/docs/design/mocks/hub/mine.html +0 -465
  192. package/docs/design/mocks/hub/picker.html +0 -421
  193. package/docs/design/mocks/hub/planets.html +0 -356
  194. package/docs/design/mocks/hub/v1.html +0 -1209
  195. package/docs/design/mocks/hub/v2.html +0 -1257
  196. package/docs/design/mocks/hub/v3.html +0 -1496
  197. package/docs/design/mocks/hub/wizard.html +0 -421
  198. package/docs/design/mocks/landing/landing-sheet.html +0 -131
  199. package/docs/design/mocks/landing/v1.html +0 -956
  200. package/docs/design/mocks/landing/v2.html +0 -708
  201. package/docs/design/mocks/landing/v3.html +0 -911
  202. package/docs/design/mocks/landing-page-mock.html +0 -687
  203. package/docs/design/mocks/landing-palettes.html +0 -103
  204. package/docs/design/mocks/projects-hub-mock.html +0 -991
  205. package/docs/design/mocks/projects-hub-variants.html +0 -146
  206. package/docs/design/mocks/projects-page-mock.html +0 -167
  207. package/docs/design/mocks/world/blue-hud/_tokens.css +0 -246
  208. package/docs/design/mocks/world/blue-hud/hall.html +0 -595
  209. package/docs/design/mocks/world/blue-hud/landing.html +0 -424
  210. package/docs/design/mocks/world/blue-hud/status.html +0 -410
  211. package/docs/design/mocks/world/chrome-blobs/_tokens.css +0 -479
  212. package/docs/design/mocks/world/chrome-blobs/hall.html +0 -553
  213. package/docs/design/mocks/world/chrome-blobs/landing-b.html +0 -581
  214. package/docs/design/mocks/world/chrome-blobs/landing.html +0 -328
  215. package/docs/design/mocks/world/chrome-blobs/status.html +0 -416
  216. package/docs/design/mocks/world/natgeo-editorial/_tokens.css +0 -377
  217. package/docs/design/mocks/world/natgeo-editorial/hall.html +0 -649
  218. package/docs/design/mocks/world/natgeo-editorial/landing-b.html +0 -743
  219. package/docs/design/mocks/world/natgeo-editorial/landing.html +0 -475
  220. package/docs/design/mocks/world/natgeo-editorial/status.html +0 -437
  221. package/docs/design/mocks/world/organic-cards/_tokens.css +0 -462
  222. package/docs/design/mocks/world/organic-cards/hall.html +0 -625
  223. package/docs/design/mocks/world/organic-cards/landing-b.html +0 -736
  224. package/docs/design/mocks/world/organic-cards/landing.html +0 -420
  225. package/docs/design/mocks/world/organic-cards/status.html +0 -458
  226. package/docs/design/mocks/world/world-sheet.html +0 -156
@@ -14,10 +14,10 @@ const RANK_TIER = { xenos: 1, thetes: 2, metic: 3, archon: 4 };
14
14
 
15
15
  // A client-safe branding projection (the shape clientBranding() returns).
16
16
  const BRAND_OTB = {
17
- identity: { productName: 'Off the Boats', worldName: 'Amazonprimea', company: { name: 'Hermeslines' } },
17
+ identity: { productName: 'Example World', worldName: 'Example', company: { name: 'Hermeslines' } },
18
18
  currency: { label: 'drachmae', symbol: '' },
19
19
  theme: { colors: {}, fonts: { display: '', body: '', links: [] }, favicon: '', backdrop: '' },
20
- copy: { tagline: 'Straight off the boats', hallName: 'Builders’ Hall', notFound: 'Page not found.' },
20
+ copy: { tagline: 'Straight example world', hallName: 'Builders’ Hall', notFound: 'Page not found.' },
21
21
  rankLabels: { xenos: 'Xenos', thetes: 'Thetes', metic: 'Metic', archon: 'Archon' },
22
22
  // the per-project policy the platform pushes (task 1003140) — the settings read-back
23
23
  project: { platformVisibility: 'gated', joinability: 'invite_only' },
@@ -37,12 +37,12 @@ const MODULES_VANILLA = {
37
37
  enabled: { game: false, 'art-pipeline': false, discord: false, 'dev-box': false },
38
38
  disciplines: ['engineer'],
39
39
  };
40
- const REPO = { owner: 'lars589', repo: 'amazonprimea', branch: 'main', blob_base: 'x', tree_base: 'y' };
40
+ const REPO = { owner: 'example-owner', repo: 'example', branch: 'main', blob_base: 'x', tree_base: 'y' };
41
41
 
42
42
  test('manifest: schema id + headline name + embedded brand', () => {
43
43
  const m = buildInstanceManifest({ branding: BRAND_OTB, modules: MODULES_OTB, rankTier: RANK_TIER, repo: REPO, authConfigured: true, openEnrollment: false, devBoxEnabled: true });
44
44
  assert.equal(m.schema, MANIFEST_SCHEMA);
45
- assert.equal(m.name, 'Off the Boats');
45
+ assert.equal(m.name, 'Example World');
46
46
  assert.equal(m.brand, BRAND_OTB);
47
47
  assert.deepEqual(m.modules, MODULES_OTB);
48
48
  });
@@ -69,7 +69,7 @@ test('manifest: rank label falls back to the key when unlabelled', () => {
69
69
 
70
70
  test('manifest: repo projects to public clone coords; null on error', () => {
71
71
  const ok = buildInstanceManifest({ branding: BRAND_OTB, modules: MODULES_OTB, rankTier: RANK_TIER, repo: REPO, authConfigured: true, openEnrollment: false, devBoxEnabled: true });
72
- assert.deepEqual(ok.repo, { owner: 'lars589', repo: 'amazonprimea', branch: 'main', url: 'https://github.com/lars589/amazonprimea' });
72
+ assert.deepEqual(ok.repo, { owner: 'example-owner', repo: 'example', branch: 'main', url: 'https://github.com/example-owner/example' });
73
73
  const none = buildInstanceManifest({ branding: BRAND_VANILLA, modules: MODULES_VANILLA, rankTier: RANK_TIER, repo: { error: 'no_repo_info' }, authConfigured: false, openEnrollment: false, devBoxEnabled: false });
74
74
  assert.equal(none.repo, null);
75
75
  });
@@ -7,7 +7,7 @@
7
7
  //
8
8
  // The guard stops the CLI from silently borrowing a DIFFERENT instance's session
9
9
  // (the 2026-07-08 demo-session failure, where a fresh demo clone used the
10
- // founder's amazonprimea.com session and offered to write into the wrong live
10
+ // founder's example.com session and offered to write into the wrong live
11
11
  // backlog). Both helpers are deterministic with no DB/network/fs, so they
12
12
  // unit-test standalone. Run: node tests/instance_mismatch_guard.mjs
13
13
 
@@ -25,14 +25,14 @@ function test(name, fn) {
25
25
  }
26
26
 
27
27
  const DEMO = { domains: { publicOrigin: 'https://demo.cloudbongos.com' } };
28
- const OTB = { domains: { publicOrigin: 'https://amazonprimea.com' } };
28
+ const OTB = { domains: { publicOrigin: 'https://example.com' } };
29
29
  const noEnv = {}; // no <PREFIX>_API_BASE override in scope
30
30
  const branded = () => true; // simulate a checkout that HAS config/branding.json (a declared instance)
31
31
  const neutral = () => false; // simulate a NEUTRAL checkout (portable core — no config/branding.json)
32
32
 
33
33
  test('instanceOriginHost: extracts host, tolerates trailing slash', () => {
34
- assert.equal(cli.instanceOriginHost('https://amazonprimea.com'), 'amazonprimea.com');
35
- assert.equal(cli.instanceOriginHost('https://amazonprimea.com/'), 'amazonprimea.com');
34
+ assert.equal(cli.instanceOriginHost('https://example.com'), 'example.com');
35
+ assert.equal(cli.instanceOriginHost('https://example.com/'), 'example.com');
36
36
  assert.equal(cli.instanceOriginHost('https://demo.cloudbongos.com/api/gds'), 'demo.cloudbongos.com');
37
37
  });
38
38
 
@@ -43,20 +43,20 @@ test('instanceOriginHost: unparseable input → null (edge)', () => {
43
43
  });
44
44
 
45
45
  test('match: same-host session + branding → no mismatch (the OTB/normal case)', () => {
46
- const r = cli.detectInstanceMismatch({ session: { api_base: 'https://amazonprimea.com' }, brand: OTB, env: noEnv, hasInstanceConfig: branded });
46
+ const r = cli.detectInstanceMismatch({ session: { api_base: 'https://example.com' }, brand: OTB, env: noEnv, hasInstanceConfig: branded });
47
47
  assert.equal(r.mismatch, false);
48
48
  });
49
49
 
50
50
  test('match: scheme/trailing-slash differences still match on host', () => {
51
- const r = cli.detectInstanceMismatch({ session: { api_base: 'https://amazonprimea.com/' }, brand: OTB, env: noEnv, hasInstanceConfig: branded });
51
+ const r = cli.detectInstanceMismatch({ session: { api_base: 'https://example.com/' }, brand: OTB, env: noEnv, hasInstanceConfig: branded });
52
52
  assert.equal(r.mismatch, false);
53
53
  });
54
54
 
55
- test('mismatch: demo repo + founder amazonprimea session → REFUSE (the reported failure)', () => {
56
- const r = cli.detectInstanceMismatch({ session: { api_base: 'https://amazonprimea.com' }, brand: DEMO, env: noEnv, hasInstanceConfig: branded });
55
+ test('mismatch: demo repo + founder example session → REFUSE (the reported failure)', () => {
56
+ const r = cli.detectInstanceMismatch({ session: { api_base: 'https://example.com' }, brand: DEMO, env: noEnv, hasInstanceConfig: branded });
57
57
  assert.equal(r.mismatch, true);
58
58
  assert.equal(r.expected, 'https://demo.cloudbongos.com');
59
- assert.equal(r.actual, 'https://amazonprimea.com');
59
+ assert.equal(r.actual, 'https://example.com');
60
60
  });
61
61
 
62
62
  test('mismatch: demo repo + cloudbongos.com session (sibling instance) → REFUSE', () => {
@@ -66,15 +66,15 @@ test('mismatch: demo repo + cloudbongos.com session (sibling instance) → REFUS
66
66
 
67
67
  test('env-override: an explicit *_API_BASE override wins (dev/staging) → no mismatch', () => {
68
68
  const r = cli.detectInstanceMismatch({
69
- session: { api_base: 'https://amazonprimea.com' }, brand: DEMO,
69
+ session: { api_base: 'https://example.com' }, brand: DEMO,
70
70
  env: { GDS_API_BASE: 'http://localhost:3000' },
71
71
  });
72
72
  assert.equal(r.mismatch, false);
73
73
  });
74
74
 
75
75
  test('no-branding: repo declares no publicOrigin → cannot assert a mismatch → no mismatch', () => {
76
- assert.equal(cli.detectInstanceMismatch({ session: { api_base: 'https://amazonprimea.com' }, brand: {}, env: noEnv, hasInstanceConfig: branded }).mismatch, false);
77
- assert.equal(cli.detectInstanceMismatch({ session: { api_base: 'https://amazonprimea.com' }, brand: { domains: {} }, env: noEnv, hasInstanceConfig: branded }).mismatch, false);
76
+ assert.equal(cli.detectInstanceMismatch({ session: { api_base: 'https://example.com' }, brand: {}, env: noEnv, hasInstanceConfig: branded }).mismatch, false);
77
+ assert.equal(cli.detectInstanceMismatch({ session: { api_base: 'https://example.com' }, brand: { domains: {} }, env: noEnv, hasInstanceConfig: branded }).mismatch, false);
78
78
  });
79
79
 
80
80
  test('NEUTRAL checkout (no config/branding.json) → trust the session, NO mismatch (task 1002399)', () => {
@@ -88,7 +88,7 @@ test('NEUTRAL checkout (no config/branding.json) → trust the session, NO misma
88
88
 
89
89
  test('neutral guard is precedence-safe: env override still wins even when neutral', () => {
90
90
  // env override short-circuits before the neutral check — order-independent.
91
- const r = cli.detectInstanceMismatch({ session: { api_base: 'https://amazonprimea.com' }, brand: DEMO, env: { GDS_API_BASE: 'http://localhost:3000' }, hasInstanceConfig: neutral });
91
+ const r = cli.detectInstanceMismatch({ session: { api_base: 'https://example.com' }, brand: DEMO, env: { GDS_API_BASE: 'http://localhost:3000' }, hasInstanceConfig: neutral });
92
92
  assert.equal(r.mismatch, false);
93
93
  });
94
94
 
@@ -0,0 +1,94 @@
1
+ // tests/leak_scan_allowlist.mjs
2
+ //
3
+ // Task 1003869 — the named exceptions to the prior-instance leak scan. The allowlist is
4
+ // a security carve-out, so what matters is not that it permits the right things but that
5
+ // it CANNOT permit the wrong ones: scoping is per (path, literal), a listed file does not
6
+ // become a free pass, and an entry that stops matching is reported rather than forgotten.
7
+ //
8
+ // Run: node tests/leak_scan_allowlist.mjs
9
+
10
+ import { strict as assert } from 'node:assert';
11
+ import { createRequire } from 'node:module';
12
+
13
+ const require = createRequire(import.meta.url);
14
+ const A = require('../scripts/gds/leak-scan-allowlist.js');
15
+ const { allowReason, partitionHits, unusedEntries, FILE_ALLOWLIST, WELL_KNOWN_PUBLIC_IPS } = A;
16
+ const { PRIOR_INSTANCE_FLOOR } = require('../scripts/gds/package-core.js');
17
+
18
+ // This test file is itself published, so it derives the literals it exercises rather
19
+ // than spelling them out — the same self-leak invariant the allowlist module holds.
20
+ const OWNER = PRIOR_INSTANCE_FLOOR.owners[0];
21
+ const TOKEN = PRIOR_INSTANCE_FLOOR.tokens[0];
22
+
23
+ let passed = 0, failed = 0;
24
+ function t(name, fn) {
25
+ try { fn(); passed++; console.log(` PASS ${name}`); }
26
+ catch (e) { failed++; console.log(` FAIL ${name}\n ${e.message}`); }
27
+ }
28
+
29
+ // ── every entry carries its reason ───────────────────────────────────────────────────
30
+ t('every entry names a path, at least one literal, and a substantive reason', () => {
31
+ for (const e of FILE_ALLOWLIST) {
32
+ assert.ok(e.path && typeof e.path === 'string', 'entry needs a path');
33
+ assert.ok(Array.isArray(e.classes) && e.classes.length > 0, `${e.path} needs classes`);
34
+ assert.ok(typeof e.reason === 'string' && e.reason.length > 40,
35
+ `${e.path} needs a reason that explains itself, not a label`);
36
+ }
37
+ for (const [ip, why] of Object.entries(WELL_KNOWN_PUBLIC_IPS)) {
38
+ assert.ok(typeof why === 'string' && why.length > 10, `${ip} needs a reason`);
39
+ }
40
+ });
41
+
42
+ // ── scoping: a listed file is NOT a free pass ────────────────────────────────────────
43
+ t('an allowlisted file still fails on a literal it was not listed for', () => {
44
+ // mirror-redact.js is listed for public-ip only. An owner login appearing there would
45
+ // be a real leak — the SELF-LEAK INVARIANT that file documents about itself.
46
+ assert.ok(allowReason('scripts/gds/mirror-redact.js', 'public-ip', '8.8.8.8'));
47
+ assert.equal(allowReason('scripts/gds/mirror-redact.js', `literal:${OWNER}`, OWNER), null,
48
+ 'a literal whose class is not named for this path must still fail');
49
+ });
50
+ t('an entry does not leak across to another path', () => {
51
+ // audit-authorship.sh may carry the owner login; an arbitrary script may not.
52
+ assert.ok(allowReason('scripts/gds/audit-authorship.sh', `literal:${OWNER}`, OWNER));
53
+ assert.equal(allowReason('scripts/gds/some-other-script.js', `literal:${OWNER}`, OWNER), null);
54
+ });
55
+ t('an unlisted file gets no exception at all', () => {
56
+ assert.equal(allowReason('src/bongos/routes/auth.js', `literal:${TOKEN}`, TOKEN), null);
57
+ assert.equal(allowReason('src/anything.js', 'public-ip', '203.0.113.9'), null,
58
+ 'an address that is not well-known is not covered anywhere');
59
+ });
60
+
61
+ // ── well-known addresses are global, and exact ───────────────────────────────────────
62
+ t('a well-known public address is covered in any file, but only by exact match', () => {
63
+ assert.ok(allowReason('tests/anything.mjs', 'public-ip', '8.8.8.8'));
64
+ assert.ok(allowReason('modules/whatever/x.js', 'public-ip', '1.1.1.1'));
65
+ // An address that is not on the well-known list is covered NOWHERE — the whole point of
66
+ // the sweep. Asserted with RFC 5737 documentation addresses rather than this instance's
67
+ // real ones: a test that pins "our droplet must not be allowlisted" by NAMING the droplet
68
+ // puts it straight back into the published trunk, which is the leak it is guarding against.
69
+ assert.equal(allowReason('tests/anything.mjs', 'public-ip', '198.51.100.7'), null);
70
+ assert.equal(allowReason('tests/anything.mjs', 'public-ip', '192.0.2.99'), null);
71
+ });
72
+
73
+ // ── partition + staleness ────────────────────────────────────────────────────────────
74
+ t('partitionHits separates covered hits from real ones and attaches the reason', () => {
75
+ const hits = [
76
+ { path: 'tests/mirror_redact.mjs', label: 'public-ip', sample: '8.8.8.8' },
77
+ { path: 'src/bongos/routes/auth.js', label: `literal:${TOKEN}`, sample: TOKEN },
78
+ ];
79
+ const { allowed, remaining } = partitionHits(hits);
80
+ assert.equal(allowed.length, 1);
81
+ assert.ok(allowed[0].reason.length > 10, 'a covered hit carries the reason it was covered');
82
+ assert.equal(remaining.length, 1);
83
+ assert.equal(remaining[0].path, 'src/bongos/routes/auth.js');
84
+ });
85
+ t('unusedEntries reports an entry that has stopped matching', () => {
86
+ // No hits at all → every file entry is stale, which is the signal to prune.
87
+ assert.ok(unusedEntries([]).length > 0);
88
+ // A hit that covers one entry removes exactly that one from the stale list.
89
+ const stale = unusedEntries([{ path: 'scripts/gds/mirror-redact.js', label: 'public-ip', sample: '8.8.8.8' }]);
90
+ assert.ok(!stale.some((s) => s.path === 'scripts/gds/mirror-redact.js' && s.literal === 'public-ip'));
91
+ });
92
+
93
+ console.log(`\n${passed} passed, ${failed} failed`);
94
+ process.exit(failed ? 1 : 0);
@@ -72,7 +72,7 @@ function printRoots({ cwd, initCwd } = {}) {
72
72
  }
73
73
 
74
74
  // A synthetic consumer: a dir with a bongos.config.json pointing at itself, exactly
75
- // as the post-split amazonprimea repo carries (bongos.config.json { instanceRoot: "." }).
75
+ // as the post-split example repo carries (bongos.config.json { instanceRoot: "." }).
76
76
  function makeConsumer() {
77
77
  const dir = mkFixture('r89-consumer-');
78
78
  writeFileSync(path.join(dir, 'bongos.config.json'), JSON.stringify({ instanceRoot: '.' }));
@@ -249,7 +249,7 @@ t('the pre-fix unquoted loop now fails loudly instead of silently skipping', ()
249
249
  // ==========================================================================
250
250
  // WHICH DATABASE does migrate target? (task 1002755)
251
251
  //
252
- // scripts/migrate.sh:52 used to read `DB="${PGDATABASE:-amazonprimea}"` — one host instance's
252
+ // scripts/migrate.sh:52 used to read `DB="${PGDATABASE:-example}"` — one host instance's
253
253
  // database name, baked into a script the core ships to EVERY instance. With no PGDATABASE in the
254
254
  // environment, a co-hosted box silently aimed at a stranger's database and everywhere else died
255
255
  // with a confusing "database ... does not exist" — after the caller had already moved its version
@@ -314,7 +314,7 @@ t('an instance that names no database is REFUSED, never defaulted', () => {
314
314
  assert.match(r.stderr, /cannot determine which database/i);
315
315
  assert.match(r.stderr, /Refusing to guess/i);
316
316
  // the regression itself: it must not reach for another instance's database
317
- assert.doesNotMatch(`${r.stdout}${r.stderr}`, /amazonprimea/i);
317
+ assert.doesNotMatch(`${r.stdout}${r.stderr}`, /example/i);
318
318
  });
319
319
 
320
320
  t('--print-migrations stays DB-free — a dry run must not require a database name', () => {
@@ -333,7 +333,7 @@ t('migrate.sh hardcodes no instance database name', () => {
333
333
  const code = src.split(/\r?\n/).filter((l) => !/^\s*#/.test(l)).join('\n');
334
334
  assert.doesNotMatch(code, /PGDATABASE:-\s*[A-Za-z]/,
335
335
  'PGDATABASE must have no literal fallback — resolve from the branding pack instead');
336
- assert.doesNotMatch(code, /amazonprimea/i, 'no instance database name in executable lines');
336
+ assert.doesNotMatch(code, /example/i, 'no instance database name in executable lines');
337
337
  });
338
338
 
339
339
  console.log(`\nmigrate_root_resolution: ${passed} passed, ${failed} failed`);
@@ -104,12 +104,12 @@ t('isPublicRoutableIPv4 classifier boundaries', () => {
104
104
 
105
105
  // ── IPv6 floor: global unicast redacted, loopback/link-local/ULA kept ─────────────────
106
106
  t('public IPv6 (the droplet) redacted; loopback/link-local/ULA kept', () => {
107
- const out = redactText('v6 2604:a880:800:14:0:2:ee66:b000 keep fe80::1 fc00::5 ::1', rules);
107
+ const out = redactText('v6 2606:4700:4700::1111 keep fe80::1 fc00::5 ::1', rules);
108
108
  assert.ok(!out.includes('2604:a880'), `public IPv6 leaked: ${out}`);
109
109
  assert.ok(out.includes('fe80::1') && out.includes('fc00::5') && out.includes('::1'), out);
110
110
  });
111
111
  t('isPublicRoutableIPv6 + a "12:34:56" timestamp is NOT treated as an IP', () => {
112
- assert.equal(isPublicRoutableIPv6('2604:a880:800:14:0:2:ee66:b000'), true);
112
+ assert.equal(isPublicRoutableIPv6('2606:4700:4700::1111'), true);
113
113
  assert.equal(isPublicRoutableIPv6('fe80::1'), false);
114
114
  assert.equal(isPublicRoutableIPv6('fc00::5'), false);
115
115
  assert.equal(isPublicRoutableIPv6('::1'), false);
@@ -127,14 +127,38 @@ t('reserved ::/8 is NOT a public IP — degenerate shorthand in binary is not a
127
127
  }
128
128
  // ...and the narrowing did NOT blunt the gate: real global unicast still fires, in
129
129
  // both the detector and the redactor.
130
- for (const s of ['2000::1', '2001:db8::1', '2606:4700:4700::1111', '3fff::1']) {
130
+ for (const s of ['2000::1', '2606:4700:4700::1111', '3fff::1']) {
131
131
  assert.equal(isPublicRoutableIPv6(s), true, `${s} is a real public address and must still be flagged`);
132
132
  }
133
+ // 2001:db8::/32 is RESERVED FOR DOCUMENTATION (RFC 3849) — the IPv6 analogue of the
134
+ // RFC 5737 TEST-NET ranges v4 already exempts, and for the same reason: it is the
135
+ // address an example is SUPPOSED to use, nothing is reachable there, and flagging it
136
+ // only punishes docs for being written correctly (task 1003869). It was listed above
137
+ // as "a real public address" until then, which RFC 3849 says it is not.
138
+ for (const s of ['2001:db8::1', '2001:0db8:85a3:0000:0000:8a2e:0370:7334']) {
139
+ assert.equal(isPublicRoutableIPv6(s), false, `${s} is the RFC 3849 doc range and must not be flagged`);
140
+ }
133
141
  assert.equal(firstPublicIP('sprite bytes :: more bytes'), null, 'binary-ish shorthand is not reported');
134
142
  assert.equal(firstPublicIP('origin 2606:4700:4700::1111'), '2606:4700:4700::1111');
135
143
  assert.ok(!redactText('host 2606:4700:4700::1111', []).includes('2606:4700'), 'a real public IPv6 is still redacted');
136
144
  });
137
145
 
146
+ // ── candidate guards: things that LOOK like an address but are not one ───────────────
147
+ t('a leading-zero octet is packed numeric data, not an address (task 1003869)', () => {
148
+ // The committed GitHub logo path contains "…5.47 7.59.4.07.5…". The candidate regex
149
+ // reads 7.59.4.07 as a dotted quad, and it flagged ten phantom public-ip leaks across
150
+ // the design mocks and the landing page. No notation writes a host with a leading-zero
151
+ // octet ("07" is octal), so the guard costs nothing on a genuinely leaked address.
152
+ assert.equal(firstPublicIP('M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.5-.17'), null);
153
+ assert.equal(firstPublicIP('host 7.59.4.07'), null);
154
+ assert.equal(firstPublicIP('host 7.59.4.7'), '7.59.4.7', 'the same quad without the zero IS an address');
155
+ });
156
+ t('RFC 2544 benchmarking space 198.18/15 is not instance topology', () => {
157
+ assert.equal(isPublicRoutableIPv4(198, 18, 0, 1), false);
158
+ assert.equal(isPublicRoutableIPv4(198, 19, 255, 254), false);
159
+ assert.equal(isPublicRoutableIPv4(198, 20, 0, 1), true, 'the neighbouring /15 is ordinary public space');
160
+ });
161
+
138
162
  // ── the DETECTOR is stricter than redaction ───────────────────────────────────────────
139
163
  t('findLeaks catches a raw literal substring a bounded rule would miss', () => {
140
164
  // "azoltanb" has no word boundary around zoltan; a \bzoltan\b rule misses it, the
@@ -143,7 +167,7 @@ t('findLeaks catches a raw literal substring a bounded rule would miss', () => {
143
167
  assert.ok(findLeaks('inline widgetco reference', literals).length > 0);
144
168
  });
145
169
  t('findLeaks is clean on fully-redacted output (fixed point)', () => {
146
- const dirty = 'https://widgetco.com by zoltan at 8.8.8.8 and 2604:a880:800:14:0:2:ee66:b000';
170
+ const dirty = 'https://widgetco.com by zoltan at 8.8.8.8 and 2606:4700:4700::1111';
147
171
  const clean = redactText(dirty, rules);
148
172
  assert.deepEqual(findLeaks(clean, literals), [], `residual leaks: ${JSON.stringify(findLeaks(clean, literals))}`);
149
173
  });
@@ -121,7 +121,7 @@ test('buildCatalog: keeps the DECLARED manifest fields beside the display credit
121
121
 
122
122
  test('buildCatalog: source and provenance are independent axes', () => {
123
123
  const rows = catalog.buildCatalog({
124
- loaded: [loadedIn(CORE, 'provisioning', { origin: 'Off the Boats', author: 'Off the Boats' })],
124
+ loaded: [loadedIn(CORE, 'provisioning', { origin: 'Example World', author: 'Example World' })],
125
125
  coreRoot: CORE, instanceRoot: INST,
126
126
  ownProjectName: 'Mercury',
127
127
  });
@@ -156,7 +156,7 @@ test('buildCatalog: survives a manifest with nothing but the required keys', ()
156
156
  const sample = () => catalog.buildCatalog({
157
157
  loaded: [
158
158
  loadedIn(CORE, 'economy', { description: 'drachmae and credits' }),
159
- loadedIn(CORE, 'provisioning', { author: 'Off the Boats', origin: 'Off the Boats', license: 'AGPL-3.0' }),
159
+ loadedIn(CORE, 'provisioning', { author: 'Example World', origin: 'Example World', license: 'AGPL-3.0' }),
160
160
  loadedIn(INST, 'game', { description: 'the world' }),
161
161
  ],
162
162
  enabled: { economy: true, game: true },
@@ -174,7 +174,7 @@ test('searchCatalog: matches key, description, author, origin and licence; empty
174
174
  assert.equal(catalog.searchCatalog(rows, '').length, 3);
175
175
  assert.equal(catalog.searchCatalog(rows, ' ').length, 3);
176
176
  assert.deepEqual(catalog.searchCatalog(rows, 'DRACHMAE').map((r) => r.key), ['economy'], 'case-insensitive, over description');
177
- assert.deepEqual(catalog.searchCatalog(rows, 'off the boats').map((r) => r.key), ['provisioning'], 'over the credit');
177
+ assert.deepEqual(catalog.searchCatalog(rows, 'example world').map((r) => r.key), ['provisioning'], 'over the credit');
178
178
  assert.deepEqual(catalog.searchCatalog(rows, 'agpl').map((r) => r.key), ['provisioning'], 'over the licence');
179
179
  assert.deepEqual(catalog.searchCatalog(rows, 'nothing-matches-this'), []);
180
180
  });
@@ -202,7 +202,7 @@ test('formatCatalog: renders every row with its credit, and marks the inferred o
202
202
  assert.match(out, /2 in the core catalog \(1 enabled\) · 1 built here · 3 total/);
203
203
  assert.match(out, /\[x\]\s+economy/, 'an enabled module is marked [x]');
204
204
  assert.match(out, /\[ \]\s+provisioning/, 'a disabled module is marked [ ]');
205
- assert.match(out, /Off the Boats/, 'a declared credit is shown');
205
+ assert.match(out, /Example World/, 'a declared credit is shown');
206
206
  assert.match(out, /credit not declared in module\.json/, 'the inferred-credit footnote appears when one is shown');
207
207
  });
208
208
 
@@ -227,7 +227,7 @@ test('formatCatalog: a search with no hits says so instead of printing an empty
227
227
 
228
228
  test('cmdList: --json emits the rows + summary, and honours --catalog/--search', () => {
229
229
  const lines = [];
230
- const code = mod.cmdList(['--json', '--catalog', '--search', 'off the boats'], {
230
+ const code = mod.cmdList(['--json', '--catalog', '--search', 'example world'], {
231
231
  log: (s) => lines.push(s),
232
232
  gather: () => ({ rows: sample(), skipped: [], errors: [], core: '1.19.0' }),
233
233
  });
@@ -59,14 +59,14 @@ await test('createModuleSubmission() INSERTs, jsonb-casts manifest/files/sign_of
59
59
  const precheckPassedAt = new Date('2026-07-08T00:00:00.000Z');
60
60
  nextRows = [{
61
61
  id: 1, module_key: 'widget', submitted_by: 42, manifest, sign_off: signOff,
62
- precheck_passed_at: precheckPassedAt, source_repo: 'lars589/amazonprimea',
62
+ precheck_passed_at: precheckPassedAt, source_repo: 'example-owner/example',
63
63
  status: 'pending', reviewed_by: null, reviewed_at: null, review_notes: null,
64
64
  submitted_at: '2026-07-08T00:00:01.000Z',
65
65
  }];
66
66
 
67
67
  const row = await moduleSubmissions.createModuleSubmission({
68
68
  moduleKey: 'widget', submittedBy: 42, manifest, files, signOff, precheckPassedAt,
69
- sourceRepo: 'lars589/amazonprimea',
69
+ sourceRepo: 'example-owner/example',
70
70
  });
71
71
 
72
72
  const { text, params } = lastCall();
@@ -83,7 +83,7 @@ await test('createModuleSubmission() INSERTs, jsonb-casts manifest/files/sign_of
83
83
  assert.equal(params[3], JSON.stringify(files));
84
84
  assert.equal(params[4], JSON.stringify(signOff));
85
85
  assert.equal(params[5], precheckPassedAt);
86
- assert.equal(params[6], 'lars589/amazonprimea');
86
+ assert.equal(params[6], 'example-owner/example');
87
87
 
88
88
  assert.equal(row.id, 1);
89
89
  assert.equal(row.status, 'pending');
@@ -585,7 +585,7 @@ t('scanArtifactForLeaks: flags a prior-instance literal in any shipped file', ()
585
585
 
586
586
  t('scanArtifactForLeaks: flags a public IP but not a private/localhost one', () => {
587
587
  const r = scanArtifactForLeaks([
588
- { path: 'a.js', content: 'host = 104.236.254.243\n' }, // public → flagged
588
+ { path: 'a.js', content: 'host = 1.2.3.4\n' }, // public → flagged
589
589
  { path: 'b.js', content: 'host = 127.0.0.1; lan = 10.0.0.5\n' }, // localhost + private → not
590
590
  ]);
591
591
  const byPath = Object.fromEntries(r.literalHits.map((h) => [h.path, h.label]));
@@ -17,12 +17,12 @@
17
17
  //
18
18
  // SAFETY: never point the live mode at production. It mutates real claim/task
19
19
  // state. Target staging (once #262 seeds it) or a local instance. The harness
20
- // refuses a BASE_URL containing "amazonprimea.com" without --i-know (the prod
20
+ // refuses a BASE_URL containing "example.com" without --i-know (the prod
21
21
  // host), so a fat-fingered run can't churn the live game's GDS.
22
22
  //
23
23
  // Usage:
24
24
  // node tests/parallel-load.mjs # self-test (CI-safe)
25
- // BASE_URL=https://staging.amazonprimea.com TOKEN=… \
25
+ // BASE_URL=https://staging.example.com TOKEN=… \
26
26
  // node tests/parallel-load.mjs --workers 5 --duration 1800 # live (staging)
27
27
  //
28
28
  // Exit 0 = no anomalies (no 5xx, no unexpected outcome class). Exit 1 = a
@@ -324,9 +324,9 @@ function report(stats, wallMs) {
324
324
 
325
325
  (async () => {
326
326
  if (!SELF_TEST && !KNOW_PROD) {
327
- // Parse the actual HOSTNAME — a substring match on "amazonprimea.com" /
327
+ // Parse the actual HOSTNAME — a substring match on "example.com" /
328
328
  // "staging." can be fooled by query strings or paths (e.g.
329
- // https://amazonprimea.com/x?ref=staging.foo). Refuse the prod apex/www
329
+ // https://example.com/x?ref=staging.foo). Refuse the prod apex/www
330
330
  // host; allow the staging subdomain and anything else (localhost, etc.).
331
331
  let host = '';
332
332
  try {
@@ -335,10 +335,10 @@ function report(stats, wallMs) {
335
335
  console.error(`REFUSING: BASE_URL "${BASE_URL}" is not a valid URL.`);
336
336
  process.exit(2);
337
337
  }
338
- const isProd = host === 'amazonprimea.com' || host === 'www.amazonprimea.com';
338
+ const isProd = host === 'example.com' || host === 'www.example.com';
339
339
  if (isProd) {
340
340
  console.error(`REFUSING: BASE_URL host "${host}" is PRODUCTION. This harness mutates claim/task state.`);
341
- console.error('Point it at staging (staging.amazonprimea.com, once #262 seeds it) or a local instance.');
341
+ console.error('Point it at staging (staging.example.com, once #262 seeds it) or a local instance.');
342
342
  console.error('If you really mean it, pass --i-know (you almost certainly do not).');
343
343
  process.exit(2);
344
344
  }
@@ -1821,7 +1821,7 @@ test("the field is the void: no drawn grid, no stars, no twinkle; the labels, th
1821
1821
 
1822
1822
  test('the kit proves the field path: the fixture carries a curated template and the states file reads it back', () => {
1823
1823
  const fixture = JSON.parse(fs.readFileSync(path.join(ROOT, 'modules', 'ui-design', 'kit', 'fixtures', 'featured.json'), 'utf8'));
1824
- const otb = fixture.projects.find((p) => p.origin === 'https://amazonprimea.com');
1824
+ const otb = fixture.projects.find((p) => p.origin === 'https://example.com');
1825
1825
  assert.equal(otb.template, 'bead-wash');
1826
1826
  const demo = fixture.projects.find((p) => p.origin === 'https://demo.cloudbongos.com');
1827
1827
  assert.equal(demo.template, 'pair-gold-wash', 'a material template rides the wire (task 1003337)');
@@ -1831,7 +1831,7 @@ test('the kit proves the field path: the fixture carries a curated template and
1831
1831
  const states = JSON.parse(fs.readFileSync(path.join(LANDING, 'projects.states.json'), 'utf8'));
1832
1832
  const attrs = states.states['in-map'].expect.attr.map((a) => a.join(' '));
1833
1833
  assert.ok(attrs.includes('#selfOrb data-template pair-chrome'));
1834
- assert.ok(attrs.some((a) => a.includes('amazonprimea.com') && a.endsWith('data-template bead-wash')), 'the curated template reaches the orb');
1834
+ assert.ok(attrs.some((a) => a.includes('example.com') && a.endsWith('data-template bead-wash')), 'the curated template reaches the orb');
1835
1835
  assert.ok(attrs.some((a) => a.includes('demo.cloudbongos.com') && a.endsWith('data-material obsidian')), 'the material reaches the orb as its own attribute');
1836
1836
  assert.ok(attrs.some((a) => a.includes('demo.cloudbongos.com') && a.endsWith('data-template pair-obsidian-tint')), 'the owner\'s choice outranks the curated template on the sky (task 1003347)');
1837
1837
  });