@bongos/core 1.24.78 → 1.24.80
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 +498 -353
- package/.claude/skills/ask-for-help/SKILL.md +1 -1
- package/.claude/skills/builder-sequence/SKILL.md +1 -1
- package/.claude/skills/design/SKILL.md +1 -1
- package/.claude/skills/goal-create/SKILL.md +1 -1
- package/.claude/skills/planning-session/SKILL.md +1 -1
- package/clients/bongos-client/README.md +1 -1
- package/clients/bongos-client/bongos-client.global.js +8 -0
- package/clients/bongos-client/index.cjs +8 -0
- package/clients/bongos-client/index.d.ts +11 -0
- package/clients/bongos-client/index.mjs +8 -0
- package/docs/adr/0274-one-kernel-three-role-packs.md +2 -2
- package/docs/adr/0399-the-visor-is-glass-over-the-scene-and-owns-no-camera.md +91 -0
- package/docs/adr/0400-a-chain-reserves-work-and-each-sub-quest-is-still-claimed-alone.md +109 -0
- package/docs/adr/0401-one-options-menu-opens-every-settings-screen-in-a-frame.md +53 -0
- package/docs/adr/README.md +3 -0
- package/docs/api/openapi.json +195 -3
- package/docs/api-reference.md +8 -4
- package/docs/architecture.md +7 -3
- package/docs/copy-inventory.md +390 -370
- package/docs/copy-registry.json +719 -518
- package/docs/design/characters/character-sprites-source.webp +0 -0
- package/docs/file-map.md +7 -8
- package/docs/module-api-changelog.md +4 -0
- package/docs/modules-contract.md +5 -0
- package/docs/onboarding/slash-commands.md +1 -1
- package/docs/packs/{engineer.md → artisan.md} +5 -5
- package/docs/packs/artist.md +50 -4
- package/docs/page-inventory.json +15 -4
- package/docs/page-readings.json +3182 -3336
- package/docs/{packs/ideator.md → recipes/ideation-playbook.md} +5 -48
- package/migrations/core_296_crafts_artisan_artist.sql +72 -0
- package/migrations/core_297_builder_character.sql +30 -0
- package/modules/copy-desk/proposals.js +1 -1
- package/modules/economy/credits-by-craft.js +29 -15
- package/modules/hall-ui/public/ai-studio.html +4 -4
- package/modules/hall-ui/public/atlas.html +5 -5
- package/modules/hall-ui/public/atlas.js +3 -1
- package/modules/hall-ui/public/blockers.html +5 -5
- package/modules/hall-ui/public/board-room.html +4 -4
- package/modules/hall-ui/public/characters/artisan.png +0 -0
- package/modules/hall-ui/public/characters/artist.png +0 -0
- package/modules/hall-ui/public/characters/patron.png +0 -0
- package/modules/hall-ui/public/city.css +2 -1
- package/modules/hall-ui/public/city.html +9 -6
- package/modules/hall-ui/public/city.js +7 -1
- package/modules/hall-ui/public/collab.html +4 -4
- package/modules/hall-ui/public/commands.html +4 -4
- package/modules/hall-ui/public/copy-desk.html +4 -4
- package/modules/hall-ui/public/craft-mode.js +258 -64
- package/modules/hall-ui/public/deploy.html +4 -4
- package/modules/hall-ui/public/diagram-viewer.js +2 -1
- package/modules/hall-ui/public/dom-utils.js +1 -1
- package/modules/hall-ui/public/goal-map.html +9 -6
- package/modules/hall-ui/public/goals.html +5 -5
- package/modules/hall-ui/public/government.html +4 -4
- package/modules/hall-ui/public/hall-render.js +3 -1
- package/modules/hall-ui/public/home-city-draw.js +3 -3
- package/modules/hall-ui/public/home-city.css +4 -0
- package/modules/hall-ui/public/home-city.js +17 -9
- package/modules/hall-ui/public/home-gallery.js +8 -1
- package/modules/hall-ui/public/home-idea-box.css +2 -2
- package/modules/hall-ui/public/home-idea-box.js +3 -3
- package/modules/hall-ui/public/idea.html +5 -5
- package/modules/hall-ui/public/ideas.html +5 -5
- package/modules/hall-ui/public/index.html +11 -7
- package/modules/hall-ui/public/market-watch-item.html +4 -4
- package/modules/hall-ui/public/market-watch-rules.html +4 -4
- package/modules/hall-ui/public/market-watch.html +6 -9
- package/modules/hall-ui/public/market-watch.js +22 -45
- package/modules/hall-ui/public/modules.html +4 -4
- package/modules/hall-ui/public/money.html +4 -4
- package/modules/hall-ui/public/my-agents.html +4 -4
- package/modules/hall-ui/public/options-menu.js +409 -0
- package/modules/hall-ui/public/paintbrush.js +3 -3
- package/modules/hall-ui/public/palette.js +11 -13
- package/modules/hall-ui/public/primer.html +5 -5
- package/modules/hall-ui/public/profile-crafts.js +1 -1
- package/modules/hall-ui/public/profile-roles.js +23 -19
- package/modules/hall-ui/public/profile.css +1 -1
- package/modules/hall-ui/public/profile.html +19 -18
- package/modules/hall-ui/public/profile.js +19 -18
- package/modules/hall-ui/public/profile.states.json +4 -4
- package/modules/hall-ui/public/project-settings.html +4 -4
- package/modules/hall-ui/public/roster.html +4 -4
- package/modules/hall-ui/public/roster.js +3 -3
- package/modules/hall-ui/public/settings.css +24 -4
- package/modules/hall-ui/public/settings.html +21 -17
- package/modules/hall-ui/public/settings.js +44 -44
- package/modules/hall-ui/public/shell-game.css +65 -0
- package/modules/hall-ui/public/shell-game.js +283 -3
- package/modules/hall-ui/public/shell.js +7 -26
- package/modules/hall-ui/public/sky-interaction.js +7 -0
- package/modules/hall-ui/public/speciality-tools.js +1 -2
- package/modules/hall-ui/public/street-inside.js +3 -4
- package/modules/hall-ui/public/street.html +4 -4
- package/modules/hall-ui/public/studio.html +5 -5
- package/modules/hall-ui/public/style.css +73 -47
- package/modules/hall-ui/public/task-detail.js +5 -4
- package/modules/hall-ui/public/task.html +5 -5
- package/modules/hall-ui/public/thinking.css +10 -0
- package/modules/hall-ui/public/thinking.html +9 -6
- package/modules/hall-ui/public/tweak-editor.html +5 -5
- package/modules/hall-ui/public/tweak-editor.js +5 -1
- package/modules/hall-ui/public/update-pill.js +91 -2
- package/modules/hall-ui/public/visor.css +80 -0
- package/modules/hall-ui/public/visor.js +316 -0
- package/modules/hall-ui/public/watch-repo-invite.js +159 -0
- package/modules/hall-ui/public/watch.html +6 -5
- package/modules/hall-ui/public/watch.js +17 -2
- package/modules/hall-ui/public/welcome-boot.js +15 -6
- package/modules/hall-ui/public/work.html +5 -5
- package/modules/hall-ui/records/builders-roster.md +2 -2
- package/modules/hall-ui/records/craft-mode.md +13 -11
- package/modules/hall-ui/records/game-mode.md +2 -2
- package/modules/hall-ui/records/governor-street.md +1 -1
- package/modules/hall-ui/records/home-city.md +3 -1
- package/modules/hall-ui/records/market-watch-settings.md +2 -0
- package/modules/hall-ui/records/options-menu.md +15 -0
- package/modules/hall-ui/records/profile-roles.md +11 -11
- package/modules/hall-ui/records/sky.md +3 -3
- package/modules/hall-ui/records/start-screen.md +21 -0
- package/modules/hall-ui/records/tweak-editor.md +1 -1
- package/modules/hall-ui/records/update-pill.md +12 -0
- package/modules/hall-ui/records/visor.md +23 -0
- package/modules/hall-ui/records/welcome-tower.md +5 -5
- package/modules/ideas/ideator-stats.js +3 -1
- package/modules/ideas/inbox.js +2 -2
- package/modules/lifecycle/activity.js +1 -1
- package/modules/lifecycle/cascade.js +4 -4
- package/modules/lifecycle/goal-spec-task.js +1 -1
- package/modules/lifecycle/help-requests.js +19 -15
- package/modules/lifecycle/kickoff-checklist.js +3 -3
- package/modules/lifecycle/kickoff-seed.js +1 -1
- package/modules/lifecycle/migrations/lifecycle_021_crafts_artisan_artist.sql +29 -0
- package/modules/lifecycle/mingle.js +4 -4
- package/modules/lifecycle/page-tweak-write.js +1 -1
- package/modules/lifecycle/routes/task-write-routes.js +3 -1
- package/modules/lifecycle/routes/tasks.js +3 -3
- package/modules/lifecycle/ship-card.js +2 -3
- package/modules/lifecycle/task-classifier.js +39 -29
- package/modules/lifecycle/tests/cascade.mjs +7 -7
- package/modules/onboarding/founding-mode.js +3 -0
- package/modules/onboarding/genesis-home.js +21 -1
- package/modules/onboarding/routes/onboarding.js +2 -0
- package/modules/page-notes/notes.js +3 -2
- package/modules/page-notes/split.js +1 -1
- package/modules/platform-identity/craft-rollup.js +35 -7
- package/modules/platform-identity/migrations/platform_identity_036_crafts_artisan_artist.sql +45 -0
- package/modules/platform-identity/platform-identity.js +2 -2
- package/modules/platform-identity/routes/community-leaderboard.js +2 -1
- package/modules/platform-identity/routes/community-search.js +2 -1
- package/modules/platform-identity/routes/sso.js +2 -1
- package/modules/platform-identity/tests/platform-identity.mjs +6 -6
- package/modules/public-landing/public/community.html +3 -5
- package/modules/public-landing/public/index.html +1 -1
- package/modules/public-landing/public/projects.html +1 -1
- package/modules/specialities/migrations/specialities_004_crafts_artisan_artist.sql +30 -0
- package/modules/specialities/routes/specialities.js +2 -2
- package/modules/status-ui/public/status.js +1 -1
- package/modules/ui-design/kit/fixtures/community-leaderboard.json +10 -10
- package/modules/ui-design/kit/fixtures/community-search.json +2 -2
- package/modules/ui-design/kit/fixtures/scouting-recruiter.json +1 -1
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/release-notes.json +76 -0
- package/scripts/bongos/autobongos-host.js +19 -4
- package/scripts/bongos/autobongos-loop.js +1 -1
- package/scripts/bongos/claude-materialize.js +20 -1
- package/scripts/bongos/discipline-modes.json +7 -12
- package/scripts/bongos/fitness.js +1 -1
- package/scripts/bongos/gen-hall-sitemap.js +7 -7
- package/scripts/bongos/grade-smoke.js +2 -2
- package/scripts/bongos/init.js +2 -2
- package/scripts/bongos/newcomer-floor.config.json +1 -2
- package/scripts/bongos/newcomer-floor.js +4 -3
- package/scripts/bongos/newcomer-floor.templates.json +10 -12
- package/scripts/bongos/newcomer-floor.test.js +47 -38
- package/scripts/bongos/role-pack-guard.js +5 -4
- package/scripts/bongos/seed-tasks.example.json +3 -3
- package/scripts/bongos/setup.js +20 -107
- package/scripts/bongos/start.js +2 -2
- package/scripts/bongos/task.js +5 -4
- package/scripts/bongos/triage.js +1 -1
- package/scripts/bongos/worktree.js +16 -4
- package/scripts/setup-builder.js +6 -46
- package/src/bongos/auth-admission.js +8 -8
- package/src/bongos/craft-mode.js +2 -0
- package/src/bongos/db.js +39 -1
- package/src/bongos/github-repos.js +78 -0
- package/src/bongos/module-scope-map.js +22 -0
- package/src/bongos/role-stats.js +27 -11
- package/src/bongos/routes/github.js +100 -2
- package/src/bongos/routes/me.js +33 -0
- package/src/bongos/serve-internal.js +26 -9
- package/src/crafts.js +66 -0
- package/src/module-api.js +6 -1
- package/src/module-loader/manifest-schema.js +16 -0
- package/src/modules.js +2 -2
- package/src/role-responsibilities.js +6 -5
- package/tests/acclaim_feed_evidence_db.mjs +1 -1
- package/tests/activity_rollup_as_of.mjs +1 -1
- package/tests/api_alias_caller_ratchet.mjs +3 -3
- package/tests/application_lifecycle.mjs +1 -1
- package/tests/artist_review.mjs +1 -1
- package/tests/artist_review_goal.mjs +1 -1
- package/tests/autobongos_host.mjs +19 -1
- package/tests/blocker_hall_live_proof.mjs +1 -1
- package/tests/blocker_tasks_named_db.mjs +2 -2
- package/tests/canonical_profile_url.mjs +1 -1
- package/tests/cap_newcomer_tasks.mjs +13 -13
- package/tests/character_creation.mjs +294 -0
- package/tests/claim_gate_open_blocker.mjs +2 -2
- package/tests/claim_gate_rebase.mjs +6 -6
- package/tests/claude_materialize.mjs +75 -1
- package/tests/clawback_confirmed_backlog.mjs +3 -3
- package/tests/collab_page.mjs +8 -9
- package/tests/collab_self_settling.mjs +2 -2
- package/tests/community_leaderboard_route.mjs +13 -5
- package/tests/community_proof_db.mjs +3 -0
- package/tests/community_search_route.mjs +7 -6
- package/tests/conductor.mjs +1 -1
- package/tests/conductor_main_e2e.mjs +8 -8
- package/tests/copy_desk_flags_db.mjs +1 -1
- package/tests/copy_desk_page_approve.mjs +2 -2
- package/tests/copy_desk_page_claim.mjs +2 -2
- package/tests/copy_desk_page_next.mjs +1 -1
- package/tests/copy_desk_page_release.mjs +1 -1
- package/tests/copy_desk_page_submit.mjs +2 -2
- package/tests/core_258_box_session_claims_db.mjs +1 -1
- package/tests/craft_mode.mjs +48 -34
- package/tests/craft_mode_home.mjs +20 -20
- package/tests/craft_mode_looks.mjs +16 -15
- package/tests/craft_mode_nav.mjs +31 -29
- package/tests/craft_review_mode.mjs +46 -41
- package/tests/crafts_vocabulary.mjs +70 -0
- package/tests/cross_discipline_priority_direction.mjs +5 -5
- package/tests/fitness.mjs +7 -11
- package/tests/funded_project_pays_proof_db.mjs +1 -1
- package/tests/genesis_home.mjs +21 -1
- package/tests/github_chip.mjs +3 -3
- package/tests/github_repo_invite.mjs +379 -0
- package/tests/goal_criterion_confirm_ui.mjs +1 -1
- package/tests/goal_invite_consent.mjs +1 -1
- package/tests/goal_map_page.mjs +2 -2
- package/tests/goal_sort_staleness.mjs +1 -1
- package/tests/goal_spec_task.mjs +1 -1
- package/tests/goal_spec_task_db.mjs +3 -3
- package/tests/grade_engine.mjs +2 -2
- package/tests/grader_no_artifact.mjs +1 -1
- package/tests/grader_prompt_fencing.mjs +1 -1
- package/tests/grader_prompt_window_bound.mjs +1 -1
- package/tests/grader_reader_lens.mjs +2 -2
- package/tests/grader_severity_gate.mjs +1 -1
- package/tests/grader_unbacked_score.mjs +1 -1
- package/tests/hall_approval_queue.mjs +1 -1
- package/tests/hall_board_world.mjs +2 -2
- package/tests/hall_builders_page_pass.mjs +1 -1
- package/tests/hall_city.mjs +1 -1
- package/tests/hall_fullscreen.mjs +27 -3
- package/tests/hall_kit_charts.mjs +1 -1
- package/tests/hall_landing_boot.mjs +1 -1
- package/tests/hall_my_agents.mjs +16 -16
- package/tests/hall_nav.mjs +22 -15
- package/tests/hall_options_menu.mjs +247 -0
- package/tests/hall_oversight_world.mjs +1 -1
- package/tests/hall_palette.mjs +8 -9
- package/tests/hall_profile_world.mjs +3 -3
- package/tests/hall_record_world.mjs +2 -2
- package/tests/hall_settings_world.mjs +2 -1
- package/tests/hall_sitemap.mjs +6 -5
- package/tests/hall_start_screen.mjs +244 -0
- package/tests/hall_street.mjs +2 -2
- package/tests/hall_street_inside.mjs +17 -9
- package/tests/hall_studio_world.mjs +3 -3
- package/tests/hall_visor.mjs +224 -0
- package/tests/help_requests.mjs +47 -15
- package/tests/helpers.mjs +4 -4
- package/tests/home_city.mjs +6 -4
- package/tests/home_city_widget.mjs +33 -14
- package/tests/home_gallery_widget.mjs +4 -4
- package/tests/home_idea_box.mjs +6 -6
- package/tests/hub_community_page.mjs +3 -3
- package/tests/hub_craft_rollup.mjs +75 -36
- package/tests/hub_recent_ships.mjs +3 -2
- package/tests/idea_cascade.mjs +2 -2
- package/tests/idea_credit_streams_db.mjs +1 -1
- package/tests/idea_detail_page.mjs +1 -1
- package/tests/idea_ideate_full.mjs +5 -2
- package/tests/idea_spark_hall.mjs +1 -1
- package/tests/init.mjs +3 -3
- package/tests/instance_manifest.mjs +2 -2
- package/tests/kickoff_checklist.mjs +1 -1
- package/tests/leaderboard_roles.mjs +34 -25
- package/tests/lifecycle_claim_ladder_refs.mjs +55 -0
- package/tests/lightbulb.mjs +14 -10
- package/tests/main_discipline.mjs +8 -8
- package/tests/markdown_line_endings.mjs +1 -1
- package/tests/market_watch_pages.mjs +52 -74
- package/tests/me_streak_leaderboard_queries.mjs +3 -3
- package/tests/migration_allocation.mjs +1 -1
- package/tests/mingle.mjs +36 -21
- package/tests/module-scope-map.mjs +22 -2
- package/tests/module_api.mjs +1 -0
- package/tests/module_contributions.mjs +13 -13
- package/tests/module_manifest.mjs +29 -0
- package/tests/module_skills_hook.mjs +2 -2
- package/tests/modules.mjs +14 -7
- package/tests/nav_permission_atoms.mjs +2 -1
- package/tests/needs_rebase.mjs +1 -1
- package/tests/newcomer_restock.mjs +13 -13
- package/tests/page_notes_panel.mjs +22 -22
- package/tests/page_tweak_no_block.mjs +1 -1
- package/tests/paintbrush.mjs +7 -7
- package/tests/privacy_matrix.mjs +1 -0
- package/tests/profile_activity.mjs +20 -23
- package/tests/profile_earnings.mjs +1 -1
- package/tests/profile_nudge_prefs.mjs +4 -4
- package/tests/profile_role_headline.mjs +73 -46
- package/tests/profile_role_stats.mjs +55 -45
- package/tests/profile_rollup_consent.mjs +19 -6
- package/tests/profile_route.mjs +12 -12
- package/tests/profile_ui_cross_project.mjs +4 -4
- package/tests/project_invite_suggestions.mjs +2 -2
- package/tests/promote_goal_id.mjs +1 -1
- package/tests/publish_manifest.mjs +1 -1
- package/tests/rank_floor_wiring.mjs +1 -1
- package/tests/regrade_actual_minutes.mjs +1 -1
- package/tests/removal_proposal.mjs +2 -2
- package/tests/reward_gate.mjs +4 -4
- package/tests/reward_mode_cost_plus_only.mjs +1 -1
- package/tests/role_responsibilities.mjs +18 -12
- package/tests/role_stats_db.mjs +17 -16
- package/tests/scouting_rollup_fanout.mjs +5 -5
- package/tests/seed_tasks.mjs +5 -2
- package/tests/session_earnings_mirror_db.mjs +1 -1
- package/tests/session_reward_on_land_db.mjs +1 -1
- package/tests/session_reward_reconcile_db.mjs +2 -2
- package/tests/sessions_kit_pager.mjs +1 -1
- package/tests/settings_art_key_absent.mjs +2 -2
- package/tests/settings_main_role.mjs +21 -20
- package/tests/setup_flow.mjs +3 -3
- package/tests/setup_smoke.mjs +20 -0
- package/tests/ship_card.mjs +6 -6
- package/tests/specialities.mjs +16 -4
- package/tests/speciality_db_shape.mjs +6 -6
- package/tests/speciality_injection.mjs +17 -17
- package/tests/speciality_offer_ui.mjs +5 -5
- package/tests/speciality_offered.mjs +6 -5
- package/tests/speciality_session_skills.mjs +7 -7
- package/tests/speciality_skills.mjs +11 -11
- package/tests/speciality_walkthrough_ui.mjs +2 -2
- package/tests/sso_checkin_identity_spoof.mjs +2 -1
- package/tests/task_classifier_vocab.mjs +10 -0
- package/tests/task_cli.mjs +11 -3
- package/tests/task_criteria_unlink_db.mjs +2 -2
- package/tests/task_discipline_required.mjs +38 -16
- package/tests/task_goal_required.mjs +4 -4
- package/tests/task_needs_db.mjs +1 -1
- package/tests/tweak_replaces_artist_review.mjs +1 -1
- package/tests/update_pill.mjs +153 -2
- package/tests/upkeep_home.mjs +1 -1
- package/tests/v3_c1_options_proof.mjs +145 -0
- package/tests/visual_review.mjs +3 -3
- package/tests/watch_applications_queue.mjs +8 -5
- package/tests/watch_sealed_floor.mjs +3 -1
- package/tests/welcome_boot.mjs +12 -9
- package/tests/welcome_boot_browser.mjs +13 -13
- package/tests/worktree_helper.mjs +16 -1
|
@@ -36,7 +36,7 @@ They are **complementary, not alternatives.** An owner-only task (a credential r
|
|
|
36
36
|
```
|
|
37
37
|
Match the `github_login` or `display_name` the user named. A name with no match is a question for the user, not a guess — a wrong `needs_builder_id` sends the ask to a stranger.
|
|
38
38
|
|
|
39
|
-
Addressing a **craft** instead of a person is the alternative: `needs_craft` is one of `artist`, `builder`, `ideator
|
|
39
|
+
Addressing a **craft** instead of a person is the alternative: `needs_craft` is one of `artisan`, `artist`, `ui` (the old spellings `builder`, `engineer` and `ideator` are still accepted and read as `artisan`/`artist`, task 1005141). It reaches only builders who declared that discipline in their profile, so a craft nobody has declared reaches nobody.
|
|
40
40
|
|
|
41
41
|
**Exactly one addressee.** Both fields is a 400 `two_addressees`; neither is `no_addressee`. The refusal body carries the valid `crafts`.
|
|
42
42
|
|
|
@@ -38,7 +38,7 @@ This skill owns the **loop and the halt discipline**. It does not re-derive how
|
|
|
38
38
|
|
|
39
39
|
3. **Claim it** — `/builder-claim <id>`, or `node scripts/bongos/claim.js <id>`.
|
|
40
40
|
|
|
41
|
-
4. **Build it** — follow the claimed task's role pack (`docs/packs/
|
|
41
|
+
4. **Build it** — follow the claimed task's role pack (`docs/packs/artisan.md` for engineer work). Stay strictly inside the task's `touches[]`. Everything the normal task loop requires still applies: read the acceptance criteria, work test-first, commit before shipping.
|
|
42
42
|
|
|
43
43
|
5. **Ship it** — `/builder-ship`. The task must reach `shipped`, not stall at `completed` or `confirmed`. A ship that does not land has not unblocked anything, so the chain cannot advance; treat it as a halt (see `ship_failed` below).
|
|
44
44
|
|
|
@@ -10,7 +10,7 @@ cost: >-
|
|
|
10
10
|
Uses your session. You see the changes on a preview before anything goes live.
|
|
11
11
|
---
|
|
12
12
|
|
|
13
|
-
You are running a **UI design session**. Two things make it different from the Engineer pack (`docs/packs/
|
|
13
|
+
You are running a **UI design session**. Two things make it different from the Engineer pack (`docs/packs/artisan.md`): the work is judged **by looking at it** (so every step ends in a rendered screen, not a paragraph), and it is done **inside a world that is not yours** — the instance's, which you read first and never override. The `ui-design` module's [CLAUDE.md](../../../modules/ui-design/CLAUDE.md) is the reference; this file is the loop.
|
|
14
14
|
|
|
15
15
|
## Step 0 — the tools, then the mode
|
|
16
16
|
|
|
@@ -114,7 +114,7 @@ node scripts/bongos/api.js POST /api/bongos/versions/<ver>/done-when --body-file
|
|
|
114
114
|
# 5c — the seed tasks, one call each. --body-file avoids shell-quoting description/arrays.
|
|
115
115
|
node scripts/bongos/api.js POST /api/bongos/tasks --body-file <path-to-task.json>
|
|
116
116
|
# {"version_id":"<ver>","goal_id":<gid>,"title":"...","description":"...",
|
|
117
|
-
# "kind":"feature|refactor|infra|spike|verify|decision","discipline":"
|
|
117
|
+
# "kind":"feature|refactor|infra|spike|verify|decision","discipline":"artisan|artist|ui",
|
|
118
118
|
# "priority":N,"est_minutes":N,
|
|
119
119
|
# "criterion_ids":["<slug>"],"source":"goal-create","source_ref":"goal-<gid>-R##"}
|
|
120
120
|
# No needs_migration here — the create rejects it as unknown; PATCH it afterwards if the
|
|
@@ -23,7 +23,7 @@ The first planning session — V3 Planning Session #1, 2026-05-12 — is the tem
|
|
|
23
23
|
- A previous planning session left proposals in `idea_inbox` tagged `kind='criterion-proposal'` that need ratification
|
|
24
24
|
- **A big design-driven ask arrives — route it here BEFORE any task is seeded (task 1004675).** The tell: the owner has a design in mind (a mockup, a named model, "it should feel like…"), and the work would span several tasks. Seeding those tasks straight from chat — through `/goal-create`, `/idea-triage`, or a hand-written `POST /tasks` — skips the spec, the interview and the design binding in Phase 2, which is exactly how a build drifts from what was agreed. A single small task, or a goal whose shape is already settled and has no design to honour, does not need this.
|
|
25
25
|
|
|
26
|
-
**Run an ideation pass first when the goal's SHAPE is not yet settled.** An
|
|
26
|
+
**Run an ideation pass first when the goal's SHAPE is not yet settled.** An ideation session (the ideas half of the [Artist pack](../../../docs/packs/artist.md)) inverts this skill's stance: there the human drives and you are the sounding board, so *their* framing sets the shape of the thing. Carry its output into Phase 1 and the Phase-4 interview is left with genuine residue instead of first-pass design.
|
|
27
27
|
|
|
28
28
|
Not a gate — a session for work whose shape is already settled should open directly. But **Phase 4 is a poor instrument for a first pass**: an `AskUserQuestion` round must author its options before the owner has said anything, so every option encodes *your* framing, and a proposal you believe is correct never becomes a question at all. The 2026-08-16 Board Room session is the evidence — three agent proposals (a role-based voting chamber, a tiered standard-of-review override ledger, Discord reaction-voting) died in the ideation half that would otherwise have been baked into the spec as defaults, none of which would have surfaced as an interview question.
|
|
29
29
|
|
|
@@ -5,7 +5,7 @@ A **generated**, zero-dependency typed client for the Bongos API — produced fr
|
|
|
5
5
|
by hand; it regenerates when the spec changes, so it can never drift from the routes.
|
|
6
6
|
|
|
7
7
|
- API version: **v1** (served at `/api/bongos/v1`)
|
|
8
|
-
-
|
|
8
|
+
- 694 operations across 85 resource groups
|
|
9
9
|
|
|
10
10
|
## Use it from your project
|
|
11
11
|
|
|
@@ -473,6 +473,8 @@ function createClient(opts = {}) {
|
|
|
473
473
|
getFoundingGenesis: (args) => request("GET", "/founding/genesis", { hasBody: false }, args),
|
|
474
474
|
// POST /founding/plan — rank: any-builder — POST /founding/plan
|
|
475
475
|
postFoundingPlan: (args) => request("POST", "/founding/plan", { hasBody: true }, args),
|
|
476
|
+
// POST /founding/skip — rank: any-builder — POST /founding/skip
|
|
477
|
+
postFoundingSkip: (args) => request("POST", "/founding/skip", { hasBody: true }, args),
|
|
476
478
|
// POST /founding/stages/{stage}/close — rank: any-builder — POST /founding/stages/:stage/close
|
|
477
479
|
postFoundingStagesStageClose: (args) => request("POST", "/founding/stages/{stage}/close", { hasBody: true }, args),
|
|
478
480
|
// POST /founding/start — rank: any-builder — POST /founding/start
|
|
@@ -485,6 +487,10 @@ function createClient(opts = {}) {
|
|
|
485
487
|
getGithubOrgsOrg: (args) => request("GET", "/github/orgs/{org}", { hasBody: false }, args),
|
|
486
488
|
// GET /github/repo — rank: any-builder — GET /github/repo
|
|
487
489
|
getGithubRepo: (args) => request("GET", "/github/repo", { hasBody: false }, args),
|
|
490
|
+
// GET /github/repo-invite — rank: archon — GET /github/repo-invite
|
|
491
|
+
getGithubRepoInvite: (args) => request("GET", "/github/repo-invite", { hasBody: false }, args),
|
|
492
|
+
// POST /github/repo-invite — rank: archon — POST /github/repo-invite
|
|
493
|
+
postGithubRepoInvite: (args) => request("POST", "/github/repo-invite", { hasBody: true }, args),
|
|
488
494
|
// POST /github/repo/visibility — rank: any-builder — POST /github/repo/visibility
|
|
489
495
|
postGithubRepoVisibility: (args) => request("POST", "/github/repo/visibility", { hasBody: true }, args),
|
|
490
496
|
// GET /github/repos — rank: any-builder — GET /github/repos
|
|
@@ -837,6 +843,8 @@ function createClient(opts = {}) {
|
|
|
837
843
|
postMeCashOutsIdCancel: (args) => request("POST", "/me/cash-outs/{id}/cancel", { hasBody: true }, args),
|
|
838
844
|
// POST /me/cash-outs/{id}/retry — rank: any-builder — POST /me/cash-outs/:id/retry
|
|
839
845
|
postMeCashOutsIdRetry: (args) => request("POST", "/me/cash-outs/{id}/retry", { hasBody: true }, args),
|
|
846
|
+
// PUT /me/character — rank: any-builder — PUT /me/character
|
|
847
|
+
putMeCharacter: (args) => request("PUT", "/me/character", { hasBody: true }, args),
|
|
840
848
|
// PATCH /me/checkout-freshness — rank: any-builder — PATCH /me/checkout-freshness
|
|
841
849
|
patchMeCheckoutFreshness: (args) => request("PATCH", "/me/checkout-freshness", { hasBody: true }, args),
|
|
842
850
|
// PATCH /me/core-move-seen — rank: any-builder — PATCH /me/core-move-seen
|
|
@@ -472,6 +472,8 @@ function createClient(opts = {}) {
|
|
|
472
472
|
getFoundingGenesis: (args) => request("GET", "/founding/genesis", { hasBody: false }, args),
|
|
473
473
|
// POST /founding/plan — rank: any-builder — POST /founding/plan
|
|
474
474
|
postFoundingPlan: (args) => request("POST", "/founding/plan", { hasBody: true }, args),
|
|
475
|
+
// POST /founding/skip — rank: any-builder — POST /founding/skip
|
|
476
|
+
postFoundingSkip: (args) => request("POST", "/founding/skip", { hasBody: true }, args),
|
|
475
477
|
// POST /founding/stages/{stage}/close — rank: any-builder — POST /founding/stages/:stage/close
|
|
476
478
|
postFoundingStagesStageClose: (args) => request("POST", "/founding/stages/{stage}/close", { hasBody: true }, args),
|
|
477
479
|
// POST /founding/start — rank: any-builder — POST /founding/start
|
|
@@ -484,6 +486,10 @@ function createClient(opts = {}) {
|
|
|
484
486
|
getGithubOrgsOrg: (args) => request("GET", "/github/orgs/{org}", { hasBody: false }, args),
|
|
485
487
|
// GET /github/repo — rank: any-builder — GET /github/repo
|
|
486
488
|
getGithubRepo: (args) => request("GET", "/github/repo", { hasBody: false }, args),
|
|
489
|
+
// GET /github/repo-invite — rank: archon — GET /github/repo-invite
|
|
490
|
+
getGithubRepoInvite: (args) => request("GET", "/github/repo-invite", { hasBody: false }, args),
|
|
491
|
+
// POST /github/repo-invite — rank: archon — POST /github/repo-invite
|
|
492
|
+
postGithubRepoInvite: (args) => request("POST", "/github/repo-invite", { hasBody: true }, args),
|
|
487
493
|
// POST /github/repo/visibility — rank: any-builder — POST /github/repo/visibility
|
|
488
494
|
postGithubRepoVisibility: (args) => request("POST", "/github/repo/visibility", { hasBody: true }, args),
|
|
489
495
|
// GET /github/repos — rank: any-builder — GET /github/repos
|
|
@@ -836,6 +842,8 @@ function createClient(opts = {}) {
|
|
|
836
842
|
postMeCashOutsIdCancel: (args) => request("POST", "/me/cash-outs/{id}/cancel", { hasBody: true }, args),
|
|
837
843
|
// POST /me/cash-outs/{id}/retry — rank: any-builder — POST /me/cash-outs/:id/retry
|
|
838
844
|
postMeCashOutsIdRetry: (args) => request("POST", "/me/cash-outs/{id}/retry", { hasBody: true }, args),
|
|
845
|
+
// PUT /me/character — rank: any-builder — PUT /me/character
|
|
846
|
+
putMeCharacter: (args) => request("PUT", "/me/character", { hasBody: true }, args),
|
|
839
847
|
// PATCH /me/checkout-freshness — rank: any-builder — PATCH /me/checkout-freshness
|
|
840
848
|
patchMeCheckoutFreshness: (args) => request("PATCH", "/me/checkout-freshness", { hasBody: true }, args),
|
|
841
849
|
// PATCH /me/core-move-seen — rank: any-builder — PATCH /me/core-move-seen
|
|
@@ -385,6 +385,7 @@ export interface PostDoneWhenCriterionIdUnsatisfyResponse { criterion: unknown }
|
|
|
385
385
|
export interface PostFeedbackReceiptRequest { sha256: string; kind?: "bug" | "idea" }
|
|
386
386
|
export interface PostFeedbackReceiptResponse { ok: boolean; receipt: unknown; hub: unknown }
|
|
387
387
|
export interface PostFoundingPlanRequest { days?: Record<string, unknown>; passes?: number; advisors?: string; government?: string; expected_builders?: number; existing?: boolean }
|
|
388
|
+
export interface PostGithubRepoInviteRequest { github_login: string; permission?: string }
|
|
388
389
|
export interface PostGithubRepoVisibilityRequest { repo: string; visibility: "public" | "private" }
|
|
389
390
|
export interface PostGithubRepoVisibilityResponse { ok: boolean; repo: unknown; private_deployable: boolean }
|
|
390
391
|
export interface PostGithubReposRequest { name: string; org?: string }
|
|
@@ -713,6 +714,8 @@ export interface PutGovernmentAsksMatterIdResponse { ok: boolean; matter_id: unk
|
|
|
713
714
|
export interface PutGovernmentRanksRankKeyPermissionsPermissionKeyResponse { ok: boolean; rank_key: unknown; permission_key: unknown; granted: unknown }
|
|
714
715
|
export interface PutGovernmentTreasuryPotsGoalIdRequest { budget_usd?: unknown }
|
|
715
716
|
export interface PutMarketWatchSettingsKeyRequest { key: string }
|
|
717
|
+
export interface PutMeCharacterRequest { character?: string }
|
|
718
|
+
export interface PutMeCharacterResponse { character: unknown }
|
|
716
719
|
export interface PutMingleOptInRequest { opted_in: boolean }
|
|
717
720
|
export interface PutMingleOptInResponse { opted_in: unknown; updated_at: unknown }
|
|
718
721
|
export interface PutMingleProjectRequest { enabled: boolean }
|
|
@@ -1132,6 +1135,8 @@ export interface BongosClient {
|
|
|
1132
1135
|
getFoundingGenesis(args?: RequestArgs): Promise<ApiResponse>;
|
|
1133
1136
|
/** POST /founding/plan — rank: any-builder */
|
|
1134
1137
|
postFoundingPlan(args?: RequestArgs & { body?: PostFoundingPlanRequest }): Promise<ApiResponse>;
|
|
1138
|
+
/** POST /founding/skip — rank: any-builder */
|
|
1139
|
+
postFoundingSkip(args?: RequestArgs): Promise<ApiResponse>;
|
|
1135
1140
|
/** POST /founding/stages/{stage}/close — rank: any-builder */
|
|
1136
1141
|
postFoundingStagesStageClose(args?: RequestArgs): Promise<ApiResponse>;
|
|
1137
1142
|
/** POST /founding/start — rank: any-builder */
|
|
@@ -1144,6 +1149,10 @@ export interface BongosClient {
|
|
|
1144
1149
|
getGithubOrgsOrg(args?: RequestArgs): Promise<GetGithubOrgsOrgResponse>;
|
|
1145
1150
|
/** GET /github/repo — rank: any-builder */
|
|
1146
1151
|
getGithubRepo(args?: RequestArgs): Promise<GetGithubRepoResponse>;
|
|
1152
|
+
/** GET /github/repo-invite — rank: archon */
|
|
1153
|
+
getGithubRepoInvite(args?: RequestArgs): Promise<ApiResponse>;
|
|
1154
|
+
/** POST /github/repo-invite — rank: archon */
|
|
1155
|
+
postGithubRepoInvite(args: RequestArgs & { body: PostGithubRepoInviteRequest }): Promise<ApiResponse>;
|
|
1147
1156
|
/** POST /github/repo/visibility — rank: any-builder */
|
|
1148
1157
|
postGithubRepoVisibility(args: RequestArgs & { body: PostGithubRepoVisibilityRequest }): Promise<PostGithubRepoVisibilityResponse>;
|
|
1149
1158
|
/** GET /github/repos — rank: any-builder */
|
|
@@ -1496,6 +1505,8 @@ export interface BongosClient {
|
|
|
1496
1505
|
postMeCashOutsIdCancel(args?: RequestArgs): Promise<ApiResponse>;
|
|
1497
1506
|
/** POST /me/cash-outs/{id}/retry — rank: any-builder */
|
|
1498
1507
|
postMeCashOutsIdRetry(args?: RequestArgs): Promise<ApiResponse>;
|
|
1508
|
+
/** PUT /me/character — rank: any-builder */
|
|
1509
|
+
putMeCharacter(args?: RequestArgs & { body?: PutMeCharacterRequest }): Promise<PutMeCharacterResponse>;
|
|
1499
1510
|
/** PATCH /me/checkout-freshness — rank: any-builder */
|
|
1500
1511
|
patchMeCheckoutFreshness(args: RequestArgs & { body: PatchMeCheckoutFreshnessRequest }): Promise<PatchMeCheckoutFreshnessResponse>;
|
|
1501
1512
|
/** PATCH /me/core-move-seen — rank: any-builder */
|
|
@@ -469,6 +469,8 @@ export function createClient(opts = {}) {
|
|
|
469
469
|
getFoundingGenesis: (args) => request("GET", "/founding/genesis", { hasBody: false }, args),
|
|
470
470
|
// POST /founding/plan — rank: any-builder — POST /founding/plan
|
|
471
471
|
postFoundingPlan: (args) => request("POST", "/founding/plan", { hasBody: true }, args),
|
|
472
|
+
// POST /founding/skip — rank: any-builder — POST /founding/skip
|
|
473
|
+
postFoundingSkip: (args) => request("POST", "/founding/skip", { hasBody: true }, args),
|
|
472
474
|
// POST /founding/stages/{stage}/close — rank: any-builder — POST /founding/stages/:stage/close
|
|
473
475
|
postFoundingStagesStageClose: (args) => request("POST", "/founding/stages/{stage}/close", { hasBody: true }, args),
|
|
474
476
|
// POST /founding/start — rank: any-builder — POST /founding/start
|
|
@@ -481,6 +483,10 @@ export function createClient(opts = {}) {
|
|
|
481
483
|
getGithubOrgsOrg: (args) => request("GET", "/github/orgs/{org}", { hasBody: false }, args),
|
|
482
484
|
// GET /github/repo — rank: any-builder — GET /github/repo
|
|
483
485
|
getGithubRepo: (args) => request("GET", "/github/repo", { hasBody: false }, args),
|
|
486
|
+
// GET /github/repo-invite — rank: archon — GET /github/repo-invite
|
|
487
|
+
getGithubRepoInvite: (args) => request("GET", "/github/repo-invite", { hasBody: false }, args),
|
|
488
|
+
// POST /github/repo-invite — rank: archon — POST /github/repo-invite
|
|
489
|
+
postGithubRepoInvite: (args) => request("POST", "/github/repo-invite", { hasBody: true }, args),
|
|
484
490
|
// POST /github/repo/visibility — rank: any-builder — POST /github/repo/visibility
|
|
485
491
|
postGithubRepoVisibility: (args) => request("POST", "/github/repo/visibility", { hasBody: true }, args),
|
|
486
492
|
// GET /github/repos — rank: any-builder — GET /github/repos
|
|
@@ -833,6 +839,8 @@ export function createClient(opts = {}) {
|
|
|
833
839
|
postMeCashOutsIdCancel: (args) => request("POST", "/me/cash-outs/{id}/cancel", { hasBody: true }, args),
|
|
834
840
|
// POST /me/cash-outs/{id}/retry — rank: any-builder — POST /me/cash-outs/:id/retry
|
|
835
841
|
postMeCashOutsIdRetry: (args) => request("POST", "/me/cash-outs/{id}/retry", { hasBody: true }, args),
|
|
842
|
+
// PUT /me/character — rank: any-builder — PUT /me/character
|
|
843
|
+
putMeCharacter: (args) => request("PUT", "/me/character", { hasBody: true }, args),
|
|
836
844
|
// PATCH /me/checkout-freshness — rank: any-builder — PATCH /me/checkout-freshness
|
|
837
845
|
patchMeCheckoutFreshness: (args) => request("PATCH", "/me/checkout-freshness", { hasBody: true }, args),
|
|
838
846
|
// PATCH /me/core-move-seen — rank: any-builder — PATCH /me/core-move-seen
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
**Date:** 2026-09-10
|
|
4
4
|
**Context:** BONGOS-V2, goal [1000095](https://cloudbongos.com/builders#/goal/1000095) (Working area 6 — Governor / Builder / Artist / Ideator experience), criterion `wa6-kernel-and-packs`, task [1002990](https://cloudbongos.com/builders#/task/1002990). Builds on [ADR 0061](<redacted>.md) (the CLAUDE.md context budget), [ADR 0062](0062-medusa-instance-model-decoupling.md) §7 (the core ↔ host split), [ADR 0272](0272-a-craft-is-an-identity-not-a-toolchain.md) (a craft is an identity, not a toolchain) and [ADR 0271](0271-the-ideator-surface-is-two-halves.md) (which predicted this move: *"when declaration lands the contract MOVES into the Ideator pack"*). Its dependency, task 1002989, widened the module map to cover the methodology surfaces so this work had a wall to stand in.
|
|
5
|
-
**Status:** Accepted.
|
|
5
|
+
**Status:** Accepted. Amended by task 1005141 (BONGOS-V3, 2026-11-09): the crafts are now Artisan and Artist, with the ideator's pack folded into the artist's — two packs, not three. The kernel/pack split this records is unchanged; the prose below describes the three-pack state it decided.
|
|
6
6
|
|
|
7
7
|
## Problem
|
|
8
8
|
|
|
@@ -41,7 +41,7 @@ Three reasons, in order of weight. `docs/` is already owned by the `methodology`
|
|
|
41
41
|
- **The ledger rule survives the split, and gets more honest.** The kernel keeps it in role-neutral form — *a change to project state is recorded in Bongos before it is made* — and each pack says what recording means for that craft. The engineer holds a claim; the ideator files the idea; the artist claims the work or records the review. The no-loopholes paragraph moves to the Engineer pack intact, where it is true.
|
|
42
42
|
- **The ship card had to move with the claim.** `modules/lifecycle/ship-card.js` routed a claimed task's "Open the work" button to `/dev`, `/paint` or `/ideate`. Left alone it would have shipped a button firing a command that no longer exists — the same divergence task 1003487 fixed in the other direction. It now points at the pack, and `tests/ship_card.mjs` asserts no core craft is routed to a slash command.
|
|
43
43
|
- **The ship card duplicates the registry, and a test is the shared source it cannot have.** `ship-card.js` is a module and may not require a core script across the boundary, which is why it and `claim.js` have always carried the map twice — and task 1003487 was exactly that duplication drifting. Rather than pretend the duplication away, `tests/fitness.mjs` now walks the registry entry for entry and asserts the card agrees, so a pack rename fails a test instead of shipping a hall button that opens nothing.
|
|
44
|
-
- **`tests/idea_ideate_full.mjs` moved with its subject.** Its thirteen assertions pinned the Full-Idea contract in `/ideate`'s prose — the same-route rule, the never-invent rule and its reason, the five-questions-are-not-restated rule. Repointing it at `docs/packs/
|
|
44
|
+
- **`tests/idea_ideate_full.mjs` moved with its subject.** Its thirteen assertions pinned the Full-Idea contract in `/ideate`'s prose — the same-route rule, the never-invent rule and its reason, the five-questions-are-not-restated rule. Repointing it at `docs/packs/artist.md` is what stops the split from deleting a guard along with the file it guarded; all thirteen pass against the pack unchanged.
|
|
45
45
|
- **The line target is not yet met.** The kernel is 216 lines against a ~200 target — a `fitness.js` warning, not a failure, and the same warning it carried before at 250. The character target, which is the real per-session cost, is now cleared. Tightening the line count is the context-budget cluster's work (tasks 1003620, 1003687, 1003688), which the goal's audit sequenced explicitly behind this one.
|
|
46
46
|
- **Governor is deliberately absent.** Three packs, not four, until the owner decides. The guard's floor is `>= 3`, so adding a fourth is additive and removing a third is a failure.
|
|
47
47
|
- **What this unblocks.** Task 1002991 (serve composed session context from the server) and 1002992 (inject role context at start and claim) now have something to compose and inject: today the pointer is printed and read, and those tasks replace the reading with injection. Task 1003732 authors the three responsibility statements into the packs' reserved seams — the Artist pack names its own, unwritten, rather than inventing it.
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# 0399 — The visor is glass over the scene, owns no camera, and spends Escape in a fixed order
|
|
2
|
+
|
|
3
|
+
- **Status:** Accepted
|
|
4
|
+
- **Date:** 2026-11-10
|
|
5
|
+
- **Tasks:** [task 1005146](https://cloudbongos.com/builders#/task/1005146) (this spike, BONGOS-V3 R06). It feeds [task 1005148](https://cloudbongos.com/builders#/task/1005148) (the first-person HUD, R08) and [task 1005153](https://cloudbongos.com/builders#/task/1005153) (lift the sky camera onto the city, R13).
|
|
6
|
+
- **Goal:** [goal 1000142](https://cloudbongos.com/builders#/goal/1000142) — criterion `you-are-a-character-in-first-person`.
|
|
7
|
+
- **Spec:** [`docs/specs/bongos-v3-game-conversion.md`](../specs/bongos-v3-game-conversion.md), section "Reuse, do not rebuild".
|
|
8
|
+
- **Builds on:** [ADR 0331](0331-the-sky-is-the-ideators-home.md) (the sky and its camera), [ADR 0272](0272-a-craft-is-an-identity-not-a-toolchain.md) (a craft is identity, not authority).
|
|
9
|
+
|
|
10
|
+
## 1. The question
|
|
11
|
+
|
|
12
|
+
The HUD (R08) puts a first-person **visor** over the project. Inside the visor you see the city or the sky ahead, your actions on the glass, and your sprite and credits in a corner. Three scenes already draw what is "ahead", and each has its own camera and its own Escape handling:
|
|
13
|
+
|
|
14
|
+
| Scene | Page | Drawn as | Camera today | Escape today |
|
|
15
|
+
|---|---|---|---|---|
|
|
16
|
+
| The sky | `/goal-map`, `/thinking` | `<canvas>` (`sky-draw.js`) | `SKY.S.cam` `{x, y, k}`, with `toScreen` / `toWorld` / `flyTo` / `fitAll` (`sky-layout.js:65-80`) and drag, wheel, arrow and `+`/`-`/`0` input (`sky-interaction.js:62-83`) | `sky-interaction.js:82`: tour → menu → pick. Each calls `preventDefault`. |
|
|
17
|
+
| The Governor City | `/city` | SVG and spans, scaled to fit the window (`city.js`) | none. The stage is fitted on resize. | `city.js:700` closes the card. `city-decide.js:676` closes the decide panel. |
|
|
18
|
+
| Home's project city | Home widget | SVG with a viewBox (`home-city.js:104-112`) | none until R13 lifts the sky camera onto it | none |
|
|
19
|
+
|
|
20
|
+
Two other layers already sit above every scene: the **craft picker** (`craft-mode.js:747`, a capture listener) and the **shared dialog** (`hall-dialog.js:73-99`, a capture listener that closes the top dialog only). The **command palette** (`palette.js:462`) is a third. At the bottom is the shell's own Escape (`shell.js:663-666`). It leaves full screen one tick later, unless something has already called `preventDefault`.
|
|
21
|
+
|
|
22
|
+
We have to decide two things: how the visor layers over these scenes, and where it sits in that Escape chain.
|
|
23
|
+
|
|
24
|
+
## 2. The decision
|
|
25
|
+
|
|
26
|
+
### 2.1 The visor is one DOM layer over the scene. It never draws inside it.
|
|
27
|
+
|
|
28
|
+
- The visor is **one overlay element** (`#visor`), positioned over the page's stage. Its root has `pointer-events: none` and its controls have `pointer-events: auto`. A drag, a wheel or a click on the world goes through the glass to the scene's own listeners unchanged. The sky's pan and zoom, the city's building buttons and Home's hover all keep working without knowing the visor is there.
|
|
29
|
+
- The visor **never draws inside a scene's canvas or SVG**, and no scene imports it. It is the same glass over the sky, the Governor City and Home's city. This includes the ideator's sky drawn over the city skyline (`home-city-draw.js` `skySvg`).
|
|
30
|
+
- The visor **is an overlay, not layout**. Showing it, hiding it or changing its parts never changes the stage's size. The sky watches `.sky-stage` with a `ResizeObserver` and refits its camera on resize (`sky-layout.js:62-63`), so a visor that took layout space would make the camera jump.
|
|
31
|
+
|
|
32
|
+
### 2.2 The visor owns no camera.
|
|
33
|
+
|
|
34
|
+
- The city's camera is the sky's camera, lifted by R13. It is **not a second camera, and it is not the visor's camera.** The visor never writes `cam.x`, `cam.y` or `cam.k`.
|
|
35
|
+
- A visor action that moves the view (for example "back to the centre") calls the scene's own function: `fitAll`, `flyTo`, `fitGoal`. A scene offers these by registering itself once, as `OTBVisor.scene({ name, actions })`. A scene with no camera (the Governor City until R13 reaches it) registers no movement actions, and the glass shows none. It does not show a disabled button.
|
|
36
|
+
- The visor reads nothing from the camera except through those actions. This keeps the one camera API (`toScreen`, `toWorld`, `flyTo`, `fitAll`) the only one, as the spec requires.
|
|
37
|
+
|
|
38
|
+
### 2.3 The stacking order, bottom to top
|
|
39
|
+
|
|
40
|
+
1. **The scene**: canvas or SVG.
|
|
41
|
+
2. **The visor's ambient glass**: the actions, the sprite and credits corner, and the hotkey hints. Nothing here hides the world, and it publishes its corners as CSS variables (`--visor-inset-top`, `-right`, `-bottom`, `-left`).
|
|
42
|
+
3. **The scene's own pop-ups**: the sky's panel, menu and tour, the city card, the decide panel and the plates. They sit **above** the glass because they are about one thing in the world that you just touched. They place themselves inside the visor's insets, so they never cover the sprite or the credits.
|
|
43
|
+
4. **The visor's open sheet**: the full action list or the hotkey sheet, when you open it.
|
|
44
|
+
5. **Modals**: the palette, the craft picker and the shared dialog, which uses the browser's top layer.
|
|
45
|
+
|
|
46
|
+
### 2.4 One Escape press closes exactly one layer, top first
|
|
47
|
+
|
|
48
|
+
| Order | Who spends it | How it is held back from the layers below |
|
|
49
|
+
|---|---|---|
|
|
50
|
+
| 0 | A text field (input, textarea, select, editable) | Every listener already skips text fields. The sky blurs the field. |
|
|
51
|
+
| 1 | The shared dialog: the top dialog only | capture on `document`, `preventDefault` and `stopPropagation` (existing) |
|
|
52
|
+
| 2 | The craft picker | capture on `document`, `preventDefault` (existing) |
|
|
53
|
+
| 3 | The command palette | `preventDefault` (existing) |
|
|
54
|
+
| 4 | **The visor's open sheet** (new) | **capture on `document`, `preventDefault` and `stopPropagation` while it is open**, the dialog's pattern |
|
|
55
|
+
| 5 | The scene's pop-up. Sky: tour → menu → pick. City: decide panel → card. | bubble listener and `preventDefault` (existing, except the city card, §3) |
|
|
56
|
+
| 6 | **Nothing left open.** In game mode this press is the options menu's (R04). Outside game mode it is the shell's, which leaves full screen. | The options menu calls `preventDefault` so the shell leaves it alone (as the R02 session log asked). The shell reads `defaultPrevented` one tick later (existing). |
|
|
57
|
+
|
|
58
|
+
There are two rules behind this table.
|
|
59
|
+
|
|
60
|
+
- **A layer above the scene listens in capture and stops propagation. A scene listens in bubble and calls `preventDefault`.** A capture listener on `document` always runs before a bubble listener, so the order of layers 1 to 4 never depends on which script loaded first. The sky's handler does not check `defaultPrevented`. A visor sheet that only called `preventDefault` would therefore close and *also* unpick the star under it, so the sheet must stop propagation.
|
|
61
|
+
- **The visor's ambient glass never takes an Escape.** It has nothing to close. A last Escape belongs to the options menu in game mode, or to the shell outside it. If the visor took it, Escape would have no way back to the navigation until R04 lands.
|
|
62
|
+
|
|
63
|
+
### 2.5 What the visor does not do
|
|
64
|
+
|
|
65
|
+
- It **never writes `hidden`** on nav or anything else. Only the rank gate writes `hidden` (`shell.js` rank gate). A character may only add `[data-craft-off]` (`craft-mode.js:194`). The visor shows the character's actions. It does not remove what rank allows.
|
|
66
|
+
- It **gates nothing**. Its actions call the same routes the pages call today, and the server's rank checks answer (C3, `character-is-identity-not-authority`). An action you lack the rank for is still offered where the page offers it today, and the server refuses it with today's error.
|
|
67
|
+
- It shows **credits, not payout** (`builders.total_credits`). No instance registers a money processor, so a payout readout would read empty (the spec's "What genuinely does not exist").
|
|
68
|
+
- It **adds no hotkey registry**. R09 builds the registry. Until then the visor's hint lines list the scene's existing keys: `L`, `?`, `0` and `/` on the sky, and `1`–`9`, arrows and Tab on the city card. R09 then makes them rebindable.
|
|
69
|
+
|
|
70
|
+
### 2.6 Where it lives
|
|
71
|
+
|
|
72
|
+
The visor goes in a new `modules/hall-ui/public/visor.js`, with styles in its own sheet. A page loads it after `shell-game.js` and `shell.js`. It is **not** written into `shell.js`, which has no lines to spare under its line limit (R02 session log), in the same way `shell-game.js` was split out. The visor shows only in game mode (`html[data-game="on"]`). Outside game mode the hall looks exactly as it does today.
|
|
73
|
+
|
|
74
|
+
## 3. Found while mapping: the city card's Escape also drops the bars
|
|
75
|
+
|
|
76
|
+
`city.js:700` `cardKey` closes the card on Escape but **does not call `preventDefault`**. The key event goes from the card (`city.js:754`) up to `window`, where the shell's listener (`shell.js:1355`) sees a press nobody spent. One tick later it leaves full screen. On `/city` in full screen, and on every page in game mode, **one Escape closes the card and brings the sidebar back together**. That breaks the hand-off protocol this ADR depends on (§2.4, row 5). The fix is one call: `e.preventDefault()` before `closeCard()`, when a card is open. It is filed as a bug for R08 or earlier. It is not fixed in this spike, which builds nothing (ADR 0227's rule for spikes).
|
|
77
|
+
|
|
78
|
+
`city-decide.js:676` and the sky (`sky-interaction.js:82`) already follow the protocol. The sky's pick case calls `preventDefault` only when something was picked or the panel was open. That is right: an Escape that closed nothing should fall through.
|
|
79
|
+
|
|
80
|
+
## 4. Consequences
|
|
81
|
+
|
|
82
|
+
- R08 builds one `visor.js` with no camera code and no drawing code. Its checks are: the glass passes pointers through, which a drag-pan on the sky with the visor up shows; an open sheet's Escape leaves the star picked; and in game mode the last Escape reaches the options menu, never the shell. `tests/hall_fullscreen.mjs` already drives the shell's half, and the visor's cases go beside it.
|
|
83
|
+
- R13 lifts the sky camera onto Home's city **as the scene's camera**. When it does, the city registers `fitAll` and `flyTo` with the visor as actions. No visor change is needed.
|
|
84
|
+
- Every new pop-up a scene adds follows row 5 (bubble listener, `preventDefault` when it closed something). Every new overlay above the scene follows rows 1 to 4 (capture listener, `stopPropagation`).
|
|
85
|
+
|
|
86
|
+
## 5. Alternatives refused
|
|
87
|
+
|
|
88
|
+
- **Draw the HUD into the scene's canvas or SVG.** Refused because it would mean three implementations, one per scene, and because the sky redraws on every frame its state is dirty. HUD text inside a canvas is also unreadable to a screen reader, which the sky's own list rule forbids (ADR 0331).
|
|
89
|
+
- **Give the visor its own camera that drives the scene.** Refused because that is the second camera the spec names a regression.
|
|
90
|
+
- **Make the visor a layout frame (a bordered box the scene shrinks into).** Refused because it changes the stage size, which refits the sky's camera every time the visor changes.
|
|
91
|
+
- **Let the visor take the last Escape (for example to fold the glass away).** Refused because in game mode that press is the only way to the navigation until R04 lands. After R04 it is the options menu's.
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# ADR 0400 — A chain reserves work; each sub-quest is still claimed on its own
|
|
2
|
+
|
|
3
|
+
- **Status:** Accepted
|
|
4
|
+
- **Date:** 2026-11-10
|
|
5
|
+
- **Task:** [task 1005158](https://cloudbongos.com/builders#/task/1005158) — spike `V3G.R18`, goal 1000144 (BONGOS-V3, criterion `work-is-claimed-as-a-chain`)
|
|
6
|
+
- **Deciders:** the owner, Lars, in the Phase 4 interview of 2026-11-07 ([`docs/specs/bongos-v3-game-conversion.md`](../specs/bongos-v3-game-conversion.md), *Interview answers*, answer 3 — the task text cites "answer 14"; the spec numbers it 3). This ADR records how that ruling is built.
|
|
7
|
+
- **Builds on:** [ADR 0153](0153-sequential-chain-runner.md) (the chain runner, and its refusal of a stored order), [ADR 0097](0097-one-active-claim-per-session-and-worktree-binding.md) (one active claim per session), [ADR 0015](0015-task-dependencies-and-auto-promotion.md) (dependencies are the order), [ADR 0226](0226-one-stale-timer-reporting-degrades-enforcement-refuses.md) (report before you act).
|
|
8
|
+
- **Gates:** task 1005159 (R19, the migration), task 1005160 (R20, reserve + claim), R21 (raid vs routine), R22 (chains replace the flat list).
|
|
9
|
+
|
|
10
|
+
## Context
|
|
11
|
+
|
|
12
|
+
The game conversion's criterion C5 says work is claimed as a chain with sub-quests beneath it, not picked from a flat table. A chain *reserves* the work and *orders* it; each sub-quest is still claimed one at a time through the existing checks. The proof: a raid chain that needs two Artisans refuses a single claimer and admits the second; a routine chain admits one.
|
|
13
|
+
|
|
14
|
+
Today nothing can hold a group of tasks:
|
|
15
|
+
|
|
16
|
+
- **Claiming is strictly per task.** `claimTasksBatch` (`modules/lifecycle/db-claims.js`) is N independent claims with N worktrees, and all-or-nothing — a successor fails `DEPS_NOT_SHIPPED` until its predecessor ships, so a dependency chain can never be batch-claimed.
|
|
17
|
+
- **`gateOneActiveClaimPerSession`** (`modules/lifecycle/routes/claims.js`, ADR 0097) refuses a second claim into the same working tree, fail-closed, backed by the unique index `uniq_active_claim_per_session`. It exists so two tasks' commits never ride out under one ship. Holding a chain *as claims* would collide with it by design.
|
|
18
|
+
- **`goal_members`** grants eligibility to claim a goal's tasks forever. It is not a reservation, and a goal is a working area (ten of them, ADR 0264) — far larger than a chain.
|
|
19
|
+
- **`scripts/bongos/sequence.js`** already walks a chain (ADR 0153): it orders a scope topologically and claims each link in turn. It reserves nothing: anyone else can claim the next link first.
|
|
20
|
+
|
|
21
|
+
ADR 0153 also rejected a `chain_id` or queue column as "a second, drift-prone source of truth" for order. That rejection still holds, and this design keeps it: the new row stores *who holds the work*, never *what order it runs in*.
|
|
22
|
+
|
|
23
|
+
## Decision
|
|
24
|
+
|
|
25
|
+
### D1 — Three new tables; none of them is a claim
|
|
26
|
+
|
|
27
|
+
Built by R19 (task 1005159), in the `lifecycle` module's migrations:
|
|
28
|
+
|
|
29
|
+
| Table | Columns (sketch) | Purpose |
|
|
30
|
+
|---|---|---|
|
|
31
|
+
| `chains` | `id`, `goal_id NOT NULL → goals`, `title`, `status` (`open` \| `reserved` \| `done` \| `abandoned`), `created_by`, `created_at`, `reserved_at` | The chain itself. Lives inside exactly one goal, so the city's "goal = building" and the goal-membership rung keep working unchanged. |
|
|
32
|
+
| `chain_tasks` | `chain_id`, `task_id`, PK both | Which tasks are its sub-quests. A partial unique index keeps a task in **at most one** non-terminal chain. Every member task must carry the chain's `goal_id` (checked on write). |
|
|
33
|
+
| `chain_party` | `chain_id`, `builder_id`, `craft` (`artisan` \| `artist`), `joined_at`, `left_at` | Who holds the reservation. An open row (`left_at IS NULL`) is a party member. |
|
|
34
|
+
|
|
35
|
+
There is **no order column, no "current step" column, and no foreign key from `claims`**. The raid/routine policy columns (required Artisans and Artists, compare-or-split) are R21's to add; this ADR only fixes that they live on `chains`.
|
|
36
|
+
|
|
37
|
+
### D2 — Order is derived, never stored
|
|
38
|
+
|
|
39
|
+
A chain's sub-quest order is the topological order of `task_dependencies` restricted to the chain's members, ties broken by priority, then calibrated estimate, then id — exactly `topoOrder` in `scripts/bongos/sequence.js` today. R20 moves that function into one shared pure module so the CLI runner, the server's chain read and the hall all compute the same order and cannot disagree.
|
|
40
|
+
|
|
41
|
+
- **The next sub-quest** is the first one in that order whose status is `ready`. Shipping a sub-quest already promotes its dependents (the `promote_dependents_on_ship` trigger), so the chain advances by itself with no write to the chain row.
|
|
42
|
+
- **A dependency outside the chain still blocks.** The claim gate's `DEPS_NOT_SHIPPED` refuses it as today, and the chain read reports it as waiting on outside work rather than skipping it (ADR 0153's "halt, do not skip").
|
|
43
|
+
- **Re-ordering a chain means editing dependencies**, the one place order already lives.
|
|
44
|
+
|
|
45
|
+
### D3 — Reserving is not claiming
|
|
46
|
+
|
|
47
|
+
Reserving a chain writes a `chain_party` row and sets `chains.status = 'reserved'`. It writes no `claims` row, binds no session and creates no worktree. Consequently:
|
|
48
|
+
|
|
49
|
+
- `gateOneActiveClaimPerSession` and its unique index have nothing new to see. A builder holding a reserved chain and one claimed sub-quest has **one** active claim, in **one** worktree — exactly the shape ADR 0097 enforces.
|
|
50
|
+
- The stale-claim sweeper (ADR 0226) is untouched; it still releases idle *claims*, never reservations.
|
|
51
|
+
- `claimTasksBatch` is not used for chains and does not change.
|
|
52
|
+
|
|
53
|
+
### D4 — Every sub-quest is claimed through the existing door
|
|
54
|
+
|
|
55
|
+
A party member claims a sub-quest with the ordinary `POST /api/gds/claims`, from the hall through the shared `claim-action.js` client, or from the CLI through `claim.js`. Every rung of the refusal ladder runs, in the same order, with the same codes and messages: inactive builder, rebase owed, not found, not ready, open blocker, rank, required rank, goal membership, relevance hold, needs, dependencies, overlap, module-disjointness — and, ahead of the route handler, the one-claim-per-session guard and the newcomer gate. A party member at too low a rank for a sub-quest is refused by the rank rung, not by the chain. **Character is not authority** (C3): joining a party never admits a claim the ladder would refuse.
|
|
56
|
+
|
|
57
|
+
### D5 — The one addition: a reserved chain refuses outsiders, at the end of the ladder
|
|
58
|
+
|
|
59
|
+
A reservation that anyone can walk around is not a reservation. So R20 adds one check: **a task in a reserved chain refuses a claimer who is not in that chain's party** (`409 CHAIN_RESERVED`, naming the chain and how to ask to join).
|
|
60
|
+
|
|
61
|
+
It is placed **after the last existing rung**, and built the way the goal-membership, relevance and needs checks are: one extracted function called from both `INSERT INTO claims` sites (`claimTask` and `claimTasksBatch`) and from the dry-run twin, so the batch path cannot bypass it.
|
|
62
|
+
|
|
63
|
+
This is what "the claim ladder is untouched" means here, stated precisely so a reviewer can check it:
|
|
64
|
+
|
|
65
|
+
1. **No existing rung moves, changes its code, or changes its message.** Every existing ladder test stays green with no edit.
|
|
66
|
+
2. **The new check can only refuse more, never admit more.** It runs only after every existing rung has said yes.
|
|
67
|
+
3. **Everyone who is refused today is refused with the same answer.** Because it runs last, an outsider who also lacks rank, membership or a shipped dependency still sees *that* refusal, not `CHAIN_RESERVED`.
|
|
68
|
+
4. **A task in no chain, or in an open (unreserved) chain, is not affected at all.**
|
|
69
|
+
|
|
70
|
+
The claimable feed applies the same rule up front, the way it decorates goal membership: a reserved chain's sub-quests show to outsiders as "held by a party — ask to join", never as claimable.
|
|
71
|
+
|
|
72
|
+
### D6 — Party size is refused at the chain's door, not the claim's
|
|
73
|
+
|
|
74
|
+
Joining a chain (`POST /chains/:id/join`, R20) is a separate door with its own refusals, so party rules never reach the claim ladder:
|
|
75
|
+
|
|
76
|
+
- **Routine** (R21's default): the first joiner reserves it and can work it alone; more may join and work independent sub-quests in parallel, each in their own worktree.
|
|
77
|
+
- **Raid:** the chain declares how many Artisans and Artists it needs. Until the party is full, its sub-quests refuse claims with `CHAIN_RESERVED` (reason `raid_quorum_unmet`) — the single Artisan is refused, the second is admitted, and the raid opens. This is the C5 proof.
|
|
78
|
+
- A member's craft for counting seats is their chosen character, which only decides *which seat they fill*. It is never read by a claim rung.
|
|
79
|
+
|
|
80
|
+
### D7 — A reservation lapses; it is reported first and acted on second
|
|
81
|
+
|
|
82
|
+
A reserved chain whose party holds no active claim in it and has shipped nothing in it for a lapse window returns to `open`, and its party rows are closed. It never releases a claim — claims keep their own sweeper. Following ADR 0226, the lapse is shown on the chain (and to its party) before it fires, and the sweep that frees it refuses to run on an unreadable window rather than guess. The window's length is R20's to set; it is measured in days, not the claim timer's hours, because a chain outlives any one sub-quest.
|
|
83
|
+
|
|
84
|
+
### D8 — One person working a chain is ADR 0153, scoped
|
|
85
|
+
|
|
86
|
+
`/builder-sequence` gains a `--chain N` scope that reads D2's order. One builder, one worktree, one claim at a time, ship then claim the next — today's runner, now walking a chain they hold so nobody can take the next link from under them.
|
|
87
|
+
|
|
88
|
+
## Rejected
|
|
89
|
+
|
|
90
|
+
- **A chain as N claims.** Holding every sub-quest as a claim row breaks ADR 0097 (two tasks' commits in one tree, one commingled ship) and cannot even be built: successors refuse `DEPS_NOT_SHIPPED` until their predecessor ships.
|
|
91
|
+
- **Changing `gateOneActiveClaimPerSession` to let a chain hold several claims.** That guard is fail-closed because a wrong answer ships unreviewed work. Loosening it to buy a feature is the largest risk in the whole conversion; the owner's ruling removes it, and this design never needs it.
|
|
92
|
+
- **A chain as a goal.** Goals are working areas, and goal membership is permanent eligibility. A chain is smaller, temporary and exclusive — three things a goal is not.
|
|
93
|
+
- **A stored order** (`position`, `next_task_id`). ADR 0153's rejection holds: the dependency edges are the order, and a second copy drifts.
|
|
94
|
+
- **Putting the chain check early in the ladder.** It would mask rank, membership and dependency refusals behind `CHAIN_RESERVED`, changing the answer an existing refusal gives. Last place is what keeps every existing answer unchanged.
|
|
95
|
+
- **A feed-only reservation** with no claim-time check. Claim-by-id walks straight past the feed — the exact trap task 1002650 closed for open blockers.
|
|
96
|
+
|
|
97
|
+
## Consequences
|
|
98
|
+
|
|
99
|
+
- **R19 (task 1005159)** — the three tables in D1, with the one-open-chain-per-task index. No change to `claims`, its indexes, or any claim function.
|
|
100
|
+
- **R20 (task 1005160)** — reserve and join; the shared order module (D2); the end-of-ladder check (D5) on both insert sites, the dry run and the feed; the lapse sweep (D7); `--chain` on the runner (D8). Its tests must include: every existing ladder test unchanged; an outsider refused `CHAIN_RESERVED` on a reserved chain; an outsider without rank still sees the rank refusal; a party member's one-claim-per-session refusal unchanged.
|
|
101
|
+
- **R21** — raid vs routine columns and the join-door refusals (D6), carrying the C5 proof.
|
|
102
|
+
- **R22** — the hall lists chains, not tasks, reading the feed decoration from D5.
|
|
103
|
+
- **Protected scope.** D5 touches `modules/lifecycle/db-claims.js`, a Metic-floor path; R20 is Metic work.
|
|
104
|
+
|
|
105
|
+
## Open questions (for R20/R21, not decided here)
|
|
106
|
+
|
|
107
|
+
1. The lapse window's length (D7).
|
|
108
|
+
2. Whether a goal owner may add sub-quests to a reserved chain (order recomputes either way, so it is a policy question, not a schema one).
|
|
109
|
+
3. What a raid does when a member leaves mid-run: pause the remaining sub-quests behind `raid_quorum_unmet` again, or let in-flight work finish.
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# 0401 — One options menu, which opens every settings screen in a frame
|
|
2
|
+
|
|
3
|
+
- **Status:** Accepted
|
|
4
|
+
- **Date:** 2026-11-10
|
|
5
|
+
- **Task:** [task 1005144](https://cloudbongos.com/builders#/task/1005144) (BONGOS-V3 R04)
|
|
6
|
+
- **Goal:** [goal 1000141](https://cloudbongos.com/builders#/goal/1000141) — criterion `game-opens-not-navigates`
|
|
7
|
+
- **Spec:** [`docs/specs/bongos-v3-game-conversion.md`](../specs/bongos-v3-game-conversion.md) (R04; "Reuse, do not rebuild": the settings panel seam and the task 1005044 move to My agents)
|
|
8
|
+
- **Builds on:** [ADR 0399](0399-the-visor-is-glass-over-the-scene-and-owns-no-camera.md) §2.4 row 6 (in game mode the last Escape is the options menu's), [ADR 0016](0016-trust-boundary-server-enforced-permissions.md) (the routes are the wall)
|
|
9
|
+
|
|
10
|
+
## 1. The question
|
|
11
|
+
|
|
12
|
+
The criterion: every setting and configuration is reachable from **one** vertical, grouped menu with a smart search, and no surface that used to be a sidebar link keeps an interface of its own. The owner chose to fold in all seven places a setting lived: Settings itself, My agents, Project settings, Modules, Permissions (with the Constitution), and Market Watch's settings and its rules.
|
|
13
|
+
|
|
14
|
+
Those six other screens are not small. Permissions alone is two rooms, eight sections and nine gated data routes; each screen has its own script, its own server page gate and its own tests. The question is how they come into one menu without rebuilding them, and without weakening a single gate.
|
|
15
|
+
|
|
16
|
+
## 2. The decision
|
|
17
|
+
|
|
18
|
+
### 2.1 The menu is the Settings page
|
|
19
|
+
|
|
20
|
+
`/settings` is the options menu (`options-menu.js`). Its left rail is a search box over a grouped list. Settings' own panels stay where they were, as the menu's **native** entries (Account, Access and keys, Preferences, Sound, Software update, Extensions). The profile chip already opened `/settings`, every doc and skill already links `/settings#cli` and friends, and all of those keep working.
|
|
21
|
+
|
|
22
|
+
### 2.2 The other six screens open inside it, in a frame
|
|
23
|
+
|
|
24
|
+
Each is an **embedded** entry: the menu appends a `<section>` holding an `<iframe>` of the old address with `?embed=1`, the first time that entry opens (so a screen's reads are paid only when someone asks for it). One script every hall page already loads first, `shell-game.js`, reads `?embed=1` **only when the page really is inside a frame** and then:
|
|
25
|
+
|
|
26
|
+
- stamps `html[data-embed="on"]`, which hides the sidebar, scrim, foot and top bar (`style.css`);
|
|
27
|
+
- turns the full-screen switch off for that page (no corner button, no Escape-to-leave);
|
|
28
|
+
- sends an Escape nobody used to the menu (`parent.OTBOptions.escape()`);
|
|
29
|
+
- opens a link to *another* page in the whole window (`target="_top"`), while a link within the page stays in the frame.
|
|
30
|
+
|
|
31
|
+
The screens themselves change by nothing, except Market Watch: its owner-only Settings tab (task 1005045) is gone, and in the frame the page shows that panel alone.
|
|
32
|
+
|
|
33
|
+
### 2.3 Every old address leads into the menu, and every gate stays where it was
|
|
34
|
+
|
|
35
|
+
`serve-internal.js` `RETIRED_TO_OPTIONS` sends a plain visit to `/my-agents`, `/project-settings`, `/modules`, `/government`, `/market-watch-rules` or `/market-watch-settings` to `/settings?open=<entry>` (302, no gate, like the other retired-page redirects). The Location carries no fragment, so the browser keeps the old `#anchor`: `/my-agents#talk` lands on `/settings?open=my-agents#talk`. The framed request (`?embed=1`) passes through to the page **and its own page gate**: `/government?embed=1` still meets `requireGovernmentPage`, and every data route keeps its own atom. The menu lists an entry only for the rank the sidebar showed its page to (the same keys as `gateAllows`), which is cosmetic, as the sidebar was.
|
|
36
|
+
|
|
37
|
+
### 2.4 Game mode's last Escape is the menu's
|
|
38
|
+
|
|
39
|
+
ADR 0399 reserved it. In game mode an Escape no dialog, picker, palette or page used opens the menu (`/settings?from=<where you were>`); on the menu, or inside one of its frames, it closes the menu and goes back to `from`. It is judged after the dispatch and marked used before the shell's own check, so the bars do not flash back. Outside game mode nothing about Escape changed. The corner button is still the way to bring the bars back.
|
|
40
|
+
|
|
41
|
+
## 3. Consequences
|
|
42
|
+
|
|
43
|
+
- The sidebar loses My agents, Project settings, Permissions and Modules; the profile chip says "Options". The palette's My agents rows open the menu; its Government rows are gone (the menu's search finds them, for the ranks that may).
|
|
44
|
+
- A new settings screen joins the menu as one `MENU` entry in `options-menu.js` (and, if it was a page, one row in each redirect map — `tests/hall_options_menu.mjs` holds the two maps equal).
|
|
45
|
+
- The frame is a second document: its own dialogs, toasts and scroll live inside it. That is the price of reusing the screens as they are; a screen that needs the whole window can always send a link to `_top`.
|
|
46
|
+
- **Sounds are switched off** (task 1004554), so the criterion's proof "change a sound preference" reaches the Sound entry and its note, not a working toggle, until sounds come back.
|
|
47
|
+
|
|
48
|
+
## 4. Alternatives refused
|
|
49
|
+
|
|
50
|
+
- **Move every screen's markup and script into `settings.html`.** Seven pages' scripts on one page, all booting at once, with id collisions to rename (the Watch tabs, task 1005049, paid that for two small pages). Permissions alone would have doubled the page. Refused for size, risk and the boot cost on the one page every builder opens to change a setting.
|
|
51
|
+
- **A new `/options` page beside Settings.** Two homes for settings is the problem being solved; every existing `/settings#…` link would need a second redirect.
|
|
52
|
+
- **Leave Permissions and Market Watch rules as links out of the menu.** Offered; the owner chose all seven, because a link out is still a surface with its own interface.
|
|
53
|
+
- **Load the screens into the menu with `fetch` and inject them.** The pages boot on `DOMContentLoaded`, which has already fired; every script would need a second boot path. The frame gives each its own document for free.
|
package/docs/adr/README.md
CHANGED
|
@@ -514,3 +514,6 @@ These 20 numbers are each shared by exactly two files. They are **accepted histo
|
|
|
514
514
|
| 0395 | [**A task says what it needs, and each person's lists show only what they can do** ([task 1004950](https://cloudbongos.com/builders#/task/1004950)). `tasks.needs` ⊆ {owner, server} is its own set, not an `automation_tag` value (that one says whether work runs unattended). Capabilities are read fresh like rank: `owner` from the owner seat (founding builder fallback, the UAT reading), `server` from `builders.capability_grants`, set only by the owner. The recommend lists (claimable feed, optimizer, autonomous runner) show only tasks whose needs the viewer holds; the runner never holds owner. The claim refuses only `server` (`NEEDS_SERVER_ACCESS`, all three surfaces). Visibility elsewhere is unchanged; the board filters by need.](0395-a-task-says-what-it-needs-and-lists-show-only-what-you-can-do.md) | lifecycle / work tracking |
|
|
515
515
|
| 0397 | [**The payment rail is Stripe Connect, one connected account per project; J.P. Morgan Payments is the fallback** ([task 1004906](https://cloudbongos.com/builders#/task/1004906), goal 1000092). The owner chose Stripe on 2026-10-30. Each project holds its money in its own connected account and each payee has one, so Cloud Bongos holds nothing (ADR 0385). Every flow in the ADR 0385 map is named against a Stripe primitive; a processor adapter module is the only place that names Stripe, so the fallback replaces one adapter. The processor is the party that monitors the money it holds. Test mode first; no live key is created, and counsel items 1 to 4 still gate real money.](0397-the-payment-rail-is-stripe-connect-with-one-connected-account-per-project.md) | economy / payments |
|
|
516
516
|
| 0398 | [**Every hosted project takes its own update, and nobody asks for one** ([task 1005128](https://cloudbongos.com/builders#/task/1005128)). "Ask for this upgrade" is gone from every hall. A hosted hall with no upgrade address still names its hub door, by its own web address (`/deploy?host=`), which the hub resolves among the visitor's own projects; every core move writes the missing address into the project's settings. A self-hosted instance keeps the `bongos upgrade` instruction.](0398-every-hosted-project-takes-its-own-update-and-nobody-asks-for-one.md) | upgrades / hosting |
|
|
517
|
+
| 0399 | [**The visor is glass over the scene, owns no camera, and spends Escape in a fixed order** ([task 1005146](https://cloudbongos.com/builders#/task/1005146), goal 1000142). The first-person HUD is one DOM overlay (`visor.js`, game mode only) over the sky, the Governor City and Home's city. It passes pointers through, never draws inside a scene and never changes the stage's size. It writes no camera: it calls the scene's own `fitAll`/`flyTo`, which the scene registers. Stacking: scene → ambient glass → the scene's pop-ups → the visor's open sheet → modals. One Escape closes one layer, top first: dialog, picker, palette, visor sheet (capture listener, `stopPropagation`), the scene's pop-up (bubble listener, `preventDefault`), then the options menu in game mode or the shell outside it. Found: the city card's Escape does not call `preventDefault`, so it also drops the bars.](0399-the-visor-is-glass-over-the-scene-and-owns-no-camera.md) | hall / game frame |
|
|
518
|
+
| 0401 | [**One options menu opens every settings screen in a frame** ([task 1005144](https://cloudbongos.com/builders#/task/1005144), goal 1000141). `/settings` is the options menu: a search box over a grouped list. Settings' own panels stay native; My agents, Project settings, Modules, Permissions and Market Watch's settings and rules open inside it in an `<iframe>` of the old address with `?embed=1`, which `shell-game.js` reads only inside a frame to drop the page's chrome, send an unused Escape to the menu and open links to other pages in the whole window. A plain visit to an old address 302s to `/settings?open=<entry>` (the old #anchor rides along); the framed request keeps its own page gate and routes. In game mode the last Escape opens the menu and closes it again. Rejected: merging seven pages' scripts into one, a second /options page, links out of the menu.](0401-one-options-menu-opens-every-settings-screen-in-a-frame.md) | hall / game frame |
|
|
519
|
+
| 0400 | [**A chain reserves work; each sub-quest is still claimed on its own** ([task 1005158](https://cloudbongos.com/builders#/task/1005158), spike V3G.R18, goal 1000144). C5 of the game conversion: work is claimed as a chain, not picked from a flat table. Owner ruling (interview answer 3): a chain RESERVES, tasks are still claimed one at a time. **Decision:** three new tables (`chains` inside one goal, `chain_tasks` with a task in at most one open chain, `chain_party`), none of them a claim — no `claims` row, no session binding, no worktree — so `gateOneActiveClaimPerSession` (ADR 0097) and its unique index never see a chain. **Order is derived, never stored** (ADR 0153's rejection holds): the topological order of `task_dependencies` over the chain's members, ties by priority/estimate/id — `sequence.js`'s `topoOrder`, moved into one shared module. Every sub-quest claims through the unchanged `POST /claims` ladder. **The one addition** is a narrowing-only `CHAIN_RESERVED` check placed AFTER the last existing rung on both insert sites + the dry run + the feed: an outsider can't claim a reserved chain's sub-quest, while every existing refusal keeps its code, message and precedence. Party size (raid quorum vs routine) is refused at the chain's own join door, never in the claim ladder; character counts seats and is never read by a claim rung. A reservation lapses after days with no claim or ship, reported before it acts (ADR 0226). Rejected: a chain as N claims, loosening the session guard, chain = goal, a stored order, an early-ladder check (would mask rank/deps refusals), a feed-only reservation.](0400-a-chain-reserves-work-and-each-sub-quest-is-still-claimed-alone.md) | lifecycle / claims / game conversion |
|