@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
package/src/bongos/db.js
ADDED
|
@@ -0,0 +1,911 @@
|
|
|
1
|
+
// src/bongos/db.js — the GDS core db RESIDUE after the lifecycle carve (BV1.R86 /
|
|
2
|
+
// ADR 0093 §3). The build state machine (tasks·claims·versions·done-when·ship)
|
|
3
|
+
// graduated to modules/lifecycle/db.js; what remains here is the non-lifecycle
|
|
4
|
+
// residue the kernel + core read routes still own:
|
|
5
|
+
// • builder IDENTITY + admission (upsertBuilder, seatFirstAdminIfUnclaimed,
|
|
6
|
+
// getBuilderByGithubId, hasInvitedAccessRequest, linkAnthropicAccount,
|
|
7
|
+
// updateBuilderDisciplines) — auth.js imports these; they CANNOT live in a
|
|
8
|
+
// module (auth.js is kernel and may not require a module).
|
|
9
|
+
// • RANK + status MANAGEMENT (setBuilderRank/_applyRankChangeTx/RANKS,
|
|
10
|
+
// getLatestRankChangeForBuilder, deactivate/reactivateBuilder) — Archon-driven
|
|
11
|
+
// identity ops consumed by routes/builders.js, NOT the task lifecycle.
|
|
12
|
+
// • AUTH sessions (builder_sessions: createSession/lookupSession/revoke*/
|
|
13
|
+
// hasCliSession/SESSION_TTL_MS) — the token store auth.js drives.
|
|
14
|
+
// • TWIN / social reads (Discord link flow, karma feed, audit-log read, the
|
|
15
|
+
// grade-trend builderRollingAvgGrade the sessions BFG also consumes) + the
|
|
16
|
+
// security_docs store (the kernel security-PROPERTY plane, routes/security.js).
|
|
17
|
+
// • The art-pipeline Gemini-key leak (api.getBuilderGeminiKeyRow/…).
|
|
18
|
+
// db-kernel.js (identity/audit/rank/withTx) stays the bounded kernel slice this
|
|
19
|
+
// re-exports through, exactly as before (ADR 0091 §2). Pure SQL plumbing;
|
|
20
|
+
// routing/auth lives elsewhere.
|
|
21
|
+
//
|
|
22
|
+
// sealSessionLog + _applyRankChangeTx (+ RANKS / singleRungPromotionError) + the
|
|
23
|
+
// gradePassCount fragment are DELIBERATELY duplicated with modules/lifecycle/db.js
|
|
24
|
+
// (ADR 0091 §2 boundary-forced duplication): the same close-row / rank-change /
|
|
25
|
+
// grade-count SQL runs on both sides of the kernel↔module line — keep in sync.
|
|
26
|
+
|
|
27
|
+
const { pool } = require('./pool');
|
|
28
|
+
// Module seam (ADR 0083 / BV1.R43). The rank/status-change paths EMIT
|
|
29
|
+
// `builder.box-reconcile-needed` AFTER COMMIT (best-effort) so the dev-box module
|
|
30
|
+
// can reconcile a droplet a demotion/graduation implies — never a direct require
|
|
31
|
+
// of the module.
|
|
32
|
+
const seams = require('../module-seams');
|
|
33
|
+
|
|
34
|
+
// Kernel db slice (BV1.R69 / ADR 0091 §2): builder IDENTITY (getBuilderById),
|
|
35
|
+
// the AUDIT log (insertAuditLog), the RANK ladder (LIVE_RANK_LADDER), and the
|
|
36
|
+
// transaction primitive (withTx) live in the bounded ./db-kernel slice the
|
|
37
|
+
// published doorway resolves through. Re-exported below so every caller is
|
|
38
|
+
// byte-identical; db-kernel depends only on ./pool, never ./db (one-way).
|
|
39
|
+
const {
|
|
40
|
+
withTx, getBuilderById, listActiveBuilders, insertAuditLog, LIVE_RANK_LADDER,
|
|
41
|
+
// Auth/identity/admission + the rank vocabulary carved to db-kernel (ADR 0102,
|
|
42
|
+
// finishing ADR 0091 §1). Re-exported below so db.js's other importers + its own
|
|
43
|
+
// internal uses (setBuilderRank's RANKS.indexOf, etc.) stay byte-identical.
|
|
44
|
+
RANKS, SESSION_TTL_MS, upsertBuilder, seatFirstAdminIfUnclaimed,
|
|
45
|
+
getBuilderByGithubId, hasInvitedAccessRequest, createSession, lookupSession,
|
|
46
|
+
} = require('./db-kernel');
|
|
47
|
+
|
|
48
|
+
// gradePassCount removed with builderRollingAvgGrade (its only core user) — that
|
|
49
|
+
// grade-TREND read carved to modules/grading/db.js (ADR 0102), with this one-line
|
|
50
|
+
// fragment inlined there. The modules/lifecycle/db.js twin of it is unaffected.
|
|
51
|
+
|
|
52
|
+
// The shared `bounds`/`days` DAY_SERIES_CTE for the costSummary day-series
|
|
53
|
+
// queries moved with costSummary into modules/economy/cost.js (BV1.R77 / ADR
|
|
54
|
+
// 0093 §§1-2) — its only two callers left the monolith.
|
|
55
|
+
|
|
56
|
+
// Seal a session_logs row inside an open transaction (ended_at is NOT NULL in
|
|
57
|
+
// the schema, so a "sealed" log = the closing row). `outcome` stays a PARAMETER
|
|
58
|
+
// — resolveClaim passes a variable ('shipped'/'partial'/'abandoned'), the two
|
|
59
|
+
// release paths pass the literal 'abandoned' (audit §2B db-tx).
|
|
60
|
+
|
|
61
|
+
async function sealSessionLog(client, { builderId, taskId, claimId, startedAt, outcome, notesMd }) {
|
|
62
|
+
await client.query(
|
|
63
|
+
`INSERT INTO session_logs (builder_id, task_id, claim_id, started_at, ended_at, outcome, notes_md)
|
|
64
|
+
VALUES ($1, $2, $3, $4, now(), $5, $6)`,
|
|
65
|
+
[builderId, taskId, claimId, startedAt, outcome, notesMd]
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// The builder on the most-recent claim for a task (the worker who did the
|
|
70
|
+
// work). Returns null when the task has no claim on record at all — each caller
|
|
71
|
+
// supplies its OWN fallback (confirmer / requester / grade-caller) at the call
|
|
72
|
+
// site, so that per-site drift is preserved (audit §2B db-deep, #538/#661).
|
|
73
|
+
|
|
74
|
+
// upsertBuilder — carved to ./db-kernel (ADR 0102). Imported + re-exported above.
|
|
75
|
+
|
|
76
|
+
// First-admin bootstrap (R62 / task 1201, ADR 0062). Replaces migration 023's
|
|
77
|
+
// hard-coded founding-Archon literal: a fresh install seats its CONFIGURED
|
|
78
|
+
// firstAdmin login as Archon, in code, at that account's first enrollment. The
|
|
79
|
+
// guard is atomic and conservative — it elevates the row ONLY while NO Archon
|
|
80
|
+
// exists yet, so it can never be used to escalate later (once an owner exists,
|
|
81
|
+
// every call is a no-op) and it is race-safe under concurrent enrollment. Login
|
|
82
|
+
// match is case-insensitive. Returns true iff this call seated the Archon.
|
|
83
|
+
|
|
84
|
+
// seatFirstAdminIfUnclaimed — carved to ./db-kernel (ADR 0102). Re-exported above.
|
|
85
|
+
|
|
86
|
+
// getBuilderById — the canonical builder-identity read — moved to ./db-kernel
|
|
87
|
+
// (BV1.R69 / ADR 0091 §2: identity is a kernel primitive). Imported +
|
|
88
|
+
// re-exported at the top of this file, so all callers are unchanged.
|
|
89
|
+
|
|
90
|
+
// V3.R10 (#235), criterion C3: store the Anthropic account a builder attested to
|
|
91
|
+
// during /builder-setup. `email` is what the builder confirmed; `userId` is the
|
|
92
|
+
// accountUuid Claude Code reported from ~/.claude.json oauthAccount. It is kept
|
|
93
|
+
// as optional cosmetic attribution only — NOT an auth boundary; the
|
|
94
|
+
// X-Anthropic-User identity pin was removed (task 1039 / idea 258).
|
|
95
|
+
// Idempotent: re-linking (e.g. re-running setup, or a builder switching machines)
|
|
96
|
+
// just overwrites the stored pair. Returns the updated identity columns.
|
|
97
|
+
|
|
98
|
+
async function linkAnthropicAccount(builderId, { email, userId }) {
|
|
99
|
+
const { rows } = await pool.query(
|
|
100
|
+
`UPDATE builders
|
|
101
|
+
SET anthropic_email = $2, anthropic_user_id = $3
|
|
102
|
+
WHERE id = $1
|
|
103
|
+
RETURNING id, anthropic_email, anthropic_user_id`,
|
|
104
|
+
[builderId, email ?? null, userId ?? null]
|
|
105
|
+
);
|
|
106
|
+
return rows[0] ?? null;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// getBuilderCostStatus() + autonomousApiSpendMtd() carved into
|
|
110
|
+
// modules/economy/cost.js (BV1.R77 / ADR 0093 §1-2). Core resolves them via the
|
|
111
|
+
// `reward` kernel port (me.js cost status; autonomy-gate.js reads them as a CLI).
|
|
112
|
+
|
|
113
|
+
// recordAutonomyRun() + lastAutonomyHead() (the autonomy_runs slice) carved into
|
|
114
|
+
// modules/autonomy/db.js (BV1.R83 / ADR 0093 §1). The MAS autonomy gate
|
|
115
|
+
// (scripts/gds/autonomy-gate.js, a CLI) reads them directly from the module; core
|
|
116
|
+
// never calls them. The autonomy_runs TABLE (migration 126) stays in core
|
|
117
|
+
// migrations/ (the shared-schema additive rule).
|
|
118
|
+
|
|
119
|
+
// setBuilderMonthlyBudget() carved into modules/economy/cost.js (BV1.R77 / ADR
|
|
120
|
+
// 0093 §1-2). routes/builders.js resolves it via the `reward` kernel port.
|
|
121
|
+
|
|
122
|
+
// setBuilderBoxBlocked + its box_blocked UPDATE RELOCATED to modules/dev-box/db.js
|
|
123
|
+
// (BV1.R68 / ADR 0091 §3): box-blocked is cleanly dev-box-owned — the module is
|
|
124
|
+
// its only writer AND reader (core never reads box_blocked) — so the query left
|
|
125
|
+
// the core monolith with the doorway re-export when the slice pattern landed.
|
|
126
|
+
|
|
127
|
+
// Approval-gated entry (2026-05-30). The web hall sign-in no longer auto-creates
|
|
128
|
+
// an account for any GitHub user — a first-time visitor must be approved first
|
|
129
|
+
// (an Archon marks their access_request 'invited'). These three small lookups
|
|
130
|
+
// back that gate (used in auth.js completeWebFlow and the access-request form).
|
|
131
|
+
|
|
132
|
+
// Does a builder row already exist for this stable GitHub numeric id? Returns a
|
|
133
|
+
// minimal row or null. github_id is the stable key (login can change).
|
|
134
|
+
|
|
135
|
+
// getBuilderByGithubId — carved to ./db-kernel (ADR 0102). Re-exported above.
|
|
136
|
+
|
|
137
|
+
// Has an Archon approved this login (an access_requests row at status='invited',
|
|
138
|
+
// case-insensitive)? This is the approval signal that lets a first-time web
|
|
139
|
+
// sign-in through — and that the form uses to say "you're already approved".
|
|
140
|
+
|
|
141
|
+
// hasInvitedAccessRequest — carved to ./db-kernel (ADR 0102). Re-exported above.
|
|
142
|
+
|
|
143
|
+
// Replace a builder's preferred_disciplines (migrations 027 + 086). Input is
|
|
144
|
+
// deduped, order-normalized, and validated against the disciplines THIS INSTANCE
|
|
145
|
+
// offers — core (engineer, ideator) plus any enabled feature module's disciplines
|
|
146
|
+
// (the art-pipeline module adds 'artist'), resolved via src/modules.js (R59 /
|
|
147
|
+
// task 1198). The DB CHECK still enforces the full known enum
|
|
148
|
+
// (engineer|artist|ideator) as a backstop; this is the instance-aware
|
|
149
|
+
// friendly-error layer, so a vanilla instance with the art pipeline off rejects
|
|
150
|
+
// 'artist' instead of silently storing an unofferable discipline. Returns the
|
|
151
|
+
// updated builder row, or throws { code: 'invalid_discipline', bad } if any
|
|
152
|
+
// element is not offered by this instance.
|
|
153
|
+
|
|
154
|
+
async function updateBuilderDisciplines(builderId, disciplines) {
|
|
155
|
+
const { enabledDisciplines } = require('../modules');
|
|
156
|
+
const offered = enabledDisciplines();
|
|
157
|
+
const list = Array.isArray(disciplines) ? disciplines : [];
|
|
158
|
+
const bad = list.filter((d) => !offered.includes(d));
|
|
159
|
+
if (bad.length) {
|
|
160
|
+
const err = new Error(`invalid discipline(s): ${bad.join(', ')}`);
|
|
161
|
+
err.code = 'invalid_discipline';
|
|
162
|
+
err.bad = bad;
|
|
163
|
+
throw err;
|
|
164
|
+
}
|
|
165
|
+
const normalized = offered.filter((d) => list.includes(d));
|
|
166
|
+
const { rows } = await pool.query(
|
|
167
|
+
`UPDATE builders
|
|
168
|
+
SET preferred_disciplines = $2
|
|
169
|
+
WHERE id = $1
|
|
170
|
+
RETURNING id, github_id, github_login, display_name, avatar_url, total_credits, karma, created_at, rank, preferred_disciplines`,
|
|
171
|
+
[builderId, normalized]
|
|
172
|
+
);
|
|
173
|
+
return rows[0] ?? null;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// The builder-PREFS db slice — the five per-builder preference jsonb columns on
|
|
177
|
+
// `builders` (skill_model_prefs / sound_prefs / behavior_prefs / event_sound_prefs)
|
|
178
|
+
// — was carved into modules/builder-settings/db.js (BV1.R80 / ADR 0093 §1). Core
|
|
179
|
+
// no longer reads/writes them: the `/me/*-prefs` routes moved to the module, and
|
|
180
|
+
// the `GET /me` aggregator resolves the `builder-settings` kernel port for the
|
|
181
|
+
// wandering/render/needs slices instead of importing those helpers directly.
|
|
182
|
+
|
|
183
|
+
// ---- per-builder Gemini key, encrypted at rest (migration 122 / task 1013) ----
|
|
184
|
+
//
|
|
185
|
+
// The plaintext key NEVER touches the DB — the caller encrypts it with
|
|
186
|
+
// src/bongos/secret-box.js (master key in server env only) and passes the opaque
|
|
187
|
+
// blob + the last-4 chars for masked display. These three helpers are the only
|
|
188
|
+
// readers/writers of the gemini_key_* columns.
|
|
189
|
+
|
|
190
|
+
// Set/replace the builder's own key. `enc` is the secret-box blob; `last4` is the
|
|
191
|
+
// plaintext's last 4 chars (for "…ABCD" display — not a secret). Returns the
|
|
192
|
+
// masked metadata, never the blob.
|
|
193
|
+
|
|
194
|
+
// setBuilderGeminiKey / clearBuilderGeminiKey / getBuilderGeminiKeyRow RELOCATED to
|
|
195
|
+
// modules/art-pipeline/db.js (ADR 0102) — the art module owns the gemini_key_*
|
|
196
|
+
// credential store + registers the 'art.getBuilderGeminiKeyRow' port; core me.js
|
|
197
|
+
// resolves that port (degrades to a no-key shape on a vanilla instance).
|
|
198
|
+
|
|
199
|
+
// Remove the builder's own key (back to "not set"). Returns { set: false }.
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
// Read the raw row for the builder's own key: { enc, last4, set_at }. `enc` is the
|
|
203
|
+
// still-encrypted blob — the caller decrypts with secret-box when it needs the
|
|
204
|
+
// plaintext (only the own-scoped /me/art-key delivery does). Returns
|
|
205
|
+
// { enc: null, ... } when no key is set.
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
// leaderboard() carved into modules/economy/credits.js (BV1.R77 / ADR 0093 §1-2).
|
|
209
|
+
// Core read routes resolve it via the `reward` kernel port.
|
|
210
|
+
|
|
211
|
+
// The full reserved rank ladder (matches the CHECK enum in migration 023).
|
|
212
|
+
// LIVE in V3: 'archon' (top), 'metic' (Archon-approved working rank — full
|
|
213
|
+
// claim/ship + triage/blocker/planning/priority; task #360 / ADR 0018),
|
|
214
|
+
// 'thetes' (the GRADUATED-newcomer rank — added in #692 / ADR 0034: claims the
|
|
215
|
+
// whole general queue but NO scope-shaping/trust powers; a Xenos auto-graduates
|
|
216
|
+
// here after THETES_GRADUATION_THRESHOLD successfully SHIPPED tasks), and 'xenos' (the
|
|
217
|
+
// sandboxed entry rank new builders default to since migration 029 — claims
|
|
218
|
+
// ONLY newcomer_friendly tasks). The rest stay reserved so future ranks never
|
|
219
|
+
// need a schema change. The DB CHECK is the backstop — this set lets the API
|
|
220
|
+
// give a clean 400 instead of leaking a constraint-violation 500.
|
|
221
|
+
//
|
|
222
|
+
// ORDER IS LOAD-BEARING: setBuilderRank uses RANKS.indexOf to decide
|
|
223
|
+
// promotion-vs-demotion (lower index = higher rank). So the live ladder must
|
|
224
|
+
// read archon > metic > thetes > xenos — thetes sits BETWEEN metic and xenos.
|
|
225
|
+
|
|
226
|
+
// RANKS — carved to ./db-kernel (ADR 0102); imported + re-exported above. Order is
|
|
227
|
+
// load-bearing (setBuilderRank's RANKS.indexOf below) and stays TWINNED with
|
|
228
|
+
// modules/lifecycle/db.js.
|
|
229
|
+
|
|
230
|
+
// THETES auto-graduation (#692 / ADR 0034; trigger corrected in #704). A Xenos
|
|
231
|
+
// who has this many SUCCESSFULLY SHIPPED tasks (tasks.status='shipped',
|
|
232
|
+
// attributed via tasks.shipped_by) is promoted xenos→thetes the moment the Nth
|
|
233
|
+
// ship lands. The signal is SHIPPED, not confirmed — a task only counts once it
|
|
234
|
+
// is merged + deployed, per the Archon rule "after 3 tasks are successfully
|
|
235
|
+
// shipped." Pure decision helper is exported so tests/rank_gate.mjs can exercise
|
|
236
|
+
// the threshold without a DB.
|
|
237
|
+
|
|
238
|
+
function singleRungPromotionError(oldRank, newRank) {
|
|
239
|
+
const a = REQUIRES_RANK_TIER[oldRank];
|
|
240
|
+
const b = REQUIRES_RANK_TIER[newRank];
|
|
241
|
+
if (!a || !b) return null; // one side is off the live ladder — not our gate
|
|
242
|
+
if (b <= a) return null; // demotion or lateral — unconstrained here
|
|
243
|
+
if (b - a === 1) return null; // exactly one rung up — allowed
|
|
244
|
+
return {
|
|
245
|
+
code: 'MULTI_RUNG_PROMOTION',
|
|
246
|
+
from: oldRank,
|
|
247
|
+
to: newRank,
|
|
248
|
+
next_rung: LIVE_RANK_LADDER[a], // rank at tier a+1 (ladder is 0-based)
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// disambiguateWorktreeName — V3.R51 (#270). Two simultaneously-ACTIVE claims
|
|
253
|
+
// must never share a worktree_name: `.claude/worktrees/<name>` is a filesystem
|
|
254
|
+
// path, and two live builders pointing at the same one would stomp each other.
|
|
255
|
+
// This is NOT a refusal (unlike ALREADY_CLAIMED / TOUCHES_CONFLICT) — we
|
|
256
|
+
// silently append a numeric suffix and let the claim succeed, returning the
|
|
257
|
+
// disambiguated name so the caller knows what they actually got.
|
|
258
|
+
//
|
|
259
|
+
// `taken` is the set of worktree_names held by currently-ACTIVE claims only
|
|
260
|
+
// (released_at IS NULL). A name freed by a resolved/shipped claim is freely
|
|
261
|
+
// reusable WITHOUT a suffix — this is load-bearing for the overnight builder,
|
|
262
|
+
// which reuses ONE worktree_name across sequential tasks (it ships, freeing the
|
|
263
|
+
// claim, before claiming the next). Keying off historical claims would break it.
|
|
264
|
+
//
|
|
265
|
+
// Suffix scheme: "name" → "name-2" → "name-3" … (first collision becomes -2,
|
|
266
|
+
// matching git-worktree / file-manager conventions). A null/empty desired name
|
|
267
|
+
// has nothing to collide on, so it's returned unchanged. Pure + exported so
|
|
268
|
+
// tests can exercise it without a DB; claimTask calls it inside the txn.
|
|
269
|
+
|
|
270
|
+
async function _applyRankChangeTx(client, { builderId, newRank, actorBuilderId, reasonNote = null, enforceSingleRungPromotion = false }) {
|
|
271
|
+
const { rows } = await client.query(
|
|
272
|
+
`SELECT id, rank, status FROM builders WHERE id = $1 FOR UPDATE`,
|
|
273
|
+
[builderId]
|
|
274
|
+
);
|
|
275
|
+
const target = rows[0];
|
|
276
|
+
if (!target) throw { code: 'BUILDER_NOT_FOUND' };
|
|
277
|
+
const oldRank = target.rank;
|
|
278
|
+
if (oldRank === newRank) throw { code: 'RANK_UNCHANGED', rank: oldRank };
|
|
279
|
+
|
|
280
|
+
// #707 — manual promotions advance ONE live rung at a time. Checked here
|
|
281
|
+
// (atomic, under the FOR UPDATE lock) but only when the caller opts in; the
|
|
282
|
+
// automatic xenos→thetes graduation (always +1) does not.
|
|
283
|
+
if (enforceSingleRungPromotion) {
|
|
284
|
+
const rungErr = singleRungPromotionError(oldRank, newRank);
|
|
285
|
+
if (rungErr) throw rungErr;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
const { rows: updated } = await client.query(
|
|
289
|
+
`UPDATE builders SET rank = $2 WHERE id = $1
|
|
290
|
+
RETURNING id, github_id, github_login, display_name, avatar_url, total_credits, created_at, rank`,
|
|
291
|
+
[builderId, newRank]
|
|
292
|
+
);
|
|
293
|
+
|
|
294
|
+
// V3.R28 / #249 — ceremony delta. Promotion (moving UP the ladder = lower
|
|
295
|
+
// index in RANKS) earns +5; demotion is audit-only (0).
|
|
296
|
+
const oldIdx = RANKS.indexOf(oldRank);
|
|
297
|
+
const newIdx = RANKS.indexOf(newRank);
|
|
298
|
+
const isPromotion = oldIdx !== -1 && newIdx !== -1 && newIdx < oldIdx;
|
|
299
|
+
const isDemotion = oldIdx !== -1 && newIdx !== -1 && newIdx > oldIdx;
|
|
300
|
+
const delta = isPromotion ? 5 : 0;
|
|
301
|
+
// reason is the join key for downstream pickup; the human-readable text stays
|
|
302
|
+
// in `description`. The "by builder#N" clause is load-bearing — the rank-change
|
|
303
|
+
// greeting parser (getLatestRankChangeForBuilder) matches on it — so an
|
|
304
|
+
// automatic promotion (#692) keeps it (actor = the builder themselves) and
|
|
305
|
+
// APPENDS the "auto-graduation: …" note rather than replacing it.
|
|
306
|
+
const description = reasonNote
|
|
307
|
+
? `rank_change: ${oldRank}→${newRank} by builder#${actorBuilderId} (${reasonNote})`
|
|
308
|
+
: `rank_change: ${oldRank}→${newRank} by builder#${actorBuilderId}`;
|
|
309
|
+
await client.query(
|
|
310
|
+
`INSERT INTO credit_log (builder_id, task_id, delta, reason, description)
|
|
311
|
+
VALUES ($1, NULL, $2, 'rank_change', $3)`,
|
|
312
|
+
[builderId, delta, description]
|
|
313
|
+
);
|
|
314
|
+
|
|
315
|
+
// V3.R38 / #259 — DEMOTION hook for criterion C7 (rank-change-near-instant).
|
|
316
|
+
// Revoke every active session in the same transaction so the demoted builder's
|
|
317
|
+
// CLI tokens stop working on their next API call. Combined with requireBuilder
|
|
318
|
+
// re-reading rank from the DB per request (ADR 0016), this is belt-and-braces.
|
|
319
|
+
// Promotion never revokes — we don't log someone out for getting a raise.
|
|
320
|
+
let demotionRevoked = 0;
|
|
321
|
+
if (isDemotion) {
|
|
322
|
+
const { rowCount } = await client.query(
|
|
323
|
+
`UPDATE builder_sessions
|
|
324
|
+
SET revoked_at = now()
|
|
325
|
+
WHERE builder_id = $1 AND revoked_at IS NULL`,
|
|
326
|
+
[builderId]
|
|
327
|
+
);
|
|
328
|
+
demotionRevoked = rowCount;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
return {
|
|
332
|
+
builder: updated[0],
|
|
333
|
+
previous_rank: oldRank,
|
|
334
|
+
status: target.status,
|
|
335
|
+
sessions_revoked: demotionRevoked,
|
|
336
|
+
direction: isPromotion ? 'promotion' : isDemotion ? 'demotion' : 'lateral',
|
|
337
|
+
credit_delta: delta,
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
async function setBuilderRank({ builderId, newRank, actorBuilderId }) {
|
|
343
|
+
const result = await withTx(async (client) => {
|
|
344
|
+
return _applyRankChangeTx(client, { builderId, newRank, actorBuilderId, enforceSingleRungPromotion: true });
|
|
345
|
+
});
|
|
346
|
+
// Source-access clawback (ADR 0031 §6 / #600). Post-commit, own connection,
|
|
347
|
+
// never throws — records the box reconcile this rank change implies (a demotion
|
|
348
|
+
// below the floor → deprovision; a graduation up → rescope). The CREDENTIAL
|
|
349
|
+
// layer is already cut off live on the next /box/source-access fetch; this
|
|
350
|
+
// just signals + audits the slower droplet-level reconcile.
|
|
351
|
+
await seams.emitAsync('builder.box-reconcile-needed', {
|
|
352
|
+
builderId, rank: newRank, status: result.status, actor: `rank-change:builder#${actorBuilderId}`,
|
|
353
|
+
});
|
|
354
|
+
return {
|
|
355
|
+
builder: result.builder,
|
|
356
|
+
previous_rank: result.previous_rank,
|
|
357
|
+
sessions_revoked: result.sessions_revoked,
|
|
358
|
+
direction: result.direction,
|
|
359
|
+
credit_delta: result.credit_delta,
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
// maybeAutoGraduateToThetes — #692 / ADR 0034 (trigger corrected #704). Call
|
|
364
|
+
// INSIDE the SHIP transaction (shipTask) AFTER the task flips to 'shipped',
|
|
365
|
+
// passing the task's attributed builder (tasks.shipped_by). If that builder is a
|
|
366
|
+
// Xenos who now has THETES_GRADUATION_THRESHOLD successfully SHIPPED tasks,
|
|
367
|
+
// promote them xenos→thetes atomically with the ship and return the rank-change
|
|
368
|
+
// result (so the caller fires the post-commit box reconcile). Returns null when
|
|
369
|
+
// no graduation happened. Idempotent: rank-guarded (only a current Xenos
|
|
370
|
+
// graduates) and counts SHIPPED tasks by attribution, so it fires exactly once
|
|
371
|
+
// per builder. The actor is the builder themselves — a system-driven promotion.
|
|
372
|
+
|
|
373
|
+
async function getLatestRankChangeForBuilder(builderId) {
|
|
374
|
+
// Match both schemas:
|
|
375
|
+
// post-R28: reason = 'rank_change'
|
|
376
|
+
// pre-R28: reason LIKE 'rank_change:%'
|
|
377
|
+
const { rows } = await pool.query(
|
|
378
|
+
`SELECT id, builder_id, delta, reason, description, recorded_at
|
|
379
|
+
FROM credit_log
|
|
380
|
+
WHERE builder_id = $1
|
|
381
|
+
AND (reason = 'rank_change' OR reason LIKE 'rank_change:%')
|
|
382
|
+
ORDER BY id DESC
|
|
383
|
+
LIMIT 1`,
|
|
384
|
+
[builderId]
|
|
385
|
+
);
|
|
386
|
+
const row = rows[0];
|
|
387
|
+
if (!row) return null;
|
|
388
|
+
// The "rank_change: <old>→<new> by builder#<actor>" string lives in
|
|
389
|
+
// `description` (post-R28) or `reason` (pre-R28).
|
|
390
|
+
const text = row.description || row.reason || '';
|
|
391
|
+
// Tolerant parser — fall back to nulls if anything's off.
|
|
392
|
+
const m = text.match(/rank_change:\s*([a-z]+)\s*→\s*([a-z]+)\s*by builder#(\d+)/i);
|
|
393
|
+
const oldRank = m ? m[1] : null;
|
|
394
|
+
const newRank = m ? m[2] : null;
|
|
395
|
+
const actorId = m ? Number(m[3]) : null;
|
|
396
|
+
// Direction by ladder index — same definition as setBuilderRank itself.
|
|
397
|
+
let direction = null;
|
|
398
|
+
if (oldRank && newRank) {
|
|
399
|
+
const oi = RANKS.indexOf(oldRank);
|
|
400
|
+
const ni = RANKS.indexOf(newRank);
|
|
401
|
+
if (oi !== -1 && ni !== -1) {
|
|
402
|
+
direction = ni < oi ? 'promotion' : ni > oi ? 'demotion' : 'lateral';
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
return {
|
|
406
|
+
id: row.id,
|
|
407
|
+
builder_id: row.builder_id,
|
|
408
|
+
old_rank: oldRank,
|
|
409
|
+
new_rank: newRank,
|
|
410
|
+
actor_builder_id: actorId,
|
|
411
|
+
delta: row.delta,
|
|
412
|
+
direction,
|
|
413
|
+
recorded_at: row.recorded_at,
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
// Graceful builder exit (V3.R88 #307). Deactivating a builder is reversible
|
|
418
|
+
// and lossless: drachmae (credits) + credit_log, shipped tasks, and historical
|
|
419
|
+
// session_logs all stay. What changes: status → inactive (blocks new claims via
|
|
420
|
+
// claimTask's guard), rank → 'xenos' (sandboxed tier), active claims released
|
|
421
|
+
// cleanly with a final 'abandoned' session_log sealing each, and the tasks
|
|
422
|
+
// returned to 'ready' for someone else. Reactivation flips status back; rank
|
|
423
|
+
// is NOT auto-restored (an Archon re-promotes deliberately via PATCH
|
|
424
|
+
// /builders/:id/rank). Memory archival is local-first and handled by the
|
|
425
|
+
// /builder-exit skill — the server never holds another builder's local memory
|
|
426
|
+
// (the server-side memory store is criterion #54's job, not this task's).
|
|
427
|
+
|
|
428
|
+
async function deactivateBuilder({ builderId, reason, actorBuilderId }) {
|
|
429
|
+
const { updated, activeClaims } = await withTx(async (client) => {
|
|
430
|
+
const { rows } = await client.query(
|
|
431
|
+
`SELECT id, rank, status FROM builders WHERE id = $1 FOR UPDATE`,
|
|
432
|
+
[builderId]
|
|
433
|
+
);
|
|
434
|
+
const target = rows[0];
|
|
435
|
+
if (!target) throw { code: 'BUILDER_NOT_FOUND' };
|
|
436
|
+
if (target.status === 'inactive') throw { code: 'ALREADY_INACTIVE' };
|
|
437
|
+
|
|
438
|
+
// Release every active claim, seal each with a final session_log, and
|
|
439
|
+
// return the task to 'ready' so the work isn't stranded.
|
|
440
|
+
const { rows: activeClaims } = await client.query(
|
|
441
|
+
`SELECT id AS claim_id, task_id, claimed_at FROM claims
|
|
442
|
+
WHERE builder_id = $1 AND released_at IS NULL FOR UPDATE`,
|
|
443
|
+
[builderId]
|
|
444
|
+
);
|
|
445
|
+
for (const c of activeClaims) {
|
|
446
|
+
await client.query(
|
|
447
|
+
`UPDATE claims SET released_at = now(), outcome = 'abandoned' WHERE id = $1`,
|
|
448
|
+
[c.claim_id]
|
|
449
|
+
);
|
|
450
|
+
// Only bounce the task back to 'ready' if it's still mid-flight.
|
|
451
|
+
await client.query(
|
|
452
|
+
`UPDATE tasks SET status = 'ready' WHERE id = $1 AND status = 'active'`,
|
|
453
|
+
[c.task_id]
|
|
454
|
+
);
|
|
455
|
+
// Seal an outstanding session_log (ended_at is NOT NULL in the schema,
|
|
456
|
+
// so "sealing" = writing the closing abandoned-on-exit row).
|
|
457
|
+
await sealSessionLog(client, {
|
|
458
|
+
builderId, taskId: c.task_id, claimId: c.claim_id, startedAt: c.claimed_at,
|
|
459
|
+
outcome: 'abandoned',
|
|
460
|
+
notesMd: `Claim released on builder exit (graceful deactivation by builder#${actorBuilderId}).`,
|
|
461
|
+
});
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
const { rows: updated } = await client.query(
|
|
465
|
+
`UPDATE builders
|
|
466
|
+
SET status = 'inactive', deactivated_at = now(),
|
|
467
|
+
deactivated_reason = $2, reactivated_at = NULL, rank = 'xenos'
|
|
468
|
+
WHERE id = $1
|
|
469
|
+
RETURNING id, github_id, github_login, display_name, avatar_url,
|
|
470
|
+
total_credits, created_at, rank, status,
|
|
471
|
+
deactivated_at, reactivated_at, deactivated_reason`,
|
|
472
|
+
[builderId, reason ?? null]
|
|
473
|
+
);
|
|
474
|
+
// Interim audit (→ audit_log when R36 lands). delta=0 = no-op for credits.
|
|
475
|
+
await client.query(
|
|
476
|
+
`INSERT INTO credit_log (builder_id, task_id, delta, reason)
|
|
477
|
+
VALUES ($1, NULL, 0, $2)`,
|
|
478
|
+
[builderId, `builder_exit: deactivated by builder#${actorBuilderId} (rank ${target.rank}→xenos)`]
|
|
479
|
+
);
|
|
480
|
+
// SECURITY (#871): revoke EVERY live session for the offboarded builder, in
|
|
481
|
+
// the same transaction. Before this, deactivateBuilder set status='inactive'
|
|
482
|
+
// + rank='xenos' via direct SQL (not setBuilderRank, which is the only path
|
|
483
|
+
// that revokes on demotion), so a deactivated/offboarded builder kept working
|
|
484
|
+
// CLI bearer tokens (which don't expire) and could still reach the API. This
|
|
485
|
+
// is the server-side teardown that pairs with the requireBuilder status gate;
|
|
486
|
+
// a genuine return requires re-auth (correct — they were offboarded).
|
|
487
|
+
await client.query(
|
|
488
|
+
`UPDATE builder_sessions SET revoked_at = now()
|
|
489
|
+
WHERE builder_id = $1 AND revoked_at IS NULL`,
|
|
490
|
+
[builderId]
|
|
491
|
+
);
|
|
492
|
+
return { updated, activeClaims };
|
|
493
|
+
});
|
|
494
|
+
// Source-access clawback (ADR 0031 §6 / #600): a deactivated builder loses
|
|
495
|
+
// their box → loses source. Post-commit, own connection, never throws. The
|
|
496
|
+
// builder is now status='inactive' (rank forced to xenos above), so the
|
|
497
|
+
// reconcile resolves to 'deprovision'. Their next /box/source-access fetch is
|
|
498
|
+
// already 403'd (inactive) — this signals the droplet teardown for `box.js
|
|
499
|
+
// reconcile` / the dormant sweep.
|
|
500
|
+
await seams.emitAsync('builder.box-reconcile-needed', {
|
|
501
|
+
builderId, rank: 'xenos', status: 'inactive', actor: `builder-exit:builder#${actorBuilderId}`,
|
|
502
|
+
});
|
|
503
|
+
return {
|
|
504
|
+
builder: updated[0],
|
|
505
|
+
claims_released: activeClaims.map((c) => c.task_id),
|
|
506
|
+
logs_sealed: activeClaims.length,
|
|
507
|
+
};
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
|
|
511
|
+
async function reactivateBuilder({ builderId, actorBuilderId }) {
|
|
512
|
+
return withTx(async (client) => {
|
|
513
|
+
const { rows } = await client.query(
|
|
514
|
+
`SELECT id, status FROM builders WHERE id = $1 FOR UPDATE`,
|
|
515
|
+
[builderId]
|
|
516
|
+
);
|
|
517
|
+
const target = rows[0];
|
|
518
|
+
if (!target) throw { code: 'BUILDER_NOT_FOUND' };
|
|
519
|
+
if (target.status !== 'inactive') throw { code: 'NOT_INACTIVE', status: target.status };
|
|
520
|
+
|
|
521
|
+
const { rows: updated } = await client.query(
|
|
522
|
+
`UPDATE builders
|
|
523
|
+
SET status = 'active', reactivated_at = now()
|
|
524
|
+
WHERE id = $1
|
|
525
|
+
RETURNING id, github_id, github_login, display_name, avatar_url,
|
|
526
|
+
total_credits, created_at, rank, status,
|
|
527
|
+
deactivated_at, reactivated_at, deactivated_reason`,
|
|
528
|
+
[builderId]
|
|
529
|
+
);
|
|
530
|
+
// Rank is intentionally left at whatever it is (xenos after a deactivation):
|
|
531
|
+
// an Archon re-promotes deliberately via PATCH /builders/:id/rank.
|
|
532
|
+
await client.query(
|
|
533
|
+
`INSERT INTO credit_log (builder_id, task_id, delta, reason)
|
|
534
|
+
VALUES ($1, NULL, 0, $2)`,
|
|
535
|
+
[builderId, `builder_exit: reactivated by builder#${actorBuilderId} (rank stays ${updated[0].rank})`]
|
|
536
|
+
);
|
|
537
|
+
return { builder: updated[0] };
|
|
538
|
+
});
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
// -------------------------------------------------------------------------
|
|
542
|
+
// Sessions (auth tokens)
|
|
543
|
+
// -------------------------------------------------------------------------
|
|
544
|
+
//
|
|
545
|
+
// V3.R38 / task #259 — short-lived sessions with refresh-on-use.
|
|
546
|
+
// V3.R90 / task #400 (2026-05-29) — TTL widened from 1h to 24h.
|
|
547
|
+
//
|
|
548
|
+
// * Every NEW session (CLI or web) defaults to a 24-hour TTL. The caller may
|
|
549
|
+
// still pass an explicit expiresAt to override (web flow uses 30 days for
|
|
550
|
+
// the cookie's max-age, but the SERVER-SIDE row still uses 24h + roll-on-use
|
|
551
|
+
// so a logged-out browser tab in someone's history can't be replayed weeks
|
|
552
|
+
// later).
|
|
553
|
+
// * Every successful lookupSession bumps BOTH last_used_at AND expires_at to
|
|
554
|
+
// NOW() + 24h. This is the "refresh-on-use" half: an actively-used session
|
|
555
|
+
// stays valid; an idle session expires after 24h. The bump is fire-and-
|
|
556
|
+
// forget — it's an optimization for the next request, not a precondition
|
|
557
|
+
// for THIS request, so we don't add request latency by awaiting it.
|
|
558
|
+
// * Migration 035 backfilled all pre-existing rows with a 24h grace runway
|
|
559
|
+
// so deploying the V3.R38 change didn't kick the supervisor / mid-flow
|
|
560
|
+
// builders. With the V3.R90 TTL = 24h, the refresh window matches that
|
|
561
|
+
// grace formula exactly — no further migration needed.
|
|
562
|
+
// * The 1h value originally backstopped C7 (rank-change-near-instant), but
|
|
563
|
+
// setBuilderRank already calls revokeAllSessionsForBuilder on every
|
|
564
|
+
// demotion (see below), so the TTL is no longer load-bearing for C7. Its
|
|
565
|
+
// remaining job is idle-session hygiene under C9 (security baseline).
|
|
566
|
+
// 24h still kills idle sessions overnight; an active builder no longer
|
|
567
|
+
// gets kicked out over lunch.
|
|
568
|
+
|
|
569
|
+
// Session TTL on refresh / creation, in milliseconds. Centralized so the
|
|
570
|
+
// migration's grace formula, the test suite, and the code agree on one number.
|
|
571
|
+
|
|
572
|
+
// SESSION_TTL_MS — carved to ./db-kernel (ADR 0102); imported + re-exported above.
|
|
573
|
+
|
|
574
|
+
|
|
575
|
+
// createSession — carved to ./db-kernel (ADR 0102). Re-exported above.
|
|
576
|
+
|
|
577
|
+
// Has this builder ever authenticated the GDS CLI? (#777) True once they've run
|
|
578
|
+
// /builder-setup (or the box-connect bootstrap) — both mint a source='cli'
|
|
579
|
+
// session via the device flow. Revoked/expired sessions still count (rows are
|
|
580
|
+
// marked, never deleted — see revokeAllSessionsForBuilder), so this is a durable
|
|
581
|
+
// "the CLI was signed in at least once" signal. Drives the onboarding checklist's
|
|
582
|
+
// "Run /builder-setup" step (auto-ticks; no manual mark) — purely a display
|
|
583
|
+
// signal, never gates graduation.
|
|
584
|
+
|
|
585
|
+
async function hasCliSession(builderId) {
|
|
586
|
+
if (!Number.isFinite(Number(builderId))) return false;
|
|
587
|
+
const { rows } = await pool.query(
|
|
588
|
+
`SELECT EXISTS (
|
|
589
|
+
SELECT 1 FROM builder_sessions WHERE builder_id = $1 AND source = 'cli'
|
|
590
|
+
) AS has`,
|
|
591
|
+
[builderId]
|
|
592
|
+
);
|
|
593
|
+
return rows[0] ? rows[0].has === true : false;
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
|
|
597
|
+
// lookupSession — carved to ./db-kernel (ADR 0102). Re-exported above.
|
|
598
|
+
|
|
599
|
+
|
|
600
|
+
async function revokeSession(token) {
|
|
601
|
+
await pool.query(
|
|
602
|
+
`UPDATE builder_sessions SET revoked_at = now() WHERE token = $1 AND revoked_at IS NULL`,
|
|
603
|
+
[token]
|
|
604
|
+
);
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
// revokeSessionById — V3.R38 / #259. Kill ONE session by primary key. Returns
|
|
608
|
+
// the number of rows revoked (0 if id didn't exist or was already revoked, 1
|
|
609
|
+
// otherwise). Used by POST /api/gds/auth/revoke (Archon-only).
|
|
610
|
+
|
|
611
|
+
async function revokeSessionById(sessionId) {
|
|
612
|
+
const { rowCount } = await pool.query(
|
|
613
|
+
`UPDATE builder_sessions
|
|
614
|
+
SET revoked_at = now()
|
|
615
|
+
WHERE id = $1 AND revoked_at IS NULL`,
|
|
616
|
+
[sessionId]
|
|
617
|
+
);
|
|
618
|
+
return rowCount;
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
// revokeAllSessionsForBuilder — V3.R38 / #259. Kill EVERY non-revoked session
|
|
622
|
+
// for a single builder. Returns the count of sessions revoked. Used by:
|
|
623
|
+
// * POST /api/gds/auth/revoke-all (Archon-only direct call)
|
|
624
|
+
// * setBuilderRank when newRank < oldRank (rank-change-near-instant per C7)
|
|
625
|
+
|
|
626
|
+
async function revokeAllSessionsForBuilder(builderId) {
|
|
627
|
+
const { rowCount } = await pool.query(
|
|
628
|
+
`UPDATE builder_sessions
|
|
629
|
+
SET revoked_at = now()
|
|
630
|
+
WHERE builder_id = $1 AND revoked_at IS NULL`,
|
|
631
|
+
[builderId]
|
|
632
|
+
);
|
|
633
|
+
return rowCount;
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
// -------------------------------------------------------------------------
|
|
637
|
+
// Versions
|
|
638
|
+
// -------------------------------------------------------------------------
|
|
639
|
+
|
|
640
|
+
|
|
641
|
+
async function recentKarmaForBuilder(builderId, limit = 10) {
|
|
642
|
+
const n = Math.min(Math.max(Number(limit) || 10, 1), 500);
|
|
643
|
+
const { rows } = await pool.query(
|
|
644
|
+
`SELECT k.id, k.delta, k.reason, k.recorded_at,
|
|
645
|
+
k.granted_by,
|
|
646
|
+
gb.github_login AS granted_by_login,
|
|
647
|
+
gb.display_name AS granted_by_display_name
|
|
648
|
+
FROM karma_log k
|
|
649
|
+
LEFT JOIN builders gb ON gb.id = k.granted_by
|
|
650
|
+
WHERE k.builder_id = $1
|
|
651
|
+
ORDER BY k.recorded_at DESC, k.id DESC
|
|
652
|
+
LIMIT $2`,
|
|
653
|
+
[builderId, n]
|
|
654
|
+
);
|
|
655
|
+
return rows;
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
// V3.R26 (#246): rolling 30-day karma delta for this builder. Powers the
|
|
659
|
+
// "karma trend" stat on the /builders profile card — the done-when "30-day
|
|
660
|
+
// delta" criterion. Returns a plain integer (0 when no karma_log rows fall in
|
|
661
|
+
// the window) so the UI can render it directly without null-handling. Cheap
|
|
662
|
+
// single-aggregate query; safe to call alongside the karma feed.
|
|
663
|
+
|
|
664
|
+
async function karmaDelta30d(builderId) {
|
|
665
|
+
const { rows } = await pool.query(
|
|
666
|
+
`SELECT COALESCE(SUM(delta), 0)::int AS delta_30d
|
|
667
|
+
FROM karma_log
|
|
668
|
+
WHERE builder_id = $1
|
|
669
|
+
AND recorded_at >= now() - interval '30 days'`,
|
|
670
|
+
[builderId]
|
|
671
|
+
);
|
|
672
|
+
return rows[0]?.delta_30d ?? 0;
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
// -------------------------------------------------------------------------
|
|
676
|
+
// Discord foundation (Phase 3 F1, ADR 0033)
|
|
677
|
+
// -------------------------------------------------------------------------
|
|
678
|
+
// Account links are 1:1 both ways and exist only because a builder PERSONALLY
|
|
679
|
+
// linked their Discord (F2's UI-first OAuth) — the bot never invents a mapping.
|
|
680
|
+
// Every write the bot later triggers re-checks the linked builder's LIVE rank
|
|
681
|
+
// (ADR 0033 §1). Applause is the cosmetic tier: open to anyone, never karma.
|
|
682
|
+
|
|
683
|
+
// Link a Discord user to a builder. Idempotent for the SAME builder (re-link
|
|
684
|
+
// updates discord_user_id). Returns { ok:true, link } on success, or
|
|
685
|
+
// { ok:false, error:'discord_taken' } if that Discord id is already linked to a
|
|
686
|
+
// DIFFERENT builder (UNIQUE(discord_user_id)) — surfaced so F2's route answers
|
|
687
|
+
// cleanly instead of 500-ing.
|
|
688
|
+
|
|
689
|
+
async function linkDiscord({ builderId, discordUserId }) {
|
|
690
|
+
try {
|
|
691
|
+
const { rows } = await pool.query(
|
|
692
|
+
`INSERT INTO discord_links (builder_id, discord_user_id)
|
|
693
|
+
VALUES ($1, $2)
|
|
694
|
+
ON CONFLICT (builder_id)
|
|
695
|
+
DO UPDATE SET discord_user_id = EXCLUDED.discord_user_id, linked_at = now()
|
|
696
|
+
RETURNING builder_id, discord_user_id, linked_at`,
|
|
697
|
+
[builderId, discordUserId]
|
|
698
|
+
);
|
|
699
|
+
return { ok: true, link: rows[0] };
|
|
700
|
+
} catch (err) {
|
|
701
|
+
if (err.code === '23505') return { ok: false, error: 'discord_taken' }; // unique_violation
|
|
702
|
+
throw err;
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
// Remove a builder's Discord link. Returns true if a row was deleted.
|
|
707
|
+
|
|
708
|
+
async function unlinkDiscord(builderId) {
|
|
709
|
+
const { rowCount } = await pool.query(
|
|
710
|
+
`DELETE FROM discord_links WHERE builder_id = $1`,
|
|
711
|
+
[builderId]
|
|
712
|
+
);
|
|
713
|
+
return rowCount > 0;
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
// The Discord link for a builder (so the hall can show "linked as ..." + an
|
|
717
|
+
// Unlink affordance), or null.
|
|
718
|
+
|
|
719
|
+
async function getDiscordLink(builderId) {
|
|
720
|
+
const { rows } = await pool.query(
|
|
721
|
+
`SELECT builder_id, discord_user_id, linked_at FROM discord_links WHERE builder_id = $1`,
|
|
722
|
+
[builderId]
|
|
723
|
+
);
|
|
724
|
+
return rows[0] || null;
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
// Record one cosmetic applause (a Discord user reacted on a shipped task).
|
|
728
|
+
// NEVER writes karma_log — that separation is load-bearing (ADR 0033 §3).
|
|
729
|
+
// Re-reacting is a harmless no-op. Returns { counted } — true if new, false if
|
|
730
|
+
// this user had already applauded this task.
|
|
731
|
+
|
|
732
|
+
async function recordApplause({ targetTaskId, discordUserId }) {
|
|
733
|
+
const { rowCount } = await pool.query(
|
|
734
|
+
`INSERT INTO discord_applause (target_task_id, discord_user_id)
|
|
735
|
+
VALUES ($1, $2)
|
|
736
|
+
ON CONFLICT (target_task_id, discord_user_id) DO NOTHING`,
|
|
737
|
+
[targetTaskId, discordUserId]
|
|
738
|
+
);
|
|
739
|
+
return { counted: rowCount > 0 };
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
|
|
743
|
+
// -------------------------------------------------------------------------
|
|
744
|
+
// Task grades (PMS-V2 task 197)
|
|
745
|
+
// -------------------------------------------------------------------------
|
|
746
|
+
|
|
747
|
+
// Last N grades for tasks shipped by this builder (passed=true OR false —
|
|
748
|
+
// the failed grades are interesting too).
|
|
749
|
+
//
|
|
750
|
+
// V3.R18 (#209): rubric_scores + signals.issues are now part of the response
|
|
751
|
+
// so /me can surface the v2 subagent's failure detail (functional_fidelity vs
|
|
752
|
+
// code_quality + the issues array) without a follow-up call.
|
|
753
|
+
|
|
754
|
+
// builderRollingAvgGrade RELOCATED to modules/grading/db.js (ADR 0102) — the
|
|
755
|
+
// grade-TREND read behind the 'grade.builderRollingAvgGrade' port (core me.js +
|
|
756
|
+
// the sessions BFG resolve it; degrades to a zero-grade shape when grading is off).
|
|
757
|
+
|
|
758
|
+
// Per-builder grade breakdown over the last `days` days. Powers the MARKS
|
|
759
|
+
// section of the Archon-only /watch page (#726) — "who is passing / failing
|
|
760
|
+
// the grader". One row per builder who has at least one graded ship in the
|
|
761
|
+
// window, joined through tasks.shipped_by. avg_score 0–10, pass_rate 0–1.
|
|
762
|
+
|
|
763
|
+
async function listAuditLog({ limit = 100, offset = 0, builderId, method, surface } = {}) {
|
|
764
|
+
const where = [];
|
|
765
|
+
const params = [];
|
|
766
|
+
if (builderId) {
|
|
767
|
+
params.push(builderId);
|
|
768
|
+
where.push(`builder_id = $${params.length}`);
|
|
769
|
+
}
|
|
770
|
+
if (method) {
|
|
771
|
+
params.push(method);
|
|
772
|
+
where.push(`method = $${params.length}`);
|
|
773
|
+
}
|
|
774
|
+
if (surface) {
|
|
775
|
+
if (surface === 'none') {
|
|
776
|
+
where.push(`surface IS NULL`);
|
|
777
|
+
} else {
|
|
778
|
+
params.push(surface);
|
|
779
|
+
where.push(`surface = $${params.length}`);
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
const whereSql = where.length ? `WHERE ${where.join(' AND ')}` : '';
|
|
783
|
+
params.push(limit);
|
|
784
|
+
const limitParam = `$${params.length}`;
|
|
785
|
+
params.push(offset);
|
|
786
|
+
const offsetParam = `$${params.length}`;
|
|
787
|
+
const { rows } = await pool.query(
|
|
788
|
+
`SELECT id, builder_id, route, method, request_body_redacted,
|
|
789
|
+
response_status, ip, user_agent, surface, recorded_at
|
|
790
|
+
FROM audit_log
|
|
791
|
+
${whereSql}
|
|
792
|
+
ORDER BY recorded_at DESC, id DESC
|
|
793
|
+
LIMIT ${limitParam} OFFSET ${offsetParam}`,
|
|
794
|
+
params
|
|
795
|
+
);
|
|
796
|
+
return rows;
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
// -------------------------------------------------------------------------
|
|
800
|
+
// Session records (BFG session-inefficiency evaluator — 6D.1/6D.2, ADR 0027)
|
|
801
|
+
// CARVED into modules/sessions/db.js (BV1.R82 / ADR 0093 §1): the
|
|
802
|
+
// session_records data plane (upsertSessionRecord[WithReward], searchSessions,
|
|
803
|
+
// summarizeSessions, getSessionById, listSessionsByBuilder, filterTaskIdsClaimedBy,
|
|
804
|
+
// the order/limit/offset helpers + the shared filter clause) is now module-owned.
|
|
805
|
+
// upsertSessionRecordWithReward resolves the economy `reward` kernel port inside
|
|
806
|
+
// its own withTx; no core file calls these (the ship-time digest write is an HTTP
|
|
807
|
+
// POST to the module's /sessions route). sumCreditsForTasks() left for
|
|
808
|
+
// modules/economy/ at BV1.R77.
|
|
809
|
+
// -------------------------------------------------------------------------
|
|
810
|
+
|
|
811
|
+
// ---- 6D.6: grade-attempt log (ADR 0027) ----------------------------------
|
|
812
|
+
|
|
813
|
+
// logGradeAttempt — append one grade ATTEMPT to grade_attempts (migration 064).
|
|
814
|
+
// task_grades is upsert-unique (latest grade only), so this is the ONLY record
|
|
815
|
+
// of re-grade thrash. BEST-EFFORT: it swallows its own errors and returns a
|
|
816
|
+
// boolean — callers (db.applyGrade, post-commit) can never be broken by it. The
|
|
817
|
+
// queryFn seam lets the unit test inject a throwing/recording stub (mirrors the
|
|
818
|
+
// audit middleware's insertFn pattern).
|
|
819
|
+
|
|
820
|
+
async function upsertSecurityDoc({ slug, title, contentMd }) {
|
|
821
|
+
const { rows } = await pool.query(
|
|
822
|
+
`INSERT INTO security_docs (slug, title, content_md)
|
|
823
|
+
VALUES ($1, $2, $3)
|
|
824
|
+
ON CONFLICT (slug) DO UPDATE
|
|
825
|
+
SET title = EXCLUDED.title,
|
|
826
|
+
content_md = EXCLUDED.content_md,
|
|
827
|
+
updated_at = now()
|
|
828
|
+
RETURNING id, slug, title, content_md, created_at, updated_at`,
|
|
829
|
+
[slug, title, contentMd]
|
|
830
|
+
);
|
|
831
|
+
return rows[0];
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
// Fetch one doc (with content) by slug. Returns the row or null.
|
|
835
|
+
|
|
836
|
+
async function getSecurityDoc(slug) {
|
|
837
|
+
const { rows } = await pool.query(
|
|
838
|
+
`SELECT id, slug, title, content_md, created_at, updated_at
|
|
839
|
+
FROM security_docs WHERE slug = $1`,
|
|
840
|
+
[slug]
|
|
841
|
+
);
|
|
842
|
+
return rows[0] ?? null;
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
// List doc METADATA — slug, title, updated_at, and the content size in chars
|
|
846
|
+
// (char_length) — but NOT the content itself, so the list view never ships the
|
|
847
|
+
// exploit bodies. Newest-updated first.
|
|
848
|
+
|
|
849
|
+
async function listSecurityDocs() {
|
|
850
|
+
const { rows } = await pool.query(
|
|
851
|
+
`SELECT slug, title, updated_at, char_length(content_md) AS bytes
|
|
852
|
+
FROM security_docs
|
|
853
|
+
ORDER BY updated_at DESC, slug ASC`
|
|
854
|
+
);
|
|
855
|
+
return rows;
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
// ---------- server-side merge lease (task 585 / idea 124) ----------
|
|
859
|
+
//
|
|
860
|
+
// merge-lock.js serializes main-mutating merges within ONE machine (a filesystem lock). When
|
|
861
|
+
// builders ship from DIFFERENT physical machines — each with its own checkout of main — a file
|
|
862
|
+
// lock can't see across machines. This is the cross-machine counterpart: a TTL'd advisory lease
|
|
863
|
+
// keyed on the merge target (default 'main'), handed out by the GDS API at merge time. Plain SQL,
|
|
864
|
+
// NOT a session-scoped pg_advisory_lock (a pooled connection can't hold one across a builder's
|
|
865
|
+
// local merge); a dead holder's lease auto-reclaims once expires_at passes. See
|
|
866
|
+
// docs/recipes/multi-builder-merge.md and merge-lock.js (the intra-machine tier) — and
|
|
867
|
+
// merge-lock.withServerMergeLease(), the composition helper a multi-machine ship wraps around it.
|
|
868
|
+
|
|
869
|
+
// Atomically acquire OR renew the lease. Returns { acquired, holder, expires_at }; acquired=false
|
|
870
|
+
// (with the current holder/expiry) means another holder owns an unexpired lease.
|
|
871
|
+
// SECURITY (for the future route that wraps this): `holder` MUST be set server-side from the
|
|
872
|
+
// authenticated builder's identity, never a client-supplied value — otherwise a builder could
|
|
873
|
+
// forge a lease under another builder's name (or release theirs). holder is intentionally free
|
|
874
|
+
// text (a machine/session label), not an FK, so the route owns that binding.
|
|
875
|
+
|
|
876
|
+
module.exports = {
|
|
877
|
+
withTx,
|
|
878
|
+
upsertBuilder,
|
|
879
|
+
seatFirstAdminIfUnclaimed,
|
|
880
|
+
getBuilderById,
|
|
881
|
+
listActiveBuilders,
|
|
882
|
+
linkAnthropicAccount,
|
|
883
|
+
getBuilderByGithubId,
|
|
884
|
+
hasInvitedAccessRequest,
|
|
885
|
+
updateBuilderDisciplines,
|
|
886
|
+
RANKS,
|
|
887
|
+
setBuilderRank,
|
|
888
|
+
getLatestRankChangeForBuilder,
|
|
889
|
+
deactivateBuilder,
|
|
890
|
+
reactivateBuilder,
|
|
891
|
+
createSession,
|
|
892
|
+
lookupSession,
|
|
893
|
+
revokeSession,
|
|
894
|
+
revokeSessionById,
|
|
895
|
+
revokeAllSessionsForBuilder,
|
|
896
|
+
hasCliSession,
|
|
897
|
+
SESSION_TTL_MS,
|
|
898
|
+
LIVE_RANK_LADDER,
|
|
899
|
+
singleRungPromotionError,
|
|
900
|
+
recentKarmaForBuilder,
|
|
901
|
+
karmaDelta30d,
|
|
902
|
+
insertAuditLog,
|
|
903
|
+
listAuditLog,
|
|
904
|
+
linkDiscord,
|
|
905
|
+
unlinkDiscord,
|
|
906
|
+
getDiscordLink,
|
|
907
|
+
recordApplause,
|
|
908
|
+
upsertSecurityDoc,
|
|
909
|
+
getSecurityDoc,
|
|
910
|
+
listSecurityDocs,
|
|
911
|
+
};
|