@bongos/core 1.19.1074 → 1.19.1076
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 +196 -211
- package/.claude/skills/blocker-solve/SKILL.md +1 -1
- package/README.md +1 -1
- package/bin/bongos.js +1 -3
- package/docs/adr/0031-cloud-dev-environments-for-builders.md +1 -1
- package/docs/adr/0035-builder-onboarding-three-paths.md +1 -1
- package/docs/adr/0044-per-box-live-game-preview.md +1 -1
- package/docs/adr/0045-devbox-desktop-app.md +1 -1
- package/docs/adr/0046-sandbox-first-review-gate.md +1 -1
- package/docs/adr/0052-sandbox-for-everyone-game-only-preview.md +1 -1
- package/docs/adr/0053-scoped-dev-box-session.md +1 -1
- package/docs/adr/0055-server-mediated-branch-publish.md +1 -1
- package/docs/adr/0057-container-cost-ledger.md +1 -1
- package/docs/adr/0059-single-approval-remove-devbox-approval-gate.md +1 -1
- package/docs/adr/0071-box-confirm-before-destroyed-and-drift-reconcile.md +1 -1
- package/docs/adr/0072-bongos-app-mac-signed-first-windows-deferred.md +1 -1
- package/docs/adr/0072-dev-box-code-staleness-visibility.md +1 -1
- package/docs/adr/0104-trust-gds-api-channel-in-auto-mode.md +1 -1
- package/docs/adr/0123-box-idle-sweep-autosave-before-destroy.md +1 -1
- package/docs/adr/0144-devbox-rehome-onto-cloudbongos-plane.md +1 -1
- package/docs/adr/0145-devbox-app-branding-driven-module.md +1 -1
- package/docs/adr/0148-task-scoped-box-source-access.md +2 -2
- package/docs/adr/0151-governance-permissions-as-atom-ranks-as-roles.md +1 -1
- package/docs/adr/0193-pause-task-scoped-box-slices.md +1 -1
- package/docs/adr/0277-a-box-is-in-use-only-while-a-human-is-attached.md +1 -1
- package/docs/adr/0346-dev-boxes-are-retired.md +69 -0
- package/docs/adr/README.md +1 -0
- package/docs/api/openapi.json +4 -4
- package/docs/architecture.md +5 -6
- package/docs/branding-contract.md +2 -2
- package/docs/canonical-permissions.md +10 -18
- package/docs/copy-inventory.md +3 -3
- package/docs/copy-registry.json +3 -3
- package/docs/design/gate-navigation-direction.md +1 -1
- package/docs/design/hall-direction-v2.md +3 -3
- package/docs/design/modular-architecture/00-research-report.md +1 -1
- package/docs/design/modular-architecture/01-architecture.md +3 -3
- package/docs/design/modular-architecture/02-module-map.md +1 -2
- package/docs/design/modular-architecture/03-builder-flows.md +22 -20
- package/docs/design/modular-architecture/04-module-lifecycle.md +1 -1
- package/docs/design/modular-architecture/README.md +4 -2
- package/docs/design/reviews/hall-v2/README.md +2 -2
- package/docs/design/vanilla-hall-ui-redesign-scope.md +4 -4
- package/docs/file-map.md +5 -5
- package/docs/handoff-template.md +1 -1
- package/docs/module-api-changelog.md +8 -0
- package/docs/modules-contract.md +11 -14
- package/docs/page-readings.json +63 -63
- package/docs/recipes/bongos-cli-release.md +1 -2
- package/docs/recipes/multi-builder-merge.md +1 -1
- package/docs/recipes/ops-gotchas.md +0 -9
- package/docs/recipes/self-host.md +1 -1
- package/docs/recipes/windows-builders.md +1 -1
- package/migrations/core_258_drop_dev_box_tables.sql +3 -0
- package/modules/copy-desk/routes/copy-desk.js +1 -1
- package/modules/discord/ship-broadcast.js +3 -3
- package/modules/economy/credits.js +2 -2
- package/modules/hall-ui/public/palette.js +143 -3
- package/modules/ideas/projection.js +1 -1
- package/modules/lifecycle/db-ship.js +4 -4
- package/modules/lifecycle/github-push.js +12 -14
- package/modules/lifecycle/publish-reconciler.js +10 -10
- package/modules/lifecycle/routes/tasks.js +8 -8
- package/modules/lifecycle/ship-card.js +1 -1
- package/modules/lifecycle/task-visuals.js +2 -2
- package/modules/memory/routes/memory.js +2 -2
- package/modules/platform-identity/routes/sso.js +3 -2
- package/modules/provisioning/capacity.js +1 -1
- package/modules/provisioning/provisioning.js +4 -3
- package/modules/provisioning/routes/provisioning.js +4 -4
- package/modules/sessions/db.js +1 -1
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/release-notes.json +28 -0
- package/scripts/gds/artifact-staleness.js +2 -2
- package/scripts/gds/backfill-task-rewards.js +5 -5
- package/scripts/gds/claude-materialize.js +2 -2
- package/scripts/gds/cli-lib.js +7 -7
- package/scripts/gds/codemod-rename-src-gds.js +1 -1
- package/scripts/gds/context-pack.js +5 -7
- package/scripts/gds/dev-box-guard.js +165 -0
- package/scripts/gds/doctor.js +3 -3
- package/scripts/gds/fitness-checks-packaging.js +4 -4
- package/scripts/gds/fitness-lib.js +10 -0
- package/scripts/gds/fitness-ratchets.js +1 -1
- package/scripts/gds/fitness.js +2 -10
- package/scripts/gds/gen-api-client.js +4 -4
- package/scripts/gds/gen-api-docs.js +1 -1
- package/scripts/gds/gen-repo-map.js +13 -14
- package/scripts/gds/gen-session-index.js +8 -8
- package/scripts/gds/leak-scan-allowlist.js +1 -1
- package/scripts/gds/plain-cards.js +1 -1
- package/scripts/gds/push-path-brief.js +10 -10
- package/scripts/gds/rename-history-check.js +1 -1
- package/scripts/gds/run-unit-tests.js +4 -0
- package/scripts/gds/session-digest-build.js +2 -2
- package/scripts/gds/ship-deploy-target.js +13 -13
- package/scripts/gds/ship-flow.js +1 -1
- package/scripts/gds/ship-land.js +6 -6
- package/scripts/gds/ship-merge.js +4 -4
- package/scripts/gds/ship-preflight-steps.js +4 -4
- package/scripts/gds/ship-regen.js +9 -12
- package/scripts/gds/ship.js +9 -9
- package/scripts/gds/skill-preflight.js +9 -8
- package/src/bongos/api-prefix.js +4 -4
- package/src/bongos/module-scope-map.js +1 -1
- package/src/bongos/platform-visibility-gate.js +1 -1
- package/src/bongos/routes/me.js +1 -1
- package/src/bongos/routes/security.js +3 -3
- package/src/bongos/routes.js +2 -2
- package/src/bongos/serve-internal.js +5 -6
- package/src/bongos-downloads.js +1 -6
- package/src/branding.js +2 -2
- package/src/build-info.js +4 -6
- package/src/instance-config.js +2 -2
- package/src/module-api.js +3 -3
- package/src/module-loader/manifest-schema.js +1 -1
- package/tests/api_alias_caller_ratchet.mjs +1 -1
- package/tests/api_alias_exceptions.mjs +1 -1
- package/tests/api_client.mjs +1 -1
- package/tests/api_path_404.mjs +1 -1
- package/tests/backfill_task_rewards.mjs +1 -1
- package/tests/{box_ship_permissions.mjs → cli_allowlist_permissions.mjs} +5 -5
- package/tests/cli_sessions.mjs +1 -1
- package/tests/context_pack.mjs +13 -13
- package/tests/copy_inventory.mjs +7 -7
- package/tests/core_258_box_session_claims_db.mjs +180 -0
- package/tests/credit_grant.mjs +2 -2
- package/tests/criterion_suggest.mjs +1 -1
- package/tests/design_tokens_sync.mjs +3 -2
- package/tests/fitness.mjs +89 -0
- package/tests/fitness_ratchets.mjs +2 -2
- package/tests/github_push_land_proof.mjs +1 -1
- package/tests/goal_advisory.mjs +3 -3
- package/tests/goal_suggest.mjs +3 -3
- package/tests/government_abuse_matrix.mjs +4 -3
- package/tests/hall_audit.mjs +1 -1
- package/tests/hall_palette.mjs +224 -11
- package/tests/helpers.mjs +1 -1
- package/tests/host_topology_skips.mjs +2 -2
- package/tests/migration_namespace.mjs +6 -6
- package/tests/module_api.mjs +2 -2
- package/tests/module_cli.mjs +5 -5
- package/tests/module_manifest.mjs +13 -13
- package/tests/module_route_rank.mjs +2 -2
- package/tests/modules_route_wiring.mjs +1 -1
- package/tests/onboarding_route_signals.mjs +1 -1
- package/tests/paste_token_session_store.mjs +1 -1
- package/tests/platform_visibility_gate.mjs +1 -1
- package/tests/project_modules_ui.mjs +17 -17
- package/tests/projects_hub_module_picker.mjs +75 -74
- package/tests/provisioning_capacity.mjs +1 -1
- package/tests/provisioning_recommendations.mjs +3 -2
- package/tests/publish_branch_route.mjs +1 -1
- package/tests/publish_manifest.mjs +1 -1
- package/tests/publish_reconciler.mjs +8 -8
- package/tests/push_path_brief.mjs +10 -9
- package/tests/regrade_eligibility.mjs +1 -1
- package/tests/rename_history_restraint.mjs +1 -1
- package/tests/repo_map.mjs +9 -9
- package/tests/seam_wiring_guard.mjs +11 -11
- package/tests/search_isolation.mjs +3 -3
- package/tests/session_records.mjs +1 -1
- package/tests/session_rename_fallback.mjs +1 -1
- package/tests/session_start_freshness.mjs +3 -3
- package/tests/session_token_hash_db.mjs +1 -1
- package/tests/ship_card.mjs +1 -1
- package/tests/ship_ci_deploy.mjs +17 -17
- package/tests/ship_premerge.mjs +1 -1
- package/tests/ship_resume.mjs +1 -1
- package/tests/skill_preflight.mjs +2 -2
- package/tests/skip_is_not_pass.mjs +1 -1
- package/tests/terms_acceptance.mjs +1 -1
- package/docs/design/reviews/hall-v2/harbor--archon.webp +0 -0
- package/docs/design/reviews/hall-v2/harbor--metic.webp +0 -0
- package/docs/design/reviews/hall-v2/harbor--xenos.webp +0 -0
- package/docs/design/reviews/hall-v2/pair--archon.webp +0 -0
- package/docs/design/reviews/hall-v2/pair--metic.webp +0 -0
- package/docs/design/reviews/hall-v2/pair--xenos.webp +0 -0
package/docs/copy-inventory.md
CHANGED
|
@@ -589,7 +589,7 @@ Identical copy within one surface. Sometimes right (a repeated button), sometime
|
|
|
589
589
|
| `9f9424a5100b` | certain | Join our Discord | `modules/hall-ui/public/hall-render.js:804` |
|
|
590
590
|
| `7ee76a958445` | certain | Join requests | `modules/hall-ui/public/goals-render.js:1411` |
|
|
591
591
|
| `b7ab5922126b` | certain | Join-requests to approve | `modules/hall-ui/public/goal-inbox.js:154` |
|
|
592
|
-
| `d305f0df6f25` | certain | Jump to | `modules/hall-ui/public/palette.js:
|
|
592
|
+
| `d305f0df6f25` | certain | Jump to | `modules/hall-ui/public/palette.js:351` |
|
|
593
593
|
| `01176c156112` | certain | Jump to a goal or a thought | `modules/hall-ui/public/goal-map.html:75` |
|
|
594
594
|
| `01176c156112` | certain | Jump to a goal or a thought | `modules/hall-ui/public/thinking.html:92` |
|
|
595
595
|
| `2bfc5a50ce88` | certain | Jump to a page or record | `modules/hall-ui/public/shell.js:485` |
|
|
@@ -696,7 +696,7 @@ Identical copy within one surface. Sometimes right (a repeated button), sometime
|
|
|
696
696
|
| `abc64639b134` | certain | No goals seeded yet. | `modules/hall-ui/public/roadmap.js:205` |
|
|
697
697
|
| `139ec3636c22` | certain | No introductions right now. One appears here when a pairing round runs. | `modules/hall-ui/public/collab.html:99` |
|
|
698
698
|
| `3b9823dd4579` | certain | No maintenance declared — nobody is on the hook for this module as the core advances. | `modules/hall-ui/public/modules.js:92` |
|
|
699
|
-
| `64a4281934d1` | certain | No match. Try a page name, or an id like | `modules/hall-ui/public/palette.js:
|
|
699
|
+
| `64a4281934d1` | certain | No match. Try a page name, or an id like | `modules/hall-ui/public/palette.js:307` |
|
|
700
700
|
| `f52552a6afcd` | certain | No notes were packed for this version. | `modules/hall-ui/public/settings-software-update.js:102` |
|
|
701
701
|
| `4f89817b92e5` | certain | No onboarding steps recorded yet. | `modules/hall-ui/public/hall-render.js:880` |
|
|
702
702
|
| `421ae031594e` | certain | No open goals in this version | `modules/hall-ui/public/task.js:589` |
|
|
@@ -1443,7 +1443,7 @@ Identical copy within one surface. Sometimes right (a repeated button), sometime
|
|
|
1443
1443
|
| `af3a8e0fe6a8` | certain | open your goals | `modules/hall-ui/public/goal-inbox.js:158` |
|
|
1444
1444
|
| `9a803563c948` | certain | open {…} | `modules/hall-ui/public/approval-queue.js:156` |
|
|
1445
1445
|
| `4f279d68175f` | certain | open, on the Security tab | `modules/hall-ui/public/watch.html:47` |
|
|
1446
|
-
| `7b85e6494596` | certain | opens a new tab | `modules/hall-ui/public/palette.js:
|
|
1446
|
+
| `7b85e6494596` | certain | opens a new tab | `modules/hall-ui/public/palette.js:315` |
|
|
1447
1447
|
| `c38db02adb61` | certain | or above | `modules/hall-ui/public/government.js:564` |
|
|
1448
1448
|
| `271de72308a4` | certain | pages tweaked | `modules/hall-ui/public/studio.html:83` |
|
|
1449
1449
|
| `884948925fcb` | certain | paste command | `modules/hall-ui/public/settings.js:914` |
|
package/docs/copy-registry.json
CHANGED
|
@@ -6727,7 +6727,7 @@
|
|
|
6727
6727
|
"surface": "builders-hall",
|
|
6728
6728
|
"text": "Jump to",
|
|
6729
6729
|
"file": "modules/hall-ui/public/palette.js",
|
|
6730
|
-
"line":
|
|
6730
|
+
"line": 351,
|
|
6731
6731
|
"origin": "js-markup",
|
|
6732
6732
|
"confidence": "certain"
|
|
6733
6733
|
},
|
|
@@ -7690,7 +7690,7 @@
|
|
|
7690
7690
|
"surface": "builders-hall",
|
|
7691
7691
|
"text": "No match. Try a page name, or an id like",
|
|
7692
7692
|
"file": "modules/hall-ui/public/palette.js",
|
|
7693
|
-
"line":
|
|
7693
|
+
"line": 307,
|
|
7694
7694
|
"origin": "js-markup",
|
|
7695
7695
|
"confidence": "certain"
|
|
7696
7696
|
},
|
|
@@ -14413,7 +14413,7 @@
|
|
|
14413
14413
|
"surface": "builders-hall",
|
|
14414
14414
|
"text": "opens a new tab",
|
|
14415
14415
|
"file": "modules/hall-ui/public/palette.js",
|
|
14416
|
-
"line":
|
|
14416
|
+
"line": 315,
|
|
14417
14417
|
"origin": "js-markup",
|
|
14418
14418
|
"confidence": "certain"
|
|
14419
14419
|
},
|
|
@@ -62,7 +62,7 @@ the apex redirects straight past it into the walled gate.
|
|
|
62
62
|
`src/platform-server.js:115-121`, conditional only on `isApexHost(req)` and the gate file existing,
|
|
63
63
|
with no session check and no query bypass.
|
|
64
64
|
|
|
65
|
-
**The live Caddyfile is not mirrored in this repo** (`infra/`
|
|
65
|
+
**The live Caddyfile is not mirrored in this repo** (`infra/` held only `box-*.sh` and has since been removed with the dev box); ADR 0152 gives
|
|
66
66
|
the intended shape as prose and marks the lock *"optional pre-launch"*, and several references to
|
|
67
67
|
`infra/Caddyfile` elsewhere in the tree are dead. Treat the host config as the source of truth.
|
|
68
68
|
|
|
@@ -28,7 +28,7 @@ Five pages carry the whole hall, and every other page inherits from one of them:
|
|
|
28
28
|
| **board** (`index.html` + `work.html`) | the home view and the work board: the densest surface in the hall |
|
|
29
29
|
| **task** (`task.html`) | one record read end to end; `idea` and `ideas` inherit |
|
|
30
30
|
| **reading** (`primer.html`) | long markdown with a table of contents; Ranks, Economy, Diagrams, Repo Atlas and Modules inherit |
|
|
31
|
-
| **goals** (`goals.html`) | the governance lists; Government, Modules, Watch,
|
|
31
|
+
| **goals** (`goals.html`) | the governance lists; Government, Modules, Watch, Gate, Sessions, People and the rest inherit |
|
|
32
32
|
| **settings** (`settings.html` + `profile.html`) | every form, switch, secret field and status line in the hall |
|
|
33
33
|
|
|
34
34
|
---
|
|
@@ -125,11 +125,11 @@ Five things were reconciled **between** the archetypes, since the builders ran i
|
|
|
125
125
|
|
|
126
126
|
**A fixture rule the round had to learn, flagged by the grader's security worker.** The settings mocks compose the
|
|
127
127
|
CLI re-issue flow, which means they have to show a token in a `<pre>`, and they were seeded with a realistic
|
|
128
|
-
64-character hex string beside the real paste command, plus
|
|
128
|
+
64-character hex string beside the real paste command, plus a hosted machine's actual `ssh <account>@<ip>` line.
|
|
129
129
|
Neither belonged in a committed artifact: the hex was invented (verified against this machine's real session files,
|
|
130
130
|
so nothing needed rotating) but a credential-shaped literal is treated as a secret regardless of intent and would
|
|
131
131
|
trip every future scanner, and the SSH host and account are real internal topology that no public API justifies.
|
|
132
|
-
Both
|
|
132
|
+
Both were made unmistakable placeholders (the SSH line has since left the mocks with the retired dev-box settings group). **The rule for any mock that composes a secret or a connection string: the
|
|
133
133
|
fixture must be self-evidently fake at a glance while keeping the real string's LENGTH and SHAPE**, because the
|
|
134
134
|
length is the composition problem being solved. "Real data, invent nothing" governs ledger figures; it does not
|
|
135
135
|
extend to credentials or infrastructure.
|
|
@@ -77,7 +77,7 @@ The "boundary rots back together" problem is universal; the cure is **architectu
|
|
|
77
77
|
- 📄 **Dependency-graph-scoped context** (`nx affected` / `turbo --filter`; [Nx AI agent skills](https://nx.dev/blog/nx-ai-agent-skills) exposes the project graph to agents).
|
|
78
78
|
- 📄 **Ticket↔component mapping is established**: Jira/Linear "Components", conventional-commit scopes, CODEOWNERS, `nx affected --files`.
|
|
79
79
|
|
|
80
|
-
🔧 **The synthesis:** `touches[]` is a file-path list (the lowest-altitude form). The industry moves the unit of affinity *up* from files to components/packages. Once modules are first-class, a task should declare **module affinity**; the agent loads only that module + the core API (small context, higher quality), parallel-safety becomes module-disjointness (cleaner than path overlap), and drift detection becomes semantic ("you said
|
|
80
|
+
🔧 **The synthesis:** `touches[]` is a file-path list (the lowest-altitude form). The industry moves the unit of affinity *up* from files to components/packages. Once modules are first-class, a task should declare **module affinity**; the agent loads only that module + the core API (small context, higher quality), parallel-safety becomes module-disjointness (cleaner than path overlap), and drift detection becomes semantic ("you said discord, you touched game"). *(Refined later: see [02](02-module-map.md)/[04](04-module-lifecycle.md) — in a fully modular world the file-path `touches[]` retires entirely in favor of the module label.)*
|
|
81
81
|
|
|
82
82
|
## 7. Thread 6 — How companies manage AI-assisted dev at scale
|
|
83
83
|
|
|
@@ -38,7 +38,7 @@ The whole product becomes **core + modules**. A module is a **vertical slice** (
|
|
|
38
38
|
graph TD
|
|
39
39
|
subgraph Modules["Modules (each a vertical slice: routes · db · ui · skills · manifest)"]
|
|
40
40
|
G[game]
|
|
41
|
-
D[
|
|
41
|
+
D[provisioning]
|
|
42
42
|
DC[discord]
|
|
43
43
|
Y["your module<br/>(no fork!)"]
|
|
44
44
|
end
|
|
@@ -94,7 +94,7 @@ graph LR
|
|
|
94
94
|
R1["long dark window — nothing ships —<br/>re-deriving the SAME core (auth, tasks, grading, ~111 migrations)"] --> R2["risky big-bang cutover ⚠"]
|
|
95
95
|
end
|
|
96
96
|
subgraph ST["Strangler migration (recommended)"]
|
|
97
|
-
S1[loader] --> S2[
|
|
97
|
+
S1[loader] --> S2[first module→module] --> S3["discord · art"] --> S4[game] --> S5["carve core + task→module"] --> S6[theming]
|
|
98
98
|
end
|
|
99
99
|
```
|
|
100
100
|
|
|
@@ -110,7 +110,7 @@ Each phase ships independently, guarded by the fitness functions; easiest/most-i
|
|
|
110
110
|
|---|---|---|
|
|
111
111
|
| 0 | Draw the doorway | define `core/module-api.js` + teach `fitness.js` the one-way rule (mostly exists) |
|
|
112
112
|
| 1 | Build the loader | discover `modules/*/module.json`, validate, compose routes behind auth, apply module migrations, start/stop pollers |
|
|
113
|
-
| 2 | Move
|
|
113
|
+
| 2 | Move the most self-contained module first | the template every other move copies; prove OTB behaves identically (the original pick, dev-box, has since been retired, ADR 0346) |
|
|
114
114
|
| 3 | Move discord, then art-pipeline | same recipe |
|
|
115
115
|
| 4 | Move game (the hard one) | Colyseus rooms + world tables + `public/`; "realtime capability" seam |
|
|
116
116
|
| 5 | Carve the core + rewire the task model | split `db.js` per-module; add `task.module`; **retire `touches[]`**; extend fitness to verify diff-in-module |
|
|
@@ -95,7 +95,6 @@ graph TD
|
|
|
95
95
|
GA[game] --> K
|
|
96
96
|
AR[art-pipeline] --> K
|
|
97
97
|
DC[discord] --> K
|
|
98
|
-
DB[dev-box] --> K
|
|
99
98
|
```
|
|
100
99
|
|
|
101
100
|
| Module | Owns |
|
|
@@ -111,6 +110,6 @@ graph TD
|
|
|
111
110
|
| autonomy/MAS | conductor dispatch · architect audits · autonomy-gate · scheduled routines |
|
|
112
111
|
| security | red-team reports · bounty (rank-gated Metic+) |
|
|
113
112
|
| hall-UI · status-UI | the two web surfaces |
|
|
114
|
-
| game · art-pipeline · discord
|
|
113
|
+
| game · art-pipeline · discord | feature modules |
|
|
115
114
|
|
|
116
115
|
> **~16 is the target ceiling, not a day-one requirement.** Start coarser; split as the coupling scan + fitness demand. Every one is a real cohesive cluster (the scan proved it), but a small team should be "as modular as the evidence supports, no finer." Merging two modules is cheap; the fitness ratchet makes splitting them safe — you're never locked into the first cut.
|
|
@@ -4,26 +4,26 @@ How a person works once the code is in modules. **Nothing you do is blocked —
|
|
|
4
4
|
|
|
5
5
|
## The one idea: two kinds of "access"
|
|
6
6
|
|
|
7
|
-
- **Platform capabilities** — claim, start, ship, file an idea, recall
|
|
8
|
-
- **Code-write scope** — which files a *single claimed task* may change. The **only** thing the structure bounds; it lives at the **worktree** level (not you, not your
|
|
7
|
+
- **Platform capabilities** — claim, start, ship, file an idea, recall. These are **kernel endpoints over HTTP, gated only by your rank.** The module structure never touches them. Available everywhere, always.
|
|
8
|
+
- **Code-write scope** — which files a *single claimed task* may change. The **only** thing the structure bounds; it lives at the **worktree** level (not you, not your checkout); escaped by seeding a new task (itself a kernel capability).
|
|
9
9
|
|
|
10
|
-
**The wall is around each task's worktree — not around you, and not around your
|
|
10
|
+
**The wall is around each task's worktree — not around you, and not around your checkout.**
|
|
11
11
|
|
|
12
|
-
## 1. What
|
|
12
|
+
## 1. What your checkout has access to
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
Your checkout is your own copy of the project repo on your own machine — a persistent environment, **not** module-scoped. Scoping happens one level down, per claim.
|
|
15
15
|
|
|
16
16
|
| Layer | Scope | Governed by |
|
|
17
17
|
|---|---|---|
|
|
18
|
-
|
|
|
18
|
+
| Your checkout (your machine) | full repo, all modules readable, whole CLI, the API, the preview | nothing — it's yours |
|
|
19
19
|
| Kernel capabilities (claim/ship/capture/…) | everything the platform can do | **your rank** (server-enforced) — never a module |
|
|
20
20
|
| A claim's worktree | write = its one module; read = that module + the kernel doorway | the task's **module label** + the ship-time diff check |
|
|
21
21
|
|
|
22
|
-
## 2. Flow: open
|
|
22
|
+
## 2. Flow: open your checkout → ship a task
|
|
23
23
|
|
|
24
24
|
```mermaid
|
|
25
25
|
graph LR
|
|
26
|
-
A["Open
|
|
26
|
+
A["Open your checkout<br/>(local)"] --> B["/builder-start<br/>lists ALL modules<br/>(kernel)"]
|
|
27
27
|
B --> C["/builder-claim N<br/>a game task<br/>(kernel)"]
|
|
28
28
|
C --> D["worktree spun:<br/>modules/game + RO kernel<br/>(module-scoped)"]
|
|
29
29
|
D --> E["agent edits game only<br/>(module-scoped)"]
|
|
@@ -31,7 +31,7 @@ graph LR
|
|
|
31
31
|
F --> G["live ✓<br/>worktree reaped"]
|
|
32
32
|
```
|
|
33
33
|
|
|
34
|
-
Five of seven steps are kernel/
|
|
34
|
+
Five of seven steps are kernel/local capabilities; only the worktree + the edits are module-scoped. The only *new* thing is a silent check inside `/builder-ship` (diff ⊆ declared module) that in-scope work never notices.
|
|
35
35
|
|
|
36
36
|
## 3. Flow: claim a task in a different module
|
|
37
37
|
|
|
@@ -39,14 +39,14 @@ You're never "in" a module — each *claim* is. A second claim just makes a seco
|
|
|
39
39
|
|
|
40
40
|
## 4. Flow: see an idea — and seed a cross-module task
|
|
41
41
|
|
|
42
|
-
Browsing ideas, filing an idea, and **seeding a task for another module** are all kernel operations — they need no access to the other module's code, so they work from anywhere. An agent in a game worktree can't *write*
|
|
42
|
+
Browsing ideas, filing an idea, and **seeding a task for another module** are all kernel operations — they need no access to the other module's code, so they work from anywhere. An agent in a game worktree can't *write* discord code, but it can always *file the task* for it (one command), then continue or hand off; a dependency link orders them if needed.
|
|
43
43
|
|
|
44
44
|
## 5. "Could this block me?" — every worry
|
|
45
45
|
|
|
46
46
|
| Worry | Why it isn't a block |
|
|
47
47
|
|---|---|
|
|
48
48
|
| Claim a task in a module I'm not "in"? | You're never "in" a module. Claiming is kernel; each claim makes its own scoped worktree. |
|
|
49
|
-
| Does my
|
|
49
|
+
| Does my checkout only have one module's code? | No — the checkout has the full repo. Only each per-claim worktree is scoped. |
|
|
50
50
|
| Agent needs another module mid-task — stuck? | No — it seeds a task for it (kernel op, needs no access to that code); a dep orders them. |
|
|
51
51
|
| Filing an idea about module X needs X access? | No — capture/inbox is kernel; file from anywhere. |
|
|
52
52
|
| Is shipping gated by my module? | No — ship is kernel; the only module check is "diff ⊆ module," which passes for normal work. |
|
|
@@ -60,7 +60,7 @@ A Claude Code session is **not** welded to one worktree. The session is a **cond
|
|
|
60
60
|
graph TD
|
|
61
61
|
S["long autonomous SESSION = <redacted> repo · full mobility · no module binding"]
|
|
62
62
|
S --> A["task A (game) → worktree A → its own PR → ship"]
|
|
63
|
-
S --> B["task B (
|
|
63
|
+
S --> B["task B (discord) → worktree B → its own PR → ship"]
|
|
64
64
|
S --> C["task C (memory) → worktree C → its own PR → ship"]
|
|
65
65
|
```
|
|
66
66
|
|
|
@@ -69,34 +69,36 @@ graph TD
|
|
|
69
69
|
|
|
70
70
|
The session has full mobility across modules; only each *task's worker* is module-isolated. This is the orchestrator-worker pattern (ADR 0024), and Bongos already assigns a per-claim worktree.
|
|
71
71
|
|
|
72
|
-
## 7. Limiting what
|
|
72
|
+
## 7. Limiting what a sandbox holds — the jailbreak blast radius
|
|
73
73
|
|
|
74
|
-
|
|
74
|
+
*This section was written for the dev box, which has since been retired ([ADR 0346](../../adr/0346-dev-boxes-are-retired.md)). The reasoning holds for any sandboxed environment a session might run in, such as a future cloud session. Today's path, a local checkout, holds the full repo by design (§1).*
|
|
75
|
+
|
|
76
|
+
The split lets a sandbox hold **far less**: only the claimed module (read/write) + the kernel's **safe contract** (signatures, read-only) + client plumbing + a scoped token. The kernel **implementation** (auth, rank, ship, grade) never leaves the server.
|
|
75
77
|
|
|
76
78
|
```mermaid
|
|
77
79
|
graph LR
|
|
78
|
-
subgraph
|
|
80
|
+
subgraph Sbx["SANDBOX · one claim (= jailbreak blast radius)"]
|
|
79
81
|
M["modules/<key>/ — read/write"]
|
|
80
82
|
KC["kernel CONTRACT — signatures + docs only (RO)"]
|
|
81
83
|
CLI["CLI plumbing (cli-lib)"]
|
|
82
84
|
TOK["scoped, claim-scoped token (not full-repo)"]
|
|
83
85
|
end
|
|
84
86
|
subgraph Server["SERVER · the trusted side"]
|
|
85
|
-
KI["KERNEL IMPL — auth · rank · ship · grade<br/>(never
|
|
87
|
+
KI["KERNEL IMPL — auth · rank · ship · grade<br/>(never in the sandbox)"]
|
|
86
88
|
OM[every other module's source]
|
|
87
89
|
FR[full repo + history]
|
|
88
90
|
EN["ENFORCES the rank ladder, live per request (ADR 0016)"]
|
|
89
91
|
end
|
|
90
|
-
|
|
92
|
+
Sbx -->|"privileged ops = HTTP call<br/>(sandbox can't push main)"| Server
|
|
91
93
|
```
|
|
92
94
|
|
|
93
|
-
**The trap to avoid:** reducing what's *on disk* is not reducing *access* — a
|
|
95
|
+
**The trap to avoid:** reducing what's *on disk* is not reducing *access* — a sandbox holding a full-repo credential re-fetches. The real lever is **scoping the sandbox's credential + fetch to the claimed module** (and module access can be **rank-gated** too, since the server mediates every fetch). The primary boundary always remains the **server-enforced rank ladder**; on-disk minimization is defense-in-depth on top.
|
|
94
96
|
|
|
95
97
|
| Approach | Efficiency | Real confidentiality boundary? |
|
|
96
98
|
|---|---|---|
|
|
97
99
|
| Sparse-checkout only | ✓ smaller tree | ✗ — `.git` still has everything |
|
|
98
|
-
| Partial clone + sparse | ✓✓ | ~ —
|
|
99
|
-
| **Server-mediated, claim-scoped fetch** | ✓✓ | **✓ —
|
|
100
|
+
| Partial clone + sparse | ✓✓ | ~ — sandbox can lazily re-fetch with its token |
|
|
101
|
+
| **Server-mediated, claim-scoped fetch** | ✓✓ | **✓ — sandbox never holds a full-repo remote or kernel source** |
|
|
100
102
|
| Per-module repos | ✓✓ | ✓✓ strongest — but contradicts single-repo (ADR 0080 rejected package-modules for v1) |
|
|
101
103
|
|
|
102
104
|
## 8. Two boundaries that compose (no new friction)
|
|
@@ -8,7 +8,7 @@ The one-way rule forbids a module importing another. But the **lifecycle** (whic
|
|
|
8
8
|
|
|
9
9
|
- **Ports** (a *required, single-provider* capability): the economy module registers a `reward` provider; at ship, the lifecycle asks the kernel to resolve `reward` and calls it. **Economy owns the formula *and* the ledger**; the lifecycle only supplies the session and delivers the result.
|
|
10
10
|
- **Events** (an *optional* reaction): the lifecycle emits `task.shipped`; the discord module reacts if it cares.
|
|
11
|
-
- **Contributions** (an *accumulating extension point*): zero-or-more modules each add a piece to a named point and the kernel hands the whole set to a core consumer — how a module adds its own slice to a shared core surface without core hardcoding it. The `profile.fields` point lets
|
|
11
|
+
- **Contributions** (an *accumulating extension point*): zero-or-more modules each add a piece to a named point and the kernel hands the whole set to a core consumer — how a module adds its own slice to a shared core surface without core hardcoding it. The `profile.fields` point lets discord/art add their slice to the `GET /me` payload (and its browser twin, `window.OTB.contributeSettingsPanel`, adds a Settings panel) instead of those being baked into `routes/me.js` + `settings.js` (BV1.R42 / task 1411 — the strangler prerequisite for those moves; game has no such coupling). Add-only: a contribution may introduce keys, never overwrite a core one.
|
|
12
12
|
|
|
13
13
|
```mermaid
|
|
14
14
|
graph LR
|
|
@@ -4,17 +4,19 @@ Five reports from the **2026-06-21 modular-architecture design session**, filed
|
|
|
4
4
|
|
|
5
5
|
> **Status: pre-red-team draft.** These are research/design reports, not a decision record. A formal numbered ADR follows once they've been red-teamed. Filed under `docs/design/` (not `docs/adr/`) on purpose — the ADR numbering is in flux (0079→0081 collisions), so the number is assigned later on an up-to-date worktree.
|
|
6
6
|
|
|
7
|
+
> **Since filing:** the dev box module that these reports use as their first example was retired on 2026-09-28 ([ADR 0346](../../adr/0346-dev-boxes-are-retired.md)). Where a report still names it (the code-size table, the import-graph findings, the migration plan), that is the tree as it stood at filing.
|
|
8
|
+
|
|
7
9
|
| # | Doc | What it answers |
|
|
8
10
|
|---|-----|-----------------|
|
|
9
11
|
| 00 | [Research report](00-research-report.md) | Industry best practice on packaging, plugins, theming, and AI-agent scoping (cited) |
|
|
10
12
|
| 01 | [Architecture](01-architecture.md) | The concrete core+modules design; why not a rewrite; the migration path |
|
|
11
13
|
| 02 | [Module map](02-module-map.md) | Where the ~95k LOC live; how finely to cut the core; the decided roster |
|
|
12
|
-
| 03 | [Builder flows](03-builder-flows.md) | What
|
|
14
|
+
| 03 | [Builder flows](03-builder-flows.md) | What a builder's checkout can access; why the structure never blocks a builder |
|
|
13
15
|
| 04 | [Module lifecycle & maintenance](04-module-lifecycle.md) | How modules interact (seams) and stay healthy as code grows |
|
|
14
16
|
|
|
15
17
|
## The decided model (one paragraph)
|
|
16
18
|
|
|
17
|
-
A small **kernel** (auth, rank, db-pool, the loader, the seam registry, trust primitives, config/identity, analytics, the trusted publish path) plus **~16 modules** (lifecycle, economy, grading, memory, onboarding, ideas, builder-settings, sessions/BFG, autonomy/MAS, security, hall-UI, status-UI + game/art-pipeline/discord
|
|
19
|
+
A small **kernel** (auth, rank, db-pool, the loader, the seam registry, trust primitives, config/identity, analytics, the trusted publish path) plus **~16 modules** (lifecycle, economy, grading, memory, onboarding, ideas, builder-settings, sessions/BFG, autonomy/MAS, security, hall-UI, status-UI + game/art-pipeline/discord). Modules **never import each other** — they interact through **kernel-mediated seams** (ports + events). Boundaries are held by **CI fitness functions** so the structure can't rot as it grows. It stays **single-package, single-process, no-bundler** — modularity is a separate axis from packaging/runtime/build. It is built via an incremental **strangler migration**, not a ground-up rewrite.
|
|
18
20
|
|
|
19
21
|
## How the boundaries were drawn
|
|
20
22
|
|
|
@@ -19,6 +19,8 @@ The 26 pages that carry a `*.states.json` (`modules/hall-ui/public/`), each rend
|
|
|
19
19
|
|
|
20
20
|
Sheets: `<page>--<rank>.webp`, one per page-lane — dark rows above light, 1440 → 390 → 320 left to right, one tile per state. (The atlas sheets are from the second run, with `atlas.json` generated.)
|
|
21
21
|
|
|
22
|
+
The `harbor` and `pair` sheets were deleted when those two pages were removed with the dev box ([ADR 0346](../../../adr/0346-dev-boxes-are-retired.md)). The counts and lists below are as walked on 2026-09-02, with both pages in them.
|
|
23
|
+
|
|
22
24
|
## Page × rank
|
|
23
25
|
|
|
24
26
|
| page | xenos | metic | archon |
|
|
@@ -31,13 +33,11 @@ Sheets: `<page>--<rank>.webp`, one per page-lane — dark rows above light, 1440
|
|
|
31
33
|
| gate | 12 · refused (metic+) | 12 · clean | 18 · clean |
|
|
32
34
|
| goals | 20 · clean | 20 · clean | 30 · clean |
|
|
33
35
|
| government | 20 · refused (permissions view is archon) | 20 · refused (same) | 30 · clean |
|
|
34
|
-
| harbor | 12 · refused (metic+) | 12 · clean | 18 · clean |
|
|
35
36
|
| idea | 8 · clean | 8 · clean | 12 · clean |
|
|
36
37
|
| ideas | 8 · clean | 8 · clean | 12 · clean |
|
|
37
38
|
| index | 16 · clean | 16 · clean | 24 · clean |
|
|
38
39
|
| modules | 20 · clean | 20 · clean | 30 · clean |
|
|
39
40
|
| not-ready | 8 · clean | 8 · clean | 12 · clean |
|
|
40
|
-
| pair | 8 · clean | 8 · clean | 12 · clean |
|
|
41
41
|
| people | 12 · clean | 12 · clean | 18 · clean |
|
|
42
42
|
| primer | 12 · harness (sign-in redirect) | 12 · harness | 18 · harness |
|
|
43
43
|
| profile | 20 · **defect 1003497** (signed-out links) | 20 · **defect 1003497** | 30 · **defect 1003497** |
|
|
@@ -38,7 +38,7 @@ The current hall is **one long single-column page** (`index.html`, `<main>` capp
|
|
|
38
38
|
|
|
39
39
|
The eleven core widgets (from `hall-widgets.js`, by mount order): **Welcome, Path (onboarding), Standing (profile), Honours (8 laurels), Karma, Acclaim, Works (ships), Marks (grades), Curve (analytics), Bounty (red-team rewards), Roll (leaderboard)** — plus a **Goals** widget (`goals.js`).
|
|
40
40
|
|
|
41
|
-
Separate full pages behind header links: **Work Board, Primer, Diagrams, Repo Atlas, Ranks, Settings
|
|
41
|
+
Separate full pages behind header links: **Work Board, Primer, Diagrams, Repo Atlas, Ranks, Settings**, plus Archon-only **Watch, Gate**.
|
|
42
42
|
|
|
43
43
|
The data and the registry seam stay. The redesign changes the **frame** the widgets live in.
|
|
44
44
|
|
|
@@ -99,7 +99,7 @@ Seven primary destinations plus a gated Admin group. Today's eleven scrolls coll
|
|
|
99
99
|
| **Leaderboard** | Roll of the Foremost | Table view | signed-in |
|
|
100
100
|
| **Docs** | Primer, Diagrams/maps, Repo Atlas | Doc pages + TOC | signed-in |
|
|
101
101
|
| **Settings** | Settings (all panels) | Sub-nav + panels | signed-in |
|
|
102
|
-
| **Admin ▾** | Watch,
|
|
102
|
+
| **Admin ▾** | Watch, Gate | Grouped, collapsed | **Archon only** |
|
|
103
103
|
|
|
104
104
|
> Rank/permission gating is **unchanged** — Xenos still don't see Work until graduation; Admin only unhides at `rank=archon`. The redesign moves *where* those links render (into the sidebar), not *whether* they gate.
|
|
105
105
|
|
|
@@ -152,7 +152,7 @@ Kept close to today's three-section structure (in-progress, claimable, history),
|
|
|
152
152
|
|
|
153
153
|
## 7. Surface · Settings — grouped panels
|
|
154
154
|
|
|
155
|
-
Settings has the most sections today (~
|
|
155
|
+
Settings has the most sections today (~13: connections, craft, display name, wandering, render, art key, CLI, voices, sounds, event sounds…). It gets its own left sub-nav so each group is a focused panel.
|
|
156
156
|
|
|
157
157
|
| Component | Type | Placement | Size |
|
|
158
158
|
|---|---|---|---|
|
|
@@ -251,7 +251,7 @@ Not layout, but it rides along. Most of this already flows through the brand pac
|
|
|
251
251
|
- Neutral default voice
|
|
252
252
|
|
|
253
253
|
**Deferred**
|
|
254
|
-
- Archon pages — Watch,
|
|
254
|
+
- Archon pages — Watch, Gate (inherit shell only; internal layout unchanged)
|
|
255
255
|
- Rank-name copy decision
|
|
256
256
|
- Public apex landing page (separate surface)
|
|
257
257
|
|
package/docs/file-map.md
CHANGED
|
@@ -94,7 +94,7 @@
|
|
|
94
94
|
│ ├── <redacted>.sql ← /builder-exit: deactivated builders drop to 'xenos'
|
|
95
95
|
│ ├── <redacted>.sql ← builders.preferred_disciplines column (enum renamed by mig 086)
|
|
96
96
|
│ ├── 029_rank_three_live.sql ← #360/ADR 0018: rank default thetes→xenos + tasks.xenos_claimable (three-rank model live)
|
|
97
|
-
│ ├── 067_builder_boxes.sql ← #598/ADR 0031:
|
|
97
|
+
│ ├── 067_builder_boxes.sql ← #598/ADR 0031: the per-builder dev box lifecycle tables; dropped by core_258 (ADR 0346)
|
|
98
98
|
│ └── <redacted>.sql ← task 615: rename disciplines engineering→engineer, creative→artist|ideator; swaps both CHECK constraints + backfills tasks.discipline & builders.preferred_disciplines
|
|
99
99
|
├── modules/ ← self-contained optional feature modules (ADR 0083 / docs/modules-contract.md). Each `modules/<key>/` is a full vertical slice — routes, migrations, skills, seam registrations — reached only through src/module-api.js. The loader discovers them at boot; no core file changes to add one.
|
|
100
100
|
│ ├── game/ ← the playable Example world — Phaser client, Colyseus rooms (WorldRoom/QueueRoom), world/terrain model, game DB tables, static assets. Moved BV1.R49 (task 1418). CLAUDE.md, module.json, routes/game.js, rooms/, world/, public/, migrations/.
|
|
@@ -149,7 +149,7 @@
|
|
|
149
149
|
│ ├── gen-file-map.js ← ADR 0066 ([#1276](https://example.com/builders#/task/1276)): generates the `.claude/skills/` + `.claude/scheduled-tasks/` sections of docs/file-map.md from disk; per-entry notes come from docs/file-map.notes.json; `--check` fails on drift OR a skill/routine with no note (CI gate via fitness.js); regenerated on deploy by ship.js regenerateFileMap()
|
|
150
150
|
│ ├── spike-task-map.js ← (task 1003282, goal 1000072) the task-network-map spike harness: builds a ~1,357-task graph across a swept dependency density, lays it out for real (<redacted> + Barnes-Hut), counts what decides readability (isolated nodes, components, distinguishable marks / overplot, crossings, ink budget, payload) and renders PNGs with a hand-rolled encoder. Zero deps, no DB. `--from <tasks.json>` measures the REAL corpus instead of the model. Verdict: docs/research/task-network-map-readability.md
|
|
151
151
|
│ ├── fitness.js ← Path C (ADR 0062 §9, [#1225](https://example.com/builders#/task/1225)): architecture fitness functions — core↔host import boundary (zero grandfathered exceptions as of R52/#1191), CLAUDE.md budget + nested-doc presence (ADR 0061), no route bypasses rank checks (reuses route-rank-check), repo-map freshness. Enforced in CI via tests/fitness.mjs (the `unit` gate). `node scripts/gds/fitness.js`
|
|
152
|
-
│ ├── ship.js ← resolve claim as shipped, award credits (`/builder-ship`); also uploads a secret-scrubbed session digest to the corpus (6D.1, ADR 0027);
|
|
152
|
+
│ ├── ship.js ← resolve claim as shipped, award credits (`/builder-ship`); also uploads a secret-scrubbed session digest to the corpus (6D.1, ADR 0027); runs the sandbox-first review gate before resolving when the checkout has a local game preview (#927, ADR 0046)
|
|
153
153
|
│ ├── ship-visual.js ← the OPTIONAL `--visual <image> [--visual-alt "…"]` leg of a ship (task 1003109): screens the file BEFORE the claim resolves (bad input costs no claim), uploads it AFTER (a failed picture never fails a ship)
|
|
154
154
|
│ ├── package-core.js ← package the core as a versioned, installable artifact + pin manifest (`bongos package-core`; R84, ADR 0100 §1, [#1688](https://example.com/builders#/task/1688)): isPublishable() selection + mirror redaction + fail-closed no-leak gate → dist/bongos-core-<version>.{tgz,manifest.json}; version = src/module-api CORE_VERSION. Recipe: docs/recipes/packaging-the-core.md
|
|
155
155
|
│ ├── release-notes.js ← what each core release brought in (task 1004218): generated at pack time from the ref's HISTORY into the package's release-notes.json (exact per-release ranges, 1 MiB bound; package-core redacts its prose like a doc), read back by the upgrade runner for a from→to range; home of the one merge-summary parser
|
|
@@ -208,7 +208,7 @@
|
|
|
208
208
|
│ │ ├── 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.
|
|
209
209
|
│ │ └── semver.js ← minimal semver `satisfies(version, range)` used by the loader (no npm dep).
|
|
210
210
|
│ ├── 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`
|
|
211
|
-
│ ├── preview-server.js ← GAME-ONLY entrypoint for the
|
|
211
|
+
│ ├── preview-server.js ← GAME-ONLY entrypoint for the local preview that `/builder-stage` runs (ADR 0052): Phaser/Colyseus + tiles, NO /api/bongos
|
|
212
212
|
│ ├── seats.js ← in-process seat counter + EventEmitter
|
|
213
213
|
│ ├── rooms/
|
|
214
214
|
│ │ ├── WorldRoom.js ← singleton room: move + interact + identity
|
|
@@ -221,8 +221,8 @@
|
|
|
221
221
|
│ │ ├── routes.js ← thin mounter — imports each routes/* sub-router + every enabled module's routes and stitches them behind kernel-composed auth
|
|
222
222
|
│ │ ├── api-prefix.js ← API_PREFIX ('/api/bongos') + LEGACY_API_PREFIXES ('/api/gds' permanent alias) + API_VERSION
|
|
223
223
|
│ │ ├── api-path-404.js ← recognize Bongos-API-shaped paths that missed the mount → JSON 404 + corrective hint (server.js catch-all; V4.R14, [#952](https://example.com/builders#/task/952))
|
|
224
|
-
│ │ ├── serve-internal.js ← (ADR 0062 R51, task 1190) the SHARED internal web surface: mountInternalSurfaces(app) wires /healthz + /version + /api/bongos + the
|
|
225
|
-
│ │ ├── routes/ ← one file per KERNEL feature so parallel branches stop colliding on routes.js — the domain routes (tasks/claims/versions/cost/leaderboard/memory/learnings/
|
|
224
|
+
│ │ ├── serve-internal.js ← (ADR 0062 R51, task 1190) the SHARED internal web surface: mountInternalSurfaces(app) wires /healthz + /version + /api/bongos + the `bongos` CLI downloads + the status & builders hosts; called by BOTH server.js (game boot) and platform-server.js (Bongos-only) so the two never drift. Also injects clientBranding() as window.__BRANDING__ into the served hall/status HTML
|
|
225
|
+
│ │ ├── routes/ ← one file per KERNEL feature so parallel branches stop colliding on routes.js — the domain routes (tasks/claims/versions/cost/leaderboard/memory/learnings/inbox/blockers/search/gate-approvals/discord/…) graduated with their domains into `modules/<key>/routes/`, reached only through the loader
|
|
226
226
|
│ │ │ ├── _helpers.js ← validateOrRespond, parseId, LIMITS, asyncHandler, publicOrigin, corsPublicGet, parseCookie
|
|
227
227
|
│ │ │ ├── healthz.js, auth.js, me.js, builders.js, instance.js
|
|
228
228
|
│ │ │ ├── my-sessions.js ← GET /me/sessions + POST /me/sessions/revoke{,-all} — the OWN-scoped session self-service (task 1003341, ADR 0206): see and kill your own sessions without an Archon. Kept apart from auth.js's admin-gated cross-builder pair so the no-caller-named-owner rule holds over a WHOLE file (tests/own_session_revoke.mjs)
|
package/docs/handoff-template.md
CHANGED
|
@@ -65,7 +65,7 @@ If even one of these is false, the claim is `[verified-smoke]` or `[implemented-
|
|
|
65
65
|
|
|
66
66
|
### Diagram backstop (task [#357](https://example.com/builders#/task/357); conceptual diagrams auto-generated [#436](https://example.com/builders#/task/436))
|
|
67
67
|
|
|
68
|
-
If your change touched anything the onboarding diagrams describe — the **rank enum or which ranks are wired** (`requireRank`, `builders.rank` default, exit/assign paths), the **task-status set**, the **versions** (id/track/status), or the **complete-architecture** (the ADR 0024 memory chain + the
|
|
68
|
+
If your change touched anything the onboarding diagrams describe — the **rank enum or which ranks are wired** (`requireRank`, `builders.rank` default, exit/assign paths), the **task-status set**, the **versions** (id/track/status), or the **complete-architecture** (the ADR 0024 memory chain + the machine → production ship flow) **/ example-karma** models (which now flip per the **shipped** status of their backing tasks) — then before shipping:
|
|
69
69
|
|
|
70
70
|
- **All five diagrams are auto-generated** by `scripts/gds/gen-diagrams.js` — run it (`node scripts/gds/gen-diagrams.js`) and confirm the result looks right; **do not hand-edit any `.mmd`**. The mechanical three (`01-task-lifecycle`, `02-rank-ladder`, `05-versioning`) regenerate from migrations + the public version API. The conceptual two (`03-example-karma`, `04-architecture`) regenerate from the **authenticated** `/tasks/:id` status of their backing tasks (and 03's seeded-achievement count); if no session is present the generator skips them cleanly. Rendering produces both `.svg` (the pannable viewer asset) and `.png` (fallback).
|
|
71
71
|
- To change a diagram's **layout or wording**, edit the matching template function in `gen-diagrams.js` — not the `.mmd`. `assertions.json` is rebuilt by the generator in lockstep, so you don't hand-maintain it.
|
|
@@ -2635,5 +2635,13 @@ is load-bearing: the script throws rather than guess if it is missing, and
|
|
|
2635
2635
|
landed since 1.19.1072 with no explicit bump. run 36485068639. (task 1002620)
|
|
2636
2636
|
1.19.1074 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
2637
2637
|
landed since 1.19.1073 with no explicit bump. run 36510198162. (task 1002620)
|
|
2638
|
+
1.19.1075 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
2639
|
+
landed since 1.19.1074 with no explicit bump. run 36512197709. (task 1002620)
|
|
2640
|
+
(note, no bump) — auth.allowBoxScope is now a deprecated no-op (task 1003894).
|
|
2641
|
+
The narrowing session scope it opted a route into, and the three box.*
|
|
2642
|
+
permissions, were removed with the dev box (ADR 0346). The export is kept so
|
|
2643
|
+
the doorway loses nothing inside 1.x; it goes at the next MAJOR.
|
|
2644
|
+
1.19.1076 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
2645
|
+
landed since 1.19.1075 with no explicit bump. run 36523068301. (task 1002620)
|
|
2638
2646
|
---------------------------------------------------------------------------
|
|
2639
2647
|
```
|
package/docs/modules-contract.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# The module plugin-API contract (`src/module-api.js` + `modules/*/`)
|
|
2
2
|
|
|
3
3
|
> **Decision record:** [ADR 0083](adr/0083-modular-architecture-strangler-build-plan.md) — the build plan.
|
|
4
|
-
> **Live state:** the shipped modules under `modules/` are the
|
|
4
|
+
> **Live state:** the shipped modules under `modules/` are the three feature modules `game`, `discord`, `art-pipeline` (+ `character-anim`, declaration-only; ADR 0088) and the carved core-domain modules `memory` (R72), `grading` (R73), `economy` (R77), `ideas` (R78), `security` (R79), `builder-settings` (R80), `onboarding` (R81), and `sessions` (R82) — see [ADR 0093](adr/0093-tranche-2-core-carve-sequence.md) for the remaining carve sequence.
|
|
5
5
|
> **Author a new module:** jump to [the module-author recipe](#module-author-recipe).
|
|
6
6
|
|
|
7
7
|
The module system turns optional features into self-contained directories. Adding a feature is "drop `modules/<key>/`"; the loader discovers, validates, and mounts it — no core file changes. The **one-way rule** is the load-bearing invariant:
|
|
@@ -19,7 +19,7 @@ Two fitness checks enforce it on every build — a violation is a red CI gate, n
|
|
|
19
19
|
## The cut: core vs modules
|
|
20
20
|
|
|
21
21
|
- **Core** is the trust kernel + the lifecycle state machine + the domains not yet carved: auth/identity/audit/rank (the kernel, [ADR 0091](adr/0091-bounding-the-kernel-and-db-carve.md) §1), the lifecycle (tasks, claims, versions, done-when, ship — never split), and the still-core domains (autonomy/MAS, the two web UIs) plus always-on infra (analytics, audit-log, gate-approvals, healthz, public). The remaining tranche-2 domains carve out per [ADR 0093](adr/0093-tranche-2-core-carve-sequence.md) §1; the lifecycle stays core. (Sessions/BFG — the `session_records` corpus + data plane + the BFG scorer + session-pulse — carved to `modules/sessions/` at R82; like `memory` it registers no port and core never calls back in. The per-claim `session_logs` ship LOG + `builder_sessions` auth tokens stay core.)
|
|
22
|
-
- **Modules** are optional features an instance turns on via `config/modules.json` or env (the feature modules `
|
|
22
|
+
- **Modules** are optional features an instance turns on via `config/modules.json` or env (the feature modules `game`, `discord`, `art-pipeline`, `character-anim`), plus the **core-domain modules** that are `default: true` (always on unless disabled): `memory` (R72), `grading` (R73), `economy` — credits/cost/streaks/achievements/leaderboard (R77), `ideas` — inbox/capture/triage/blockers (R78), `security` — red-team reports + bounty (R79), `builder-settings` — wandering/skill/sound/render prefs + builder-needs (R80), `onboarding` — admission/onboarding-state/newcomer-restock (R81), and `sessions` — session_records corpus + BFG + session-pulse (R82). Each is a self-contained directory under `modules/<key>/`.
|
|
23
23
|
|
|
24
24
|
---
|
|
25
25
|
|
|
@@ -34,7 +34,7 @@ The **only** core file a module may `require`. It re-exports the kernel capabili
|
|
|
34
34
|
| `allowBoxScope` | **Deprecated no-op** (task 1003894): the narrowing session scope it opted a route into was retired, and a session of an undeclared source is now denied on every route regardless. Kept so the doorway loses no export inside 1.x; drop at the next MAJOR. |
|
|
35
35
|
| `pool` | The shared Postgres pool. A module owns its `<key>_*` tables via its migrations. |
|
|
36
36
|
| `instanceDbName` | The resolved DB name (from branding). |
|
|
37
|
-
| `db` | Kernel-managed DB helpers (`getBuilderById`, `
|
|
37
|
+
| `db` | Kernel-managed DB helpers (`getBuilderById`, `getBuilderGeminiKeyRow`, `setBuilderGeminiKey`, `clearBuilderGeminiKey`, `insertAuditLog`, `createTask`). Grow this additive-only. |
|
|
38
38
|
| `branding` | The branding contract resolver — the resolved instance strings. |
|
|
39
39
|
| `instanceConfig` | Module enablement config + env override resolution. |
|
|
40
40
|
| `seams` | The seam registry (`registerProvider`, `hasProvider`, `resolve`, `resolveOptional`, `emit`, `on`) — how modules cooperate without importing each other. |
|
|
@@ -76,12 +76,12 @@ Every module must have a `module.json` at its root (`modules/<key>/module.json`)
|
|
|
76
76
|
|
|
77
77
|
```jsonc
|
|
78
78
|
{
|
|
79
|
-
"key": "
|
|
80
|
-
"title": "
|
|
79
|
+
"key": "discord", // REQUIRED. ^[a-z][a-z0-9-]*$ — must match the dir name.
|
|
80
|
+
"title": "Discord", // REQUIRED. Human label.
|
|
81
81
|
"description": "…", // REQUIRED. One sentence.
|
|
82
82
|
"version": "1.0.0", // REQUIRED. The module's OWN exact version "X.Y.Z" (not a range) —
|
|
83
83
|
// what update, rollout channels and re-assessment name (task 1003781).
|
|
84
|
-
"coreVersion": "^1.
|
|
84
|
+
"coreVersion": "^1.4.0", // REQUIRED. semver range of CORE_VERSION this module supports.
|
|
85
85
|
"default": false, // OPTIONAL (default false). Fail-safe when no config names it.
|
|
86
86
|
"author": "…", // OPTIONAL. Attribution (ADR 0107 §2) — portable, not a cross-Bongos FK.
|
|
87
87
|
"origin": "…", // OPTIONAL. Origin instance/project this module was built in.
|
|
@@ -95,12 +95,12 @@ Every module must have a `module.json` at its root (`modules/<key>/module.json`)
|
|
|
95
95
|
"note": "…" // OPTIONAL. The path out, in one sentence.
|
|
96
96
|
},
|
|
97
97
|
"contributes": { // REQUIRED object (may be empty {}).
|
|
98
|
-
"routes": ["
|
|
98
|
+
"routes": ["discord"], // route-factory files in routes/ (one export = () => Router())
|
|
99
99
|
"rooms": ["WorldRoom"], // Colyseus room classes (game module only)
|
|
100
|
-
"pollers": ["
|
|
100
|
+
"pollers": ["discord-bot"], // background pollers (start/stop lifecycle)
|
|
101
101
|
"disciplines": ["artist"], // builder disciplines this module adds
|
|
102
102
|
"skills": ["otb-tile-generate"], // slash-command skills it ships
|
|
103
|
-
"uiSections": ["
|
|
103
|
+
"uiSections": ["task-where"], // hall/status UI sections gated by window.__MODULES__. Ship public/hall-widget.js
|
|
104
104
|
// and it is injected into the hall index; ship public/task-widget.js and it
|
|
105
105
|
// is injected into a task's page before task.js, to fill #task-contrib on
|
|
106
106
|
// `otb:task-shown` (task 1004301). The page itself names no module.
|
|
@@ -109,7 +109,7 @@ Every module must have a `module.json` at its root (`modules/<key>/module.json`)
|
|
|
109
109
|
// apex root (ADR 0218). One or the other, never both.
|
|
110
110
|
"migrations": true // true → modules/<key>/migrations/*.sql applied if enabled
|
|
111
111
|
},
|
|
112
|
-
"provides": ["
|
|
112
|
+
"provides": ["discord.isLinked"], // OPTIONAL. Seam PORTS this module registers a provider for.
|
|
113
113
|
"consumes": [], // OPTIONAL. Seam ports this module resolves (required caps).
|
|
114
114
|
"prerequisites": { "modules": [] }, // OPTIONAL. Other modules that must be enabled first.
|
|
115
115
|
"spend": { "requiresPayer": true }, // OPTIONAL. This module spends MONEY for whoever calls it.
|
|
@@ -196,7 +196,7 @@ The loader is safe-by-construction: with no `modules/` dir it returns empty and
|
|
|
196
196
|
env override → config/modules.json → config/modules.neutral.json → manifest.default (false)
|
|
197
197
|
```
|
|
198
198
|
|
|
199
|
-
Env override key: `<envPrefix>_MODULE_<NAME>` (`NAME` = upper-snake of the key; `
|
|
199
|
+
Env override key: `<envPrefix>_MODULE_<NAME>` (`NAME` = upper-snake of the key; `npm-release` → `NPM_RELEASE`). Example: `OTB_MODULE_DISCORD=0`.
|
|
200
200
|
|
|
201
201
|
A fresh instance with **no** config resolves to **vanilla**: every module off (fail-to-vanilla).
|
|
202
202
|
|
|
@@ -218,7 +218,6 @@ A module calls `api.seams.emit(eventName, payload)` to broadcast. Any module tha
|
|
|
218
218
|
|
|
219
219
|
| Port / Event | Provider | Consumer(s) | Contract |
|
|
220
220
|
|---|---|---|---|
|
|
221
|
-
| Port: `box.hasEverConnected` | `dev-box` | core `routes/me.js`, `routes/builders.js` | `(builderId) → Promise<bool>` — whether the builder's box has ever connected. Core reads via `resolveOptional(…, async () => false)` so onboarding degrades cleanly on a box-less instance. |
|
|
222
221
|
| Port: `game.staticRoot` | `game` | `server.js` static-serve | `() → string` — absolute path to the game's static root. |
|
|
223
222
|
| Port: `game.registerRooms` | `game` | `server.js` Colyseus setup | `(matchMaker) → void` — registers WorldRoom + QueueRoom. |
|
|
224
223
|
| Port: `game.precreateWorldRoom` | `game` | `server.js` pre-create step | `(matchMaker) → Promise<void>` — pre-creates the singleton room. |
|
|
@@ -230,7 +229,6 @@ A module calls `api.seams.emit(eventName, payload)` to broadcast. Any module tha
|
|
|
230
229
|
| Port: `security` | `security` (R79) | core `routes/public.js` (`/public/bounty-table`) | `{ bountyTableDetailed(), bountyTable() }` — the env-aware red-team bounty payout schedule. Core reads via `resolveOptional('security').bountyTableDetailed()` instead of importing the module (security is default-on; only <redacted> moved — [ADR 0093](adr/0093-tranche-2-core-carve-sequence.md) §1, [02-module-map §5](design/modular-architecture/02-module-map.md)). |
|
|
231
230
|
| Port: `builder-settings` | `builder-settings` (R80) | core `routes/me.js` (`GET /me`) + `cascade-dispatch.js` | `{ getBuilderBehaviorPrefs, describeWandering, describeRender, computeNeeds, skillCeiling }` — the per-builder prefs read surface. The `GET /me` aggregator resolves it for its wandering/render/needs slices; the dormant cascade router for the skill ceiling. Default-on; degrades gracefully when off ([ADR 0093](adr/0093-tranche-2-core-carve-sequence.md) §1, [02-module-map §2](design/modular-architecture/02-module-map.md)). |
|
|
232
231
|
| Port: `onboarding` | `onboarding` (R81) | the lifecycle (`db.js` claim/ship — transaction-participant `markStage`) + `auth.js` + `routes/me.js`/`builders.js`/`tasks.js`/`claims.js` | `{ getState, shapeForApi, safeMarkStage, markStage, broadcastGraduation, restockForClaim, restockAll, SOURCE_TAG }` — the onboarding state-machine + newcomer-restock surface. The FIRST core→module port the lifecycle ticks inside its own txn (alongside `reward`). Default-on; degrades to best-effort no-ops when off ([ADR 0093](adr/0093-tranche-2-core-carve-sequence.md) §1). |
|
|
233
|
-
| Event: `builder.box-reconcile-needed` | core `db.js` (on rank change / deactivate / auto-graduation) | `dev-box` | `{ builderId, rank, status, actor }` — flags the box for reconciliation. |
|
|
234
232
|
| Event: `builder.secrets-scrub-needed` | core `db.js` (`deactivateBuilder`) | `art-pipeline` (when installed) | `{ builderId, actor }` — task 1003338 / [ADR 0332](adr/0332-offboarding-secret-scrub-semantics.md): best-effort teardown port for a MODULE-owned builder-keyed secret (today: the Gemini BYOK key, `gemini_key_enc`/`last4`/`set_at`). Core does not write those columns directly (ADR 0102) — the module listens and clears its own store. `github_oauth_tokens` (core-owned) is deleted synchronously inside `deactivateBuilder`'s transaction instead, no event needed. |
|
|
235
233
|
|
|
236
234
|
---
|
|
@@ -264,7 +262,6 @@ Rules (enforced by the `BV1.R45` fitness check):
|
|
|
264
262
|
|
|
265
263
|
| Module | `contributes` | Seam ports | `coreVersion` |
|
|
266
264
|
|---|---|---|---|
|
|
267
|
-
| **`dev-box`** | routes: `box`; pollers: `box-lifecycle`; uiSections: `boxes` | provides `box.hasEverConnected`; listens `builder.box-reconcile-needed` | `^1.2.0` |
|
|
268
265
|
| **`game`** | routes: `game`; rooms: `WorldRoom`/`QueueRoom` | provides `game.staticRoot`, `game.registerRooms`, `game.precreateWorldRoom` | `^1.4.0` |
|
|
269
266
|
| **`discord`** | routes: `discord`, `bug-attachments`; pollers: `discord-bot` | provides `discord.isLinked`; consumes `ideas.capture` | `^1.4.0` |
|
|
270
267
|
| **`art-pipeline`** | routes: `art-key`; disciplines: `artist`; skills: `otb-tile-generate` etc.; uiSections: `art` | provides `art.sharedKeyConfigured` | `^1.3.0` |
|