@bongos/core 1.19.156 → 1.19.158

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 (63) hide show
  1. package/.bongos-core.json +73 -68
  2. package/.claude/skills/blocker-review/SKILL.md +3 -3
  3. package/.claude/skills/blocker-solve/SKILL.md +3 -3
  4. package/.claude/skills/builder-backup/SKILL.md +2 -2
  5. package/.claude/skills/builder-box/SKILL.md +1 -1
  6. package/.claude/skills/builder-claim/SKILL.md +1 -1
  7. package/.claude/skills/builder-connect/SKILL.md +5 -5
  8. package/.claude/skills/builder-cost/SKILL.md +2 -2
  9. package/.claude/skills/builder-exit/SKILL.md +1 -1
  10. package/.claude/skills/builder-reauth/SKILL.md +2 -2
  11. package/.claude/skills/builder-redteam/SKILL.md +2 -2
  12. package/.claude/skills/builder-setup/SKILL.md +4 -4
  13. package/.claude/skills/builder-start/SKILL.md +4 -4
  14. package/.claude/skills/close-box/SKILL.md +2 -2
  15. package/.claude/skills/design-sync/SKILL.md +2 -2
  16. package/.claude/skills/dev/SKILL.md +2 -2
  17. package/.claude/skills/feedback/SKILL.md +2 -2
  18. package/.claude/skills/fix-task/SKILL.md +1 -1
  19. package/.claude/skills/goal-create/SKILL.md +2 -2
  20. package/.claude/skills/goal-review/SKILL.md +2 -2
  21. package/.claude/skills/grader-health/SKILL.md +1 -1
  22. package/.claude/skills/idea-triage/SKILL.md +3 -3
  23. package/.claude/skills/merge-mode/SKILL.md +2 -2
  24. package/.claude/skills/planning-session/SKILL.md +2 -2
  25. package/.claude/skills/priority-session/SKILL.md +2 -2
  26. package/.claude/skills/read-session-export/SKILL.md +2 -2
  27. package/.claude/skills/scan-before-install/SKILL.md +3 -3
  28. package/.claude/skills/status/SKILL.md +1 -1
  29. package/docs/architecture.md +7 -7
  30. package/docs/branding-contract.md +1 -1
  31. package/docs/design/modular-architecture/01-architecture.md +2 -2
  32. package/docs/design/modular-architecture/02-module-map.md +1 -1
  33. package/docs/design/modular-architecture/03-builder-flows.md +1 -1
  34. package/docs/design-contract.md +4 -4
  35. package/docs/file-map.md +12 -12
  36. package/docs/modules-contract.md +2 -2
  37. package/docs/onboarding/diagrams/README.md +4 -4
  38. package/docs/onboarding/drachmae-and-karma.md +1 -1
  39. package/docs/recipes/README.md +1 -1
  40. package/docs/recipes/audit-replay.md +1 -1
  41. package/docs/recipes/builder-box-lifecycle.md +2 -2
  42. package/docs/recipes/claude-design-loop.md +4 -4
  43. package/docs/recipes/core-release-pipeline.md +1 -1
  44. package/docs/recipes/devbox-app-release.md +2 -2
  45. package/docs/recipes/devbox-app-windows-test.md +1 -1
  46. package/docs/recipes/figma-design-loop.md +4 -4
  47. package/docs/recipes/gds-db-backup.md +3 -3
  48. package/docs/recipes/instance-deploy.md +1 -1
  49. package/docs/recipes/managed-settings-remote-control.md +9 -9
  50. package/docs/recipes/ops-gotchas.md +2 -2
  51. package/docs/recipes/overnight-builder.md +2 -2
  52. package/docs/recipes/packaging-the-core.md +1 -1
  53. package/docs/recipes/search-index-ingestion.md +3 -3
  54. package/docs/recipes/self-host.md +2 -2
  55. package/docs/recipes/work-on-a-task-from-your-dev-box.md +1 -1
  56. package/docs/research/llm-model-agnostic-and-cheaper-grader.md +1 -1
  57. package/modules/platform-identity/platform-identity.js +31 -12
  58. package/modules/platform-identity/tests/platform-identity.mjs +18 -1
  59. package/package-lock.json +2 -2
  60. package/package.json +1 -1
  61. package/scripts/gds/run-unit-tests.js +1 -1
  62. package/src/module-api.js +5 -1
  63. package/tests/scouting_rollup_fanout.mjs +113 -0
package/docs/file-map.md CHANGED
@@ -27,12 +27,12 @@
27
27
  │ ├── v1-shipped.md ← V1 game archive (shipped 2026-05-12)
28
28
  │ ├── pms-v2-shipped.md ← PMS-V2 archive (shipped 2026-05-12)
29
29
  │ ├── pms-v1-shipped.md ← PMS-V1 archive (shipped 2026-05-09)
