@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
|
@@ -76,7 +76,7 @@ async function fileNote(note, { grade, capture, db, log } = {}) {
|
|
|
76
76
|
// an empty list means nothing filed and the caller says so.
|
|
77
77
|
async function fileIdeatorNotes(submit, { grade, capture, log, authorId, authorName } = {}) {
|
|
78
78
|
const page = { page_id: submit.page_id, page_path: submit.page_path, page_title: submit.page_title, body_md: submit.body_md };
|
|
79
|
-
let ideas = await aiIdeas({ note: page, grade, voice: '
|
|
79
|
+
let ideas = await aiIdeas({ note: page, grade, voice: 'notes', timeoutMs: IDEATOR_TIMEOUT_MS });
|
|
80
80
|
let splitBy = 'ai';
|
|
81
81
|
if (!ideas) { ideas = [N.wholeDocIdea({ pageTitle: page.page_title, pageId: page.page_id, bodyMd: page.body_md })]; splitBy = 'whole'; }
|
|
82
82
|
const filed = [];
|
|
@@ -5,15 +5,16 @@
|
|
|
5
5
|
// A reporting instance sends, per craft the builder has EARNED credits in, that
|
|
6
6
|
// craft's headline counts (src/bongos/auth-admission.js readCraftRollup):
|
|
7
7
|
//
|
|
8
|
-
//
|
|
9
|
-
// artist { pages_approved, credits }
|
|
10
|
-
//
|
|
8
|
+
// artisan { shipped, credits }
|
|
9
|
+
// artist { pages_approved, filed, full_ideas, ratified, credits }
|
|
10
|
+
//
|
|
11
|
+
// (the old engineer / artist / ideator shape is folded in at ingest, foldLegacy)
|
|
11
12
|
//
|
|
12
13
|
// Two halves live here, next to each other so they cannot disagree on the shape:
|
|
13
14
|
//
|
|
14
15
|
// sanitizeCrafts — what upsertActivity BINDS. The report is third-party
|
|
15
16
|
// self-report (ADR 0171 D7), so the shape and the caps are the hub's, not
|
|
16
|
-
// the sender's: only the
|
|
17
|
+
// the sender's: only the two crafts, only the named counts, each a
|
|
17
18
|
// non-negative integer under a ceiling or null. Anything else is dropped.
|
|
18
19
|
// A count is never text, so nothing here can carry a title or wording.
|
|
19
20
|
//
|
|
@@ -30,10 +31,36 @@
|
|
|
30
31
|
'use strict';
|
|
31
32
|
|
|
32
33
|
const CRAFT_FIELDS = Object.freeze({
|
|
33
|
-
|
|
34
|
-
artist: Object.freeze(['pages_approved', 'credits']),
|
|
35
|
-
ideator: Object.freeze(['filed', 'full_ideas', 'ratified', 'credits']),
|
|
34
|
+
artisan: Object.freeze(['shipped', 'credits']),
|
|
35
|
+
artist: Object.freeze(['pages_approved', 'filed', 'full_ideas', 'ratified', 'credits']),
|
|
36
36
|
});
|
|
37
|
+
|
|
38
|
+
// A reporting instance on a core older than task 1005141 still sends the old
|
|
39
|
+
// crafts: `engineer`, and `artist` + `ideator` as two blocks. They are folded
|
|
40
|
+
// into today's shape BEFORE the hub's caps run, so an old report and a new one
|
|
41
|
+
// land identically: engineer becomes artisan, and the ideator's counts join the
|
|
42
|
+
// artist block with the two credit figures summed. A craft already reported under
|
|
43
|
+
// its new name wins over an old-name block for the same craft.
|
|
44
|
+
function foldLegacy(raw) {
|
|
45
|
+
const out = { ...raw };
|
|
46
|
+
if (out.engineer && !out.artisan) out.artisan = out.engineer;
|
|
47
|
+
delete out.engineer;
|
|
48
|
+
const ideator = out.ideator;
|
|
49
|
+
delete out.ideator;
|
|
50
|
+
if (ideator && typeof ideator === 'object' && !Array.isArray(ideator)) {
|
|
51
|
+
const art = out.artist && typeof out.artist === 'object' && !Array.isArray(out.artist) ? out.artist : {};
|
|
52
|
+
// Each half is capped BEFORE the sum: a hostile -3 on one side must not
|
|
53
|
+
// quietly shave the other side's honest count.
|
|
54
|
+
const a = cleanCount(art.credits);
|
|
55
|
+
const i = cleanCount(ideator.credits);
|
|
56
|
+
out.artist = {
|
|
57
|
+
...art,
|
|
58
|
+
filed: ideator.filed, full_ideas: ideator.full_ideas, ratified: ideator.ratified,
|
|
59
|
+
credits: a == null && i == null ? null : (a || 0) + (i || 0),
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
return out;
|
|
63
|
+
}
|
|
37
64
|
// Far above any honest count, low enough that a sum over every project stays a
|
|
38
65
|
// safe integer and a hostile report cannot dominate a profile by one number.
|
|
39
66
|
const MAX_CRAFT_COUNT = 10_000_000;
|
|
@@ -45,6 +72,7 @@ function cleanCount(v) {
|
|
|
45
72
|
function sanitizeCrafts(raw) {
|
|
46
73
|
const out = {};
|
|
47
74
|
if (!raw || typeof raw !== 'object' || Array.isArray(raw)) return out;
|
|
75
|
+
raw = foldLegacy(raw);
|
|
48
76
|
for (const [craft, fields] of Object.entries(CRAFT_FIELDS)) {
|
|
49
77
|
const block = raw[craft];
|
|
50
78
|
if (!block || typeof block !== 'object' || Array.isArray(block)) continue;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
-- platform_identity_036 — the hub's per-project activity rollup follows core_296's craft
|
|
2
|
+
-- rename (task 1005141, BONGOS-V3 C1): engineer → artisan, ideator → artist.
|
|
3
|
+
--
|
|
4
|
+
-- `disciplines` is mapped and deduped. `crafts` (platform_identity_029) is keyed by
|
|
5
|
+
-- craft: the engineer block becomes the artisan block, and the ideator block's counts
|
|
6
|
+
-- (filed, full_ideas, ratified) merge into the artist block, with credits summed —
|
|
7
|
+
-- the shape modules/platform-identity/craft-rollup.js now sanitizes. A report from an
|
|
8
|
+
-- instance still on an older core is folded the same way at ingest, so these rows and
|
|
9
|
+
-- fresh reports agree.
|
|
10
|
+
|
|
11
|
+
BEGIN;
|
|
12
|
+
|
|
13
|
+
UPDATE platform_identity_builder_project_activity a
|
|
14
|
+
SET disciplines = ARRAY(
|
|
15
|
+
SELECT m.craft FROM (
|
|
16
|
+
SELECT CASE d WHEN 'engineer' THEN 'artisan' WHEN 'ideator' THEN 'artist' ELSE d END AS craft,
|
|
17
|
+
min(ord) AS first_seen
|
|
18
|
+
FROM unnest(a.disciplines) WITH ORDINALITY AS u(d, ord)
|
|
19
|
+
GROUP BY 1
|
|
20
|
+
) m ORDER BY m.first_seen)
|
|
21
|
+
WHERE a.disciplines && ARRAY['engineer', 'ideator']::text[];
|
|
22
|
+
|
|
23
|
+
UPDATE platform_identity_builder_project_activity
|
|
24
|
+
SET crafts = (crafts - 'engineer') || jsonb_build_object('artisan', crafts -> 'engineer')
|
|
25
|
+
WHERE crafts ? 'engineer' AND NOT crafts ? 'artisan';
|
|
26
|
+
|
|
27
|
+
UPDATE platform_identity_builder_project_activity
|
|
28
|
+
SET crafts = (crafts - 'ideator') || jsonb_build_object('artist',
|
|
29
|
+
coalesce(crafts -> 'artist', '{}'::jsonb)
|
|
30
|
+
|| jsonb_strip_nulls(jsonb_build_object(
|
|
31
|
+
'filed', crafts -> 'ideator' -> 'filed',
|
|
32
|
+
'full_ideas', crafts -> 'ideator' -> 'full_ideas',
|
|
33
|
+
'ratified', crafts -> 'ideator' -> 'ratified'))
|
|
34
|
+
|| jsonb_build_object('credits',
|
|
35
|
+
CASE WHEN jsonb_typeof(crafts -> 'artist' -> 'credits') = 'number'
|
|
36
|
+
OR jsonb_typeof(crafts -> 'ideator' -> 'credits') = 'number'
|
|
37
|
+
THEN to_jsonb(coalesce((crafts -> 'artist' ->> 'credits')::bigint, 0)
|
|
38
|
+
+ coalesce((crafts -> 'ideator' ->> 'credits')::bigint, 0))
|
|
39
|
+
ELSE 'null'::jsonb END))
|
|
40
|
+
WHERE crafts ? 'ideator';
|
|
41
|
+
|
|
42
|
+
INSERT INTO schema_migrations (version) VALUES ('platform_identity_036_crafts_artisan_artist')
|
|
43
|
+
ON CONFLICT (version) DO NOTHING;
|
|
44
|
+
|
|
45
|
+
COMMIT;
|
|
@@ -671,8 +671,8 @@ async function upsertActivity({ clientId, githubId, credits = 0, tasksShipped =
|
|
|
671
671
|
// api.LIVE_RANK_LADDER is a published doorway export (src/module-api.js, a
|
|
672
672
|
// lazy getter over db-kernel's canonical four-rank ladder).
|
|
673
673
|
const safeRank = api.LIVE_RANK_LADDER.includes(rank) ? rank : null;
|
|
674
|
-
const disc = (Array.isArray(disciplines) ? disciplines : [])
|
|
675
|
-
.filter((d) => typeof d === 'string' && d.length > 0 && d.length <= MAX_DISCIPLINE_LENGTH)
|
|
674
|
+
const disc = api.crafts.normalizeCrafts((Array.isArray(disciplines) ? disciplines : []) // an older core's engineer/ideator → today's crafts, as foldLegacy (task 1005193)
|
|
675
|
+
.filter((d) => typeof d === 'string' && d.length > 0 && d.length <= MAX_DISCIPLINE_LENGTH))
|
|
676
676
|
.slice(0, MAX_ROLLUP_DISCIPLINES);
|
|
677
677
|
const ships = sanitizeRecentShips(recentShips, clientOrigin);
|
|
678
678
|
// Each craft's own counts (task 1004440), shaped and capped here — see craft-rollup.js.
|
|
@@ -55,7 +55,8 @@ module.exports = function communityLeaderboardRoutes() {
|
|
|
55
55
|
if (!leaderboard.isWindow(window)) {
|
|
56
56
|
return res.fail('bad_window', { status: 400, message: `window must be one of: ${leaderboard.WINDOWS.join(', ')}` });
|
|
57
57
|
}
|
|
58
|
-
|
|
58
|
+
// An old link's engineer/ideator reads as today's craft (task 1005141).
|
|
59
|
+
const discipline = require('../../../src/module-api').crafts.normalizeCraft((typeof req.query.discipline === 'string' ? req.query.discipline : '').trim());
|
|
59
60
|
if (discipline.length > leaderboard.MAX_DISCIPLINE_CHARS) {
|
|
60
61
|
return res.fail('discipline_too_long', { status: 400, message: `discipline must be at most ${leaderboard.MAX_DISCIPLINE_CHARS} characters` });
|
|
61
62
|
}
|
|
@@ -63,7 +63,8 @@ module.exports = function communitySearchRoutes() {
|
|
|
63
63
|
if (q.length > builderSearch.MAX_QUERY_CHARS) {
|
|
64
64
|
return res.fail('query_too_long', { status: 400, message: `q must be at most ${builderSearch.MAX_QUERY_CHARS} characters` });
|
|
65
65
|
}
|
|
66
|
-
|
|
66
|
+
// An old link's engineer/ideator reads as today's craft (task 1005141).
|
|
67
|
+
const discipline = require('../../../src/module-api').crafts.normalizeCraft((typeof req.query.discipline === 'string' ? req.query.discipline : '').trim());
|
|
67
68
|
if (discipline.length > builderSearch.MAX_DISCIPLINE_CHARS) {
|
|
68
69
|
return res.fail('discipline_too_long', { status: 400, message: `discipline must be at most ${builderSearch.MAX_DISCIPLINE_CHARS} characters` });
|
|
69
70
|
}
|
|
@@ -691,7 +691,8 @@ module.exports = function ssoRoutes() {
|
|
|
691
691
|
tasksShipped: b.tasks_shipped,
|
|
692
692
|
karma: b.karma,
|
|
693
693
|
rank: b.rank || null,
|
|
694
|
-
|
|
694
|
+
// An instance on an older core still reports engineer/ideator (task 1005141).
|
|
695
|
+
disciplines: Array.isArray(b.disciplines) ? api.crafts.normalizeCrafts(b.disciplines) : [],
|
|
695
696
|
recentShips: b.recent_ships,
|
|
696
697
|
crafts: b.crafts,
|
|
697
698
|
// The AUTHENTICATED client's registered origin — the bound every pushed
|
|
@@ -606,14 +606,14 @@ const upsertCall = (pool) => pool.calls.find((c) => /INSERT INTO platform_identi
|
|
|
606
606
|
|
|
607
607
|
await ta('upsertActivity upserts per (client_id, github_id) with the talent snapshot', async () => {
|
|
608
608
|
const pool = activityPool();
|
|
609
|
-
await P.upsertActivity({ clientId: 'c1', githubId: 42, credits: 100, tasksShipped: 5, karma: 3, rank: 'metic', disciplines: ['
|
|
609
|
+
await P.upsertActivity({ clientId: 'c1', githubId: 42, credits: 100, tasksShipped: 5, karma: 3, rank: 'metic', disciplines: ['artisan'] }, { pool });
|
|
610
610
|
const c = upsertCall(pool);
|
|
611
611
|
assert.match(c.text, /ON CONFLICT \(client_id, github_id\) DO UPDATE/);
|
|
612
612
|
// recent_ships (task 1002803) rides the same row as a jsonb STRING param —
|
|
613
613
|
// an empty list when the sender reported none, never NULL. Its own cap,
|
|
614
614
|
// shape and link bound are covered by tests/hub_recent_ships.mjs. The last param
|
|
615
615
|
// is the report's as-of stamp (task 1004268): null when the sender gave none.
|
|
616
|
-
assert.deepEqual(c.params, ['c1', 42, 100, 5, 3, 'metic', ['
|
|
616
|
+
assert.deepEqual(c.params, ['c1', 42, 100, 5, 3, 'metic', ['artisan'], '[]', null, '{}']);
|
|
617
617
|
});
|
|
618
618
|
|
|
619
619
|
await ta('upsertActivity sanitizes third-party self-report (ADR 0171 D7): off-ladder rank → null, disciplines validated + capped', async () => {
|
|
@@ -622,7 +622,7 @@ await ta('upsertActivity sanitizes third-party self-report (ADR 0171 D7): off-la
|
|
|
622
622
|
clientId: 'c1', githubId: 42,
|
|
623
623
|
rank: 'Supreme Overlord', // not one of the four core rank keys → stored null
|
|
624
624
|
disciplines: [
|
|
625
|
-
'
|
|
625
|
+
'artisan', 42, null, { evil: true }, // non-strings dropped
|
|
626
626
|
'x'.repeat(33), // over-length dropped
|
|
627
627
|
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', // valid tail — capped to 8 total
|
|
628
628
|
],
|
|
@@ -633,7 +633,7 @@ await ta('upsertActivity sanitizes third-party self-report (ADR 0171 D7): off-la
|
|
|
633
633
|
assert.ok(disc.length <= 8, `disciplines capped at 8 (got ${disc.length})`);
|
|
634
634
|
assert.ok(disc.every((d) => typeof d === 'string' && d.length > 0 && d.length <= 32),
|
|
635
635
|
'only bounded string elements survive');
|
|
636
|
-
assert.equal(disc[0], '
|
|
636
|
+
assert.equal(disc[0], 'artisan', 'valid elements pass through in order');
|
|
637
637
|
});
|
|
638
638
|
|
|
639
639
|
await ta('upsertActivity keeps a legitimate core rank key', async () => {
|
|
@@ -733,7 +733,7 @@ await ta('getRollupForBuilder guards non-numeric github_id BEFORE any query (no
|
|
|
733
733
|
|
|
734
734
|
await ta('getRollupForBuilder aggregates un-fanned + names only publicly-catalogued projects', async () => {
|
|
735
735
|
const pool = mockPool([
|
|
736
|
-
{ rows: [{ projects: 2, credits: 150, works_shipped: 7, karma: 4, last_active: 'T', disciplines: ['
|
|
736
|
+
{ rows: [{ projects: 2, credits: 150, works_shipped: 7, karma: 4, last_active: 'T', disciplines: ['artisan', 'ui'] }] },
|
|
737
737
|
{ rows: [
|
|
738
738
|
{ name: 'Public Proj', origin: 'https://pub.example', rank_held: 'metic', is_public: true },
|
|
739
739
|
{ name: 'Secret Proj', origin: 'https://sec.example', rank_held: 'archon', is_public: false },
|
|
@@ -741,7 +741,7 @@ await ta('getRollupForBuilder aggregates un-fanned + names only publicly-catalog
|
|
|
741
741
|
]);
|
|
742
742
|
const out = await P.getRollupForBuilder(42, { pool });
|
|
743
743
|
assert.deepEqual(out.totals, { projects: 2, credits: 150, works_shipped: 7, karma: 4 });
|
|
744
|
-
assert.deepEqual(out.disciplines, ['
|
|
744
|
+
assert.deepEqual(out.disciplines, ['artisan', 'ui']);
|
|
745
745
|
assert.equal(out.projects.length, 1, 'only the public catalog row is named');
|
|
746
746
|
// recent_ships rides the project row it belongs to (task 1002803), so a work
|
|
747
747
|
// title can only surface where the project name already may.
|
|
@@ -262,9 +262,8 @@
|
|
|
262
262
|
<div class="commFilters">
|
|
263
263
|
<div class="commTabs" id="craftTabs" role="group" aria-label="Role">
|
|
264
264
|
<button class="commTab" type="button" data-craft="" aria-pressed="true">Everyone</button>
|
|
265
|
-
<button class="commTab" type="button" data-craft="
|
|
265
|
+
<button class="commTab" type="button" data-craft="artisan" aria-pressed="false">Artisans</button>
|
|
266
266
|
<button class="commTab" type="button" data-craft="artist" aria-pressed="false">Artists</button>
|
|
267
|
-
<button class="commTab" type="button" data-craft="ideator" aria-pressed="false">Ideators</button>
|
|
268
267
|
<button class="commTab" type="button" data-craft="ui" aria-pressed="false">Designers</button>
|
|
269
268
|
</div>
|
|
270
269
|
<div class="commWhen">
|
|
@@ -314,9 +313,8 @@
|
|
|
314
313
|
<label class="vh" for="findCraft">Role</label>
|
|
315
314
|
<select id="findCraft">
|
|
316
315
|
<option value="">Any role</option>
|
|
317
|
-
<option value="
|
|
316
|
+
<option value="artisan">Artisans</option>
|
|
318
317
|
<option value="artist">Artists</option>
|
|
319
|
-
<option value="ideator">Ideators</option>
|
|
320
318
|
<option value="ui">Designers</option>
|
|
321
319
|
</select>
|
|
322
320
|
<button id="findBtn" type="submit" class="btn small">Search</button>
|
|
@@ -365,7 +363,7 @@
|
|
|
365
363
|
var WINDOWS = ['7d', '30d', '365d', 'all'];
|
|
366
364
|
var QUERY_MIN = 2;
|
|
367
365
|
var QUERY_MAX = 100;
|
|
368
|
-
var CRAFT_WORD = {
|
|
366
|
+
var CRAFT_WORD = { artisan: 'artisan', artist: 'artist', ui: 'designer' };
|
|
369
367
|
// The five sub-pages this file is served as (platform-server.js's /community routes);
|
|
370
368
|
// the path picks one, and its menu items are marked current. The home adds no title.
|
|
371
369
|
var VIEWS = {
|
|
@@ -774,7 +774,7 @@ composition A; landing composition v3, picked by the owner 2026-08-27. No roll,
|
|
|
774
774
|
<div class="layer">
|
|
775
775
|
<h1 data-brand-tagline><span class="l1">Building Digitally,</span><span class="l2">as simple as Bongos.</span></h1>
|
|
776
776
|
|
|
777
|
-
<p class="lede">Bringing AI to the
|
|
777
|
+
<p class="lede">Bringing AI to the artisan and the artist in everyone.</p>
|
|
778
778
|
|
|
779
779
|
<div class="doors">
|
|
780
780
|
<div class="doorbar">
|
|
@@ -1389,7 +1389,7 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
1389
1389
|
<div class="card mSec" id="mInvite">
|
|
1390
1390
|
<h2>Invite a builder</h2>
|
|
1391
1391
|
<div id="mInv">
|
|
1392
|
-
<p class="finePrint">By GitHub username. The invite is sent from your project’s own hall — that is the invite that lets them in — and they see it on their projects page here too.</p>
|
|
1392
|
+
<p class="finePrint">By GitHub username. The invite is sent from your project’s own hall — that is the invite that lets them in — and they see it on their projects page here too. The hall’s invite box can also invite them to the project’s GitHub repository, which is a separate invite they accept on GitHub.</p>
|
|
1393
1393
|
<div class="attach">
|
|
1394
1394
|
<label class="vh" for="mInviteWho">GitHub username</label>
|
|
1395
1395
|
<input type="text" id="mInviteWho" placeholder="GitHub username" autocomplete="off" autocapitalize="off" spellcheck="false" maxlength="200">
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
-- specialities_004 — specialities follow core_296's craft rename (task 1005141,
|
|
2
|
+
-- BONGOS-V3 C1): engineer → artisan, ideator → artist.
|
|
3
|
+
--
|
|
4
|
+
-- A speciality's discipline is immutable to its OWNER (the update path refuses a
|
|
5
|
+
-- change); this is a vocabulary rename, not a move between crafts, so it rewrites the
|
|
6
|
+
-- catalog and the adoption copy together.
|
|
7
|
+
--
|
|
8
|
+
-- The fold has one collision: specialities_adoptions allows ONE active adoption per
|
|
9
|
+
-- builder per craft. A builder with an active artist speciality AND an active ideator
|
|
10
|
+
-- one would hold two artist adoptions after the rename, so the ideator adoption is
|
|
11
|
+
-- deactivated first (deactivating is how a builder switches; nothing is deleted, and
|
|
12
|
+
-- they can re-adopt it from their speciality page).
|
|
13
|
+
|
|
14
|
+
BEGIN;
|
|
15
|
+
|
|
16
|
+
UPDATE specialities_adoptions i
|
|
17
|
+
SET active = FALSE
|
|
18
|
+
WHERE i.active AND i.discipline = 'ideator'
|
|
19
|
+
AND EXISTS (SELECT 1 FROM specialities_adoptions a
|
|
20
|
+
WHERE a.builder_id = i.builder_id AND a.active AND a.discipline = 'artist');
|
|
21
|
+
|
|
22
|
+
UPDATE specialities_catalog SET discipline = 'artisan' WHERE discipline = 'engineer';
|
|
23
|
+
UPDATE specialities_catalog SET discipline = 'artist' WHERE discipline = 'ideator';
|
|
24
|
+
UPDATE specialities_adoptions SET discipline = 'artisan' WHERE discipline = 'engineer';
|
|
25
|
+
UPDATE specialities_adoptions SET discipline = 'artist' WHERE discipline = 'ideator';
|
|
26
|
+
|
|
27
|
+
INSERT INTO schema_migrations (version) VALUES ('specialities_004_crafts_artisan_artist')
|
|
28
|
+
ON CONFLICT (version) DO NOTHING;
|
|
29
|
+
|
|
30
|
+
COMMIT;
|
|
@@ -192,7 +192,7 @@ module.exports = function buildSpecialitiesRouter() {
|
|
|
192
192
|
|
|
193
193
|
const draft = {
|
|
194
194
|
name: String(b.name).trim(),
|
|
195
|
-
discipline: b.discipline,
|
|
195
|
+
discipline: api.crafts.normalizeCraft(b.discipline), // old spellings read as today's (task 1005141)
|
|
196
196
|
summary: b.summary || '',
|
|
197
197
|
contract_md: b.contract_md || '',
|
|
198
198
|
visibility: b.visibility || 'private',
|
|
@@ -247,7 +247,7 @@ module.exports = function buildSpecialitiesRouter() {
|
|
|
247
247
|
const b = req.body || {};
|
|
248
248
|
const draft = {
|
|
249
249
|
name: String(b.name).trim(),
|
|
250
|
-
discipline: b.discipline,
|
|
250
|
+
discipline: api.crafts.normalizeCraft(b.discipline), // old spellings read as today's (task 1005141)
|
|
251
251
|
summary: b.summary || '',
|
|
252
252
|
contract_md: b.contract_md || '',
|
|
253
253
|
visibility: b.visibility || 'private',
|
|
@@ -987,7 +987,7 @@ function renderAchievementRow(ids) {
|
|
|
987
987
|
// task 1004437 (WA6.RP07): each row names its roles, main first — the crafts
|
|
988
988
|
// the builder has EARNED in, from the row's own `roles.shown`, not only what
|
|
989
989
|
// they declared. The same words the hall's roster uses. Text only, never markup.
|
|
990
|
-
const ROLE_WORD = {
|
|
990
|
+
const ROLE_WORD = { artisan: 'Artisan', artist: 'Artist' };
|
|
991
991
|
function renderRoles(roles) {
|
|
992
992
|
const shown = roles && Array.isArray(roles.shown) ? roles.shown.filter((c) => ROLE_WORD[c]) : [];
|
|
993
993
|
if (!shown.length) return null;
|
|
@@ -2,27 +2,27 @@
|
|
|
2
2
|
"_": "GET /community/leaderboard for the kit stub (task 1003363): one ranked list per window, already in the route's order (credits, ships, karma, handle). The stub filters by discipline and numbers `place`. Names are invented; the long one tests the row's wrap.",
|
|
3
3
|
"boards": {
|
|
4
4
|
"all": [
|
|
5
|
-
{ "handle": "priya-nair", "github_login": "priyanair", "display_name": "Priya Nair", "avatar_url": "/__kit/avatar.svg", "credits": 18420, "tasks_shipped": 212, "karma": 64, "disciplines": ["
|
|
6
|
-
{ "handle": "tomas-ek", "github_login": "tomasek", "display_name": "Tomas Ek", "avatar_url": "/__kit/avatar.svg", "credits": 9310, "tasks_shipped": 131, "karma": 40, "disciplines": ["
|
|
5
|
+
{ "handle": "priya-nair", "github_login": "priyanair", "display_name": "Priya Nair", "avatar_url": "/__kit/avatar.svg", "credits": 18420, "tasks_shipped": 212, "karma": 64, "disciplines": ["artisan", "ui"] },
|
|
6
|
+
{ "handle": "tomas-ek", "github_login": "tomasek", "display_name": "Tomas Ek", "avatar_url": "/__kit/avatar.svg", "credits": 9310, "tasks_shipped": 131, "karma": 40, "disciplines": ["artisan"] },
|
|
7
7
|
{ "handle": "ada-okafor", "github_login": "adaokafor", "display_name": "Ada Okafor", "avatar_url": "/__kit/avatar.svg", "credits": 6125, "tasks_shipped": 77, "karma": 52, "disciplines": ["artist"] },
|
|
8
|
-
{ "handle": "lin-wei", "github_login": "linwei", "display_name": "Lin Wei", "avatar_url": null, "credits": 2480, "tasks_shipped": 31, "karma": 18, "disciplines": ["
|
|
8
|
+
{ "handle": "lin-wei", "github_login": "linwei", "display_name": "Lin Wei", "avatar_url": null, "credits": 2480, "tasks_shipped": 31, "karma": 18, "disciplines": ["artist", "artisan"] },
|
|
9
9
|
{ "handle": "maximiliana-van-der-berghe-lindqvist", "github_login": "mvdbl", "display_name": "Maximiliana van der Berghe-Lindqvist", "avatar_url": "/__kit/avatar.svg", "credits": 940, "tasks_shipped": 12, "karma": 7, "disciplines": ["ui"] },
|
|
10
|
-
{ "handle": "jo-park", "github_login": "jopark", "display_name": null, "avatar_url": "/__kit/avatar.svg", "credits": 310, "tasks_shipped": 1, "karma": 0, "disciplines": ["
|
|
10
|
+
{ "handle": "jo-park", "github_login": "jopark", "display_name": null, "avatar_url": "/__kit/avatar.svg", "credits": 310, "tasks_shipped": 1, "karma": 0, "disciplines": ["artist"] }
|
|
11
11
|
],
|
|
12
12
|
"365d": [
|
|
13
|
-
{ "handle": "priya-nair", "github_login": "priyanair", "display_name": "Priya Nair", "avatar_url": "/__kit/avatar.svg", "credits": 12200, "tasks_shipped": 150, "karma": 41, "disciplines": ["
|
|
13
|
+
{ "handle": "priya-nair", "github_login": "priyanair", "display_name": "Priya Nair", "avatar_url": "/__kit/avatar.svg", "credits": 12200, "tasks_shipped": 150, "karma": 41, "disciplines": ["artisan", "ui"] },
|
|
14
14
|
{ "handle": "ada-okafor", "github_login": "adaokafor", "display_name": "Ada Okafor", "avatar_url": "/__kit/avatar.svg", "credits": 6125, "tasks_shipped": 77, "karma": 52, "disciplines": ["artist"] },
|
|
15
|
-
{ "handle": "tomas-ek", "github_login": "tomasek", "display_name": "Tomas Ek", "avatar_url": "/__kit/avatar.svg", "credits": 4020, "tasks_shipped": 58, "karma": 22, "disciplines": ["
|
|
16
|
-
{ "handle": "lin-wei", "github_login": "linwei", "display_name": "Lin Wei", "avatar_url": null, "credits": 2480, "tasks_shipped": 31, "karma": 18, "disciplines": ["
|
|
15
|
+
{ "handle": "tomas-ek", "github_login": "tomasek", "display_name": "Tomas Ek", "avatar_url": "/__kit/avatar.svg", "credits": 4020, "tasks_shipped": 58, "karma": 22, "disciplines": ["artisan"] },
|
|
16
|
+
{ "handle": "lin-wei", "github_login": "linwei", "display_name": "Lin Wei", "avatar_url": null, "credits": 2480, "tasks_shipped": 31, "karma": 18, "disciplines": ["artist", "artisan"] }
|
|
17
17
|
],
|
|
18
18
|
"30d": [
|
|
19
19
|
{ "handle": "ada-okafor", "github_login": "adaokafor", "display_name": "Ada Okafor", "avatar_url": "/__kit/avatar.svg", "credits": 1340, "tasks_shipped": 19, "karma": 9, "disciplines": ["artist"] },
|
|
20
|
-
{ "handle": "priya-nair", "github_login": "priyanair", "display_name": "Priya Nair", "avatar_url": "/__kit/avatar.svg", "credits": 880, "tasks_shipped": 11, "karma": 4, "disciplines": ["
|
|
21
|
-
{ "handle": "jo-park", "github_login": "jopark", "display_name": null, "avatar_url": "/__kit/avatar.svg", "credits": 310, "tasks_shipped": 1, "karma": 0, "disciplines": ["
|
|
20
|
+
{ "handle": "priya-nair", "github_login": "priyanair", "display_name": "Priya Nair", "avatar_url": "/__kit/avatar.svg", "credits": 880, "tasks_shipped": 11, "karma": 4, "disciplines": ["artisan", "ui"] },
|
|
21
|
+
{ "handle": "jo-park", "github_login": "jopark", "display_name": null, "avatar_url": "/__kit/avatar.svg", "credits": 310, "tasks_shipped": 1, "karma": 0, "disciplines": ["artist"] }
|
|
22
22
|
],
|
|
23
23
|
"7d": [
|
|
24
24
|
{ "handle": "ada-okafor", "github_login": "adaokafor", "display_name": "Ada Okafor", "avatar_url": "/__kit/avatar.svg", "credits": 420, "tasks_shipped": 6, "karma": 3, "disciplines": ["artist"] },
|
|
25
|
-
{ "handle": "tomas-ek", "github_login": "tomasek", "display_name": "Tomas Ek", "avatar_url": "/__kit/avatar.svg", "credits": -15, "tasks_shipped": 0, "karma": 1, "disciplines": ["
|
|
25
|
+
{ "handle": "tomas-ek", "github_login": "tomasek", "display_name": "Tomas Ek", "avatar_url": "/__kit/avatar.svg", "credits": -15, "tasks_shipped": 0, "karma": 1, "disciplines": ["artisan"] }
|
|
26
26
|
]
|
|
27
27
|
}
|
|
28
28
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"_": "GET /community/search for the kit stub (task 1003363): the public, existence-visible builders the stub matches by name or handle. Sam Rivera hides their numbers, so `disciplines` is null: found by name, dropped by any craft filter (builder-search.js).",
|
|
3
3
|
"directory": [
|
|
4
|
-
{ "handle": "priya-nair", "github_login": "priyanair", "display_name": "Priya Nair", "avatar_url": "/__kit/avatar.svg", "disciplines": ["
|
|
4
|
+
{ "handle": "priya-nair", "github_login": "priyanair", "display_name": "Priya Nair", "avatar_url": "/__kit/avatar.svg", "disciplines": ["artisan", "ui"] },
|
|
5
5
|
{ "handle": "priyanka-shah", "github_login": "pshah", "display_name": "Priyanka Shah", "avatar_url": "/__kit/avatar.svg", "disciplines": ["artist"] },
|
|
6
|
-
{ "handle": "tomas-ek", "github_login": "tomasek", "display_name": "Tomas Ek", "avatar_url": "/__kit/avatar.svg", "disciplines": ["
|
|
6
|
+
{ "handle": "tomas-ek", "github_login": "tomasek", "display_name": "Tomas Ek", "avatar_url": "/__kit/avatar.svg", "disciplines": ["artisan"] },
|
|
7
7
|
{ "handle": "ada-okafor", "github_login": "adaokafor", "display_name": "Ada Okafor", "avatar_url": "/__kit/avatar.svg", "disciplines": ["artist"] },
|
|
8
8
|
{ "handle": "sam-rivera", "github_login": "samrivera", "display_name": "Sam Rivera", "avatar_url": "/__kit/avatar.svg", "disciplines": null }
|
|
9
9
|
]
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"_": "GET /scouting for a viewer the recruiting door admits — a project owner (task 1003363). `builders` is the ranked tier, which the community page never draws (the leaderboard already shows those numbers to everyone); `name_only` is ADR 0334's hidden-but-open-to-recruiters tier, login, name and avatar only, alphabetical by login as listScoutingNameOnly sends it.",
|
|
3
3
|
"builders": [
|
|
4
|
-
{ "github_id": "9001", "github_login": "priyanair", "display_name": "Priya Nair", "avatar_url": "/__kit/avatar.svg", "project_count": 3, "total_credits": 18420, "total_tasks_shipped": 212, "total_karma": 64, "last_active": "2026-10-20T10:00:00Z", "disciplines": ["
|
|
4
|
+
{ "github_id": "9001", "github_login": "priyanair", "display_name": "Priya Nair", "avatar_url": "/__kit/avatar.svg", "project_count": 3, "total_credits": 18420, "total_tasks_shipped": 212, "total_karma": 64, "last_active": "2026-10-20T10:00:00Z", "disciplines": ["artisan", "ui"] }
|
|
5
5
|
],
|
|
6
6
|
"name_only": [
|
|
7
7
|
{ "github_login": "kemi-a", "display_name": "Kemi Adeyemi", "avatar_url": "/__kit/avatar.svg" },
|
package/package-lock.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bongos/core",
|
|
3
|
-
"version": "1.24.
|
|
3
|
+
"version": "1.24.80",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@bongos/core",
|
|
9
|
-
"version": "1.24.
|
|
9
|
+
"version": "1.24.80",
|
|
10
10
|
"license": "AGPL-3.0-or-later",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"express": "^4.21.2",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bongos/core",
|
|
3
|
-
"version": "1.24.
|
|
3
|
+
"version": "1.24.80",
|
|
4
4
|
"description": "Cloud Bongos — the AI-first build platform core (GDS + platform surfaces + module system), installed as a versioned dependency (ADR 0108).",
|
|
5
5
|
"license": "AGPL-3.0-or-later",
|
|
6
6
|
"main": "src/platform-server.js",
|
package/release-notes.json
CHANGED
|
@@ -11507,5 +11507,81 @@
|
|
|
11507
11507
|
"id": "1005094",
|
|
11508
11508
|
"text": "Running Autobongos on a device is now one button. In Settings, Add a device gives you one line to paste on any Windows PC or Mac; its card then appears by itself with a Run button. The button's face tells you what the device i"
|
|
11509
11509
|
}
|
|
11510
|
+
],
|
|
11511
|
+
"1.24.79": [
|
|
11512
|
+
{
|
|
11513
|
+
"id": "1005186",
|
|
11514
|
+
"text": "Closed a gap opened by letting Autobongos run on any device. The runner now keeps its own sign-in in its own folder, and the rule that stops an AI session from opening sign-in files did not yet cover that folder. It does now,"
|
|
11515
|
+
}
|
|
11516
|
+
],
|
|
11517
|
+
"1.24.80": [
|
|
11518
|
+
{
|
|
11519
|
+
"id": "1005193",
|
|
11520
|
+
"text": "New versions can be published again: the checks broken by the craft rename pass, and projects on older versions no longer show the old craft name on the hub."
|
|
11521
|
+
},
|
|
11522
|
+
{
|
|
11523
|
+
"id": "1005148",
|
|
11524
|
+
"text": "In game mode, each builder now sees the project through a visor: their character's actions on the glass, their own character and credits in the corner, and a list of every action on the A key."
|
|
11525
|
+
},
|
|
11526
|
+
{
|
|
11527
|
+
"id": "1005145",
|
|
11528
|
+
"text": "Checked and locked in: after signing in and pressing Start there is no sidebar, and sound, the command-line key and module switches are all reached inside the one options menu; the old settings pages now only send you there."
|
|
11529
|
+
},
|
|
11530
|
+
{
|
|
11531
|
+
"id": "1004794",
|
|
11532
|
+
"text": "Modules can now say what language they are written in, and one naming a language Bongos cannot run yet is turned away with a clear reason."
|
|
11533
|
+
},
|
|
11534
|
+
{
|
|
11535
|
+
"id": "1004793",
|
|
11536
|
+
"text": "Work on the module store can now be planned under a goal, because its code finally has an owner in the project map."
|
|
11537
|
+
},
|
|
11538
|
+
{
|
|
11539
|
+
"id": "1005147",
|
|
11540
|
+
"text": "Builders now pick one of three characters (Artisan, Artist or Patron, drawn from the owner's art) when they join; the pick follows them to every device and shows as their sprite in the top bar."
|
|
11541
|
+
},
|
|
11542
|
+
{
|
|
11543
|
+
"id": "1005144",
|
|
11544
|
+
"text": "Every setting now lives in one options menu with a search box, and in game mode Escape opens it and closes it again."
|
|
11545
|
+
},
|
|
11546
|
+
{
|
|
11547
|
+
"id": "1005191",
|
|
11548
|
+
"text": "A project that is behind now asks its owner, in a clear pop-up, whether to update the builders hall."
|
|
11549
|
+
},
|
|
11550
|
+
{
|
|
11551
|
+
"id": "1005143",
|
|
11552
|
+
"text": "Signing in now opens a start screen (Start, Options, Achievements, Extras, Quit). Start plays a short load screen where the project city builds up week by week with a tip, then the hall opens full screen."
|
|
11553
|
+
},
|
|
11554
|
+
{
|
|
11555
|
+
"id": "1005158",
|
|
11556
|
+
"text": "Design written for claiming work as a chain: a chain reserves a run of tasks for you and your party, while each task inside it is still claimed on its own through the same safety checks as today. Nobody outside the party can g"
|
|
11557
|
+
},
|
|
11558
|
+
{
|
|
11559
|
+
"id": "1005190",
|
|
11560
|
+
"text": "A project owner can now skip the setup stages and open the full hall straight away, with the skip recorded."
|
|
11561
|
+
},
|
|
11562
|
+
{
|
|
11563
|
+
"id": "1005189",
|
|
11564
|
+
"text": "Setting up as a new builder no longer stops to ask for an optional image-generation key."
|
|
11565
|
+
},
|
|
11566
|
+
{
|
|
11567
|
+
"id": "1005146",
|
|
11568
|
+
"text": "Decided how the game's first-person visor sits over the city and the sky, and what the Escape key closes first. Also found a small bug where closing a city card brings the sidebar back."
|
|
11569
|
+
},
|
|
11570
|
+
{
|
|
11571
|
+
"id": "1005066",
|
|
11572
|
+
"text": "Project owners can now invite someone to the project's GitHub repository from the hall's invite box, always read-only, so a person who signs in to the hall can also see the code on their own GitHub once they accept GitHub's em"
|
|
11573
|
+
},
|
|
11574
|
+
{
|
|
11575
|
+
"id": "1005185",
|
|
11576
|
+
"text": "Making a new worktree on a hosted project now tells you the claim command that actually works there (npx bongos claim), instead of one that fails."
|
|
11577
|
+
},
|
|
11578
|
+
{
|
|
11579
|
+
"id": "1005183",
|
|
11580
|
+
"text": "The notes that guide agents around the claim rules pointed at the wrong lines of code. They now name the code directly, and a test stops them going stale again."
|
|
11581
|
+
},
|
|
11582
|
+
{
|
|
11583
|
+
"id": "1005141",
|
|
11584
|
+
"text": "The builders' crafts now carry their game names: Engineers are Artisans, Ideators join the Artists, and Patron is the third character; old links and old records keep working."
|
|
11585
|
+
}
|
|
11510
11586
|
]
|
|
11511
11587
|
}
|
|
@@ -74,16 +74,31 @@ const LOG_ROTATE_BYTES = 20 * 1024 * 1024;
|
|
|
74
74
|
function runnerHome(env = process.env, home = os.homedir(), repoRoot = REPO_ROOT) {
|
|
75
75
|
if (env.AUTOBONGOS_HOME) return path.resolve(env.AUTOBONGOS_HOME);
|
|
76
76
|
if (path.basename(repoRoot) === 'repo' && isRunnerCopy(repoRoot)) return path.dirname(repoRoot);
|
|
77
|
-
return path.join(home,
|
|
77
|
+
return path.join(home, RUNNER_DIR);
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
//
|
|
81
|
-
//
|
|
80
|
+
// The runner's folder in the person's home. Named once: the read-deny rule that
|
|
81
|
+
// keeps agents out of the runner's login names this same folder
|
|
82
|
+
// (scripts/bongos/claude-materialize.js RUNNER_CONFIG_DENY), and a test holds the
|
|
83
|
+
// two together.
|
|
84
|
+
const RUNNER_DIR = '.cloudbongos-runner';
|
|
85
|
+
|
|
86
|
+
// hostPaths — every file this program owns. `configRoot` is handed to the
|
|
87
|
+
// supervisor as BONGOS_CONFIG_ROOT, which is what keeps its login apart.
|
|
88
|
+
//
|
|
89
|
+
// THE LOGIN LIVES IN ONE PLACE ON EVERY DEVICE (task 1005186): configRoot is always
|
|
90
|
+
// <home>/.cloudbongos-runner/config, WHATEVER AUTOBONGOS_HOME says. That variable
|
|
91
|
+
// moves the runner's copy of the project, its logs and its lock; it does not move
|
|
92
|
+
// the login. The reason is the deny rule: agents are refused reads under exactly
|
|
93
|
+
// that folder, and a login that could be put somewhere else by an environment
|
|
94
|
+
// variable would be a login the rule does not cover — on precisely the device
|
|
95
|
+
// someone had customised. One runner per device already, so there is nothing a
|
|
96
|
+
// second config folder would be for.
|
|
82
97
|
function hostPaths(env = process.env, home = os.homedir()) {
|
|
83
98
|
const root = runnerHome(env, home);
|
|
84
99
|
return {
|
|
85
100
|
root,
|
|
86
|
-
configRoot: path.join(
|
|
101
|
+
configRoot: path.join(home, RUNNER_DIR, 'config'),
|
|
87
102
|
logDir: path.join(root, 'logs'),
|
|
88
103
|
log: path.join(root, 'logs', 'autobongos.log'),
|
|
89
104
|
lock: path.join(root, 'host.json'),
|
|
@@ -82,7 +82,7 @@ function buildWorkerArgs({ sessionId, model = DEFAULT_MODEL, isRoot = false } =
|
|
|
82
82
|
// runs unattended with the power to ship, so that text must never be able to
|
|
83
83
|
// instruct it. Reuses the grader's hardened fence rather than re-typing one, so
|
|
84
84
|
// there is a single place this class of text is scrubbed and delimited.
|
|
85
|
-
function buildWorkerPrompt({ task, packPath = 'docs/packs/
|
|
85
|
+
function buildWorkerPrompt({ task, packPath = 'docs/packs/artisan.md' } = {}) {
|
|
86
86
|
if (!task || !task.id) throw new Error('buildWorkerPrompt: a task with an id is required');
|
|
87
87
|
return [
|
|
88
88
|
`You are an autonomous builder working ONE claimed task end to end. Read CLAUDE.md and ${packPath} for context. The task is ${task.id}.`,
|
|
@@ -481,10 +481,29 @@ const STARTER_DENY_SECRETS = [
|
|
|
481
481
|
'Read(**/*.pem)', 'Read(**/id_rsa*)', 'Read(**/id_ed25519*)',
|
|
482
482
|
];
|
|
483
483
|
const SESSION_STORE_DENY = `Read(~/.config/${ic.FALLBACK_DIR}/instances/**)`;
|
|
484
|
+
// An Autobongos runner keeps ITS OWN login and files in a folder of its own (task 1005095:
|
|
485
|
+
// BONGOS_CONFIG_ROOT, so adding a laptop as a runner never touches the builder's CLI session).
|
|
486
|
+
// That put the runner's session file, and the session store beside it, outside every rule above,
|
|
487
|
+
// which all stop at ~/.config — so on a runner device a worker could open the file and read the
|
|
488
|
+
// runner's login (task 1005186). The whole folder is denied rather than one file name: the
|
|
489
|
+
// runner's heartbeat and run log sit there too and no agent has a reason to read any of it, and
|
|
490
|
+
// a rule on the folder cannot be stepped around by a session file under a new name.
|
|
491
|
+
// The folder name is the device program's (scripts/bongos/autobongos-host.js hostPaths); it is
|
|
492
|
+
// spelled here rather than required from there because this file is the installer and must not
|
|
493
|
+
// load the runner, and tests/claude_materialize.mjs fails if the two ever name different places.
|
|
494
|
+
const RUNNER_CONFIG_DENY = 'Read(~/.cloudbongos-runner/config/**)';
|
|
495
|
+
|
|
496
|
+
// The rules that name a FIXED place, whatever the instance is called.
|
|
497
|
+
const FIXED_PLACE_DENY = [SESSION_STORE_DENY, RUNNER_CONFIG_DENY];
|
|
484
498
|
|
|
485
499
|
// A checkout's settings.json takes the identity rebrand like every copied file, and the store's
|
|
486
500
|
// dir is one of the core's `.config/<dir>` literals it rewrites. The store does not move with the
|
|
487
501
|
// brand (task 1003741), so its rule is put back where the CLI reads it (task 1004155).
|
|
502
|
+
//
|
|
503
|
+
// The runner rule needs no putting back: the rebrand rewrites `.config/<core dir>` literals, and
|
|
504
|
+
// the runner's folder is not one (measured: with the put-back removed, the three-brand case in
|
|
505
|
+
// tests/claude_materialize.mjs still holds). That case is what would notice a future rebrand
|
|
506
|
+
// rule broad enough to carry it off.
|
|
488
507
|
function rebrandSettings(text, rebrand) {
|
|
489
508
|
const moved = rebrand(SESSION_STORE_DENY);
|
|
490
509
|
return rebrand(text).split(JSON.stringify(moved)).join(JSON.stringify(SESSION_STORE_DENY));
|
|
@@ -504,7 +523,7 @@ function credentialDeny(branding = {}) {
|
|
|
504
523
|
return [
|
|
505
524
|
...STARTER_DENY_SECRETS,
|
|
506
525
|
...dirs.flatMap((dir) => credentialFiles.map((file) => `Read(~/.config/${dir}/${file})`)),
|
|
507
|
-
|
|
526
|
+
...FIXED_PLACE_DENY,
|
|
508
527
|
];
|
|
509
528
|
}
|
|
510
529
|
|