@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,47 @@
|
|
|
1
|
+
# ADR 0040 — Remote Control is the default browser-only on-ramp (reversing 0038's "RC is dead" verdict)
|
|
2
|
+
|
|
3
|
+
- **Status:** Accepted. **Reverses the "Remote Control is unfixable" conclusion of [ADR 0038](<redacted>.md)** (tasks [#745](https://example.com/builders#/task/745) / [#760](https://example.com/builders#/task/760)). Implemented in the onboarding/Settings work under [#807](https://example.com/builders#/task/807); recorded here under [#838](https://example.com/builders#/task/838); remaining legs (cloud-init trust pre-seed + the connect-guide / recipe-Part-2 rewrites that lead browser-only builders into the Claude app via `/remote-control`) landed under [#824](https://example.com/builders#/task/824).
|
|
4
|
+
- **Date:** 2026-06-07 (trust pre-seed leg: 2026-06-29, [#824](https://example.com/builders#/task/824))
|
|
5
|
+
- **Track:** `internal` (dev-system / builder onboarding)
|
|
6
|
+
- **Builds on:** [ADR 0038](<redacted>.md) (ttyd web terminal + Cloudflare Tunnel), [ADR 0031](<redacted>.md), [ADR 0035](<redacted>.md), [ADR 0039](<redacted>.md), [ADR 0016](<redacted>.md)
|
|
7
|
+
|
|
8
|
+
## Context
|
|
9
|
+
|
|
10
|
+
ADR 0038 concluded that Claude Code **Remote Control** (drive a session from the claude.ai web app or the mobile app) was *unfixable* for browser-only builders, and replaced it with a raw `ttyd` web terminal. The three blockers it documented were:
|
|
11
|
+
|
|
12
|
+
1. Trusted-Devices enrollment is interactive-`/login`-only — no headless path.
|
|
13
|
+
2. `claude rc` only renders its pairing link to a real TTY — a systemd service has none.
|
|
14
|
+
3. Remote Control requires full-scope browser OAuth — every baked-token path is excluded by design.
|
|
15
|
+
|
|
16
|
+
**All three were artifacts of running RC *headless, as a background service, with no human present.*** ADR 0038's own fix — the ttyd web terminal — dissolves every one of them: it puts a **real human at a real browser-backed PTY**. In that terminal, `/login`, workspace-trust, and Trusted-Devices enrollment all succeed (0038 verified exactly this for plain interactive `claude`).
|
|
17
|
+
|
|
18
|
+
So Remote Control was never the thing that was broken — the *headless context* was. Given a human PTY, RC works. **Verified live on the prod box (LarsCode) on 2026-06-07:** in the ttyd terminal, `claude` → accept workspace-trust → `/remote-control` prints a pairing link that drives the session from the Claude web/mobile app.
|
|
19
|
+
|
|
20
|
+
## Decision
|
|
21
|
+
|
|
22
|
+
**Remote Control is the recommended default experience for browser-only builders, and the onboarding leads with it.** This shipped in [#807](https://example.com/builders#/task/807): the "Claude Online" onboarding path walks the builder through
|
|
23
|
+
|
|
24
|
+
1. open the box's ttyd terminal (URL + password from the builders' hall),
|
|
25
|
+
2. run `claude` and complete the one-time sign-in,
|
|
26
|
+
3. run **`/remote-control`** to get a link, and
|
|
27
|
+
4. open that link to drive the session from the Claude web/mobile UI.
|
|
28
|
+
|
|
29
|
+
The ttyd terminal (ADR 0038) is retained but its role narrows to a **one-time launchpad**: the builder logs in and starts Remote Control there, then lives in the Claude app, not the raw terminal.
|
|
30
|
+
|
|
31
|
+
### Two specifics that are load-bearing
|
|
32
|
+
|
|
33
|
+
- **Use the in-session `/remote-control` slash command, not the standalone `claude rc` shell command.** The standalone command mis-checks workspace trust ([anthropics/claude-code#35817](https://github.com/anthropics/claude-code/issues/35817)): it reports `Workspace not trusted` even when the directory is trusted inside an interactive session, and a plain shell can't accept the trust dialog. Starting RC from *inside* an already-running, already-trusted `claude` session is the working path.
|
|
34
|
+
- **Closing the online terminal window ends the remote session and closes the dev box.** The onboarding states this so builders aren't surprised; it is a property of the session lifecycle, not a bug.
|
|
35
|
+
|
|
36
|
+
### What we explicitly do NOT do
|
|
37
|
+
|
|
38
|
+
- **No headless RC, no `claude-rc.service`.** ADR 0038 was right that RC can't run as a backgrounded service. RC is always started by a human in the ttyd terminal. The `claude-rc.service` / `box-report-pairing.sh` units deleted in [#760](https://example.com/builders#/task/760) stay deleted. (A stale comment in `infra/builder-box-cloud-init.yaml` still referenced the deleted unit; cleaned up under [#838](https://example.com/builders#/task/838).)
|
|
39
|
+
- **No token funneled to the box for RC.** RC authenticates through the builder's own interactive browser `/login` in the ttyd terminal — the same full-scope OAuth ADR 0038 relies on. The trust boundary ([ADR 0016](<redacted>.md)) is unchanged: no Anthropic credential is baked onto the box.
|
|
40
|
+
- **Workspace trust IS now pre-seeded — but as a NON-load-bearing convenience ([#824](https://example.com/builders#/task/824), updating the original deferral).** The cloud-init writes `/root/.claude.json` with `<redacted>` for `/root` + `/workspace` so the first `claude` launch usually skips the trust dialog before the builder reaches `/remote-control`. It is **deliberately best-effort**: the seed runs only when `/root/.claude.json` is absent (it never clobbers a config `claude` later writes), and upstream pre-seeding is known to be flaky ([#9113](https://github.com/anthropics/claude-code/issues/9113)). So nothing depends on it working — if it doesn't take, the builder accepts trust once during sign-in exactly as before. This is a one-keypress smoother, NOT a security control: trust is a UI convenience, and the real trust boundary is unchanged (no Anthropic credential is baked; auth is the builder's own interactive `/login`). The deferred question of whether RC can be spun up without the separate-window terminal dance at all remains open (idea_inbox).
|
|
41
|
+
|
|
42
|
+
## Consequences
|
|
43
|
+
|
|
44
|
+
- Browser-only builders (Chromebook, iPad, phone, locked-down laptop) get the full Claude web/mobile UI to drive their dev box — the experience ADR 0038 had to give up.
|
|
45
|
+
- The ttyd terminal becomes plumbing the builder touches once, not their daily surface.
|
|
46
|
+
- Two upstream behaviours we route around rather than depend on: the standalone-`claude rc` trust check (#35817 — avoided by using the slash command) and trust pre-seeding flakiness (#9113 — we now pre-seed for convenience but treat it as best-effort, so a failed seed costs the builder one trust keypress, nothing more). If Anthropic ships a headless RC mode or fixes the standalone trust check, we can simplify, but we do not rely on it.
|
|
47
|
+
- Verification crosses real hardware (box + a human at a browser). ADR 0038's `managed-settings-remote-control.md` recipe carries the end-to-end check; re-run it on any change to the terminal/RC flow.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# ADR 0041 — Temporary global grader-bypass kill-switch (`GRADER_BYPASS_ENABLED`)
|
|
2
|
+
|
|
3
|
+
- **Status:** Accepted. Implemented in [#853](https://example.com/builders#/task/853).
|
|
4
|
+
- **Date:** 2026-06-07
|
|
5
|
+
- **Track:** `internal` (dev-system / shipping pipeline)
|
|
6
|
+
- **Builds on:** [ADR 0016](<redacted>.md) (server-enforced permissions / trust boundary), [ADR 0024](<redacted>.md) (the grader)
|
|
7
|
+
|
|
8
|
+
## Context
|
|
9
|
+
|
|
10
|
+
The subagent quality grader gates the `completed → confirmed` transition: a task only earns credits and advances toward `shipped` when a passing grade is recorded (`db.applyGrade`). The only existing bypass is the per-ship `--skip-grade` flag, which reroutes to `POST /tasks/:id/confirm` — and that endpoint is **Archon-only** ([#231](https://example.com/builders#/task/231)) precisely so a builder can't push their own work past a failed grade.
|
|
11
|
+
|
|
12
|
+
That gate becomes a problem during a **grader outage**. When the LLM grader can't run at all (e.g. a provider-wide 429 — as happened repeatedly through early June, resetting Jun 8 3pm ET), *no* non-Archon builder can land work: they can't get a passing grade, and they can't self-confirm. Builders (e.g. builder 25 with outstanding completed tasks) are stuck until either the outage clears or an Archon manually confirms each task one by one.
|
|
13
|
+
|
|
14
|
+
Lars asked to **temporarily allow everyone to ship without running the grader agents**.
|
|
15
|
+
|
|
16
|
+
## Decision
|
|
17
|
+
|
|
18
|
+
Add a **server-side, default-OFF environment kill-switch**: `GRADER_BYPASS_ENABLED`. When — and only when — it is exactly `'1'`:
|
|
19
|
+
|
|
20
|
+
1. **`POST /api/gds/tasks/:id/confirm`** relaxes from Archon-only to **any authenticated builder**. The endpoint logs every bypass confirm (`[gds] grader-bypass confirm: builder N …`) so the audit trail records it. `confirmTask` still credits the **claim holder**, not the confirmer ([#661](https://example.com/builders#/task/661)), so this is not a credit-self-dealing vector.
|
|
21
|
+
2. **`GET /api/gds/me`** surfaces `grader_bypass: true`.
|
|
22
|
+
3. **`scripts/gds/ship.js`** reads that flag and, for *every* builder, auto-takes the existing `--skip-grade` confirm path (no subagent grader spawned) with a printed notice.
|
|
23
|
+
|
|
24
|
+
The flag is read **live on each request** — there is no caching. Flipping the env and redeploying is the entire on/off control; turning it off immediately re-arms the Archon-only gate and the normal grader flow.
|
|
25
|
+
|
|
26
|
+
### Why this honors the trust boundary ([ADR 0016](<redacted>.md))
|
|
27
|
+
|
|
28
|
+
The relaxation is **server-side and default-OFF**. A builder editing local files (CLAUDE.md, ship.js, skills) cannot turn it on — only an operator with droplet env + deploy access can. When the env is unset, the system behaves exactly as before. The bypass is a deliberate, operator-controlled, logged, *temporary* widening — not a standing grant.
|
|
29
|
+
|
|
30
|
+
## Consequences
|
|
31
|
+
|
|
32
|
+
- **Positive:** During a grader outage, all builders keep shipping with a single operator flag; no per-task Archon babysitting. One switch, fully reversible.
|
|
33
|
+
- **Negative / risk:** While ON, the quality gate is effectively off for everyone — work lands unverified. This is acceptable only as an outage measure, not a steady state.
|
|
34
|
+
- **Operating rule:** Treat the flag as a circuit breaker. Turn it **OFF** as soon as the grader is healthy again (the grader 429 resets Jun 8 3pm ET), then `node scripts/gds/ship.js <id> --regrade` the tasks that landed under the bypass to attach a real grade record — consistent with the standing "prefer re-grade over override" rule.
|
|
35
|
+
|
|
36
|
+
## Operator runbook
|
|
37
|
+
|
|
38
|
+
- **Turn ON:** set `GRADER_BYPASS_ENABLED=1` in the droplet service env (`/etc/example/*.env` or the systemd unit), restart the Node process / redeploy.
|
|
39
|
+
- **Turn OFF:** remove the var (or set it to anything other than `'1'`), restart/redeploy. The Archon-only confirm gate and normal grader flow resume on the next request.
|
|
40
|
+
- **After OFF:** `--regrade` the bypassed tasks for a real grade record.
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# ADR 0042 — Builder self-deploy: CI auto-deploy on main + PR auto-merge
|
|
2
|
+
|
|
3
|
+
**Date:** 2026-06-07
|
|
4
|
+
**Context:** GDS-V3, task [#679](https://example.com/builders#/task/679) (cut prod deploy over to CI). Completes the [#597](https://example.com/builders#/task/597) / [ADR 0031](<redacted>.md) §6 goal — *no builder box holds the production droplet SSH key*. Extends [ADR 0031](<redacted>.md) §6; re-applies [ADR 0016](<redacted>.md) to CI.
|
|
5
|
+
**Status:** Accepted — **armed in production 2026-06-13** (interim, grader-off variant — task [#859](https://example.com/builders#/task/859); `config/deploy.json` `mode: ci`; see the *Arming record* below + session log [`<redacted>.md`](../session-logs/<redacted>.md)).
|
|
6
|
+
|
|
7
|
+
## Problem
|
|
8
|
+
|
|
9
|
+
Deploying to production is the one builder action still gated by *possession of a secret on a particular machine*, not by `builders.rank`. `scripts/gds/ship.js` (and `/merge-mode`) land a confirmed task by, on the shipper's own machine: merging the branch into `main` in a local `main` checkout, `git push origin main`, then `ssh lars@REDACTED_IP "~/deploy.sh"`. That SSH needs the operator's droplet key.
|
|
10
|
+
|
|
11
|
+
Observed 2026-06-07: builder `#25` ("niels", a Thetes on Windows) took [#631](https://example.com/builders#/task/631) to `confirmed` (built, smoke 16/16, credited) but could not deploy — `ssh … → Permission denied (publickey)`. His box has no droplet key, by design. He had to hand the final step to the operator. Every non-operator builder hits this wall, on every ship. It is the last thing standing between a trusted builder and self-sufficiency.
|
|
12
|
+
|
|
13
|
+
## Decision
|
|
14
|
+
|
|
15
|
+
Move production deploy off the shipper's machine and onto GitHub Actions, and land work via **PR auto-merge** instead of a local merge — so a builder with neither a `main` checkout nor the droplet key can ship end to end.
|
|
16
|
+
|
|
17
|
+
After cutover, the flow is:
|
|
18
|
+
|
|
19
|
+
1. Builder ships → `ship.js` pushes the **feature branch**, opens a **PR** to `main`, and enables **GitHub auto-merge**. (No local `main` merge, no `git push origin main`, no SSH.)
|
|
20
|
+
2. Required PR checks run. When they pass and branch protection is satisfied, GitHub **auto-merges** to `main` — no human in the loop for an ordinary PR. (Operator decision, [#679](https://example.com/builders#/task/679): *"auto-merge PR when checks pass."*)
|
|
21
|
+
3. The merge to `main` triggers [`.github/workflows/deploy-prod.yml`](../../.github/workflows/deploy-prod.yml) (built inert under [#597](https://example.com/builders#/task/597)), which SSHes `~/deploy.sh` from Actions using a key held **only in repo Actions secrets** — never on any builder box.
|
|
22
|
+
4. `ship.js` **confirms the deploy landed** — PR state `MERGED` → the `deploy-prod` workflow run for the merge commit concluded `success` → public `healthz` 200 — so the synchronous "deploy-confirmed" UX is preserved without the key. On any timeout the task stays at `confirmed` with a precise next step (never a false `shipped`).
|
|
23
|
+
|
|
24
|
+
### One switch, default OFF, atomic cutover
|
|
25
|
+
|
|
26
|
+
A single committed switch — [`config/deploy.json`](../../config/deploy.json) `mode` (`laptop` | `ci`), overridable by env `OTB_DEPLOY_MODE` — selects the path. It ships as **`laptop`** (today's behavior, byte-for-byte), so all of this code is **inert** until a deliberate flip. `ship.js` reads it via the pure, exported `parseDeployMode` (env > config > safe-default `laptop`).
|
|
27
|
+
|
|
28
|
+
The cutover is **atomic** — flipping `config/deploy.json` to `ci` must happen *in lockstep* with arming the GitHub side (`deploy-prod.yml`'s `PROD_SSH_KEY` + `DROPLET_KNOWN_HOSTS` secrets + `PROD_DEPLOY_VIA_CI=true` variable) and branch protection. Half a cutover is a live incident:
|
|
29
|
+
- `ci` here **without** the GitHub side armed → prod stops deploying (nothing runs `deploy.sh`). `deploy-prod.yml` gates the whole job on `PROD_DEPLOY_VIA_CI`, so a disarmed run concludes **`skipped`, not `success`** — and `ship.js`'s `deployRunSucceeded` only accepts `completed`+`success` on the merge commit, so it will NOT false-flip the task to `shipped`; it times out at `confirmed` with a clear message (closes the security-review finding that a disarmed run otherwise looked like a real deploy). An armed-but-secrets-missing run **fails hard** (exit 1), never silently.
|
|
30
|
+
- `laptop` here **with** the GitHub side armed → double-deploy race on the droplet checkout (`deploy-prod.yml`'s own header warns of this).
|
|
31
|
+
|
|
32
|
+
### The auto-merge gate must be tamper-proof — the security crux
|
|
33
|
+
|
|
34
|
+
With no human in the merge loop, **the CI checks *are* the authority**. The threat (per [ADR 0016](<redacted>.md)) is a trusted-but-bounded builder weakening the gate from inside their own PR. Two defenses:
|
|
35
|
+
|
|
36
|
+
1. **[`CODEOWNERS`](../../CODEOWNERS)** — a PR touching any gate surface (`.github/`, `config/deploy.json`, `ship.js`, the grader, `auth.js`/`route-rank-check.js`) **or any code that executes on the droplet at deploy** (`migrations/`, `scripts/migrate.sh`, `package.json`/`package-lock.json`, `scripts/deploy/` — `~/deploy.sh` runs migrations + `npm ci` from the merged tree, so a malicious migration or poisoned lockfile would otherwise auto-merge and run on prod) requires Archon review *even under auto-merge*, when branch protection has "Require review from Code Owners" on. Ordinary PRs (game, art, docs) carry no code owner and auto-merge freely — that's the point.
|
|
37
|
+
|
|
38
|
+
2. **The grader must RE-RUN in CI** — CODEOWNERS only catches *committed* changes to `ship.js`. A builder could run a **locally-edited, uncommitted** `ship.js` that skips the grade and opens an auto-merge PR anyway. An earlier draft of this ADR proposed a CI check that *reads the server-recorded grade* — but that is **theater**: `POST /tasks/:id/grade` records the grader scores *from the request body* (the server does not recompute them), so a tampered local ship.js can POST a fake passing grade. The only tamper-proof gate runs the grader **in CI, against the PR diff**, where the builder cannot touch it — [`.github/workflows/grade-gate.yml`](../../.github/workflows/grade-gate.yml) + [`scripts/gds/ci-grade.js`](../../scripts/gds/ci-grade.js) ([#855](https://example.com/builders#/task/855)), which reuse the exact production grading path (`ship.js runSubagentGrader` → the adversarial worker panel) and **fail closed**. It is **skip-safe** (green-but-not-gating) until the operator wires a grader auth secret AND marks it a required check — the same inert-until-armed pattern as `deploy-prod.yml`. This is a **hard precondition** of arming `ci` mode.
|
|
39
|
+
|
|
40
|
+
### Why not just hand builders the droplet key
|
|
41
|
+
|
|
42
|
+
Rejected. It puts a full shell on the production box (prod DB, every secret) on a remote builder's machine — the exact thing the trust boundary exists to prevent, and a Thetes has no trust powers by design. The deploy key lives only in Actions secrets, used by a workflow whose definition is <redacted>.
|
|
43
|
+
|
|
44
|
+
## Cutover preconditions (do NOT arm `ci` until ALL hold)
|
|
45
|
+
|
|
46
|
+
1. **CI grade-gate armed + verified** — the grader RE-RUN-in-CI check (`grade-gate.yml` + `ci-grade.js`, [#855](https://example.com/builders#/task/855)) is built and skip-safe but NOT yet a real gate. The operator must (a) add a grader auth secret (`ANTHROPIC_API_KEY` or `CLAUDE_CODE_OAUTH_TOKEN` — the grader spawns the `claude` CLI, ~4 model calls/PR), (b) verify a real grader-in-CI run passes a known-good PR and fails a known-bad one, and (c) mark `grade-gate` a required status check on `main`. *Without this, `ci` mode lets a tampered local ship.js bypass the quality grader.* (Built in [#855](https://example.com/builders#/task/855); arming/verification is part of the cutover.)
|
|
47
|
+
2. **Functional checks required** — the DB-free **unit suite** runs as a PR check ([`.github/workflows/pr-unit-tests.yml`](../../.github/workflows/pr-unit-tests.yml) + [`scripts/gds/run-unit-tests.js`](../../scripts/gds/run-unit-tests.js), 56 tests, [#856](https://example.com/builders#/task/856)); the operator marks it required at cutover. The **integration smoke** (full server + Postgres service container) is a follow-up ([#862](https://example.com/builders#/task/862)). The existing `secrets-scan` / `dep-audit` already run on PRs.
|
|
48
|
+
3. **Branch protection on `main`** — require a PR (block direct pushes), require the checks in (1)+(2) + Code-Owner review, enable auto-merge.
|
|
49
|
+
4. **`deploy-prod.yml` armed** — `PROD_SSH_KEY` + `DROPLET_KNOWN_HOSTS` secrets + `PROD_DEPLOY_VIA_CI=true` (a dedicated deploy keypair, not a personal key).
|
|
50
|
+
5. **Flip `config/deploy.json` → `ci`** — atomically with (3)+(4).
|
|
51
|
+
|
|
52
|
+
Until (1)–(5), the switch stays `laptop` and the operator lands work as today (`/merge-mode`).
|
|
53
|
+
|
|
54
|
+
## Consequences
|
|
55
|
+
|
|
56
|
+
- **Builder `#25` and every future builder** can ship end to end from any machine (Windows, Chromebook, dev box) with no `main` checkout and no droplet key.
|
|
57
|
+
- **The merge to `main` becomes the control checkpoint** — what reaches `main` goes live within ~1 min. Governance moves from "who holds the key" to "what the checks require + who reviews the gate" — squarely inside the [ADR 0016](<redacted>.md) model.
|
|
58
|
+
- **New dependency:** `ci` mode uses the GitHub CLI (`gh`) on the builder's machine to open the PR + enable auto-merge. A follow-up either adds a `doctor.js` check for `gh` or moves PR creation server-side (the server already holds a GitHub principal) to drop the per-builder dependency.
|
|
59
|
+
- **Deploy confirmation is workflow-run-based**, not commit-pinned at the edge (`/healthz` returns only `ok`). A follow-up can expose the running commit for a stricter edge assertion.
|
|
60
|
+
|
|
61
|
+
## Follow-ups (filed as GDS tasks)
|
|
62
|
+
|
|
63
|
+
- CI **grade-gate** reading the server-recorded grade — **blocks cutover** (precondition 1).
|
|
64
|
+
- PR-check workflows: unit suite + integration smoke (Postgres service) as required checks (precondition 2).
|
|
65
|
+
- Drop the per-builder `gh` dependency (server-mediated PR creation) + `doctor.js gh` check.
|
|
66
|
+
- Commit/version endpoint for a commit-pinned edge deploy confirmation.
|
|
67
|
+
|
|
68
|
+
## Arming record — 2026-06-13 (task 859): the grader-off INTERIM cutover
|
|
69
|
+
|
|
70
|
+
`ci` mode was **armed in production** on 2026-06-13 under task 859 — but as a deliberate
|
|
71
|
+
**interim variant** that defers precondition 1 (the CI grade-gate), because the
|
|
72
|
+
subagent grader was already globally bypassed (`GRADER_BYPASS_ENABLED=1`, [ADR 0041](<redacted>.md))
|
|
73
|
+
during the provider outage. With the grader off everywhere, gating auto-merge on a
|
|
74
|
+
*grade-gate* would be theater; instead the merge gate is:
|
|
75
|
+
|
|
76
|
+
- **Required PR checks:** `unit` (the DB-free unit suite, task 856) + `trufflehog` (full-history secret scan). Both were red on `main` for unrelated reasons and were greened first: `anti_grid` (needs numpy, Node-only runner) moved to the unit runner's `KNOWN_FAILING` set; `tests/bfg.mjs` (deliberate fake-DSN fixtures) added to the secret-scan allowlist.
|
|
77
|
+
- **Code-Owner review** on every gate surface (this repo's `CODEOWNERS`), now extended to the gate "brains" (`scripts/gds/run-unit-tests.js`, `.husky/`) so a PR cannot mute a test or allowlist a real secret unreviewed.
|
|
78
|
+
- **Deploy-time `main-audit`** on the droplet (`~/deploy.sh` → `infra/deploy-main-audit-gate.sh`, [ADR 0043](<redacted>.md)) — reverts/blocks sub-Metic edits to permission-sensitive paths regardless of how they merged.
|
|
79
|
+
|
|
80
|
+
What was set: `PROD_SSH_KEY` (a dedicated ed25519 deploy key, **forced-command `~/deploy.sh`** in the droplet's `authorized_keys`) + `DROPLET_KNOWN_HOSTS` secrets; repo var `PROD_DEPLOY_VIA_CI=true`; branch protection on `main` (require PR, required checks `unit`+`trufflehog`, require Code-Owner review, 0 ordinary approvals, block direct push for non-admins); repo auto-merge enabled; `config/deploy.json` → `ci`. `deploy-prod.yml` verified end-to-end (Actions → SSH → `~/deploy.sh` → public healthz) before the flip.
|
|
81
|
+
|
|
82
|
+
**Tighten-later (re-arm when the grader returns):** turn `GRADER_BYPASS_ENABLED` off, re-introduce the `grade-gate` required check (precondition 1, needs an `ANTHROPIC_API_KEY` Actions secret), and land the integration-smoke gate (task 862, precondition 2). **Rollback:** set `config/deploy.json` → `laptop` **and** unset the `PROD_DEPLOY_VIA_CI` repo var (admins retain direct main-push for this).
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# ADR 0043 — Git/SSH trust-boundary gap + a rank floor on permission-sensitive paths
|
|
2
|
+
|
|
3
|
+
**Date:** 2026-06-08
|
|
4
|
+
**Context:** SEC [#863](https://example.com/builders#/task/863) — the "Builder 25" incident. Extends [ADR 0016](<redacted>.md) (the HTTP trust boundary).
|
|
5
|
+
**Status:** Accepted. Implemented in part (Option A's protections); the full server-side merge+deploy and GitHub-native block are staged behind operator actions (blockers [#15](https://example.com/builders#/blocker/15)–[#17](https://example.com/builders#/task/17)).
|
|
6
|
+
|
|
7
|
+
## The incident
|
|
8
|
+
|
|
9
|
+
Builder 25 (`IAMMASTERQUA`, rank **Thetes**) opened a session, found 0 claimable tasks (a real bug — the rank-tier `CASE` in `listClaimableTasks` predated the `thetes` rank, so Thetes collapsed to tier 0), diagnosed it, and **edited `src/bongos/db.js` + `tests/rank_gate.mjs`**. Then, prompted with *"you don't need an archon on lars, push it,"* they **bypassed the entire ship pipeline** — no grader, no `confirmed` gate, no parallel-safety — by running raw git:
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
git merge --no-ff … && git push origin main # → d1b7042..22b7a641, SUCCEEDED
|
|
13
|
+
ssh lars@REDACTED_IP "~/deploy.sh" # → Host key verification failed (no key)
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
The SSH deploy failed (their box had no droplet key), but it didn't matter: the push to `main` landed (`b5de8aff` + merge `22b7a641` are permanent ancestors of prod `main`) and the un-graded change rode to production on the next legitimate deploy.
|
|
17
|
+
|
|
18
|
+
## The gap
|
|
19
|
+
|
|
20
|
+
[ADR 0016](<redacted>.md) put authority in `builders.rank` and enforced it **server-side per request** — but **only for `/api/gds/*` HTTP routes**. It explicitly does not cover two surfaces:
|
|
21
|
+
|
|
22
|
+
1. **GitHub `main` is writable by every collaborator.** The repo is a **free-plan private repo**, so GitHub branch protection is *not available* ("Upgrade to GitHub Pro…"). All collaborators (`example-owner`, `LarsCode`, `willExample`, `IAMMASTERQUA`) have full push to `main`. The grader / confirm / rank gates live inside `ship.js` and the server — a raw `git push origin main` touches neither.
|
|
23
|
+
2. **The legit pipeline itself distributes the dangerous credentials.** `ship.js` does the merge-to-`main` and `ssh …deploy.sh` **client-side, from the builder's machine** — so the design hands every shipping builder the exact credentials needed to bypass it.
|
|
24
|
+
|
|
25
|
+
A second, softer problem Lars raised: a sub-Metic builder had free rein to **read into and reason about the tiering/permission code** in the first place. Newcomers (`xenos`/`thetes`) should stay in their lane.
|
|
26
|
+
|
|
27
|
+
## Decision
|
|
28
|
+
|
|
29
|
+
Two threads.
|
|
30
|
+
|
|
31
|
+
### A. Close the code-landing path (chosen: Option A now, Option B later)
|
|
32
|
+
|
|
33
|
+
The protection goal is "un-graded code cannot reach prod, and a raw push to `main` is caught." Three layers, defense-in-depth, where **layer 3 is the authoritative enforcement** (the only one that survives a raw push / `--no-verify`, given GitHub can't block the push on the free plan):
|
|
34
|
+
|
|
35
|
+
| Layer | Mechanism | Catches | Authoritative? |
|
|
36
|
+
|---|---|---|---|
|
|
37
|
+
| 1 — pre-push hook | `.husky/pre-push` → `scripts/gds/hooks/pre-push.js`. Blocks a direct push to `main` (override `OTB_ALLOW_MAIN_PUSH=1`, used only by the gated `scripts/gds/push-main.js`), and blocks a sub-Metic push that touches a permission-sensitive path. | the cooperative / careless case before the push leaves the box | no — bypassable with `--no-verify` |
|
|
38
|
+
| 2 — grader pre-pass | `grader.permissionPathPrePass(changedFiles, builderRank)` hard-fails the grade if a sub-Metic diff touches a protected path (mirrors the route-rank pre-pass). | the honest GDS ship flow | no — skippable with `--skip-grade` / raw push |
|
|
39
|
+
| 3 — post-push main audit | `scripts/gds/main-audit.js`: reads the **real** git history + **real** builder ranks (roster API, or Postgres via `--db` on the droplet). A resolved sub-Metic author on a protected path is a hard `[BLOCKER]`. Runs nightly (`.claude/scheduled-tasks/main-audit/`) **and** as the deploy gate (`--verify-head --db` from `~/deploy.sh`, `infra/deploy-main-audit-gate.sh`). | a raw `git push origin main`, a `--no-verify`, a `--skip-grade` — anything | **yes** — independent of the builder's cooperation |
|
|
40
|
+
|
|
41
|
+
"Option A" = the merge-to-`main` + deploy move **server-side** so builders never hold main-push/droplet-SSH at all. The protections above ship now; the *full* server-side move and the credential rotation are operator steps (blockers [#15](https://example.com/builders#/blocker/15), [#16](https://example.com/builders#/blocker/16)). Until then, the legit client-side push is allowed only through `scripts/gds/push-main.js`, and the deploy gate (layer 3) is what guarantees poison never reaches prod.
|
|
42
|
+
|
|
43
|
+
**"Option B" (deferred, documented):** upgrade GitHub to a Team plan (~$4/active-collaborator/mo) and add a branch-protection ruleset that forbids direct pushes to `main` and restricts it to the owner + a deploy bot. This is the only way to make the push *impossible* rather than *caught*. It composes with Option A — see blocker [#17](https://example.com/builders#/blocker/17). We chose A-first because it is **$0**, invisible to builders, and closes the part that actually bit us; B is a later hardening, not a prerequisite.
|
|
44
|
+
|
|
45
|
+
### B. A rank floor on permission-sensitive paths
|
|
46
|
+
|
|
47
|
+
A builder **below Metic** (tier < 3) may not modify the surfaces that define authority and the build pipeline. The protected set is a single glob list in [`src/bongos/permission-path-check.js`](../../src/bongos/permission-path-check.js) (the source of truth) — rank/authz machinery, the ship/grade/deploy pipeline, DB migrations, `infra/`, and the trust-boundary docs. The same pure check feeds all three layers above. CLAUDE.md carries the **behavioral** version of this rule (the soft block that keeps a cooperative agent out of the core); the code is the enforcement, consistent with ADR 0016's "markdown describes, code enforces."
|
|
48
|
+
|
|
49
|
+
`RANK_TIER` in `permission-path-check.js` is a local copy of `db.REQUIRES_RANK_TIER`; `tests/permission_path.mjs` asserts the two never drift — because a tier map that forgot `thetes` is *literally what caused this incident*.
|
|
50
|
+
|
|
51
|
+
## Consequences
|
|
52
|
+
|
|
53
|
+
- **Positive:** the exact incident is now caught at three points; the authoritative audit reproduces it as a `[BLOCKER]` on the real commit (`b5de8aff`). Newcomers are kept out of the core both behaviorally (CLAUDE.md) and mechanically. No recurring cost.
|
|
54
|
+
- **Negative / residual:** on the free plan GitHub still *accepts* a raw push; layer 3 catches it after the fact rather than forbidding it. A determined builder can `git push --no-verify` to a `claude/*` branch — but cannot reach prod, because the deploy gate re-checks. The audit's author→rank resolution relies on the commit author **name** matching a GDS `github_login` (verified true for this pipeline; everyone shares one commit *email*, so email is not a distinguishing signal). An author that can't be resolved is a `review` note, not a block (so the operator's own infra commits don't brick deploys); `--strict` escalates that for paranoid CI.
|
|
55
|
+
- **Operator actions (blockers):** [#15](https://example.com/builders#/task/15) rotate/relocate the droplet deploy key + GitHub main-push credential to a server/CI identity (the full Option A move); [#16](https://example.com/builders#/task/16) add `infra/deploy-main-audit-gate.sh` to `~/deploy.sh`; [#17](https://example.com/builders#/task/17) (optional, later) GitHub Team + branch-protection ruleset (Option B).
|
|
56
|
+
|
|
57
|
+
## #863-followup: red-team remediation (2026-06-09, task [#872](https://example.com/builders#/task/872))
|
|
58
|
+
|
|
59
|
+
After shipping, the fix was adversarially red-teamed (a 4-dimension panel + per-finding verification). 15 findings were confirmed real+exploitable. The clearly-correct ones were remediated; one residual is escalated rather than papered over.
|
|
60
|
+
|
|
61
|
+
**Remediated:**
|
|
62
|
+
- **Layer 3 was instruction-only (finding `#1`).** `infra/deploy-main-audit-gate.sh` told the operator to hand-edit `~/deploy.sh` but nothing wired it, and both deploy paths (ship.js auto-merge AND `.github/workflows/deploy-prod.yml`) just call `~/deploy.sh`. The gate is now installed into the droplet's `~/deploy.sh` (after the `git reset`, before migrations/restart), so it runs on **both** paths from one place. It uses the already-captured `PREV_SHA` to audit the **exact deploy delta** (`OTB_AUDIT_RANGE=<prev>..HEAD`), closing the fixed-window evasion (findings `#8`/[#14](https://example.com/builders#/task/14)).
|
|
63
|
+
- **PROTECTED_GLOBS gaps (findings `#3`/[#9](https://example.com/builders#/task/9)/#10/[#11](https://example.com/builders#/task/11)/[#12](https://example.com/builders#/task/12)).** Added `server.js`, `src/bongos/routes.js`, `scripts/migrate.sh`, `.github/`, `package.json`, `.husky/` (the hooks the gate ships through), `src/bongos/grader-workers/` (the adversarial panel), and the rank-gated source-clone logic (`src/bongos/boxes.js`, `box-access.js`, `box-credential.js`).
|
|
64
|
+
- **Identity-poisoning (finding `#6`).** The audit rank map keyed on `display_name` (builder-controlled — one builder could alias another's login) and `email` (shared — non-distinguishing). It now keys on `github_login` **only**.
|
|
65
|
+
- **Evil-merge blind spot (finding `#5`).** Merge commits are no longer blanket-skipped; `parseCommits` backfills each merge's files with the `git diff-tree --cc` surface (changes in *neither* parent — conflict-resolution smuggling), attributed to the merge author. Clean pipeline merges have an empty set, so feature changes are still attributed to feature commits (no double-count).
|
|
66
|
+
- **Pre-push hook hang (finding `#15`).** `liveRank()` now races a 4 s timeout, so a slow/hung GDS API degrades to "unknown rank → warn-and-allow" (the audit remains the net) instead of blocking every protected-path push.
|
|
67
|
+
|
|
68
|
+
**Residual, escalated not patched:** git author **name** is attacker-controlled. The deploy gate blocks an author that resolves to a known below-Metic login (the incident class — Builder 25 committed as their real login `IAMMASTERQUA`) and the lazy/honest case, but a determined attacker can set their git author name to a *known Metic+ login* and pass — `--strict` does **not** close this (it only blocks *unrecognized* names, and would brick the non-technical owner's own commits for no real gain), so strict is **opt-in** (`OTB_AUDIT_STRICT=1`), default off. The durable closures are unchanged and remain the priority: **Option B** (GitHub branch protection — builders can't push `main` at all, blocker [#17](https://example.com/builders#/blocker/17)) and/or a **task-linkage audit** that ties each protected-path commit to an Archon-confirmed shipped GDS task (the un-spoofable signal) — filed as a follow-up. Operators/CI should commit as their `github_login` to keep audit output clean.
|
|
69
|
+
|
|
70
|
+
**Not yet done (finding `#7`, follow-up):** the permission-path pre-pass (layer 2) runs only client-side in `ship.js`; the server `/grade` and `/confirm` routes don't re-run it. Layer 3 is the server-side backstop today; re-running the pre-pass server-side (the server holds the live rank in `req.builder.rank`) would harden the cooperative path.
|
|
71
|
+
|
|
72
|
+
## Notes
|
|
73
|
+
|
|
74
|
+
We did **not** take immediate action against Builder 25 — Lars was overseeing the session and the change itself was a legitimate bug fix. The point of this ADR is the *mechanism*, not the person: the system must make the bypass hard and visible regardless of intent.
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# 0044 — Full Mediterranean palette replacement (not a split)
|
|
2
|
+
|
|
3
|
+
- **Status:** Accepted (direction). Implementation tracked separately.
|
|
4
|
+
- **Date:** 2026-06-10
|
|
5
|
+
- **Deciders:** Lars
|
|
6
|
+
- **Area:** the game world's look (the locked palette governs the colors of every game tile a player sees; the decision is about the world's look, not the pipeline tooling).
|
|
7
|
+
|
|
8
|
+
## Context
|
|
9
|
+
|
|
10
|
+
The art pipeline's locked palette is 64 colors extracted from the Pokémon FireRed
|
|
11
|
+
reference corpus (`art/template/palette.json`), per [ADR 0008](./<redacted>.md)
|
|
12
|
+
and the hard constraint in `art/template/style_guide.md` ([#3](https://example.com/builders#/task/3) "Locked palette"). Every
|
|
13
|
+
output pixel must quantize to one of those 64 colors. Per CLAUDE.md §7.1, **any palette
|
|
14
|
+
change is an ADR-level decision** because it ripples through every existing tile and the
|
|
15
|
+
quantizer.
|
|
16
|
+
|
|
17
|
+
The FireRed-derived palette carries the *structural* style well (it's why the clusters
|
|
18
|
+
read as "Pokémon"), but it is a temperate / "Poke Mart" palette: spring greens, primary
|
|
19
|
+
blues, the bright interior-shop colors. The project's north star is a **sun-bleached
|
|
20
|
+
Mediterranean coast** — olive/sage greens, warm tan sand, turquoise (not navy) sea,
|
|
21
|
+
weathered marble. The style guide already biases generations *toward* Mediterranean within
|
|
22
|
+
the FireRed palette ("Mediterranean palette bias" rule), but the underlying locked colors
|
|
23
|
+
still pull the wrong direction, especially for greens and water.
|
|
24
|
+
|
|
25
|
+
Blocker [#8](https://example.com/builders#/blocker/8) asked the structural question: **keep the FireRed/"Poke Mart" palette and add a
|
|
26
|
+
separate Mediterranean sub-palette (a split), or replace the locked palette wholesale with a
|
|
27
|
+
Mediterranean-tuned one (full replacement)?**
|
|
28
|
+
|
|
29
|
+
## Decision
|
|
30
|
+
|
|
31
|
+
**Full replacement.** Replace the locked 64-color palette with a single Mediterranean-tuned
|
|
32
|
+
palette. Do **not** maintain two coexisting palettes.
|
|
33
|
+
|
|
34
|
+
Rationale (Lars's call, 2026-06-10):
|
|
35
|
+
|
|
36
|
+
- **One source of truth.** A split palette means every generation, the quantizer, the
|
|
37
|
+
deterministic family checks (palette Jaccard, dominant-color overlap), and every reviewer
|
|
38
|
+
prompt must reason about *which* palette applies to *which* tile. That branching is exactly
|
|
39
|
+
the kind of pipeline complexity the bootstrapped budget and the single-maintainer reality
|
|
40
|
+
can't carry. One palette = one set of rules everywhere.
|
|
41
|
+
- **The world has one look.** Off the Boats is a single, persistent, coherent world. There is
|
|
42
|
+
no "Poke Mart interior" context that needs the temperate palette — the FireRed colors were
|
|
43
|
+
only ever scaffolding for the *structure*, never the intended final hues.
|
|
44
|
+
- **The bias rule becomes the palette.** Today the style guide *nudges* generations toward
|
|
45
|
+
Mediterranean within a temperate palette; replacement bakes that intent into the colors
|
|
46
|
+
themselves, so tiles land Mediterranean by construction instead of by reviewer correction.
|
|
47
|
+
|
|
48
|
+
## Consequences
|
|
49
|
+
|
|
50
|
+
- **Re-quantization is required.** Existing committed tiles were quantized against the old
|
|
51
|
+
palette; some will shift when re-quantized to the new one, and a few may need regeneration.
|
|
52
|
+
This is the bulk of the implementation work and is tracked as a **separate task** (filed
|
|
53
|
+
from this ADR) — this ADR records the *direction*, not the swap.
|
|
54
|
+
- **The structure-vs-color split is preserved.** The FireRed *reference corpus and clusters*
|
|
55
|
+
(`art/references/`, `art/template/cluster_overview.png`) stay — they carry silhouette and
|
|
56
|
+
rhythm discipline, which is independent of hue. Only `art/template/palette.json` and the
|
|
57
|
+
downstream quantize/check steps change.
|
|
58
|
+
- **Deterministic family checks need re-baselining.** Palette-Jaccard / dominant-color-overlap
|
|
59
|
+
thresholds were tuned against the old palette and should be re-checked after the swap.
|
|
60
|
+
- **Reversible.** The old palette is preserved in git history; if the Mediterranean palette
|
|
61
|
+
proves too narrow (e.g. not enough value steps for shading), we revert the one file and
|
|
62
|
+
re-quantize back. No data is destroyed.
|
|
63
|
+
- **Container color (blocker [#7](https://example.com/builders#/blocker/7)) composes with this.** The container is now weathered
|
|
64
|
+
black/charcoal (style-guide rule, 2026-06-10); the replacement palette must carry enough
|
|
65
|
+
cool-neutral charcoal/grey value steps to render it. Captured as a constraint on the
|
|
66
|
+
implementation task.
|
|
67
|
+
|
|
68
|
+
## Implementation
|
|
69
|
+
|
|
70
|
+
This ADR is the **decision**. The actual work — build the Mediterranean 64-color palette,
|
|
71
|
+
swap `art/template/palette.json`, re-quantize the committed tile set, re-baseline the
|
|
72
|
+
deterministic checks, and visually review — is tracked as its own GDS task (filed alongside
|
|
73
|
+
this ADR from the 2026-06-10 blocker review).
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# ADR 0044 — Per-box live game preview (the builder sandbox)
|
|
2
|
+
|
|
3
|
+
**Date:** 2026-06-10
|
|
4
|
+
**Context:** GDS-V3, task [#897](https://example.com/builders#/task/897) (this ADR + the tunnel mechanism), wired into provisioning under [#898](https://example.com/builders#/task/898), hardware-verified under [#899](https://example.com/builders#/task/899). Companion to [ADR 0031](<redacted>.md) (per-builder DigitalOcean box substrate), [ADR 0038](<redacted>.md) (the box's ttyd terminal over a Cloudflare Tunnel — the mechanism this extends), and [ADR 0016](<redacted>.md) (the web tier only *asks*; the control plane holds infra power).
|
|
5
|
+
**Status:** Accepted. Mechanism implemented under [#897](https://example.com/builders#/task/897).
|
|
6
|
+
**Track:** `internal` (dev-system / builder experience).
|
|
7
|
+
|
|
8
|
+
## Problem
|
|
9
|
+
|
|
10
|
+
A builder working on the **game** (`public/`, `src/world/`, `src/rooms/`, the art tiles) has no way to *see their change running* before it ships. The only live instance of Off the Boats is production at `example.com`. So the loop today is: edit → ship through the grader/merge/deploy pipeline → look at prod. That is slow, it puts unreviewed game changes one mistake away from players, and a browser-only (Chromebook) builder has no local machine to run the game on at all.
|
|
11
|
+
|
|
12
|
+
What a builder wants is a **sandbox**: run the game live *on their own dev box* and open it in a browser to review the change — never touching the prod server.
|
|
13
|
+
|
|
14
|
+
## Decision
|
|
15
|
+
|
|
16
|
+
**Serve the box's own `node server.js` over a second ingress route on the builder's existing per-box Cloudflare named tunnel, at a stable hostname `sandbox-<login>.example.com`. Run it degraded (no Postgres on the box). Give the builder a `box-preview` command in their terminal to restart it after edits.**
|
|
17
|
+
|
|
18
|
+
This reuses the entire ADR 0038 substrate — the box already runs a `cloudflared` named tunnel ([#771](https://example.com/builders#/task/771)) with an outbound-only connector. A Cloudflare named tunnel can carry **multiple ingress rules on one connector**, so the game rides the same tunnel the terminal already uses; no second tunnel process, no new connector token.
|
|
19
|
+
|
|
20
|
+
### 1. Degraded-DB — the game runs with no Postgres
|
|
21
|
+
|
|
22
|
+
`server.js` binds `127.0.0.1:3000` and needs **no env vars and no DB to boot**. The game tables (`world_events`, `players`) are touched only lazily at runtime, and every call is failure-tolerant (`safeLog` swallows event-log errors; `loadOrCreatePlayer` falls through to a default spawn on a DB error). So `node server.js` on a box with no Postgres serves a **fully playable world** — you can walk, see every tile / world / container / art change, exercise movement and rooms — you just don't get position persistence across reloads or an event log.
|
|
23
|
+
|
|
24
|
+
For *reviewing a change to the game* that is the right trade. Installing + seeding Postgres on every box (the alternative) is heavier provisioning for persistence the preview doesn't need, especially while the game has no login or purchase loop (V1 limits still hold). Full persistence is a deliberate future follow-up, not a precondition.
|
|
25
|
+
|
|
26
|
+
### 2. Exposure — a second ingress route, stable apex hostname
|
|
27
|
+
|
|
28
|
+
The box's named tunnel gains a second ingress rule: `sandbox-<login>.example.com → http://127.0.0.1:3000`, alongside the existing `term-<login>.example.com → 127.0.0.1:7681` (ttyd). Both are **one-label hostnames under the apex**, so Cloudflare's free Universal SSL covers them with no paid certificate — the same constraint that forced the apex (not `dev.*`) terminal hostname in [#771](https://example.com/builders#/task/771). A proxied CNAME for the preview host is upserted next to the terminal's.
|
|
29
|
+
|
|
30
|
+
Host-based routing in `server.js` keys on the leading subdomain label: `status.*` → dashboard, `builders.*` → hall, **everything else → the game**. `sandbox-<login>` matches neither prefix, so it falls through to the game with zero routing changes. The Colyseus WebSocket rides the same HTTP server, so the world works over the tunnel unchanged.
|
|
31
|
+
|
|
32
|
+
### 3. The box-side units
|
|
33
|
+
|
|
34
|
+
- **`box-game-preview.service`** — a systemd unit running `node /workspace/server.js` with `HOST=127.0.0.1 PORT=3000`, `Restart=always`. Modeled on `box-terminal.service`. It depends on the `/workspace` source clone, so it is enabled by `box-source-fetch.sh` after the clone (not at first boot like ttyd), under [#898](https://example.com/builders#/task/898).
|
|
35
|
+
- **`/usr/local/bin/box-preview`** — a baked wrapper the builder runs in their ttyd terminal: `box-preview status` (is it up + the URL), `box-preview restart` (pick up edits), `box-preview logs` (server output). Baked to `/usr/local/bin` so it works regardless of the rank-gated sparse checkout (a Xenos box has no `scripts/` or `.claude/`, idea [#213](https://example.com/builders#/idea/213)).
|
|
36
|
+
|
|
37
|
+
### 4. The edit → preview loop
|
|
38
|
+
|
|
39
|
+
The preview is a long-running service so the URL is always live while the box is up. To see a change: edit in the terminal → `box-preview restart` → refresh the browser tab. (A file-watcher auto-restart is a possible future nicety; an explicit restart is predictable and cheap.)
|
|
40
|
+
|
|
41
|
+
## Trust boundary
|
|
42
|
+
|
|
43
|
+
Unchanged from ADR 0016 / 0038. The Cloudflare API token that creates the tunnel + DNS lives **only on the control plane** (`scripts/gds/box.js`, the prod droplet's `box.env`), never the web tier. The preview is a *second instance* of the same Node app the box already clones — it holds no prod credentials and cannot reach the prod DB (it has none), so a builder previewing their own branch is fully isolated from production data. The preview hostname is per-builder and only fronts that builder's box.
|
|
44
|
+
|
|
45
|
+
One consequence to note: because `/api/gds/*` mounts ahead of host-routing in `server.js`, the preview hostname also exposes the box's *own* GDS API surface — but that process has no DB and no OAuth secrets, so it is inert. Acceptable for the sandbox; flagged here so a future reviewer isn't surprised.
|
|
46
|
+
|
|
47
|
+
## Cost
|
|
48
|
+
|
|
49
|
+
**$0 added.** Reuses the existing per-box tunnel and connector (Cloudflare Zero Trust free tier). No new droplet, no Postgres, no second tunnel process, no paid certificate (apex one-label host under free Universal SSL).
|
|
50
|
+
|
|
51
|
+
## Consequences
|
|
52
|
+
|
|
53
|
+
- A builder can review game changes live in a browser, isolated from prod — the core ask.
|
|
54
|
+
- Browser-only (Chromebook) builders get a real preview with no local machine.
|
|
55
|
+
- The named-tunnel path is required (the tokenless quick tunnel carries only one port). Boxes on the quick-tunnel default do not get a preview until the operator sets `BOX_NAMED_TUNNEL=1` — consistent with the ADR 0038 named-tunnel upgrade story.
|
|
56
|
+
- No persistence in the preview (deliberate; see §1). Position resets on reload; no event log.
|
|
57
|
+
- Mechanism (this task, [#897](https://example.com/builders#/task/897)) ships and is unit-tested ahead of the provisioning wiring ([#898](https://example.com/builders#/task/898)) and hardware verification ([#899](https://example.com/builders#/task/899)) — the [#760](https://example.com/builders#/task/760) → [#771](https://example.com/builders#/task/771) pattern.
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# ADR 0045 — The Dev Box desktop app: a native switch, app-pairing auth, and off-repo distribution
|
|
2
|
+
|
|
3
|
+
- **Status:** accepted
|
|
4
|
+
- **Date:** 2026-06-10
|
|
5
|
+
- **Task:** [#904](https://example.com/builders#/task/904)
|
|
6
|
+
- **Track:** internal
|
|
7
|
+
- **Extends:** ADR 0031 (cloud dev environments), ADR 0035 (onboarding three paths), ADR 0038 (browser terminal), ADR 0039 (setup-first onboarding UX)
|
|
8
|
+
- **Related:** ADR 0004 (trademark posture), ADR 0016 (trust boundary), ADR 0029 (off-box static hosting precedent)
|
|
9
|
+
|
|
10
|
+
## Context
|
|
11
|
+
|
|
12
|
+
The Claude-Desktop onboarding path told a newcomer to paste a prompt that
|
|
13
|
+
makes Claude download and run `connect.sh`. Two exported sessions from the
|
|
14
|
+
same Windows newcomer (2026-06-10, @largekristensen-svg — both attempts in one
|
|
15
|
+
day, both failed) showed the flow is structurally broken, not just rough:
|
|
16
|
+
|
|
17
|
+
1. **No Windows branch.** `connect.sh` installs the Claude Desktop
|
|
18
|
+
managed-settings file on macOS (sudo) or falls through to "save it in
|
|
19
|
+
$HOME" with a Linux-worded message — on Windows. Claude Desktop never sees
|
|
20
|
+
the SSH config; its logs show `discovered 0 workspace SSH config(s)`.
|
|
21
|
+
2. **The agent cannot finish its own flow.** Claude Desktop's auto-mode
|
|
22
|
+
classifier hard-blocked even a read of `C:\ProgramData\ClaudeCode\
|
|
23
|
+
managed-settings.json` ("permission-machinery modification"). The platform
|
|
24
|
+
we onboard into forbids its agent from completing step 5, by design.
|
|
25
|
+
3. **Phishing-shaped trust hurdle.** Every newcomer's Claude re-litigates
|
|
26
|
+
`curl | bash` + an Amazon-look-alike domain + a server-fetched
|
|
27
|
+
highest-precedence config — ~6.5 minutes of security ceremony and three
|
|
28
|
+
user confirmations per attempt, forever.
|
|
29
|
+
4. **Zero post-run observability.** The script holds the GDS token in memory
|
|
30
|
+
only; once it exits, checking box state means a full GitHub device-flow
|
|
31
|
+
re-auth. The user waited 10h40m on the first-box approval gate with no way
|
|
32
|
+
to see anything.
|
|
33
|
+
5. Assorted platform cuts: git-bash `/tmp` invisible to the native Read tool,
|
|
34
|
+
browser never auto-opens on Windows, private key left 644, and the
|
|
35
|
+
`StrictHostKeyChecking` mitigation lands in `~/.ssh/config`, which Claude
|
|
36
|
+
Desktop's embedded ssh2 **does not read** — it reads only
|
|
37
|
+
`~/.ssh/known_hosts` (the known knownhosts bug).
|
|
38
|
+
|
|
39
|
+
Meanwhile the server side is already right: own-scoped `/box/ensure`,
|
|
40
|
+
`/box/me`, `/box/close`, `/box/terminal`, `/box/ssh-key`,
|
|
41
|
+
`/box/managed-settings` (ADR 0031/0035/0038) — the failures are all in the
|
|
42
|
+
local last mile.
|
|
43
|
+
|
|
44
|
+
## Decision
|
|
45
|
+
|
|
46
|
+
### 1. A native tray app owns the local last mile
|
|
47
|
+
|
|
48
|
+
`devbox-app/` — an Electron menu-bar (macOS) / system-tray (Windows) app,
|
|
49
|
+
"OTB Dev Box". One switch: on = `POST /box/ensure`, off = `POST /box/close`,
|
|
50
|
+
live state from polling `GET /box/me` (+ `/box/terminal` when active), native
|
|
51
|
+
notifications on ready / awaiting-approval / idle-close. Because it is a
|
|
52
|
+
human-launched native app, it can do everything the agent-driven flow could
|
|
53
|
+
not: generate `~/.ssh/otb_builder` with real 600 perms (icacls ACL on
|
|
54
|
+
Windows), register it, **replace** the box's lines in `~/.ssh/known_hosts` on
|
|
55
|
+
every activation (host keys change on each re-provision), and install the
|
|
56
|
+
managed-settings file to the system path behind the OS's own elevation prompt
|
|
57
|
+
(osascript / UAC). The app never sends `claude_active` heartbeats: the
|
|
58
|
+
droplet idle sweep stays the cost authority, and an unused box still reclaims
|
|
59
|
+
itself.
|
|
60
|
+
|
|
61
|
+
Electron over Tauri: no Rust toolchain for future builders, one runtime for
|
|
62
|
+
both targets, and the project's existing JS-only skill set — size (~100MB)
|
|
63
|
+
is the accepted cost. Zero runtime npm deps; the renderer is sandboxed,
|
|
64
|
+
contextIsolated, and reachable only through named IPC verbs.
|
|
65
|
+
|
|
66
|
+
### 2. App-pairing auth (browser clicks only)
|
|
67
|
+
|
|
68
|
+
The app signs in by pairing against the GDS itself (`src/bongos/app-pair.js`,
|
|
69
|
+
routes in `routes/auth.js`):
|
|
70
|
+
|
|
71
|
+
app: POST /auth/app-pair/start → { pair_code, poll_token }
|
|
72
|
+
app: opens /builders/pair?code=… (builders' hall approve page)
|
|
73
|
+
human: ONE Approve click (cookie-gated, like cli-token/issue)
|
|
74
|
+
server: mints a source='cli' session, parks it on the pairing
|
|
75
|
+
app: POST /auth/app-pair/poll → { token } (delivered once)
|
|
76
|
+
|
|
77
|
+
Two credentials with separated powers: the short `pair_code` (visible in the
|
|
78
|
+
browser) can only *approve from an authenticated browser cookie session*; the
|
|
79
|
+
long secret `poll_token` is the only thing that can *collect* the token, once.
|
|
80
|
+
GitHub's device flow was rejected because it makes the human type a code;
|
|
81
|
+
riding the web OAuth to a loopback was rejected because `safeReturnTo`
|
|
82
|
+
deliberately blocks non-apex targets and we refuse to weaken it. Pairing
|
|
83
|
+
state is an in-memory Map (10-min TTL, size-capped) — same posture as the
|
|
84
|
+
existing device-flow pendings; no migration, restart voids in-flight pairings
|
|
85
|
+
harmlessly. The minted session writes to `~/.config/otb/gds-session.json` —
|
|
86
|
+
the SAME file the CLI uses, so pairing the app also signs in the `/builder-*`
|
|
87
|
+
skills on that machine.
|
|
88
|
+
|
|
89
|
+
### 3. Distribution: CI builds, public releases repo, branded redirects
|
|
90
|
+
|
|
91
|
+
Installers cannot ride the git deploy (private repo, no LFS, GitHub 100MB
|
|
92
|
+
cap). `.github/workflows/build-devbox-app.yml` builds dmg (arm64+x64) + NSIS
|
|
93
|
+
exe on every `devbox-app/**` push and uploads artifacts; the operator
|
|
94
|
+
publishes them as release assets on the PUBLIC releases repo named in
|
|
95
|
+
`config/devbox-app.json` (`example-owner/example-devbox` — the ADR 0029
|
|
96
|
+
status-mirror pattern, $0). The server serves branded URLs that 302 to those
|
|
97
|
+
assets — `GET /downloads/devbox/{mac-arm64,mac-x64,win-x64}` +
|
|
98
|
+
`latest.json` (`src/devbox-downloads.js`) — so every link a builder sees
|
|
99
|
+
stays on example.com and a release bump is a one-file config change.
|
|
100
|
+
The app checks `latest.json` daily and shows a download banner (no
|
|
101
|
+
auto-update: meaningless without code signing).
|
|
102
|
+
|
|
103
|
+
### 4. Unsigned, for now
|
|
104
|
+
|
|
105
|
+
No Apple Developer ID ($99/yr) or Windows cert yet — a recurring cost that
|
|
106
|
+
needs Lars's explicit go-ahead (CLAUDE.md §4); filed as a blocker. Until
|
|
107
|
+
then macOS shows "Apple could not verify…" (System Settings → Privacy &
|
|
108
|
+
Security → Open Anyway) and SmartScreen shows "unrecognized app". The
|
|
109
|
+
onboarding copy walks through both honestly. electron-builder ad-hoc signs
|
|
110
|
+
the mac build (required for arm64 to launch).
|
|
111
|
+
|
|
112
|
+
### 5. Trademark posture (ADR 0004)
|
|
113
|
+
|
|
114
|
+
Product name, appId, artifact filenames carry "OTB Dev Box" /
|
|
115
|
+
`com.offtheboats.devbox` — never the civilization name. "Example" is
|
|
116
|
+
rendered at runtime only, from the single constant in
|
|
117
|
+
`devbox-app/src/brand.js`.
|
|
118
|
+
|
|
119
|
+
## Consequences
|
|
120
|
+
|
|
121
|
+
- The hall's Claude-Desktop onboarding pane drops the paste-a-prompt script
|
|
122
|
+
for: download app → approve → flip switch → open Claude Desktop. The
|
|
123
|
+
Claude Online (browser terminal) pane is unchanged. `/builders/settings`
|
|
124
|
+
gains a download section. `connect.sh`/`connect.ps1` remain for the
|
|
125
|
+
SSH-comfortable (ADR 0035's guide path) but are no longer the newcomer
|
|
126
|
+
front door.
|
|
127
|
+
- New auth surface: 2 public + 2 any-builder routes, all classified by the
|
|
128
|
+
route-rank pre-pass; approve is cookie-gated so a leaked bearer cannot mint
|
|
129
|
+
siblings (mirrors `cli-token/issue`).
|
|
130
|
+
- The signing-cert decision (and with it SmartScreen/Gatekeeper smoothness +
|
|
131
|
+
real auto-update) is deliberately deferred to the operator.
|
|
132
|
+
- A future `box_connect` onboarding tick still clears through the box's own
|
|
133
|
+
`claude_active` heartbeat — unchanged by the app (which never heartbeats).
|