@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.
- package/.bongos-core.json +176 -491
- package/.devcontainer/Dockerfile +1 -1
- package/.devcontainer/devcontainer.json +2 -2
- package/.devcontainer/healthcheck.sh +1 -1
- package/.devcontainer/init-firewall.sh +1 -1
- package/.devcontainer/post-create.sh +2 -2
- package/.env.local.example +1 -1
- package/Dockerfile +1 -1
- package/docs/copy-inventory.md +1 -1
- package/docs/copy-registry.json +9 -9
- package/docs/module-api-changelog.md +2 -0
- package/docs/recipes/devbox-app-release.md +4 -4
- package/modules/dev-box/app/scripts/dmgbuild-settings.py +5 -5
- package/modules/dev-box/app/scripts/gen-brand.js +1 -1
- package/modules/dev-box/app/src/brand.js +1 -1
- package/modules/dev-box/app/test/unit.mjs +16 -16
- package/modules/dev-box/box-access.js +1 -1
- package/modules/dev-box/routes/box.js +1 -1
- package/modules/discord/discord-approvals.js +1 -1
- package/modules/grading/grader-model.js +1 -1
- package/modules/grading/grader-prompt.js +1 -1
- package/modules/grading/grader-workers/quality.js +1 -1
- package/modules/hall-ui/module.json +1 -1
- package/modules/hall-ui/public/brand-apply.js +1 -1
- package/modules/hall-ui/public/shell.js +1 -1
- package/modules/hall-ui/public/work.js +1 -1
- package/modules/lifecycle/conflict-resolve.js +1 -1
- package/modules/lifecycle/db-analytics.js +1 -1
- package/modules/lifecycle/routes/analytics.js +1 -1
- package/modules/onboarding/approval-broadcast.js +1 -1
- package/modules/onboarding/onboarding.js +1 -1
- package/modules/provisioning/tests/liveness.mjs +1 -1
- package/modules/public-landing/public/index.html +1 -1
- package/modules/public-landing/public/projects-floor.states.json +2 -2
- package/modules/public-landing/public/projects.probes.json +4 -4
- package/modules/public-landing/public/projects.states.json +2 -2
- package/modules/status-ui/module.json +1 -1
- package/modules/status-ui/public/status.js +4 -4
- package/modules/status-ui/public/style.css +1 -1
- package/modules/ui-design/kit/fixtures/cost-summary.json +1 -1
- package/modules/ui-design/kit/fixtures/featured-hub.json +1 -1
- package/modules/ui-design/kit/fixtures/featured.json +1 -1
- package/modules/ui-design/kit/fixtures/leaderboard.json +1 -1
- package/modules/ui-design/kit/fixtures/my-projects.json +1 -1
- package/modules/ui-design/kit/fixtures/progress.json +1 -1
- package/modules/ui-design/kit/fixtures/recent-shipped.json +1 -1
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/scripts/cron/style_guide_audit.sh +1 -1
- package/scripts/discord/lib.js +1 -1
- package/scripts/discord/post.js +1 -1
- package/scripts/gds/audit-authorship.sh +1 -1
- package/scripts/gds/audit-replay.sh +29 -2
- package/scripts/gds/audit-ships.js +1 -1
- package/scripts/gds/backfill-sessions.js +2 -2
- package/scripts/gds/cf-tunnel.js +4 -4
- package/scripts/gds/claude-materialize.js +2 -2
- package/scripts/gds/cli-lib.js +6 -6
- package/scripts/gds/cutover-codemod.js +1 -1
- package/scripts/gds/dev-lib.js +2 -2
- package/scripts/gds/diagnose-achievements.js +2 -2
- package/scripts/gds/fitness-checks-identity.js +6 -4
- package/scripts/gds/gen-diagrams.js +1 -1
- package/scripts/gds/leak-scan-allowlist.js +293 -0
- package/scripts/gds/learning-capture.js +1 -1
- package/scripts/gds/linkify-refs.js +2 -2
- package/scripts/gds/local-preview-lib.js +1 -1
- package/scripts/gds/mirror-lineage-check.js +1 -1
- package/scripts/gds/mirror-redact.js +17 -2
- package/scripts/gds/newcomer-floor.templates.json +1 -1
- package/scripts/gds/package-core.js +18 -1
- package/scripts/gds/paste-token.js +1 -1
- package/scripts/gds/provision-units.js +2 -2
- package/scripts/gds/publish-manifest.js +15 -0
- package/scripts/gds/repo-metrics.js +1 -1
- package/scripts/gds/sandbox-stage.js +1 -1
- package/scripts/gds/seed-bongos-coreB-tranche1-tasks.js +1 -1
- package/scripts/gds/seed-bongos-coreB-tranche2-tasks.js +1 -1
- package/scripts/gds/seed-bongos-goal-hierarchy-tasks.js +1 -1
- package/scripts/gds/seed-bongos-tasks.js +2 -2
- package/scripts/gds/seed-gds-v4-tasks.js +1 -1
- package/scripts/gds/seed-medusa-tasks.js +10 -10
- package/scripts/gds/seed-module-upstreaming.js +1 -1
- package/scripts/gds/seed-productization-tasks.js +6 -6
- package/scripts/gds/seed-provisioning-tasks.js +2 -2
- package/scripts/gds/seed-staging.sh +19 -6
- package/scripts/gds/ship-deploy-target.js +1 -1
- package/scripts/gds/ship-flow.js +1 -1
- package/scripts/gds/smoke-gds.js +1 -1
- package/scripts/status-probe.mjs +2 -2
- package/src/bongos/auth-discord.js +2 -2
- package/src/bongos/live-channel.js +1 -1
- package/src/bongos/pool.js +1 -1
- package/src/bongos/routes/auth.js +11 -11
- package/src/bongos/routes/security.js +1 -1
- package/src/bongos/routes.js +1 -1
- package/src/branding.js +1 -1
- package/src/devbox-downloads.js +1 -1
- package/src/instance-config.js +2 -2
- package/src/module-api.js +1 -1
- package/src/module-loader/provenance.js +2 -2
- package/tests/art_stage.mjs +2 -2
- package/tests/auth_anthropic_identity.mjs +1 -1
- package/tests/auth_duplicate_cookie.mjs +1 -1
- package/tests/auth_error_brand.mjs +1 -1
- package/tests/auth_inactive_builder.mjs +1 -1
- package/tests/backup_cli.mjs +4 -4
- package/tests/bongos_box_connect.mjs +2 -2
- package/tests/bongos_downloads.mjs +2 -2
- package/tests/bongos_login.mjs +5 -5
- package/tests/box_connect_e2e.mjs +2 -2
- package/tests/box_dns_repoint.mjs +10 -10
- package/tests/box_host_keys.mjs +1 -1
- package/tests/box_onboard.mjs +9 -9
- package/tests/box_scope_session.mjs +1 -1
- package/tests/box_terminal_ssrf.mjs +7 -7
- package/tests/boxes.mjs +9 -9
- package/tests/branding.mjs +2 -2
- package/tests/bump_version.mjs +2 -2
- package/tests/cf_tunnel.mjs +40 -40
- package/tests/cli_token_reissue.mjs +7 -7
- package/tests/cloud_bongos_pack.mjs +1 -1
- package/tests/currency_label.mjs +8 -8
- package/tests/dev_lib.mjs +4 -4
- package/tests/devbox_dmg_backdrop.mjs +1 -1
- package/tests/devbox_downloads.mjs +2 -2
- package/tests/devbox_icons.mjs +1 -1
- package/tests/discord_approvals.mjs +1 -1
- package/tests/discord_oauth.mjs +2 -2
- package/tests/executed_closure.mjs +6 -1
- package/tests/first_admin_bootstrap.mjs +1 -1
- package/tests/gate_approvals.mjs +5 -5
- package/tests/grade_aggregates_unavailable.mjs +1 -1
- package/tests/hook_user_agents.mjs +2 -2
- package/tests/init.mjs +6 -6
- package/tests/instance_config.mjs +1 -1
- package/tests/instance_manifest.mjs +5 -5
- package/tests/instance_mismatch_guard.mjs +13 -13
- package/tests/leak_scan_allowlist.mjs +94 -0
- package/tests/migrate_root_resolution.mjs +4 -4
- package/tests/mirror_redact.mjs +28 -4
- package/tests/module_catalog.mjs +5 -5
- package/tests/module_submissions.mjs +3 -3
- package/tests/package_core.mjs +1 -1
- package/tests/parallel-load.mjs +6 -6
- package/tests/projects_hub.mjs +2 -2
- package/tests/provision.mjs +50 -50
- package/tests/provisioning_github_app_routes.mjs +1 -1
- package/tests/provisioning_onboard_mode.mjs +2 -2
- package/tests/publish_reconciler.mjs +4 -4
- package/tests/sandbox_stage.mjs +1 -1
- package/tests/scrubber_corpus.mjs +3 -3
- package/tests/search_isolation.mjs +1 -1
- package/tests/session_records.mjs +1 -1
- package/tests/ship_card.mjs +6 -6
- package/tests/ship_ci_deploy.mjs +1 -1
- package/tests/single_host_hall.mjs +9 -9
- package/tests/smoke_preflight.mjs +1 -1
- package/tests/smoke_target.mjs +1 -1
- package/tests/status-probe.mjs +1 -1
- package/tests/status_mirror_sync.mjs +1 -1
- package/docs/adr/0004-amazonprimea-name-and-trademark-acceptance.md +0 -45
- package/docs/design/mocks/_schemes.css +0 -604
- package/docs/design/mocks/component-sheet.html +0 -428
- package/docs/design/mocks/hall/_tokens.css +0 -370
- package/docs/design/mocks/hall/board/v1.html +0 -846
- package/docs/design/mocks/hall/board/v2.html +0 -858
- package/docs/design/mocks/hall/board/v3.html +0 -884
- package/docs/design/mocks/hall/goals/v1.html +0 -1212
- package/docs/design/mocks/hall/goals/v2.html +0 -1192
- package/docs/design/mocks/hall/goals/v3.html +0 -1205
- package/docs/design/mocks/hall/hall-sheet.html +0 -244
- package/docs/design/mocks/hall/reading/v1.html +0 -1125
- package/docs/design/mocks/hall/reading/v2.html +0 -1177
- package/docs/design/mocks/hall/reading/v3.html +0 -1150
- package/docs/design/mocks/hall/settings/v1.html +0 -1238
- package/docs/design/mocks/hall/settings/v2.html +0 -1235
- package/docs/design/mocks/hall/settings/v3.html +0 -1299
- package/docs/design/mocks/hall/task/v1.html +0 -633
- package/docs/design/mocks/hall/task/v2.html +0 -646
- package/docs/design/mocks/hall/task/v3.html +0 -647
- package/docs/design/mocks/hub/assets/r3-space-deepfield-half.jpg +0 -0
- package/docs/design/mocks/hub/assets/r3-space-deepfield-half.jpg.json +0 -13
- package/docs/design/mocks/hub/assets/r3-space-dust-half.jpg +0 -0
- package/docs/design/mocks/hub/assets/r3-space-dust-half.jpg.json +0 -13
- package/docs/design/mocks/hub/assets/r3-space-nebula-half.jpg +0 -0
- package/docs/design/mocks/hub/assets/r3-space-nebula-half.jpg.json +0 -13
- package/docs/design/mocks/hub/assets/r3-space-starfield-half.jpg +0 -0
- package/docs/design/mocks/hub/assets/r3-space-starfield-half.jpg.json +0 -13
- package/docs/design/mocks/hub/hub-sheet.html +0 -192
- package/docs/design/mocks/hub/mine.html +0 -465
- package/docs/design/mocks/hub/picker.html +0 -421
- package/docs/design/mocks/hub/planets.html +0 -356
- package/docs/design/mocks/hub/v1.html +0 -1209
- package/docs/design/mocks/hub/v2.html +0 -1257
- package/docs/design/mocks/hub/v3.html +0 -1496
- package/docs/design/mocks/hub/wizard.html +0 -421
- package/docs/design/mocks/landing/landing-sheet.html +0 -131
- package/docs/design/mocks/landing/v1.html +0 -956
- package/docs/design/mocks/landing/v2.html +0 -708
- package/docs/design/mocks/landing/v3.html +0 -911
- package/docs/design/mocks/landing-page-mock.html +0 -687
- package/docs/design/mocks/landing-palettes.html +0 -103
- package/docs/design/mocks/projects-hub-mock.html +0 -991
- package/docs/design/mocks/projects-hub-variants.html +0 -146
- package/docs/design/mocks/projects-page-mock.html +0 -167
- package/docs/design/mocks/world/blue-hud/_tokens.css +0 -246
- package/docs/design/mocks/world/blue-hud/hall.html +0 -595
- package/docs/design/mocks/world/blue-hud/landing.html +0 -424
- package/docs/design/mocks/world/blue-hud/status.html +0 -410
- package/docs/design/mocks/world/chrome-blobs/_tokens.css +0 -479
- package/docs/design/mocks/world/chrome-blobs/hall.html +0 -553
- package/docs/design/mocks/world/chrome-blobs/landing-b.html +0 -581
- package/docs/design/mocks/world/chrome-blobs/landing.html +0 -328
- package/docs/design/mocks/world/chrome-blobs/status.html +0 -416
- package/docs/design/mocks/world/natgeo-editorial/_tokens.css +0 -377
- package/docs/design/mocks/world/natgeo-editorial/hall.html +0 -649
- package/docs/design/mocks/world/natgeo-editorial/landing-b.html +0 -743
- package/docs/design/mocks/world/natgeo-editorial/landing.html +0 -475
- package/docs/design/mocks/world/natgeo-editorial/status.html +0 -437
- package/docs/design/mocks/world/organic-cards/_tokens.css +0 -462
- package/docs/design/mocks/world/organic-cards/hall.html +0 -625
- package/docs/design/mocks/world/organic-cards/landing-b.html +0 -736
- package/docs/design/mocks/world/organic-cards/landing.html +0 -420
- package/docs/design/mocks/world/organic-cards/status.html +0 -458
- package/docs/design/mocks/world/world-sheet.html +0 -156
|
@@ -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.
|
|
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>.
|
|
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://
|
|
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://
|
|
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
|
|
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;
|
|
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
|
|
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/
|
|
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
|
|
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.
|
|
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
|
|
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-
|
|
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.
|
|
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/
|
|
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='
|
|
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
|
|
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 =
|
|
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** (
|
|
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 (
|
|
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
|
|
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
|
|
84
|
-
- **discord** (57, 64, 94): inbound #ideas, build-broadcast, channel layout → reference the discord module; the general mechanism lives there, anything naming the
|
|
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
|
|
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
|
|
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
|
|
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://
|
|
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
|
|
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
|
|
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)
|
|
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
|
-
|
|
28
|
-
|
|
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"
|
|
31
|
-
echo "REFUSING:
|
|
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://
|
|
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)
|
package/scripts/gds/ship-flow.js
CHANGED
|
@@ -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>.
|
|
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
|
package/scripts/gds/smoke-gds.js
CHANGED
|
@@ -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://
|
|
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
|
package/scripts/status-probe.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
// External uptime prober for
|
|
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://
|
|
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
|
|
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
|
-
// (.
|
|
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 "
|
|
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() {
|
package/src/bongos/pool.js
CHANGED
|
@@ -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='
|
|
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.
|
|
@@ -267,12 +267,12 @@ const REPOS_COOKIE = 'gds_oauth_repos';
|
|
|
267
267
|
const HANDSHAKE_COOKIE_MS = 30 * 60 * 1000;
|
|
268
268
|
|
|
269
269
|
// The apex domain the instance is served under, read from the instance branding
|
|
270
|
-
// pack's cookieDomain (".
|
|
270
|
+
// pack's cookieDomain (".example.com" → "example.com",
|
|
271
271
|
// ".cloudbongos.com" → "cloudbongos.com"). The session + OAuth-state cookies are
|
|
272
272
|
// scoped to ".<apex>" so a single sign-in is shared across every subdomain
|
|
273
273
|
// (apex, builders., status.) — the enabler for the dedicated builders subdomain
|
|
274
274
|
// (#726). MUST come from config, not a hardcoded literal: a hardcoded
|
|
275
|
-
// "
|
|
275
|
+
// "example.com" made every OTHER instance (e.g. cloudbongos.com) set a
|
|
276
276
|
// cookie for the wrong domain, which the browser drops → the OAuth state cookie
|
|
277
277
|
// never persisted → "state mismatch / the gate is closed" (ADR 0062 §3/§5: domains
|
|
278
278
|
// woven into auth, config swaps must not widen cookie scope). Each instance scopes
|
|
@@ -296,7 +296,7 @@ function reqHost(req) {
|
|
|
296
296
|
}
|
|
297
297
|
|
|
298
298
|
// The production-facing hosts that share one sign-in. Deliberately enumerated
|
|
299
|
-
// (not "any *.
|
|
299
|
+
// (not "any *.example.com") so staging.example.com — a SEPARATE
|
|
300
300
|
// process + DB on :3001 — keeps a host-only cookie and never bleeds an
|
|
301
301
|
// apex-scoped token into prod (or vice versa).
|
|
302
302
|
// When COOKIE_APEX is "" (localhost / no configured cookieDomain) the set is
|
|
@@ -309,7 +309,7 @@ const APEX_COOKIE_HOSTS = new Set(
|
|
|
309
309
|
|
|
310
310
|
// Cookie attributes that vary by host. On the production-facing hosts the
|
|
311
311
|
// session cookie is scoped to the apex so it crosses subdomains (the enabler
|
|
312
|
-
// for builders.
|
|
312
|
+
// for builders.example.com, #726); everywhere else (localhost, staging)
|
|
313
313
|
// it stays host-only. Returns a spread-able object.
|
|
314
314
|
function sessionCookieDomainOpts(req) {
|
|
315
315
|
if (APEX_COOKIE_HOSTS.has(reqHost(req))) {
|
|
@@ -320,7 +320,7 @@ function sessionCookieDomainOpts(req) {
|
|
|
320
320
|
|
|
321
321
|
// Validate a caller-supplied post-sign-in return target. Accept ONLY:
|
|
322
322
|
// - a relative path beginning with a single '/' (not '//', no backslash), or
|
|
323
|
-
// - an absolute https URL whose host is the apex or a *.
|
|
323
|
+
// - an absolute https URL whose host is the apex or a *.example.com sub.
|
|
324
324
|
// Anything else (other origins, javascript:, protocol-relative) → null, so the
|
|
325
325
|
// caller falls back to the safe default. This is an open-redirect guard.
|
|
326
326
|
function safeReturnTo(raw) {
|
|
@@ -355,7 +355,7 @@ function recoveryStartHref(req) {
|
|
|
355
355
|
|
|
356
356
|
// The canonical sign-in origin, read from the instance branding pack (oauthOrigin,
|
|
357
357
|
// else publicOrigin) so a non-OTB Cloud Bongos instance pins its OAuth redirects to
|
|
358
|
-
// ITS OWN apex instead of a hardcoded "
|
|
358
|
+
// ITS OWN apex instead of a hardcoded "example.com" (ADR 0062 §3/§5; the
|
|
359
359
|
// branding contract). The fixed GDS_PUBLIC_ORIGIN env knob still wins for
|
|
360
360
|
// dev/staging (auth.js's documented FIXED env name, not a <PREFIX>_ one). Resolved
|
|
361
361
|
// once at module load; falls back to '' if branding fails, which leaves the env knob
|
|
@@ -535,7 +535,7 @@ module.exports = function buildAuthRouter() {
|
|
|
535
535
|
const state = crypto.randomBytes(16).toString('hex');
|
|
536
536
|
// redirect_uri is PINNED to the canonical origin (#734) — never derived from
|
|
537
537
|
// the request host. GitHub only knows the apex callback, so a sign-in begun
|
|
538
|
-
// on builders.
|
|
538
|
+
// on builders.example.com must still hand GitHub the apex redirect_uri
|
|
539
539
|
// or GitHub rejects it. Same posture the Discord flow already uses.
|
|
540
540
|
const redirectUri = `${WEB_REDIRECT_ORIGIN}/api/gds/auth/web/callback`;
|
|
541
541
|
res.cookie(STATE_COOKIE, state, {
|
|
@@ -551,7 +551,7 @@ module.exports = function buildAuthRouter() {
|
|
|
551
551
|
// the page gates); otherwise fall back to the Referer (the page that kicked
|
|
552
552
|
// off sign-in), so the dozens of client 401 redirects land a builder back
|
|
553
553
|
// where they were with no per-call-site change. Both go through the
|
|
554
|
-
// open-redirect allowlist (relative path or *.
|
|
554
|
+
// open-redirect allowlist (relative path or *.example.com https).
|
|
555
555
|
const returnTo = safeReturnTo(req.query.return) || safeReturnTo(req.headers.referer);
|
|
556
556
|
if (returnTo) {
|
|
557
557
|
res.cookie(RETURN_COOKIE, returnTo, {
|
|
@@ -676,7 +676,7 @@ module.exports = function buildAuthRouter() {
|
|
|
676
676
|
path: '/',
|
|
677
677
|
expires: expiresAt,
|
|
678
678
|
// Apex-scoped on the production hosts so one sign-in spans
|
|
679
|
-
//
|
|
679
|
+
// example.com + builders. + status. (#726); host-only elsewhere.
|
|
680
680
|
...sessionCookieDomainOpts(req),
|
|
681
681
|
});
|
|
682
682
|
// A browser arriving with an older session name must not keep it: two
|
|
@@ -805,7 +805,7 @@ module.exports = function buildAuthRouter() {
|
|
|
805
805
|
secure: req.secure || req.headers['x-forwarded-proto'] === 'https',
|
|
806
806
|
maxAge: 10 * 60 * 1000,
|
|
807
807
|
// Apex-scoped (#734 parity) so the state survives the host switch: the
|
|
808
|
-
// link may start on builders.
|
|
808
|
+
// link may start on builders.example.com but DISCORD_REDIRECT_URI
|
|
809
809
|
// always lands the callback on the apex. A host-only cookie would be
|
|
810
810
|
// dropped on the hop and the state check would fail ("Link handshake
|
|
811
811
|
// expired"). Mirrors the GitHub web-flow state cookie above.
|
|
@@ -1036,7 +1036,7 @@ module.exports = function buildAuthRouter() {
|
|
|
1036
1036
|
const cookieToken = sessionCookieToken(req);
|
|
1037
1037
|
if (!cookieToken) {
|
|
1038
1038
|
// Name the instance's own sign-in host (from the branding pack), not a
|
|
1039
|
-
// hardcoded "
|
|
1039
|
+
// hardcoded "example.com" (ADR 0062 §3/§5).
|
|
1040
1040
|
const signInHost = configuredOAuthOrigin().replace(/^https?:\/\//, '').split('/')[0] || 'the sign-in page';
|
|
1041
1041
|
return res.fail('cookie_required', { status: 403, message: `This endpoint mints CLI bearers from an authenticated browser session. Sign in at ${signInHost} first; bearer-only requests are rejected so a leaked CLI token cannot mint replacements for itself.` });
|
|
1042
1042
|
}
|
|
@@ -35,7 +35,7 @@ const SECURITY_DOC_CONTENT_MAX = 2_000_000;
|
|
|
35
35
|
|
|
36
36
|
// Where the full ADR is expected to live on the droplet. Configurable so dev /
|
|
37
37
|
// staging can point at a different file; the recommended prod path is
|
|
38
|
-
// /etc/
|
|
38
|
+
// /etc/example/security-adr.md (chmod 600, owned by the deploy user).
|
|
39
39
|
function adrPath() {
|
|
40
40
|
return (resolveEnv('SECURITY_ADR_PATH') || '').trim() || null;
|
|
41
41
|
}
|
package/src/bongos/routes.js
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
// Three logical groups:
|
|
12
12
|
// - /auth/* — GitHub Device Flow (CLI) + Authorization Code (web)
|
|
13
13
|
// - /me, /tasks/*, /claims/*, /cost/*, /credits/*, ... — authenticated CLI/web ops
|
|
14
|
-
// - /public/* — read-only, no auth, for status.
|
|
14
|
+
// - /public/* — read-only, no auth, for status.example.com
|
|
15
15
|
//
|
|
16
16
|
// All JSON. Same Express app as the game server.
|
|
17
17
|
|
package/src/branding.js
CHANGED
|
@@ -186,7 +186,7 @@ const branding = () => (_cached ||= loadBranding());
|
|
|
186
186
|
|
|
187
187
|
// The HTTP User-Agent the GDS sends on outbound API calls (GitHub, Discord),
|
|
188
188
|
// derived from the instance branding pack so a non-OTB Cloud Bongos instance
|
|
189
|
-
// identifies itself with ITS OWN name rather than a hardcoded "
|
|
189
|
+
// identifies itself with ITS OWN name rather than a hardcoded "example-gds"
|
|
190
190
|
// (ADR 0062 §3/§5; the branding contract). Source order: the repo name (the
|
|
191
191
|
// GitHub binding these calls actually target), else the env prefix, else a neutral
|
|
192
192
|
// fallback. Falls back hard if branding fails so an outbound call never crashes.
|
package/src/devbox-downloads.js
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
// GET /downloads/devbox/latest.json → { version, assets: { target: url } }
|
|
11
11
|
// GET /downloads/devbox/<target> → 302 to the release asset
|
|
12
12
|
//
|
|
13
|
-
// so every URL a builder ever sees or shares stays on
|
|
13
|
+
// so every URL a builder ever sees or shares stays on example.com, and a
|
|
14
14
|
// release bump is a one-file config change that rides the normal ship flow.
|
|
15
15
|
// Pure (config in, urls out) so tests need no server.
|
|
16
16
|
|
package/src/instance-config.js
CHANGED
|
@@ -73,9 +73,9 @@ function envPrefix(b = safeBrand()) {
|
|
|
73
73
|
// The default API base the CLI targets when there is no <PREFIX>_API_BASE env
|
|
74
74
|
// override AND no logged-in session api_base — i.e. the last-resort fallback.
|
|
75
75
|
// Resolves to THIS instance's own publicOrigin from the branding pack (OTB →
|
|
76
|
-
// https://
|
|
76
|
+
// https://example.com, vanilla → http://localhost:3000), so the portable
|
|
77
77
|
// core never hard-codes another instance's URL (task 1002201 — pre-ADR-0139 the
|
|
78
|
-
// literal 'https://
|
|
78
|
+
// literal 'https://example.com' was baked into cli-lib, sending every
|
|
79
79
|
// unconfigured consumer at the founder's game box). Single source of truth: every
|
|
80
80
|
// CLI base resolution routes through here. Last-resort http://localhost:3000 when
|
|
81
81
|
// branding can't be read at all — a local dev origin, never a foreign prod, so an
|
package/src/module-api.js
CHANGED
|
@@ -71,7 +71,7 @@ const { responsibilityFor, ROLE_RESPONSIBILITIES } = require('./role-responsibil
|
|
|
71
71
|
// there. scripts/gds/bump-version.js still rewrites the literal below; it appends
|
|
72
72
|
// the entry to that file. Look for a version's history there, not here.
|
|
73
73
|
// ---------------------------------------------------------------------------
|
|
74
|
-
const CORE_VERSION = '1.19.
|
|
74
|
+
const CORE_VERSION = '1.19.727'; // CI auto-patch carrier (ADR 0161); changelog: docs/module-api-changelog.md
|
|
75
75
|
|
|
76
76
|
// A namespaced logger so a module's log lines are attributable + consistent.
|
|
77
77
|
// Usage: const log = api.logger('dev-box'); log.info('mounted');
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
//
|
|
7
7
|
// No module in this tree names a FOREIGN origin today — every module here was
|
|
8
8
|
// built in this repo. Some name THIS instance as their origin (e.g. the
|
|
9
|
-
// provisioning module's "
|
|
9
|
+
// provisioning module's "Example World (the first Cloud Bongos instance…)"),
|
|
10
10
|
// which is still own-built. The split (core-loaded) side lights up only once a
|
|
11
11
|
// module is actually pulled back in from the shared catalog under a different
|
|
12
12
|
// project's name (ADR 0107 §8 pipeline, tasks 1770/1772).
|
|
@@ -17,7 +17,7 @@ function deriveProvenance(origin, ownProjectName) {
|
|
|
17
17
|
const own = ownProjectName && String(ownProjectName).trim().toLowerCase();
|
|
18
18
|
// "names this instance itself" (ADR 0107 §9) — an origin that IS, or leads
|
|
19
19
|
// with, the own project name is own-built (a self-referential origin like
|
|
20
|
-
// "
|
|
20
|
+
// "Example World (the first Cloud Bongos instance)" counts). Only an origin
|
|
21
21
|
// naming a DIFFERENT project is core-loaded from the shared catalog. (An
|
|
22
22
|
// exact `===` was too brittle: it was written when no module set `origin`,
|
|
23
23
|
// so it never met a real, descriptive value — task 1776 re-land.)
|