@bongos/core 1.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.bongos-core.json +5727 -0
- package/.claude/skills/blocker-review/SKILL.md +91 -0
- package/.claude/skills/blocker-solve/SKILL.md +96 -0
- package/.claude/skills/builder-backup/SKILL.md +54 -0
- package/.claude/skills/builder-box/SKILL.md +45 -0
- package/.claude/skills/builder-claim/SKILL.md +76 -0
- package/.claude/skills/builder-connect/SKILL.md +59 -0
- package/.claude/skills/builder-cost/SKILL.md +47 -0
- package/.claude/skills/builder-end/SKILL.md +81 -0
- package/.claude/skills/builder-exit/SKILL.md +88 -0
- package/.claude/skills/builder-key/SKILL.md +40 -0
- package/.claude/skills/builder-reauth/SKILL.md +50 -0
- package/.claude/skills/builder-redteam/SKILL.md +109 -0
- package/.claude/skills/builder-release/SKILL.md +41 -0
- package/.claude/skills/builder-setup/SKILL.md +62 -0
- package/.claude/skills/builder-ship/SKILL.md +79 -0
- package/.claude/skills/builder-stage/SKILL.md +51 -0
- package/.claude/skills/builder-start/SKILL.md +46 -0
- package/.claude/skills/close-box/SKILL.md +43 -0
- package/.claude/skills/design-sync/SKILL.md +69 -0
- package/.claude/skills/dev/SKILL.md +49 -0
- package/.claude/skills/feedback/SKILL.md +32 -0
- package/.claude/skills/figma-design-sync/SKILL.md +74 -0
- package/.claude/skills/goal-review/SKILL.md +89 -0
- package/.claude/skills/idea-triage/SKILL.md +144 -0
- package/.claude/skills/ideate/SKILL.md +82 -0
- package/.claude/skills/merge-mode/SKILL.md +169 -0
- package/.claude/skills/new-project/SKILL.md +108 -0
- package/.claude/skills/otb-character-review/SKILL.md +71 -0
- package/.claude/skills/otb-design-review/SKILL.md +47 -0
- package/.claude/skills/otb-feedback-capture/SKILL.md +45 -0
- package/.claude/skills/otb-figma-sync/SKILL.md +54 -0
- package/.claude/skills/otb-tile-generate/SKILL.md +45 -0
- package/.claude/skills/paint/SKILL.md +70 -0
- package/.claude/skills/planning-session/SKILL.md +299 -0
- package/.claude/skills/priority-session/SKILL.md +134 -0
- package/.claude/skills/read-session-export/SKILL.md +58 -0
- package/.claude/skills/recall/SKILL.md +52 -0
- package/.claude/skills/session-handoff/SKILL.md +46 -0
- package/.claude/skills/status/SKILL.md +33 -0
- package/.devcontainer/Dockerfile +69 -0
- package/.devcontainer/README.md +73 -0
- package/.devcontainer/devcontainer-lock.json +19 -0
- package/.devcontainer/devcontainer.json +93 -0
- package/.devcontainer/healthcheck.sh +84 -0
- package/.devcontainer/init-firewall.sh +198 -0
- package/.devcontainer/post-create.sh +153 -0
- package/.dockerignore +36 -0
- package/.env.local.example +32 -0
- package/.gitattributes +83 -0
- package/.gitignore +91 -0
- package/CLAUDE.md +242 -0
- package/CODE_OF_CONDUCT.md +46 -0
- package/CONTRIBUTING.md +51 -0
- package/Dockerfile +46 -0
- package/GOVERNANCE.md +44 -0
- package/LICENSE +661 -0
- package/README.md +88 -0
- package/bin/bongos.js +222 -0
- package/clients/bongos-client/README.md +48 -0
- package/clients/bongos-client/bongos-client.global.js +617 -0
- package/clients/bongos-client/examples/hello-world.mjs +62 -0
- package/clients/bongos-client/index.cjs +619 -0
- package/clients/bongos-client/index.d.ts +793 -0
- package/clients/bongos-client/index.mjs +614 -0
- package/clients/bongos-client/package.json +32 -0
- package/config/branding.neutral.json +60 -0
- package/config/design-tokens.neutral.json +51 -0
- package/config/design-tokens.schema.json +96 -0
- package/config/modules.neutral.json +9 -0
- package/docker-compose.yml +52 -0
- package/docker-entrypoint.sh +30 -0
- package/docs/adr/0001-stack-choice-single-vps.md +45 -0
- package/docs/adr/0002-digitalocean-over-hetzner.md +27 -0
- package/docs/adr/0003-cloudflare-origin-cert-over-letsencrypt.md +35 -0
- package/docs/adr/0004-amazonprimea-name-and-trademark-acceptance.md +45 -0
- package/docs/adr/0005-invisible-other-players-in-v1.md +37 -0
- package/docs/adr/0006-singleton-worldroom-plus-queueroom.md +30 -0
- package/docs/adr/0007-persistent-identity-via-localstorage-uuid.md +31 -0
- package/docs/adr/0008-family-based-tile-generation.md +86 -0
- package/docs/adr/0008-google-chat-oauth-user-auth.md +37 -0
- package/docs/adr/0009-autotile-architecture.md +181 -0
- package/docs/adr/0010-pms-architecture.md +70 -0
- package/docs/adr/0011-terrain-id-rendering-model.md +174 -0
- package/docs/adr/0012-ground-object-cell-split.md +208 -0
- package/docs/adr/0013-paths-as-object-overlays-with-autotile-dispatch.md +158 -0
- package/docs/adr/0014-families-canonical-over-vocabulary.md +103 -0
- package/docs/adr/0015-task-dependencies-and-auto-promotion.md +125 -0
- package/docs/adr/0016-trust-boundary-server-enforced-permissions.md +132 -0
- package/docs/adr/0017-code-simplification-and-repo-cleanliness.md +74 -0
- package/docs/adr/0018-three-rank-model-goes-live.md +97 -0
- package/docs/adr/0019-red-team-bounty-payout-table.md +52 -0
- package/docs/adr/0020-security-model-public-stub.md +70 -0
- package/docs/adr/0021-per-builder-skill-model-preferences.md +99 -0
- package/docs/adr/0022-secrets-policy.md +124 -0
- package/docs/adr/0023-kind-multipliers-and-idea-bonus.md +118 -0
- package/docs/adr/0024-cloneable-repo-local-first-memory.md +277 -0
- package/docs/adr/0024-multi-agent-system-architecture.md +125 -0
- package/docs/adr/0025-offsite-backup-vendor-digitalocean-spaces.md +59 -0
- package/docs/adr/0025-structured-criterion-task-link.md +44 -0
- package/docs/adr/0026-bfg-memory-hygiene-and-cross-builder-learning.md +117 -0
- package/docs/adr/0027-bfg-session-inefficiency-evaluator.md +170 -0
- package/docs/adr/0028-honest-llm-spend-accounting.md +109 -0
- package/docs/adr/0029-status-page-outage-resilience.md +59 -0
- package/docs/adr/0030-builders-hall-live-updates.md +59 -0
- package/docs/adr/0031-cloud-dev-environments-for-builders.md +222 -0
- package/docs/adr/0032-discord-mirror-of-gds.md +50 -0
- package/docs/adr/0033-discord-bot-service-principal.md +82 -0
- package/docs/adr/0034-thetes-graduated-newcomer-rank.md +53 -0
- package/docs/adr/0035-builder-onboarding-three-paths.md +128 -0
- package/docs/adr/0036-builders-subdomain-and-ui-reorg.md +40 -0
- package/docs/adr/0037-discord-channel-management.md +51 -0
- package/docs/adr/0038-chromebook-ttyd-cloudflare-tunnel.md +111 -0
- package/docs/adr/0039-setup-first-onboarding-ux.md +49 -0
- package/docs/adr/0040-remote-control-default-browser-onramp.md +47 -0
- package/docs/adr/0041-temporary-grader-bypass-killswitch.md +40 -0
- package/docs/adr/0042-builder-self-deploy-ci-auto-merge.md +82 -0
- package/docs/adr/0043-git-ssh-trust-boundary-and-rank-floor-on-permission-paths.md +74 -0
- package/docs/adr/0044-mediterranean-palette-replacement.md +73 -0
- package/docs/adr/0044-per-box-live-game-preview.md +57 -0
- package/docs/adr/0045-devbox-desktop-app.md +133 -0
- package/docs/adr/0046-sandbox-first-review-gate.md +72 -0
- package/docs/adr/0047-discord-bugs-intake-anti-abuse.md +36 -0
- package/docs/adr/0048-works-in-progress-ia-split.md +32 -0
- package/docs/adr/0049-split-parallel-safety-contract.md +46 -0
- package/docs/adr/0050-device-flow-admission-invite-gated-by-default.md +43 -0
- package/docs/adr/0051-full-session-transcript-corpus.md +57 -0
- package/docs/adr/0052-sandbox-for-everyone-game-only-preview.md +70 -0
- package/docs/adr/0053-scoped-dev-box-session.md +55 -0
- package/docs/adr/0054-session-token-reward-cost-plus.md +63 -0
- package/docs/adr/0055-server-mediated-branch-publish.md +47 -0
- package/docs/adr/0056-prod-deploy-script-mirror-and-healthcheck-retry.md +62 -0
- package/docs/adr/0057-container-cost-ledger.md +28 -0
- package/docs/adr/0057-discord-archon-approval-channels.md +64 -0
- package/docs/adr/0058-automatic-gate-surface-gatekeeper.md +64 -0
- package/docs/adr/0059-single-approval-remove-devbox-approval-gate.md +37 -0
- package/docs/adr/0060-gds-retrieval-layer.md +97 -0
- package/docs/adr/0061-context-layer-decomposition.md +61 -0
- package/docs/adr/0062-medusa-instance-model-decoupling.md +107 -0
- package/docs/adr/0063-generated-repo-map-symbol-skeleton.md +44 -0
- package/docs/adr/0064-rename-medusa-to-cloud-bongos.md +49 -0
- package/docs/adr/0065-agpl-nonprofit-ai-first-governance.md +69 -0
- package/docs/adr/0066-generated-file-map-sections.md +51 -0
- package/docs/adr/0067-session-start-fast-forward-pull.md +43 -0
- package/docs/adr/0068-shared-art-key-for-newcomers.md +38 -0
- package/docs/adr/0069-hall-live-channel-sse-decouple.md +35 -0
- package/docs/adr/0070-deterministic-session-card-delivery.md +44 -0
- package/docs/adr/0071-box-confirm-before-destroyed-and-drift-reconcile.md +59 -0
- package/docs/adr/0072-bongos-app-mac-signed-first-windows-deferred.md +35 -0
- package/docs/adr/0072-dev-box-code-staleness-visibility.md +39 -0
- package/docs/adr/0073-builder-needs-signal-and-byok-gemini-key.md +64 -0
- package/docs/adr/0073-secrets-scan-exclude-uri-detector.md +37 -0
- package/docs/adr/0074-memory-map-stays-light.md +32 -0
- package/docs/adr/0075-per-system-cost-attribution.md +37 -0
- package/docs/adr/0076-in-session-deterministic-compaction.md +58 -0
- package/docs/adr/0077-content-addressed-llm-cache.md +32 -0
- package/docs/adr/0078-deterministic-first-cron.md +48 -0
- package/docs/adr/0079-value-gated-autonomous-engagement.md +39 -0
- package/docs/adr/0080-llm-cache-api-transport-and-trust-model.md +46 -0
- package/docs/adr/0081-tool-agnostic-design-layer.md +62 -0
- package/docs/adr/0082-productized-key-storage-provisioning.md +32 -0
- package/docs/adr/0082-server-side-merge-conflict-auto-resolution.md +55 -0
- package/docs/adr/0083-modular-architecture-strangler-build-plan.md +143 -0
- package/docs/adr/0084-auto-derived-per-task-rank-floor.md +86 -0
- package/docs/adr/0085-remove-default-per-builder-spend-cap.md +39 -0
- package/docs/adr/0086-goal-scoped-work-hierarchy.md +123 -0
- package/docs/adr/0087-bongos-app-architecture-and-handoff-contract.md +49 -0
- package/docs/adr/0087-compete-on-governance-not-tooling-cursor.md +65 -0
- package/docs/adr/0088-consistent-character-generative-animation.md +169 -0
- package/docs/adr/0089-modular-multi-model-adversarial-grader.md +179 -0
- package/docs/adr/0090-metic-task-authoring.md +73 -0
- package/docs/adr/0091-bounding-the-kernel-and-db-carve.md +106 -0
- package/docs/adr/0092-hosting-module-and-on-prem-target.md +117 -0
- package/docs/adr/0093-tranche-2-core-carve-sequence.md +72 -0
- package/docs/adr/0094-repo-atlas-self-drawing-codebase-map.md +49 -0
- package/docs/adr/0095-borrowed-memory-and-retrieval-concepts.md +65 -0
- package/docs/adr/0095-cross-agent-context-management.md +58 -0
- package/docs/adr/0096-require-reward-before-workable.md +209 -0
- package/docs/adr/0097-one-active-claim-per-session-and-worktree-binding.md +46 -0
- package/docs/adr/0097-retroactive-reward-backfill.md +124 -0
- package/docs/adr/0098-public-mirror-publish-manifest.md +92 -0
- package/docs/adr/0099-delayed-redacted-mirror-export.md +55 -0
- package/docs/adr/0100-two-repo-instance-model.md +60 -0
- package/docs/adr/0101-goal-hierarchy-phase-5-judge-membership-reward.md +90 -0
- package/docs/adr/0102-finish-bounding-the-kernel.md +36 -0
- package/docs/adr/0103-core-first-extraction-cloud-bongos-trunk.md +70 -0
- package/docs/adr/0103-gdsv4-bongos-consolidation.md +28 -0
- package/docs/adr/0104-trust-gds-api-channel-in-auto-mode.md +42 -0
- package/docs/adr/0105-instance-seed-migrations-out-of-core.md +47 -0
- package/docs/adr/0106-goal-owner-manager-authority.md +84 -0
- package/docs/adr/0107-module-upstreaming-contribution-to-core-catalog.md +83 -0
- package/docs/adr/0108-instance-composition-configurable-root.md +87 -0
- package/docs/adr/0109-self-describing-openapi-and-hosted-docs.md +44 -0
- package/docs/adr/0110-untrack-whole-file-generated-nav-docs.md +49 -0
- package/docs/adr/0111-instance-hosting-provisioning-module.md +135 -0
- package/docs/adr/0112-private-goals-invitations-join-requests.md +72 -0
- package/docs/adr/0113-sandbox-studio-descope-superseded-by-0044-0052.md +41 -0
- package/docs/adr/0114-instance-docs-discovery-contract.md +32 -0
- package/docs/adr/0115-scheduled-routines-portability.md +31 -0
- package/docs/adr/0116-api-error-envelope-and-code-taxonomy.md +62 -0
- package/docs/adr/0117-api-versioning-and-deprecation-policy.md +50 -0
- package/docs/adr/0118-api-contract-source-of-truth-code-first.md +47 -0
- package/docs/adr/0119-api-pagination-contract.md +34 -0
- package/docs/adr/0120-pay-on-land-and-builder-owned-rebase-gate.md +108 -0
- package/docs/adr/0121-greenfield-vs-brownfield-onboarding-adopt-existing-repo.md +97 -0
- package/docs/adr/0122-onboarding-diagram-renders-deploy-rendered-off-git.md +43 -0
- package/docs/adr/0123-box-idle-sweep-autosave-before-destroy.md +36 -0
- package/docs/adr/0124-typed-api-response-bodies.md +37 -0
- package/docs/adr/0125-control-plane-scaffolds-standalone-instance-repo.md +36 -0
- package/docs/adr/0126-dedicated-cloudbongos-control-plane-droplet.md +30 -0
- package/docs/adr/0127-cross-box-fleet-observability.md +64 -0
- package/docs/adr/0128-provisioning-runner-privilege-and-db-auth-model.md +46 -0
- package/docs/adr/0129-cloudbongos-control-plane-pull-deploy.md +34 -0
- package/docs/adr/0130-provision-remote-exec-over-ssh.md +61 -0
- package/docs/adr/0131-rank-scoped-skill-visibility.md +47 -0
- package/docs/adr/0132-cohost-fleet-control-plane-migration.md +54 -0
- package/docs/adr/0133-github-app-manifest-onboarding-signin.md +42 -0
- package/docs/adr/0134-private-first-npm-distribution.md +38 -0
- package/docs/adr/README.md +208 -0
- package/docs/api/openapi.json +13720 -0
- package/docs/api-reference.md +437 -0
- package/docs/architecture.md +244 -0
- package/docs/branding-contract.md +66 -0
- package/docs/branding-fill-prompt.md +25 -0
- package/docs/canonical-permissions.md +241 -0
- package/docs/design/container-exterior-tiles.md +49 -0
- package/docs/design/container-exterior.md +81 -0
- package/docs/design/container-interior.md +77 -0
- package/docs/design/modular-architecture/00-research-report.md +107 -0
- package/docs/design/modular-architecture/01-architecture.md +125 -0
- package/docs/design/modular-architecture/02-module-map.md +116 -0
- package/docs/design/modular-architecture/03-builder-flows.md +104 -0
- package/docs/design/modular-architecture/04-module-lifecycle.md +62 -0
- package/docs/design/modular-architecture/README.md +27 -0
- package/docs/design/vanilla-hall-ui-redesign-scope.md +284 -0
- package/docs/design/world-map-scroll.md +41 -0
- package/docs/design-contract.md +320 -0
- package/docs/file-map.md +418 -0
- package/docs/handoff-template.md +92 -0
- package/docs/modules-contract.md +293 -0
- package/docs/onboarding/browser-terminal-guide.md +73 -0
- package/docs/onboarding/diagrams/01-task-lifecycle.mmd +28 -0
- package/docs/onboarding/diagrams/02-rank-ladder.mmd +54 -0
- package/docs/onboarding/diagrams/03-drachmae-karma.mmd +37 -0
- package/docs/onboarding/diagrams/04-architecture.mmd +51 -0
- package/docs/onboarding/diagrams/05-versioning.mmd +29 -0
- package/docs/onboarding/diagrams/README.md +94 -0
- package/docs/onboarding/diagrams/assertions.json +170 -0
- package/docs/onboarding/diagrams/puppeteer-config.json +1 -0
- package/docs/onboarding/diagrams/render-config.json +9 -0
- package/docs/onboarding/drachmae-and-karma.md +178 -0
- package/docs/onboarding/primer.md +202 -0
- package/docs/project-context.template.md +67 -0
- package/docs/recipes/README.md +35 -0
- package/docs/recipes/audit-replay.md +100 -0
- package/docs/recipes/bongos-cli-release.md +66 -0
- package/docs/recipes/builder-box-lifecycle.md +152 -0
- package/docs/recipes/claude-design-loop.md +143 -0
- package/docs/recipes/claude-gemini-bongos-doors.md +155 -0
- package/docs/recipes/cloudbongos-staging-gate.md +139 -0
- package/docs/recipes/cloudbongos-standup.md +111 -0
- package/docs/recipes/devbox-app-release.md +93 -0
- package/docs/recipes/devbox-app-windows-test.md +128 -0
- package/docs/recipes/failed-ship-recovery-proof.md +102 -0
- package/docs/recipes/figma-design-loop.md +129 -0
- package/docs/recipes/gds-db-backup.md +255 -0
- package/docs/recipes/instance-deploy.md +37 -0
- package/docs/recipes/managed-settings-remote-control.md +416 -0
- package/docs/recipes/memory-backup.md +71 -0
- package/docs/recipes/memory-sync-conflicts.md +98 -0
- package/docs/recipes/multi-builder-merge.md +78 -0
- package/docs/recipes/ops-gotchas.md +212 -0
- package/docs/recipes/overnight-builder.md +53 -0
- package/docs/recipes/packaging-the-core.md +49 -0
- package/docs/recipes/parallel-load-results-2026-05-30.md +63 -0
- package/docs/recipes/parallel-load-test.md +32 -0
- package/docs/recipes/pixel-art-pipeline.md +411 -0
- package/docs/recipes/private-npm-distribution.md +79 -0
- package/docs/recipes/search-index-ingestion.md +67 -0
- package/docs/recipes/self-host.md +60 -0
- package/docs/recipes/ship-and-regrade.md +72 -0
- package/docs/recipes/staging-data.md +50 -0
- package/docs/recipes/staging-environment.md +215 -0
- package/docs/recipes/upgrading-the-core.md +58 -0
- package/docs/research/cursor-competitive-analysis.md +255 -0
- package/docs/research/llm-model-agnostic-and-cheaper-grader.md +227 -0
- package/migrations/003_pms.sql +284 -0
- package/migrations/004_pms_cost_idempotency.sql +13 -0
- package/migrations/005_pms_smoke_filter.sql +44 -0
- package/migrations/006_pms_v2.sql +378 -0
- package/migrations/007_pms_v2_hierarchy_trigger.sql +59 -0
- package/migrations/008_pms_v2_migration_allocator.sql +27 -0
- package/migrations/009_pms_v2_blockers_table.sql +68 -0
- package/migrations/010_uptime.sql +29 -0
- package/migrations/011_backfill_v2_v3_done_when.sql +20 -0
- package/migrations/012_pms_v2_task_lifecycle_states.sql +82 -0
- package/migrations/013_claim_locking.sql +22 -0
- package/migrations/014_pms_task_discipline.sql +86 -0
- package/migrations/015_pms_estimation_calibration.sql +140 -0
- package/migrations/016_pms_task_grades.sql +60 -0
- package/migrations/017_version_progress_exclude_abandoned.sql +49 -0
- package/migrations/019_rename_pms_v3_to_gds_v3.sql +65 -0
- package/migrations/020_task_dependencies.sql +99 -0
- package/migrations/021_v3_renumber_and_deps.sql +224 -0
- package/migrations/022_v3_reconcile_dep_gated_status.sql +41 -0
- package/migrations/023_pms_rank.sql +30 -0
- package/migrations/025_builder_exit_status.sql +15 -0
- package/migrations/027_builders_preferred_disciplines.sql +46 -0
- package/migrations/028_tasks_parallel_safe.sql +71 -0
- package/migrations/029_rank_three_live.sql +32 -0
- package/migrations/030_vulnerability_reports.sql +61 -0
- package/migrations/031_reward_simplification.sql +57 -0
- package/migrations/032_repo_health_snapshots.sql +56 -0
- package/migrations/033_audit_log.sql +64 -0
- package/migrations/034_lifecycle_breakdown_leaf_only.sql +62 -0
- package/migrations/035_auth_token_hygiene.sql +66 -0
- package/migrations/037_builder_skill_model_prefs.sql +44 -0
- package/migrations/038_task_override_requests.sql +51 -0
- package/migrations/039_newcomer_friendly_column.sql +124 -0
- package/migrations/040_builder_karma.sql +58 -0
- package/migrations/041_kind_multipliers_and_idea_bonus.sql +42 -0
- package/migrations/042_criterion_proposal_workflow.sql +78 -0
- package/migrations/043_builder_onboarding_observability.sql +66 -0
- package/migrations/044_tasks_requires_rank.sql +97 -0
- package/migrations/045_builder_onboarding_state.sql +147 -0
- package/migrations/046_cost_log_builder_attribution.sql +42 -0
- package/migrations/054_builder_memory.sql +108 -0
- package/migrations/055_task_criteria.sql +90 -0
- package/migrations/058_peer_votes.sql +41 -0
- package/migrations/059_onboarding_pick_disciplines.sql +59 -0
- package/migrations/060_access_requests.sql +46 -0
- package/migrations/061_backfill_override_ship_attribution.sql +29 -0
- package/migrations/062_session_records.sql +34 -0
- package/migrations/063_session_records_tool_errors_idx.sql +11 -0
- package/migrations/064_grade_attempts.sql +18 -0
- package/migrations/065_bfg_principal.sql +58 -0
- package/migrations/066_live_notify_triggers.sql +69 -0
- package/migrations/067_builder_boxes.sql +117 -0
- package/migrations/067_discord_bot_foundation.sql +69 -0
- package/migrations/068_thetes_requires_rank.sql +27 -0
- package/migrations/069_builder_ssh_keys.sql +66 -0
- package/migrations/070_box_intents.sql +101 -0
- package/migrations/071_box_first_provision_approval.sql +46 -0
- package/migrations/072_onboarding_ship_three_remove_primer.sql +80 -0
- package/migrations/073_box_terminal_access.sql +46 -0
- package/migrations/075_builder_sound_prefs.sql +28 -0
- package/migrations/078_box_claude_active.sql +22 -0
- package/migrations/079_box_first_connected_at.sql +20 -0
- package/migrations/081_tasks_needs_migration.sql +34 -0
- package/migrations/084_tasks_security_sensitive.sql +24 -0
- package/migrations/085_security_engagement_docs.sql +34 -0
- package/migrations/086_rename_disciplines.sql +125 -0
- package/migrations/088_builders_anthropic_link.sql +28 -0
- package/migrations/089_builders_monthly_budget.sql +19 -0
- package/migrations/090_box_scoped_sessions.sql +38 -0
- package/migrations/091_session_token_reward.sql +44 -0
- package/migrations/093_tasks_sandbox_review.sql +22 -0
- package/migrations/102_remove_box_first_provision_approval.sql +58 -0
- package/migrations/103_search_chunks.sql +90 -0
- package/migrations/104_builder_box_blocked.sql +34 -0
- package/migrations/105_box_host_keys.sql +35 -0
- package/migrations/111_medusa_customer0_framing.sql +35 -0
- package/migrations/112_drop_track_check.sql +25 -0
- package/migrations/113_merge_lease.sql +16 -0
- package/migrations/114_cloudbongos_rename_live_strings.sql +32 -0
- package/migrations/118_currency_label_decoupling.sql +23 -0
- package/migrations/119_builder_behavior_prefs.sql +31 -0
- package/migrations/121_box_code_version.sql +37 -0
- package/migrations/122_builder_gemini_key.sql +30 -0
- package/migrations/123_cost_log_tiers.sql +33 -0
- package/migrations/124_cost_baseline.sql +45 -0
- package/migrations/125_llm_cache.sql +54 -0
- package/migrations/126_autonomy_runs.sql +33 -0
- package/migrations/143_cost_calibration.sql +63 -0
- package/migrations/145_backfill_task_requires_rank.sql +84 -0
- package/migrations/160_goal_tier.sql +88 -0
- package/migrations/163_polymorphic_dependencies.sql +187 -0
- package/migrations/164_event_sound_prefs.sql +20 -0
- package/migrations/165_task_module_key.sql +15 -0
- package/migrations/171_claims_published_head_sha.sql +24 -0
- package/migrations/174_close_orphaned_claims_on_terminal_tasks.sql +30 -0
- package/migrations/175_task_grades_diff_hash.sql +9 -0
- package/migrations/176_promotion_respects_open_blockers.sql +58 -0
- package/migrations/176_ui_discipline.sql +40 -0
- package/migrations/177_require_reward_before_workable.sql +76 -0
- package/migrations/178_reward_gate_auto_assign_revert_autopromote.sql +61 -0
- package/migrations/179_search_chunk_usefulness.sql +33 -0
- package/migrations/180_one_active_claim_per_session.sql +54 -0
- package/migrations/181_cost_log_skill_name.sql +33 -0
- package/migrations/184_claim_release_requested.sql +25 -0
- package/migrations/185_module_upstreaming_goal_wiring.sql +59 -0
- package/migrations/187_goal_sort_order.sql +30 -0
- package/migrations/187_tasks_kind_check_add_verify.sql +21 -0
- package/migrations/README.md +88 -0
- package/migrations/core_188_goal_visibility_and_membership_requests.sql +71 -0
- package/migrations/core_189_core_upgrades_ledger.sql +37 -0
- package/migrations/core_189_credit_log_task_id_index.sql +19 -0
- package/migrations/core_190_rebuild_claimable_task_views.sql +71 -0
- package/migrations/instance/018_pms_v3_planning_seed.sql +131 -0
- package/migrations/instance/080_gds_v4_planning_seed.sql +75 -0
- package/migrations/instance/110_medusa_planning_seed.sql +70 -0
- package/migrations/instance/120_bongos_v1_planning_seed.sql +69 -0
- package/migrations/instance/144_bongos_v1_module_system_criterion.sql +26 -0
- package/migrations/instance/159_bongos_v1_goal_hierarchy_criterion.sql +29 -0
- package/migrations/instance/172_v2_world_planning_seed.sql +163 -0
- package/migrations/instance/173_bongos_v1_c7_core_modularized.sql +33 -0
- package/migrations/instance/182_gdsv4_bongos_consolidation.sql +132 -0
- package/migrations/instance/183_gdsv4_carryover_themed_goals.sql +116 -0
- package/migrations/instance/186_bongos_v1_governance_planning_seed.sql +69 -0
- package/modules/autonomy/CLAUDE.md +49 -0
- package/modules/autonomy/db.js +50 -0
- package/modules/autonomy/module.json +13 -0
- package/modules/autonomy/pollers/routine-timers.js +146 -0
- package/modules/autonomy/routes/autonomy.js +37 -0
- package/modules/builder-settings/CLAUDE.md +58 -0
- package/modules/builder-settings/builder-needs.js +115 -0
- package/modules/builder-settings/db.js +168 -0
- package/modules/builder-settings/display-name.js +84 -0
- package/modules/builder-settings/event-sound-prefs.js +169 -0
- package/modules/builder-settings/interaction-prefs.js +201 -0
- package/modules/builder-settings/model-alloc-prefs.js +147 -0
- package/modules/builder-settings/module.json +10 -0
- package/modules/builder-settings/render-prefs.js +103 -0
- package/modules/builder-settings/routes/settings.js +417 -0
- package/modules/builder-settings/settings.js +52 -0
- package/modules/builder-settings/skill-prefs.js +196 -0
- package/modules/builder-settings/sound-prefs.js +178 -0
- package/modules/builder-settings/wandering-prefs.js +282 -0
- package/modules/dev-box/CLAUDE.md +38 -0
- package/modules/dev-box/box-access.js +275 -0
- package/modules/dev-box/box-credential.js +94 -0
- package/modules/dev-box/box-onboard.js +486 -0
- package/modules/dev-box/boxes.js +842 -0
- package/modules/dev-box/db.js +39 -0
- package/modules/dev-box/module.json +14 -0
- package/modules/dev-box/routes/box.js +977 -0
- package/modules/discord/CLAUDE.md +50 -0
- package/modules/discord/auth.js +54 -0
- package/modules/discord/bug-attachments.js +210 -0
- package/modules/discord/db.js +96 -0
- package/modules/discord/discord-approvals.js +145 -0
- package/modules/discord/discord-audit.js +29 -0
- package/modules/discord/discord-bot.js +545 -0
- package/modules/discord/discord-bugs.js +257 -0
- package/modules/discord/discord-channels.js +412 -0
- package/modules/discord/discord-inbound.js +147 -0
- package/modules/discord/discord-message-buffer.js +54 -0
- package/modules/discord/discord-reaction.js +186 -0
- package/modules/discord/discord-role-sync.js +318 -0
- package/modules/discord/module.json +14 -0
- package/modules/discord/pollers/discord-bot.js +19 -0
- package/modules/discord/routes/bug-attachments.js +44 -0
- package/modules/discord/routes/discord.js +102 -0
- package/modules/discord/ship-broadcast.js +78 -0
- package/modules/discord/webhook.js +74 -0
- package/modules/economy/CLAUDE.md +48 -0
- package/modules/economy/achievements.js +594 -0
- package/modules/economy/cost-classify.js +331 -0
- package/modules/economy/cost-summary-shape.js +90 -0
- package/modules/economy/cost.js +438 -0
- package/modules/economy/credits.js +430 -0
- package/modules/economy/migrations/economy_001_fix_gds_shipper_description.sql +91 -0
- package/modules/economy/module.json +10 -0
- package/modules/economy/reward.js +61 -0
- package/modules/economy/routes/cost.js +97 -0
- package/modules/economy/routes/leaderboard.js +26 -0
- package/modules/economy/routes/reward.js +42 -0
- package/modules/economy/streak.js +285 -0
- package/modules/grading/CLAUDE.md +42 -0
- package/modules/grading/db.js +39 -0
- package/modules/grading/grader-rubric.json +151 -0
- package/modules/grading/grader-workers/efficiency.js +213 -0
- package/modules/grading/grader-workers/extract-json.js +80 -0
- package/modules/grading/grader-workers/fence.js +100 -0
- package/modules/grading/grader-workers/hacker.js +239 -0
- package/modules/grading/grader-workers/index.js +183 -0
- package/modules/grading/grader-workers/narc.js +207 -0
- package/modules/grading/grader-workers/quality.js +198 -0
- package/modules/grading/grader-workers/rubric.js +20 -0
- package/modules/grading/grader-workers/worker-prompt.js +89 -0
- package/modules/grading/grader-workers/worker-verdict.js +50 -0
- package/modules/grading/grader.js +1790 -0
- package/modules/grading/module.json +12 -0
- package/modules/grading/routes/grade.js +51 -0
- package/modules/hall-ui/CLAUDE.md +61 -0
- package/modules/hall-ui/module.json +14 -0
- package/modules/hall-ui/public/atlas.html +180 -0
- package/modules/hall-ui/public/atlas.js +336 -0
- package/modules/hall-ui/public/box-panel.js +423 -0
- package/modules/hall-ui/public/brand-apply.js +117 -0
- package/modules/hall-ui/public/builders.js +3028 -0
- package/modules/hall-ui/public/chime.wav +0 -0
- package/modules/hall-ui/public/copy-on-click.js +174 -0
- package/modules/hall-ui/public/cursors/arrow.png +0 -0
- package/modules/hall-ui/public/cursors/hand-pointer.png +0 -0
- package/modules/hall-ui/public/cursors/magnifier-out.png +0 -0
- package/modules/hall-ui/public/cursors/magnifier.png +0 -0
- package/modules/hall-ui/public/diagram-viewer.css +125 -0
- package/modules/hall-ui/public/diagram-viewer.js +330 -0
- package/modules/hall-ui/public/diagrams.html +113 -0
- package/modules/hall-ui/public/dom-utils.js +212 -0
- package/modules/hall-ui/public/drachmae.html +68 -0
- package/modules/hall-ui/public/drachmae.js +136 -0
- package/modules/hall-ui/public/gate.html +143 -0
- package/modules/hall-ui/public/gate.js +228 -0
- package/modules/hall-ui/public/goals-page.js +1297 -0
- package/modules/hall-ui/public/goals.html +376 -0
- package/modules/hall-ui/public/goals.js +119 -0
- package/modules/hall-ui/public/hall-widgets.js +189 -0
- package/modules/hall-ui/public/harbor.html +167 -0
- package/modules/hall-ui/public/harbor.js +335 -0
- package/modules/hall-ui/public/index.html +116 -0
- package/modules/hall-ui/public/instances-panel.js +172 -0
- package/modules/hall-ui/public/md-reader.js +234 -0
- package/modules/hall-ui/public/modules.html +119 -0
- package/modules/hall-ui/public/modules.js +154 -0
- package/modules/hall-ui/public/new-project-wizard.js +186 -0
- package/modules/hall-ui/public/not-ready.html +48 -0
- package/modules/hall-ui/public/pair.html +119 -0
- package/modules/hall-ui/public/pair.js +132 -0
- package/modules/hall-ui/public/primer.css +404 -0
- package/modules/hall-ui/public/primer.html +85 -0
- package/modules/hall-ui/public/primer.js +641 -0
- package/modules/hall-ui/public/profile.html +85 -0
- package/modules/hall-ui/public/profile.js +236 -0
- package/modules/hall-ui/public/ranks.html +69 -0
- package/modules/hall-ui/public/ranks.js +206 -0
- package/modules/hall-ui/public/roadmap.html +209 -0
- package/modules/hall-ui/public/roadmap.js +375 -0
- package/modules/hall-ui/public/sessions.html +92 -0
- package/modules/hall-ui/public/sessions.js +222 -0
- package/modules/hall-ui/public/settings.html +640 -0
- package/modules/hall-ui/public/settings.js +1219 -0
- package/modules/hall-ui/public/shell.js +495 -0
- package/modules/hall-ui/public/style.css +1748 -0
- package/modules/hall-ui/public/task-detail.js +253 -0
- package/modules/hall-ui/public/task.html +83 -0
- package/modules/hall-ui/public/task.js +326 -0
- package/modules/hall-ui/public/watch.html +333 -0
- package/modules/hall-ui/public/watch.js +859 -0
- package/modules/hall-ui/public/work.html +469 -0
- package/modules/hall-ui/public/work.js +1292 -0
- package/modules/ideas/CLAUDE.md +37 -0
- package/modules/ideas/blockers.js +100 -0
- package/modules/ideas/inbox.js +459 -0
- package/modules/ideas/module.json +10 -0
- package/modules/ideas/routes/blockers.js +120 -0
- package/modules/ideas/routes/inbox.js +230 -0
- package/modules/lifecycle/CLAUDE.md +63 -0
- package/modules/lifecycle/conflict-resolve.js +436 -0
- package/modules/lifecycle/db.js +4970 -0
- package/modules/lifecycle/done-when.js +355 -0
- package/modules/lifecycle/github-push.js +969 -0
- package/modules/lifecycle/goal-conflicts.js +133 -0
- package/modules/lifecycle/hierarchy.js +104 -0
- package/modules/lifecycle/lifecycle.js +58 -0
- package/modules/lifecycle/merge-lock.js +261 -0
- package/modules/lifecycle/migrations/lifecycle_001_goal_first_leads.sql +28 -0
- package/modules/lifecycle/migrations/lifecycle_002_backfill_orphan_task_goals.sql +36 -0
- package/modules/lifecycle/module.json +13 -0
- package/modules/lifecycle/pollers/publish-reconciler.js +20 -0
- package/modules/lifecycle/publish-reconciler.js +418 -0
- package/modules/lifecycle/routes/analytics.js +63 -0
- package/modules/lifecycle/routes/claims.js +506 -0
- package/modules/lifecycle/routes/dependencies.js +82 -0
- package/modules/lifecycle/routes/done-when.js +136 -0
- package/modules/lifecycle/routes/gate-approvals.js +197 -0
- package/modules/lifecycle/routes/goals.js +1419 -0
- package/modules/lifecycle/routes/lifecycle.js +43 -0
- package/modules/lifecycle/routes/tasks.js +1703 -0
- package/modules/lifecycle/routes/versions.js +128 -0
- package/modules/lifecycle/ship-card.js +505 -0
- package/modules/lifecycle/ship-preflight.js +225 -0
- package/modules/lifecycle/task-classifier.js +512 -0
- package/modules/lifecycle/version-close.js +106 -0
- package/modules/memory/CLAUDE.md +40 -0
- package/modules/memory/learnings.js +275 -0
- package/modules/memory/memory.js +572 -0
- package/modules/memory/module.json +12 -0
- package/modules/memory/routes/learnings.js +90 -0
- package/modules/memory/routes/memory.js +916 -0
- package/modules/memory/routes/search.js +188 -0
- package/modules/memory/search-chunker.js +252 -0
- package/modules/memory/search.js +320 -0
- package/modules/onboarding/CLAUDE.md +55 -0
- package/modules/onboarding/approval-broadcast.js +59 -0
- package/modules/onboarding/db.js +54 -0
- package/modules/onboarding/module.json +10 -0
- package/modules/onboarding/newcomer-restock.js +212 -0
- package/modules/onboarding/onboarding-state.js +532 -0
- package/modules/onboarding/onboarding.js +508 -0
- package/modules/onboarding/port.js +63 -0
- package/modules/onboarding/routes/access-requests.js +208 -0
- package/modules/onboarding/routes/onboarding.js +54 -0
- package/modules/security/CLAUDE.md +44 -0
- package/modules/security/module.json +10 -0
- package/modules/security/routes/reports.js +251 -0
- package/modules/security/secret-scrub.js +201 -0
- package/modules/security/security.js +294 -0
- package/modules/sessions/CLAUDE.md +39 -0
- package/modules/sessions/bfg.js +357 -0
- package/modules/sessions/db.js +326 -0
- package/modules/sessions/module.json +10 -0
- package/modules/sessions/pulse.js +149 -0
- package/modules/sessions/routes/sessions.js +331 -0
- package/modules/status-ui/CLAUDE.md +47 -0
- package/modules/status-ui/module.json +14 -0
- package/modules/status-ui/public/README.md +29 -0
- package/modules/status-ui/public/cursors/arrow.png +0 -0
- package/modules/status-ui/public/cursors/hand-pointer.png +0 -0
- package/modules/status-ui/public/index.html +363 -0
- package/modules/status-ui/public/snapshots/.gitkeep +0 -0
- package/modules/status-ui/public/status.js +1375 -0
- package/modules/status-ui/public/style.css +1342 -0
- package/package-lock.json +975 -0
- package/package.json +28 -0
- package/public-docs/index.html +35 -0
- package/public-docs/redoc.standalone.js +1838 -0
- package/public-docs/redoc.standalone.js.LICENSE.txt +102 -0
- package/public-landing/buddha.png +0 -0
- package/public-landing/create.html +868 -0
- package/public-landing/index.html +168 -0
- package/scripts/bongos-mcp.js +28 -0
- package/scripts/cron/style_guide_audit.sh +134 -0
- package/scripts/discord/README.md +52 -0
- package/scripts/discord/lib.js +80 -0
- package/scripts/discord/post.js +51 -0
- package/scripts/gds/CLAUDE.md +144 -0
- package/scripts/gds/abandon.js +58 -0
- package/scripts/gds/adopt-detect.js +123 -0
- package/scripts/gds/adopt-import.js +111 -0
- package/scripts/gds/adopt-preflight.js +121 -0
- package/scripts/gds/api.js +78 -0
- package/scripts/gds/architect-audit.js +288 -0
- package/scripts/gds/art-stage.js +152 -0
- package/scripts/gds/audit-authorship.sh +243 -0
- package/scripts/gds/audit-deps.js +121 -0
- package/scripts/gds/audit-exports.js +128 -0
- package/scripts/gds/audit-replay.sh +161 -0
- package/scripts/gds/audit-ships.js +251 -0
- package/scripts/gds/autonomy-gate.js +135 -0
- package/scripts/gds/backfill-cost.js +165 -0
- package/scripts/gds/backfill-sessions.js +351 -0
- package/scripts/gds/backfill-task-rewards.js +408 -0
- package/scripts/gds/backup.js +94 -0
- package/scripts/gds/bfg-principal-token.js +65 -0
- package/scripts/gds/box-auth-check.js +160 -0
- package/scripts/gds/box-connect-lib.js +453 -0
- package/scripts/gds/box.js +1258 -0
- package/scripts/gds/build-bongos.js +94 -0
- package/scripts/gds/capture.js +123 -0
- package/scripts/gds/cf-tunnel.js +419 -0
- package/scripts/gds/ci-grade.js +82 -0
- package/scripts/gds/claim-recall.js +112 -0
- package/scripts/gds/claim.js +333 -0
- package/scripts/gds/classify-discipline.js +153 -0
- package/scripts/gds/claude-materialize.js +176 -0
- package/scripts/gds/cleanup-orphans.js +74 -0
- package/scripts/gds/cli-lib.js +518 -0
- package/scripts/gds/code.js +101 -0
- package/scripts/gds/codemod-rename-src-gds.js +145 -0
- package/scripts/gds/conductor-dispatch.js +426 -0
- package/scripts/gds/context-pack.js +228 -0
- package/scripts/gds/coreB-carve-proof.sh +716 -0
- package/scripts/gds/cost.js +47 -0
- package/scripts/gds/db-backup-nightly.sh +160 -0
- package/scripts/gds/db-backup-offsite.sh +152 -0
- package/scripts/gds/demote.js +40 -0
- package/scripts/gds/design-sync.js +62 -0
- package/scripts/gds/diagnose-achievements.js +118 -0
- package/scripts/gds/diagram-facts.js +319 -0
- package/scripts/gds/discipline-modes.json +25 -0
- package/scripts/gds/discord-channels.js +66 -0
- package/scripts/gds/do-api.js +176 -0
- package/scripts/gds/docs-entropy.js +403 -0
- package/scripts/gds/doctor.js +389 -0
- package/scripts/gds/feedback-latest.js +94 -0
- package/scripts/gds/fetch-art-key.js +106 -0
- package/scripts/gds/fetch-sound-prefs.js +88 -0
- package/scripts/gds/figma-design-sync.js +61 -0
- package/scripts/gds/fitness.js +1446 -0
- package/scripts/gds/gate-review.js +322 -0
- package/scripts/gds/gating.js +325 -0
- package/scripts/gds/gds-db-backup.service +24 -0
- package/scripts/gds/gds-db-backup.timer +20 -0
- package/scripts/gds/gds-db-offsite.service +29 -0
- package/scripts/gds/gds-db-offsite.timer +18 -0
- package/scripts/gds/gen-api-client.js +508 -0
- package/scripts/gds/gen-api-docs.js +1037 -0
- package/scripts/gds/gen-atlas.js +366 -0
- package/scripts/gds/gen-diagrams.js +608 -0
- package/scripts/gds/gen-file-map.js +196 -0
- package/scripts/gds/gen-repo-map.js +519 -0
- package/scripts/gds/gen-session-index.js +210 -0
- package/scripts/gds/git-merge-regen.js +147 -0
- package/scripts/gds/grade-smoke.js +205 -0
- package/scripts/gds/hooks/pre-push.js +169 -0
- package/scripts/gds/http-api-client.js +88 -0
- package/scripts/gds/init.js +903 -0
- package/scripts/gds/install-git-hooks.js +114 -0
- package/scripts/gds/key-card.js +213 -0
- package/scripts/gds/key-status.js +126 -0
- package/scripts/gds/land-watch.js +168 -0
- package/scripts/gds/learning-capture.js +145 -0
- package/scripts/gds/lib.sh +44 -0
- package/scripts/gds/linkify-refs.js +473 -0
- package/scripts/gds/local-preview-lib.js +159 -0
- package/scripts/gds/local-preview.js +95 -0
- package/scripts/gds/login.js +225 -0
- package/scripts/gds/main-audit.js +279 -0
- package/scripts/gds/me.js +88 -0
- package/scripts/gds/memory-map.js +174 -0
- package/scripts/gds/merge-lock.js +71 -0
- package/scripts/gds/migration-namespace.js +200 -0
- package/scripts/gds/mirror-lineage-check.js +319 -0
- package/scripts/gds/mirror-redact.js +305 -0
- package/scripts/gds/module.js +482 -0
- package/scripts/gds/newcomer-floor.config.json +13 -0
- package/scripts/gds/newcomer-floor.js +415 -0
- package/scripts/gds/newcomer-floor.templates.json +86 -0
- package/scripts/gds/newcomer-floor.test.js +235 -0
- package/scripts/gds/next-number.js +163 -0
- package/scripts/gds/oauth-secret.js +197 -0
- package/scripts/gds/onboard.js +217 -0
- package/scripts/gds/onboarding-analyze.js +226 -0
- package/scripts/gds/onboarding-config.js +178 -0
- package/scripts/gds/onboarding-ship.js +92 -0
- package/scripts/gds/package-core.js +684 -0
- package/scripts/gds/paste-token.js +131 -0
- package/scripts/gds/portability-smoke-art.sh +85 -0
- package/scripts/gds/portability-smoke-memory.sh +147 -0
- package/scripts/gds/provision.js +1324 -0
- package/scripts/gds/publish-manifest.js +307 -0
- package/scripts/gds/pulse.js +309 -0
- package/scripts/gds/push-main.js +45 -0
- package/scripts/gds/read-session-export.js +359 -0
- package/scripts/gds/reauth.js +149 -0
- package/scripts/gds/recall.js +135 -0
- package/scripts/gds/release.js +71 -0
- package/scripts/gds/render-ideas.js +173 -0
- package/scripts/gds/repo-metrics.js +363 -0
- package/scripts/gds/resolve-skill-model.js +57 -0
- package/scripts/gds/run-routine.js +197 -0
- package/scripts/gds/run-unit-tests.js +178 -0
- package/scripts/gds/sandbox-stage.js +653 -0
- package/scripts/gds/search-ingest-db.js +209 -0
- package/scripts/gds/search-ingest-md.js +225 -0
- package/scripts/gds/security-baseline-check.sh +180 -0
- package/scripts/gds/seed-adopt-tasks.js +75 -0
- package/scripts/gds/seed-api-contract-goal-tasks.js +141 -0
- package/scripts/gds/seed-bongos-app-tasks.js +294 -0
- package/scripts/gds/seed-bongos-coreB-tranche1-tasks.js +81 -0
- package/scripts/gds/seed-bongos-coreB-tranche2-tasks.js +100 -0
- package/scripts/gds/seed-bongos-goal-hierarchy-tasks.js +307 -0
- package/scripts/gds/seed-bongos-module-system-tasks.js +346 -0
- package/scripts/gds/seed-bongos-tasks.js +214 -0
- package/scripts/gds/seed-gds-v4-tasks.js +624 -0
- package/scripts/gds/seed-governance-tasks.js +340 -0
- package/scripts/gds/seed-medusa-tasks.js +440 -0
- package/scripts/gds/seed-module-upstreaming.js +219 -0
- package/scripts/gds/seed-productization-tasks.js +235 -0
- package/scripts/gds/seed-provisioning-tasks.js +83 -0
- package/scripts/gds/seed-staging.sh +104 -0
- package/scripts/gds/seed-v2-world-tasks.js +283 -0
- package/scripts/gds/seed-v3-tasks.js +1981 -0
- package/scripts/gds/session-cost.js +393 -0
- package/scripts/gds/session-digest.js +179 -0
- package/scripts/gds/session-eval.js +576 -0
- package/scripts/gds/session.js +404 -0
- package/scripts/gds/setup.js +504 -0
- package/scripts/gds/shell.js +100 -0
- package/scripts/gds/ship.js +3618 -0
- package/scripts/gds/smoke-batch-claim.sh +213 -0
- package/scripts/gds/smoke-batch-release.sh +296 -0
- package/scripts/gds/smoke-box.sh +150 -0
- package/scripts/gds/smoke-claim-consistency.sh +212 -0
- package/scripts/gds/smoke-dependencies.sh +84 -0
- package/scripts/gds/smoke-gds.js +125 -0
- package/scripts/gds/smoke-write.sh +168 -0
- package/scripts/gds/start.js +782 -0
- package/scripts/gds/status.js +365 -0
- package/scripts/gds/triage.js +366 -0
- package/scripts/gds/upgrade.js +421 -0
- package/scripts/gds/validate-design.js +254 -0
- package/scripts/gds/version-close.js +549 -0
- package/scripts/migrate.sh +183 -0
- package/scripts/migrate_cost_ledger.sh +178 -0
- package/scripts/public-mirror-export.js +291 -0
- package/scripts/render-diagrams.sh +88 -0
- package/scripts/security/dep-audit.js +276 -0
- package/scripts/setup-builder.js +274 -0
- package/scripts/setup-builder.sh +28 -0
- package/scripts/snapshots/backfill-history.mjs +292 -0
- package/scripts/snapshots/maybe-render-on-deploy.sh +66 -0
- package/scripts/snapshots/render-pre-art-eras.mjs +329 -0
- package/scripts/snapshots/render-world.mjs +322 -0
- package/scripts/status-mirror-sync.js +192 -0
- package/scripts/status-probe.mjs +185 -0
- package/server.js +212 -0
- package/src/asset-version.js +71 -0
- package/src/bongos/CLAUDE.md +64 -0
- package/src/bongos/api-errors.js +281 -0
- package/src/bongos/api-path-404.js +67 -0
- package/src/bongos/api-prefix.js +38 -0
- package/src/bongos/app-pair.js +172 -0
- package/src/bongos/auth.js +979 -0
- package/src/bongos/cascade-dispatch.js +123 -0
- package/src/bongos/db-kernel.js +252 -0
- package/src/bongos/db.js +911 -0
- package/src/bongos/goal-scope-check.js +120 -0
- package/src/bongos/hierarchy-config.js +189 -0
- package/src/bongos/live-channel.js +145 -0
- package/src/bongos/llm-cache.js +260 -0
- package/src/bongos/llm-pricing.js +220 -0
- package/src/bongos/metrics.js +286 -0
- package/src/bongos/middleware/audit.js +274 -0
- package/src/bongos/middleware/error-envelope.js +93 -0
- package/src/bongos/middleware/rate-limit.js +195 -0
- package/src/bongos/module-scope-map.js +271 -0
- package/src/bongos/optimizer.js +166 -0
- package/src/bongos/path-match.js +47 -0
- package/src/bongos/permission-path-check.js +248 -0
- package/src/bongos/pool.js +55 -0
- package/src/bongos/repo-info.js +91 -0
- package/src/bongos/route-rank-check.js +420 -0
- package/src/bongos/routes/CLAUDE.md +43 -0
- package/src/bongos/routes/_helpers.js +369 -0
- package/src/bongos/routes/audit-log.js +59 -0
- package/src/bongos/routes/auth.js +755 -0
- package/src/bongos/routes/backup.js +104 -0
- package/src/bongos/routes/builders.js +526 -0
- package/src/bongos/routes/healthz.js +16 -0
- package/src/bongos/routes/instance.js +129 -0
- package/src/bongos/routes/live.js +125 -0
- package/src/bongos/routes/llm-cache.js +119 -0
- package/src/bongos/routes/me.js +380 -0
- package/src/bongos/routes/modules.js +131 -0
- package/src/bongos/routes/optimizer.js +54 -0
- package/src/bongos/routes/public.js +476 -0
- package/src/bongos/routes/security.js +207 -0
- package/src/bongos/routes.js +166 -0
- package/src/bongos/secret-box.js +177 -0
- package/src/bongos/sensitive-surfaces.js +30 -0
- package/src/bongos/serve-internal.js +889 -0
- package/src/bongos/uptime-poller.js +90 -0
- package/src/bongos-downloads.js +70 -0
- package/src/branding.js +182 -0
- package/src/build-info.js +77 -0
- package/src/devbox-downloads.js +67 -0
- package/src/instance-config.js +200 -0
- package/src/module-api.js +366 -0
- package/src/module-loader/loader.js +268 -0
- package/src/module-loader/manifest-schema.js +140 -0
- package/src/module-loader/provenance.js +28 -0
- package/src/module-loader/semver.js +100 -0
- package/src/module-seams.js +291 -0
- package/src/modules.js +254 -0
- package/src/platform-server.js +135 -0
- package/src/ui/adapters/claude-design/index.js +333 -0
- package/src/ui/adapters/figma/index.js +328 -0
- package/tests/abandon_task.mjs +138 -0
- package/tests/achievements_reconcile.mjs +167 -0
- package/tests/adopt_detect.mjs +141 -0
- package/tests/adopt_import.mjs +132 -0
- package/tests/adopt_preflight.mjs +105 -0
- package/tests/anti_grid.mjs +89 -0
- package/tests/api_client.mjs +231 -0
- package/tests/api_docs.mjs +283 -0
- package/tests/api_error_envelope_buildcheck.mjs +56 -0
- package/tests/api_error_envelope_middleware.mjs +99 -0
- package/tests/api_error_registry.mjs +108 -0
- package/tests/api_pagination_contract.mjs +51 -0
- package/tests/api_path_404.mjs +96 -0
- package/tests/app_pair.mjs +168 -0
- package/tests/architect.mjs +140 -0
- package/tests/art_key.mjs +121 -0
- package/tests/art_stage.mjs +121 -0
- package/tests/asset_version.mjs +94 -0
- package/tests/atlas.mjs +69 -0
- package/tests/audit_deps.mjs +74 -0
- package/tests/audit_middleware.mjs +385 -0
- package/tests/auth_admission_gate.mjs +164 -0
- package/tests/auth_anthropic_identity.mjs +95 -0
- package/tests/auth_duplicate_cookie.mjs +56 -0
- package/tests/auth_error_brand.mjs +77 -0
- package/tests/auth_flow_slice1.mjs +223 -0
- package/tests/auth_inactive_builder.mjs +94 -0
- package/tests/auth_page_gate.mjs +92 -0
- package/tests/auth_session_ttl.mjs +155 -0
- package/tests/autonomous_fit_protected_paths.mjs +115 -0
- package/tests/autonomy_gate.mjs +85 -0
- package/tests/autotile_variants.mjs +256 -0
- package/tests/autotile_xverify.mjs +133 -0
- package/tests/backfill_sessions.mjs +101 -0
- package/tests/backfill_task_rewards.mjs +152 -0
- package/tests/backup_cli.mjs +104 -0
- package/tests/bfg.mjs +327 -0
- package/tests/bfg_write.mjs +423 -0
- package/tests/bongos_box_connect.mjs +89 -0
- package/tests/bongos_dispatch.mjs +74 -0
- package/tests/bongos_downloads.mjs +118 -0
- package/tests/bongos_login.mjs +34 -0
- package/tests/box_access.mjs +186 -0
- package/tests/box_auth_check.mjs +114 -0
- package/tests/box_code_staleness.mjs +116 -0
- package/tests/box_connect_e2e.mjs +196 -0
- package/tests/box_cost.mjs +70 -0
- package/tests/box_dns_repoint.mjs +151 -0
- package/tests/box_host_keys.mjs +102 -0
- package/tests/box_onboard.mjs +317 -0
- package/tests/box_scope_session.mjs +115 -0
- package/tests/box_ship_permissions.mjs +71 -0
- package/tests/box_terminal_ssrf.mjs +90 -0
- package/tests/boxes.mjs +1255 -0
- package/tests/branding.mjs +88 -0
- package/tests/bug_attachments.mjs +189 -0
- package/tests/build_info.mjs +88 -0
- package/tests/builder_needs.mjs +99 -0
- package/tests/cap_newcomer_tasks.mjs +114 -0
- package/tests/cascade-dispatch.mjs +95 -0
- package/tests/cf_tunnel.mjs +459 -0
- package/tests/claim_recall.mjs +150 -0
- package/tests/claims_bind_session.mjs +47 -0
- package/tests/claude_materialize.mjs +148 -0
- package/tests/cli_box_scope.mjs +52 -0
- package/tests/cli_lib_formatters.mjs +87 -0
- package/tests/cli_token_reissue.mjs +147 -0
- package/tests/client_bundle_route.mjs +47 -0
- package/tests/cloud_bongos_pack.mjs +85 -0
- package/tests/conductor.mjs +496 -0
- package/tests/confirm_attribution.mjs +156 -0
- package/tests/conflict_resolve.mjs +462 -0
- package/tests/context_pack.mjs +240 -0
- package/tests/cost.mjs +94 -0
- package/tests/cost_audit.mjs +122 -0
- package/tests/cost_budget_status.mjs +78 -0
- package/tests/cost_reconcile.mjs +102 -0
- package/tests/cost_summary_shape.mjs +94 -0
- package/tests/credit_grant.mjs +376 -0
- package/tests/criterion_progress.mjs +220 -0
- package/tests/criterion_proposal.mjs +109 -0
- package/tests/criterion_ref_parse.mjs +53 -0
- package/tests/currency_label.mjs +119 -0
- package/tests/day_cycle.mjs +197 -0
- package/tests/dependencies_migration.mjs +77 -0
- package/tests/dependencies_polymorphic.mjs +212 -0
- package/tests/deploy_instance.mjs +78 -0
- package/tests/devbox_downloads.mjs +122 -0
- package/tests/diff_derived_signals.mjs +115 -0
- package/tests/discord_approvals.mjs +174 -0
- package/tests/discord_autojoin.mjs +158 -0
- package/tests/discord_bot.mjs +94 -0
- package/tests/discord_bugs.mjs +297 -0
- package/tests/discord_channels.mjs +337 -0
- package/tests/discord_foundation.mjs +76 -0
- package/tests/discord_inbound.mjs +190 -0
- package/tests/discord_message_buffer.mjs +87 -0
- package/tests/discord_oauth.mjs +55 -0
- package/tests/discord_reaction.mjs +170 -0
- package/tests/discord_role_sync.mjs +151 -0
- package/tests/display_name.mjs +123 -0
- package/tests/dns_preflight.mjs +74 -0
- package/tests/event_sound_prefs.mjs +194 -0
- package/tests/eviction_policy.mjs +279 -0
- package/tests/figma_adapter.mjs +199 -0
- package/tests/file_map.mjs +91 -0
- package/tests/first_admin_bootstrap.mjs +40 -0
- package/tests/fitness.mjs +435 -0
- package/tests/fitness_two_root.mjs +104 -0
- package/tests/fixtures/session-506-digest.json +34 -0
- package/tests/gate_approvals.mjs +451 -0
- package/tests/gate_review.mjs +152 -0
- package/tests/git_merge_regen.mjs +151 -0
- package/tests/github_push_ancestry.mjs +119 -0
- package/tests/github_push_land_proof.mjs +127 -0
- package/tests/github_push_merge_driver.mjs +175 -0
- package/tests/goal_abuse_matrix.mjs +187 -0
- package/tests/goal_achievement.mjs +146 -0
- package/tests/goal_conflicts.mjs +305 -0
- package/tests/goal_dependencies_read.mjs +73 -0
- package/tests/goal_member_roles.mjs +420 -0
- package/tests/goal_membership_requests.mjs +332 -0
- package/tests/goal_routes.mjs +203 -0
- package/tests/goal_scope_check.mjs +167 -0
- package/tests/goal_tier.mjs +312 -0
- package/tests/goal_wall_proof.mjs +112 -0
- package/tests/grade_attempts.mjs +73 -0
- package/tests/grade_attribution.mjs +117 -0
- package/tests/grade_diff_hash.mjs +191 -0
- package/tests/grade_server_authoritative.mjs +305 -0
- package/tests/grade_unavailable_display.mjs +66 -0
- package/tests/grader.mjs +1960 -0
- package/tests/grader_bypass.mjs +57 -0
- package/tests/grader_panel.mjs +252 -0
- package/tests/grader_prompt_fencing.mjs +192 -0
- package/tests/helpers.mjs +52 -0
- package/tests/hierarchy-config.mjs +81 -0
- package/tests/init.mjs +463 -0
- package/tests/instance_config.mjs +76 -0
- package/tests/instance_manifest.mjs +110 -0
- package/tests/interaction_prefs.mjs +72 -0
- package/tests/key-card.mjs +110 -0
- package/tests/key-status.mjs +45 -0
- package/tests/land_watch.mjs +115 -0
- package/tests/lifecycle-card.mjs +145 -0
- package/tests/lifecycle_breakdown_view.mjs +236 -0
- package/tests/linkify_refs.mjs +264 -0
- package/tests/live_channel.mjs +128 -0
- package/tests/live_sse.mjs +122 -0
- package/tests/llm-cache-route.mjs +110 -0
- package/tests/llm-cache.mjs +140 -0
- package/tests/llm-pricing.mjs +152 -0
- package/tests/local_preview.mjs +136 -0
- package/tests/main_audit.mjs +137 -0
- package/tests/memory_isolation.mjs +431 -0
- package/tests/memory_map.mjs +107 -0
- package/tests/memory_pull.mjs +429 -0
- package/tests/merge_lease.mjs +100 -0
- package/tests/merge_lock.mjs +312 -0
- package/tests/metrics.mjs +147 -0
- package/tests/migration_allocation.mjs +146 -0
- package/tests/migration_namespace.mjs +185 -0
- package/tests/migrations_fresh_replay_guard.mjs +38 -0
- package/tests/mirror_lineage_fulltree.mjs +45 -0
- package/tests/mirror_lineage_proof.mjs +72 -0
- package/tests/mirror_redact.mjs +193 -0
- package/tests/model_alloc_prefs.mjs +63 -0
- package/tests/module-scope-map.mjs +88 -0
- package/tests/module_api.mjs +110 -0
- package/tests/module_cli.mjs +292 -0
- package/tests/module_contributions.mjs +148 -0
- package/tests/module_loader.mjs +286 -0
- package/tests/module_manifest.mjs +194 -0
- package/tests/module_owned_tests.mjs +105 -0
- package/tests/module_provenance.mjs +34 -0
- package/tests/module_route_rank.mjs +147 -0
- package/tests/module_seams.mjs +68 -0
- package/tests/modules.mjs +156 -0
- package/tests/modules_route.mjs +38 -0
- package/tests/newcomer_floor.mjs +17 -0
- package/tests/newcomer_restock.mjs +80 -0
- package/tests/next_number.mjs +154 -0
- package/tests/oauth_secret.mjs +60 -0
- package/tests/onboard.mjs +70 -0
- package/tests/onboarding_gate.mjs +267 -0
- package/tests/onboarding_observability.mjs +344 -0
- package/tests/onboarding_route_signals.mjs +175 -0
- package/tests/onboarding_state.mjs +346 -0
- package/tests/one_active_claim_per_session.mjs +111 -0
- package/tests/orphaned_claim_ship.mjs +135 -0
- package/tests/override_attribution.mjs +142 -0
- package/tests/override_request_ownership.mjs +235 -0
- package/tests/package_core.mjs +435 -0
- package/tests/parallel-load.mjs +402 -0
- package/tests/path_match.mjs +62 -0
- package/tests/permission_path.mjs +151 -0
- package/tests/platform_boot.mjs +167 -0
- package/tests/pre_compact.mjs +60 -0
- package/tests/preview_server.mjs +127 -0
- package/tests/profile_route.mjs +197 -0
- package/tests/provision.mjs +805 -0
- package/tests/provisioning_github_app_routes.mjs +98 -0
- package/tests/public_mirror_export.mjs +124 -0
- package/tests/public_task_resolver.mjs +112 -0
- package/tests/publish_branch_route.mjs +422 -0
- package/tests/publish_manifest.mjs +184 -0
- package/tests/publish_reconciler.mjs +728 -0
- package/tests/rank_gate.mjs +463 -0
- package/tests/rate_limit_public.mjs +217 -0
- package/tests/read_session_export.mjs +89 -0
- package/tests/recall_cli.mjs +82 -0
- package/tests/recall_hints.mjs +119 -0
- package/tests/recent_shipped_window.mjs +80 -0
- package/tests/regrade_eligibility.mjs +202 -0
- package/tests/render_prefs.mjs +122 -0
- package/tests/repo_map.mjs +92 -0
- package/tests/reward_gate.mjs +284 -0
- package/tests/route_rank_check.mjs +243 -0
- package/tests/route_validation.mjs +490 -0
- package/tests/routine_timers.mjs +72 -0
- package/tests/rubric_fixtures.mjs +140 -0
- package/tests/run_routine.mjs +69 -0
- package/tests/sandbox_stage.mjs +582 -0
- package/tests/scrubber_corpus.mjs +257 -0
- package/tests/search_chunker.mjs +209 -0
- package/tests/search_ingest.mjs +96 -0
- package/tests/search_ingest_db.mjs +88 -0
- package/tests/search_isolation.mjs +204 -0
- package/tests/search_route.mjs +95 -0
- package/tests/secret_box.mjs +189 -0
- package/tests/security_docs.mjs +186 -0
- package/tests/security_route.mjs +108 -0
- package/tests/served_paths_shipped.mjs +118 -0
- package/tests/session-cards.mjs +142 -0
- package/tests/session_506_regression.mjs +69 -0
- package/tests/session_caps.mjs +238 -0
- package/tests/session_cost.mjs +133 -0
- package/tests/session_digest.mjs +73 -0
- package/tests/session_eval.mjs +386 -0
- package/tests/session_index.mjs +105 -0
- package/tests/session_records.mjs +369 -0
- package/tests/session_search.mjs +78 -0
- package/tests/session_start_freshness.mjs +123 -0
- package/tests/setup_smoke.mjs +154 -0
- package/tests/ship_autolinkify.mjs +60 -0
- package/tests/ship_automerge_injection.mjs +174 -0
- package/tests/ship_broadcast_routing.mjs +125 -0
- package/tests/ship_broadcast_server.mjs +175 -0
- package/tests/ship_card.mjs +280 -0
- package/tests/ship_ci_deploy.mjs +374 -0
- package/tests/ship_preflight.mjs +368 -0
- package/tests/ship_premerge.mjs +75 -0
- package/tests/ship_resume.mjs +129 -0
- package/tests/ship_upload_skip.mjs +89 -0
- package/tests/ship_zero_commit.mjs +60 -0
- package/tests/single_host_hall.mjs +98 -0
- package/tests/skill_prefs.mjs +150 -0
- package/tests/smoke_preflight.mjs +66 -0
- package/tests/snapshot_picker.mjs +233 -0
- package/tests/sound_prefs.mjs +198 -0
- package/tests/sprite_facing.mjs +35 -0
- package/tests/status-probe.mjs +89 -0
- package/tests/status_backfill.mjs +94 -0
- package/tests/stop_refcheck.mjs +127 -0
- package/tests/streak.mjs +175 -0
- package/tests/subdomain_auth.mjs +58 -0
- package/tests/task_classifier_vocab.mjs +41 -0
- package/tests/task_create_idempotency.mjs +96 -0
- package/tests/task_goal_link.mjs +93 -0
- package/tests/task_ownership_gate.mjs +125 -0
- package/tests/terrain_picker.mjs +298 -0
- package/tests/touches_overlap.mjs +75 -0
- package/tests/triage_development.mjs +140 -0
- package/tests/turn_in_place.mjs +280 -0
- package/tests/upgrade.mjs +357 -0
- package/tests/verify_task_guard.mjs +64 -0
- package/tests/version_close.mjs +76 -0
- package/tests/versions_route.mjs +93 -0
- package/tests/walkability.mjs +188 -0
- package/tests/wandering_prefs.mjs +176 -0
- package/tests/worktree_disambiguation.mjs +105 -0
- package/tests/worktree_guard.mjs +90 -0
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
// tests/lifecycle_breakdown_view.mjs
|
|
2
|
+
//
|
|
3
|
+
// Coverage for V3.R23 / #243: version_lifecycle_breakdown must count ONLY
|
|
4
|
+
// LEAF TASKS, the same way version_progress does. Pre-fix, the view was
|
|
5
|
+
// defined in migration 012 with FILTER clauses that referenced t.status only —
|
|
6
|
+
// it had no `NOT EXISTS (SELECT 1 FROM tasks c WHERE c.parent_task_id = t.id)`
|
|
7
|
+
// guard. The result: a parent task with N shipped children inflated
|
|
8
|
+
// shipped_count by N+1 (the parent itself + each child).
|
|
9
|
+
//
|
|
10
|
+
// Migration 034 replaces the view with the leaf predicate. This test proves
|
|
11
|
+
// two properties:
|
|
12
|
+
//
|
|
13
|
+
// 1. The migration text itself contains the leaf predicate in EVERY
|
|
14
|
+
// per-state FILTER clause. (Static SQL assertion — protects against a
|
|
15
|
+
// future hand-edit dropping the guard from one state and not another.)
|
|
16
|
+
// 2. The view's filter semantics, simulated in JS over a fixture of
|
|
17
|
+
// parent + 2 children, produces single counts — not double counts —
|
|
18
|
+
// AND the OLD pre-fix predicate on the SAME fixture would have
|
|
19
|
+
// double-counted. The "would have" half is the load-bearing proof that
|
|
20
|
+
// the migration actually changed behaviour, not just SQL text.
|
|
21
|
+
//
|
|
22
|
+
// No live DB. The view's predicate is pure (status + title + leaf-ness), so
|
|
23
|
+
// reproducing it in JS gives high-fidelity coverage without spinning Postgres.
|
|
24
|
+
//
|
|
25
|
+
// Run: node tests/lifecycle_breakdown_view.mjs
|
|
26
|
+
|
|
27
|
+
import { strict as assert } from 'node:assert';
|
|
28
|
+
import { readFileSync } from 'node:fs';
|
|
29
|
+
import { fileURLToPath } from 'node:url';
|
|
30
|
+
import { dirname, join } from 'node:path';
|
|
31
|
+
|
|
32
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
33
|
+
const repoRoot = join(__dirname, '..');
|
|
34
|
+
|
|
35
|
+
let passed = 0;
|
|
36
|
+
let failed = 0;
|
|
37
|
+
async function test(name, fn) {
|
|
38
|
+
try {
|
|
39
|
+
await fn();
|
|
40
|
+
console.log(` ok ${name}`);
|
|
41
|
+
passed++;
|
|
42
|
+
} catch (err) {
|
|
43
|
+
console.error(` FAIL ${name}`);
|
|
44
|
+
console.error(' ', err.message);
|
|
45
|
+
failed++;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// --- helpers -----------------------------------------------------------------
|
|
50
|
+
|
|
51
|
+
// Mirrors the view's WHERE / FILTER predicate. Given the full tasks array
|
|
52
|
+
// (so we can check children) and a candidate task t, decide whether it
|
|
53
|
+
// counts toward the per-state breakdown.
|
|
54
|
+
function leafPredicate(t, allTasks) {
|
|
55
|
+
if (!t) return false;
|
|
56
|
+
if (typeof t.title === 'string' && t.title.startsWith('__smoke__')) return false;
|
|
57
|
+
const hasChildren = allTasks.some((c) => c.parent_task_id === t.id);
|
|
58
|
+
return !hasChildren;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Old pre-fix predicate (migration 012): per-state filter only on status +
|
|
62
|
+
// __smoke__ title. NO leaf guard. We reproduce it so the test can demonstrate
|
|
63
|
+
// the bug the migration fixes.
|
|
64
|
+
function oldPredicate(t /*, allTasks */) {
|
|
65
|
+
if (!t) return false;
|
|
66
|
+
if (typeof t.title === 'string' && t.title.startsWith('__smoke__')) return false;
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Compute the per-state breakdown the way the NEW view does — leaf-only.
|
|
71
|
+
function breakdownNew(tasks) {
|
|
72
|
+
const out = { completed_count: 0, confirmed_count: 0, shipped_count: 0 };
|
|
73
|
+
for (const t of tasks) {
|
|
74
|
+
if (!leafPredicate(t, tasks)) continue;
|
|
75
|
+
if (t.status === 'completed') out.completed_count++;
|
|
76
|
+
else if (t.status === 'confirmed') out.confirmed_count++;
|
|
77
|
+
else if (t.status === 'shipped') out.shipped_count++;
|
|
78
|
+
}
|
|
79
|
+
return out;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Compute the per-state breakdown the way the OLD (buggy) view did — every row.
|
|
83
|
+
function breakdownOld(tasks) {
|
|
84
|
+
const out = { completed_count: 0, confirmed_count: 0, shipped_count: 0 };
|
|
85
|
+
for (const t of tasks) {
|
|
86
|
+
if (!oldPredicate(t, tasks)) continue;
|
|
87
|
+
if (t.status === 'completed') out.completed_count++;
|
|
88
|
+
else if (t.status === 'confirmed') out.confirmed_count++;
|
|
89
|
+
else if (t.status === 'shipped') out.shipped_count++;
|
|
90
|
+
}
|
|
91
|
+
return out;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// --- tests -------------------------------------------------------------------
|
|
95
|
+
|
|
96
|
+
await (async () => {
|
|
97
|
+
console.log('migration 034: view SQL text');
|
|
98
|
+
|
|
99
|
+
const migrationPath = join(repoRoot, 'migrations', '034_lifecycle_breakdown_leaf_only.sql');
|
|
100
|
+
const migrationSql = readFileSync(migrationPath, 'utf8');
|
|
101
|
+
|
|
102
|
+
await test('migration 034 defines version_lifecycle_breakdown', () => {
|
|
103
|
+
assert.ok(
|
|
104
|
+
/CREATE VIEW version_lifecycle_breakdown/i.test(migrationSql),
|
|
105
|
+
'migration 034 must (re)create version_lifecycle_breakdown'
|
|
106
|
+
);
|
|
107
|
+
assert.ok(
|
|
108
|
+
/DROP VIEW IF EXISTS version_lifecycle_breakdown/i.test(migrationSql),
|
|
109
|
+
'migration 034 must DROP the old view first (column-list safety)'
|
|
110
|
+
);
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
await test('each per-state FILTER clause carries the leaf predicate', () => {
|
|
114
|
+
// Split on "count(*) FILTER" — each chunk after the first should be
|
|
115
|
+
// a single FILTER clause body, and each must include the leaf guard.
|
|
116
|
+
// Match the predicate flexibly w.r.t. whitespace.
|
|
117
|
+
const leafGuard = /NOT\s+EXISTS\s*\(\s*SELECT\s+1\s+FROM\s+tasks\s+c\s+WHERE\s+c\.parent_task_id\s*=\s*t\.id\s*\)/i;
|
|
118
|
+
|
|
119
|
+
const filterChunks = migrationSql.split(/count\(\*\)\s+FILTER/i).slice(1);
|
|
120
|
+
assert.equal(
|
|
121
|
+
filterChunks.length, 3,
|
|
122
|
+
`expected 3 per-state FILTER clauses (completed / confirmed / shipped); found ${filterChunks.length}`
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
for (const [idx, chunk] of filterChunks.entries()) {
|
|
126
|
+
// Bound each chunk to its own closing paren-region — take up to the
|
|
127
|
+
// first ") AS <name>_count" so we don't pull the predicate from a
|
|
128
|
+
// neighbouring clause.
|
|
129
|
+
const body = chunk.split(/\)\s+AS\s+\w+_count/i)[0];
|
|
130
|
+
assert.ok(
|
|
131
|
+
leafGuard.test(body),
|
|
132
|
+
`FILTER clause #${idx + 1} must contain the leaf guard NOT EXISTS (...). body was: ${body.slice(0, 200)}…`
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
await test('migration 034 bumps the migration counter and registers itself', () => {
|
|
138
|
+
assert.ok(
|
|
139
|
+
/UPDATE\s+migration_counter\s+SET\s+next_number\s*=\s*GREATEST\(next_number,\s*35\)/i.test(migrationSql),
|
|
140
|
+
'migration must bump migration_counter.next_number to >= 35'
|
|
141
|
+
);
|
|
142
|
+
assert.ok(
|
|
143
|
+
/INSERT\s+INTO\s+schema_migrations\s*\(\s*version\s*\)\s*VALUES\s*\(\s*'034_lifecycle_breakdown_leaf_only'/i.test(migrationSql),
|
|
144
|
+
"migration must INSERT INTO schema_migrations the '034_lifecycle_breakdown_leaf_only' row"
|
|
145
|
+
);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
console.log('view semantics: leaf-only rollup');
|
|
149
|
+
|
|
150
|
+
// Fixture: a parent task with 2 shipped children, both inside one version.
|
|
151
|
+
// The bug being fixed: pre-fix rollup reports shipped_count = 3 (parent +
|
|
152
|
+
// each child). Post-fix it reports shipped_count = 2 (children only).
|
|
153
|
+
const parentChildrenAllShipped = [
|
|
154
|
+
{ id: 1, version_id: 'GDS-V3', parent_task_id: null, status: 'shipped', title: 'Parent' },
|
|
155
|
+
{ id: 2, version_id: 'GDS-V3', parent_task_id: 1, status: 'shipped', title: 'Child A' },
|
|
156
|
+
{ id: 3, version_id: 'GDS-V3', parent_task_id: 1, status: 'shipped', title: 'Child B' },
|
|
157
|
+
];
|
|
158
|
+
|
|
159
|
+
await test('NEW view: parent + 2 shipped children → shipped_count = 2 (leaves only)', () => {
|
|
160
|
+
const got = breakdownNew(parentChildrenAllShipped);
|
|
161
|
+
assert.deepEqual(got, { completed_count: 0, confirmed_count: 0, shipped_count: 2 });
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
await test('OLD view (regression baseline): same fixture WOULD have reported shipped_count = 3', () => {
|
|
165
|
+
const got = breakdownOld(parentChildrenAllShipped);
|
|
166
|
+
assert.deepEqual(got, { completed_count: 0, confirmed_count: 0, shipped_count: 3 },
|
|
167
|
+
'the pre-fix predicate must over-count by 1 (the parent row); if it doesn\'t, the test no longer proves the fix matters');
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
await test('mixed lifecycle states: leaf-only rollup is honest per-state', () => {
|
|
171
|
+
const tasks = [
|
|
172
|
+
// Parent with mixed-state children → only children count.
|
|
173
|
+
{ id: 10, version_id: 'GDS-V3', parent_task_id: null, status: 'shipped', title: 'Parent X' },
|
|
174
|
+
{ id: 11, version_id: 'GDS-V3', parent_task_id: 10, status: 'completed', title: 'X child 1' },
|
|
175
|
+
{ id: 12, version_id: 'GDS-V3', parent_task_id: 10, status: 'confirmed', title: 'X child 2' },
|
|
176
|
+
{ id: 13, version_id: 'GDS-V3', parent_task_id: 10, status: 'shipped', title: 'X child 3' },
|
|
177
|
+
// Standalone leaf shipped.
|
|
178
|
+
{ id: 20, version_id: 'GDS-V3', parent_task_id: null, status: 'shipped', title: 'Solo Y' },
|
|
179
|
+
// Standalone leaf in confirmed.
|
|
180
|
+
{ id: 21, version_id: 'GDS-V3', parent_task_id: null, status: 'confirmed', title: 'Solo Z' },
|
|
181
|
+
];
|
|
182
|
+
// Leaves: 11 (completed), 12 (confirmed), 13 (shipped), 20 (shipped), 21 (confirmed).
|
|
183
|
+
// → completed=1, confirmed=2, shipped=2
|
|
184
|
+
assert.deepEqual(
|
|
185
|
+
breakdownNew(tasks),
|
|
186
|
+
{ completed_count: 1, confirmed_count: 2, shipped_count: 2 }
|
|
187
|
+
);
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
await test('__smoke__ rows are excluded (matches view FILTER)', () => {
|
|
191
|
+
const tasks = [
|
|
192
|
+
{ id: 30, version_id: 'GDS-V3', parent_task_id: null, status: 'shipped', title: 'Real leaf' },
|
|
193
|
+
{ id: 31, version_id: 'GDS-V3', parent_task_id: null, status: 'shipped', title: '__smoke__ excluded' },
|
|
194
|
+
];
|
|
195
|
+
assert.deepEqual(
|
|
196
|
+
breakdownNew(tasks),
|
|
197
|
+
{ completed_count: 0, confirmed_count: 0, shipped_count: 1 }
|
|
198
|
+
);
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
await test('a parent with NO children IS itself a leaf — gets counted', () => {
|
|
202
|
+
// Edge case worth pinning: in this schema "parent" is purely a function
|
|
203
|
+
// of OTHER rows pointing at this one via parent_task_id. A row that
|
|
204
|
+
// happens to be parent_task_id=null AND has no children is still a leaf.
|
|
205
|
+
const tasks = [
|
|
206
|
+
{ id: 40, version_id: 'GDS-V3', parent_task_id: null, status: 'shipped', title: 'Childless top-level' },
|
|
207
|
+
];
|
|
208
|
+
assert.deepEqual(
|
|
209
|
+
breakdownNew(tasks),
|
|
210
|
+
{ completed_count: 0, confirmed_count: 0, shipped_count: 1 }
|
|
211
|
+
);
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
await test('predicate parity: leaf clause matches the one version_progress uses (migration 017)', () => {
|
|
215
|
+
// Cross-check against the live version_progress definition so the two
|
|
216
|
+
// views stay aligned. If someone evolves version_progress's leaf guard
|
|
217
|
+
// (different operator, different table alias) we want this test to FAIL
|
|
218
|
+
// loudly until the lifecycle view is updated in lockstep.
|
|
219
|
+
const progressMigration = readFileSync(
|
|
220
|
+
join(repoRoot, 'migrations', '017_version_progress_exclude_abandoned.sql'),
|
|
221
|
+
'utf8'
|
|
222
|
+
);
|
|
223
|
+
const leafGuard = /NOT\s+EXISTS\s*\(\s*SELECT\s+1\s+FROM\s+tasks\s+c\s+WHERE\s+c\.parent_task_id\s*=\s*t\.id\s*\)/i;
|
|
224
|
+
assert.ok(
|
|
225
|
+
leafGuard.test(progressMigration),
|
|
226
|
+
'version_progress (migration 017) must use the same leaf guard — if this fails, the two views have diverged and migration 034 should be re-aligned'
|
|
227
|
+
);
|
|
228
|
+
assert.ok(
|
|
229
|
+
leafGuard.test(migrationSql),
|
|
230
|
+
'version_lifecycle_breakdown (migration 034) must use the same leaf guard'
|
|
231
|
+
);
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
console.log(`\n${passed} passed, ${failed} failed`);
|
|
235
|
+
if (failed > 0) process.exit(1);
|
|
236
|
+
})();
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
// tests/linkify_refs.mjs
|
|
2
|
+
//
|
|
3
|
+
// #604 — the doc-linkifier classifier. The whole value of the rewrite is that
|
|
4
|
+
// it is CONSERVATIVE: a wrong rewrite (pointing a "#NNN" at the wrong thing)
|
|
5
|
+
// just recreates the Xenos's complaint, so these tests pin down exactly which
|
|
6
|
+
// refs are rewritten and which are deliberately left bare.
|
|
7
|
+
//
|
|
8
|
+
// Pure function — no API, no filesystem. validIds is a fixed Set.
|
|
9
|
+
//
|
|
10
|
+
// Run: node tests/linkify_refs.mjs
|
|
11
|
+
|
|
12
|
+
import { strict as assert } from 'node:assert';
|
|
13
|
+
import { createRequire } from 'node:module';
|
|
14
|
+
|
|
15
|
+
const require = createRequire(import.meta.url);
|
|
16
|
+
const { linkifyText, RESOLVER_BASE, RESOLVER_BASE_IDEA, RESOLVER_BASE_BLOCKER, discoverDocs } =
|
|
17
|
+
require('../scripts/gds/linkify-refs.js');
|
|
18
|
+
|
|
19
|
+
let passed = 0;
|
|
20
|
+
let failed = 0;
|
|
21
|
+
function t(name, fn) {
|
|
22
|
+
try { fn(); passed++; console.log(` PASS ${name}`); }
|
|
23
|
+
catch (e) { failed++; console.log(` FAIL ${name}\n ${e.message}`); }
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const IDS = new Set([12, 30, 170, 197, 227, 308, 475]);
|
|
27
|
+
const link = (n) => `[#${n}](${RESOLVER_BASE}${n})`;
|
|
28
|
+
const run = (s, ids = IDS) => linkifyText(s, ids).text;
|
|
29
|
+
|
|
30
|
+
t('a bare task ref is linkified', () => {
|
|
31
|
+
assert.equal(run('shipped in #475 today'), `shipped in ${link(475)} today`);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
t('a parenthesized task ref is linkified (these are task refs here, not PRs)', () => {
|
|
35
|
+
assert.equal(run('R01-followup (#308, 2026-05-13)'), `R01-followup (${link(308)}, 2026-05-13)`);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
t('an explicit "task #NNN" ref is linkified', () => {
|
|
39
|
+
assert.equal(run('via task #197 we'), `via task ${link(197)} we`);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
t('a number that is NOT a known task is left bare', () => {
|
|
43
|
+
assert.equal(run('see PR #999 for the merge'), 'see PR #999 for the merge');
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
t('a markdown HEADING ANCHOR is never touched (would break the TOC)', () => {
|
|
47
|
+
const s = '[Session Update Protocol](#12-session-update-protocol)';
|
|
48
|
+
assert.equal(run(s), s);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
t('a link TARGET like ](#227) is left alone', () => {
|
|
52
|
+
const s = 'see [the section](#227)';
|
|
53
|
+
assert.equal(run(s), s);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
t('a ref INSIDE markdown link text is not linkified (would nest links)', () => {
|
|
57
|
+
// mid-text, not right after '[': the bug that shipped [task [#415](r)](url)
|
|
58
|
+
assert.equal(run('see [task #170](https://x.com) for detail'),
|
|
59
|
+
'see [task #170](https://x.com) for detail');
|
|
60
|
+
assert.equal(run('[V3.R13 / #197](../CLAUDE.md) ref', new Set([197])),
|
|
61
|
+
'[V3.R13 / #197](../CLAUDE.md) ref');
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
t('already-linked refs are not double-wrapped (idempotent)', () => {
|
|
65
|
+
const once = run('shipped in #475 today');
|
|
66
|
+
assert.equal(run(once), once);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
t('idea-context refs are NEUTRALIZED (code span) — never task-linked, never bare-404', () => {
|
|
70
|
+
assert.equal(run('GDS-V4 (idea_inbox #30) will'), 'GDS-V4 (idea_inbox `#30`) will');
|
|
71
|
+
assert.equal(run('captured as idea #30 last week'), 'captured as idea `#30` last week');
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
t('an entity ref is neutralized even when the number is NOT a known task id', () => {
|
|
75
|
+
// "idea #170" was the original Xenos complaint: left bare it autolinks to a
|
|
76
|
+
// dead github.com issue. Entity context decides; the task-id set does not.
|
|
77
|
+
assert.equal(run('filed idea #222 yesterday', new Set([1])), 'filed idea `#222` yesterday');
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
t('blocker-context refs are neutralized — blocker ids share the integer space', () => {
|
|
81
|
+
assert.equal(run('a blocker #170 needs Lars', new Set([170])), 'a blocker `#170` needs Lars');
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
t('report/learning/claim/builder entity refs are neutralized too', () => {
|
|
85
|
+
assert.equal(run('captured learning #53 today', new Set([53])), 'captured learning `#53` today');
|
|
86
|
+
assert.equal(run('filed as security_reports #2', new Set([2])), 'filed as security_reports `#2`');
|
|
87
|
+
assert.equal(run('builder #3 was reset', new Set([3])), 'builder `#3` was reset');
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
t('a session ORDINAL ("Planning Session #1") is not a task ref', () => {
|
|
91
|
+
assert.equal(run('via Planning Session #1 today', new Set([1])), 'via Planning Session `#1` today');
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
t('a PR number ("PR #475") is left bare even when it collides with a task id — GitHub autolinks it CORRECTLY', () => {
|
|
95
|
+
assert.equal(run('merged in PR #475', new Set([475])), 'merged in PR #475');
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
t('entity classification carries across a comma list ("blockers #1, #2")', () => {
|
|
99
|
+
// Both are blocker ids — neither should become a task link…
|
|
100
|
+
assert.equal(run('blockers #1, #2 remain', new Set([1, 2])), 'blockers `#1`, `#2` remain');
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
t('entity classification carries across a RANGE ("reports #2–#11")', () => {
|
|
104
|
+
assert.equal(run('reports #2–#11 filed', new Set([2, 11])), 'reports `#2`–`#11` filed');
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
t('…but a genuine task list ("Tasks #1, #2") still linkifies BOTH', () => {
|
|
108
|
+
assert.equal(run('Tasks #1, #2 shipped', new Set([1, 2])), `Tasks ${link(1)}, ${link(2)} shipped`);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
t('mixed line: "Tasks #1, #2 + blockers #1, #2" links the task half, neutralizes the blocker half', () => {
|
|
112
|
+
const out = run('Tasks #1, #2 + blockers #1, #2', new Set([1, 2]));
|
|
113
|
+
assert.equal(out, `Tasks ${link(1)}, ${link(2)} + blockers \`#1\`, \`#2\``);
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
t('entity context does not over-extend past non-glue text', () => {
|
|
117
|
+
// "idea #30, then task #197" — idea neutralized, but the comma+word gap
|
|
118
|
+
// breaks inheritance so the real task ref still linkifies.
|
|
119
|
+
assert.equal(run('idea #30, then task #197 ran', new Set([30, 197])),
|
|
120
|
+
`idea \`#30\`, then task ${link(197)} ran`);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
t('neutralization is idempotent — a `#30` code span is never re-wrapped', () => {
|
|
124
|
+
const once = run('captured as idea #30 last week');
|
|
125
|
+
assert.equal(run(once), once);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
t('a PAST mis-linkification in entity context is unwrapped to a code span', () => {
|
|
129
|
+
// An earlier linkifier run wrongly sent "learning #53" to the task resolver.
|
|
130
|
+
assert.equal(run(`captured learning ${link(53)} today`, new Set([53])),
|
|
131
|
+
'captured learning `#53` today');
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
t('a PAST mis-linkification of a PR ref is unwrapped back to BARE (autolink is correct there)', () => {
|
|
135
|
+
assert.equal(run(`merged in PR ${link(475)}`, new Set([475])), 'merged in PR #475');
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
t('a RANGE of past mis-linkifications unwraps on both ends', () => {
|
|
139
|
+
assert.equal(run(`security_reports ${link(2)}–${link(11)} filed`, new Set([2, 11])),
|
|
140
|
+
'security_reports `#2`–`#11` filed');
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
t('a CORRECT task resolver link is never unwrapped', () => {
|
|
144
|
+
const s = `shipped in ${link(475)} today`;
|
|
145
|
+
assert.equal(run(s), s);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
t('inline code spans are not transformed', () => {
|
|
149
|
+
const s = 'the `#197` marker stays code';
|
|
150
|
+
assert.equal(run(s), s);
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
t('fenced code blocks are not transformed', () => {
|
|
154
|
+
const s = ['before #475', '```', 'code #475 here', '```', 'after #475'].join('\n');
|
|
155
|
+
const out = run(s).split('\n');
|
|
156
|
+
assert.equal(out[0], `before ${link(475)}`);
|
|
157
|
+
assert.equal(out[2], 'code #475 here'); // inside fence — untouched
|
|
158
|
+
assert.equal(out[4], `after ${link(475)}`);
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
t('multiple refs on one line all linkify', () => {
|
|
162
|
+
assert.equal(run('Phase 1 #197, Phase 2 #227.'), `Phase 1 ${link(197)}, Phase 2 ${link(227)}.`);
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
t('a slugged ref like #170foo is treated as not-bare and skipped', () => {
|
|
166
|
+
assert.equal(run('#170foo'), '#170foo');
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
t('stats report linkified + skip reasons', () => {
|
|
170
|
+
const stats = { linkified: 0, skipped: {} };
|
|
171
|
+
linkifyText('#475 and #999 and idea #30 and [x](#12-y)', IDS, stats);
|
|
172
|
+
assert.equal(stats.linkified, 1, 'only #475 should linkify');
|
|
173
|
+
assert.ok(stats.skipped['not-a-task'] >= 1, 'a non-task was skipped');
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
// ========================================================================
|
|
177
|
+
// #629 — idea/blocker refs LINK to their resolvers when the id validates.
|
|
178
|
+
// `ids` is now {tasks, ideas, blockers}; the existing tests above pass a bare
|
|
179
|
+
// task Set (empty idea/blocker sets), so those refs still NEUTRALIZE — the new
|
|
180
|
+
// behavior only kicks in when the matching id set contains the number.
|
|
181
|
+
// ========================================================================
|
|
182
|
+
|
|
183
|
+
const ilink = (n) => `[#${n}](${RESOLVER_BASE_IDEA}${n})`;
|
|
184
|
+
const blink = (n) => `[#${n}](${RESOLVER_BASE_BLOCKER}${n})`;
|
|
185
|
+
const runIds = (s, ids) => linkifyText(s, ids).text;
|
|
186
|
+
|
|
187
|
+
t('a bare idea ref LINKS to the idea resolver when the id is a known idea', () => {
|
|
188
|
+
assert.equal(runIds('GDS-V4 (idea_inbox #30) will', { tasks: new Set(), ideas: new Set([30]), blockers: new Set() }),
|
|
189
|
+
`GDS-V4 (idea_inbox ${ilink(30)}) will`);
|
|
190
|
+
assert.equal(runIds('captured as idea #173 last week', { ideas: new Set([173]) }),
|
|
191
|
+
`captured as idea ${ilink(173)} last week`);
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
t('a bare blocker ref LINKS to the blocker resolver when the id is a known blocker', () => {
|
|
195
|
+
assert.equal(runIds('a blocker #10 needs Lars', { blockers: new Set([10]) }),
|
|
196
|
+
`a blocker ${blink(10)} needs Lars`);
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
t('an idea ref whose id is NOT a known idea is still NEUTRALIZED (no wrong link, no 404)', () => {
|
|
200
|
+
assert.equal(runIds('filed idea #222 yesterday', { ideas: new Set([1]) }), 'filed idea `#222` yesterday');
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
t('a task id and an idea id that collide resolve to DIFFERENT resolvers by context', () => {
|
|
204
|
+
const ids = { tasks: new Set([170]), ideas: new Set([170]), blockers: new Set() };
|
|
205
|
+
assert.equal(runIds('task #170 vs idea #170', ids), `task ${link(170)} vs idea ${ilink(170)}`);
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
t('idea/blocker classification carries across a list → BOTH link', () => {
|
|
209
|
+
assert.equal(runIds('blockers #1, #2 remain', { blockers: new Set([1, 2]) }),
|
|
210
|
+
`blockers ${blink(1)}, ${blink(2)} remain`);
|
|
211
|
+
assert.equal(runIds('ideas #30 and #173', { ideas: new Set([30, 173]) }),
|
|
212
|
+
`ideas ${ilink(30)} and ${ilink(173)}`);
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
t('Phase 2: a PRIOR idea/blocker neutralization `#N` is UPGRADED to a resolver link', () => {
|
|
216
|
+
assert.equal(runIds('see idea_inbox `#160` here', { ideas: new Set([160]) }),
|
|
217
|
+
`see idea_inbox ${ilink(160)} here`);
|
|
218
|
+
assert.equal(runIds('blocker `#7` is open', { blockers: new Set([7]) }),
|
|
219
|
+
`blocker ${blink(7)} is open`);
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
t('Phase 2 upgrade carries across a list of code spans ("blockers `#1`, `#2`")', () => {
|
|
223
|
+
assert.equal(runIds('blockers `#1`, `#2` remain', { blockers: new Set([1, 2]) }),
|
|
224
|
+
`blockers ${blink(1)}, ${blink(2)} remain`);
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
t('Phase 2 does NOT upgrade an other-entity code span (no resolver for learnings)', () => {
|
|
228
|
+
assert.equal(runIds('captured learning `#53` today', { ideas: new Set([53]), blockers: new Set([53]) }),
|
|
229
|
+
'captured learning `#53` today');
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
t('Phase 2 does NOT touch a legit code span with no idea/blocker context', () => {
|
|
233
|
+
// "the `#197` marker" — even if 197 is a known idea, there is no idea noun
|
|
234
|
+
// before it, so it stays a literal code span.
|
|
235
|
+
assert.equal(runIds('the `#197` marker stays code', { ideas: new Set([197]) }),
|
|
236
|
+
'the `#197` marker stays code');
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
t('idea/blocker linking is idempotent (link, then link again = no change)', () => {
|
|
240
|
+
const ids = { ideas: new Set([30]), blockers: new Set([7]) };
|
|
241
|
+
const once = runIds('idea #30 and blocker #7', ids);
|
|
242
|
+
assert.equal(once, `idea ${ilink(30)} and blocker ${blink(7)}`);
|
|
243
|
+
assert.equal(runIds(once, ids), once);
|
|
244
|
+
// and a freshly-upgraded code span is stable on a second pass too
|
|
245
|
+
const up = runIds('idea_inbox `#30`', ids);
|
|
246
|
+
assert.equal(runIds(up, ids), up);
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
t('a known idea link is never unwrapped by the past-mislink pass', () => {
|
|
250
|
+
const ids = { ideas: new Set([30]) };
|
|
251
|
+
const s = `idea ${ilink(30)} shipped`;
|
|
252
|
+
assert.equal(runIds(s, ids), s);
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
t('discoverDocs finds CLAUDE.md + session logs, only .md, skips the generated ideas file', () => {
|
|
256
|
+
const docs = discoverDocs();
|
|
257
|
+
assert.ok(docs.includes('CLAUDE.md'), 'includes CLAUDE.md');
|
|
258
|
+
assert.ok(docs.some((d) => d.startsWith('docs/session-logs/')), 'includes session logs');
|
|
259
|
+
assert.ok(docs.every((d) => d.endsWith('.md')), 'only markdown files');
|
|
260
|
+
assert.ok(!docs.includes('generative-ideas.md'), 'excludes the generated ideas file');
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
console.log(`\nlinkify_refs: ${passed} passed, ${failed} failed`);
|
|
264
|
+
process.exit(failed ? 1 : 0);
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
// tests/live_channel.mjs
|
|
2
|
+
//
|
|
3
|
+
// Unit smoke for the GDS live-update relay (#569 / ADR 0030).
|
|
4
|
+
//
|
|
5
|
+
// Verifies the in-process fan-out logic in src/bongos/live-channel.js WITHOUT a
|
|
6
|
+
// real Postgres — a fake pg.Client is injected via _setClientFactory. This is
|
|
7
|
+
// the transport-agnostic layer: in production the hall's SSE endpoint
|
|
8
|
+
// (src/bongos/routes/live.js) subscribes here and writes each nudge to connected
|
|
9
|
+
// EventSource clients. (Before R55 / ADR 0069 the subscriber was the Colyseus
|
|
10
|
+
// BuildersHallRoom; this relay is unchanged either way.)
|
|
11
|
+
// 1. First subscriber lazily opens ONE LISTEN connection (connect + LISTEN).
|
|
12
|
+
// 2. A NOTIFY on the 'gds_live' channel reaches every subscriber, parsed.
|
|
13
|
+
// 3. A NOTIFY on some OTHER channel is ignored.
|
|
14
|
+
// 4. Malformed JSON payload → subscriber gets null (no throw).
|
|
15
|
+
// 5. One throwing subscriber doesn't starve the others.
|
|
16
|
+
// 6. A second subscriber REUSES the same connection (factory called once).
|
|
17
|
+
// 7. Connection closes only when the LAST subscriber leaves.
|
|
18
|
+
//
|
|
19
|
+
// Run: node tests/live_channel.mjs
|
|
20
|
+
|
|
21
|
+
import { strict as assert } from 'node:assert';
|
|
22
|
+
import { createRequire } from 'node:module';
|
|
23
|
+
import { EventEmitter } from 'node:events';
|
|
24
|
+
|
|
25
|
+
const require = createRequire(import.meta.url);
|
|
26
|
+
const live = require('../src/bongos/live-channel.js');
|
|
27
|
+
|
|
28
|
+
const tick = () => new Promise((r) => setTimeout(r, 10));
|
|
29
|
+
|
|
30
|
+
// A fake pg.Client: records calls, lets the test emit notifications.
|
|
31
|
+
let factoryCalls = 0;
|
|
32
|
+
let lastClient = null;
|
|
33
|
+
function fakeFactory() {
|
|
34
|
+
factoryCalls += 1;
|
|
35
|
+
const c = new EventEmitter();
|
|
36
|
+
c.queries = [];
|
|
37
|
+
c.ended = false;
|
|
38
|
+
c.connect = async () => {};
|
|
39
|
+
c.query = async (sql) => { c.queries.push(sql); };
|
|
40
|
+
c.end = async () => { c.ended = true; };
|
|
41
|
+
lastClient = c;
|
|
42
|
+
return c;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
live._setClientFactory(fakeFactory);
|
|
46
|
+
|
|
47
|
+
// --- 1 + 2 + 6: lazy connect, delivery, single connection -----------------
|
|
48
|
+
const got1 = [];
|
|
49
|
+
const got2 = [];
|
|
50
|
+
const unsub1 = live.subscribe((p) => got1.push(p));
|
|
51
|
+
await tick();
|
|
52
|
+
|
|
53
|
+
assert.equal(factoryCalls, 1, 'first subscriber opens exactly one client');
|
|
54
|
+
assert.ok(lastClient, 'a client was created');
|
|
55
|
+
assert.ok(
|
|
56
|
+
lastClient.queries.some((q) => /LISTEN\s+gds_live/i.test(q)),
|
|
57
|
+
'client issued LISTEN gds_live',
|
|
58
|
+
);
|
|
59
|
+
assert.deepEqual(live._state(), { subscribers: 1, connected: true });
|
|
60
|
+
|
|
61
|
+
const unsub2 = live.subscribe((p) => got2.push(p));
|
|
62
|
+
await tick();
|
|
63
|
+
assert.equal(factoryCalls, 1, 'second subscriber REUSES the connection');
|
|
64
|
+
assert.equal(live._state().subscribers, 2);
|
|
65
|
+
|
|
66
|
+
// Deliver a well-formed notification.
|
|
67
|
+
lastClient.emit('notification', { channel: 'gds_live', payload: '{"table":"tasks","op":"UPDATE"}' });
|
|
68
|
+
assert.deepEqual(got1.at(-1), { table: 'tasks', op: 'UPDATE' }, 'subscriber 1 got parsed payload');
|
|
69
|
+
assert.deepEqual(got2.at(-1), { table: 'tasks', op: 'UPDATE' }, 'subscriber 2 got parsed payload');
|
|
70
|
+
|
|
71
|
+
// --- 3: other channel ignored ---------------------------------------------
|
|
72
|
+
const before = got1.length;
|
|
73
|
+
lastClient.emit('notification', { channel: 'something_else', payload: '{"x":1}' });
|
|
74
|
+
assert.equal(got1.length, before, 'notification on another channel is ignored');
|
|
75
|
+
|
|
76
|
+
// --- 4: malformed JSON → null, no throw ------------------------------------
|
|
77
|
+
lastClient.emit('notification', { channel: 'gds_live', payload: 'not json{' });
|
|
78
|
+
assert.equal(got1.at(-1), null, 'malformed payload delivered as null');
|
|
79
|
+
|
|
80
|
+
// --- 5: a throwing subscriber must not starve the others -------------------
|
|
81
|
+
const got3 = [];
|
|
82
|
+
const unsub3 = live.subscribe(() => { throw new Error('boom'); });
|
|
83
|
+
const got4 = [];
|
|
84
|
+
const unsub4 = live.subscribe((p) => got4.push(p));
|
|
85
|
+
await tick();
|
|
86
|
+
lastClient.emit('notification', { channel: 'gds_live', payload: '{"table":"builders","op":"INSERT"}' });
|
|
87
|
+
assert.deepEqual(got4.at(-1), { table: 'builders', op: 'INSERT' }, 'good subscriber still gets payload despite a throwing peer');
|
|
88
|
+
|
|
89
|
+
// --- 7: connection closes only after the LAST subscriber leaves ------------
|
|
90
|
+
unsub1();
|
|
91
|
+
unsub2();
|
|
92
|
+
unsub3();
|
|
93
|
+
assert.equal(lastClient.ended, false, 'still connected while one subscriber remains');
|
|
94
|
+
assert.equal(live._state().connected, true);
|
|
95
|
+
unsub4();
|
|
96
|
+
assert.equal(lastClient.ended, true, 'connection closed after the last subscriber left');
|
|
97
|
+
assert.deepEqual(live._state(), { subscribers: 0, connected: false });
|
|
98
|
+
|
|
99
|
+
// --- 8: a dropped LISTEN connection reconnects while a subscriber remains ---
|
|
100
|
+
// #983: shrink the reconnect backoff via the test-only seam so this exercises
|
|
101
|
+
// the reconnect path WITHOUT a multi-second real-time wait (was a hard
|
|
102
|
+
// `setTimeout(2300)`, the slowest assertion in the suite).
|
|
103
|
+
live._setReconnectDelay(10);
|
|
104
|
+
const startCalls = factoryCalls;
|
|
105
|
+
const got5 = [];
|
|
106
|
+
const unsub5 = live.subscribe((p) => got5.push(p));
|
|
107
|
+
await tick();
|
|
108
|
+
assert.equal(factoryCalls, startCalls + 1, 'resubscribe opens a fresh client');
|
|
109
|
+
const firstClient = lastClient;
|
|
110
|
+
|
|
111
|
+
// Simulate the LISTEN connection dropping mid-flight.
|
|
112
|
+
firstClient.emit('error', new Error('connection terminated unexpectedly'));
|
|
113
|
+
assert.equal(live._state().connected, false, 'connection torn down on error');
|
|
114
|
+
|
|
115
|
+
// scheduleReconnect waits ~10ms (test backoff), then reconnects because a
|
|
116
|
+
// subscriber remains. Poll briefly instead of a fixed long sleep.
|
|
117
|
+
for (let i = 0; i < 50 && factoryCalls < startCalls + 2; i++) await tick();
|
|
118
|
+
assert.equal(factoryCalls, startCalls + 2, 'reconnected with a new client after the backoff');
|
|
119
|
+
assert.equal(live._state().connected, true, 'live again after reconnect');
|
|
120
|
+
|
|
121
|
+
// Nudges flow over the reconnected client.
|
|
122
|
+
lastClient.emit('notification', { channel: 'gds_live', payload: '{"table":"claims","op":"DELETE"}' });
|
|
123
|
+
assert.deepEqual(got5.at(-1), { table: 'claims', op: 'DELETE' }, 'nudges resume after reconnect');
|
|
124
|
+
|
|
125
|
+
unsub5();
|
|
126
|
+
assert.equal(live._state().connected, false, 'closed after the final unsubscribe');
|
|
127
|
+
|
|
128
|
+
console.log('live_channel: all assertions passed');
|