30
- │ └── backlog.md ← FROZEN archive after one-time DB import (live tasks in GDS DB)
31
- ├── generative-ideas.md ← FROZEN archive after Phase 2c DB import (live ideas in GDS idea_inbox table)
30
+ │ └── backlog.md ← FROZEN archive after one-time DB import (live tasks in Bongos DB)
31
+ ├── generative-ideas.md ← FROZEN archive after Phase 2c DB import (live ideas in Bongos idea_inbox table)
32
32
  │ (chat-inbox.md removed 2026-06-05 — inbound is now Discord #ideas → idea_inbox, ADR 0033 F6)
33
33
  ├── blockers/
34
34
  │ ├── README.md
35
- │ └── blockers.md ← FROZEN archive after Phase 2a DB import (live blockers in GDS blockers table)
35
+ │ └── blockers.md ← FROZEN archive after Phase 2a DB import (live blockers in Bongos blockers table)
36
36
  │
37
37
  ├── brand/ ← repo-canonical design system (ADR 0081)
38
38
  │ └── cloud-bongos/ ← Cloud Bongos brand: README design guide + tokens.json + regen_*.py + assets/ (mascot, 9 animation states, Docker-homage sky-whale, coin logo + Baloo 2 wordmark, painted code-glyph charms). Built under task 1506 (mascot restyle 1529, code glyphs 1527); illustrations generated via Gemini (modules/art-pipeline/pipeline gen_api).
@@ -43,7 +43,7 @@
43
43
  │ ├── adr/ ← Architecture Decision Records
44
44
  │ │ ├── README.md ← full ADR index (authoritative)
45
45
  │ │ └── 0001…0120-*.md ← 133 ADR files (a handful of numbers collide — see README.md's disambiguation note; README.md has the live list)
46
- │ ├── architecture.md ← §10 detail: live infra, app stack, DB schema, GDS API (split out V3.R86)
46
+ │ ├── architecture.md ← §10 detail: live infra, app stack, DB schema, Bongos API (split out V3.R86)
47
47
  │ ├── canonical-permissions.md ← rank ladder + trust boundary reference (read-only mirror; DB enforces)
48
48
  │ ├── design/ ← game design docs (V2 visual redesign cluster)
49
49
  │ │ ├── container-exterior.md ← (#641) container building exterior: two-storey stacked-container structure, glass facade, deck, rooftop
@@ -81,12 +81,12 @@
81
81
  │ ├── box-terminal.service ← (#760/ADR 0038) always-on ttyd web terminal (127.0.0.1:7681, per-box basic-auth) for thin-device (Chromebook/browser) builders
82
82
  │ ├── cloudflared.service ← (#760/ADR 0038) outbound-only Cloudflare Tunnel exposing the box terminal (no inbound ports); runs cloudflared-run.sh
83
83
  │ └── cloudflared-run.sh ← (#760/ADR 0038) runs ON THE BOX: named tunnel (BOX_TUNNEL_TOKEN) or tokenless quick tunnel; writes the public URL to /run/otb/terminal-url
84
- ├── migrations/ ← CORE (build-system / GDS) migrations — schema + platform-universal seeds, applied on EVERY instance (migrate.sh `migrations/*.sql`). Game-module migrations moved to modules/game/migrations/ (BV1.R49).
84
+ ├── migrations/ ← CORE (build-system / Bongos) migrations — schema + platform-universal seeds, applied on EVERY instance (migrate.sh `migrations/*.sql`). Game-module migrations moved to modules/game/migrations/ (BV1.R49).
85
85
  │ ├── instance/ ← OTB/product SCOPE-TRUTH seeds (versions, goals, done_when_criteria). Applied only on the OWNING instance — `GDS_APPLY_INSTANCE_SEEDS=1`, default OFF — so a vanilla/branded self-host never inherits them (task 1704 / ADR 0105). Merge-sorted with core by basename, so global order is preserved.
86
86
  │ ├── game/ ← LEGACY game-module migrations (moved to modules/game/migrations/ in BV1.R49 — stem-keyed, so they did NOT re-run on prod). Kept here as a frozen archive; migrate.sh still applies them for backward compat.
87
87
  │ │ ├── 001_initial.sql ← schema_migrations + world_events (game)
88
88
  │ │ └── 002_players.sql ← players — persistent identity (game)
89
- │ ├── 003_pms.sql ← GDS schema: builders, versions, tasks, claims, costs, credits, sessions
89
+ │ ├── 003_pms.sql ← Bongos schema: builders, versions, tasks, claims, costs, credits, sessions
90
90
  │ ├── 112_drop_track_check.sql ← task 1191: drop the product|internal track CHECK on versions (taxonomy → branding.tracks config); name-independent + idempotent
91
91
  │ ├── <redacted>.sql ← cost_log unique (source, source_ref) for idempotent backfill
92
92
  │ ├── 005_pms_smoke_filter.sql ← filter __smoke__ tasks from claimable_tasks + version_progress
@@ -128,8 +128,8 @@
128
128
  │
129
129
  ├── scripts/
130
130
  │ ├── migrate.sh ← idempotent migration runner; applies core `migrations/*.sql` always + `modules/<key>/migrations/*.sql` only when the module is enabled (ADR 0083 §module-owned-migrations); stem-keyed so relocating a migration between dirs never re-runs it on prod
131
- │ ├── verify-gds-only-schema.sh ← task 1191: throwaway-DB proof that a GDS-only migration run yields the build-system schema with NO game tables (needs local Postgres; not the DB-free unit gate)
132
- │ ├── setup-builder.js ← one-command new-builder bootstrap (toolchain + npm ci + .env.local + GDS auth); cross-platform node entry (#673)
131
+ │ ├── verify-gds-only-schema.sh ← task 1191: throwaway-DB proof that a Bongos-only migration run yields the build-system schema with NO game tables (needs local Postgres; not the DB-free unit gate)
132
+ │ ├── setup-builder.js ← one-command new-builder bootstrap (toolchain + npm ci + .env.local + Bongos auth); cross-platform node entry (#673)
133
133
  │ ├── setup-builder.sh ← thin bash shim → setup-builder.js (Mac/Linux convenience + devcontainer/README refs)
134
134
  │ ├── deploy/ ← deploy scripts that run ON the droplet
135
135
  │ │ ├── deploy-prod.sh ← #1026/ADR 0056: version-controlled MIRROR of the droplet's hand-maintained ~/deploy.sh (byte-faithful). NOT auto-installed — the ci deploy key is forced-command-locked (ADR 0042/0043); reinstall by hand on change. Localhost /healthz retried 15×@1s so a slow bind no longer false-fails a deploy.
@@ -140,7 +140,7 @@
140
140
  │ │ ├── README.md
141
141
  │ │ ├── lib.js ← webhook poster (reads ~/.config/otb/discord-webhooks.json, mode 600)
142
142
  │ │ └── post.js ← post a ship summary to a channel (default ship_news)
143
- │ └── gds/ ← Game Development System CLI + bootstrap (renamed from `pms/` in V3.R01)
143
+ │ └── gds/ ← Bongos CLI + bootstrap (renamed from `pms/` in V3.R01)
144
144
  │ ├── cli-lib.js ← shared: session token, apiCall(), formatters
145
145
  │ ├── discord-channels.js ← Archon CLI: plan/apply the Discord channel layout via the API (ADR 0036, #727)
146
146
  │ ├── setup.js ← one-time GitHub Device Flow → ~/.config/otb/gds-session.json
@@ -170,7 +170,7 @@
170
170
  │ ├── smoke-gds.js ← public-surface + 401-check smoke test (asserts /api/pms/* now 404s — removed in V3.R01-followup #308)
171
171
  │ ├── box.js ← (#598/ADR 0031) per-builder dev box lifecycle CLI: provision·park·wake·deprovision·sweep-idle·sweep-dormant·status (dry-run default, --apply to act; rank-gated)
172
172
  │ ├── smoke-box.sh ← (#598) hermetic box-lifecycle smoke (no DB/DO/network): runs tests/boxes.mjs + tests/cf_tunnel.mjs (#771 named tunnel) + route-rank + module-load
173
- │ ├── recall.js ← `/recall` CLI: two-call progressive-disclosure search (summary → `--expand <id>`) over the GDS retrieval layer (ADR 0060); `node scripts/gds/recall.js <query>`
173
+ │ ├── recall.js ← `/recall` CLI: two-call progressive-disclosure search (summary → `--expand <id>`) over Bongos retrieval layer (ADR 0060); `node scripts/gds/recall.js <query>`
174
174
  │ ├── capture.js ← file an idea_inbox row from the CLI (the ideas.capture kernel port); backs the "capture a tangent" flow across skills
175
175
  │ ├── worktree.js ← (task 1002809) junction-safe worktree add/remove/list — outside-repo worktrees get a node_modules junction via node (no shell quoting), removed BEFORE `git worktree remove`
176
176
  │ ├── learning-capture.js ← file a `learnings` row (DB-backed short-form rule capture, replacing hand-edited recipe files for a single gotcha)
@@ -194,7 +194,7 @@
194
194
  │ │ ├── provenance.js ← pure "who BUILT this module" classifier from manifest.origin — the CREDIT axis (ADR 0107 §9). own-built vs core-loaded.
195
195
  │ │ ├── catalog.js ← the browsable module catalog model (ADR 0167 / ADR 0107 §2/§3): `source` (which TREE ships it — core package vs instance, read off the loader's discovery root) + resolved author/origin `credit` with an `inferred` flag. The ONE builder behind both `GET /api/bongos/modules` and `bongos module list --catalog`, so the hall + CLI can't drift.
196
196
  │ │ └── semver.js ← minimal semver `satisfies(version, range)` used by the loader (no npm dep).
197
- │ ├── platform-server.js ← GDS-ONLY entrypoint (ADR 0062 R51, task 1190): boots Express + the shared internal surface (API + hall + status) with NO game in the process; the inverse of preview-server.js. `node src/platform-server.js`
197
+ │ ├── platform-server.js ← BONGOS-ONLY entrypoint (ADR 0062 R51, task 1190): boots Express + the shared internal surface (API + hall + status) with NO game in the process; the inverse of preview-server.js. `node src/platform-server.js`
198
198
  │ ├── preview-server.js ← GAME-ONLY entrypoint for the per-box sandbox (ADR 0052): Phaser/Colyseus + tiles, NO /api/gds
199
199
  │ ├── seats.js ← in-process seat counter + EventEmitter
200
200
  │ ├── rooms/
@@ -404,7 +404,7 @@ To install on a new machine, symlink each routine's directory under `~/.claude/s
404
404
  ├── pre-compact.js ← PreCompact: thin reader around eviction-policy.js — emits an eviction directive (blocks to drop + one-line recovery stubs) at the compaction seam (task 1349)
405
405
  ├── eviction-policy.js ← pure deterministic in-session compaction classifier (transcript turns → eviction set + replacement stubs); no I/O, unit-tested in tests/eviction_policy.mjs; consumed by pre-compact.js (task 1348)
406
406
  ├── stop-sound.js ← Stop: completion sound on macOS (afplay; Glass / Hero on /tmp/otb-celebrate); silent no-op on other OSes
407
- └── stop-refcheck.js ← Stop: deterministic backstop that catches a bare `#NNN` GDS ref in live session text (autolinks to a 404 GitHub issue) and asks for the clickable form (follow-on to task 929)
407
+ └── stop-refcheck.js ← Stop: deterministic backstop that catches a bare `#NNN` Bongos ref in live session text (autolinks to a 404 GitHub issue) and asks for the clickable form (follow-on to task 929)
408
408
  ```
409
409
 
410
410
  (Before [#671](https://example.com/builders#/task/671) these ran via `bash` shims — `sync-env-local.sh`, `conductor.sh`, `onboarding-ship-logs.sh`, `rank-change-greeting.sh`, `pull-memory.sh` — which failed on Windows without Git Bash. The Node entries above replaced them.)
@@ -79,7 +79,7 @@ Every module must have a `module.json` at its root (`modules/<key>/module.json`)
79
79
  "description": "…", // REQUIRED. One sentence.
80
80
  "coreVersion": "^1.2.0", // REQUIRED. semver range of CORE_VERSION this module supports.
81
81
  "default": false, // OPTIONAL (default false). Fail-safe when no config names it.
82
- "author": "…", // OPTIONAL. Attribution (ADR 0107 §2) — portable, not a cross-GDS FK.
82
+ "author": "…", // OPTIONAL. Attribution (ADR 0107 §2) — portable, not a cross-Bongos FK.
83
83
  "origin": "…", // OPTIONAL. Origin instance/project this module was built in.
84
84
  "license": "AGPL-3.0", // OPTIONAL. License this module is offered under.
85
85
  "maintainer": "…", // OPTIONAL. Who to credit/contact if this module is upstreamed.
@@ -113,7 +113,7 @@ An unknown key throws at validate time — typos fail loud (top-level attributio
113
113
 
114
114
  `@bongos/core` ships lean — its synthesized `package.json` declares only `express` + `pg` ([ADR 0108](adr/<redacted>.md)). A bundled module that needs an external npm package at runtime (e.g. `discord` → `discord.js`) declares it in its own `module.json` `dependencies` (`{ "<npm-name>": "<semver-range>" }`, schema-validated). **Core does not carry it**, so the *consumer* must — greenfield `bongos init` composes the ENABLED modules' declared deps into the instance `package.json` (`enabledModuleDeps` → `buildInstancePackageJson`; an explicit pre-existing pin wins, `@bongos/core` is always set), and the R89 cutover preserves the monolith's existing dependency closure. If a module needs a dep and neither declares it nor is it in the consumer's closure, an instance that enables the module crashes at boot — so **declare it here**.
115
115
 
116
- **Attribution (`author`/`origin`/`license`/`maintainer`) is portable metadata, not a cross-GDS link** — each repo runs its own GDS with its own builder identities ([ADR 0100](adr/<redacted>.md) §3), so credit travels *with the module* rather than through a foreign key ([ADR 0107](adr/<redacted>.md) §2). `bongos module new` stamps all four as TODO placeholders (license defaults to `AGPL-3.0`) so a module carries its authorship from the day it's scaffolded, not bolted on later at upstream-submit time.
116
+ **Attribution (`author`/`origin`/`license`/`maintainer`) is portable metadata, not a cross-Bongos link** — each repo runs its own Bongos with its own builder identities ([ADR 0100](adr/<redacted>.md) §3), so credit travels *with the module* rather than through a foreign key ([ADR 0107](adr/<redacted>.md) §2). `bongos module new` stamps all four as TODO placeholders (license defaults to `AGPL-3.0`) so a module carries its authorship from the day it's scaffolded, not bolted on later at upstream-submit time.
117
117
 
118
118
  **`bongos module list [--catalog] [--search <text>] [--json]`** ([ADR 0107](adr/<redacted>.md) §2/§3, [ADR 0167](adr/<redacted>.md)) is the browsable catalog from the terminal: every module on disk with its enabled state, its author + origin credit, and its upkeep posture. `--catalog` narrows to the **core-shipped** modules — the shared catalog an instance opts into (§6, default-off). Two axes travel on each row and they are *not* the same question: **`source`** (which tree ships it — the core package or this instance's own repo, read structurally from the loader's discovery root, [ADR 0108](adr/<redacted>.md) §1) and **`provenance`** (who built it, derived from the declared `origin`). A core module that declares no attribution is credited to the platform and the credit is **marked inferred** (`*`) rather than left blank or silently invented. The hall's Modules tab renders the same model (`src/module-loader/catalog.js`) via `GET /modules`, so the two surfaces cannot drift.
119
119
 
@@ -1,6 +1,6 @@
1
- # How the GDS works — visual diagrams
1
+ # How Bongos works — visual diagrams
2
2
 
3
- Five flowcharts that explain the Game Development System (GDS) to a new builder at a glance. Each diagram is committed as **Mermaid source** (`.mmd`) plus a rendered **`.svg`** (the crisp, pannable/zoomable asset) and **`.png`** (a static fallback / external-embed image), embedded in the `/builders` hall at `/builders/diagrams` and the builder primer ([V3.R13 / #237](../../../CLAUDE.md)). On those pages the diagrams are **pan-and-zoom canvases** (drag to pan, scroll to zoom, fullscreen) — see [`modules/hall-ui/public/diagram-viewer.js`](../../../modules/hall-ui/public/diagram-viewer.js).
3
+ Five flowcharts that explain Bongos to a new builder at a glance. Each diagram is committed as **Mermaid source** (`.mmd`) plus a rendered **`.svg`** (the crisp, pannable/zoomable asset) and **`.png`** (a static fallback / external-embed image), embedded in the `/builders` hall at `/builders/diagrams` and the builder primer ([V3.R13 / #237](../../../CLAUDE.md)). On those pages the diagrams are **pan-and-zoom canvases** (drag to pan, scroll to zoom, fullscreen) — see [`modules/hall-ui/public/diagram-viewer.js`](../../../modules/hall-ui/public/diagram-viewer.js).
4
4
 
5
5
  > Built under **V3.R76 ([#295](https://example.com/builders#/task/295))**; auto-regeneration + drift detection added under **[#356](https://example.com/builders#/task/356)/[#357](https://example.com/builders#/task/357)**; conceptual diagrams (03/04) made auto-generated under **[#436](https://example.com/builders#/task/436)**; a dev-box topology diagram (06) added under **[#1031](https://example.com/builders#/task/1031)** and then **merged with 04 into the single `04-architecture` map + SVG pan/zoom viewer under [#1059](https://example.com/builders#/task/1059)**.
6
6
 
@@ -11,13 +11,13 @@ Five flowcharts that explain the Game Development System (GDS) to a new builder
11
11
  | Diagram | What drives its state |
12
12
  |---|---|
13
13
  | `01-task-lifecycle` · `02-rank-ladder` · `05-versioning` (**mechanical**) | The task-status set + rank enum/wiring (read from `migrations/` + `src/bongos/`) and the live version set (production API). No auth needed — always regenerate. |
14
- | `03-example-karma` · `04-architecture` (**conceptual**) | Each feature-piece is **LIVE iff its backing GDS task is `shipped`**, plus 03's "N seeded" count from the achievements seed in `migrations/`. These read the **authenticated** `/tasks/:id` status, so when no GDS session is available (headless run, no creds) the generator **skips** 03/04 and leaves them untouched rather than emit wrong data. (04's device/box/server/GitHub *topology* is structural; only its LIVE/PLANNED markers — the memory chain + the box→prod ship-flow legs — are task-gated.) |
14
+ | `03-example-karma` · `04-architecture` (**conceptual**) | Each feature-piece is **LIVE iff its backing Bongos task is `shipped`**, plus 03's "N seeded" count from the achievements seed in `migrations/`. These read the **authenticated** `/tasks/:id` status, so when no Bongos session is available (headless run, no creds) the generator **skips** 03/04 and leaves them untouched rather than emit wrong data. (04's device/box/server/GitHub *topology* is structural; only its LIVE/PLANNED markers — the memory chain + the box→prod ship-flow legs — are task-gated.) |
15
15
 
16
16
  The mechanical diagrams regenerate **on every deploy** (`ship.js` / `/merge-mode` run `gen-diagrams.js` before deploying; a changed diagram is committed and shipped automatically). The conceptual diagrams regenerate the same way whenever a session is present (the deploy host has one). The `diagram-drift` routine remains as a belt-and-braces backstop. So `/builders/diagrams` is never more than one deploy behind the live architecture.
17
17
 
18
18
  ## Reading the diagrams — live vs planned
19
19
 
20
- The GDS is mid-build. These diagrams deliberately distinguish **what exists today** from **what GDS-V3 plans to add**, so they double as a "where are we at" snapshot:
20
+ Bongos is mid-build. These diagrams deliberately distinguish **what exists today** from **what GDS-V3 plans to add**, so they double as a "where are we at" snapshot:
21
21
 
22
22
  | Marker | Meaning |
23
23
  |---|---|
@@ -1,6 +1,6 @@
1
1
  # Example & karma — how you get paid, and how you earn trust
2
2
 
3
- *The complete reference for the two reputation tracks in the GDS. The [primer](primer.md) gives you the one-paragraph version; this is the full picture, kept honest against the live system. ~8 minutes.*
3
+ *The complete reference for the two reputation tracks in Bongos. The [primer](primer.md) gives you the one-paragraph version; this is the full picture, kept honest against the live system. ~8 minutes.*
4
4
 
5
5
  > **Source of truth.** The numbers live in the production database (`builders.total_credits`, `builders.karma`) and the rules live in code (`src/bongos/db.js`, `src/bongos/cost.js`). This doc *describes* them; where they disagree, the code wins. The two diagrams that visualize this — [task lifecycle](diagrams/01-task-lifecycle.png) and [example & karma](diagrams/03-example-karma.png) — are auto-generated from the same live facts.
6
6
 
@@ -1,6 +1,6 @@
1
1
  # `docs/recipes/` — long-form operational recipes
2
2
 
3
- > **Renamed from `learnings/` in Phase 2b** (2026-05-10). The folder used to hold a mix of long-form guides and short-form rules; the dual-write with the GDS `learnings` table made the split confusing. Now: this folder = long-form recipes (multi-page operational guides); the DB `learnings` table = short-form per-rule learnings (rule + why + how-to-apply).
3
+ > **Renamed from `learnings/` in Phase 2b** (2026-05-10). The folder used to hold a mix of long-form guides and short-form rules; the dual-write with Bongos `learnings` table made the split confusing. Now: this folder = long-form recipes (multi-page operational guides); the DB `learnings` table = short-form per-rule learnings (rule + why + how-to-apply).
4
4
 
5
5
  This folder holds **things we have already discovered the hard way and need to write up at length**. Read the relevant file before you do similar work, and you will not repeat the discovery.
6
6
 
@@ -24,7 +24,7 @@ Notably absent — and worth knowing about so you can ask follow-up questions if
24
24
 
25
25
  - **GET requests** are not in `audit_log` (by design; high volume, low signal). Read patterns aren't part of this replay.
26
26
  - **Builder rank changes** show up as `HTTP_PATCH route=/api/gds/builders/:id/rank` rows and as `CREDIT` rows when the rank change carries a example adjustment. The new rank value lives in `audit_log.request_body_redacted`.
27
- - **Game-server WebSocket events** (movement, world state) live in `world_events` and are NOT included here — this script is GDS-scoped. If a game-side investigation is needed, query `world_events` separately.
27
+ - **Game-server WebSocket events** (movement, world state) live in `world_events` and are NOT included here — this script is Bongos-scoped. If a game-side investigation is needed, query `world_events` separately.
28
28
 
29
29
  ## Running the script
30
30
 
@@ -26,7 +26,7 @@ none ─provision─▶ active ────────────────
26
26
 
27
27
  The idle sweep **deprovisions** a box when its `last_activity_at` (else `active_since`) is older than `BOX_IDLE_MINUTES` **and** `claude_active` is not true. Both signals are set by **`infra/box-heartbeat.sh`**, which runs **inside the box** every ~5 min and POSTs `/api/gds/box/heartbeat` *only while the box is in use* — an interactive login session, an established SSH connection, an **open browser terminal** (ttyd websocket, [#1161](https://example.com/builders#/task/1161)), or non-trivial CPU load. Silence = the sweep is free to destroy it.
28
28
 
29
- > ⚠️ **The idle sweep's correctness depends on the box-side heartbeat reaching the server.** If it isn't pinging — no GDS token on the box yet, a pre-[#1161](https://example.com/builders#/task/1161) script that can't see a browser terminal, or the cron not installed — `last_activity_at` never advances and the sweep falls back to `active_since`, i.e. it measures **uptime**, not activity, and will **destroy** a box someone is actively using. Because the idle path is now a full deprovision (no park to wake from), that wrongly-reaped box also loses uncommitted work (spike [#837](https://example.com/builders#/task/837)).
29
+ > ⚠️ **The idle sweep's correctness depends on the box-side heartbeat reaching the server.** If it isn't pinging — no Bongos token on the box yet, a pre-[#1161](https://example.com/builders#/task/1161) script that can't see a browser terminal, or the cron not installed — `last_activity_at` never advances and the sweep falls back to `active_since`, i.e. it measures **uptime**, not activity, and will **destroy** a box someone is actively using. Because the idle path is now a full deprovision (no park to wake from), that wrongly-reaped box also loses uncommitted work (spike [#837](https://example.com/builders#/task/837)).
30
30
  >
31
31
  > **Live mitigation (2026-06-16):** `BOX_IDLE_MINUTES` is raised to **120** in `/etc/example/box.env` as a soak margin until [#1161](https://example.com/builders#/task/1161)'s browser-terminal heartbeat is verified on a newcomer box; lower it back toward the 10-min default once that's proven.
32
32
 
@@ -63,7 +63,7 @@ node scripts/gds/box.js reconcile-drift # DO⇄DB drift; add --apply to
63
63
 
64
64
  The teardown is now **confirm-before-destroyed**: `deprovision` only marks a box `destroyed` AFTER DigitalOcean confirms the droplet is deleted (idempotent + retried). A delete that genuinely fails parks the box at `state='error'` with `droplet_id` preserved and **throws** — it never silently leaves a running droplet behind a `destroyed` row (the old "zombie" bug).
65
65
 
66
- `reconcile-drift` is the backstop. It lists the real fleet droplets (a live read — needs `DO_API_TOKEN`, present in `box.env`) and reconciles against the GDS rows **both ways**:
66
+ `reconcile-drift` is the backstop. It lists the real fleet droplets (a live read — needs `DO_API_TOKEN`, present in `box.env`) and reconciles against the Bongos rows **both ways**:
67
67
 
68
68
  - **Zombie** — a droplet no live box row claims → force-delete the droplet + its tunnel/DNS.
69
69
  - **Ghost** — a live row whose `droplet_id` vanished from DO → mark it `destroyed`.
@@ -12,14 +12,14 @@
12
12
 
13
13
  - Starting a UI sprint and want Claude Design to prototype from real tokens, not approximations.
14
14
  - Tokens or surfaces changed and the Claude Design project is stale.
15
- - A Claude Design prototype is done and you want to land the generated code as a GDS task.
15
+ - A Claude Design prototype is done and you want to land the generated code as a Bongos task.
16
16
 
17
17
  ---
18
18
 
19
19
  ## Prerequisites
20
20
 
21
21
  - **Rank: Metic+** (design-sync routes are Metic-gated server-side).
22
- - **Claimed GDS task** — use this for the handoff step. If you're just exporting, no claim is required; a claim is required when you `export()` and commit the generated code.
22
+ - **Claimed Bongos task** — use this for the handoff step. If you're just exporting, no claim is required; a claim is required when you `export()` and commit the generated code.
23
23
  - **DesignSync MCP** — the `mcp__DesignSync__*` tools must be available in your session.
24
24
 
25
25
  ---
@@ -84,11 +84,11 @@ Claude Design can now reference the token cards. Typical workflow:
84
84
 
85
85
  ---
86
86
 
87
- ## 4. Land the handoff as a GDS task
87
+ ## 4. Land the handoff as a Bongos task
88
88
 
89
89
  When Claude Design's output is ready:
90
90
 
91
- **a. Claim a GDS task** (if not already done).
91
+ **a. Claim a Bongos task** (if not already done).
92
92
 
93
93
  **b. Run the export step** — either via the skill or directly:
94
94
 
@@ -27,7 +27,7 @@ A change crosses three independent gates. **None of them implies the next**, and
27
27
  | **2** | **Released** | a `CORE_VERSION` exists that *contains* the commit, and an artifact was cut from it | a builder bumps + packages; **the owner publishes** | the version is published / a `.tgz` exists |
28
28
  | **3** | **Deployed** | a specific instance moved its pin to that version | per instance | that instance's `/version` reports the new `coreVersion` |
29
29
 
30
- The GDS vocabulary collides with gate 1 in a way worth naming: **task status `shipped` means "merged to `main`"** — it does not mean released, and it does not mean live. `ship.js` says so in its own comment and, since task 1002521, prints a divergence warning at the end of every ship.
30
+ Bongos vocabulary collides with gate 1 in a way worth naming: **task status `shipped` means "merged to `main`"** — it does not mean released, and it does not mean live. `ship.js` says so in its own comment and, since task 1002521, prints a divergence warning at the end of every ship.
31
31
 
32
32
  ---
33
33
 
@@ -46,7 +46,7 @@ releases repo → a one-line config bump re-points the branded
46
46
 
47
47
  1. Bump `devbox-app/package.json` version (e.g. `1.1.0`) and regenerate
48
48
  icons only if they changed (`npm run icons`).
49
- 2. Land the bump on `main` through the normal GDS flow, then wait for
49
+ 2. Land the bump on `main` through the normal Bongos flow, then wait for
50
50
  `build-devbox-app` to go green **on the `main` run** — that is the run that
51
51
  carries the installers.
52
52
  3. Download the artifacts (they expire after 3 days — re-run the workflow on
@@ -69,7 +69,7 @@ releases repo → a one-line config bump re-points the branded
69
69
  5. Update `config/devbox-app.json`: `version` + the four asset filenames
70
70
  (they embed the version — `tests/devbox_downloads.mjs` fails the gate on a
71
71
  half-bumped config).
72
- 6. Ship the config change through the normal GDS flow. **Bumping `config/devbox-app.json`
72
+ 6. Ship the config change through the normal Bongos flow. **Bumping `config/devbox-app.json`
73
73
  `version` is what triggers the in-app update banner in the field ([#924](https://example.com/builders#/task/924))** — running
74
74
  apps poll `GET /downloads/devbox/version`, compare it to their own `package.json`
75
75
  version with a proper semver compare (`devbox-app/src/updater.js`), and show
@@ -113,7 +113,7 @@ the Claude Desktop connection file:
113
113
 
114
114
  ## Recording results
115
115
 
116
- File outcomes against the verification task in the GDS. For any failure
116
+ File outcomes against the verification task in Bongos. For any failure
117
117
  grab: the panel state, `%TEMP%`/console output if launched from a terminal
118
118
  (`& "$env:LOCALAPPDATA\Programs\OTB Dev Box\OTB Dev Box.exe"` shows logs),
119
119
  the relevant PowerShell output from steps 3–4, and a screenshot. The fastest
@@ -14,14 +14,14 @@
14
14
 
15
15
  - A designer wants to make a manual edit to a UI surface directly in Figma (the "human escape hatch").
16
16
  - Tokens or surfaces changed and the Figma file is stale — push before the designer opens it.
17
- - A Figma edit is done (via Code Connect or a raw canvas change) and you want to land it as a GDS task.
17
+ - A Figma edit is done (via Code Connect or a raw canvas change) and you want to land it as a Bongos task.
18
18
 
19
19
  ---
20
20
 
21
21
  ## Prerequisites
22
22
 
23
23
  - **Rank: Metic+** for the handoff step (task authoring / commit under a claim).
24
- - **Claimed GDS task** — required when you `export()` and commit the generated code.
24
+ - **Claimed Bongos task** — required when you `export()` and commit the generated code.
25
25
  - **Figma MCP write capability** in your session (`mcp__figma__*` write tools, or `use_figma`). Read-only tools alone are not enough to push. If unavailable, stop and surface the gap rather than faking the push — see `otb-figma-sync`'s own capability check for the same pattern.
26
26
 
27
27
  ---
@@ -64,9 +64,9 @@ The designer opens the pushed frames (or an existing component) and makes a manu
64
64
 
65
65
  ---
66
66
 
67
- ## 4. Land the edit as a GDS task
67
+ ## 4. Land the edit as a Bongos task
68
68
 
69
- **a. Claim a GDS task** (if not already done).
69
+ **a. Claim a Bongos task** (if not already done).
70
70
 
71
71
  **b. Run the export step.** Figma hands back one of two shapes:
72
72
 
@@ -1,4 +1,4 @@
1
- # Recipe — GDS DB backup (local nightly + offsite weekly)
1
+ # Recipe — Bongos DB backup (local nightly + offsite weekly)
2
2
 
3
3
  > **Filed by:** task [#412](https://example.com/builders#/task/412) (V3.R62-precondition, local nightly) + [#415](https://example.com/builders#/task/415) (V3.R62-offsite, weekly offsite archive) — both under [ADR 0024](../adr/<redacted>.md) §5 (backup cadence). Vendor choice for the offsite copy: [ADR 0025](../adr/<redacted>.md) (DigitalOcean Spaces).
4
4
  > **Two layers:** a **local daily** `pg_dump` to `/var/backups/gds/` (protects against corruption / bad migration / accidental delete) **plus** a **weekly offsite copy** of the latest local dump to a DigitalOcean Space (protects against whole-droplet loss).
@@ -244,8 +244,8 @@ curl -s https://example.com/api/gds/public/progress | jq '.progress[0]'
244
244
 
245
245
  ## Limits — what this recipe does NOT cover
246
246
 
247
- 1. **Whole-droplet loss window is ~1 week, not zero.** The weekly offsite copy ([#415](https://example.com/builders#/task/415), above) closes the catastrophic-loss gap, but it runs weekly — so in the worst case (droplet dies right before the weekly run) you lose up to ~7 days of writes that made it into the local daily dumps but not yet offsite. Acceptable for the GDS DB's shape; tighten the offsite cadence to daily if that ever stops being true.
248
- 2. **Continuous archiving / PITR is not configured.** A restore brings you back to the most recent nightly snapshot, not the precise moment of failure. Up to 24 hours of writes can be lost in a worst-case restore. That's acceptable for the GDS DB's current shape (work-state ledger, no transactional money flows) but worth revisiting if/when the DB takes on stripe-payment or fulfillment state.
247
+ 1. **Whole-droplet loss window is ~1 week, not zero.** The weekly offsite copy ([#415](https://example.com/builders#/task/415), above) closes the catastrophic-loss gap, but it runs weekly — so in the worst case (droplet dies right before the weekly run) you lose up to ~7 days of writes that made it into the local daily dumps but not yet offsite. Acceptable for the Bongos DB's shape; tighten the offsite cadence to daily if that ever stops being true.
248
+ 2. **Continuous archiving / PITR is not configured.** A restore brings you back to the most recent nightly snapshot, not the precise moment of failure. Up to 24 hours of writes can be lost in a worst-case restore. That's acceptable for the Bongos DB's current shape (work-state ledger, no transactional money flows) but worth revisiting if/when the DB takes on stripe-payment or fulfillment state.
249
249
  3. **No automated alerting on a failed run yet.** The unit emits a non-zero exit on failure, which `systemctl status gds-db-backup.timer` will surface, but nothing pages you. Add a check to the existing `overnight-builder` health surface or the `weekly-security-review` scheduled task if backups silently failing for N days becomes a real concern.
250
250
  4. **No automated cadence for the restore drill.** The recipe above is just text until a human (or scheduled task) runs it. [#281](https://example.com/builders#/task/281) R62 is where the formal drill cadence lands.
251
251
 
@@ -16,7 +16,7 @@
16
16
  1. **`git pull --ff-only origin main`** the *instance* repo — host content only: `config/`, `migrations/instance/`, and the pinned core version in `package.json`.
17
17
  2. **`npm ci --omit=dev`** — installs the pinned `@bongos/core` + instance deps. This is what replaces `git reset --hard`: the core is a dependency, so an upgrade is a pin bump + `npm ci`, not a source merge.
18
18
  3. **`bash <core>/scripts/migrate.sh`** — the core's **three-root** migrate (W5 / ADR 0108 §5) merges `<core>/migrations` + `<instance>/migrations/instance` + each enabled module's migrations, keyed by namespaced filename stems (`core_NNN_`, `<key>_NNN_`, bare instance) so the two repos never collide. It resolves core-root vs instance-root via `src/instance-config.js`.
19
- 4. **restart the platform** — a systemd unit runs `node <core>/src/platform-server.js` (GDS-only) with `WorkingDirectory` = the instance root (so `resolveInstanceRoot()` resolves to the instance) + `PORT`/`HOST` env; then poll `/healthz`.
19
+ 4. **restart the platform** — a systemd unit runs `node <core>/src/platform-server.js` (Bongos-only) with `WorkingDirectory` = the instance root (so `resolveInstanceRoot()` resolves to the instance) + `PORT`/`HOST` env; then poll `/healthz`.
20
20
 
21
21
  `docker-compose.yml` + `.github/workflows/selfhost-boot.yml` already model this shape (fresh Postgres → `npm ci` → `migrate.sh` → `platform-server`), so the flow is validated end-to-end there.
22
22
 
@@ -69,7 +69,7 @@ Override with `--allow-no-keys` only if you will re-provision once they register
69
69
 
70
70
  **How the key reaches the box without an operator SSH round-trip:** `box.js` reads the
71
71
  builder's registered keys from the DB and **bakes** them into the cloud-init managed
72
- block at provision (so the first login works before the box has any GDS token). From
72
+ block at provision (so the first login works before the box has any Bongos token). From
73
73
  then on, `infra/<redacted>.sh` (a 10-min cron on the box, wired by the
74
74
  cloud-init) keeps `authorized_keys` in sync via `GET /box/authorized-keys` — which is
75
75
  **gated on the builder's LIVE rank+status** exactly like source access ([#600](https://example.com/builders#/task/600)). A
@@ -178,7 +178,7 @@ The builder opens the tunnel URL in any browser, authenticates at the basic-auth
178
178
 
179
179
  > **Workspace trust is pre-seeded ([#824](https://example.com/builders#/task/824)).** The cloud-init writes `/root/.claude.json` with `<redacted>` for `/root` + `/workspace`, so the first `claude` launch usually skips the trust dialog entirely. This is **non-load-bearing** (ADR 0040): the seed is best-effort and only written when the file is absent (upstream pre-seeding is flaky, [#9113](https://github.com/anthropics/claude-code/issues/9113)). If it doesn't take, the builder just accepts trust once — the flow works either way.
180
180
 
181
- The cloud-init wires both units automatically (and `infra/box-source-fetch.sh` re-installs them on its post-clone bring-up, so a box provisioned before this shipped picks them up on its next refresh). It copies `infra/box-terminal.service` and `infra/cloudflared.service` to `/etc/systemd/system/`, enables them with `systemctl enable --now`, and wires `infra/box-report-terminal.sh` as a 1-minute cron that publishes the terminal URL + credential **up** to the GDS (`POST /box/terminal`) so the builder's self-serve flow can read them back.
181
+ The cloud-init wires both units automatically (and `infra/box-source-fetch.sh` re-installs them on its post-clone bring-up, so a box provisioned before this shipped picks them up on its next refresh). It copies `infra/box-terminal.service` and `infra/cloudflared.service` to `/etc/systemd/system/`, enables them with `systemctl enable --now`, and wires `infra/box-report-terminal.sh` as a 1-minute cron that publishes the terminal URL + credential **up** to Bongos (`POST /box/terminal`) so the builder's self-serve flow can read them back.
182
182
 
183
183
  **Tunnel modes:**
184
184
 
@@ -210,7 +210,7 @@ Then:
210
210
 
211
211
  | State | What happens |
212
212
  |---|---|
213
- | Box first boots | `box-terminal.service` (ttyd) + `cloudflared.service` start; `box-report-terminal` cron publishes the URL + credential to the GDS within ~1 min |
213
+ | Box first boots | `box-terminal.service` (ttyd) + `cloudflared.service` start; `box-report-terminal` cron publishes the URL + credential to Bongos within ~1 min |
214
214
  | Builder connects (first time) | Opens the tunnel URL, basic-auths as `otb`, runs `claude` (one-time browser `/login`), then `/remote-control` to get a pairing link and drive the box from the Claude app (ADR 0040) |
215
215
  | Builder works (each session) | Lives in the Claude web/mobile app via the RC link; the ttyd terminal is only the launchpad they logged in through |
216
216
  | Session ends | Builder closes the browser tab; the terminal + tunnel stay up for the next visit |
@@ -229,7 +229,7 @@ journalctl -u cloudflared -n 100 # last 100 lines
229
229
  sudo systemctl restart box-terminal cloudflared
230
230
  ```
231
231
 
232
- The quick-tunnel hostname is printed in the `cloudflared` journal; the same value is published to the GDS by the `box-report-terminal` cron (verify with `crontab -l | grep box-report-terminal`).
232
+ The quick-tunnel hostname is printed in the `cloudflared` journal; the same value is published to Bongos by the `box-report-terminal` cron (verify with `crontab -l | grep box-report-terminal`).
233
233
 
234
234
  ### Named-tunnel automation (control plane, [#771](https://example.com/builders#/task/771))
235
235
 
@@ -293,7 +293,7 @@ The build is unit- and smoke-covered, but the loop crosses real hardware + a hum
293
293
 
294
294
  - **Packaged ttyd collision (fixed).** The Ubuntu `ttyd` apt package ships its OWN auto-started `ttyd.service` that binds `127.0.0.1:7681` with **no `--credential`** and runs `login`. It both blocks our `box-terminal.service` (the unit crash-loops on `EADDRINUSE`) and — because the tunnel fronts whatever sits on 7681 — would expose an **unauthenticated** terminal. Cloud-init and the `box-source-fetch` post-clone bring-up now `systemctl mask ttyd` so only our basic-auth ttyd binds the port. On a box provisioned before this fix: `sudo systemctl disable --now ttyd && sudo systemctl mask ttyd && sudo systemctl restart box-terminal`.
295
295
  - **IPv4-only Cloudflare calls (fixed).** The CF API token is IP-locked to the droplet's IPv4 (least privilege). The droplet also has IPv6 egress; `cf-tunnel.js` pins IPv4 (undici `Agent{connect:{family:4}}`) or every call 401s — mirroring `box-dns-cloudflare.sh`'s `curl -4`.
296
- - **⚠ Browser-only bootstrap gap (OPEN — follow-up).** The `ttyd`/`cloudflared` systemd units live in the repo (`/workspace/infra/*.service`), so they only start **after** `box-source-fetch` clones — which needs the **builder's GDS token on the box**. A pure Chromebook builder has no SSH and no terminal yet, so there is **no first-boot path to place that token** → the terminal never comes up for them. Today it only works if the token is seeded another way (SSH, or an operator). The fix (a follow-up) is to bring ttyd up at **first boot independent of the clone** — e.g. cloud-init writes the unit inline rather than copying it from the repo. Until then, the browser on-ramp is verified to work *given a token on the box*, not from a truly bare browser-only device.
296
+ - **⚠ Browser-only bootstrap gap (OPEN — follow-up).** The `ttyd`/`cloudflared` systemd units live in the repo (`/workspace/infra/*.service`), so they only start **after** `box-source-fetch` clones — which needs the **builder's Bongos token on the box**. A pure Chromebook builder has no SSH and no terminal yet, so there is **no first-boot path to place that token** → the terminal never comes up for them. Today it only works if the token is seeded another way (SSH, or an operator). The fix (a follow-up) is to bring ttyd up at **first boot independent of the clone** — e.g. cloud-init writes the unit inline rather than copying it from the repo. Until then, the browser on-ramp is verified to work *given a token on the box*, not from a truly bare browser-only device.
297
297
 
298
298
  ---
299
299
 
@@ -317,13 +317,13 @@ If missing (pre-[#599](https://example.com/builders#/task/599) box):
317
317
  ## Part 4 — Rank-gated source access ([#600](https://example.com/builders#/task/600), ADR 0031 §6 / §9.2)
318
318
 
319
319
  The box holds **no baked credential**. Instead it fetches a rank-scoped clone spec
320
- from the GDS at boot and on a 10-minute cron, via `infra/box-source-fetch.sh`
320
+ from Bongos at boot and on a 10-minute cron, via `infra/box-source-fetch.sh`
321
321
  (carried onto the box as base64 inside the cloud-init `write_files`). The flow:
322
322
 
323
- 1. The box reads the builder's GDS session token (it appears after they authenticate
323
+ 1. The box reads the builder's Bongos session token (it appears after they authenticate
324
324
  Claude Code / run `/builder-reauth` — so the **first clone lands after the builder
325
325
  connects**, not at boot).
326
- 2. It calls `GET /api/gds/box/source-access`. The GDS checks the builder's **live**
326
+ 2. It calls `GET /api/gds/box/source-access`. Bongos checks the builder's **live**
327
327
  rank + status (ADR 0016 — unforgeable from the box):
328
328
  - **403 `SOURCE_ACCESS_REVOKED`** — builder demoted below the floor or deactivated.
329
329
  The script cuts the credentialed remote (box-side clawback); `box.js reconcile`
@@ -399,7 +399,7 @@ bash infra/gen-managed-settings.sh alice > /tmp/alice-managed-settings.json
399
399
 
400
400
  # 4. For thin-device (Chromebook) path: the web terminal is ready automatically
401
401
  # (box-terminal.service + cloudflared.service start at boot; box-report-terminal
402
- # publishes the URL + credential to the GDS within ~1 min)
402
+ # publishes the URL + credential to Bongos within ~1 min)
403
403
  # Builder self-serves: POST /api/gds/box/ensure, then poll GET /api/gds/box/terminal
404
404
  # -> open the url, basic-auth as user 'otb' with the returned credential, run: claude
405
405
  # -> then /remote-control to drive the box from the Claude app (ADR 0040)
@@ -167,7 +167,7 @@ Organized by topic, not chronology. New entries go in the matching section; crea
167
167
 
168
168
  ---
169
169
 
170
- ## GDS build pipeline
170
+ ## Bongos build pipeline
171
171
 
172
172
  ### Two deterministic routines run as in-process server timers, not external cron
173
173
 
@@ -221,7 +221,7 @@ Organized by topic, not chronology. New entries go in the matching section; crea
221
221
 
222
222
  - **Symptom:** the site is down for hours, but The Watch still shows 100% / "standing".
223
223
  - **Root cause:** `status.example.com` is served by the same Node process on the same droplet as the game, and the in-process poller (`src/bongos/uptime-poller.js`) probes `127.0.0.1`. When the droplet dies, the page dies with it and the poller writes **zero rows** — the gap renders as green. A monitor that lives inside the monitored thing cannot witness its own death.
224
- - **Fix:** measure availability from **outside** (the external GitHub-Actions prober — `.github/workflows/status-probe.yml`, task [#565](https://example.com/builders#/task/565)) and host the status page **off-box** (follow-up [#566](https://example.com/builders#/task/566)). See [ADR 0029](../adr/<redacted>.md) + GDS learning `#35`.
224
+ - **Fix:** measure availability from **outside** (the external GitHub-Actions prober — `.github/workflows/status-probe.yml`, task [#565](https://example.com/builders#/task/565)) and host the status page **off-box** (follow-up [#566](https://example.com/builders#/task/566)). See [ADR 0029](../adr/<redacted>.md) + Bongos learning `#35`.
225
225
  - **Why it bites:** a status page that lies is worse than none — it actively reassures you while the product is on fire.
226
226
 
227
227
  ### The live status page is NOT served by the droplet — editing the status surface + deploying does nothing
@@ -4,9 +4,9 @@
4
4
 
5
5
  ## What it does
6
6
 
7
- Starts one session that works the GDS queue **by priority, on its own**. It claims the highest-priority safe task, works it in a fresh sub-agent, ships it, then re-polls the claimable list — the promote-on-ship DB trigger (migration 020) self-feeds the queue, so as soon as one task ships the next unblocked one is waiting. It loops until nothing claimable remains, the time budget runs out, or the cost cap is hit.
7
+ Starts one session that works the Bongos queue **by priority, on its own**. It claims the highest-priority safe task, works it in a fresh sub-agent, ships it, then re-polls the claimable list — the promote-on-ship DB trigger (migration 020) self-feeds the queue, so as soon as one task ships the next unblocked one is waiting. It loops until nothing claimable remains, the time budget runs out, or the cost cap is hit.
8
8
 
9
- It only ever touches tasks the GDS marks safe to run unattended (`automation_tag = 'overnight-safe'`, `manual_degree <= 2`, unblocked). Nothing broken reaches `main`: the quality grader gates credits and the auto-merge re-runs smoke tests and bails (parking the task) on any conflict or failure.
9
+ It only ever touches tasks Bongos marks safe to run unattended (`automation_tag = 'overnight-safe'`, `manual_degree <= 2`, unblocked). Nothing broken reaches `main`: the quality grader gates credits and the auto-merge re-runs smoke tests and bails (parking the task) on any conflict or failure.
10
10
 
11
11
  ## Start it (serial — the proven path)
12
12
 
@@ -60,5 +60,5 @@ The manifest's `files[]` carries the same `{ path, mode, sha256 }` triples, so t
60
60
  ## Boundaries + relation to the mirror
61
61
 
62
62
  - **Not the public mirror.** The delayed, redacted, ~6-month-lagged public mirror ([ADR 0099](../adr/<redacted>.md)) is the open-source surface. This artifact is a *current*, versioned unit for **dependency consumption** by a sister repo — no lag. Both reuse the same `isPublishable()` selection and the same redaction; `package-core.js` imports the mirror's `redactBlob` so the redaction logic is defined once.
63
- - **Per-repo GDS.** Each instance runs its own database, tasks, builders, and credits ([ADR 0100 §3](../adr/<redacted>.md)). Packaging the core moves *code*, never work-tracking state.
63
+ - **Per-repo Bongos.** Each instance runs its own database, tasks, builders, and credits ([ADR 0100 §3](../adr/<redacted>.md)). Packaging the core moves *code*, never work-tracking state.
64
64
  - **The single-checkout instance model is not deprecated** — it stays the cheaper shape for a quick reskin (cloudbongos.com). Two-repo is the destination for a project that wants to be its own thing and pull core updates on its own schedule.
@@ -1,4 +1,4 @@
1
- # Recipe — GDS search-index ingestion (repo markdown)
1
+ # Recipe — Bongos search-index ingestion (repo markdown)
2
2
 
3
3
  How the `search_chunks` index (the recall layer, [ADR 0060](../adr/0060-gds-retrieval-layer.md)) gets populated from repo markdown, and how to operate it. Read before touching `scripts/gds/search-ingest-md.js` or the deploy hook.
4
4
 
@@ -26,7 +26,7 @@ node scripts/gds/search-ingest-md.js --dry-run
26
26
 
27
27
  # Full ingest (writes to search_chunks). Idempotent — safe to re-run; unchanged
28
28
  # chunks are skipped. Run on the droplet (DB on the local socket) or anywhere the
29
- # GDS Postgres env (PGHOST/PGDATABASE) resolves.
29
+ # Bongos Postgres env (PGHOST/PGDATABASE) resolves.
30
30
  node scripts/gds/search-ingest-md.js
31
31
 
32
32
  # Initial backfill after first deploy of the recall layer: just run the full
@@ -62,6 +62,6 @@ journalctl -u search-index-db.service -n 20 --no-pager # check the run
62
62
 
63
63
  ## Gotchas
64
64
 
65
- - **`node` must be on PATH** in the deploy shell (it is — systemd runs the app via node). The script connects via the shared `src/db.js` pool (the same Postgres the app uses), so it needs the GDS env, not a token.
65
+ - **`node` must be on PATH** in the deploy shell (it is — systemd runs the app via node). The script connects via the shared `src/db.js` pool (the same Postgres the app uses), so it needs Bongos env, not a token.
66
66
  - **The index lags the merge by one deploy** for any doc changed in a PR that doesn't itself trigger a deploy — acceptable; the deploy hook re-indexes on every prod deploy, and the [staleness monitor + /watch tile](https://example.com/builders) (`#972`) surfaces a stalled index.
67
67
  - **Don't lower the chunk size** without re-checking the eval set ([#939](https://example.com/builders#/task/939)) — chunk granularity affects recall quality and (later) embedding cost.
@@ -10,7 +10,7 @@ Bring up a vanilla Cloud Bongos instance — the build platform + builders' hall
10
10
  docker compose up
11
11
  ```
12
12
 
13
- That builds the image, starts Postgres, applies the build-system migrations (game-module migrations are skipped — this is a GDS-only instance), and serves the builders' hall at **http://localhost:3000**.
13
+ That builds the image, starts Postgres, applies the build-system migrations (game-module migrations are skipped — this is a Bongos-only instance), and serves the builders' hall at **http://localhost:3000**.
14
14
 
15
15
  - The instance is **vanilla** by default: the neutral Cloud Bongos brand, every feature module (game, art pipeline, Discord, dev boxes) **off**. `.dockerignore` keeps the host's `config/branding.json` and `config/modules.json` out of the image, so it resolves to `config/branding.neutral.json` + `config/modules.neutral.json`.
16
16
  - **No OTB scope-truth is seeded.** OTB/product data (game versions, goals, done-when criteria) lives in opt-in seed migrations under `migrations/instance/` (plus a few guarded blocks in the mixed files 003/006). `scripts/migrate.sh` skips them unless `GDS_APPLY_INSTANCE_SEEDS=1`, so a fresh DB comes up with only the schema and platform-universal defaults (ranks, achievements) — no crash, no foreign-key failures, no leftover versions. Platform system principals (`bfg-system`, `discord-bot-system`) are generic and remain. See task 1704 / [ADR 0105](../adr/<redacted>.md).
@@ -51,7 +51,7 @@ Author `config/branding.json` from the neutral starter — see [the branding con
51
51
 
52
52
  ## What the image contains
53
53
 
54
- - `node src/platform-server.js` — the GDS-only entrypoint (no Colyseus, no game rooms, no game assets).
54
+ - `node src/platform-server.js` — Bongos-only entrypoint (no Colyseus, no game rooms, no game assets).
55
55
  - `postgresql-client` (for `scripts/migrate.sh`) + `tini` as PID 1.
56
56
  - Runs as the unprivileged `node` user; a `HEALTHCHECK` polls `/healthz`.
57
57
 
@@ -48,7 +48,7 @@ spec. Lose the claim or a rank, and the next fetch is cut off at the server.
48
48
 
49
49
  If you haven't yet, run **`/builder-connect`** (or follow the
50
50
  [dev-box lifecycle recipe](builder-box-lifecycle.md)) to raise and connect to your
51
- box, then **`/builder-setup`** once on the box to sign the GDS CLI in. The browser
51
+ box, then **`/builder-setup`** once on the box to sign the Bongos CLI in. The browser
52
52
  terminal drops you into `/workspace` — the one working folder.
53
53
 
54
54
  > **`bongos shell` / `bongos code` re-scope on connect (BV1.R101).** Connecting with
@@ -182,7 +182,7 @@ The grader is the **single best place to spend a cheaper model**, for three reas
182
182
 
183
183
  ## 6. Recommended sequence (what to build, in order)
184
184
 
185
- 🔧 This mirrors ADR 0089's "Implementation (task-pending)" staging, pinned to the files this audit found. Each step is a candidate GDS task; each is behind a flag and ships without destabilizing the live gate.
185
+ 🔧 This mirrors ADR 0089's "Implementation (task-pending)" staging, pinned to the files this audit found. Each step is a candidate Bongos task; each is behind a flag and ships without destabilizing the live gate.
186
186
 
187
187
  | # | Step | Primary files | Behavior change | Owner cost ask |
188
188
  |---|---|---|---|---|
@@ -423,21 +423,40 @@ async function upsertActivity({ clientId, githubId, credits = 0, tasksShipped =
423
423
  // The scouting rollup: one row PER BUILDER, aggregated across every project they
424
424
  // build on. Joined to the account for display. Ranked by total credits then ships —
425
425
  // a talent signal, NOT an authority. Powers the Archon-only scouting view (#1002114).
426
+ //
427
+ // The scalar aggregates MUST see exactly one row per (builder, project): joining
428
+ // unnest(disciplines) before GROUP BY multiplied every activity row by the number
429
+ // of disciplines on it, inflating project_count and the credits/ships/karma sums
430
+ // (task 1002911). So scalars aggregate in `agg` over the un-fanned table, and the
431
+ // disciplines union is computed separately in `disc`. Proven against real SQL by
432
+ // tests/scouting_rollup_fanout.mjs.
426
433
  async function listScoutingRollup({ limit = 100, pool = defaultPool } = {}) {
427
434
  const { rows } = await pool.query(
428
- `SELECT a.github_id,
435
+ `WITH agg AS (
436
+ SELECT a.github_id,
437
+ count(*)::int AS project_count,
438
+ sum(a.credits)::int AS total_credits,
439
+ sum(a.tasks_shipped)::int AS total_tasks_shipped,
440
+ sum(a.karma)::int AS total_karma,
441
+ max(a.last_active) AS last_active
442
+ FROM platform_identity_builder_project_activity a
443
+ GROUP BY a.github_id
444
+ ), disc AS (
445
+ SELECT x.github_id, array_agg(DISTINCT x.d) AS disciplines
446
+ FROM (SELECT a.github_id, unnest(a.disciplines) AS d
447
+ FROM platform_identity_builder_project_activity a) x
448
+ WHERE x.d IS NOT NULL
449
+ GROUP BY x.github_id
450
+ )
451
+ SELECT agg.github_id,
429
452
  acc.github_login, acc.display_name, acc.avatar_url,
430
- count(*)::int AS project_count,
431
- sum(a.credits)::int AS total_credits,
432
- sum(a.tasks_shipped)::int AS total_tasks_shipped,
433
- sum(a.karma)::int AS total_karma,
434
- max(a.last_active) AS last_active,
435
- array_agg(DISTINCT d) FILTER (WHERE d IS NOT NULL) AS disciplines
436
- FROM platform_identity_builder_project_activity a
437
- LEFT JOIN platform_identity_accounts acc ON acc.github_id = a.github_id
438
- LEFT JOIN LATERAL unnest(a.disciplines) AS d ON true
439
- GROUP BY a.github_id, acc.github_login, acc.display_name, acc.avatar_url
440
- ORDER BY total_credits DESC, total_tasks_shipped DESC
453
+ agg.project_count, agg.total_credits, agg.total_tasks_shipped,
454
+ agg.total_karma, agg.last_active,
455
+ disc.disciplines
456
+ FROM agg
457
+ LEFT JOIN platform_identity_accounts acc ON acc.github_id = agg.github_id
458
+ LEFT JOIN disc ON disc.github_id = agg.github_id
459
+ ORDER BY agg.total_credits DESC, agg.total_tasks_shipped DESC
441
460
  LIMIT $1`,
442
461
  [limit],
443
462
  );