@bongos/core 1.17.0
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 +5727 -0
- package/.claude/skills/blocker-review/SKILL.md +91 -0
- package/.claude/skills/blocker-solve/SKILL.md +96 -0
- package/.claude/skills/builder-backup/SKILL.md +54 -0
- package/.claude/skills/builder-box/SKILL.md +45 -0
- package/.claude/skills/builder-claim/SKILL.md +76 -0
- package/.claude/skills/builder-connect/SKILL.md +59 -0
- package/.claude/skills/builder-cost/SKILL.md +47 -0
- package/.claude/skills/builder-end/SKILL.md +81 -0
- package/.claude/skills/builder-exit/SKILL.md +88 -0
- package/.claude/skills/builder-key/SKILL.md +40 -0
- package/.claude/skills/builder-reauth/SKILL.md +50 -0
- package/.claude/skills/builder-redteam/SKILL.md +109 -0
- package/.claude/skills/builder-release/SKILL.md +41 -0
- package/.claude/skills/builder-setup/SKILL.md +62 -0
- package/.claude/skills/builder-ship/SKILL.md +79 -0
- package/.claude/skills/builder-stage/SKILL.md +51 -0
- package/.claude/skills/builder-start/SKILL.md +46 -0
- package/.claude/skills/close-box/SKILL.md +43 -0
- package/.claude/skills/design-sync/SKILL.md +69 -0
- package/.claude/skills/dev/SKILL.md +49 -0
- package/.claude/skills/feedback/SKILL.md +32 -0
- package/.claude/skills/figma-design-sync/SKILL.md +74 -0
- package/.claude/skills/goal-review/SKILL.md +89 -0
- package/.claude/skills/idea-triage/SKILL.md +144 -0
- package/.claude/skills/ideate/SKILL.md +82 -0
- package/.claude/skills/merge-mode/SKILL.md +169 -0
- package/.claude/skills/new-project/SKILL.md +108 -0
- package/.claude/skills/otb-character-review/SKILL.md +71 -0
- package/.claude/skills/otb-design-review/SKILL.md +47 -0
- package/.claude/skills/otb-feedback-capture/SKILL.md +45 -0
- package/.claude/skills/otb-figma-sync/SKILL.md +54 -0
- package/.claude/skills/otb-tile-generate/SKILL.md +45 -0
- package/.claude/skills/paint/SKILL.md +70 -0
- package/.claude/skills/planning-session/SKILL.md +299 -0
- package/.claude/skills/priority-session/SKILL.md +134 -0
- package/.claude/skills/read-session-export/SKILL.md +58 -0
- package/.claude/skills/recall/SKILL.md +52 -0
- package/.claude/skills/session-handoff/SKILL.md +46 -0
- package/.claude/skills/status/SKILL.md +33 -0
- package/.devcontainer/Dockerfile +69 -0
- package/.devcontainer/README.md +73 -0
- package/.devcontainer/devcontainer-lock.json +19 -0
- package/.devcontainer/devcontainer.json +93 -0
- package/.devcontainer/healthcheck.sh +84 -0
- package/.devcontainer/init-firewall.sh +198 -0
- package/.devcontainer/post-create.sh +153 -0
- package/.dockerignore +36 -0
- package/.env.local.example +32 -0
- package/.gitattributes +83 -0
- package/.gitignore +91 -0
- package/CLAUDE.md +242 -0
- package/CODE_OF_CONDUCT.md +46 -0
- package/CONTRIBUTING.md +51 -0
- package/Dockerfile +46 -0
- package/GOVERNANCE.md +44 -0
- package/LICENSE +661 -0
- package/README.md +88 -0
- package/bin/bongos.js +222 -0
- package/clients/bongos-client/README.md +48 -0
- package/clients/bongos-client/bongos-client.global.js +617 -0
- package/clients/bongos-client/examples/hello-world.mjs +62 -0
- package/clients/bongos-client/index.cjs +619 -0
- package/clients/bongos-client/index.d.ts +793 -0
- package/clients/bongos-client/index.mjs +614 -0
- package/clients/bongos-client/package.json +32 -0
- package/config/branding.neutral.json +60 -0
- package/config/design-tokens.neutral.json +51 -0
- package/config/design-tokens.schema.json +96 -0
- package/config/modules.neutral.json +9 -0
- package/docker-compose.yml +52 -0
- package/docker-entrypoint.sh +30 -0
- package/docs/adr/0001-stack-choice-single-vps.md +45 -0
- package/docs/adr/0002-digitalocean-over-hetzner.md +27 -0
- package/docs/adr/0003-cloudflare-origin-cert-over-letsencrypt.md +35 -0
- package/docs/adr/0004-amazonprimea-name-and-trademark-acceptance.md +45 -0
- package/docs/adr/0005-invisible-other-players-in-v1.md +37 -0
- package/docs/adr/0006-singleton-worldroom-plus-queueroom.md +30 -0
- package/docs/adr/0007-persistent-identity-via-localstorage-uuid.md +31 -0
- package/docs/adr/0008-family-based-tile-generation.md +86 -0
- package/docs/adr/0008-google-chat-oauth-user-auth.md +37 -0
- package/docs/adr/0009-autotile-architecture.md +181 -0
- package/docs/adr/0010-pms-architecture.md +70 -0
- package/docs/adr/0011-terrain-id-rendering-model.md +174 -0
- package/docs/adr/0012-ground-object-cell-split.md +208 -0
- package/docs/adr/0013-paths-as-object-overlays-with-autotile-dispatch.md +158 -0
- package/docs/adr/0014-families-canonical-over-vocabulary.md +103 -0
- package/docs/adr/0015-task-dependencies-and-auto-promotion.md +125 -0
- package/docs/adr/0016-trust-boundary-server-enforced-permissions.md +132 -0
- package/docs/adr/0017-code-simplification-and-repo-cleanliness.md +74 -0
- package/docs/adr/0018-three-rank-model-goes-live.md +97 -0
- package/docs/adr/0019-red-team-bounty-payout-table.md +52 -0
- package/docs/adr/0020-security-model-public-stub.md +70 -0
- package/docs/adr/0021-per-builder-skill-model-preferences.md +99 -0
- package/docs/adr/0022-secrets-policy.md +124 -0
- package/docs/adr/0023-kind-multipliers-and-idea-bonus.md +118 -0
- package/docs/adr/0024-cloneable-repo-local-first-memory.md +277 -0
- package/docs/adr/0024-multi-agent-system-architecture.md +125 -0
- package/docs/adr/0025-offsite-backup-vendor-digitalocean-spaces.md +59 -0
- package/docs/adr/0025-structured-criterion-task-link.md +44 -0
- package/docs/adr/0026-bfg-memory-hygiene-and-cross-builder-learning.md +117 -0
- package/docs/adr/0027-bfg-session-inefficiency-evaluator.md +170 -0
- package/docs/adr/0028-honest-llm-spend-accounting.md +109 -0
- package/docs/adr/0029-status-page-outage-resilience.md +59 -0
- package/docs/adr/0030-builders-hall-live-updates.md +59 -0
- package/docs/adr/0031-cloud-dev-environments-for-builders.md +222 -0
- package/docs/adr/0032-discord-mirror-of-gds.md +50 -0
- package/docs/adr/0033-discord-bot-service-principal.md +82 -0
- package/docs/adr/0034-thetes-graduated-newcomer-rank.md +53 -0
- package/docs/adr/0035-builder-onboarding-three-paths.md +128 -0
- package/docs/adr/0036-builders-subdomain-and-ui-reorg.md +40 -0
- package/docs/adr/0037-discord-channel-management.md +51 -0
- package/docs/adr/0038-chromebook-ttyd-cloudflare-tunnel.md +111 -0
- package/docs/adr/0039-setup-first-onboarding-ux.md +49 -0
- package/docs/adr/0040-remote-control-default-browser-onramp.md +47 -0
- package/docs/adr/0041-temporary-grader-bypass-killswitch.md +40 -0
- package/docs/adr/0042-builder-self-deploy-ci-auto-merge.md +82 -0
- package/docs/adr/0043-git-ssh-trust-boundary-and-rank-floor-on-permission-paths.md +74 -0
- package/docs/adr/0044-mediterranean-palette-replacement.md +73 -0
- package/docs/adr/0044-per-box-live-game-preview.md +57 -0
- package/docs/adr/0045-devbox-desktop-app.md +133 -0
- package/docs/adr/0046-sandbox-first-review-gate.md +72 -0
- package/docs/adr/0047-discord-bugs-intake-anti-abuse.md +36 -0
- package/docs/adr/0048-works-in-progress-ia-split.md +32 -0
- package/docs/adr/0049-split-parallel-safety-contract.md +46 -0
- package/docs/adr/0050-device-flow-admission-invite-gated-by-default.md +43 -0
- package/docs/adr/0051-full-session-transcript-corpus.md +57 -0
- package/docs/adr/0052-sandbox-for-everyone-game-only-preview.md +70 -0
- package/docs/adr/0053-scoped-dev-box-session.md +55 -0
- package/docs/adr/0054-session-token-reward-cost-plus.md +63 -0
- package/docs/adr/0055-server-mediated-branch-publish.md +47 -0
- package/docs/adr/0056-prod-deploy-script-mirror-and-healthcheck-retry.md +62 -0
- package/docs/adr/0057-container-cost-ledger.md +28 -0
- package/docs/adr/0057-discord-archon-approval-channels.md +64 -0
- package/docs/adr/0058-automatic-gate-surface-gatekeeper.md +64 -0
- package/docs/adr/0059-single-approval-remove-devbox-approval-gate.md +37 -0
- package/docs/adr/0060-gds-retrieval-layer.md +97 -0
- package/docs/adr/0061-context-layer-decomposition.md +61 -0
- package/docs/adr/0062-medusa-instance-model-decoupling.md +107 -0
- package/docs/adr/0063-generated-repo-map-symbol-skeleton.md +44 -0
- package/docs/adr/0064-rename-medusa-to-cloud-bongos.md +49 -0
- package/docs/adr/0065-agpl-nonprofit-ai-first-governance.md +69 -0
- package/docs/adr/0066-generated-file-map-sections.md +51 -0
- package/docs/adr/0067-session-start-fast-forward-pull.md +43 -0
- package/docs/adr/0068-shared-art-key-for-newcomers.md +38 -0
- package/docs/adr/0069-hall-live-channel-sse-decouple.md +35 -0
- package/docs/adr/0070-deterministic-session-card-delivery.md +44 -0
- package/docs/adr/0071-box-confirm-before-destroyed-and-drift-reconcile.md +59 -0
- package/docs/adr/0072-bongos-app-mac-signed-first-windows-deferred.md +35 -0
- package/docs/adr/0072-dev-box-code-staleness-visibility.md +39 -0
- package/docs/adr/0073-builder-needs-signal-and-byok-gemini-key.md +64 -0
- package/docs/adr/0073-secrets-scan-exclude-uri-detector.md +37 -0
- package/docs/adr/0074-memory-map-stays-light.md +32 -0
- package/docs/adr/0075-per-system-cost-attribution.md +37 -0
- package/docs/adr/0076-in-session-deterministic-compaction.md +58 -0
- package/docs/adr/0077-content-addressed-llm-cache.md +32 -0
- package/docs/adr/0078-deterministic-first-cron.md +48 -0
- package/docs/adr/0079-value-gated-autonomous-engagement.md +39 -0
- package/docs/adr/0080-llm-cache-api-transport-and-trust-model.md +46 -0
- package/docs/adr/0081-tool-agnostic-design-layer.md +62 -0
- package/docs/adr/0082-productized-key-storage-provisioning.md +32 -0
- package/docs/adr/0082-server-side-merge-conflict-auto-resolution.md +55 -0
- package/docs/adr/0083-modular-architecture-strangler-build-plan.md +143 -0
- package/docs/adr/0084-auto-derived-per-task-rank-floor.md +86 -0
- package/docs/adr/0085-remove-default-per-builder-spend-cap.md +39 -0
- package/docs/adr/0086-goal-scoped-work-hierarchy.md +123 -0
- package/docs/adr/0087-bongos-app-architecture-and-handoff-contract.md +49 -0
- package/docs/adr/0087-compete-on-governance-not-tooling-cursor.md +65 -0
- package/docs/adr/0088-consistent-character-generative-animation.md +169 -0
- package/docs/adr/0089-modular-multi-model-adversarial-grader.md +179 -0
- package/docs/adr/0090-metic-task-authoring.md +73 -0
- package/docs/adr/0091-bounding-the-kernel-and-db-carve.md +106 -0
- package/docs/adr/0092-hosting-module-and-on-prem-target.md +117 -0
- package/docs/adr/0093-tranche-2-core-carve-sequence.md +72 -0
- package/docs/adr/0094-repo-atlas-self-drawing-codebase-map.md +49 -0
- package/docs/adr/0095-borrowed-memory-and-retrieval-concepts.md +65 -0
- package/docs/adr/0095-cross-agent-context-management.md +58 -0
- package/docs/adr/0096-require-reward-before-workable.md +209 -0
- package/docs/adr/0097-one-active-claim-per-session-and-worktree-binding.md +46 -0
- package/docs/adr/0097-retroactive-reward-backfill.md +124 -0
- package/docs/adr/0098-public-mirror-publish-manifest.md +92 -0
- package/docs/adr/0099-delayed-redacted-mirror-export.md +55 -0
- package/docs/adr/0100-two-repo-instance-model.md +60 -0
- package/docs/adr/0101-goal-hierarchy-phase-5-judge-membership-reward.md +90 -0
- package/docs/adr/0102-finish-bounding-the-kernel.md +36 -0
- package/docs/adr/0103-core-first-extraction-cloud-bongos-trunk.md +70 -0
- package/docs/adr/0103-gdsv4-bongos-consolidation.md +28 -0
- package/docs/adr/0104-trust-gds-api-channel-in-auto-mode.md +42 -0
- package/docs/adr/0105-instance-seed-migrations-out-of-core.md +47 -0
- package/docs/adr/0106-goal-owner-manager-authority.md +84 -0
- package/docs/adr/0107-module-upstreaming-contribution-to-core-catalog.md +83 -0
- package/docs/adr/0108-instance-composition-configurable-root.md +87 -0
- package/docs/adr/0109-self-describing-openapi-and-hosted-docs.md +44 -0
- package/docs/adr/0110-untrack-whole-file-generated-nav-docs.md +49 -0
- package/docs/adr/0111-instance-hosting-provisioning-module.md +135 -0
- package/docs/adr/0112-private-goals-invitations-join-requests.md +72 -0
- package/docs/adr/0113-sandbox-studio-descope-superseded-by-0044-0052.md +41 -0
- package/docs/adr/0114-instance-docs-discovery-contract.md +32 -0
- package/docs/adr/0115-scheduled-routines-portability.md +31 -0
- package/docs/adr/0116-api-error-envelope-and-code-taxonomy.md +62 -0
- package/docs/adr/0117-api-versioning-and-deprecation-policy.md +50 -0
- package/docs/adr/0118-api-contract-source-of-truth-code-first.md +47 -0
- package/docs/adr/0119-api-pagination-contract.md +34 -0
- package/docs/adr/0120-pay-on-land-and-builder-owned-rebase-gate.md +108 -0
- package/docs/adr/0121-greenfield-vs-brownfield-onboarding-adopt-existing-repo.md +97 -0
- package/docs/adr/0122-onboarding-diagram-renders-deploy-rendered-off-git.md +43 -0
- package/docs/adr/0123-box-idle-sweep-autosave-before-destroy.md +36 -0
- package/docs/adr/0124-typed-api-response-bodies.md +37 -0
- package/docs/adr/0125-control-plane-scaffolds-standalone-instance-repo.md +36 -0
- package/docs/adr/0126-dedicated-cloudbongos-control-plane-droplet.md +30 -0
- package/docs/adr/0127-cross-box-fleet-observability.md +64 -0
- package/docs/adr/0128-provisioning-runner-privilege-and-db-auth-model.md +46 -0
- package/docs/adr/0129-cloudbongos-control-plane-pull-deploy.md +34 -0
- package/docs/adr/0130-provision-remote-exec-over-ssh.md +61 -0
- package/docs/adr/0131-rank-scoped-skill-visibility.md +47 -0
- package/docs/adr/0132-cohost-fleet-control-plane-migration.md +54 -0
- package/docs/adr/0133-github-app-manifest-onboarding-signin.md +42 -0
- package/docs/adr/0134-private-first-npm-distribution.md +38 -0
- package/docs/adr/README.md +208 -0
- package/docs/api/openapi.json +13720 -0
- package/docs/api-reference.md +437 -0
- package/docs/architecture.md +244 -0
- package/docs/branding-contract.md +66 -0
- package/docs/branding-fill-prompt.md +25 -0
- package/docs/canonical-permissions.md +241 -0
- package/docs/design/container-exterior-tiles.md +49 -0
- package/docs/design/container-exterior.md +81 -0
- package/docs/design/container-interior.md +77 -0
- package/docs/design/modular-architecture/00-research-report.md +107 -0
- package/docs/design/modular-architecture/01-architecture.md +125 -0
- package/docs/design/modular-architecture/02-module-map.md +116 -0
- package/docs/design/modular-architecture/03-builder-flows.md +104 -0
- package/docs/design/modular-architecture/04-module-lifecycle.md +62 -0
- package/docs/design/modular-architecture/README.md +27 -0
- package/docs/design/vanilla-hall-ui-redesign-scope.md +284 -0
- package/docs/design/world-map-scroll.md +41 -0
- package/docs/design-contract.md +320 -0
- package/docs/file-map.md +418 -0
- package/docs/handoff-template.md +92 -0
- package/docs/modules-contract.md +293 -0
- package/docs/onboarding/browser-terminal-guide.md +73 -0
- package/docs/onboarding/diagrams/01-task-lifecycle.mmd +28 -0
- package/docs/onboarding/diagrams/02-rank-ladder.mmd +54 -0
- package/docs/onboarding/diagrams/03-drachmae-karma.mmd +37 -0
- package/docs/onboarding/diagrams/04-architecture.mmd +51 -0
- package/docs/onboarding/diagrams/05-versioning.mmd +29 -0
- package/docs/onboarding/diagrams/README.md +94 -0
- package/docs/onboarding/diagrams/assertions.json +170 -0
- package/docs/onboarding/diagrams/puppeteer-config.json +1 -0
- package/docs/onboarding/diagrams/render-config.json +9 -0
- package/docs/onboarding/drachmae-and-karma.md +178 -0
- package/docs/onboarding/primer.md +202 -0
- package/docs/project-context.template.md +67 -0
- package/docs/recipes/README.md +35 -0
- package/docs/recipes/audit-replay.md +100 -0
- package/docs/recipes/bongos-cli-release.md +66 -0
- package/docs/recipes/builder-box-lifecycle.md +152 -0
- package/docs/recipes/claude-design-loop.md +143 -0
- package/docs/recipes/claude-gemini-bongos-doors.md +155 -0
- package/docs/recipes/cloudbongos-staging-gate.md +139 -0
- package/docs/recipes/cloudbongos-standup.md +111 -0
- package/docs/recipes/devbox-app-release.md +93 -0
- package/docs/recipes/devbox-app-windows-test.md +128 -0
- package/docs/recipes/failed-ship-recovery-proof.md +102 -0
- package/docs/recipes/figma-design-loop.md +129 -0
- package/docs/recipes/gds-db-backup.md +255 -0
- package/docs/recipes/instance-deploy.md +37 -0
- package/docs/recipes/managed-settings-remote-control.md +416 -0
- package/docs/recipes/memory-backup.md +71 -0
- package/docs/recipes/memory-sync-conflicts.md +98 -0
- package/docs/recipes/multi-builder-merge.md +78 -0
- package/docs/recipes/ops-gotchas.md +212 -0
- package/docs/recipes/overnight-builder.md +53 -0
- package/docs/recipes/packaging-the-core.md +49 -0
- package/docs/recipes/parallel-load-results-2026-05-30.md +63 -0
- package/docs/recipes/parallel-load-test.md +32 -0
- package/docs/recipes/pixel-art-pipeline.md +411 -0
- package/docs/recipes/private-npm-distribution.md +79 -0
- package/docs/recipes/search-index-ingestion.md +67 -0
- package/docs/recipes/self-host.md +60 -0
- package/docs/recipes/ship-and-regrade.md +72 -0
- package/docs/recipes/staging-data.md +50 -0
- package/docs/recipes/staging-environment.md +215 -0
- package/docs/recipes/upgrading-the-core.md +58 -0
- package/docs/research/cursor-competitive-analysis.md +255 -0
- package/docs/research/llm-model-agnostic-and-cheaper-grader.md +227 -0
- package/migrations/003_pms.sql +284 -0
- package/migrations/004_pms_cost_idempotency.sql +13 -0
- package/migrations/005_pms_smoke_filter.sql +44 -0
- package/migrations/006_pms_v2.sql +378 -0
- package/migrations/007_pms_v2_hierarchy_trigger.sql +59 -0
- package/migrations/008_pms_v2_migration_allocator.sql +27 -0
- package/migrations/009_pms_v2_blockers_table.sql +68 -0
- package/migrations/010_uptime.sql +29 -0
- package/migrations/011_backfill_v2_v3_done_when.sql +20 -0
- package/migrations/012_pms_v2_task_lifecycle_states.sql +82 -0
- package/migrations/013_claim_locking.sql +22 -0
- package/migrations/014_pms_task_discipline.sql +86 -0
- package/migrations/015_pms_estimation_calibration.sql +140 -0
- package/migrations/016_pms_task_grades.sql +60 -0
- package/migrations/017_version_progress_exclude_abandoned.sql +49 -0
- package/migrations/019_rename_pms_v3_to_gds_v3.sql +65 -0
- package/migrations/020_task_dependencies.sql +99 -0
- package/migrations/021_v3_renumber_and_deps.sql +224 -0
- package/migrations/022_v3_reconcile_dep_gated_status.sql +41 -0
- package/migrations/023_pms_rank.sql +30 -0
- package/migrations/025_builder_exit_status.sql +15 -0
- package/migrations/027_builders_preferred_disciplines.sql +46 -0
- package/migrations/028_tasks_parallel_safe.sql +71 -0
- package/migrations/029_rank_three_live.sql +32 -0
- package/migrations/030_vulnerability_reports.sql +61 -0
- package/migrations/031_reward_simplification.sql +57 -0
- package/migrations/032_repo_health_snapshots.sql +56 -0
- package/migrations/033_audit_log.sql +64 -0
- package/migrations/034_lifecycle_breakdown_leaf_only.sql +62 -0
- package/migrations/035_auth_token_hygiene.sql +66 -0
- package/migrations/037_builder_skill_model_prefs.sql +44 -0
- package/migrations/038_task_override_requests.sql +51 -0
- package/migrations/039_newcomer_friendly_column.sql +124 -0
- package/migrations/040_builder_karma.sql +58 -0
- package/migrations/041_kind_multipliers_and_idea_bonus.sql +42 -0
- package/migrations/042_criterion_proposal_workflow.sql +78 -0
- package/migrations/043_builder_onboarding_observability.sql +66 -0
- package/migrations/044_tasks_requires_rank.sql +97 -0
- package/migrations/045_builder_onboarding_state.sql +147 -0
- package/migrations/046_cost_log_builder_attribution.sql +42 -0
- package/migrations/054_builder_memory.sql +108 -0
- package/migrations/055_task_criteria.sql +90 -0
- package/migrations/058_peer_votes.sql +41 -0
- package/migrations/059_onboarding_pick_disciplines.sql +59 -0
- package/migrations/060_access_requests.sql +46 -0
- package/migrations/061_backfill_override_ship_attribution.sql +29 -0
- package/migrations/062_session_records.sql +34 -0
- package/migrations/063_session_records_tool_errors_idx.sql +11 -0
- package/migrations/064_grade_attempts.sql +18 -0
- package/migrations/065_bfg_principal.sql +58 -0
- package/migrations/066_live_notify_triggers.sql +69 -0
- package/migrations/067_builder_boxes.sql +117 -0
- package/migrations/067_discord_bot_foundation.sql +69 -0
- package/migrations/068_thetes_requires_rank.sql +27 -0
- package/migrations/069_builder_ssh_keys.sql +66 -0
- package/migrations/070_box_intents.sql +101 -0
- package/migrations/071_box_first_provision_approval.sql +46 -0
- package/migrations/072_onboarding_ship_three_remove_primer.sql +80 -0
- package/migrations/073_box_terminal_access.sql +46 -0
- package/migrations/075_builder_sound_prefs.sql +28 -0
- package/migrations/078_box_claude_active.sql +22 -0
- package/migrations/079_box_first_connected_at.sql +20 -0
- package/migrations/081_tasks_needs_migration.sql +34 -0
- package/migrations/084_tasks_security_sensitive.sql +24 -0
- package/migrations/085_security_engagement_docs.sql +34 -0
- package/migrations/086_rename_disciplines.sql +125 -0
- package/migrations/088_builders_anthropic_link.sql +28 -0
- package/migrations/089_builders_monthly_budget.sql +19 -0
- package/migrations/090_box_scoped_sessions.sql +38 -0
- package/migrations/091_session_token_reward.sql +44 -0
- package/migrations/093_tasks_sandbox_review.sql +22 -0
- package/migrations/102_remove_box_first_provision_approval.sql +58 -0
- package/migrations/103_search_chunks.sql +90 -0
- package/migrations/104_builder_box_blocked.sql +34 -0
- package/migrations/105_box_host_keys.sql +35 -0
- package/migrations/111_medusa_customer0_framing.sql +35 -0
- package/migrations/112_drop_track_check.sql +25 -0
- package/migrations/113_merge_lease.sql +16 -0
- package/migrations/114_cloudbongos_rename_live_strings.sql +32 -0
- package/migrations/118_currency_label_decoupling.sql +23 -0
- package/migrations/119_builder_behavior_prefs.sql +31 -0
- package/migrations/121_box_code_version.sql +37 -0
- package/migrations/122_builder_gemini_key.sql +30 -0
- package/migrations/123_cost_log_tiers.sql +33 -0
- package/migrations/124_cost_baseline.sql +45 -0
- package/migrations/125_llm_cache.sql +54 -0
- package/migrations/126_autonomy_runs.sql +33 -0
- package/migrations/143_cost_calibration.sql +63 -0
- package/migrations/145_backfill_task_requires_rank.sql +84 -0
- package/migrations/160_goal_tier.sql +88 -0
- package/migrations/163_polymorphic_dependencies.sql +187 -0
- package/migrations/164_event_sound_prefs.sql +20 -0
- package/migrations/165_task_module_key.sql +15 -0
- package/migrations/171_claims_published_head_sha.sql +24 -0
- package/migrations/174_close_orphaned_claims_on_terminal_tasks.sql +30 -0
- package/migrations/175_task_grades_diff_hash.sql +9 -0
- package/migrations/176_promotion_respects_open_blockers.sql +58 -0
- package/migrations/176_ui_discipline.sql +40 -0
- package/migrations/177_require_reward_before_workable.sql +76 -0
- package/migrations/178_reward_gate_auto_assign_revert_autopromote.sql +61 -0
- package/migrations/179_search_chunk_usefulness.sql +33 -0
- package/migrations/180_one_active_claim_per_session.sql +54 -0
- package/migrations/181_cost_log_skill_name.sql +33 -0
- package/migrations/184_claim_release_requested.sql +25 -0
- package/migrations/185_module_upstreaming_goal_wiring.sql +59 -0
- package/migrations/187_goal_sort_order.sql +30 -0
- package/migrations/187_tasks_kind_check_add_verify.sql +21 -0
- package/migrations/README.md +88 -0
- package/migrations/core_188_goal_visibility_and_membership_requests.sql +71 -0
- package/migrations/core_189_core_upgrades_ledger.sql +37 -0
- package/migrations/core_189_credit_log_task_id_index.sql +19 -0
- package/migrations/core_190_rebuild_claimable_task_views.sql +71 -0
- package/migrations/instance/018_pms_v3_planning_seed.sql +131 -0
- package/migrations/instance/080_gds_v4_planning_seed.sql +75 -0
- package/migrations/instance/110_medusa_planning_seed.sql +70 -0
- package/migrations/instance/120_bongos_v1_planning_seed.sql +69 -0
- package/migrations/instance/144_bongos_v1_module_system_criterion.sql +26 -0
- package/migrations/instance/159_bongos_v1_goal_hierarchy_criterion.sql +29 -0
- package/migrations/instance/172_v2_world_planning_seed.sql +163 -0
- package/migrations/instance/173_bongos_v1_c7_core_modularized.sql +33 -0
- package/migrations/instance/182_gdsv4_bongos_consolidation.sql +132 -0
- package/migrations/instance/183_gdsv4_carryover_themed_goals.sql +116 -0
- package/migrations/instance/186_bongos_v1_governance_planning_seed.sql +69 -0
- package/modules/autonomy/CLAUDE.md +49 -0
- package/modules/autonomy/db.js +50 -0
- package/modules/autonomy/module.json +13 -0
- package/modules/autonomy/pollers/routine-timers.js +146 -0
- package/modules/autonomy/routes/autonomy.js +37 -0
- package/modules/builder-settings/CLAUDE.md +58 -0
- package/modules/builder-settings/builder-needs.js +115 -0
- package/modules/builder-settings/db.js +168 -0
- package/modules/builder-settings/display-name.js +84 -0
- package/modules/builder-settings/event-sound-prefs.js +169 -0
- package/modules/builder-settings/interaction-prefs.js +201 -0
- package/modules/builder-settings/model-alloc-prefs.js +147 -0
- package/modules/builder-settings/module.json +10 -0
- package/modules/builder-settings/render-prefs.js +103 -0
- package/modules/builder-settings/routes/settings.js +417 -0
- package/modules/builder-settings/settings.js +52 -0
- package/modules/builder-settings/skill-prefs.js +196 -0
- package/modules/builder-settings/sound-prefs.js +178 -0
- package/modules/builder-settings/wandering-prefs.js +282 -0
- package/modules/dev-box/CLAUDE.md +38 -0
- package/modules/dev-box/box-access.js +275 -0
- package/modules/dev-box/box-credential.js +94 -0
- package/modules/dev-box/box-onboard.js +486 -0
- package/modules/dev-box/boxes.js +842 -0
- package/modules/dev-box/db.js +39 -0
- package/modules/dev-box/module.json +14 -0
- package/modules/dev-box/routes/box.js +977 -0
- package/modules/discord/CLAUDE.md +50 -0
- package/modules/discord/auth.js +54 -0
- package/modules/discord/bug-attachments.js +210 -0
- package/modules/discord/db.js +96 -0
- package/modules/discord/discord-approvals.js +145 -0
- package/modules/discord/discord-audit.js +29 -0
- package/modules/discord/discord-bot.js +545 -0
- package/modules/discord/discord-bugs.js +257 -0
- package/modules/discord/discord-channels.js +412 -0
- package/modules/discord/discord-inbound.js +147 -0
- package/modules/discord/discord-message-buffer.js +54 -0
- package/modules/discord/discord-reaction.js +186 -0
- package/modules/discord/discord-role-sync.js +318 -0
- package/modules/discord/module.json +14 -0
- package/modules/discord/pollers/discord-bot.js +19 -0
- package/modules/discord/routes/bug-attachments.js +44 -0
- package/modules/discord/routes/discord.js +102 -0
- package/modules/discord/ship-broadcast.js +78 -0
- package/modules/discord/webhook.js +74 -0
- package/modules/economy/CLAUDE.md +48 -0
- package/modules/economy/achievements.js +594 -0
- package/modules/economy/cost-classify.js +331 -0
- package/modules/economy/cost-summary-shape.js +90 -0
- package/modules/economy/cost.js +438 -0
- package/modules/economy/credits.js +430 -0
- package/modules/economy/migrations/economy_001_fix_gds_shipper_description.sql +91 -0
- package/modules/economy/module.json +10 -0
- package/modules/economy/reward.js +61 -0
- package/modules/economy/routes/cost.js +97 -0
- package/modules/economy/routes/leaderboard.js +26 -0
- package/modules/economy/routes/reward.js +42 -0
- package/modules/economy/streak.js +285 -0
- package/modules/grading/CLAUDE.md +42 -0
- package/modules/grading/db.js +39 -0
- package/modules/grading/grader-rubric.json +151 -0
- package/modules/grading/grader-workers/efficiency.js +213 -0
- package/modules/grading/grader-workers/extract-json.js +80 -0
- package/modules/grading/grader-workers/fence.js +100 -0
- package/modules/grading/grader-workers/hacker.js +239 -0
- package/modules/grading/grader-workers/index.js +183 -0
- package/modules/grading/grader-workers/narc.js +207 -0
- package/modules/grading/grader-workers/quality.js +198 -0
- package/modules/grading/grader-workers/rubric.js +20 -0
- package/modules/grading/grader-workers/worker-prompt.js +89 -0
- package/modules/grading/grader-workers/worker-verdict.js +50 -0
- package/modules/grading/grader.js +1790 -0
- package/modules/grading/module.json +12 -0
- package/modules/grading/routes/grade.js +51 -0
- package/modules/hall-ui/CLAUDE.md +61 -0
- package/modules/hall-ui/module.json +14 -0
- package/modules/hall-ui/public/atlas.html +180 -0
- package/modules/hall-ui/public/atlas.js +336 -0
- package/modules/hall-ui/public/box-panel.js +423 -0
- package/modules/hall-ui/public/brand-apply.js +117 -0
- package/modules/hall-ui/public/builders.js +3028 -0
- package/modules/hall-ui/public/chime.wav +0 -0
- package/modules/hall-ui/public/copy-on-click.js +174 -0
- package/modules/hall-ui/public/cursors/arrow.png +0 -0
- package/modules/hall-ui/public/cursors/hand-pointer.png +0 -0
- package/modules/hall-ui/public/cursors/magnifier-out.png +0 -0
- package/modules/hall-ui/public/cursors/magnifier.png +0 -0
- package/modules/hall-ui/public/diagram-viewer.css +125 -0
- package/modules/hall-ui/public/diagram-viewer.js +330 -0
- package/modules/hall-ui/public/diagrams.html +113 -0
- package/modules/hall-ui/public/dom-utils.js +212 -0
- package/modules/hall-ui/public/drachmae.html +68 -0
- package/modules/hall-ui/public/drachmae.js +136 -0
- package/modules/hall-ui/public/gate.html +143 -0
- package/modules/hall-ui/public/gate.js +228 -0
- package/modules/hall-ui/public/goals-page.js +1297 -0
- package/modules/hall-ui/public/goals.html +376 -0
- package/modules/hall-ui/public/goals.js +119 -0
- package/modules/hall-ui/public/hall-widgets.js +189 -0
- package/modules/hall-ui/public/harbor.html +167 -0
- package/modules/hall-ui/public/harbor.js +335 -0
- package/modules/hall-ui/public/index.html +116 -0
- package/modules/hall-ui/public/instances-panel.js +172 -0
- package/modules/hall-ui/public/md-reader.js +234 -0
- package/modules/hall-ui/public/modules.html +119 -0
- package/modules/hall-ui/public/modules.js +154 -0
- package/modules/hall-ui/public/new-project-wizard.js +186 -0
- package/modules/hall-ui/public/not-ready.html +48 -0
- package/modules/hall-ui/public/pair.html +119 -0
- package/modules/hall-ui/public/pair.js +132 -0
- package/modules/hall-ui/public/primer.css +404 -0
- package/modules/hall-ui/public/primer.html +85 -0
- package/modules/hall-ui/public/primer.js +641 -0
- package/modules/hall-ui/public/profile.html +85 -0
- package/modules/hall-ui/public/profile.js +236 -0
- package/modules/hall-ui/public/ranks.html +69 -0
- package/modules/hall-ui/public/ranks.js +206 -0
- package/modules/hall-ui/public/roadmap.html +209 -0
- package/modules/hall-ui/public/roadmap.js +375 -0
- package/modules/hall-ui/public/sessions.html +92 -0
- package/modules/hall-ui/public/sessions.js +222 -0
- package/modules/hall-ui/public/settings.html +640 -0
- package/modules/hall-ui/public/settings.js +1219 -0
- package/modules/hall-ui/public/shell.js +495 -0
- package/modules/hall-ui/public/style.css +1748 -0
- package/modules/hall-ui/public/task-detail.js +253 -0
- package/modules/hall-ui/public/task.html +83 -0
- package/modules/hall-ui/public/task.js +326 -0
- package/modules/hall-ui/public/watch.html +333 -0
- package/modules/hall-ui/public/watch.js +859 -0
- package/modules/hall-ui/public/work.html +469 -0
- package/modules/hall-ui/public/work.js +1292 -0
- package/modules/ideas/CLAUDE.md +37 -0
- package/modules/ideas/blockers.js +100 -0
- package/modules/ideas/inbox.js +459 -0
- package/modules/ideas/module.json +10 -0
- package/modules/ideas/routes/blockers.js +120 -0
- package/modules/ideas/routes/inbox.js +230 -0
- package/modules/lifecycle/CLAUDE.md +63 -0
- package/modules/lifecycle/conflict-resolve.js +436 -0
- package/modules/lifecycle/db.js +4970 -0
- package/modules/lifecycle/done-when.js +355 -0
- package/modules/lifecycle/github-push.js +969 -0
- package/modules/lifecycle/goal-conflicts.js +133 -0
- package/modules/lifecycle/hierarchy.js +104 -0
- package/modules/lifecycle/lifecycle.js +58 -0
- package/modules/lifecycle/merge-lock.js +261 -0
- package/modules/lifecycle/migrations/lifecycle_001_goal_first_leads.sql +28 -0
- package/modules/lifecycle/migrations/lifecycle_002_backfill_orphan_task_goals.sql +36 -0
- package/modules/lifecycle/module.json +13 -0
- package/modules/lifecycle/pollers/publish-reconciler.js +20 -0
- package/modules/lifecycle/publish-reconciler.js +418 -0
- package/modules/lifecycle/routes/analytics.js +63 -0
- package/modules/lifecycle/routes/claims.js +506 -0
- package/modules/lifecycle/routes/dependencies.js +82 -0
- package/modules/lifecycle/routes/done-when.js +136 -0
- package/modules/lifecycle/routes/gate-approvals.js +197 -0
- package/modules/lifecycle/routes/goals.js +1419 -0
- package/modules/lifecycle/routes/lifecycle.js +43 -0
- package/modules/lifecycle/routes/tasks.js +1703 -0
- package/modules/lifecycle/routes/versions.js +128 -0
- package/modules/lifecycle/ship-card.js +505 -0
- package/modules/lifecycle/ship-preflight.js +225 -0
- package/modules/lifecycle/task-classifier.js +512 -0
- package/modules/lifecycle/version-close.js +106 -0
- package/modules/memory/CLAUDE.md +40 -0
- package/modules/memory/learnings.js +275 -0
- package/modules/memory/memory.js +572 -0
- package/modules/memory/module.json +12 -0
- package/modules/memory/routes/learnings.js +90 -0
- package/modules/memory/routes/memory.js +916 -0
- package/modules/memory/routes/search.js +188 -0
- package/modules/memory/search-chunker.js +252 -0
- package/modules/memory/search.js +320 -0
- package/modules/onboarding/CLAUDE.md +55 -0
- package/modules/onboarding/approval-broadcast.js +59 -0
- package/modules/onboarding/db.js +54 -0
- package/modules/onboarding/module.json +10 -0
- package/modules/onboarding/newcomer-restock.js +212 -0
- package/modules/onboarding/onboarding-state.js +532 -0
- package/modules/onboarding/onboarding.js +508 -0
- package/modules/onboarding/port.js +63 -0
- package/modules/onboarding/routes/access-requests.js +208 -0
- package/modules/onboarding/routes/onboarding.js +54 -0
- package/modules/security/CLAUDE.md +44 -0
- package/modules/security/module.json +10 -0
- package/modules/security/routes/reports.js +251 -0
- package/modules/security/secret-scrub.js +201 -0
- package/modules/security/security.js +294 -0
- package/modules/sessions/CLAUDE.md +39 -0
- package/modules/sessions/bfg.js +357 -0
- package/modules/sessions/db.js +326 -0
- package/modules/sessions/module.json +10 -0
- package/modules/sessions/pulse.js +149 -0
- package/modules/sessions/routes/sessions.js +331 -0
- package/modules/status-ui/CLAUDE.md +47 -0
- package/modules/status-ui/module.json +14 -0
- package/modules/status-ui/public/README.md +29 -0
- package/modules/status-ui/public/cursors/arrow.png +0 -0
- package/modules/status-ui/public/cursors/hand-pointer.png +0 -0
- package/modules/status-ui/public/index.html +363 -0
- package/modules/status-ui/public/snapshots/.gitkeep +0 -0
- package/modules/status-ui/public/status.js +1375 -0
- package/modules/status-ui/public/style.css +1342 -0
- package/package-lock.json +975 -0
- package/package.json +28 -0
- package/public-docs/index.html +35 -0
- package/public-docs/redoc.standalone.js +1838 -0
- package/public-docs/redoc.standalone.js.LICENSE.txt +102 -0
- package/public-landing/buddha.png +0 -0
- package/public-landing/create.html +868 -0
- package/public-landing/index.html +168 -0
- package/scripts/bongos-mcp.js +28 -0
- package/scripts/cron/style_guide_audit.sh +134 -0
- package/scripts/discord/README.md +52 -0
- package/scripts/discord/lib.js +80 -0
- package/scripts/discord/post.js +51 -0
- package/scripts/gds/CLAUDE.md +144 -0
- package/scripts/gds/abandon.js +58 -0
- package/scripts/gds/adopt-detect.js +123 -0
- package/scripts/gds/adopt-import.js +111 -0
- package/scripts/gds/adopt-preflight.js +121 -0
- package/scripts/gds/api.js +78 -0
- package/scripts/gds/architect-audit.js +288 -0
- package/scripts/gds/art-stage.js +152 -0
- package/scripts/gds/audit-authorship.sh +243 -0
- package/scripts/gds/audit-deps.js +121 -0
- package/scripts/gds/audit-exports.js +128 -0
- package/scripts/gds/audit-replay.sh +161 -0
- package/scripts/gds/audit-ships.js +251 -0
- package/scripts/gds/autonomy-gate.js +135 -0
- package/scripts/gds/backfill-cost.js +165 -0
- package/scripts/gds/backfill-sessions.js +351 -0
- package/scripts/gds/backfill-task-rewards.js +408 -0
- package/scripts/gds/backup.js +94 -0
- package/scripts/gds/bfg-principal-token.js +65 -0
- package/scripts/gds/box-auth-check.js +160 -0
- package/scripts/gds/box-connect-lib.js +453 -0
- package/scripts/gds/box.js +1258 -0
- package/scripts/gds/build-bongos.js +94 -0
- package/scripts/gds/capture.js +123 -0
- package/scripts/gds/cf-tunnel.js +419 -0
- package/scripts/gds/ci-grade.js +82 -0
- package/scripts/gds/claim-recall.js +112 -0
- package/scripts/gds/claim.js +333 -0
- package/scripts/gds/classify-discipline.js +153 -0
- package/scripts/gds/claude-materialize.js +176 -0
- package/scripts/gds/cleanup-orphans.js +74 -0
- package/scripts/gds/cli-lib.js +518 -0
- package/scripts/gds/code.js +101 -0
- package/scripts/gds/codemod-rename-src-gds.js +145 -0
- package/scripts/gds/conductor-dispatch.js +426 -0
- package/scripts/gds/context-pack.js +228 -0
- package/scripts/gds/coreB-carve-proof.sh +716 -0
- package/scripts/gds/cost.js +47 -0
- package/scripts/gds/db-backup-nightly.sh +160 -0
- package/scripts/gds/db-backup-offsite.sh +152 -0
- package/scripts/gds/demote.js +40 -0
- package/scripts/gds/design-sync.js +62 -0
- package/scripts/gds/diagnose-achievements.js +118 -0
- package/scripts/gds/diagram-facts.js +319 -0
- package/scripts/gds/discipline-modes.json +25 -0
- package/scripts/gds/discord-channels.js +66 -0
- package/scripts/gds/do-api.js +176 -0
- package/scripts/gds/docs-entropy.js +403 -0
- package/scripts/gds/doctor.js +389 -0
- package/scripts/gds/feedback-latest.js +94 -0
- package/scripts/gds/fetch-art-key.js +106 -0
- package/scripts/gds/fetch-sound-prefs.js +88 -0
- package/scripts/gds/figma-design-sync.js +61 -0
- package/scripts/gds/fitness.js +1446 -0
- package/scripts/gds/gate-review.js +322 -0
- package/scripts/gds/gating.js +325 -0
- package/scripts/gds/gds-db-backup.service +24 -0
- package/scripts/gds/gds-db-backup.timer +20 -0
- package/scripts/gds/gds-db-offsite.service +29 -0
- package/scripts/gds/gds-db-offsite.timer +18 -0
- package/scripts/gds/gen-api-client.js +508 -0
- package/scripts/gds/gen-api-docs.js +1037 -0
- package/scripts/gds/gen-atlas.js +366 -0
- package/scripts/gds/gen-diagrams.js +608 -0
- package/scripts/gds/gen-file-map.js +196 -0
- package/scripts/gds/gen-repo-map.js +519 -0
- package/scripts/gds/gen-session-index.js +210 -0
- package/scripts/gds/git-merge-regen.js +147 -0
- package/scripts/gds/grade-smoke.js +205 -0
- package/scripts/gds/hooks/pre-push.js +169 -0
- package/scripts/gds/http-api-client.js +88 -0
- package/scripts/gds/init.js +903 -0
- package/scripts/gds/install-git-hooks.js +114 -0
- package/scripts/gds/key-card.js +213 -0
- package/scripts/gds/key-status.js +126 -0
- package/scripts/gds/land-watch.js +168 -0
- package/scripts/gds/learning-capture.js +145 -0
- package/scripts/gds/lib.sh +44 -0
- package/scripts/gds/linkify-refs.js +473 -0
- package/scripts/gds/local-preview-lib.js +159 -0
- package/scripts/gds/local-preview.js +95 -0
- package/scripts/gds/login.js +225 -0
- package/scripts/gds/main-audit.js +279 -0
- package/scripts/gds/me.js +88 -0
- package/scripts/gds/memory-map.js +174 -0
- package/scripts/gds/merge-lock.js +71 -0
- package/scripts/gds/migration-namespace.js +200 -0
- package/scripts/gds/mirror-lineage-check.js +319 -0
- package/scripts/gds/mirror-redact.js +305 -0
- package/scripts/gds/module.js +482 -0
- package/scripts/gds/newcomer-floor.config.json +13 -0
- package/scripts/gds/newcomer-floor.js +415 -0
- package/scripts/gds/newcomer-floor.templates.json +86 -0
- package/scripts/gds/newcomer-floor.test.js +235 -0
- package/scripts/gds/next-number.js +163 -0
- package/scripts/gds/oauth-secret.js +197 -0
- package/scripts/gds/onboard.js +217 -0
- package/scripts/gds/onboarding-analyze.js +226 -0
- package/scripts/gds/onboarding-config.js +178 -0
- package/scripts/gds/onboarding-ship.js +92 -0
- package/scripts/gds/package-core.js +684 -0
- package/scripts/gds/paste-token.js +131 -0
- package/scripts/gds/portability-smoke-art.sh +85 -0
- package/scripts/gds/portability-smoke-memory.sh +147 -0
- package/scripts/gds/provision.js +1324 -0
- package/scripts/gds/publish-manifest.js +307 -0
- package/scripts/gds/pulse.js +309 -0
- package/scripts/gds/push-main.js +45 -0
- package/scripts/gds/read-session-export.js +359 -0
- package/scripts/gds/reauth.js +149 -0
- package/scripts/gds/recall.js +135 -0
- package/scripts/gds/release.js +71 -0
- package/scripts/gds/render-ideas.js +173 -0
- package/scripts/gds/repo-metrics.js +363 -0
- package/scripts/gds/resolve-skill-model.js +57 -0
- package/scripts/gds/run-routine.js +197 -0
- package/scripts/gds/run-unit-tests.js +178 -0
- package/scripts/gds/sandbox-stage.js +653 -0
- package/scripts/gds/search-ingest-db.js +209 -0
- package/scripts/gds/search-ingest-md.js +225 -0
- package/scripts/gds/security-baseline-check.sh +180 -0
- package/scripts/gds/seed-adopt-tasks.js +75 -0
- package/scripts/gds/seed-api-contract-goal-tasks.js +141 -0
- package/scripts/gds/seed-bongos-app-tasks.js +294 -0
- package/scripts/gds/seed-bongos-coreB-tranche1-tasks.js +81 -0
- package/scripts/gds/seed-bongos-coreB-tranche2-tasks.js +100 -0
- package/scripts/gds/seed-bongos-goal-hierarchy-tasks.js +307 -0
- package/scripts/gds/seed-bongos-module-system-tasks.js +346 -0
- package/scripts/gds/seed-bongos-tasks.js +214 -0
- package/scripts/gds/seed-gds-v4-tasks.js +624 -0
- package/scripts/gds/seed-governance-tasks.js +340 -0
- package/scripts/gds/seed-medusa-tasks.js +440 -0
- package/scripts/gds/seed-module-upstreaming.js +219 -0
- package/scripts/gds/seed-productization-tasks.js +235 -0
- package/scripts/gds/seed-provisioning-tasks.js +83 -0
- package/scripts/gds/seed-staging.sh +104 -0
- package/scripts/gds/seed-v2-world-tasks.js +283 -0
- package/scripts/gds/seed-v3-tasks.js +1981 -0
- package/scripts/gds/session-cost.js +393 -0
- package/scripts/gds/session-digest.js +179 -0
- package/scripts/gds/session-eval.js +576 -0
- package/scripts/gds/session.js +404 -0
- package/scripts/gds/setup.js +504 -0
- package/scripts/gds/shell.js +100 -0
- package/scripts/gds/ship.js +3618 -0
- package/scripts/gds/smoke-batch-claim.sh +213 -0
- package/scripts/gds/smoke-batch-release.sh +296 -0
- package/scripts/gds/smoke-box.sh +150 -0
- package/scripts/gds/smoke-claim-consistency.sh +212 -0
- package/scripts/gds/smoke-dependencies.sh +84 -0
- package/scripts/gds/smoke-gds.js +125 -0
- package/scripts/gds/smoke-write.sh +168 -0
- package/scripts/gds/start.js +782 -0
- package/scripts/gds/status.js +365 -0
- package/scripts/gds/triage.js +366 -0
- package/scripts/gds/upgrade.js +421 -0
- package/scripts/gds/validate-design.js +254 -0
- package/scripts/gds/version-close.js +549 -0
- package/scripts/migrate.sh +183 -0
- package/scripts/migrate_cost_ledger.sh +178 -0
- package/scripts/public-mirror-export.js +291 -0
- package/scripts/render-diagrams.sh +88 -0
- package/scripts/security/dep-audit.js +276 -0
- package/scripts/setup-builder.js +274 -0
- package/scripts/setup-builder.sh +28 -0
- package/scripts/snapshots/backfill-history.mjs +292 -0
- package/scripts/snapshots/maybe-render-on-deploy.sh +66 -0
- package/scripts/snapshots/render-pre-art-eras.mjs +329 -0
- package/scripts/snapshots/render-world.mjs +322 -0
- package/scripts/status-mirror-sync.js +192 -0
- package/scripts/status-probe.mjs +185 -0
- package/server.js +212 -0
- package/src/asset-version.js +71 -0
- package/src/bongos/CLAUDE.md +64 -0
- package/src/bongos/api-errors.js +281 -0
- package/src/bongos/api-path-404.js +67 -0
- package/src/bongos/api-prefix.js +38 -0
- package/src/bongos/app-pair.js +172 -0
- package/src/bongos/auth.js +979 -0
- package/src/bongos/cascade-dispatch.js +123 -0
- package/src/bongos/db-kernel.js +252 -0
- package/src/bongos/db.js +911 -0
- package/src/bongos/goal-scope-check.js +120 -0
- package/src/bongos/hierarchy-config.js +189 -0
- package/src/bongos/live-channel.js +145 -0
- package/src/bongos/llm-cache.js +260 -0
- package/src/bongos/llm-pricing.js +220 -0
- package/src/bongos/metrics.js +286 -0
- package/src/bongos/middleware/audit.js +274 -0
- package/src/bongos/middleware/error-envelope.js +93 -0
- package/src/bongos/middleware/rate-limit.js +195 -0
- package/src/bongos/module-scope-map.js +271 -0
- package/src/bongos/optimizer.js +166 -0
- package/src/bongos/path-match.js +47 -0
- package/src/bongos/permission-path-check.js +248 -0
- package/src/bongos/pool.js +55 -0
- package/src/bongos/repo-info.js +91 -0
- package/src/bongos/route-rank-check.js +420 -0
- package/src/bongos/routes/CLAUDE.md +43 -0
- package/src/bongos/routes/_helpers.js +369 -0
- package/src/bongos/routes/audit-log.js +59 -0
- package/src/bongos/routes/auth.js +755 -0
- package/src/bongos/routes/backup.js +104 -0
- package/src/bongos/routes/builders.js +526 -0
- package/src/bongos/routes/healthz.js +16 -0
- package/src/bongos/routes/instance.js +129 -0
- package/src/bongos/routes/live.js +125 -0
- package/src/bongos/routes/llm-cache.js +119 -0
- package/src/bongos/routes/me.js +380 -0
- package/src/bongos/routes/modules.js +131 -0
- package/src/bongos/routes/optimizer.js +54 -0
- package/src/bongos/routes/public.js +476 -0
- package/src/bongos/routes/security.js +207 -0
- package/src/bongos/routes.js +166 -0
- package/src/bongos/secret-box.js +177 -0
- package/src/bongos/sensitive-surfaces.js +30 -0
- package/src/bongos/serve-internal.js +889 -0
- package/src/bongos/uptime-poller.js +90 -0
- package/src/bongos-downloads.js +70 -0
- package/src/branding.js +182 -0
- package/src/build-info.js +77 -0
- package/src/devbox-downloads.js +67 -0
- package/src/instance-config.js +200 -0
- package/src/module-api.js +366 -0
- package/src/module-loader/loader.js +268 -0
- package/src/module-loader/manifest-schema.js +140 -0
- package/src/module-loader/provenance.js +28 -0
- package/src/module-loader/semver.js +100 -0
- package/src/module-seams.js +291 -0
- package/src/modules.js +254 -0
- package/src/platform-server.js +135 -0
- package/src/ui/adapters/claude-design/index.js +333 -0
- package/src/ui/adapters/figma/index.js +328 -0
- package/tests/abandon_task.mjs +138 -0
- package/tests/achievements_reconcile.mjs +167 -0
- package/tests/adopt_detect.mjs +141 -0
- package/tests/adopt_import.mjs +132 -0
- package/tests/adopt_preflight.mjs +105 -0
- package/tests/anti_grid.mjs +89 -0
- package/tests/api_client.mjs +231 -0
- package/tests/api_docs.mjs +283 -0
- package/tests/api_error_envelope_buildcheck.mjs +56 -0
- package/tests/api_error_envelope_middleware.mjs +99 -0
- package/tests/api_error_registry.mjs +108 -0
- package/tests/api_pagination_contract.mjs +51 -0
- package/tests/api_path_404.mjs +96 -0
- package/tests/app_pair.mjs +168 -0
- package/tests/architect.mjs +140 -0
- package/tests/art_key.mjs +121 -0
- package/tests/art_stage.mjs +121 -0
- package/tests/asset_version.mjs +94 -0
- package/tests/atlas.mjs +69 -0
- package/tests/audit_deps.mjs +74 -0
- package/tests/audit_middleware.mjs +385 -0
- package/tests/auth_admission_gate.mjs +164 -0
- package/tests/auth_anthropic_identity.mjs +95 -0
- package/tests/auth_duplicate_cookie.mjs +56 -0
- package/tests/auth_error_brand.mjs +77 -0
- package/tests/auth_flow_slice1.mjs +223 -0
- package/tests/auth_inactive_builder.mjs +94 -0
- package/tests/auth_page_gate.mjs +92 -0
- package/tests/auth_session_ttl.mjs +155 -0
- package/tests/autonomous_fit_protected_paths.mjs +115 -0
- package/tests/autonomy_gate.mjs +85 -0
- package/tests/autotile_variants.mjs +256 -0
- package/tests/autotile_xverify.mjs +133 -0
- package/tests/backfill_sessions.mjs +101 -0
- package/tests/backfill_task_rewards.mjs +152 -0
- package/tests/backup_cli.mjs +104 -0
- package/tests/bfg.mjs +327 -0
- package/tests/bfg_write.mjs +423 -0
- package/tests/bongos_box_connect.mjs +89 -0
- package/tests/bongos_dispatch.mjs +74 -0
- package/tests/bongos_downloads.mjs +118 -0
- package/tests/bongos_login.mjs +34 -0
- package/tests/box_access.mjs +186 -0
- package/tests/box_auth_check.mjs +114 -0
- package/tests/box_code_staleness.mjs +116 -0
- package/tests/box_connect_e2e.mjs +196 -0
- package/tests/box_cost.mjs +70 -0
- package/tests/box_dns_repoint.mjs +151 -0
- package/tests/box_host_keys.mjs +102 -0
- package/tests/box_onboard.mjs +317 -0
- package/tests/box_scope_session.mjs +115 -0
- package/tests/box_ship_permissions.mjs +71 -0
- package/tests/box_terminal_ssrf.mjs +90 -0
- package/tests/boxes.mjs +1255 -0
- package/tests/branding.mjs +88 -0
- package/tests/bug_attachments.mjs +189 -0
- package/tests/build_info.mjs +88 -0
- package/tests/builder_needs.mjs +99 -0
- package/tests/cap_newcomer_tasks.mjs +114 -0
- package/tests/cascade-dispatch.mjs +95 -0
- package/tests/cf_tunnel.mjs +459 -0
- package/tests/claim_recall.mjs +150 -0
- package/tests/claims_bind_session.mjs +47 -0
- package/tests/claude_materialize.mjs +148 -0
- package/tests/cli_box_scope.mjs +52 -0
- package/tests/cli_lib_formatters.mjs +87 -0
- package/tests/cli_token_reissue.mjs +147 -0
- package/tests/client_bundle_route.mjs +47 -0
- package/tests/cloud_bongos_pack.mjs +85 -0
- package/tests/conductor.mjs +496 -0
- package/tests/confirm_attribution.mjs +156 -0
- package/tests/conflict_resolve.mjs +462 -0
- package/tests/context_pack.mjs +240 -0
- package/tests/cost.mjs +94 -0
- package/tests/cost_audit.mjs +122 -0
- package/tests/cost_budget_status.mjs +78 -0
- package/tests/cost_reconcile.mjs +102 -0
- package/tests/cost_summary_shape.mjs +94 -0
- package/tests/credit_grant.mjs +376 -0
- package/tests/criterion_progress.mjs +220 -0
- package/tests/criterion_proposal.mjs +109 -0
- package/tests/criterion_ref_parse.mjs +53 -0
- package/tests/currency_label.mjs +119 -0
- package/tests/day_cycle.mjs +197 -0
- package/tests/dependencies_migration.mjs +77 -0
- package/tests/dependencies_polymorphic.mjs +212 -0
- package/tests/deploy_instance.mjs +78 -0
- package/tests/devbox_downloads.mjs +122 -0
- package/tests/diff_derived_signals.mjs +115 -0
- package/tests/discord_approvals.mjs +174 -0
- package/tests/discord_autojoin.mjs +158 -0
- package/tests/discord_bot.mjs +94 -0
- package/tests/discord_bugs.mjs +297 -0
- package/tests/discord_channels.mjs +337 -0
- package/tests/discord_foundation.mjs +76 -0
- package/tests/discord_inbound.mjs +190 -0
- package/tests/discord_message_buffer.mjs +87 -0
- package/tests/discord_oauth.mjs +55 -0
- package/tests/discord_reaction.mjs +170 -0
- package/tests/discord_role_sync.mjs +151 -0
- package/tests/display_name.mjs +123 -0
- package/tests/dns_preflight.mjs +74 -0
- package/tests/event_sound_prefs.mjs +194 -0
- package/tests/eviction_policy.mjs +279 -0
- package/tests/figma_adapter.mjs +199 -0
- package/tests/file_map.mjs +91 -0
- package/tests/first_admin_bootstrap.mjs +40 -0
- package/tests/fitness.mjs +435 -0
- package/tests/fitness_two_root.mjs +104 -0
- package/tests/fixtures/session-506-digest.json +34 -0
- package/tests/gate_approvals.mjs +451 -0
- package/tests/gate_review.mjs +152 -0
- package/tests/git_merge_regen.mjs +151 -0
- package/tests/github_push_ancestry.mjs +119 -0
- package/tests/github_push_land_proof.mjs +127 -0
- package/tests/github_push_merge_driver.mjs +175 -0
- package/tests/goal_abuse_matrix.mjs +187 -0
- package/tests/goal_achievement.mjs +146 -0
- package/tests/goal_conflicts.mjs +305 -0
- package/tests/goal_dependencies_read.mjs +73 -0
- package/tests/goal_member_roles.mjs +420 -0
- package/tests/goal_membership_requests.mjs +332 -0
- package/tests/goal_routes.mjs +203 -0
- package/tests/goal_scope_check.mjs +167 -0
- package/tests/goal_tier.mjs +312 -0
- package/tests/goal_wall_proof.mjs +112 -0
- package/tests/grade_attempts.mjs +73 -0
- package/tests/grade_attribution.mjs +117 -0
- package/tests/grade_diff_hash.mjs +191 -0
- package/tests/grade_server_authoritative.mjs +305 -0
- package/tests/grade_unavailable_display.mjs +66 -0
- package/tests/grader.mjs +1960 -0
- package/tests/grader_bypass.mjs +57 -0
- package/tests/grader_panel.mjs +252 -0
- package/tests/grader_prompt_fencing.mjs +192 -0
- package/tests/helpers.mjs +52 -0
- package/tests/hierarchy-config.mjs +81 -0
- package/tests/init.mjs +463 -0
- package/tests/instance_config.mjs +76 -0
- package/tests/instance_manifest.mjs +110 -0
- package/tests/interaction_prefs.mjs +72 -0
- package/tests/key-card.mjs +110 -0
- package/tests/key-status.mjs +45 -0
- package/tests/land_watch.mjs +115 -0
- package/tests/lifecycle-card.mjs +145 -0
- package/tests/lifecycle_breakdown_view.mjs +236 -0
- package/tests/linkify_refs.mjs +264 -0
- package/tests/live_channel.mjs +128 -0
- package/tests/live_sse.mjs +122 -0
- package/tests/llm-cache-route.mjs +110 -0
- package/tests/llm-cache.mjs +140 -0
- package/tests/llm-pricing.mjs +152 -0
- package/tests/local_preview.mjs +136 -0
- package/tests/main_audit.mjs +137 -0
- package/tests/memory_isolation.mjs +431 -0
- package/tests/memory_map.mjs +107 -0
- package/tests/memory_pull.mjs +429 -0
- package/tests/merge_lease.mjs +100 -0
- package/tests/merge_lock.mjs +312 -0
- package/tests/metrics.mjs +147 -0
- package/tests/migration_allocation.mjs +146 -0
- package/tests/migration_namespace.mjs +185 -0
- package/tests/migrations_fresh_replay_guard.mjs +38 -0
- package/tests/mirror_lineage_fulltree.mjs +45 -0
- package/tests/mirror_lineage_proof.mjs +72 -0
- package/tests/mirror_redact.mjs +193 -0
- package/tests/model_alloc_prefs.mjs +63 -0
- package/tests/module-scope-map.mjs +88 -0
- package/tests/module_api.mjs +110 -0
- package/tests/module_cli.mjs +292 -0
- package/tests/module_contributions.mjs +148 -0
- package/tests/module_loader.mjs +286 -0
- package/tests/module_manifest.mjs +194 -0
- package/tests/module_owned_tests.mjs +105 -0
- package/tests/module_provenance.mjs +34 -0
- package/tests/module_route_rank.mjs +147 -0
- package/tests/module_seams.mjs +68 -0
- package/tests/modules.mjs +156 -0
- package/tests/modules_route.mjs +38 -0
- package/tests/newcomer_floor.mjs +17 -0
- package/tests/newcomer_restock.mjs +80 -0
- package/tests/next_number.mjs +154 -0
- package/tests/oauth_secret.mjs +60 -0
- package/tests/onboard.mjs +70 -0
- package/tests/onboarding_gate.mjs +267 -0
- package/tests/onboarding_observability.mjs +344 -0
- package/tests/onboarding_route_signals.mjs +175 -0
- package/tests/onboarding_state.mjs +346 -0
- package/tests/one_active_claim_per_session.mjs +111 -0
- package/tests/orphaned_claim_ship.mjs +135 -0
- package/tests/override_attribution.mjs +142 -0
- package/tests/override_request_ownership.mjs +235 -0
- package/tests/package_core.mjs +435 -0
- package/tests/parallel-load.mjs +402 -0
- package/tests/path_match.mjs +62 -0
- package/tests/permission_path.mjs +151 -0
- package/tests/platform_boot.mjs +167 -0
- package/tests/pre_compact.mjs +60 -0
- package/tests/preview_server.mjs +127 -0
- package/tests/profile_route.mjs +197 -0
- package/tests/provision.mjs +805 -0
- package/tests/provisioning_github_app_routes.mjs +98 -0
- package/tests/public_mirror_export.mjs +124 -0
- package/tests/public_task_resolver.mjs +112 -0
- package/tests/publish_branch_route.mjs +422 -0
- package/tests/publish_manifest.mjs +184 -0
- package/tests/publish_reconciler.mjs +728 -0
- package/tests/rank_gate.mjs +463 -0
- package/tests/rate_limit_public.mjs +217 -0
- package/tests/read_session_export.mjs +89 -0
- package/tests/recall_cli.mjs +82 -0
- package/tests/recall_hints.mjs +119 -0
- package/tests/recent_shipped_window.mjs +80 -0
- package/tests/regrade_eligibility.mjs +202 -0
- package/tests/render_prefs.mjs +122 -0
- package/tests/repo_map.mjs +92 -0
- package/tests/reward_gate.mjs +284 -0
- package/tests/route_rank_check.mjs +243 -0
- package/tests/route_validation.mjs +490 -0
- package/tests/routine_timers.mjs +72 -0
- package/tests/rubric_fixtures.mjs +140 -0
- package/tests/run_routine.mjs +69 -0
- package/tests/sandbox_stage.mjs +582 -0
- package/tests/scrubber_corpus.mjs +257 -0
- package/tests/search_chunker.mjs +209 -0
- package/tests/search_ingest.mjs +96 -0
- package/tests/search_ingest_db.mjs +88 -0
- package/tests/search_isolation.mjs +204 -0
- package/tests/search_route.mjs +95 -0
- package/tests/secret_box.mjs +189 -0
- package/tests/security_docs.mjs +186 -0
- package/tests/security_route.mjs +108 -0
- package/tests/served_paths_shipped.mjs +118 -0
- package/tests/session-cards.mjs +142 -0
- package/tests/session_506_regression.mjs +69 -0
- package/tests/session_caps.mjs +238 -0
- package/tests/session_cost.mjs +133 -0
- package/tests/session_digest.mjs +73 -0
- package/tests/session_eval.mjs +386 -0
- package/tests/session_index.mjs +105 -0
- package/tests/session_records.mjs +369 -0
- package/tests/session_search.mjs +78 -0
- package/tests/session_start_freshness.mjs +123 -0
- package/tests/setup_smoke.mjs +154 -0
- package/tests/ship_autolinkify.mjs +60 -0
- package/tests/ship_automerge_injection.mjs +174 -0
- package/tests/ship_broadcast_routing.mjs +125 -0
- package/tests/ship_broadcast_server.mjs +175 -0
- package/tests/ship_card.mjs +280 -0
- package/tests/ship_ci_deploy.mjs +374 -0
- package/tests/ship_preflight.mjs +368 -0
- package/tests/ship_premerge.mjs +75 -0
- package/tests/ship_resume.mjs +129 -0
- package/tests/ship_upload_skip.mjs +89 -0
- package/tests/ship_zero_commit.mjs +60 -0
- package/tests/single_host_hall.mjs +98 -0
- package/tests/skill_prefs.mjs +150 -0
- package/tests/smoke_preflight.mjs +66 -0
- package/tests/snapshot_picker.mjs +233 -0
- package/tests/sound_prefs.mjs +198 -0
- package/tests/sprite_facing.mjs +35 -0
- package/tests/status-probe.mjs +89 -0
- package/tests/status_backfill.mjs +94 -0
- package/tests/stop_refcheck.mjs +127 -0
- package/tests/streak.mjs +175 -0
- package/tests/subdomain_auth.mjs +58 -0
- package/tests/task_classifier_vocab.mjs +41 -0
- package/tests/task_create_idempotency.mjs +96 -0
- package/tests/task_goal_link.mjs +93 -0
- package/tests/task_ownership_gate.mjs +125 -0
- package/tests/terrain_picker.mjs +298 -0
- package/tests/touches_overlap.mjs +75 -0
- package/tests/triage_development.mjs +140 -0
- package/tests/turn_in_place.mjs +280 -0
- package/tests/upgrade.mjs +357 -0
- package/tests/verify_task_guard.mjs +64 -0
- package/tests/version_close.mjs +76 -0
- package/tests/versions_route.mjs +93 -0
- package/tests/walkability.mjs +188 -0
- package/tests/wandering_prefs.mjs +176 -0
- package/tests/worktree_disambiguation.mjs +105 -0
- package/tests/worktree_guard.mjs +90 -0
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# `economy` module — credits, cost ledger, streaks, achievements, leaderboard + the `reward` kernel port
|
|
2
|
+
|
|
3
|
+
> The **third CORE-domain** carved into a module (BV1.R77, [ADR 0093](../../docs/adr/<redacted>.md) §1-2) — after memory (R72) and grading (R73). Like grading, it follows ADR 0091 §4's load-bearing pattern: **keep the lifecycle state machine whole, extract the capability it invokes behind a kernel seam.** The lifecycle no longer imports the credit/achievement code directly; it resolves a `reward` PORT this module registers.
|
|
4
|
+
|
|
5
|
+
Owns the **builder economy**: the cost-plus + kind-multiplier credit-allocation model (the real-money credit ledger), the idea-promotion bonus, the flat session-token reward, the net-negative (simplification) ship bonus, the cost ledger + dashboard rollups, builder streaks, achievements/gamification, and the leaderboard. `default: true` in `module.json` — every instance rewards its own builders, so it mounts unconditionally unless explicitly disabled.
|
|
6
|
+
|
|
7
|
+
## The boundary (the one rule)
|
|
8
|
+
|
|
9
|
+
This module reaches core **only** through the published doorway `../../src/module-api.js` (`coreVersion ^1.7.0` — it needs the R77 doorway addition: `llmPricing`, the shared token→USD pricing lib). It must **never** `require()` a core internal directly, and never another module. Core, in turn, must never `require()` a file in here — it reaches economy only through the `reward` port (below). Both directions are enforced by the BV1.R44/R45 fitness checks; R70's `kernel-imports-no-domain` check keeps the kernel from reaching back in.
|
|
10
|
+
|
|
11
|
+
## The `reward` kernel PORT (ADR 0093 §1-2 — the headline of this carve)
|
|
12
|
+
|
|
13
|
+
- **Provides — port `reward`** → the economy module's reward surface (`modules/economy/reward.js`). Registered in `routes/reward.js`'s factory (the loader runs it at boot, and again whenever a test rebuilds the GDS router — `hasProvider`-guarded so re-instantiation never trips the single-provider duplicate guard).
|
|
14
|
+
- **It is a TRANSACTION-PARTICIPANT port** (unlike the stateless `grade` port): the credit-allocation methods (`insertMultipliedConfirmCredit`, `maybeAwardIdeaPromotionBonus`, `awardNetNegativeBonus`, `awardSessionTokenReward`) and the claim/ship gamification hooks (`evaluateAfterClaim/Ship/CreditAward`) take the **caller's tx `client` as the first arg**. The core lifecycle opens the `withTx`, runs the state-machine SQL (FOR UPDATE, `task_grades` upsert, `UPDATE tasks status`, claim-holder lookup, `logGradeAttempt`) itself, and calls `reward.*(client, …)` inside that same transaction — so the credit write commits atomically with the status flip. Extract the capability; keep the state machine (ADR 0091 §4).
|
|
15
|
+
- **Core consumes it WITHOUT importing this module:**
|
|
16
|
+
- the LIFECYCLE — `db.applyGrade` / `db.confirmTask` / `db.decideOverrideRequest` / `db.claimTask` / `db.upsertSessionRecordWithReward` resolve it via `seams.resolveOptional('reward')` and call the credit/achievement methods inside their own `withTx`.
|
|
17
|
+
- the READ routes — `routes/me.js` (achievement getters + streak preview + `getBuilderCostStatus`), `routes/public.js` (`costSummary` + `getLeaderboardWithAchievements`), `routes/builders.js` (`setBuilderMonthlyBudget`), `routes/sessions.js` (`sumCreditsForTasks`), and `publish-reconciler.js` (`reconcileSessionCosts`) resolve the same port and call its read surface. economy registers ONE port; its provider exposes both the lifecycle methods and the read surface (the grading precedent registers the whole module surface on its single port too).
|
|
18
|
+
- This replaced the former `const achievements = require('./achievements')` / `cost` / `cost-summary-shape` core→domain requires in `db.js`, the `db.leaderboard`/`db.logCost`/etc. monolith helpers, and the `require('../streak')` core-route imports.
|
|
19
|
+
|
|
20
|
+
## Files
|
|
21
|
+
|
|
22
|
+
| File | What |
|
|
23
|
+
|---|---|
|
|
24
|
+
| `credits.js` | the credit-allocation model: `KIND_MULTIPLIERS`/`IDEA_BONUS_FRACTION`/`REWARD_MARGIN_PCT`, `applyKindMultiplier`, `computeSessionTokenReward`, `insertMultipliedConfirmCredit`, `maybeAwardIdeaPromotionBonus`, `awardSessionTokenReward`, `awardNetNegativeBonus` (+ `NET_NEGATIVE_BONUS`/`SUBTRACTOR_THRESHOLD`/`netNegativeBonusAmount`), the `leaderboard`, and `sumCreditsForTasks`. Writes `credit_log`. |
|
|
25
|
+
| `cost.js` | the cost ledger: `logCost` (the one `cost_log` writer), `reconcileSessionCosts`, `costSummary`/`costCalibrationSummary`, `getBuilderCostStatus`, `setBuilderMonthlyBudget`, `autonomousApiSpendMtd`. |
|
|
26
|
+
| `cost-classify.js` | pure cost-attribution audit + budget classification (`classifyCostStatus`, `auditCostAttribution`, `formatAuditReport`, `OWNERLESS_CATEGORIES`, `SOFT_CAP_FRACTION`). Moved from `src/bongos/cost.js` (renamed to avoid colliding with `cost.js`). |
|
|
27
|
+
| `cost-summary-shape.js` | pure cost-summary dimension shapers (`shapeBySource`/`shapeByTier`/`shapeSavings`/`shapeCostCalibration`). |
|
|
28
|
+
| `streak.js` | streak math + anti-gaming guards (`computeStreak`, `wouldExtendStreak`, …). Reaches the shared pool through the doorway. |
|
|
29
|
+
| `achievements.js` | the achievement evaluators (`evaluateAfterClaim/Ship/CreditAward`, `alreadyUnlocked`, `unlockAchievement`, `filesForBadges`) PLUS the getter slice moved from `db.js` (`listAchievements`, `getBuilderAchievements`, `getLeaderboardWithAchievements`, `getLockedAchievementsProgress`, `renderProgressText`). `require('./streak')` is an intra-module sibling. |
|
|
30
|
+
| `reward.js` | the `reward` port provider surface — DELEGATES (does not spread) to `credits`/`achievements`/`cost`/`streak` so test stubs bite at call time. |
|
|
31
|
+
| `routes/reward.js` | registers the `reward` port (above); no HTTP endpoint. |
|
|
32
|
+
| `routes/cost.js` | `POST /cost` — log a cost row (idempotent). Reaches auth/validators via the doorway; the writer via `../cost`. |
|
|
33
|
+
| `routes/leaderboard.js` | `GET /leaderboard` — public drachmae-ordered leaderboard, via `../credits`. |
|
|
34
|
+
|
|
35
|
+
## NOT in this module (deliberately left in core)
|
|
36
|
+
|
|
37
|
+
- **`llm-pricing.js`** — the shared token→USD pricing lib stays core shared LLM-cost infra (consumed by BOTH this module's reward/cost paths AND core cost scripts `ship.js`/`session-cost.js`, so it can't be economy-owned). It is exposed to this module on the doorway as `api.llmPricing` (a tracked R73-style domain leak, like `api.llmCache`). It relocates behind a port if/when an llm-infra domain is carved (tranche 2). The economy scope-map glob lists `src/bongos/llm-pricing.js` for task-affinity even though the FILE stays in core.
|
|
38
|
+
- **The recent-ships feed + estimation-drift + grade-trend reads** (`db.recentShippedTasks`, `<redacted>`, `getEstVsActualRatio`, `estimationDriftSummary`, `recentGradesForBuilder`, `builderRollingAvgGrade`, `rollingAvgGrade`, `gradeTrendByDay`) — these stay `db.*` (lifecycle/sessions reads, not economy ledger SQL); out of scope for this carve.
|
|
39
|
+
- **The karma feed** (`recentKarmaForBuilder`, `karmaDelta30d`, `karma_log`) — stays in core `db.js` (a separate social-signal domain).
|
|
40
|
+
- **The economy-owned CLIs** — a command travels with its domain but stays under `scripts/`: `backfill-cost.js` (requires `../../modules/economy/cost-classify`), `diagnose-achievements.js` (requires `../../modules/economy/streak`). (The memory/grading-carve precedent.)
|
|
41
|
+
|
|
42
|
+
## Tables
|
|
43
|
+
|
|
44
|
+
None owned. `credit_log`, `cost_log`, `cost_baseline`, `achievements`, `builder_achievements` (+ their migrations) were created before the module system and stay in core `migrations/` (the schema-migrations stem-key makes a later relocation a no-op). The module owns the *queries*; any **new** economy migration belongs in `modules/economy/migrations/` namespaced `economy_*` (the additive rule).
|
|
45
|
+
|
|
46
|
+
## Tests
|
|
47
|
+
|
|
48
|
+
`tests/credit_grant.mjs` (credits.js), `tests/cost.mjs`/`tests/cost_audit.mjs`/`tests/cost_budget_status.mjs` (cost-classify.js), `tests/cost_summary_shape.mjs`, `tests/streak.mjs`, and `tests/diff_derived_signals.mjs` import from `modules/economy/…`. The lifecycle-attribution tests (`tests/grade_attribution.mjs`, `tests/confirm_attribution.mjs`, `tests/grade_server_authoritative.mjs`, `tests/override_attribution.mjs`, `tests/override_request_ownership.mjs`) register the `reward` port (and stub `achievements` on the live module object) before driving `db.applyGrade`/`confirmTask`/`decideOverrideRequest`. See ADR 0093.
|
|
@@ -0,0 +1,594 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// Achievement evaluation — runs inside existing DB transactions so unlocks
|
|
4
|
+
// are atomic with the action that triggered them.
|
|
5
|
+
//
|
|
6
|
+
// Three entry points, each called by the relevant route:
|
|
7
|
+
// evaluateAfterClaim(client, builderId, claimId)
|
|
8
|
+
// evaluateAfterShip(client, builderId, taskId)
|
|
9
|
+
// evaluateAfterCreditAward(client, builderId, totalBefore, totalAfter)
|
|
10
|
+
//
|
|
11
|
+
// Each returns an array of { id, name, credit_bonus } for achievements just
|
|
12
|
+
// unlocked in this call — the route adds them to its API response as
|
|
13
|
+
// just_unlocked.
|
|
14
|
+
|
|
15
|
+
const streak = require('./streak');
|
|
16
|
+
// Carved into modules/economy/ (BV1.R77 / ADR 0093 §1-2): the achievement GETTER
|
|
17
|
+
// slice (listAchievements/getBuilderAchievements/getLeaderboardWithAchievements/
|
|
18
|
+
// getLockedAchievementsProgress/renderProgressText), moved from src/bongos/db.js,
|
|
19
|
+
// reads the shared pool through the published doorway — a module never requires a
|
|
20
|
+
// core internal. The evaluators above take a tx `client` from the caller.
|
|
21
|
+
const { pool } = require('../../src/module-api');
|
|
22
|
+
|
|
23
|
+
async function alreadyUnlocked(client, builderId, achievementId) {
|
|
24
|
+
const r = await client.query(
|
|
25
|
+
'SELECT 1 FROM builder_achievements WHERE builder_id=$1 AND achievement_id=$2',
|
|
26
|
+
[builderId, achievementId]
|
|
27
|
+
);
|
|
28
|
+
return r.rowCount > 0;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async function unlockAchievement(client, builderId, achievementId, taskId) {
|
|
32
|
+
const ach = await client.query(
|
|
33
|
+
'SELECT id, name, credit_bonus FROM achievements WHERE id=$1',
|
|
34
|
+
[achievementId]
|
|
35
|
+
);
|
|
36
|
+
if (ach.rowCount === 0) return null;
|
|
37
|
+
const { id, name, credit_bonus } = ach.rows[0];
|
|
38
|
+
|
|
39
|
+
await client.query(
|
|
40
|
+
`INSERT INTO builder_achievements (builder_id, achievement_id, unlocked_at, unlocked_by_task_id)
|
|
41
|
+
VALUES ($1, $2, now(), $3)
|
|
42
|
+
ON CONFLICT DO NOTHING`,
|
|
43
|
+
[builderId, id, taskId ?? null]
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
if (credit_bonus > 0) {
|
|
47
|
+
await client.query(
|
|
48
|
+
`INSERT INTO credit_log (builder_id, task_id, delta, reason, recorded_at)
|
|
49
|
+
VALUES ($1, $2, $3, $4, now())`,
|
|
50
|
+
[builderId, taskId ?? null, credit_bonus, `achievement.${id}`]
|
|
51
|
+
);
|
|
52
|
+
// trigger on credit_log bumps builders.total_credits automatically
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return { id, name, credit_bonus };
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async function evaluateAfterClaim(client, builderId, _claimId) {
|
|
59
|
+
const results = [];
|
|
60
|
+
|
|
61
|
+
// first-claim: this is the builder's very first claim
|
|
62
|
+
if (!await alreadyUnlocked(client, builderId, 'first-claim')) {
|
|
63
|
+
const count = await client.query(
|
|
64
|
+
'SELECT COUNT(*) FROM claims WHERE builder_id=$1',
|
|
65
|
+
[builderId]
|
|
66
|
+
);
|
|
67
|
+
if (Number(count.rows[0].count) === 1) {
|
|
68
|
+
const unlocked = await unlockAchievement(client, builderId, 'first-claim', null);
|
|
69
|
+
if (unlocked) results.push(unlocked);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return results;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// touches[] cleanup [3/8] (task 878): the prefix-keyed shipper badges should
|
|
77
|
+
// reflect what was ACTUALLY shipped, not the predicted touches[]. ship.js
|
|
78
|
+
// computes the committed changed-files for the grader (touches-independent per
|
|
79
|
+
// #536) and passes them through /grade → applyGrade → here as `changedFiles`.
|
|
80
|
+
// When that list is present we key the badges off it; otherwise we fall back to
|
|
81
|
+
// the task's touches[] (manual confirms, older callers, or a ship with no diff
|
|
82
|
+
// info). Once #882 backfills touches[] from the committed diff at ship time the
|
|
83
|
+
// fallback itself becomes diff-accurate, so the two converge.
|
|
84
|
+
function filesForBadges(changedFiles, touches) {
|
|
85
|
+
return Array.isArray(changedFiles) && changedFiles.length > 0
|
|
86
|
+
? changedFiles
|
|
87
|
+
: Array.isArray(touches) ? touches : [];
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
async function evaluateAfterShip(client, builderId, taskId, changedFiles = null) {
|
|
91
|
+
const results = [];
|
|
92
|
+
|
|
93
|
+
// first-ship: this is the builder's very first ship.
|
|
94
|
+
//
|
|
95
|
+
// BUG FIX (PMS-V2 #190, 2026-05-11): originally queried session_logs and
|
|
96
|
+
// compared `=== 1`. That was wrong because the session_logs row for THIS
|
|
97
|
+
// ship is INSERTed in db.js AFTER evaluateAfterShip returns (line ~614),
|
|
98
|
+
// so at evaluator time the count reflects only PRIOR ships. The first
|
|
99
|
+
// ship therefore had count===0, never matched `=== 1`, and the
|
|
100
|
+
// achievement never fired.
|
|
101
|
+
//
|
|
102
|
+
// Switched to claims.outcome='shipped' (the claim row HAS been UPDATEd
|
|
103
|
+
// to outcome='shipped' + released_at=now() before this evaluator runs,
|
|
104
|
+
// per db.js line ~540) and check `=== 1` — the just-shipped claim is
|
|
105
|
+
// the only matching row, meaning this is the first ship.
|
|
106
|
+
if (!await alreadyUnlocked(client, builderId, 'first-ship')) {
|
|
107
|
+
const count = await client.query(
|
|
108
|
+
`SELECT COUNT(*) FROM claims
|
|
109
|
+
WHERE builder_id=$1 AND outcome='shipped'`,
|
|
110
|
+
[builderId]
|
|
111
|
+
);
|
|
112
|
+
if (Number(count.rows[0].count) === 1) {
|
|
113
|
+
const unlocked = await unlockAchievement(client, builderId, 'first-ship', taskId);
|
|
114
|
+
if (unlocked) results.push(unlocked);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// art-pipeline-shipper: the shipped diff includes art/ (falls back to touches[]).
|
|
119
|
+
if (!await alreadyUnlocked(client, builderId, 'art-pipeline-shipper')) {
|
|
120
|
+
const task = await client.query(
|
|
121
|
+
'SELECT touches FROM tasks WHERE id=$1',
|
|
122
|
+
[taskId]
|
|
123
|
+
);
|
|
124
|
+
if (task.rowCount > 0) {
|
|
125
|
+
const files = filesForBadges(changedFiles, task.rows[0].touches || []);
|
|
126
|
+
if (files.some((t) => t.startsWith('art/'))) {
|
|
127
|
+
const unlocked = await unlockAchievement(client, builderId, 'art-pipeline-shipper', taskId);
|
|
128
|
+
if (unlocked) results.push(unlocked);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// gds-shipper: the shipped diff includes src/bongos/ or scripts/gds/ (falls back to touches[]).
|
|
134
|
+
if (!await alreadyUnlocked(client, builderId, 'gds-shipper')) {
|
|
135
|
+
const task = await client.query(
|
|
136
|
+
'SELECT touches FROM tasks WHERE id=$1',
|
|
137
|
+
[taskId]
|
|
138
|
+
);
|
|
139
|
+
if (task.rowCount > 0) {
|
|
140
|
+
const files = filesForBadges(changedFiles, task.rows[0].touches || []);
|
|
141
|
+
if (files.some((t) => t.startsWith('src/bongos/') || t.startsWith('scripts/gds/'))) {
|
|
142
|
+
const unlocked = await unlockAchievement(client, builderId, 'gds-shipper', taskId);
|
|
143
|
+
if (unlocked) results.push(unlocked);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// first-parallel-claim (strict): two of this builder's claims overlapped on
|
|
149
|
+
// the wall clock AND both shipped successfully. Awarded on the LATER of the
|
|
150
|
+
// two ships. Called from inside resolveClaim's transaction after the current
|
|
151
|
+
// claim has been resolved with outcome='shipped' and released_at=now(), so
|
|
152
|
+
// both legs of the pair are visible to this query.
|
|
153
|
+
//
|
|
154
|
+
// Locked definition (PMS-V2 planning, limitations/pms-v2.md):
|
|
155
|
+
// - outcome='shipped' required on BOTH claims (abandoned/partial don't count)
|
|
156
|
+
// - claim intervals must overlap: tstzrange(A) && tstzrange(B)
|
|
157
|
+
// - unlocked_by_task_id = the second-shipped claim's task_id
|
|
158
|
+
// - unlocked_at = the later released_at (handled by unlockAchievement's now())
|
|
159
|
+
if (!await alreadyUnlocked(client, builderId, 'first-parallel-claim')) {
|
|
160
|
+
// Find any pair of shipped claims by this builder whose intervals overlap.
|
|
161
|
+
// Pick the pair with the latest second-ship; report the second-shipped
|
|
162
|
+
// claim's task_id so the achievement is attributed to it.
|
|
163
|
+
const pair = await client.query(
|
|
164
|
+
`WITH shipped AS (
|
|
165
|
+
SELECT id, task_id, claimed_at, released_at
|
|
166
|
+
FROM claims
|
|
167
|
+
WHERE builder_id = $1
|
|
168
|
+
AND outcome = 'shipped'
|
|
169
|
+
AND released_at IS NOT NULL
|
|
170
|
+
)
|
|
171
|
+
SELECT b.task_id AS later_task_id
|
|
172
|
+
FROM shipped a
|
|
173
|
+
JOIN shipped b ON b.id <> a.id
|
|
174
|
+
WHERE tstzrange(a.claimed_at, a.released_at) && tstzrange(b.claimed_at, b.released_at)
|
|
175
|
+
AND b.released_at >= a.released_at
|
|
176
|
+
ORDER BY b.released_at DESC, a.released_at DESC
|
|
177
|
+
LIMIT 1`,
|
|
178
|
+
[builderId]
|
|
179
|
+
);
|
|
180
|
+
if (pair.rowCount > 0) {
|
|
181
|
+
const laterTaskId = pair.rows[0].later_task_id;
|
|
182
|
+
const unlocked = await unlockAchievement(client, builderId, 'first-parallel-claim', laterTaskId);
|
|
183
|
+
if (unlocked) results.push(unlocked);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// streak-3 and streak-7: consecutive qualifying ship-days in builder's local
|
|
188
|
+
// timezone. computeStreak reads the just-resolved claim from the same
|
|
189
|
+
// transaction client (claim row already has outcome='shipped' + released_at
|
|
190
|
+
// by the time evaluateAfterShip is called from resolveClaim). The task is
|
|
191
|
+
// also at status='confirmed' by then (verification passed branch only).
|
|
192
|
+
//
|
|
193
|
+
// Anti-double-unlock is enforced both here (alreadyUnlocked check) and by
|
|
194
|
+
// the (builder_id, achievement_id) PK on builder_achievements.
|
|
195
|
+
//
|
|
196
|
+
// Once unlocked, these achievements stay unlocked — a streak-3 unlocked
|
|
197
|
+
// yesterday is NOT re-locked when today is a non-ship-day. The PK enforces
|
|
198
|
+
// this automatically (no re-insert possible).
|
|
199
|
+
const needStreak3 = !await alreadyUnlocked(client, builderId, 'streak-3');
|
|
200
|
+
const needStreak7 = !await alreadyUnlocked(client, builderId, 'streak-7');
|
|
201
|
+
if (needStreak3 || needStreak7) {
|
|
202
|
+
const s = await streak.computeStreak(builderId, client);
|
|
203
|
+
if (needStreak3 && s.current_streak >= 3) {
|
|
204
|
+
const unlocked = await unlockAchievement(client, builderId, 'streak-3', taskId);
|
|
205
|
+
if (unlocked) results.push(unlocked);
|
|
206
|
+
}
|
|
207
|
+
if (needStreak7 && s.current_streak >= 7) {
|
|
208
|
+
const unlocked = await unlockAchievement(client, builderId, 'streak-7', taskId);
|
|
209
|
+
if (unlocked) results.push(unlocked);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
return results;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// Called after credits are awarded — pass total_credits before and after the delta.
|
|
217
|
+
async function evaluateAfterCreditAward(client, builderId, totalBefore, totalAfter) {
|
|
218
|
+
const results = [];
|
|
219
|
+
|
|
220
|
+
// breaking-the-100c-bar: crossed 100 from below
|
|
221
|
+
if (!await alreadyUnlocked(client, builderId, 'breaking-the-100c-bar')) {
|
|
222
|
+
if (totalBefore < 100 && totalAfter >= 100) {
|
|
223
|
+
const unlocked = await unlockAchievement(client, builderId, 'breaking-the-100c-bar', null);
|
|
224
|
+
if (unlocked) results.push(unlocked);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
return results;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// -------------------------------------------------------------------------
|
|
232
|
+
// State-based reconcile (task 1679) — the durable replacement for the fragile
|
|
233
|
+
// "evaluate exactly what just happened in this txn" hooks above.
|
|
234
|
+
//
|
|
235
|
+
// WHY this exists: the granular evaluators only ran on SOME ship paths.
|
|
236
|
+
// db.applyGrade (the subagent-grader path) called evaluateAfterShip +
|
|
237
|
+
// evaluateAfterCreditAward, but db.confirmTask (the --skip-grade / server
|
|
238
|
+
// grader_bypass path — the DOMINANT one) called NEITHER. So a builder who ships
|
|
239
|
+
// with grader_bypass on only ever unlocked first-claim (the claim path works).
|
|
240
|
+
// And breaking-the-100c-bar was boundary-only (totalBefore<100 && totalAfter>=100)
|
|
241
|
+
// on a credit branch the per-session cost-plus reward (ADR 0054) never hits, so
|
|
242
|
+
// it fired for NOBODY — even lars589 at 22k credits. The whole board looked dead.
|
|
243
|
+
//
|
|
244
|
+
// reconcileBuilderAchievements evaluates every achievement against CURRENT DB
|
|
245
|
+
// state and unlocks any the builder is eligible for but hasn't. It is:
|
|
246
|
+
// - idempotent: the alreadyUnlocked guard + the (builder_id, achievement_id)
|
|
247
|
+
// PK + ON CONFLICT DO NOTHING mean re-running never double-unlocks or
|
|
248
|
+
// double-awards a credit bonus.
|
|
249
|
+
// - path-independent: keyed off committed state (claims.outcome='shipped',
|
|
250
|
+
// tasks.touches — backfilled from the REAL diff at ship per #882 —
|
|
251
|
+
// builders.total_credits, credit_log), so it works no matter which ship
|
|
252
|
+
// path ran. Callers wrap it in a SAVEPOINT so it can never fail a ship.
|
|
253
|
+
// - the SINGLE SOURCE OF TRUTH for eligibility (STATE_EVALUATORS below).
|
|
254
|
+
// scripts/gds/diagnose-achievements.js and the backfill CLI import this same
|
|
255
|
+
// list, so the stale-prefix drift that silently broke gds-shipper
|
|
256
|
+
// (idea 44/idea 50: the diagnose/backfill copies still said src/pms/) cannot
|
|
257
|
+
// recur — there is now one definition, not three.
|
|
258
|
+
//
|
|
259
|
+
// Each predicate takes (client, builderId) → boolean. `client` may be a tx
|
|
260
|
+
// client (reconcile-at-ship) or the shared pool (diagnose / backfill CLI).
|
|
261
|
+
|
|
262
|
+
async function eligible_firstClaim(client, builderId) {
|
|
263
|
+
const r = await client.query('SELECT 1 FROM claims WHERE builder_id=$1 LIMIT 1', [builderId]);
|
|
264
|
+
return r.rowCount > 0;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
async function eligible_firstShip(client, builderId) {
|
|
268
|
+
const r = await client.query(
|
|
269
|
+
`SELECT 1 FROM claims WHERE builder_id=$1 AND outcome='shipped' LIMIT 1`,
|
|
270
|
+
[builderId]
|
|
271
|
+
);
|
|
272
|
+
return r.rowCount > 0;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
async function eligible_artPipelineShipper(client, builderId) {
|
|
276
|
+
const r = await client.query(
|
|
277
|
+
`SELECT 1
|
|
278
|
+
FROM claims c JOIN tasks t ON t.id = c.task_id
|
|
279
|
+
WHERE c.builder_id = $1 AND c.outcome = 'shipped'
|
|
280
|
+
AND EXISTS (SELECT 1 FROM unnest(t.touches) AS p WHERE p LIKE 'art/%')
|
|
281
|
+
LIMIT 1`,
|
|
282
|
+
[builderId]
|
|
283
|
+
);
|
|
284
|
+
return r.rowCount > 0;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
async function eligible_gdsShipper(client, builderId) {
|
|
288
|
+
const r = await client.query(
|
|
289
|
+
`SELECT 1
|
|
290
|
+
FROM claims c JOIN tasks t ON t.id = c.task_id
|
|
291
|
+
WHERE c.builder_id = $1 AND c.outcome = 'shipped'
|
|
292
|
+
AND EXISTS (SELECT 1 FROM unnest(t.touches) AS p
|
|
293
|
+
WHERE p LIKE 'src/bongos/%' OR p LIKE 'scripts/gds/%')
|
|
294
|
+
LIMIT 1`,
|
|
295
|
+
[builderId]
|
|
296
|
+
);
|
|
297
|
+
return r.rowCount > 0;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
async function eligible_firstParallelClaim(client, builderId) {
|
|
301
|
+
const r = await client.query(
|
|
302
|
+
`WITH shipped AS (
|
|
303
|
+
SELECT id, claimed_at, released_at FROM claims
|
|
304
|
+
WHERE builder_id = $1 AND outcome = 'shipped' AND released_at IS NOT NULL
|
|
305
|
+
)
|
|
306
|
+
SELECT 1 FROM shipped a JOIN shipped b ON b.id <> a.id
|
|
307
|
+
WHERE tstzrange(a.claimed_at, a.released_at) && tstzrange(b.claimed_at, b.released_at)
|
|
308
|
+
LIMIT 1`,
|
|
309
|
+
[builderId]
|
|
310
|
+
);
|
|
311
|
+
return r.rowCount > 0;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
async function eligible_breaking100c(client, builderId) {
|
|
315
|
+
const r = await client.query('SELECT total_credits FROM builders WHERE id = $1', [builderId]);
|
|
316
|
+
return r.rowCount > 0 && Number(r.rows[0].total_credits) >= 100;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
async function eligible_subtractor(client, builderId) {
|
|
320
|
+
// Mirror credits.awardNetNegativeBonus: subtractor unlocks at SUBTRACTOR_THRESHOLD
|
|
321
|
+
// net-negative ship bonuses. Lazy-require the threshold (credits.js requires
|
|
322
|
+
// this module, so a top-level require would be circular — same lazy pattern
|
|
323
|
+
// renderProgressText uses for ./streak).
|
|
324
|
+
const { SUBTRACTOR_THRESHOLD } = require('./credits');
|
|
325
|
+
const r = await client.query(
|
|
326
|
+
`SELECT COUNT(*)::int AS n FROM credit_log
|
|
327
|
+
WHERE builder_id = $1 AND reason = 'ship.net_negative'`,
|
|
328
|
+
[builderId]
|
|
329
|
+
);
|
|
330
|
+
return Number(r.rows[0].n) >= SUBTRACTOR_THRESHOLD;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// Streaks use longest_streak (NOT current_streak): reconcile asks "did this
|
|
334
|
+
// builder EVER reach an N-night streak", and per the achievement's own contract
|
|
335
|
+
// an unlocked streak stays unlocked even after a gap. (The live evaluateAfterShip
|
|
336
|
+
// checks current_streak because it only fires the instant a streak extends; the
|
|
337
|
+
// retroactive view is longest_streak.)
|
|
338
|
+
async function eligible_streak3(client, builderId) {
|
|
339
|
+
const s = await streak.computeStreak(builderId, client);
|
|
340
|
+
return s.longest_streak >= 3;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
async function eligible_streak7(client, builderId) {
|
|
344
|
+
const s = await streak.computeStreak(builderId, client);
|
|
345
|
+
return s.longest_streak >= 7;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// Ordered by achievements.sort_order so banners/backfill output read naturally.
|
|
349
|
+
const STATE_EVALUATORS = [
|
|
350
|
+
{ id: 'first-ship', fn: eligible_firstShip },
|
|
351
|
+
{ id: 'first-claim', fn: eligible_firstClaim },
|
|
352
|
+
{ id: 'first-parallel-claim', fn: eligible_firstParallelClaim },
|
|
353
|
+
{ id: 'streak-3', fn: eligible_streak3 },
|
|
354
|
+
{ id: 'streak-7', fn: eligible_streak7 },
|
|
355
|
+
{ id: 'art-pipeline-shipper', fn: eligible_artPipelineShipper },
|
|
356
|
+
{ id: 'subtractor', fn: eligible_subtractor },
|
|
357
|
+
{ id: 'gds-shipper', fn: eligible_gdsShipper },
|
|
358
|
+
{ id: 'breaking-the-100c-bar', fn: eligible_breaking100c },
|
|
359
|
+
];
|
|
360
|
+
|
|
361
|
+
// Unlock every achievement the builder currently qualifies for but hasn't yet.
|
|
362
|
+
// Returns the array of just-unlocked { id, name, credit_bonus }. Idempotent.
|
|
363
|
+
// Callers inside a ship transaction MUST wrap this in a SAVEPOINT so a predicate
|
|
364
|
+
// error rolls back only the reconcile, never the ship/confirm it runs within.
|
|
365
|
+
async function reconcileBuilderAchievements(client, builderId, opts = {}) {
|
|
366
|
+
const { taskId = null } = opts;
|
|
367
|
+
const results = [];
|
|
368
|
+
for (const ev of STATE_EVALUATORS) {
|
|
369
|
+
if (await alreadyUnlocked(client, builderId, ev.id)) continue;
|
|
370
|
+
if (await ev.fn(client, builderId)) {
|
|
371
|
+
const unlocked = await unlockAchievement(client, builderId, ev.id, taskId);
|
|
372
|
+
if (unlocked) results.push(unlocked);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
return results;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
// -------------------------------------------------------------------------
|
|
379
|
+
// Achievements — minimal getters added by migration 006_pms_v2.
|
|
380
|
+
// Full evaluator + unlock writes live in src/bongos/achievements.js (task K1).
|
|
381
|
+
// -------------------------------------------------------------------------
|
|
382
|
+
|
|
383
|
+
async function listAchievements() {
|
|
384
|
+
const { rows } = await pool.query(
|
|
385
|
+
`SELECT id, name, description, icon, credit_bonus, sort_order
|
|
386
|
+
FROM achievements
|
|
387
|
+
ORDER BY sort_order, id`
|
|
388
|
+
);
|
|
389
|
+
return rows;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
async function getBuilderAchievements(builderId) {
|
|
393
|
+
const { rows } = await pool.query(
|
|
394
|
+
`SELECT ba.builder_id, ba.achievement_id, ba.unlocked_at, ba.unlocked_by_task_id,
|
|
395
|
+
a.name, a.description, a.icon, a.credit_bonus, a.sort_order
|
|
396
|
+
FROM builder_achievements ba
|
|
397
|
+
JOIN achievements a ON a.id = ba.achievement_id
|
|
398
|
+
WHERE ba.builder_id = $1
|
|
399
|
+
ORDER BY a.sort_order`,
|
|
400
|
+
[builderId]
|
|
401
|
+
);
|
|
402
|
+
return rows;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
// PMS-V2 #188: enriched leaderboard. Single query — for each builder in the
|
|
406
|
+
// top N (by total_credits), includes an `achievements` string[] of up to
|
|
407
|
+
// `perBuilderCap` achievement IDs the builder has unlocked, sorted by
|
|
408
|
+
// achievements.sort_order. No N+1: one round trip total.
|
|
409
|
+
async function getLeaderboardWithAchievements(limit = 10, perBuilderCap = 5) {
|
|
410
|
+
const { rows } = await pool.query(
|
|
411
|
+
`SELECT b.id,
|
|
412
|
+
b.github_login,
|
|
413
|
+
b.display_name,
|
|
414
|
+
b.avatar_url,
|
|
415
|
+
b.total_credits,
|
|
416
|
+
b.rank,
|
|
417
|
+
COALESCE((
|
|
418
|
+
SELECT array_agg(t.achievement_id ORDER BY t.sort_order)
|
|
419
|
+
FROM (
|
|
420
|
+
SELECT ba.achievement_id, a.sort_order
|
|
421
|
+
FROM builder_achievements ba
|
|
422
|
+
JOIN achievements a ON a.id = ba.achievement_id
|
|
423
|
+
WHERE ba.builder_id = b.id
|
|
424
|
+
ORDER BY a.sort_order
|
|
425
|
+
LIMIT $2
|
|
426
|
+
) t
|
|
427
|
+
), ARRAY[]::text[]) AS achievements
|
|
428
|
+
FROM builders b
|
|
429
|
+
ORDER BY b.total_credits DESC, b.created_at ASC
|
|
430
|
+
LIMIT $1`,
|
|
431
|
+
[limit, perBuilderCap]
|
|
432
|
+
);
|
|
433
|
+
return rows;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
// PMS-V2 #188: compute human-readable progress for every achievement the
|
|
437
|
+
// builder hasn't unlocked yet. Returns rows shaped like:
|
|
438
|
+
// { achievement_id, name, description, icon, progress_text }
|
|
439
|
+
// Single round-trip — one aggregate query that joins achievements with the
|
|
440
|
+
// per-builder counters (shipped tasks, claims, art ships, pms ships,
|
|
441
|
+
// overlapping-pair count) and renders the progress sentence in JS.
|
|
442
|
+
async function getLockedAchievementsProgress(builderId) {
|
|
443
|
+
// One query — pulls achievements + the counters this builder needs to
|
|
444
|
+
// produce progress text. The CROSS JOIN against the single-row counters
|
|
445
|
+
// CTE is cheap; the builder_achievements anti-join (NOT EXISTS) excludes
|
|
446
|
+
// achievements already unlocked.
|
|
447
|
+
const { rows } = await pool.query(
|
|
448
|
+
`WITH counters AS (
|
|
449
|
+
SELECT
|
|
450
|
+
(SELECT COUNT(*) FROM session_logs
|
|
451
|
+
WHERE builder_id = $1 AND outcome = 'shipped') AS ships,
|
|
452
|
+
(SELECT COUNT(*) FROM claims
|
|
453
|
+
WHERE builder_id = $1) AS claims_total,
|
|
454
|
+
-- touches[] cleanup [3/8] (task 878): these retrospective counters key
|
|
455
|
+
-- off touches[] (the prediction). Unlike the one-time shipper badges
|
|
456
|
+
-- (re-pointed at the real diff via evaluateAfterShip), a per-load
|
|
457
|
+
-- aggregate over historical ships has no committed diff to read, so it
|
|
458
|
+
-- stays on touches[] — which becomes diff-accurate once #882 backfills
|
|
459
|
+
-- touches[] from the committed diff at ship time. No bespoke plumbing.
|
|
460
|
+
(SELECT COUNT(*) FROM tasks
|
|
461
|
+
WHERE shipped_by = $1 AND status = 'shipped'
|
|
462
|
+
AND EXISTS (SELECT 1 FROM unnest(COALESCE(touches, ARRAY[]::text[])) t
|
|
463
|
+
WHERE t LIKE 'art/%')) AS art_ships,
|
|
464
|
+
(SELECT COUNT(*) FROM tasks
|
|
465
|
+
WHERE shipped_by = $1 AND status = 'shipped'
|
|
466
|
+
AND EXISTS (SELECT 1 FROM unnest(COALESCE(touches, ARRAY[]::text[])) t
|
|
467
|
+
WHERE t LIKE 'src/bongos/%' OR t LIKE 'scripts/gds/%')) AS pms_ships,
|
|
468
|
+
(SELECT COALESCE(b.total_credits, 0) FROM builders b WHERE b.id = $1) AS total_credits,
|
|
469
|
+
(SELECT COUNT(*)
|
|
470
|
+
FROM claims a
|
|
471
|
+
JOIN claims b2 ON b2.id <> a.id
|
|
472
|
+
AND b2.builder_id = a.builder_id
|
|
473
|
+
WHERE a.builder_id = $1
|
|
474
|
+
AND a.outcome = 'shipped' AND a.released_at IS NOT NULL
|
|
475
|
+
AND b2.outcome = 'shipped' AND b2.released_at IS NOT NULL
|
|
476
|
+
AND tstzrange(a.claimed_at, a.released_at)
|
|
477
|
+
&& tstzrange(b2.claimed_at, b2.released_at)) AS overlap_pairs
|
|
478
|
+
)
|
|
479
|
+
SELECT a.id AS achievement_id,
|
|
480
|
+
a.name,
|
|
481
|
+
a.description,
|
|
482
|
+
a.icon,
|
|
483
|
+
a.credit_bonus,
|
|
484
|
+
c.ships,
|
|
485
|
+
c.claims_total,
|
|
486
|
+
c.art_ships,
|
|
487
|
+
c.pms_ships,
|
|
488
|
+
c.total_credits,
|
|
489
|
+
c.overlap_pairs
|
|
490
|
+
FROM achievements a
|
|
491
|
+
CROSS JOIN counters c
|
|
492
|
+
WHERE NOT EXISTS (
|
|
493
|
+
SELECT 1 FROM builder_achievements ba
|
|
494
|
+
WHERE ba.builder_id = $1 AND ba.achievement_id = a.id
|
|
495
|
+
)
|
|
496
|
+
ORDER BY a.sort_order`,
|
|
497
|
+
[builderId]
|
|
498
|
+
);
|
|
499
|
+
|
|
500
|
+
return rows.map((r) => ({
|
|
501
|
+
achievement_id: r.achievement_id,
|
|
502
|
+
name: r.name,
|
|
503
|
+
description: r.description,
|
|
504
|
+
icon: r.icon,
|
|
505
|
+
progress_text: renderProgressText(r),
|
|
506
|
+
}));
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
// Pure function — turns the counters row into a human-readable progress
|
|
510
|
+
// sentence. Fallbacks gracefully when src/bongos/streak.js (task #52) hasn't
|
|
511
|
+
// shipped yet: the streak achievements report a generic "track N consecutive
|
|
512
|
+
// ship-days" hint instead of a real count.
|
|
513
|
+
function renderProgressText(row) {
|
|
514
|
+
const id = row.achievement_id;
|
|
515
|
+
const ships = Number(row.ships || 0);
|
|
516
|
+
const claimsTotal = Number(row.claims_total || 0);
|
|
517
|
+
const artShips = Number(row.art_ships || 0);
|
|
518
|
+
const pmsShips = Number(row.pms_ships || 0);
|
|
519
|
+
const totalCredits = Number(row.total_credits || 0);
|
|
520
|
+
const overlapPairs = Number(row.overlap_pairs || 0);
|
|
521
|
+
|
|
522
|
+
// Optional dependency — task #52 may or may not have shipped yet.
|
|
523
|
+
let streak = null;
|
|
524
|
+
try {
|
|
525
|
+
// eslint-disable-next-line global-require
|
|
526
|
+
streak = require('./streak');
|
|
527
|
+
} catch (_) {
|
|
528
|
+
streak = null;
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
switch (id) {
|
|
532
|
+
case 'first-ship':
|
|
533
|
+
return ships === 0
|
|
534
|
+
? 'needs first shipped task'
|
|
535
|
+
: 'keep building';
|
|
536
|
+
case 'first-claim':
|
|
537
|
+
return claimsTotal === 0
|
|
538
|
+
? 'needs first claim'
|
|
539
|
+
: 'keep building';
|
|
540
|
+
case 'first-parallel-claim':
|
|
541
|
+
return overlapPairs === 0
|
|
542
|
+
? 'needs two shipped tasks with overlapping claim windows'
|
|
543
|
+
: 'keep building';
|
|
544
|
+
case 'streak-3':
|
|
545
|
+
case 'streak-7': {
|
|
546
|
+
const threshold = id === 'streak-3' ? 3 : 7;
|
|
547
|
+
// Use streak.js if present (task #52). Render as e.g.
|
|
548
|
+
// "1 of 3 ships toward streak-3"
|
|
549
|
+
if (streak && typeof streak.computeStreak === 'function') {
|
|
550
|
+
try {
|
|
551
|
+
// computeStreak may be async — handle both shapes by ignoring promise
|
|
552
|
+
// returns (we can't await inside this sync renderer). If async, fall
|
|
553
|
+
// through to the generic hint.
|
|
554
|
+
const res = streak.computeStreak();
|
|
555
|
+
if (res && typeof res.then !== 'function' && typeof res.current_streak === 'number') {
|
|
556
|
+
const cur = Math.max(0, Math.min(res.current_streak, threshold));
|
|
557
|
+
return `${cur} of ${threshold} ships toward ${id}`;
|
|
558
|
+
}
|
|
559
|
+
} catch (_) { /* fall through */ }
|
|
560
|
+
}
|
|
561
|
+
return `track ${threshold} consecutive ship-days`;
|
|
562
|
+
}
|
|
563
|
+
case 'art-pipeline-shipper':
|
|
564
|
+
return artShips === 0
|
|
565
|
+
? 'needs one shipped task touching art/'
|
|
566
|
+
: 'keep building';
|
|
567
|
+
case 'gds-shipper':
|
|
568
|
+
return pmsShips === 0
|
|
569
|
+
? 'needs one shipped task touching src/bongos/ or scripts/gds/'
|
|
570
|
+
: 'keep building';
|
|
571
|
+
case 'breaking-the-100c-bar': {
|
|
572
|
+
const have = Math.max(0, Math.min(totalCredits, 100));
|
|
573
|
+
return `${have} of 100c toward breaking-the-100c-bar`;
|
|
574
|
+
}
|
|
575
|
+
default:
|
|
576
|
+
return 'keep building';
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
module.exports = {
|
|
581
|
+
evaluateAfterClaim,
|
|
582
|
+
evaluateAfterShip,
|
|
583
|
+
evaluateAfterCreditAward,
|
|
584
|
+
reconcileBuilderAchievements,
|
|
585
|
+
STATE_EVALUATORS,
|
|
586
|
+
alreadyUnlocked,
|
|
587
|
+
unlockAchievement,
|
|
588
|
+
filesForBadges,
|
|
589
|
+
listAchievements,
|
|
590
|
+
getBuilderAchievements,
|
|
591
|
+
getLeaderboardWithAchievements,
|
|
592
|
+
getLockedAchievementsProgress,
|
|
593
|
+
renderProgressText,
|
|
594
|
+
};
|