@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
|
@@ -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
|
@@ -11513,5 +11513,75 @@
|
|
|
11513
11513
|
"id": "1005186",
|
|
11514
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
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
|
+
}
|
|
11516
11586
|
]
|
|
11517
11587
|
}
|
|
@@ -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}.`,
|
|
@@ -1,20 +1,15 @@
|
|
|
1
1
|
{
|
|
2
|
-
"_doc": "The ROLE REGISTRY: discipline -> the operating playbook that craft works from (task 1267; reshaped by task 1002990). Since the kernel/pack split, a CORE craft names a `pack` — a markdown role pack under docs/packs/ that carries everything the root CLAUDE.md kernel deliberately does not, because it is true for one craft only. A module-contributed discipline may instead name a `skill` (a slash-command playbook under .claude/skills/), which is how `ui` -> /design still works (ADR 0272 keeps ui-design's contribution unchanged). An entry may carry both; it must carry at least one. GET /me reads this (src/bongos/craft-mode.js) and puts each active claim's entry — `directive` plus pack path — on the claim as `craft_mode`; the Conductor hook injects the one for the claim bound to the session's worktree, so the session opens the right playbook without anyone reading terminal output (task 1002992). claim.js reads it too, printing only the one role line and running `materializeModuleSkills`. There is NO classification step — `discipline` is already a column on the task. One registry, never a server-side copy. A missing or invalid version of this file must never break a claim (claim.js fails open) — but fitness.js DOES hard-fail CI when an entry names a pack that is not in the tree, so the fail-open runtime cannot hide a broken registry from the build.
|
|
2
|
+
"_doc": "The ROLE REGISTRY: discipline -> the operating playbook that craft works from (task 1267; reshaped by task 1002990). Since the kernel/pack split, a CORE craft names a `pack` — a markdown role pack under docs/packs/ that carries everything the root CLAUDE.md kernel deliberately does not, because it is true for one craft only. A module-contributed discipline may instead name a `skill` (a slash-command playbook under .claude/skills/), which is how `ui` -> /design still works (ADR 0272 keeps ui-design's contribution unchanged). An entry may carry both; it must carry at least one. GET /me reads this (src/bongos/craft-mode.js) and puts each active claim's entry — `directive` plus pack path — on the claim as `craft_mode`; the Conductor hook injects the one for the claim bound to the session's worktree, so the session opens the right playbook without anyone reading terminal output (task 1002992). claim.js reads it too, printing only the one role line and running `materializeModuleSkills`. There is NO classification step — `discipline` is already a column on the task. One registry, never a server-side copy. A missing or invalid version of this file must never break a claim (claim.js fails open) — but fitness.js DOES hard-fail CI when an entry names a pack that is not in the tree, so the fail-open runtime cannot hide a broken registry from the build. THE GAME'S CHARACTERS (task 1005141, BONGOS-V3): engineer is now artisan, and the ideator folded into the artist, so there are two core packs — artisan.md and artist.md (which carries the ideation half). Patron is a character, not a task craft, and has no pack yet. A task row still holding an old spelling is read as the new one (src/crafts.js normalizeCraft). A mode entry may also set \"materializeModuleSkills\": true to have the claim land that mode's module-owned skills into this checkout's .claude/skills/ (task 1003486) — opt-in per discipline, core-checkout only, and fail-open like the hint itself.",
|
|
3
3
|
"modes": {
|
|
4
|
-
"
|
|
5
|
-
"pack": "docs/packs/
|
|
6
|
-
"label": "
|
|
7
|
-
"directive": "This is an
|
|
8
|
-
},
|
|
9
|
-
"ideator": {
|
|
10
|
-
"pack": "docs/packs/ideator.md",
|
|
11
|
-
"label": "Ideation session",
|
|
12
|
-
"directive": "This is an IDEATOR task. Read the Ideator pack now and work from it — it is the operating playbook for ideation and the only place the experience is defined. It inverts the usual dynamic: you (the human ideator) are the creative driver and Claude is your sounding board / research arm / devil's advocate, not a content generator filing ideas on command. Quick ideas stay ONE LINE, and after one is filed Claude asks whether to develop it into a Full Idea — five questions, drawn out of the conversation in the ideator's own words and scored on completeness. If no human is present (autonomous / bypass-permissions), the pack runs a self-adversarial divergence-and-critique loop instead of dumping a fixed batch. THE SURFACE, not just the behavior (ADR 0271): an ideator session is QUIET about its own machinery. Report outcomes, not mechanism — do not narrate tool calls, file paths, script names, API routes or task/claim bookkeeping unless they ask or something actually failed. Speak in the language of the idea, not the plumbing. If a step breaks, say plainly what broke and what you need — quiet never means hiding a problem."
|
|
4
|
+
"artisan": {
|
|
5
|
+
"pack": "docs/packs/artisan.md",
|
|
6
|
+
"label": "Artisan session",
|
|
7
|
+
"directive": "This is an ARTISAN task (the craft once called engineer). Read the Artisan pack now, before working — it is the operating playbook for this craft and the only place the standard build loop is written down: understand the code before editing -> make the smallest correct, scoped change -> VERIFY it (smoke tests + the preview/verification workflow when observable) -> /builder-ship with real notes. Building is already the default way you'd work, so the pack is the standard made explicit (plus the autonomous-mode guardrails: be conservative, verify hard, don't wander), not a redirect."
|
|
13
8
|
},
|
|
14
9
|
"artist": {
|
|
15
10
|
"pack": "docs/packs/artist.md",
|
|
16
|
-
"label": "
|
|
17
|
-
"directive": "This is an ARTIST task. Read the Artist pack now and work from it — it is the operating playbook for
|
|
11
|
+
"label": "Artist session",
|
|
12
|
+
"directive": "This is an ARTIST task. Read the Artist pack now and work from it — it is the operating playbook for the artist craft, which holds both halves of what used to be two crafts (task 1005141): how the project LOOKS AND READS, and its IDEAS. It is show-first and low-text: communicate in pictures and rendered surfaces, not paragraphs about what ran. Interpret as little as possible — take the brief literally, you are the artist's hands and not their art director — and arrive precalculated: load the look, have the options already rendered, never open with a form of intake questions. The artist's subject is how the project LOOKS AND READS, which is core (ADR 0272); a pixel-art or asset pipeline is a host module the pack drives only when the instance ships one. If no human is present (autonomous / bypass-permissions), make it, gate it hard, stage the passes and park the visuals for human review. When the work is an idea rather than a surface, the pack's ideation half applies: It inverts the usual dynamic: you (the human artist) are the creative driver and Claude is your sounding board / research arm / devil's advocate, not a content generator filing ideas on command. Quick ideas stay ONE LINE, and after one is filed Claude asks whether to develop it into a Full Idea — five questions, drawn out of the conversation in the ideator's own words and scored on completeness. If no human is present (autonomous / bypass-permissions), the pack runs a self-adversarial divergence-and-critique loop instead of dumping a fixed batch. THE SURFACE, not just the behavior (ADR 0271): an ideation session is QUIET about its own machinery. Report outcomes, not mechanism — do not narrate tool calls, file paths, script names, API routes or task/claim bookkeeping unless they ask or something actually failed. Speak in the language of the idea, not the plumbing. If a step breaks, say plainly what broke and what you need — quiet never means hiding a problem."
|
|
18
13
|
},
|
|
19
14
|
"ui": {
|
|
20
15
|
"skill": "design",
|
|
@@ -524,7 +524,7 @@ const KERNEL_FILES = [
|
|
|
524
524
|
'src/module-api.js', // the published doorway
|
|
525
525
|
'src/modules.js', // the registry/resolver facade
|
|
526
526
|
'src/module-seams.js', // the seam registry (ports/events/contributions)
|
|
527
|
-
'src/role-responsibilities.js', 'src/html-escape.js', 'src/sleep.js', // owner's role statements (task 1003732) + THE server HTML escaper (task 1004876) + THE server sleep (task 1004893) — all import nothing
|
|
527
|
+
'src/crafts.js', 'src/role-responsibilities.js', 'src/html-escape.js', 'src/sleep.js', // the craft vocabulary (task 1005141) + owner's role statements (task 1003732) + THE server HTML escaper (task 1004876) + THE server sleep (task 1004893) — all import nothing
|
|
528
528
|
'src/module-loader/loader.js', // the disk loader (discover → validate → mount)
|
|
529
529
|
'src/module-loader/manifest-schema.js', // the manifest validator
|
|
530
530
|
'src/module-loader/semver.js', // coreVersion compatibility
|