@bongos/core 1.24.79 → 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 +495 -350
- 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 +2 -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 +70 -0
- package/scripts/bongos/autobongos-loop.js +1 -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/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 +1 -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
|
@@ -142,7 +142,9 @@
|
|
|
142
142
|
if (!res.ok) {
|
|
143
143
|
// the envelope (ADR 0116) nests the sentence under `error`; older handlers answer flat
|
|
144
144
|
const env = data.error && typeof data.error === 'object' ? data.error : null;
|
|
145
|
-
|
|
145
|
+
const e = new Error((env && env.message) || data.message || (typeof data.error === 'string' ? data.error : '') || `${path} → ${res.status}`);
|
|
146
|
+
if (env && env.code) e.code = env.code; // the repo invite branches on repo_scope_required
|
|
147
|
+
throw e;
|
|
146
148
|
}
|
|
147
149
|
return data;
|
|
148
150
|
}
|
|
@@ -276,6 +278,10 @@
|
|
|
276
278
|
const ghost = (attrs, label, danger = false) =>
|
|
277
279
|
`<button type="button" class="btn-ghost${danger ? ' btn-ghost--danger' : ''}" ${attrs}>${label}</button>`;
|
|
278
280
|
|
|
281
|
+
// The GitHub repository half of an invite (watch-repo-invite.js): a separate door from
|
|
282
|
+
// the hall invite, and always read-only.
|
|
283
|
+
const repoInvite = window.OTBWatchRepoInvite.make({ api, API, postJson, $ });
|
|
284
|
+
|
|
279
285
|
// =========================================================================
|
|
280
286
|
// 1. GATE — access requests (pending)
|
|
281
287
|
// =========================================================================
|
|
@@ -299,8 +305,10 @@
|
|
|
299
305
|
'<label class="ov-field__l" for="gate-invite-login">Invite by GitHub username</label>' +
|
|
300
306
|
'<input type="text" id="gate-invite-login" name="github_login" autocomplete="off" placeholder="e.g. octocat" maxlength="40">' +
|
|
301
307
|
'</div>' +
|
|
308
|
+
repoInvite.formFieldsHtml() + // the GitHub repository is a separate door
|
|
302
309
|
'<button type="submit" class="btn-accent">Invite</button>' +
|
|
303
310
|
`<p class="ov-form__why">${escapeHtml(why)}</p>` +
|
|
311
|
+
repoInvite.explainerHtml() +
|
|
304
312
|
'</form>'
|
|
305
313
|
);
|
|
306
314
|
}
|
|
@@ -337,11 +345,14 @@
|
|
|
337
345
|
const login = ((input && input.value) || '').trim().replace(/^@/, '');
|
|
338
346
|
if (!login) { toast('A GitHub username is needed.'); return; }
|
|
339
347
|
const btn = form.querySelector('button[type="submit"]');
|
|
348
|
+
const repo = repoInvite.readForm(form);
|
|
340
349
|
if (btn) btn.disabled = true;
|
|
341
350
|
try {
|
|
342
351
|
const r = await postJson('/access-requests/invite', { github_login: login });
|
|
343
352
|
toast(r.already_invited ? `@${login} is already invited.` : `@${login} invited — their sign-in gets in.`);
|
|
353
|
+
const repoResult = repo.want ? await repoInvite.inviteToRepo(login) : null;
|
|
344
354
|
await loadGate();
|
|
355
|
+
if (repoResult) repoInvite.showRepoNote(repoResult);
|
|
345
356
|
} catch (err) {
|
|
346
357
|
if (err && err.kind === '401') return;
|
|
347
358
|
if (btn) btn.disabled = false;
|
|
@@ -493,7 +504,9 @@
|
|
|
493
504
|
// the only move, so the row offers none.
|
|
494
505
|
if (r.expired) return '';
|
|
495
506
|
if (r.status === 'invited') {
|
|
496
|
-
|
|
507
|
+
// The GitHub repository is its own door: check where this person stands on it, and
|
|
508
|
+
// send (or re-send) a read-only invite. A Google-only member has no GitHub name.
|
|
509
|
+
return repoInvite.rowButtonHtml(r, ghost) + ghost(`data-gate-action="dismissed" data-gate-from="invited" data-id="${id}"`, 'Rescind', true);
|
|
497
510
|
}
|
|
498
511
|
if (r.status === 'dismissed') return '';
|
|
499
512
|
return ghost(`data-gate-action="invited" data-id="${id}"`, 'Invite')
|
|
@@ -533,6 +546,7 @@
|
|
|
533
546
|
vouchedHandleHtml(r, !!profile) +
|
|
534
547
|
`<span class="ov-row__when">Asked ${escapeHtml(fmtDate(r.created_at))}</span>` +
|
|
535
548
|
decided +
|
|
549
|
+
repoInvite.rowStateHtml(r) +
|
|
536
550
|
'</div>' +
|
|
537
551
|
'</div>' +
|
|
538
552
|
(actions ? `<div class="ov-row__right"><div class="ov-row__actions">${actions}</div></div>` : '') +
|
|
@@ -638,6 +652,7 @@
|
|
|
638
652
|
if (requests.length) {
|
|
639
653
|
wireActions(target, '[data-gate-bulk]', (btn) =>
|
|
640
654
|
inviteAll(String(btn.getAttribute('data-ids') || '').split(',').filter(Boolean)), 'Could not invite');
|
|
655
|
+
wireActions(target, '[data-gate-gh]', repoInvite.gateGithubStep, 'Could not check GitHub');
|
|
641
656
|
wireActions(target, '[data-gate-action]', async (btn) => {
|
|
642
657
|
const id = btn.getAttribute('data-id');
|
|
643
658
|
const status = btn.getAttribute('data-gate-action');
|
|
@@ -10,8 +10,9 @@
|
|
|
10
10
|
// hall underneath.
|
|
11
11
|
//
|
|
12
12
|
// Rules:
|
|
13
|
-
// - A signed-in builder sees it once per LOCAL day
|
|
14
|
-
//
|
|
13
|
+
// - A signed-in builder sees it once per LOCAL day. A fresh sign-in (the sign-in click leaves a
|
|
14
|
+
// flag in localStorage that the return visit consumes) opens on the game's start screen
|
|
15
|
+
// instead (task 1005143, shell-game.js); without that file it is greeted here as before. Storage that
|
|
15
16
|
// throws cannot remember, so such a browser is never shown it (it would replay on every visit).
|
|
16
17
|
// - A visitor who is not signed in sees the Welcome on Home, every visit, with a "Sign in with
|
|
17
18
|
// GitHub" button in place of the role choices. Only on Home, never over a deep link (#/task/N, #/idea/N).
|
|
@@ -73,11 +74,12 @@
|
|
|
73
74
|
|
|
74
75
|
// ---------- the roles (the owner's mapping) ----------
|
|
75
76
|
// `mode` is the craft mode the pick sets; `href` null means stay on Home.
|
|
77
|
+
// The game's three characters (task 1005141): Owner became Patron, and the
|
|
78
|
+
// ideator's and the artist's doors are one Artist door (the studio).
|
|
76
79
|
var ROLES = [
|
|
77
|
-
{ id: '
|
|
78
|
-
{ id: '
|
|
79
|
-
{ id: '
|
|
80
|
-
{ id: 'engineer', label: 'Engineer', room: 'Home', href: null, mode: 'building', dot: '#60a5fa' },
|
|
80
|
+
{ id: 'patron', label: 'Patron', room: 'City', href: '/city', mode: 'patron', dot: 'var(--accent)' },
|
|
81
|
+
{ id: 'artist', label: 'Artist', room: 'Studio', href: '/studio', mode: 'artist', dot: '#f472b6' },
|
|
82
|
+
{ id: 'artisan', label: 'Artisan', room: 'Home', href: null, mode: 'artisan', dot: '#60a5fa' },
|
|
81
83
|
];
|
|
82
84
|
function rolesFor(craft) {
|
|
83
85
|
return ROLES.filter(function (r) { return !craft || typeof craft.offered !== 'function' || craft.offered(r.mode); });
|
|
@@ -382,6 +384,13 @@
|
|
|
382
384
|
} catch (_) { return false; }
|
|
383
385
|
shown = true;
|
|
384
386
|
var c = craft();
|
|
387
|
+
// A fresh sign-in opens on the game's start screen instead (task 1005143, shell-game.js): the
|
|
388
|
+
// same still behind it, and the craft picker asked once the world is showing.
|
|
389
|
+
var game = window.OTBShellGame;
|
|
390
|
+
if (fresh && game && typeof game.start === 'function' && game.start({
|
|
391
|
+
name: projectName(window.__BRANDING__), art: artFor(timeOfDay(now)),
|
|
392
|
+
done: function () { if (c && typeof c.onAccess === 'function') c.onAccess(access, builder); },
|
|
393
|
+
})) return true;
|
|
385
394
|
if (c && typeof c.markAsked === 'function') c.markAsked();
|
|
386
395
|
show(builder);
|
|
387
396
|
return true;
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
<link rel="icon" href="/modules/ui-design/public/brand/favicon.svg" type="image/svg+xml">
|
|
9
9
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
10
10
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
11
|
-
<link rel="stylesheet" href="/builders/style.css?v=2026-
|
|
11
|
+
<link rel="stylesheet" href="/builders/style.css?v=2026-11-10-options">
|
|
12
12
|
<!-- Page-local styles (task 2170) — extracted from the old inline <style>
|
|
13
13
|
block per the hall placement rules; shared pager/count-pill styles now
|
|
14
14
|
live in style.css's hall-kit section. -->
|
|
@@ -172,10 +172,10 @@
|
|
|
172
172
|
<!-- The app shell (sidebar + top bar + footer). Dependency-free; runs at parse
|
|
173
173
|
time so the chrome exists before the deferred page scripts execute. -->
|
|
174
174
|
<script src="/builders/dom-utils.js?v=2026-11-05-numbers"></script>
|
|
175
|
-
<script src="/builders/shell-game.js?v=2026-11-
|
|
175
|
+
<script src="/builders/shell-game.js?v=2026-11-10-options"></script>
|
|
176
176
|
<script src="/builders/shell-trail.js?v=2026-11-05-numbers"></script>
|
|
177
|
-
<script src="/builders/craft-mode.js?v=2026-11-
|
|
178
|
-
<script src="/builders/shell.js?v=2026-11-
|
|
177
|
+
<script src="/builders/craft-mode.js?v=2026-11-10-visor"></script>
|
|
178
|
+
<script src="/builders/shell.js?v=2026-11-10-character"></script>
|
|
179
179
|
<script src="/builders/hall-dialog.js"></script>
|
|
180
180
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
181
181
|
<script src="/builders/palette.js" defer></script>
|
|
@@ -192,7 +192,7 @@
|
|
|
192
192
|
<script src="/builders/mine-lens.js" defer></script>
|
|
193
193
|
<!-- the Completed tab's project-wide momentum card (window.OTBWorkSummary), carved out of work.js. -->
|
|
194
194
|
<script src="/builders/work-summary.js" defer></script>
|
|
195
|
-
<script src="/builders/task-detail.js?v=2026-
|
|
195
|
+
<script src="/builders/task-detail.js?v=2026-11-10-options" defer></script>
|
|
196
196
|
<script src="/builders/brand-apply.js?v=2026-06-19-r56" defer></script>
|
|
197
197
|
<script src="/builders/bulk-toolbar.js" defer></script>
|
|
198
198
|
<script src="/builders/work.js?v=2026-09-30-bulktoolbar" defer></script>
|
|
@@ -11,12 +11,12 @@ Pinned by `tests/hall_nav.mjs` (the Community group's middle id is `roster`) and
|
|
|
11
11
|
|
|
12
12
|
## The roles (task 1004437, WA6.RP07)
|
|
13
13
|
|
|
14
|
-
Owner decision (b), 2026-09-30: the leaderboard gets BOTH a column naming each builder's roles and the Everyone / Engineers / Artists / Ideators toggle above it. The approved mock is `docs/design/mocks/profile-roles/` (`?state=board`, `?state=board-artists`).
|
|
14
|
+
Owner decision (b), 2026-09-30: the leaderboard gets BOTH a column naming each builder's roles and the Everyone / Engineers / Artists / Ideators toggle above it (Everyone / Artisans / Artists since task 1005141, `roster.js` `ROLE_CHIPS`). The approved mock is `docs/design/mocks/profile-roles/` (`?state=board`, `?state=board-artists`).
|
|
15
15
|
|
|
16
16
|
- **The roster now reads `GET /public/leaderboard`,** the list the status page reads, which carries each row's `roles` (`src/bongos/role-stats.js` `readRolesForBuilders`: the profile's own main/shown rules, two reads for the whole page) and, since this task, `karma`. The hall and the public page cannot rank a role differently. The authed `/leaderboard` is unchanged and no longer read by the hall.
|
|
17
17
|
- **Roles column:** one pill per role in `roles.shown`, the main one a step stronger. `shown` is the main role plus every craft the builder has EARNED in, so it is evidence of work, not only a declared preference.
|
|
18
18
|
- **The toggle** keeps the builders a craft is shown for and ranks them by the credits that craft earned (`roles.credits_by_craft`, in the row: ADR 0255). The place column becomes the place inside that craft, the credits header says "Credits as artist", and the karma/rank/tokens lenses still apply on top.
|
|
19
|
-
- **Tokens only where they apply.** A builder with no recorded AI session (an artist in the studio
|
|
19
|
+
- **Tokens only where they apply.** A builder with no recorded AI session (an artist in the studio or in the room) reads a dash, and the cell's tooltip says no AI sessions were recorded, instead of a 0 and a "0 tokens per credit" figure that read as "did nothing".
|
|
20
20
|
- **Home's Standing card** reads the same list and adds "#N as an artist" beside "#N on the leaderboard" when the place inside the builder's main role differs from the overall one (`hall-render.js` `rolePlaceText`).
|
|
21
21
|
- **The status page** names each builder's roles under their name, on that page's own palette (`status.js` `renderRoles`).
|
|
22
22
|
|
|
@@ -4,10 +4,12 @@ Covers: every shelled hall page (`craft-mode.js`, `shell.js`, `style.css`), and
|
|
|
4
4
|
|
|
5
5
|
## What it is
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
7
|
+
> **Renamed by task 1005141.** The four modes are three now: Building is **Artisan** (`artisan`), Artistry and Ideating are one **Artist** (`artist`), Governing is **Patron** (`patron`). A mode stored under an old id is read as the new one (`LEGACY_MODES`). Lines below that name the old modes are the record of what was built.
|
|
8
|
+
|
|
9
|
+
- On entering the hall, once per browser session, a signed-in builder is asked **"What are you doing now?"**: Artisan, Artist or Patron (Building, Artistry, Ideating or Governing until task 1005141). A fifth choice, **Legacy mode** (2026-10-01: the hall exactly as it was), was removed in task 1004567 (owner, 2026-10-04: "builder has all those tabs anyways"); a browser that still has `legacy` stored reads it as no mode, because `valid()` ignores any id that is not a mode. The approved prototype is the design canvas linked on the task; the doors carry its four scenes (the work desk, the night room, the sky, the governor city).
|
|
10
|
+
- The answer is ONE attribute, `html[data-craft="artisan|artist|patron"]`, readable by every hall page. Every change also fires `otb:craft` on `document` with `{ detail: { mode } }`, so a page can react without polling.
|
|
11
|
+
- The top bar carries a switch with all three; pressing one changes the mode without a reload. Under 1180px it drops the words; at phone width only the current mode shows (or a "Choose your mode" button when there is none), and tapping it opens the picker.
|
|
12
|
+
- Artist is pre-selected for a builder whose `main_discipline` is `artist` (or, with no main role, whose first craft is).
|
|
11
13
|
|
|
12
14
|
## The rules an edit here must keep
|
|
13
15
|
|
|
@@ -24,13 +26,13 @@ Covers: every shelled hall page (`craft-mode.js`, `shell.js`, `style.css`), and
|
|
|
24
26
|
## The nav follows the mode (task 1004493)
|
|
25
27
|
|
|
26
28
|
- **Each craft has a named tab list**, `MODE_TABS` in `craft-mode.js`, by NAV id. `ALWAYS_TABS` is the owner's list of tabs no mode may hide (2026-10-01: Builders, NAV id `roster`, first), and every mode's list is `ALWAYS_TABS` plus its own. No mode has no entry, so it shows every tab, as before.
|
|
27
|
-
- **Government shows only in
|
|
29
|
+
- **Government shows only in Patron**, which leads with City and folds its other tabs under More (`MODE_LEAD`). Artisan is Goals, Goal map, Work, Blockers, Your thinking, Studio, Market Watch; Artist is Studio, Goals, Your thinking, Goal map, Market Watch (`MODE_TABS`). The prototype names rooms that do not exist yet (Store, Page reviews, Treasury); a list names only real NAV items, and `tests/craft_mode_nav.mjs` requires every NAV item to sit in some mode.
|
|
28
30
|
- **The mode only ever takes away, and never through `hidden`.** The access gate owns `hidden`; `applyNav()` marks what the mode leaves out with `[data-craft-off]`, which `style.css` hides. So a mode can never show a tab the gate hid, and switching mode just moves the attribute. A group head goes too once nothing under it shows.
|
|
29
31
|
- **Two callers.** `apply()` runs it on every mode change (live, no reload), and `shell.js` `applyAccess` runs it right after its gate loop, so a later `/me` answer (a promotion, a permission) brings a head back with its tabs. Hidden tabs still open by their URL; nothing is enforced (ADR 0016).
|
|
30
32
|
|
|
31
33
|
## Each mode's look (task 1004495)
|
|
32
34
|
|
|
33
|
-
- **
|
|
35
|
+
- **Two modes wear a look; Artisan and no mode wear none.** Artist and Patron each set `--craft` (where you are) and `--craft-on` (text on it) on `html[data-craft="<mode>"]`, with a dark twin on `html[data-theme="dark"][data-craft="<mode>"]` that also darkens the ground and tints the glass. Values and contrast are the direction's, `docs/design/craft-mode-direction.md`. No rule in `style.css` names `artisan`, and none matches any mode at all; `tests/craft_mode_looks.mjs` pins both, and re-measures every colour pair.
|
|
34
36
|
- **The accent stays the action colour.** `--craft` paints only the switch's current pill, the current tab (tint, icon, label, marker) and the top bar's hairline.
|
|
35
37
|
- **Two pieces are drawn by `craft-mode.js` `applyLook()`, on every mode change:** the eyebrow beside `#topbar-title` (`LOOKS`: "the studio · night", "the sky", "the city"; hidden at <=640px, where it overflowed phones) and the scene plate under `.app-sidebar__brand` (40px closed rail, 64px open). The plate's markup IS `artHtml(mode)`, the picker's door art, exported rather than copied; light mode recolours it to each scene's day (the city is the dark one through `invert(1) hue-rotate(180deg)`). It does not animate.
|
|
36
38
|
- **Always-present tabs widened** (owner, 2026-10-03): `ALWAYS_TABS` is Builders, Collab and Profile, so every mode keeps the You and Community groups.
|
|
@@ -38,7 +40,7 @@ Covers: every shelled hall page (`craft-mode.js`, `shell.js`, `style.css`), and
|
|
|
38
40
|
|
|
39
41
|
## The paintbrush (task 1004497)
|
|
40
42
|
|
|
41
|
-
- **
|
|
43
|
+
- **Artist carries the palette and the paintbrush** (and the lightbulb, below): the palette (a feedback doc, `page-notes.js`, record `page-notes.md`) and the paintbrush (`paintbrush.js`). Both are `TOOLS` entries in `craft-mode.js` and load their own script on first press.
|
|
42
44
|
- **The paintbrush edits the page's own words where they stand, as a REAL wording change** (owner, 2026-10-04): it is the copy desk's page round, the same one the tweak editor and the studio's own words write (ADR 0341). Pressing it reads `GET /copy-desk/pages/builders:<page>/draft`; a page nobody holds is OFFERED, never taken silently (taking it is the copy desk's artists-only claim, and the page shows as being tweaked while held). Typing saves the whole draft; "Review" lists every change as was/now; "Send for approval" submits the round. It never writes `page-notes` (owner: kept separate from the feedback docs).
|
|
43
45
|
- **Only a leaf element inside `<main>` whose words are one reading line becomes editable.** Shared chrome, a line with a `{…}` hole, controls (`button`, form fields, `code`), and anything hidden stay as they are; the bar counts the lines it cannot reach and links to the tweak editor for them. A click on edited words inside a link does not navigate.
|
|
44
46
|
- **Nobody else's view changes, and neither does yours once editing ends**: "Stop editing" and "Send" both put the page's own words back. The draft stays on the round.
|
|
@@ -47,20 +49,20 @@ Covers: every shelled hall page (`craft-mode.js`, `shell.js`, `style.css`), and
|
|
|
47
49
|
|
|
48
50
|
### Removing a line, and the artist review alongside (task 1004696)
|
|
49
51
|
|
|
50
|
-
- **An artist can recommend removing a line** (owner, 2026-10-09: pages carry superfluous subtitles and text). The line the artist is in shows in the bar with **Remove this line**; emptying a line's words and leaving it does the same. A removed line shows the page's own words struck through and faded, is no longer typed into but stays focusable, and **Keep this line** puts it back. Review lists it as its own "Remove" row and says it goes to an engineer. It is saved as `{ key, remove: true }` (the copy desk's rule, `modules/copy-desk/CLAUDE.md`), so the send files an
|
|
52
|
+
- **An artist can recommend removing a line** (owner, 2026-10-09: pages carry superfluous subtitles and text). The line the artist is in shows in the bar with **Remove this line**; emptying a line's words and leaving it does the same. A removed line shows the page's own words struck through and faded, is no longer typed into but stays focusable, and **Keep this line** puts it back. Review lists it as its own "Remove" row and says it goes to an engineer. It is saved as `{ key, remove: true }` (the copy desk's rule, `modules/copy-desk/CLAUDE.md`), so the send files an artisan task to take it out.
|
|
51
53
|
- **The artist review is one press away**: **Artist review** in the editing bar saves the words and opens the palette's sheet (`page-notes.js`, loaded on demand like a tool) over the page; editing carries on when it closes. Once the words are sent, the bar asks "Review how this page looks too?" with **Start an artist review** (closes the bar, opens the sheet) and **Not now**. The paintbrush still writes no feedback doc itself: `tests/paintbrush.mjs` allows `page-notes.js` as the only page-notes name in the file.
|
|
52
54
|
|
|
53
55
|
## The lightbulb (task 1004498)
|
|
54
56
|
|
|
55
|
-
- **
|
|
56
|
-
- **Only the ideas remain** (owner, 2026-10-04). `POST /page-notes/ideas` splits the notes with the palette's AI split (
|
|
57
|
+
- **The lightbulb** (`lightbulb.js`, a `TOOLS` entry loaded on first press) was Ideating's one tool and is the Artist's third since task 1005141. Its button wears its own note glyph, not the mode's lightbulb, so it is never read as the Ideating pill beside it (owner, 2026-10-04). It is a watered-down palette: the same side sheet and `.pn` styles, text only, no uploads.
|
|
58
|
+
- **Only the ideas remain** (owner, 2026-10-04). `POST /page-notes/ideas` splits the notes with the palette's AI split (the notes wording, once the ideator's; one idea if the split cannot run) and files each idea under its author, its body ending in a link to the page. Nothing else is stored: no doc row, no reference doc. The split answers inside the request, so it gives up after 45 seconds and files the notes whole.
|
|
57
59
|
- **The panel lists the ideas already filed from this page** (`GET /page-notes/ideas?page_path=`): open and promoted ideas whose body carries the page's link, from the lightbulb (`](/page)`) or the palette (`](/page?note=`). That link is the only record of where an idea came from, so `notes.pageLinks` and the two idea bodies are pinned together in `tests/lightbulb.mjs`.
|
|
58
60
|
- **Unsent text waits in this browser only**, per page (`localStorage 'hall-lightbulb:<path>'`), and is forgotten once it files.
|
|
59
61
|
- `tests/lightbulb.mjs` runs the real routes and the real script over a small DOM.
|
|
60
62
|
|
|
61
63
|
## Artist review mode (task 1004686)
|
|
62
64
|
|
|
63
|
-
- **Review is a split pill** (owner, 2026-10-09): pressing Review still opens the feedback doc; hovering it with a mouse, or pressing its chevron, opens a menu: "Write feedback on this page", then the
|
|
65
|
+
- **Review is a split pill** (owner, 2026-10-09): pressing Review still opens the feedback doc; hovering it with a mouse, or pressing its chevron, opens a menu: "Write feedback on this page", then the experiences in the owner's order (Ideator, Governing, Building, Artistry experience when written; since task 1005141 three: Patron, Artisan, Artist experience), then "Stop reviewing" while a review is on. Hover is asked of the pointer (`pointerType === 'mouse'`), never `(hover: hover)`: a touch laptop can report no hover at all. On a phone (<=640px) the chevron folds away and a tap on Review opens the menu.
|
|
64
66
|
- **Picking one makes the hall wear that mode** (`html[data-craft]`, so its tabs, look, eyebrow and tallies follow) and stamps `html[data-craft-review]`. The artist's own mode stays Artistry: `sessionStorage['hall-craft-review']` holds the experience for the session only, and is ignored unless the mode is Artistry. Choosing any mode from the switch or the picker ends it. The artist keeps Review and Edit words; the experience's own tools follow them, marked `craft-tool--guest` so a phone under 360px can fold them away (three tools pushed 320px 36px sideways; Artistry alone overflows 4px there today, before and after).
|
|
65
67
|
- **The scribble wall** (`craft-review.js`, loaded on demand; `craft-review.css`, imported by `style.css`): a flexible box in the top bar's empty space where a pen tip scribbles six small doodles in the sky's hand (thinking.css: hairlines, stars, a dashed orbit, a constellation, a crescent, a shooting star, a looped scribble, sparks), each at its own spot and height, a new one every 5s of a 30s round and each up about 10s, so two or three show at once. **Ink alone** (owner, 2026-10-09, after a first cut of big painted colour tags: "small black white graffiti scribbling"): every mark is `--ink`, black on the light bar and white on the dark, with the sky's fainter ladder for trails and orbits; the test holds the wall section to that one token. No doodle is wider than 56px or taller than 24px; the two widest fold away on a wall under 58px (Governing at 1440px keeps about 60), all of them under 34px and on a phone. The wipe is two opposite `translateX` moves, so every motion is transform or opacity in CSS, and the kill switch leaves three doodles standing, finished, with no pen. A doodle not yet begun keeps its pen unseen (`gx-track` starts at opacity 0), or each waiting tip shows as a stray dot.
|
|
66
68
|
- **An @import lands before style.css's own rules**, so a rule in `craft-review.css` that restyles `.craft-tool` needs two classes, or `.craft-tool` silently wins (it did, for the reviewing wash and the guest fold, until measured).
|
|
@@ -7,7 +7,7 @@ Covers: every shelled hall page (`shell-game.js`, `shell.js`). Spec: `docs/specs
|
|
|
7
7
|
- **Game mode is the existing full-screen switch, made hall-wide. There is no second full-screen mode.** The switch was already on every page (task 1004430) but remembered per page, so a reader had to turn it on 33 times. Game mode is one `localStorage` key, `hall-game`; while it is `on`, `shell.js` `storedFullscreen()` answers yes for every page, whatever that page remembers. What hides, the corner button and the Escape hand-off are the shell's, unchanged.
|
|
8
8
|
- **`shell-game.js` holds the mode and nothing else**: `window.OTBShellGame` = `on()`, `set(bool)`, `hint()`. It stamps `html[data-game="on"]` for a sheet or script that wants to read the mode. `shell.js` reads it through a fallback object, so a page without the file is never in game mode. It is its own file because `shell.js` sits on the 1,500-line ratchet; the start screen and options menu (R03, R04) are expected to grow here, not in `shell.js`.
|
|
9
9
|
- **Load order**: `shell-game.js` before `shell-trail.js` / `craft-mode.js` / `shell.js`, loaded the same way (deferred or not) as the shell on that page. Test-pinned.
|
|
10
|
-
- **Leaving is for this page load only.** In game mode the corner button
|
|
10
|
+
- **Leaving is for this page load only.** In game mode the corner button brings the bars back (Escape did too until task 1005144; it opens the options menu now), and nothing is written: the next page opens without them again, and a page's own `hall-fullscreen:<page>` memory is never overwritten. Turning game mode off (`set(false)`) hands each page back what it remembered. `OTBShell.setFullscreen(null)` is the "re-read what should show" call `set()` uses.
|
|
11
11
|
- **No page may opt out.** `<body data-fullscreen-switch="off">` would keep that page's sidebar in game mode; the test fails on one. A new hall page needs `#app-topbar` and the `shell-game.js` tag, like the rest.
|
|
12
12
|
- **The "how to leave" line shows once per tab in game mode** (`sessionStorage 'hall-game-hint'`), not on every page load. Outside game mode the shell's rule is unchanged.
|
|
13
13
|
- **How it is turned on today**: `?game=on` / `?game=off` on any hall URL, or `OTBShellGame.set()`. Nothing in the hall's interface sets it yet; the start screen (R03) is where that lands.
|
|
@@ -15,6 +15,6 @@ Covers: every shelled hall page (`shell-game.js`, `shell.js`). Spec: `docs/specs
|
|
|
15
15
|
## For the tasks after this one
|
|
16
16
|
|
|
17
17
|
- A HUD or options menu that wants Escape must call `preventDefault()` on the press. `shell.js` `onFullscreenKey` waits one tick before leaving so a listener added after it still wins.
|
|
18
|
-
-
|
|
18
|
+
- Since R04 (task 1005144, ADR 0401) the last Escape in game mode opens the options menu (`shell-game.js` `onEscape`), and on the menu it closes it again. The corner button is still the way back to the bars.
|
|
19
19
|
|
|
20
20
|
Tests: `tests/hall_fullscreen.mjs` (the eight `game mode:` cases run the real `shell-game.js` + `shell.js`), and the script lists in `tests/hall_city.mjs`, `tests/hall_street.mjs`, `tests/hall_my_agents.mjs`, `tests/goal_map_page.mjs`.
|
|
@@ -29,7 +29,7 @@ Files: `street-inside.js` (`window.GovInside`, node-require-safe, pure): the pro
|
|
|
29
29
|
- **The lift and the flip.** The lift is one node kept across draws, so picking a floor slides it by a CSS transform transition; the chosen floor's block is two blocks that take turns (`flipA` / `flipB`), so it re-enters on every pick. Both are dead under reduced motion.
|
|
30
30
|
- **Change how this works** is present and honest: pressed, it says drafting an amendment from here is not built yet (task 1004530 wires it).
|
|
31
31
|
- **No "on the table here" list.** The prototype's list of the building's open matters was removed on the owner's direction (task 1004565): the floor desks carry every matter as an actionable row, so the list was duplication. Inside a building a matter is its desk row; the short card opens from the street's pins.
|
|
32
|
-
- **Districts.** The goal's tasks (`GET /tasks?goal_id=N`, read once per goal): shape from the discipline (tower
|
|
32
|
+
- **Districts.** The goal's tasks (`GET /tasks?goal_id=N`, read once per goal): shape from the discipline (tower artisan, studio artist, glass front UI; none or any other is a tower; the ideator's pavilion went with task 1005141), stage from the status (backlog and blocked a staked plot, ready a slab, active a scaffold, completed and confirmed built with a flag, shipped lit), label the kind; height from the estimate. Up to ten stand on the road, work in flight first; the rest are counted with a link to the goal. Each one opens its task.
|
|
33
33
|
- **Narrow.** Under 900 px the board becomes a column: the drawing in its own sideways strip (never scaled under 0.6, so a floor stays a 24 px target), then the panel.
|
|
34
34
|
|
|
35
35
|
Tests: `tests/hall_street_inside.mjs` runs the prototype's own `Component` beside `street-inside.js` on the prototype's sample floors and holds every building's section, panel bindings and every district equal to it in both modes, then the docket rules (no invented numbers) and the page in a vm (the persistent lift, the flip, the drawers, the amendment note, the card from a table row, back to the street, a district's tasks). The states file renders every building, a floor pick, the amendment note and a district.
|
|
@@ -87,6 +87,8 @@ the builder's Home. Steps 2–4 (the ideator's sky, the artist's gallery, the st
|
|
|
87
87
|
|
|
88
88
|
## v16 step 2 — the ideator's sky (task 1005059)
|
|
89
89
|
|
|
90
|
+
> **Not drawn since task 1005141.** The Ideating mode folded into Artist, so `home-city.js` `craft()` never answers `ideating` and every craft lands in the city; the sky is a door away (Your thinking). The branch and `skySvg` are kept so the sky can come back as its own view. What follows is the record of what step 2 built.
|
|
91
|
+
|
|
90
92
|
The mock is [`v16-ideating.html`](../../../docs/design/mocks/hall/home/v16-ideating.html). While the craft is
|
|
91
93
|
**Ideating** (`OTBCraftMode.current()`, redrawn on `otb:craft`) the same widget, from the same one read, draws
|
|
92
94
|
`home-city-draw.js` `skySvg` instead of the city. Every other craft keeps the builder's city untouched.
|
|
@@ -108,7 +110,7 @@ The mock is [`v16-ideating.html`](../../../docs/design/mocks/hall/home/v16-ideat
|
|
|
108
110
|
new idea (these two weeks) that is open, in no area, not the viewer's, and not yet voted on by them. In the
|
|
109
111
|
week an idea became work it falls into its tower; after that it lights a window there. The moon is the
|
|
110
112
|
version, its phase what the areas have shipped over every task under them (`version.tasks`).
|
|
111
|
-
- **The ladder**
|
|
113
|
+
- **The ladder** (in the dormant sky view) ranked the week's ideators: ideas filed, idea votes cast, and ideas of theirs that became work.
|
|
112
114
|
- **The read stays one and bounded.** `GET /home/city` adds these fields to the ideas list it already sent
|
|
113
115
|
(still newest first, at most 120 rows), plus idea votes per builder per week and a per-area task count.
|
|
114
116
|
The `ideas_votes` table is probed first, so a project with the ideas module off answers without votes.
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# Market Watch settings, the owner's Settings tab on /market-watch (task 1004938; a tab since task 1005045)
|
|
2
2
|
|
|
3
|
+
**Since task 1005144 (ADR 0401) the settings are an options menu entry, not a tab.** The menu opens `/market-watch?embed=1#settings` in its frame and the page shows `#mw-panel-settings` alone; a plain visit is the watch with no tab strip and no settings read, an old `/market-watch#settings` link `location.replace`s to `/settings?open=market-watch`, and `/market-watch-settings` 302s to the same entry (`RETIRED_TO_OPTIONS`). The owner check moved with it: the menu lists the entry for an archon, and the four routes stay the wall. The tab-era notes below are history; see `records/options-menu.md`.
|
|
4
|
+
|
|
3
5
|
**Since task 1005045 (owner decision 2026-11-03, idea 1001310) this is a tab, not a page.** The sidebar showed "Market Watch" twice — the page and these settings — so the settings page is gone and its markup is the `#mw-panel-settings` panel in `market-watch.html`. What that move settled:
|
|
4
6
|
|
|
5
7
|
- **Only the owner gets the strip.** `market-watch.js` adopts the shell's one `/me` read (`window.__hallReads`, no second request); for an archon it builds two kit tabs (`watch`, `settings`, `hash: true`) and calls `OTBMarketWatchSettings.load()`. Anyone else gets no tab strip at all, and their page never asks for the settings. An unreadable `/me` is not an owner. Cosmetic only: the four routes below are still the wall (ADR 0016).
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# The options menu — Settings, and the six screens it opens (task 1005144, BONGOS-V3 R04; ADR 0401)
|
|
2
|
+
|
|
3
|
+
Every setting and configuration is reached from one vertical, grouped menu with a search box at the top. The menu IS `/settings`; the profile chip opens it and says "Options".
|
|
4
|
+
|
|
5
|
+
- **Two kinds of entry** (`options-menu.js` `MENU`). *Native* entries are Settings' own groups (`data-group` in `settings.html`): Account, Access and keys, Preferences, Sound, Software update, Extensions (only when a module contributed a panel). *Embedded* entries open an old page in an `<iframe>` of its address with `?embed=1`: Your agents (`/my-agents`), Project settings, Modules, Permissions and constitution (`/government`), Market Watch settings (`/market-watch#settings`) and Market Watch rules. A frame is created the first time its entry opens, never at boot.
|
|
6
|
+
- **Who sees an entry** is the rank key the old sidebar item used (`signed`, `member`, `government`, `archon`), plus a module gate (`market-watch`). Cosmetic: each framed page keeps its server page gate and its routes.
|
|
7
|
+
- **The search** (`search()`, pure) matches every typed word against a line's label, its `words`, its entry and its group. Each entry can list `anchors` (CLI access, How Claude talks to you, …) so a search lands on the exact place; Enter opens the first line, so the ranking puts a label hit first, then the exact place above the group that merely holds it.
|
|
8
|
+
- **Addresses.** `/settings#<entry>` or `/settings?open=<entry>#<anchor>`; a panel anchor (`#cli`, `#art-key`) still lands as before. The address follows what is open (`replaceState`), and `?from=` survives switches so closing returns.
|
|
9
|
+
- **Embedded pages** (`shell-game.js`, only inside a frame): `html[data-embed="on"]` hides the sidebar, scrim, foot and top bar; the full-screen switch is off; an unused Escape goes to the menu; a link to another page opens in the whole window. A link on the menu's own panels to an old page (Settings' "these moved to My agents" lines) opens that entry in place instead.
|
|
10
|
+
- **Old addresses** 302 to the menu (`serve-internal.js` `RETIRED_TO_OPTIONS`, the twin of `options-menu.js` `RETIRED`); `?embed=1` passes through, except for `/market-watch-settings`, which has no page left.
|
|
11
|
+
- **Game mode.** The last Escape on any page opens the menu (`/settings?from=…`); on the menu or in a frame it closes it. Outside game mode the menu is a page like any other.
|
|
12
|
+
- **Layout.** The rail is sticky beside the open screen and scrolls itself; a frame fills the column to the window's foot. Below 860px the menu stacks above the screen, and choosing an entry scrolls the screen up clear of the top bar.
|
|
13
|
+
- **Left the sidebar:** My agents, Project settings, Permissions, Modules (and their glyphs). The palette's agent rows open the menu; its Government rows are gone.
|
|
14
|
+
- **Tests:** `tests/hall_options_menu.mjs` (the catalogue, gates, search, addresses, both redirect maps, the embedded page, game-mode Escape); `tests/hall_fullscreen.mjs` (Escape in game mode); `tests/market_watch_pages.mjs` (the settings panel in the frame).
|
|
15
|
+
- **Known:** sounds are switched off (task 1004554), so the Sound entry shows its note, not a toggle.
|
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
|
|
5
5
|
## What the page says now
|
|
6
6
|
|
|
7
|
-
- **The main craft's headline** — "N works shipped" (
|
|
7
|
+
- **The main craft's headline** — "N works shipped" (artisan), "N pages approved" (artist; an artist with ideas and no approved page leads with "N thoughts filed", since task 1005141 folded the ideator into the artist) — leads the tally. It was also the subtitle under the h1 until task 1004827 removed the page's sub-line (no top block).
|
|
8
8
|
- **The identity band** keeps the avatar, name, rank badge, handle, member-since and the "Answerable for" block unchanged. The "Preferred work:" line became **craft chips**, main role first ("Artist, main role"), then every other craft the server lists in `roles.shown`, which is a craft that has *earned* credits (the owner's 2026-09-30 rule; the server decides it, never this page).
|
|
9
|
-
- **The tally** replaces the credits/karma column: the studio's corner tally carried onto the profile, the total first and then the two numbers the main craft leads with (
|
|
9
|
+
- **The tally** replaces the credits/karma column: the studio's corner tally carried onto the profile, the total first and then the two numbers the main craft leads with (artisan: works shipped, karma; artist: pages approved, thoughts filed — or thoughts filed, ignited when they have ideas and no approved page).
|
|
10
10
|
- **By the numbers** is the main craft's set of tiles, then one headline tile per other shown craft. The artist adds the studio's "N of M tweaked" per surface underneath, on `OTBKit.barSeriesHtml` with this sheet only moving the three cells into the mock's layout (name and count on a line, the bar under them).
|
|
11
11
|
|
|
12
12
|
## Where the words live
|
|
@@ -16,28 +16,28 @@
|
|
|
16
16
|
## Rules an edit must keep
|
|
17
17
|
|
|
18
18
|
- **A number the instance could not read is a dash, never a zero.** The role ports are optional; "0 pages approved" would be a claim about the person.
|
|
19
|
-
- **The ~ on an
|
|
19
|
+
- **The ~ on an artist's total size** is the sky's historical-estimate mark; its tile's tooltip says how much is estimated.
|
|
20
20
|
- **The per-surface rows follow the MAIN craft only.**
|
|
21
21
|
- Every page that boots `profile.js` in a vm must load `profile-roles.js` first (`tests/helpers.mjs` `bootProfilePage` and `tests/profile_ui_cross_project.mjs` do).
|
|
22
22
|
|
|
23
23
|
## Harness
|
|
24
24
|
|
|
25
|
-
Three fixtures
|
|
25
|
+
Three fixtures: `builders__profile` (the artisan, id 95, the viewer's own), `<redacted>` (an artist who never shipped), `builders__2002__profile` (an artist whose work is ideas, who never shipped, part of whose size is estimated; the ideator fixture until task 1005141). `profile.states.json` renders them as `own`, `artist` and `artist-ideas`.
|
|
26
26
|
|
|
27
27
|
## Deliberate differences from the mock
|
|
28
28
|
|
|
29
|
-
- The
|
|
30
|
-
- The
|
|
31
|
-
- **Karma ends
|
|
29
|
+
- The artisan's tally shows **karma** where the mock shows "+120 this week", and the fourth artisan tile is **achievements** where the mock shows a shipping streak: neither weekly artisan credits nor a weekly streak is in the profile read, and a number the page cannot read is not drawn.
|
|
30
|
+
- The artisan tile "works shipped" has no "across N goals" foot, the artist's "thoughts filed" no "since <month>" foot, the artist's "credits from pages" no "N a page" foot, and the surface rows no "where" sub-label: none of those is in the read.
|
|
31
|
+
- **Karma ends the artist's set of tiles** (every main craft but the artisan's), which the mock does not draw. The owner's call, reviewing this build on 2026-10-01: "karma for artists and ideators is definitely key" (the ideator is part of the artist craft since task 1005141). The artisan's set carries it already.
|
|
32
32
|
- The tiles' grid fits at 148px rather than 170px, so five tiles sit on one row inside the hall's narrower panel.
|
|
33
33
|
|
|
34
34
|
## The Activity tabs, one per role (task 1004435, WA6.RP05)
|
|
35
35
|
|
|
36
36
|
The section used to offer All / Engineer / Artist / Ideator / UI tabs over one task ledger, so an ideator's tab listed tasks whose discipline happened to be "ideator" and an artist's listed only artist-labelled tasks they had shipped. Now there is **one tab per role the person has** (`roles.shown`, the header's chips, main first), each counted the way the header leads, each its craft's own record, each with its own panel:
|
|
37
37
|
|
|
38
|
-
- **
|
|
39
|
-
- **Ideator
|
|
40
|
-
- **Artist**: the pages they rewrote in Tweak Mode that were approved, four at a time with "Show N more", from `GET /copy-desk/artists/:id/pages` (signed in; copy-desk's `composeArtistPages`). Each row: page, surface, approval day, changed-line count, and a before/after: the round's first changed line beside the approval renders (`/tasks/:id/visuals`, `before-` and `after-desktop-light`) as small thumbnails.
|
|
38
|
+
- **Artisan**: the works completed and goals created ledgers, WHOLE (no craft filter: most of the corpus is unclassified and a filter reads as "you did less").
|
|
39
|
+
- **Artist, the ideas half** (its own Ideator tab until task 1005141; now drawn under the approved pages on the one Artist tab): the room's public trail, `public/profile-crafts.js`. One read of up to the route's cap of thoughts (`GET /inbox/by-builder/:id`, which already carried each thought's `state` and `size`), drawn as the sky's five marks by the day each was filed (size = diameter, brightness = a star's opacity, a folded-in thought tethered to the one it joined), the legend in the sky's words from `OTBIdeaObjects`, and every drawn thought a row in the ledger under it: state, size (~ for a historical estimate), still alive, and the old trail's "what became of it" cell folded in whole. A mark and its row light together on hover or focus; clicking a mark focuses its row.
|
|
40
|
+
- **Artist, the pages half**: the pages they rewrote in Tweak Mode that were approved, four at a time with "Show N more", from `GET /copy-desk/artists/:id/pages` (signed in; copy-desk's `composeArtistPages`). Each row: page, surface, approval day, changed-line count, and a before/after: the round's first changed line beside the approval renders (`/tasks/:id/visuals`, `before-` and `after-desktop-light`) as small thumbnails.
|
|
41
41
|
|
|
42
42
|
Signed out, the section is one sign-in line (owner decision (a)).
|
|
43
43
|
|
|
@@ -59,7 +59,7 @@ The Overview's charts used to stop at "No works shipped yet" before they read a
|
|
|
59
59
|
- **The works charts still need a shipped task**, and without one they are a single line under the figure ("No works shipped yet ..."), not two empty cards. Someone with neither credits nor works gets one line for the whole section.
|
|
60
60
|
- **On a phone** the figure stacks: the line, then "where it came from". The plot's viewBox is half again a card's on a wide screen so its type matches the cards', and the kit's own on a phone (read at draw time, at the same 720px the grid stacks).
|
|
61
61
|
|
|
62
|
-
Harness: `builders__earnings.json` serves any id; the artist (2001) and the
|
|
62
|
+
Harness: `builders__earnings.json` serves any id; the artist (2001) and the ideas artist (2002) carry their own earnings beside an empty `builders__<id>__activity.json`, and the `artist`/`artist-ideas` states expect `#chart-drachmae` and `.pearn__kinds`.
|
|
63
63
|
|
|
64
64
|
### Deliberate differences from the mock (RP06)
|
|
65
65
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# The sky — /thinking and /goal-map (tasks 1004231, 1004232, 1004233)
|
|
2
2
|
|
|
3
|
-
**THE SKY landed at `/thinking` (task 1004231 / sky part 3 of 5, goal 1000095; [ADR 0331](../../../docs/adr/0331-the-sky-is-the-ideators-home.md), ADR 0227 §11)** — the ideator's home. It replaced BOTH the room (task 1004098, `/thinking`) and the first ambient sky (task 1004105, `/sky` — the URL 301s here now) with the prototype the owner adopted as the design of record: `docs/design/mocks/sky/sky.template.html` is the **pixel contract** — copy, layout, colours, the thirteen tour steps, the toggles, the keys (`L` list, `?` tour, `0` fit, `/` compose) — built for real over `GET /sky` and `GET /sky/mine` (part 2). The room survives inside it as the list drawer: every drawn thought is a row with its whole sentence, one key away. Eight things it settled:
|
|
3
|
+
**THE SKY landed at `/thinking` (task 1004231 / sky part 3 of 5, goal 1000095; [ADR 0331](../../../docs/adr/0331-the-sky-is-the-ideators-home.md), ADR 0227 §11)** — the ideator's home (the artist craft's since task 1005141 folded the ideator into it). It replaced BOTH the room (task 1004098, `/thinking`) and the first ambient sky (task 1004105, `/sky` — the URL 301s here now) with the prototype the owner adopted as the design of record: `docs/design/mocks/sky/sky.template.html` is the **pixel contract** — copy, layout, colours, the thirteen tour steps, the toggles, the keys (`L` list, `?` tour, `0` fit, `/` compose) — built for real over `GET /sky` and `GET /sky/mine` (part 2). The room survives inside it as the list drawer: every drawn thought is a row with its whole sentence, one key away. Eight things it settled:
|
|
4
4
|
|
|
5
5
|
- **The page has no hall chrome, on purpose.** `thinking.html` is the template's markup (no shell.js, no sidebar); `thinking.css` is its `<style>`, one file; the world's tokens are not loaded — the template's values ARE the contract. The hall's doors (the record, the goal, the task) open from the panel, resolved against `hallBase()` (apex `/builders` or the subdomain). The title stamps `{{worldName}}` like every hall page.
|
|
6
6
|
- **One script became seven files under the 1,500-line ratchet, on ONE shared object.** `window.OTBSky`: `SKY.S` is every `let` the prototype's closure held; everything else is a function or a constant. Load order is pinned in the HTML — `sky-data.js` (helpers, the vocabulary, the two adaptors, the bands, the world, the thoughts, the five reads) → `sky-layout.js` (clock, routes, explore, camera) → `sky-draw.js` (the drawing, the hit test) → `sky-interaction.js` (card, menu, pointer, keys, lenses, stats, jump, legend) → `sky-panel.js` (the panel, the drawer) → `sky-composer.js` (gravity, quick + full filing, the nod) → `sky-tour.js` (the thirteen steps, the frame loop, the boot). A file only CALLS a later file through `SKY.name(...)`, never at load time. The README says a split is not a deviation; a changed behaviour inside one is — and every deviation a gate or a route forced is listed in the task's ship notes, one line each.
|
|
@@ -37,8 +37,8 @@ Pinned by `tests/hall_sky.mjs` (31 cases: the reads, the five objects, the two c
|
|
|
37
37
|
|
|
38
38
|
**Owner decision 2026-09-27: "Your thinking is only your thinking."** Part 4's "one page, two doors" above is SUPERSEDED: the two pages share the renderer and nothing else. The owner confirmed that "the your projects tab" means the whole-project lens, its switch and the project-map features. What this settled:
|
|
39
39
|
- **The lens and the features separate; the drawing does not.** `thinking.css`, the seven `sky-*.js` files and every draw path stay shared. What each page may be in is `S.lenses` (set once in `sky-data.js` from `data-sky-lens`): `['simple', 'mine']` on `/thinking`, `['all']` on `/goal-map`. `setLens` clamps to it, so nothing — a button, the tour, a jump, the panel's "descend" — can take a page into a lens it lacks, and no button leaves for the other page (`location.assign` is gone from `sky-interaction.js`).
|
|
40
|
-
- **Absent, not hidden.** `/thinking` carries no "the whole project" button, no "my ideas", no "explore" and no "where do you begin" dialog; `/goal-map` carries no switcher at all and none of
|
|
41
|
-
- **Two tours from one list.** Every step in `ALL_STEPS` says which sky it belongs to; `/thinking` walks nine of the template's thirteen (the
|
|
40
|
+
- **Absent, not hidden.** `/thinking` carries no "the whole project" button, no "my ideas", no "explore" and no "where do you begin" dialog; `/goal-map` carries no switcher at all and none of `/thinking`'s pills (recent, claude layer, my influence). The scripts touch a one-page control through `SKY.hide` / `SKY.press` / `SKY.on`, which do nothing when the element is not there. `thinking.css` gained one rule, `.brand + .tools { margin-left: auto; }`, so `/goal-map`'s tools keep the switcher's push to the right and its top strip reads as before.
|
|
41
|
+
- **Two tours from one list.** Every step in `ALL_STEPS` says which sky it belongs to; `/thinking` walks nine of the template's thirteen (the thinking sky's steps, the wells and rings, the clock, the composer, simple), `/goal-map` walks eight — the wells, rings, life, routes, settled systems, the clock and explore — opened by one new step, "This is the whole project.", because the template's first step is "This is your sky." and belongs to `/thinking`. The project tour turns explore off for its length and gives it back. Each tour has its own seen key (S.tourKey: sky-tour-seen here, sky-map-tour-seen on the map), so one does not silence the other.
|
|
42
42
|
- **"Descend into the well" stays in its sky.** On `/goal-map` it only flies; on `/thinking` it steps "simple" up to "your thinking" (the one lens there that zooms). The legend drops "unexplored" on `/thinking`, which has no explore.
|
|
43
43
|
- **Kept on both:** the list drawer (the room on `/thinking`, the ledger on `/goal-map`), the clock, the composer, "what if", the panel. Filing a thought from the project map still works; the owner's decision names the lens and the overlay, not the composer.
|
|
44
44
|
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# The start screen and the load screen — a sign-in opens the game (task 1005143, BONGOS-V3 R03)
|
|
2
|
+
|
|
3
|
+
Covers: Home (`shell-game.js` `start()`, `shell-game.css`, the hand-off in `welcome-boot.js`). Spec: `docs/specs/bongos-v3-game-conversion.md` C1 `game-opens-not-navigates`. Game mode itself is in `game-mode.md`.
|
|
4
|
+
|
|
5
|
+
## What it settled
|
|
6
|
+
|
|
7
|
+
- **A fresh sign-in opens on the start screen, on Home.** Home is where a sign-in lands (`postLoginLanding`), and `welcome-boot.js` already knows a fresh sign-in from a return visit (the flag the sign-in click leaves). On one, `OTBWelcome.onAccess` calls `OTBShellGame.start({ name, art, done })` in place of its own greeting. The day's first visit without a sign-in keeps the welcome; a signed-out visitor keeps the welcome. A sign-in that returns to a deep link or another page goes straight there, as the welcome always did. `shell.js` is untouched.
|
|
8
|
+
- **Five choices, one column: Start, Options, Achievements, Extras, Quit.** Start is the one filled pill. Options is a link to `/settings`, which IS the one options menu since task 1005144 (`records/options-menu.md`); Achievements is `/profile`. Extras opens three links under the menu (the thinking sky, the atlas, the docs). Quit calls `window.close()`; a browser only closes a tab a script opened, so when the tab is still there 300ms later the screen says "Close it to quit" instead of doing nothing.
|
|
9
|
+
- **Start turns game mode on** (`set(true)`), then shows the load screen. Nothing else in the hall's interface sets it.
|
|
10
|
+
- **The load screen is the still, a tip, and the city building up.** The still is the welcome's painting for the time of day, handed in by `welcome-boot.js` (this file names no picture). In a card of the hall's own tokens, the project city is drawn by `home-city-draw.js` `citySvg` from the one bounded read Home already uses (`GET /home/city?weeks=10`), at 31 stops from the oldest week to now, about three seconds, with "The city, N weeks ago" under it. Each stop is a whole drawing set as state; nothing animates in JavaScript. With reduced motion it is the finished city at once. With no city to draw (the read failed, the scripts are missing) the still and the tip stand for 1.4s. Either way the world opens.
|
|
11
|
+
- **Tips rotate** (`localStorage 'hall-game-tip'` counts them), so each load shows the next one. A tip must be true of the hall today; the first one is the Escape rule from `game-mode.md` (rewritten by task 1005144: Escape opens the options menu).
|
|
12
|
+
- **The craft picker waits for the world.** While the start screen is up the shell asks no picker (`onAccess` returned true). `done` runs once the screen is gone and asks `OTBCraftMode.onAccess` then.
|
|
13
|
+
- **Keys.** While either screen is up it keeps every key: the arrows and Tab walk the menu, Escape folds Extras away and does nothing else, so the shell's Escape cannot flip the bars underneath. Once the world shows, the last Escape opens the options menu (task 1005144); the screen's capture listener calls `preventDefault`, so the menu never opens from under it.
|
|
14
|
+
- **The look.** The painting under the hall's `--scrim`, and on it one card of the hall's own tokens per screen (`--bg-card`, `--ink`, `--rule`; Start is the hall's primary pill, `--accent` under `--accent-on`), so both follow the hall's theme and the sheet holds no colour literal (`tests/hall_audit.mjs`). Sizes, corners and spacing are `--ds-*` tokens only; the sheet has no `@media` (the column is `max-width` in `rem` and wraps). The fade into the world is one CSS opacity transition, stopped by the hall's reduced-motion rule.
|
|
15
|
+
|
|
16
|
+
## For the tasks after this one
|
|
17
|
+
|
|
18
|
+
- R04 (task 1005144): point Options at the options menu and move Achievements/Extras targets if those pages lose their interfaces. Escape on the start screen is free for the menu to use.
|
|
19
|
+
- `shell-game.js` is loaded on every hall page but only Home calls `start()`; `shell-game.css` is linked on Home only. A second page that wants the start screen links the sheet and calls `start()` with its own still.
|
|
20
|
+
|
|
21
|
+
Tests: `tests/hall_start_screen.mjs` (the hand-off and pure parts in a vm; both screens, Quit, the no-city and reduced-motion paths in a real browser).
|
|
@@ -6,7 +6,7 @@ Files: `tweak-editor.html` (the markup), `tweak-editor.css` (the artboard's inli
|
|
|
6
6
|
|
|
7
7
|
- **Which page.** `?page=<page id>` (`landing:index`). With none, the page the caller holds (`GET /copy-desk/next`'s `resume`), and with nothing held, the "is in" panel's next up, so a bare link still leads somewhere. The studio (TW16) links here.
|
|
8
8
|
- **One read opens it.** `GET /copy-desk/pages/:pageId/draft` (added here: `GET /copy-desk/pages/:pageId` carries neither the lines nor the draft) answers every reading line with its margin note, the open round and `held_by_you`, and the saved draft, only on the current reading (`draft_on_older_reading` otherwise). The note is the server's: `engineer` is `pages.goesToEngineer`, the submit's own rule, so a shared line with no registry row says "goes to an engineer", which is what the submit will do with it.
|
|
9
|
-
- **The autosave is the whole draft, debounced (700ms) and on blur**, one save in flight at a time, skipped when the body equals the last accepted one; a last `keepalive` PUT on `pagehide`. An emptied box is saved as a removal, `{ key, remove: true }` (task 1004696): its margin note says it is to be removed and goes to an engineer, and the submit files that
|
|
9
|
+
- **The autosave is the whole draft, debounced (700ms) and on blur**, one save in flight at a time, skipped when the body equals the last accepted one; a last `keepalive` PUT on `pagehide`. An emptied box is saved as a removal, `{ key, remove: true }` (task 1004696): its margin note says it is to be removed and goes to an engineer, and the submit files that artisan task (an empty `after` alone is still the server's `line_empty`), and the counter reads "not saved" with the server's own words above the paper when a save is refused.
|
|
10
10
|
- **Holding decides writing.** A page nobody holds is read-only with one button, "take this page" (the claim); another builder's is read-only and names them; a submitted one is frozen. Upload and submit are the holder's only, as their routes are.
|
|
11
11
|
- **Every write is named** (`WRITES`: the draft PUT, the .docx POST, the submit, the claim on a server-given `take.path`), and `tests/hall_tweak_editor.mjs` pins the list. The upload is a raw `fetch` because the generated client JSON-encodes every body.
|
|
12
12
|
- **It opens full screen.** The artboard is the whole window, so the first visit sets the shell's switch (task 1004327) on; after that the shell remembers the artist's choice for this page. In full screen the switch button wears the room's glass, since the stage is dark in both themes.
|
|
@@ -10,3 +10,15 @@ The owner, 2026-11-03: upgrading Bongos from a project's hall was "way too obstr
|
|
|
10
10
|
- **shell.js got smaller.** The banner's 109 lines became a 61-line loader that fetches `/core-update` once per page and loads the pill only when there is news or a run in flight (1,499 → 1,451 lines).
|
|
11
11
|
|
|
12
12
|
Tests: `tests/update_pill.mjs` (the pure half, and the real shell + pill in a DOM stub: who sees it, never a link, both doors, refusals, a blocked window, held, a run across pages, done → Reload), `tests/deploy_handoff.mjs` (the hub's three refusals, and its page run for real). Each origin, opener and version check was deleted once and watched to go red. Harness fixture: `core-update.json` (behind, so the pill shows).
|
|
13
|
+
|
|
14
|
+
## The pop-up (task 1005191)
|
|
15
|
+
|
|
16
|
+
The owner, 2026-11-10: the pill alone was not seen. Game mode (task 1005142) opens every page without its bars, and full screen hid everything in the top bar's right side except its own button, so a hosted project sat three minor versions behind with nobody told. What this settled:
|
|
17
|
+
|
|
18
|
+
- **A ready update also asks, once.** `update-pill.js` `maybeAsk` opens the hall's one dialog (`OTBDialog.open`, no bespoke dialog): "Update the builders hall?", up to three release-note lines, the takes-a-few-minutes note, both versions, then *Later* and *Update now*. It reads the same `/software-update` answer the card reads, so both name one version and the two-step rule (ADR 0293 D4) holds.
|
|
19
|
+
- **Update now runs inside the press.** A hosted project opens the hub's window, which a browser allows only from the click; the progress card then opens under the pill.
|
|
20
|
+
- **Any other way of closing it is "later".** That version is not asked about again in this browser for a day (`bongos.update.later`); a newer version asks at once. The pill stays, so later never means lost.
|
|
21
|
+
- **Who is not asked:** a viewer the door would refuse, the hub's handoff window, the `/deploy` page, a builder held at the setup screen, a held version, an update already running. A self-hosted project is told the command, with one *Close* button.
|
|
22
|
+
- **The pill stays with the bars away** (`style.css`, `html[data-fullscreen="on"] .upd-pill`), beside the button that brings the bars back.
|
|
23
|
+
|
|
24
|
+
Tests: `tests/update_pill.mjs`, the ten cases under "the pop-up".
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# The visor — the first-person HUD over every scene (task 1005148, BONGOS-V3 R08; ADR 0399)
|
|
2
|
+
|
|
3
|
+
Covers: `visor.js` + `visor.css`, loaded on Home, `/city`, `/goal-map` and `/thinking`, and the three scene registrations (`sky-interaction.js`, `city.js`, `home-city.js`). Spec: `docs/specs/bongos-v3-game-conversion.md` C2 `you-are-a-character-in-first-person`. Game mode itself is in `game-mode.md`.
|
|
4
|
+
|
|
5
|
+
## What it settled
|
|
6
|
+
|
|
7
|
+
- **The look the owner agreed (2026-11-10, five mock-up rounds).** A quiet layout with "hairline instruments" from the helmet round: thin curved visor lines across the top, bottom and both sides, a small centre cross, and a compass of nine slanted cells along the top line with the one salmon marker under its centre. No tracker or radar (tried and dropped), no clipped corners: the pills stay round (DESIGN.md "pill or nothing"). No glow (DESIGN.md's rejected near-black-plus-neon HUD). The frame is one SVG in a 1000×1000 box stretched over the stage with non-scaling strokes, so it is a hairline at every size.
|
|
8
|
+
- **What sits where.** Bottom-left: the character's main action, the one accent pill, with its key. Bottom-right: the sprite (task 1005147's art, `OTBCraftMode.spriteSrc`) with the character's name and the credit count (`/me` `builder.total_credits` through `OTBCraftMode.me()`; credits only, never a payout). Top-right: Actions (key A), which opens the sheet: the character's actions, then "This place" (the scene's own actions and keys), then Options on Escape. A place line under the compass names the scene; the sky leaves it empty because its own heading names it.
|
|
9
|
+
- **Each character's actions** (`ACTIONS`): Artisan Claim a task C (`/work`), Blockers B, Goal sky G, Your thinking T. Artist Review this page R, Edit its words E, Write an idea I (the three craft-mode tools, through `OTBCraftMode.openTool`), Studio S. Patron Board room O, Governor city V, Blockers B, Watch W. Every one is a page or tool the hall already has; the visor gates nothing, and the server's rank checks answer exactly as before (ADR 0399 §2.5). No key a scene binds is reused (the sky's L 0 / ?, the gallery's F, the palette's K, the city card's digits, arrows and Tab).
|
|
10
|
+
- **Glass, not layout (ADR 0399 §2.1).** `#visor` is `position: fixed` with `pointer-events: none`; only the pills and the sheet take a pointer. A drag across a frame line pans the sky (test-pinned).
|
|
11
|
+
- **No camera (§2.2).** A scene registers once: `window.__visorScene = { name, place, actions, keys }`, then `OTBVisor.scene(...)` if the visor is already loaded (it also reads the global at start, so load order between the two does not matter). The sky offers "Back to centre" (its own `fitAll`); the Governor City and Home have no camera yet and offer none, with no disabled button. R13 adds Home's.
|
|
12
|
+
- **Escape (§2.4).** The open sheet takes the press in capture with `preventDefault` and `stopPropagation`, so the sky's pick under it survives; the ambient glass never takes Escape, so the last press reaches the options menu. The letter keys listen in bubble on `window` and skip a press a scene already spent (`defaultPrevented`), one with a modifier, one in a field, and any press while the character picker, the start screen or an `aria-modal` dialog is up.
|
|
13
|
+
- **When it shows.** Game mode (`html[data-game="on"]`) AND a registered scene AND a character (the held one, else this session's craft mode) AND not inside the options menu's frame. Otherwise the hall is exactly as before.
|
|
14
|
+
- **Scenes keep clear of the glass.** While it shows, `visor.js` puts `visor-on` on `<html>`, and `thinking.css` moves the sky's top row, composer, jump field and side panels below the compass, and its foot and tour above the corner pills. A new scene with fixed furniture does the same in its own sheet.
|
|
15
|
+
- **Stacking.** The glass is z 4: above the scene, under the sky's pop-ups (5–8). The Governor City's card lives inside `.city-main`'s stacking context, so the glass is drawn over it; nothing collides (the card is centred, the pills are in the corners).
|
|
16
|
+
|
|
17
|
+
## For the tasks after this one
|
|
18
|
+
|
|
19
|
+
- R09 (one hotkey registry): `ACTIONS` keys and the scene `keys` lines are what it registers; the sheet is where a rebind shows.
|
|
20
|
+
- R13 (the sky camera on Home's city): register `fitAll` / `flyTo` as actions in `home-city.js`'s `__visorScene`.
|
|
21
|
+
- R11 (Patron for everyone): no visor change; the Patron's actions already open pages whose routes keep their rank walls.
|
|
22
|
+
|
|
23
|
+
Tests: `tests/hall_visor.mjs` (the pure parts in a vm; the glass, the pointer pass-through, the Escape order, the sheet, the Artist's tools and the key guards in a real browser over a stand-in scene). The script-order pins in `tests/hall_city.mjs` and `tests/goal_map_page.mjs` name the visor after the shell.
|
|
@@ -32,14 +32,14 @@ finally had Gemini paint the city by day and by night and asked for those to be
|
|
|
32
32
|
- **Banner.** "Working on the core of <project>" from `__BRANDING__.identity` (never a hardcoded word),
|
|
33
33
|
with `core <version>` under it when the public `GET /version` reports one.
|
|
34
34
|
- **Sequence.** Veil lifts, the city powers up (pulses brighten), the greeting comes up at ~3.4s.
|
|
35
|
-
**Skip** jumps to the greeting; **Esc**, "Your home page" and
|
|
35
|
+
**Skip** jumps to the greeting; **Esc**, "Your home page" and Artisan leave slowly: the picture sinks
|
|
36
36
|
past the rooftops while the welcome fades into the hall underneath (about 2.4s), and the hall can be
|
|
37
37
|
clicked and scrolled from the first moment. A role bound for another room sinks into the veil, then
|
|
38
38
|
opens that room. Under `prefers-reduced-motion` nothing moves and leaving is immediate.
|
|
39
|
-
- **Roles** (the owner's mapping):
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
seat — and the list is built when "Start with your role" is pressed, after the seats have settled.
|
|
39
|
+
- **Roles** (the owner's mapping, renamed by task 1005141): Patron → `/city`, Artist → `/studio`,
|
|
40
|
+
Artisan → stays on Home (the Ideator door, once `/thinking`, folded into Artist). A pick also calls
|
|
41
|
+
`OTBCraftMode.choose()` with patron / artist / artisan. **Patron shows only where
|
|
42
|
+
`OTBCraftMode.offered('patron')`** — the patron craft is a seat — and the list is built when "Start with your role" is pressed, after the seats have settled.
|
|
43
43
|
- **No painting** (a 404) hides the image and leaves the sky gradient; everything else works.
|
|
44
44
|
- **Colours are the paintings'**, in both hall themes: `welcome-boot.css` and `welcome-boot.js` are on
|
|
45
45
|
`tests/hall_audit.mjs`'s literal exemptions with that reason.
|
|
@@ -132,7 +132,9 @@ async function readIdeatorStats(builderId, deps = {}) {
|
|
|
132
132
|
if (reward && typeof reward.creditsByCraft === 'function') {
|
|
133
133
|
const byCraft = await reward.creditsByCraft([builderId]);
|
|
134
134
|
const row = byCraft.get(String(builderId));
|
|
135
|
-
|
|
135
|
+
// The idea streams alone — artist credits also carry page money since the
|
|
136
|
+
// ideator folded into the artist (task 1005141), so `artist` would overstate this.
|
|
137
|
+
ideatorCredits = row ? (Number.isFinite(row.ideas) ? row.ideas : 0) : 0;
|
|
136
138
|
}
|
|
137
139
|
|
|
138
140
|
let ratifiedIds = null;
|