@bongos/core 1.19.725 → 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 (229) hide show
  1. package/.bongos-core.json +179 -494
  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 +4 -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/gate-review.js +14 -6
  64. package/scripts/gds/gen-diagrams.js +1 -1
  65. package/scripts/gds/leak-scan-allowlist.js +293 -0
  66. package/scripts/gds/learning-capture.js +1 -1
  67. package/scripts/gds/linkify-refs.js +2 -2
  68. package/scripts/gds/local-preview-lib.js +1 -1
  69. package/scripts/gds/mirror-lineage-check.js +1 -1
  70. package/scripts/gds/mirror-redact.js +17 -2
  71. package/scripts/gds/newcomer-floor.templates.json +1 -1
  72. package/scripts/gds/package-core.js +18 -1
  73. package/scripts/gds/paste-token.js +1 -1
  74. package/scripts/gds/provision-units.js +2 -2
  75. package/scripts/gds/publish-manifest.js +15 -0
  76. package/scripts/gds/repo-metrics.js +1 -1
  77. package/scripts/gds/sandbox-stage.js +1 -1
  78. package/scripts/gds/seed-bongos-coreB-tranche1-tasks.js +1 -1
  79. package/scripts/gds/seed-bongos-coreB-tranche2-tasks.js +1 -1
  80. package/scripts/gds/seed-bongos-goal-hierarchy-tasks.js +1 -1
  81. package/scripts/gds/seed-bongos-tasks.js +2 -2
  82. package/scripts/gds/seed-gds-v4-tasks.js +1 -1
  83. package/scripts/gds/seed-medusa-tasks.js +10 -10
  84. package/scripts/gds/seed-module-upstreaming.js +1 -1
  85. package/scripts/gds/seed-productization-tasks.js +6 -6
  86. package/scripts/gds/seed-provisioning-tasks.js +2 -2
  87. package/scripts/gds/seed-staging.sh +19 -6
  88. package/scripts/gds/ship-deploy-target.js +1 -1
  89. package/scripts/gds/ship-flow.js +1 -1
  90. package/scripts/gds/smoke-gds.js +1 -1
  91. package/scripts/status-probe.mjs +2 -2
  92. package/src/bongos/auth-discord.js +2 -2
  93. package/src/bongos/live-channel.js +1 -1
  94. package/src/bongos/permission-path-check.js +80 -3
  95. package/src/bongos/pool.js +1 -1
  96. package/src/bongos/routes/auth.js +11 -11
  97. package/src/bongos/routes/security.js +1 -1
  98. package/src/bongos/routes.js +1 -1
  99. package/src/branding.js +1 -1
  100. package/src/devbox-downloads.js +1 -1
  101. package/src/instance-config.js +2 -2
  102. package/src/module-api.js +1 -1
  103. package/src/module-loader/provenance.js +2 -2
  104. package/tests/art_stage.mjs +2 -2
  105. package/tests/auth_anthropic_identity.mjs +1 -1
  106. package/tests/auth_duplicate_cookie.mjs +1 -1
  107. package/tests/auth_error_brand.mjs +1 -1
  108. package/tests/auth_inactive_builder.mjs +1 -1
  109. package/tests/backup_cli.mjs +4 -4
  110. package/tests/bongos_box_connect.mjs +2 -2
  111. package/tests/bongos_downloads.mjs +2 -2
  112. package/tests/bongos_login.mjs +5 -5
  113. package/tests/box_connect_e2e.mjs +2 -2
  114. package/tests/box_dns_repoint.mjs +10 -10
  115. package/tests/box_host_keys.mjs +1 -1
  116. package/tests/box_onboard.mjs +9 -9
  117. package/tests/box_scope_session.mjs +1 -1
  118. package/tests/box_terminal_ssrf.mjs +7 -7
  119. package/tests/boxes.mjs +9 -9
  120. package/tests/branding.mjs +2 -2
  121. package/tests/bump_version.mjs +2 -2
  122. package/tests/cf_tunnel.mjs +40 -40
  123. package/tests/cli_token_reissue.mjs +7 -7
  124. package/tests/cloud_bongos_pack.mjs +1 -1
  125. package/tests/currency_label.mjs +8 -8
  126. package/tests/dev_lib.mjs +4 -4
  127. package/tests/devbox_dmg_backdrop.mjs +1 -1
  128. package/tests/devbox_downloads.mjs +2 -2
  129. package/tests/devbox_icons.mjs +1 -1
  130. package/tests/discord_approvals.mjs +1 -1
  131. package/tests/discord_oauth.mjs +2 -2
  132. package/tests/executed_closure.mjs +6 -1
  133. package/tests/first_admin_bootstrap.mjs +1 -1
  134. package/tests/gate_approvals.mjs +5 -5
  135. package/tests/government_protected_surfaces.mjs +137 -0
  136. package/tests/grade_aggregates_unavailable.mjs +1 -1
  137. package/tests/hook_user_agents.mjs +2 -2
  138. package/tests/init.mjs +6 -6
  139. package/tests/instance_config.mjs +1 -1
  140. package/tests/instance_manifest.mjs +5 -5
  141. package/tests/instance_mismatch_guard.mjs +13 -13
  142. package/tests/leak_scan_allowlist.mjs +94 -0
  143. package/tests/migrate_root_resolution.mjs +4 -4
  144. package/tests/mirror_redact.mjs +28 -4
  145. package/tests/module_catalog.mjs +5 -5
  146. package/tests/module_submissions.mjs +3 -3
  147. package/tests/package_core.mjs +1 -1
  148. package/tests/parallel-load.mjs +6 -6
  149. package/tests/projects_hub.mjs +2 -2
  150. package/tests/provision.mjs +50 -50
  151. package/tests/provisioning_github_app_routes.mjs +1 -1
  152. package/tests/provisioning_onboard_mode.mjs +2 -2
  153. package/tests/publish_reconciler.mjs +4 -4
  154. package/tests/sandbox_stage.mjs +1 -1
  155. package/tests/scrubber_corpus.mjs +3 -3
  156. package/tests/search_isolation.mjs +1 -1
  157. package/tests/session_records.mjs +1 -1
  158. package/tests/ship_card.mjs +6 -6
  159. package/tests/ship_ci_deploy.mjs +1 -1
  160. package/tests/single_host_hall.mjs +9 -9
  161. package/tests/smoke_preflight.mjs +1 -1
  162. package/tests/smoke_target.mjs +1 -1
  163. package/tests/status-probe.mjs +1 -1
  164. package/tests/status_mirror_sync.mjs +1 -1
  165. package/docs/adr/0004-amazonprimea-name-and-trademark-acceptance.md +0 -45
  166. package/docs/design/mocks/_schemes.css +0 -604
  167. package/docs/design/mocks/component-sheet.html +0 -428
  168. package/docs/design/mocks/hall/_tokens.css +0 -370
  169. package/docs/design/mocks/hall/board/v1.html +0 -846
  170. package/docs/design/mocks/hall/board/v2.html +0 -858
  171. package/docs/design/mocks/hall/board/v3.html +0 -884
  172. package/docs/design/mocks/hall/goals/v1.html +0 -1212
  173. package/docs/design/mocks/hall/goals/v2.html +0 -1192
  174. package/docs/design/mocks/hall/goals/v3.html +0 -1205
  175. package/docs/design/mocks/hall/hall-sheet.html +0 -244
  176. package/docs/design/mocks/hall/reading/v1.html +0 -1125
  177. package/docs/design/mocks/hall/reading/v2.html +0 -1177
  178. package/docs/design/mocks/hall/reading/v3.html +0 -1150
  179. package/docs/design/mocks/hall/settings/v1.html +0 -1238
  180. package/docs/design/mocks/hall/settings/v2.html +0 -1235
  181. package/docs/design/mocks/hall/settings/v3.html +0 -1299
  182. package/docs/design/mocks/hall/task/v1.html +0 -633
  183. package/docs/design/mocks/hall/task/v2.html +0 -646
  184. package/docs/design/mocks/hall/task/v3.html +0 -647
  185. package/docs/design/mocks/hub/assets/r3-space-deepfield-half.jpg +0 -0
  186. package/docs/design/mocks/hub/assets/r3-space-deepfield-half.jpg.json +0 -13
  187. package/docs/design/mocks/hub/assets/r3-space-dust-half.jpg +0 -0
  188. package/docs/design/mocks/hub/assets/r3-space-dust-half.jpg.json +0 -13
  189. package/docs/design/mocks/hub/assets/r3-space-nebula-half.jpg +0 -0
  190. package/docs/design/mocks/hub/assets/r3-space-nebula-half.jpg.json +0 -13
  191. package/docs/design/mocks/hub/assets/r3-space-starfield-half.jpg +0 -0
  192. package/docs/design/mocks/hub/assets/r3-space-starfield-half.jpg.json +0 -13
  193. package/docs/design/mocks/hub/hub-sheet.html +0 -192
  194. package/docs/design/mocks/hub/mine.html +0 -465
  195. package/docs/design/mocks/hub/picker.html +0 -421
  196. package/docs/design/mocks/hub/planets.html +0 -356
  197. package/docs/design/mocks/hub/v1.html +0 -1209
  198. package/docs/design/mocks/hub/v2.html +0 -1257
  199. package/docs/design/mocks/hub/v3.html +0 -1496
  200. package/docs/design/mocks/hub/wizard.html +0 -421
  201. package/docs/design/mocks/landing/landing-sheet.html +0 -131
  202. package/docs/design/mocks/landing/v1.html +0 -956
  203. package/docs/design/mocks/landing/v2.html +0 -708
  204. package/docs/design/mocks/landing/v3.html +0 -911
  205. package/docs/design/mocks/landing-page-mock.html +0 -687
  206. package/docs/design/mocks/landing-palettes.html +0 -103
  207. package/docs/design/mocks/projects-hub-mock.html +0 -991
  208. package/docs/design/mocks/projects-hub-variants.html +0 -146
  209. package/docs/design/mocks/projects-page-mock.html +0 -167
  210. package/docs/design/mocks/world/blue-hud/_tokens.css +0 -246
  211. package/docs/design/mocks/world/blue-hud/hall.html +0 -595
  212. package/docs/design/mocks/world/blue-hud/landing.html +0 -424
  213. package/docs/design/mocks/world/blue-hud/status.html +0 -410
  214. package/docs/design/mocks/world/chrome-blobs/_tokens.css +0 -479
  215. package/docs/design/mocks/world/chrome-blobs/hall.html +0 -553
  216. package/docs/design/mocks/world/chrome-blobs/landing-b.html +0 -581
  217. package/docs/design/mocks/world/chrome-blobs/landing.html +0 -328
  218. package/docs/design/mocks/world/chrome-blobs/status.html +0 -416
  219. package/docs/design/mocks/world/natgeo-editorial/_tokens.css +0 -377
  220. package/docs/design/mocks/world/natgeo-editorial/hall.html +0 -649
  221. package/docs/design/mocks/world/natgeo-editorial/landing-b.html +0 -743
  222. package/docs/design/mocks/world/natgeo-editorial/landing.html +0 -475
  223. package/docs/design/mocks/world/natgeo-editorial/status.html +0 -437
  224. package/docs/design/mocks/world/organic-cards/_tokens.css +0 -462
  225. package/docs/design/mocks/world/organic-cards/hall.html +0 -625
  226. package/docs/design/mocks/world/organic-cards/landing-b.html +0 -736
  227. package/docs/design/mocks/world/organic-cards/landing.html +0 -420
  228. package/docs/design/mocks/world/organic-cards/status.html +0 -458
  229. package/docs/design/mocks/world/world-sheet.html +0 -156
@@ -71,8 +71,8 @@ function serviceUnitPath(inst) { return `/etc/systemd/system/${inst.slug}.servic
71
71
  // ── nightly DB backup: per-instance timer + service (task 2213) ─────────────
72
72
  // PRODUCTIZES the manual task-2210 fix: a newly-provisioned instance was born with
73
73
  // NO backups (dir absent, GDS_BACKUP_DB unset → the script fell back to the
74
- // nonexistent `amazonprimea` default, and the repo's global gds-db-backup units
75
- // hardcode /home/lars/amazonprimea — wrong for the consumer node_modules/@bongos/
74
+ // nonexistent `example` default, and the repo's global gds-db-backup units
75
+ // hardcode /home/lars/example — wrong for the consumer node_modules/@bongos/
76
76
  // core layout). These generators emit a PER-INSTANCE unit pair that fixes all three:
77
77
  // • name → `<slug>-db-backup.{service,timer}` so co-tenant instances on one box
78
78
  // never collide (each dumps its OWN db; the script's retention prune is
@@ -281,12 +281,27 @@ const INSTANCE_EXCLUDE = [
281
281
  'docs/design/container-exterior-tiles.md',
282
282
  'docs/design/container-interior.md',
283
283
  'docs/design/world-map-scroll.md',
284
+ // instance-specific UI MOCKUPS — iteration snapshots of THIS instance's own hub (hub v1/v2/v3,
285
+ // the wizard, the projects hub, the world chrome), branded end to end in markup a consumer of
286
+ // the portable core has no use for: they are our design history, not methodology. Same reason as
287
+ // the game-design carve-out above, and the same failure mode — redaction de-brands names in DOCS,
288
+ // but an .html is a FUNCTIONAL file that ships verbatim, so every brand string in the mock markup
289
+ // reached the published artifact. They were 117 of the 240 remaining leak-scan hits. Excluding the
290
+ // subtree rather than the six files is deliberate: it is the boundary that holds when someone adds
291
+ // mockup number seven. (task 1003869)
292
+ 'docs/design/mocks/',
284
293
  // instance-HISTORY ADRs (task 1002219 / audit H5). These record THIS platform-family's own
285
294
  // migration + identity history (the amazonprimea→cloudbongos lift, the standalone reprovision,
286
295
  // the cloudbongos identity hub) — they are inherently full of the prior instance's name/owner and
287
296
  // genericize to nothing (unlike a portable methodology ADR). docs/adr/ is allowlisted wholesale for
288
297
  // the portable decision records; these three stay in this repo and never ship in the core, mirroring
289
298
  // the instance-recipe / game-design carve-outs above. (The portable ADRs + the README index still publish.)
299
+ // The instance's OWN name + trademark decision. Its prose redacts cleanly, but the FILENAME
300
+ // carries the brand and the publish manifest lists every path — so the literal shipped in
301
+ // .bongos-core.json no matter how well the body was redacted. It also genericizes to nothing:
302
+ // "accepting trademark risk on <our name>" is not a decision another instance inherits.
303
+ // (task 1003869 — the last literal in the artifact.)
304
+ 'docs/adr/0004-amazonprimea-name-and-trademark-acceptance.md',
290
305
  'docs/adr/0139-platform-history-migration-to-cloudbongos.md',
291
306
  'docs/adr/0140-cloudbongos-standalone-reprovision.md',
292
307
  'docs/adr/0141-cross-site-identity-federated-hub-idp.md',
@@ -6,7 +6,7 @@
6
6
  // out to git / wc / knip and emits a JSON snapshot of repo health, then upserts
7
7
  // it into repo_health_snapshots (idempotent on calendar date — rerun same day
8
8
  // = upsert, not a new row). The latest row feeds /api/gds/public/repo-health,
9
- // which renders a trend tile on status.amazonprimea.com.
9
+ // which renders a trend tile on status.example.com.
10
10
  //
11
11
  // What the snapshot contains:
12
12
  // - total_loc + loc_by_dir — tracked JS/MJS line counts, per watched dir
@@ -6,7 +6,7 @@
6
6
  //
7
7
  // Two preview contexts (resolvePreviewContext picks one):
8
8
  // - BOX (ADR 0031): box-game-preview.service serves the working tree at
9
- // https://sandbox-<login>.amazonprimea.com; "staging" restarts the service.
9
+ // https://sandbox-<login>.example.com; "staging" restarts the service.
10
10
  // - LOCAL (task 1056): a builder on a full local clone (laptop) runs the same
11
11
  // ADR 0052 game-only entry privately at http://localhost:<port> via
12
12
  // scripts/gds/local-preview.js; "staging" (re)starts that local process.
@@ -7,7 +7,7 @@
7
7
  // Run: node scripts/gds/seed-bongos-coreB-tranche1-tasks.js
8
8
  const os = require('os');
9
9
  const TOKEN = require(os.homedir() + '/.config/otb/gds-session.json').token;
10
- const BASE = require('../../src/instance-config').resolveEnv('BASE') || 'https://amazonprimea.com';
10
+ const BASE = require('../../src/instance-config').resolveEnv('BASE') || 'https://example.com';
11
11
  const H = { Authorization: `Bearer ${TOKEN}`, 'Content-Type': 'application/json' };
12
12
 
13
13
  // ref → task spec. depends_on_refs are local R## refs resolved after create.
@@ -9,7 +9,7 @@
9
9
  // Run: node scripts/gds/seed-bongos-coreB-tranche2-tasks.js
10
10
  const os = require('os');
11
11
  const TOKEN = require(os.homedir() + '/.config/otb/gds-session.json').token;
12
- const BASE = require('../../src/instance-config').resolveEnv('BASE') || 'https://amazonprimea.com';
12
+ const BASE = require('../../src/instance-config').resolveEnv('BASE') || 'https://example.com';
13
13
  const H = { Authorization: `Bearer ${TOKEN}`, 'Content-Type': 'application/json' };
14
14
 
15
15
  // ref → task spec. deps are local R## refs resolved after create. Clean-slicing
@@ -47,7 +47,7 @@ const TASKS = [
47
47
  {
48
48
  key: 'G02',
49
49
  title: 'config/hierarchy.json + hierarchy-config.js — the six-tier preset (onboarding-edited)',
50
- description: `Phase 1 of the goal hierarchy (ADR 0086 §1 — the ADR 0062 core/host pattern applied to the work model). Add \`config/hierarchy.json\` (joins branding.json/modules.json as host config) declaring the tiers — names, order, and which tier carries scope, membership, and criteria. Ship the six-tier Amazonprimea preset: Project → Version → Goal → Criteria → Task → Sub-task. Add \`src/bongos/hierarchy-config.js\` (mirrors src/modules.js) to load + validate it. v1 "editable" = owner-set labels, enable/disable, and which tier owns scope/criteria/membership; arbitrary custom tier graphs are explicitly DEFERRED. Owner fills/edits during onboarding (extend the scripts/gds/init.js interview).
50
+ description: `Phase 1 of the goal hierarchy (ADR 0086 §1 — the ADR 0062 core/host pattern applied to the work model). Add \`config/hierarchy.json\` (joins branding.json/modules.json as host config) declaring the tiers — names, order, and which tier carries scope, membership, and criteria. Ship the six-tier Example preset: Project → Version → Goal → Criteria → Task → Sub-task. Add \`src/bongos/hierarchy-config.js\` (mirrors src/modules.js) to load + validate it. v1 "editable" = owner-set labels, enable/disable, and which tier owns scope/criteria/membership; arbitrary custom tier graphs are explicitly DEFERRED. Owner fills/edits during onboarding (extend the scripts/gds/init.js interview).
51
51
 
52
52
  **Done when:** hierarchy.json + hierarchy-config.js exist; the loader validates + exposes the tier set; the six-tier preset is the OTB default; onboarding can set labels/enable/scope-owner; unit test covers a malformed preset rejected.`,
53
53
  kind: 'feature', discipline: 'engineer', priority: 5,
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  // Seed the 6 net-new "Cloud Bongos CLI" tasks added to GDS-V4 (C8) — the
3
3
  // conda/Miniconda-style terminal-first onboarding toolkit. `bongos` is the CLI
4
- // command (Cloud Bongos = the standalone build platform; Amazonprimea =
4
+ // command (Cloud Bongos = the standalone build platform; Example =
5
5
  // instance 1). Design doc: artifact 02bcca71 (the bongos toolkit).
6
6
  //
7
7
  // Shape mirrors seed-medusa-tasks.js exactly:
@@ -98,7 +98,7 @@ A small public, read-only endpoint returning the instance descriptor assembled f
98
98
 
99
99
  \`bongos login <instance-url>\` fetches the P4A manifest, runs the GitHub device-flow (browser-click, no token paste — the UI-first rule), stores a per-instance scoped session, and brands the CLI for that instance. For someone NOT yet admitted, it files the public POST /api/gds/access-requests (their GitHub username) and polls — telling them "an Archon will approve you with a 👍 in Discord" — until admission flips, then completes sign-in. No GitHub collaborator invite is involved. Default admission is invite-only. Also folds the already-planned \`bongos init\` (scaffold a brand-new instance, R65) and \`bongos upgrade\` (R64) in as subcommands of the same CLI.
100
100
 
101
- **Done when:** \`bongos login <any-instance-url>\` works end-to-end including the not-yet-admitted path (files the request, polls, completes once approved); the CLI is instance-agnostic (no hard-coded amazonprimea); \`init\`/\`upgrade\` are reachable subcommands.`,
101
+ **Done when:** \`bongos login <any-instance-url>\` works end-to-end including the not-yet-admitted path (files the request, polls, completes once approved); the CLI is instance-agnostic (no hard-coded example); \`init\`/\`upgrade\` are reachable subcommands.`,
102
102
  kind: 'feature', discipline: 'engineer', priority: 3,
103
103
  est_minutes: 360, manual_degree: 2, credits_reward: 60,
104
104
  touches: ['bin/', 'scripts/gds/'], criteria: ['C8'], deps: ['P1', 'P4A'],
@@ -379,7 +379,7 @@ Reconcile shipped tasks against uploaded session records (BFG 6D follow-up to ta
379
379
  title: 'Embedding provider decision + key provisioning (Archon go-ahead)',
380
380
  description: `**Criterion:** one-call-recall (gated by V4.R24's go/no-go).
381
381
 
382
- If the eval gate says GO: pick the provider (research recommendation: Voyage voyage-4-lite — $0.02/M tokens, 200M free tier, Matryoshka dims; fallback OpenAI text-embedding-3-small), create the account, provision EMBEDDINGS_API_KEY into /etc/amazonprimea/secrets.env per ADR 0022. New external account = Lars's explicit go-ahead per the budget rules.
382
+ If the eval gate says GO: pick the provider (research recommendation: Voyage voyage-4-lite — $0.02/M tokens, 200M free tier, Matryoshka dims; fallback OpenAI text-embedding-3-small), create the account, provision EMBEDDINGS_API_KEY into /etc/example/secrets.env per ADR 0022. New external account = Lars's explicit go-ahead per the budget rules.
383
383
 
384
384
  **Done when:** decision recorded (ADR addendum), key live on the droplet, cost expectations logged.`,
385
385
  kind: 'decision', discipline: 'engineering', priority: 2,
@@ -2,9 +2,9 @@
2
2
  // Seed the 24 net-new "Medusa" tasks (R50–R73) added to GDS-V4 in the
3
3
  // 2026-06-17 Medusa Planning Session (meta task 1188 / claim 982).
4
4
  //
5
- // Medusa = decouple the GDS from the Amazonprimea game into a standalone,
5
+ // Medusa = decouple the GDS from the Example game into a standalone,
6
6
  // configurable, self-hostable, AGPL open-source, non-profit, AI-first build
7
- // platform. Amazonprimea becomes instance 1.
7
+ // platform. Example becomes instance 1.
8
8
  //
9
9
  // Companion migration 110_medusa_planning_seed.sql handles:
10
10
  // - the 2 done_when_criteria rows (C8 = medusa-standalone-instance,
@@ -66,7 +66,7 @@ A Medusa-only boot (sibling to src/preview-server.js) that builds the Express ap
66
66
  title: 'GDS-owned DB pool + migration carve-out + drop the track enum',
67
67
  description: `Part of Medusa (C8). Cross-ref: R50 design.
68
68
 
69
- A GDS-owned pool reading DATABASE_URL/PG* (not hard-defaulting to the amazonprimea DB name); a GDS-only migration sequence (game migrations 001/002 simply not applied on a fresh non-game instance); drop the product/internal 'track' distinction. Live prod keeps its existing DB. Zero cross-FKs exist between game and GDS tables, so the split is clean.
69
+ A GDS-owned pool reading DATABASE_URL/PG* (not hard-defaulting to the example DB name); a GDS-only migration sequence (game migrations 001/002 simply not applied on a fresh non-game instance); drop the product/internal 'track' distinction. Live prod keeps its existing DB. Zero cross-FKs exist between game and GDS tables, so the split is clean.
70
70
 
71
71
  **Done when:** a fresh-DB migration run produces only the build-system schema; a query asserts the game tables (world_events, players, seats) are absent; live prod unaffected.`,
72
72
  kind: 'infra', discipline: 'engineer', priority: 5,
@@ -80,7 +80,7 @@ A GDS-owned pool reading DATABASE_URL/PG* (not hard-defaulting to the amazonprim
80
80
 
81
81
  A per-instance config layer (config/branding.json + a documented schema + a neutral starter + a fill-it-in prompt an owner's own LLM uses) supplying product name, domain/cookie apex, sign-in (OAuth) origin, repo binding, currency label, copy, fonts, palette, icons/favicon/cursors. Core reads identity + branding from this layer; defaults preserve live OTB exactly. NOT a vanilla strip — branding becomes per-instance config; OTB's look becomes instance 1's pack (extracted in R57).
82
82
 
83
- **Done when:** core resolves all identity + branding from config; booting under a non-amazonprimea.com domain + a non-game name needs config only, no source edits. Gates most de-brand + self-host tasks.`,
83
+ **Done when:** core resolves all identity + branding from config; booting under a non-example.com domain + a non-game name needs config only, no source edits. Gates most de-brand + self-host tasks.`,
84
84
  kind: 'feature', discipline: 'engineer', priority: 5,
85
85
  est_minutes: 360, manual_degree: 2, credits_reward: 60,
86
86
  touches: ['config/', 'src/bongos/', 'public-builders/'], criteria: ['C8'], deps: ['R50'],
@@ -128,7 +128,7 @@ Make the reward currency a configurable label (neutral default; OTB's instance =
128
128
  title: "Extract OTB's look into instance 1's branding pack (not a vanilla strip)",
129
129
  description: `Part of Medusa (C8). Cross-ref: R53, R56.
130
130
 
131
- Move the ~272 archaic strings, the Greek fonts, the parchment palette, favicon/cursors/SVG sigils, and the page copy out of the hall + status code and into instance 1's branding pack; core renders from the R53 branding layer with a neutral starter as the fallback. status.amazonprimea.com + builders.amazonprimea.com look IDENTICAL afterward — their look just comes from config now. Add a rank display-label map so the Greek rank LABELS are presentation (the enum stays Greek by decision).
131
+ Move the ~272 archaic strings, the Greek fonts, the parchment palette, favicon/cursors/SVG sigils, and the page copy out of the hall + status code and into instance 1's branding pack; core renders from the R53 branding layer with a neutral starter as the fallback. status.example.com + builders.example.com look IDENTICAL afterward — their look just comes from config now. Add a rank display-label map so the Greek rank LABELS are presentation (the enum stays Greek by decision).
132
132
 
133
133
  **Done when:** no project branding is hard-coded in public-builders/ or public-status/; OTB's surfaces render unchanged from instance 1's pack; a fresh instance renders the neutral starter.`,
134
134
  kind: 'refactor', discipline: 'engineer', priority: 4,
@@ -142,7 +142,7 @@ Move the ~272 archaic strings, the Greek fonts, the parchment palette, favicon/c
142
142
 
143
143
  scripts/gds/gen-diagrams.js auto-generates the onboarding diagrams + assertions.json on every deploy. Make its template strings + assertions read the instance branding config so deploy-time regeneration emits neutral (instance-correct) branding. Rank names stay Greek by decision. This prevents the "we de-branded but Greek text reappeared after the next deploy" regression.
144
144
 
145
- **Done when:** running gen-diagrams.js under a neutral instance config produces diagrams + assertions.json with no hard-coded OTB/Amazonprimea tokens; OTB's instance still renders its own branding.`,
145
+ **Done when:** running gen-diagrams.js under a neutral instance config produces diagrams + assertions.json with no hard-coded OTB/Example tokens; OTB's instance still renders its own branding.`,
146
146
  kind: 'refactor', discipline: 'engineer', priority: 4,
147
147
  est_minutes: 180, manual_degree: 2, credits_reward: 30,
148
148
  touches: ['scripts/gds/gen-diagrams.js'], criteria: ['C8'], deps: ['R53'],
@@ -190,7 +190,7 @@ The CLI config root (~/.config/otb/: gds-session.json, env, discord-webhooks.jso
190
190
  title: 'Config-driven owner bootstrap + per-instance repo/OAuth binding',
191
191
  description: `Part of Medusa (C8). Cross-ref: R52, R53.
192
192
 
193
- Replace migration 023's hard-coded founding-Archon literal (UPDATE builders SET rank='archon' WHERE github_login='lars589') with an install-time first-admin bootstrap from instance config. Make the GitHub repo binding (repo-info.js — the OTB_GITHUB_OWNER/REPO seam already exists) and the OAuth/App config per-instance. Single-project model keeps the global economy fine — only the owner literal + repo/OAuth need to generalize.
193
+ Replace migration 023's hard-coded founding-Archon literal (UPDATE builders SET rank='archon' WHERE github_login='example-owner') with an install-time first-admin bootstrap from instance config. Make the GitHub repo binding (repo-info.js — the OTB_GITHUB_OWNER/REPO seam already exists) and the OAuth/App config per-instance. Single-project model keeps the global economy fine — only the owner literal + repo/OAuth need to generalize.
194
194
 
195
195
  **Done when:** grep over migrations/ returns zero login literals; a fresh install seats the configured first admin; repo + OAuth resolve from instance config.`,
196
196
  kind: 'feature', discipline: 'engineer', priority: 4,
@@ -202,7 +202,7 @@ Replace migration 023's hard-coded founding-Archon literal (UPDATE builders SET
202
202
  title: 'Containerized self-host instance (Dockerfile + docker-compose)',
203
203
  description: `Part of Medusa (C8). Cross-ref: R51, R52.
204
204
 
205
- A Dockerfile + docker-compose (app + Postgres) that brings a Medusa instance up from clean state with ZERO hard-coded droplet IP (104.236.254.243), amazonprimea systemd unit, or hand-maintained ~/deploy.sh. This is the self-host artifact; it does not touch prod's existing laptop/CI deploy path.
205
+ A Dockerfile + docker-compose (app + Postgres) that brings a Medusa instance up from clean state with ZERO hard-coded droplet IP, instance-specific systemd unit, or hand-maintained ~/deploy.sh. This is the self-host artifact; it does not touch prod's existing laptop/CI deploy path.
206
206
 
207
207
  **Done when:** \`docker compose up\` on a machine that has never seen our droplet brings up Medusa + Postgres and the hall is reachable; no prod topology referenced anywhere in the path.`,
208
208
  kind: 'infra', discipline: 'engineer', priority: 4,
@@ -248,7 +248,7 @@ Separate the portable methodology core Medusa ships (the working rules, the sess
248
248
  {
249
249
  ref: 'R67',
250
250
  title: 'PROOF — Medusa dogfood: a second, differently-branded non-game instance ships a task',
251
- description: `Part of Medusa (C8) — the proof-task that satisfies C8 ("the GDS builds itself"). Customer 0 = Medusa itself, running on the vanilla brand pack (R74); customer 1 = Amazonprimea.
251
+ description: `Part of Medusa (C8) — the proof-task that satisfies C8 ("the GDS builds itself"). Customer 0 = Medusa itself, running on the vanilla brand pack (R74); customer 1 = Example.
252
252
 
253
253
  Stand Medusa up as customer 0 (its own database, vanilla brand, no game code) and take one real task through the full lifecycle on it: claim -> grade -> merge -> ship with credits awarded. Medusa building Medusa, on Medusa. (A separate non-game third project is an acceptable alternative proof, but customer-0 self-build is the truest.)
254
254
 
@@ -342,7 +342,7 @@ Verify the private and public lineages stay consistent: migration numbering (the
342
342
  title: 'Medusa vanilla brand pack — the plain "customer 0" identity (Substack-like)',
343
343
  description: `Part of Medusa (C8). Cross-ref: R53 (branding-contract layer), R57 (customer 1 / OTB pack).
344
344
 
345
- Design + build the canonical Medusa VANILLA brand pack — the identity Medusa itself runs on as **customer 0** (Amazonprimea is customer 1). Deliberately PLAIN, clean, modern, professional — restrained palette, clean sans-serif type, minimal wordmark, plain-English product copy, simple favicon/icons. Aesthetic touchstone: Substack-plain; take INSPIRATION from planetscale.com's simplicity (do NOT copy). Delivered as a branding pack against the R53 contract; it is the default the hall + status render under when no other pack is supplied, and the brand Medusa ships on. Distinct from R57 (extracting customer 1 / OTB's Greek look) — this is customer 0's identity. No game/Greek flavor.
345
+ Design + build the canonical Medusa VANILLA brand pack — the identity Medusa itself runs on as **customer 0** (Example is customer 1). Deliberately PLAIN, clean, modern, professional — restrained palette, clean sans-serif type, minimal wordmark, plain-English product copy, simple favicon/icons. Aesthetic touchstone: Substack-plain; take INSPIRATION from planetscale.com's simplicity (do NOT copy). Delivered as a branding pack against the R53 contract; it is the default the hall + status render under when no other pack is supplied, and the brand Medusa ships on. Distinct from R57 (extracting customer 1 / OTB's Greek look) — this is customer 0's identity. No game/Greek flavor.
346
346
 
347
347
  **Done when:** a complete Medusa vanilla brand pack (name/wordmark, restrained palette, clean type, plain copy, favicon/icons) renders the hall + status as a plain, professional dev toolkit; it is the pack customer 0 (Medusa) runs on; verified on the standalone boot.`,
348
348
  kind: 'feature', discipline: 'artist', priority: 4,
@@ -19,7 +19,7 @@ const DRY = process.argv.includes('--dry-run');
19
19
  const VERSION = 'BONGOS-V1';
20
20
  const GOAL_TITLE = 'Module upstreaming & catalog — instances contribute modules into core';
21
21
  const GOAL_DESC =
22
- 'ADR 0107. The reverse of the ADR 0100/0103 distribution arrow: instances (Amazonprimea, ' +
22
+ 'ADR 0107. The reverse of the ADR 0100/0103 distribution arrow: instances (Example, ' +
23
23
  'Mercury) build feature modules and submit them for approval to be merged INTO the shared ' +
24
24
  'Cloud Bongos core catalog, credited to author + origin project. Accepted modules land in ' +
25
25
  'core modules/<key>/ default-off, added to the isPublishable() allowlist; every instance may ' +
@@ -52,7 +52,7 @@ const TASKS = [
52
52
  title: 'ADR: instance docs-discovery contract (how an agent finds its hall/docs)',
53
53
  description: `From the 2026-07-04 review (bullet 6). Today the only pointer to an instance's doc surface is \`domains.buildersOrigin\` in branding.json. A fresh self-hosted instance needs a DEFINED contract for how an agent reliably locates its builders' hall + rendered docs from config alone (standard docs location? discovery endpoint? manifest field?). Write an ADR that pins the contract, then CLAUDE.md's preamble references it instead of hand-waving.
54
54
 
55
- **Done when:** an ADR records the docs-discovery contract; branding/config carries the needed field(s); CLAUDE.md §0 points at the contract; a second instance can resolve its docs surface with no hard-coded amazonprimea.`,
55
+ **Done when:** an ADR records the docs-discovery contract; branding/config carries the needed field(s); CLAUDE.md §0 points at the contract; a second instance can resolve its docs surface with no hard-coded example.`,
56
56
  kind: 'decision', discipline: 'engineer', priority: 3,
57
57
  est_minutes: 90, manual_degree: 3, credits_reward: 20,
58
58
  touches: ['docs/adr/', 'config/', 'CLAUDE.md'], criteria: ['C16'], deps: [],
@@ -80,12 +80,12 @@ const TASKS = [
80
80
  {
81
81
  key: 'NAV-HYGIENE',
82
82
  title: 'Nav hygiene — reference the module, split instance-specifics',
83
- description: `From the 2026-07-04 review (bullets 42, 57, 64, 66, 68, 94). Several nav rows (and §2 prose) INLINE content that belongs to a module or to instance-specifics. Convert them to module references, and split anything naming the amazonprimea servers/assets into project-specific detail. By module:
84
- - **discord** (57, 64, 94): inbound #ideas, build-broadcast, channel layout → reference the discord module; the general mechanism lives there, anything naming the amazonprimea Discord server specifically → project-specific detail.
83
+ description: `From the 2026-07-04 review (bullets 42, 57, 64, 66, 68, 94). Several nav rows (and §2 prose) INLINE content that belongs to a module or to instance-specifics. Convert them to module references, and split anything naming the example servers/assets into project-specific detail. By module:
84
+ - **discord** (57, 64, 94): inbound #ideas, build-broadcast, channel layout → reference the discord module; the general mechanism lives there, anything naming the example Discord server specifically → project-specific detail.
85
85
  - **art-pipeline** (66): the pixel-art design-system row → reference the art module; the pixel/greek style choice itself is instance detail.
86
86
  - **game** (68): world-cell model + paths-as-overlays rows → the game module / instance context (out of the portable core).
87
87
 
88
- **Done when:** those nav/§2 items are thin references to their modules; no module-owned or amazonprimea-server-specific detail is inlined in the core; the game-specific rows are out of core.`,
88
+ **Done when:** those nav/§2 items are thin references to their modules; no module-owned or example-server-specific detail is inlined in the core; the game-specific rows are out of core.`,
89
89
  kind: 'cleanup', discipline: 'engineer', priority: 3,
90
90
  est_minutes: 120, manual_degree: 3, credits_reward: 25,
91
91
  touches: ['CLAUDE.md'], criteria: ['C32'], deps: [],
@@ -123,7 +123,7 @@ const TASKS = [
123
123
  {
124
124
  key: 'IDENTITY-ORG',
125
125
  title: 'Rationalize the identity apparatus + structure project-context.md',
126
- description: `From the 2026-07-04 review (bullets 109-111, 134/140, 187). Almost every identity section (§§1,3,5,6,7,9) is now a thin pointer to project-context.md, the §3 stub verbosely re-explains the core↔host split that §1 + the charter already cover, and the §6/§7 stubs still NAME the instance ("the Amazonprimea world", "the \`otb-*\` art skills"). Meanwhile project-context.md is getting overloaded (bullet 187). Fix: collapse §§3/5/6/7 to a single minimal pointer (or one-liners), genericize instance names out of any surviving stub, and give project-context.md a real section structure.
126
+ description: `From the 2026-07-04 review (bullets 109-111, 134/140, 187). Almost every identity section (§§1,3,5,6,7,9) is now a thin pointer to project-context.md, the §3 stub verbosely re-explains the core↔host split that §1 + the charter already cover, and the §6/§7 stubs still NAME the instance ("the Example world", "the \`otb-*\` art skills"). Meanwhile project-context.md is getting overloaded (bullet 187). Fix: collapse §§3/5/6/7 to a single minimal pointer (or one-liners), genericize instance names out of any surviving stub, and give project-context.md a real section structure.
127
127
 
128
128
  **Done when:** the stub scaffolding is minimal + instance-name-free in the core; project-context.md has a clear, non-overloaded structure; anchors/cross-refs still resolve.`,
129
129
  kind: 'cleanup', discipline: 'engineer', priority: 3,
@@ -148,7 +148,7 @@ const TASKS = [
148
148
  title: 'Scheduled-routines portability to self-host + multi-builder',
149
149
  description: `From the 2026-07-04 review (bullet 241). The ~17 autonomous cron routines under \`.claude/scheduled-tasks/\` (overnight-code-review, idea-triage-nightly, overnight-builder, bfg, security-review-weekly, …) are written for this instance. Define how they port to a self-hosted, multi-builder world: which run instance-wide vs per-builder, how a fresh instance inherits/configures them, and what a builder gets by default. Spike → a contract (and likely a config surface).
150
150
 
151
- **Done when:** there's a documented model for which routines are instance-wide vs per-builder, how a fresh instance inherits them, and how a builder configures their own; no routine hard-assumes the amazonprimea instance.`,
151
+ **Done when:** there's a documented model for which routines are instance-wide vs per-builder, how a fresh instance inherits them, and how a builder configures their own; no routine hard-assumes the example instance.`,
152
152
  kind: 'spike', discipline: 'engineer', priority: 2,
153
153
  est_minutes: 120, manual_degree: 3, credits_reward: 25,
154
154
  touches: ['.claude/scheduled-tasks/', 'docs/'], criteria: ['C16'], deps: [],
@@ -7,7 +7,7 @@
7
7
  // Run: node scripts/gds/seed-provisioning-tasks.js
8
8
  const os = require('os');
9
9
  const TOKEN = require(os.homedir() + '/.config/otb/gds-session.json').token;
10
- const BASE = require('../../src/instance-config').resolveEnv('BASE') || 'https://amazonprimea.com';
10
+ const BASE = require('../../src/instance-config').resolveEnv('BASE') || 'https://example.com';
11
11
  const H = { Authorization: `Bearer ${TOKEN}`, 'Content-Type': 'application/json' };
12
12
  const GOAL = 26; // Cloud Bongos productization and self-host
13
13
 
@@ -27,7 +27,7 @@ const TASKS = [
27
27
  deps: ['P1', 'P2'], extDeps: [] },
28
28
  { ref: 'P4', kind: 'infra', discipline: 'engineer', priority: 2, est: 300,
29
29
  title: 'BV1 — Automated DNS record + Caddy on-demand ACME TLS for a provisioned host',
30
- description: 'ADR 0111 §4. Cloudflare A-record UPSERT via the shared client (P2), plus Caddy on-demand ACME (Let\'s Encrypt) so a NEWLY provisioned host is TLS-ready with no manual Cloudflare Origin-Cert console step (the least-automated leg today). On-demand TLS MUST be allow-listed to hostnames the module actually provisioned (no cert-minting for arbitrary names). Existing amazonprimea/cloudbongos apexes keep their Origin Certs unchanged. deps: P2, P3. (buildable now)',
30
+ description: 'ADR 0111 §4. Cloudflare A-record UPSERT via the shared client (P2), plus Caddy on-demand ACME (Let\'s Encrypt) so a NEWLY provisioned host is TLS-ready with no manual Cloudflare Origin-Cert console step (the least-automated leg today). On-demand TLS MUST be allow-listed to hostnames the module actually provisioned (no cert-minting for arbitrary names). Existing example/cloudbongos apexes keep their Origin Certs unchanged. deps: P2, P3. (buildable now)',
31
31
  deps: ['P2', 'P3'], extDeps: [] },
32
32
  { ref: 'P5', kind: 'feature', discipline: 'engineer', priority: 2, est: 240,
33
33
  title: 'BV1 — Wire provisioning into `bongos init` (idea #345 — "configured via the API")',
@@ -16,19 +16,32 @@
16
16
  # column that referenced a session, then deletes all sessions so NO real
17
17
  # bearer token persists on staging.
18
18
  #
19
- # SAFETY: hard-refuses to target anything but `amazonprimea_staging`, so a
19
+ # SAFETY: hard-refuses to target any database not named `*_staging`, so a
20
20
  # fat-fingered env can never point the wipe at production. Everything runs at
21
- # table-owner privilege (no superuser) since `lars` owns the staging objects.
21
+ # table-owner privilege (no superuser) the invoking role owns the staging objects.
22
22
  #
23
23
  # "What's real, what's faked on staging": see docs/recipes/staging-data.md.
24
24
 
25
25
  set -euo pipefail
26
26
 
27
- PROD_DB="${PROD_DB:-amazonprimea}"
28
- STAGING_DB="${STAGING_DB:-amazonprimea_staging}"
27
+ # No baked-in database names. A portable core cannot know an instance's DB, and the
28
+ # founder's two were hardcoded here until task 1003869 — including inside the safety
29
+ # check, which meant de-branding the names alone would have quietly disarmed it. So the
30
+ # guard is STRUCTURAL now instead of a name comparison: the target must be named
31
+ # <something>_staging. That keeps the original property ("a fat-fingered env can never
32
+ # point the wipe at production", since no production DB is called *_staging) and extends
33
+ # it to every instance rather than one. Both names must be set explicitly — this script
34
+ # WIPES its target, so there is no default worth guessing.
35
+ PROD_DB="${PROD_DB:-}"
36
+ STAGING_DB="${STAGING_DB:-}"
29
37
 
30
- if [ "$STAGING_DB" != "amazonprimea_staging" ]; then
31
- echo "REFUSING: STAGING_DB must be 'amazonprimea_staging' (got '$STAGING_DB'). This script wipes its target." >&2
38
+ if [ -z "$STAGING_DB" ] || [ -z "$PROD_DB" ]; then
39
+ echo "REFUSING: set PROD_DB (the dump source) and STAGING_DB (the wipe target) explicitly." >&2
40
+ echo " e.g. PROD_DB=myapp STAGING_DB=myapp_staging $0" >&2
41
+ exit 2
42
+ fi
43
+ if ! printf '%s' "$STAGING_DB" | grep -qE '^[A-Za-z0-9_]+_staging$'; then
44
+ echo "REFUSING: STAGING_DB '$STAGING_DB' must be a bare identifier ending in '_staging'. This script wipes its target." >&2
32
45
  exit 2
33
46
  fi
34
47
  if [ "$PROD_DB" = "$STAGING_DB" ]; then
@@ -171,7 +171,7 @@ function readSessionApiBase() {
171
171
  // PR-body deploy note, and the manual-confirm curl guidance. Precedence mirrors the
172
172
  // CLI's own base resolution: <PREFIX>_API_BASE env → the signed-in session's
173
173
  // api_base → branding publicOrigin → null (unknowable). There is NO hardcoded
174
- // founder host — 5 sites here baked in `https://amazonprimea.com`, so a ci-land /
174
+ // founder host — 5 sites here baked in `https://example.com`, so a ci-land /
175
175
  // manual-confirm on a migrated instance pointed the builder at the WRONG box; the
176
176
  // ci-land/guidance sibling of resolveDeployTarget()'s laptop-mode fix (task 1002232
177
177
  // ⊃ task 1002202). Pure over its injected inputs (env / sessionApiBase / branding)
@@ -306,7 +306,7 @@ async function shipMain() {
306
306
 
307
307
  // ---- Sandbox-first review gate (#927, ADR 0046) ----
308
308
  // On a dev box, a diff that touches game surfaces must be STAGED on the
309
- // builder's own live preview (sandbox-<login>.amazonprimea.com, ADR 0044)
309
+ // builder's own live preview (sandbox-<login>.example.com, ADR 0044)
310
310
  // and reviewed in a browser before the claim resolves — see it running,
311
311
  // get the chance to iterate, THEN decide to ship to the main game. Laptop
312
312
  // sessions, non-game diffs, quick-tunnel boxes, and --skip-stage all pass
@@ -54,7 +54,7 @@ function matchedApiBaseVar(env) {
54
54
  // null.
55
55
  //
56
56
  // There is deliberately NO hardcoded host. This file baked in
57
- // `https://amazonprimea.com` as its fallback, so a builder signed into any OTHER
57
+ // `https://example.com` as its fallback, so a builder signed into any OTHER
58
58
  // instance who shipped without an env override ran the ship's verification smoke
59
59
  // against the founder's box — which PASSED, because that box is healthy. The ship
60
60
  // then reported "smoke=clean" on the strength of testing a system it never
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- // External uptime prober for amazonprimea.com (incident 2026-06-03, task #565).
2
+ // External uptime prober for example.com (incident 2026-06-03, task #565).
3
3
  //
4
4
  // WHY THIS EXISTS, AND WHY IT IS NOT src/bongos/uptime-poller.js:
5
5
  // The in-process poller (src/bongos/uptime-poller.js) runs INSIDE the Node
@@ -27,7 +27,7 @@
27
27
  // the step output). Non-zero only on its own internal error.
28
28
  //
29
29
  // USAGE:
30
- // node scripts/status-probe.mjs [--dir .] [--target https://amazonprimea.com/healthz]
30
+ // node scripts/status-probe.mjs [--dir .] [--target https://example.com/healthz]
31
31
  // [--attempts 3] [--timeout-ms 15000] [--gap-ms 10000]
32
32
 
33
33
  import { readFile, writeFile, mkdir } from 'node:fs/promises';
@@ -167,9 +167,9 @@ async function addDiscordGuildMember({ guildId, discordUserId, accessToken, role
167
167
 
168
168
  // Collect EVERY candidate auth token on the request, in priority order, with
169
169
  // duplicates removed. A browser can legitimately carry MORE THAN ONE
170
- // gds_session cookie: a host-only one (set on amazonprimea.com before the
170
+ // gds_session cookie: a host-only one (set on example.com before the
171
171
  // #726/#734 apex-scoping rollout) AND the current apex-scoped one
172
- // (.amazonprimea.com). The browser sends both in the Cookie header. We must try
172
+ // (.example.com). The browser sends both in the Cookie header. We must try
173
173
  // them ALL — picking only the first (as the old single-value extractToken did)
174
174
  // meant a stale/expired duplicate could shadow the live session and 401 the
175
175
  // builder (hit on the Discord link callback for builder 25). Order: Bearer
@@ -35,7 +35,7 @@ let reconnectDelayMs = 2000; // backoff before re-LISTEN; test-tunable via _set
35
35
  // exact same socket + database (PGHOST/PGDATABASE env overrides honored for
36
36
  // non-droplet environments). The DB-name default resolves through pool.js's
37
37
  // instanceDbName() — the SINGLE source for the instance's configured db.database
38
- // (from the branding pack) — instead of a second hardcoded "amazonprimea" literal
38
+ // (from the branding pack) — instead of a second hardcoded "example" literal
39
39
  // (ADR 0062 §5). A non-OTB instance LISTENs on its OWN DB, and there is one place
40
40
  // to change the default.
41
41
  function pgConfig() {
@@ -140,13 +140,80 @@ function escapeRe(s) {
140
140
  return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
141
141
  }
142
142
 
143
- const COMPILED = PROTECTED_SURFACES.map((s) => ({ ...s, re: globToRegExp(s.glob) }));
143
+ // task 1002874: the glob is normalised ONCE here, at build, not per candidate —
144
+ // there are 51 surfaces and `matchProtected` runs over every changed file on the
145
+ // push/claim/grade path. `s.glob` itself is kept VERBATIM on the entry, because it
146
+ // is what gets reported back to a refused builder and in the registry's own docs;
147
+ // only the compiled matcher is folded.
148
+ const COMPILED = PROTECTED_SURFACES.map((s) => ({ ...s, re: globToRegExp(foldForMatch(s.glob)) }));
144
149
 
145
150
  // Normalize a path the way git reports it (forward slashes, no leading ./).
151
+ // normalize — put a path in the ONE spelling matching happens in.
152
+ //
153
+ // task 1002874 (ADR 0151 §4, the last piece of R101's scope): this used to do
154
+ // only backslash→slash and strip a leading './', so matching was exact-BYTES. On
155
+ // a case-insensitive filesystem — macOS by default, and Windows, i.e. the two
156
+ // platforms most builders use — `Src/Bongos/Auth.js` and `src/bongos/auth.js` name
157
+ // the SAME file, and only one of them matched the protected-surface glob. Unicode
158
+ // composition does the same thing invisibly: NFD (`e` + U+0301) and NFC (`é`) are
159
+ // different byte strings for one filename, and a checkout can hand you either.
160
+ // A protected-path wall you can step over by spelling is not a wall.
161
+ //
162
+ // BOTH SIDES go through this — the candidate here, and every registry glob ONCE at
163
+ // COMPILED build — so the transform is applied symmetrically and matching cannot
164
+ // become narrower. It is a strict widening: any pair that matched byte-for-byte
165
+ // still matches after both are folded the same way. The only regression shape is
166
+ // OVER-protection, surfacing as an unexpected claim/push refusal, never a silent
167
+ // un-protection.
168
+ //
169
+ // CASE FOLD: `toLowerCase()`, and that IS the invariant fold here. The Turkish-I
170
+ // hazard the ADR warns about belongs to `toLocaleLowerCase('tr')`, which maps
171
+ // 'I' → 'ı' (dotless) — measured. Plain `toLowerCase()` is Unicode Default Case
172
+ // Conversion and is locale-independent by specification, so it is the correct
173
+ // primitive and `toLocaleLowerCase` is the one that must never appear on this
174
+ // path. A test asserts it does not.
175
+ //
176
+ // ORDER: NFC first, then fold. Measured equivalent to folding first for the
177
+ // composed-accent cases, and NFC-first keeps the input in one canonical form
178
+ // before any other transform reasons about it.
146
179
  function normalize(p) {
147
180
  return String(p || '').replace(/\\/g, '/').replace(/^\.\//, '').trim();
148
181
  }
149
182
 
183
+ // foldForMatch — the spelling MATCHING happens in. Separate from normalize() on
184
+ // purpose: normalize() still produces the path we REPORT, and that must keep its
185
+ // original case. A finding, a refusal message and a grader issue all carry
186
+ // `file`, and on a case-sensitive filesystem (Linux, i.e. CI) a lowercased path
187
+ // names nothing — a consumer that tried to read it would get ENOENT for a file
188
+ // that exists.
189
+ function foldForMatch(p) {
190
+ return normalize(p).normalize('NFC').toLowerCase();
191
+ }
192
+
193
+ // compileGlobMatcher(globs) → (file) => boolean, with the fold applied to BOTH
194
+ // sides: each glob once here, the candidate on every call.
195
+ //
196
+ // task 1002874: this exists because `globToRegExp` + the raw `PROTECTED_GLOBS`
197
+ // are BOTH exported, and a consumer that compiles them itself gets a byte-exact
198
+ // matcher — which is precisely the wall this task removed, rebuilt by accident.
199
+ // gate-review.js had done exactly that (its ESCALATE / HARD_FLOOR classifier),
200
+ // so an uppercased spelling still slipped past CI's auto-merge gate after the
201
+ // matcher here was fixed. Anything matching a PROTECTED-surface list should
202
+ // compile through this, not through globToRegExp directly.
203
+ //
204
+ // NOT a blanket replacement for globToRegExp, deliberately. Folding widens what
205
+ // matches, and that is only safe when matching more means protecting more. On an
206
+ // ALLOW-list — publish-manifest's PUBLISH_ALLOWLIST, which decides what reaches
207
+ // the public OSS mirror — widening would publish MORE files. Those lists keep
208
+ // the exact matcher on purpose.
209
+ function compileGlobMatcher(globs) {
210
+ const compiled = (globs || []).map((g) => globToRegExp(foldForMatch(g)));
211
+ return (file) => {
212
+ const folded = foldForMatch(file);
213
+ return folded ? compiled.some((re) => re.test(folded)) : false;
214
+ };
215
+ }
216
+
150
217
  // Which of `files` are permission-sensitive? Returns
151
218
  // [{ file, glob, floor, permission }] — floor + permission come straight from the
152
219
  // registry entry that matched, so a governance re-map flows through every caller.
@@ -155,7 +222,11 @@ function matchProtected(files) {
155
222
  for (const raw of files || []) {
156
223
  const f = normalize(raw);
157
224
  if (!f) continue;
158
- const hit = COMPILED.find((c) => c.re.test(f));
225
+ // Match on the FOLDED spelling, report the original one — see foldForMatch.
226
+ // Hoisted OUT of the predicate on purpose: inside it, the fold re-runs once
227
+ // per registry surface (51 today) for every candidate file.
228
+ const folded = foldForMatch(raw);
229
+ const hit = COMPILED.find((c) => c.re.test(folded));
159
230
  if (hit) out.push({ file: f, glob: hit.glob, floor: hit.floor, permission: hit.permission });
160
231
  }
161
232
  return out;
@@ -164,7 +235,8 @@ function matchProtected(files) {
164
235
  // The registry entry governing `file`, or null when the path is unprotected.
165
236
  function surfaceFor(file) {
166
237
  const f = normalize(file);
167
- const hit = f ? COMPILED.find((c) => c.re.test(f)) : null;
238
+ const folded = f ? foldForMatch(file) : '';
239
+ const hit = f ? COMPILED.find((c) => c.re.test(folded)) : null;
168
240
  return hit ? { glob: hit.glob, floor: hit.floor, permission: hit.permission, group: hit.group, why: hit.why } : null;
169
241
  }
170
242
 
@@ -271,6 +343,11 @@ module.exports = {
271
343
  REGISTRY_PATH,
272
344
  SPECIALTY,
273
345
  globToRegExp,
346
+ compileGlobMatcher,
347
+ // foldForMatch is deliberately NOT exported: it is the internal spelling rule,
348
+ // and every caller should go through compileGlobMatcher so the fold is applied
349
+ // to BOTH sides. Handing it out invites a consumer to fold one side only, which
350
+ // is the asymmetry that breaks matching outright.
274
351
  matchProtected,
275
352
  surfaceFor,
276
353
  floorFor,
@@ -10,7 +10,7 @@
10
10
  // DB resolution (highest wins), NOT hard-defaulting to a host's DB name:
11
11
  // DATABASE_URL -> PGHOST/PGDATABASE env -> the instance's configured db.database
12
12
  // (config/branding.json, else config/branding.neutral.json)
13
- // OTB's branding pack carries db.database='amazonprimea', so prod (no DB env set) resolves to the
13
+ // OTB's branding pack carries db.database='example', so prod (no DB env set) resolves to the
14
14
  // exact same socket+database it used before this carve-out — live prod is unaffected. A fresh
15
15
  // instance points this at its own DB via env or its own branding pack; the neutral starter has
16
16
  // db.database=null so a misconfigured instance fails loudly rather than silently targeting OTB.