@bongos/core 1.17.1 → 1.17.3
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 +521 -281
- package/.claude/skills/blocker-review/SKILL.md +1 -1
- package/.claude/skills/builder-claim/SKILL.md +2 -0
- package/.claude/skills/builder-exit/SKILL.md +2 -2
- package/.claude/skills/builder-redteam/SKILL.md +3 -3
- package/.claude/skills/builder-setup/SKILL.md +2 -2
- package/.claude/skills/builder-start/SKILL.md +1 -1
- package/.claude/skills/dev/SKILL.md +1 -1
- package/.claude/skills/idea-triage/SKILL.md +2 -2
- package/.claude/skills/ideate/SKILL.md +1 -1
- package/.claude/skills/merge-mode/SKILL.md +1 -1
- package/.claude/skills/new-project/SKILL.md +3 -0
- package/.claude/skills/paint/SKILL.md +1 -1
- package/GOVERNANCE.md +1 -1
- package/README.md +1 -1
- package/clients/bongos-client/README.md +1 -1
- package/clients/bongos-client/bongos-client.global.js +2 -0
- package/clients/bongos-client/index.cjs +2 -0
- package/clients/bongos-client/index.d.ts +4 -2
- package/clients/bongos-client/index.mjs +2 -0
- package/docs/adr/0001-stack-choice-single-vps.md +1 -1
- package/docs/adr/0008-google-chat-oauth-user-auth.md +1 -1
- package/docs/adr/0019-red-team-bounty-payout-table.md +3 -3
- package/docs/adr/0020-security-model-public-stub.md +1 -1
- package/docs/adr/0023-kind-multipliers-and-idea-bonus.md +1 -1
- package/docs/adr/0024-cloneable-repo-local-first-memory.md +1 -1
- package/docs/adr/0026-bfg-memory-hygiene-and-cross-builder-learning.md +4 -4
- package/docs/adr/0027-bfg-session-inefficiency-evaluator.md +3 -3
- package/docs/adr/0030-builders-hall-live-updates.md +1 -1
- package/docs/adr/0031-cloud-dev-environments-for-builders.md +4 -4
- package/docs/adr/0032-discord-mirror-of-gds.md +2 -2
- package/docs/adr/0034-thetes-graduated-newcomer-rank.md +1 -1
- package/docs/adr/0044-mediterranean-palette-replacement.md +1 -1
- package/docs/adr/0044-per-box-live-game-preview.md +1 -1
- package/docs/adr/0054-session-token-reward-cost-plus.md +10 -10
- package/docs/adr/0057-container-cost-ledger.md +3 -3
- package/docs/adr/0062-medusa-instance-model-decoupling.md +4 -4
- package/docs/adr/0065-agpl-nonprofit-ai-first-governance.md +2 -2
- package/docs/adr/0085-remove-default-per-builder-spend-cap.md +1 -1
- package/docs/adr/0086-goal-scoped-work-hierarchy.md +1 -1
- package/docs/adr/0096-require-reward-before-workable.md +9 -9
- package/docs/adr/0097-retroactive-reward-backfill.md +3 -3
- package/docs/adr/0100-two-repo-instance-model.md +1 -1
- package/docs/adr/0101-goal-hierarchy-phase-5-judge-membership-reward.md +3 -3
- package/docs/adr/0103-core-first-extraction-cloud-bongos-trunk.md +3 -3
- package/docs/adr/0107-module-upstreaming-contribution-to-core-catalog.md +1 -1
- package/docs/adr/0120-pay-on-land-and-builder-owned-rebase-gate.md +6 -6
- package/docs/adr/0136-update-channel-subscription-policy.md +51 -0
- package/docs/adr/0137-upstream-publish-policy-manual-owner-gated.md +40 -0
- package/docs/adr/0138-bundled-module-deps-declared-per-module.md +45 -0
- package/docs/adr/README.md +9 -6
- package/docs/api/openapi.json +65 -26
- package/docs/api-reference.md +3 -2
- package/docs/architecture.md +2 -2
- package/docs/branding-contract.md +5 -4
- package/docs/canonical-permissions.md +1 -1
- package/docs/design/vanilla-hall-ui-redesign-scope.md +1 -1
- package/docs/file-map.md +18 -17
- package/docs/handoff-template.md +2 -2
- package/docs/modules-contract.md +6 -1
- package/docs/onboarding/diagrams/README.md +7 -7
- package/docs/onboarding/drachmae-and-karma.md +18 -18
- package/docs/onboarding/primer.md +9 -9
- package/docs/recipes/audit-replay.md +2 -2
- package/docs/recipes/builder-box-lifecycle.md +2 -2
- package/docs/recipes/claude-design-loop.md +1 -1
- package/docs/recipes/ops-gotchas.md +1 -1
- package/docs/recipes/private-npm-distribution.md +17 -0
- package/docs/recipes/staging-environment.md +1 -1
- package/docs/recipes/upgrading-the-core.md +55 -0
- package/docs/research/cursor-competitive-analysis.md +1 -1
- package/docs/research/llm-model-agnostic-and-cheaper-grader.md +1 -1
- package/modules/discord/module.json +2 -1
- package/modules/economy/achievements.js +9 -1
- package/modules/economy/credits.js +10 -1
- package/modules/hall-ui/public/builders.js +137 -620
- package/modules/hall-ui/public/goal-inbox.js +232 -0
- package/modules/hall-ui/public/goals-page.js +4 -1
- package/modules/hall-ui/public/goals.html +8 -0
- package/modules/hall-ui/public/hall-kit.js +474 -0
- package/modules/hall-ui/public/hall-widgets.js +14 -5
- package/modules/hall-ui/public/index.html +3 -0
- package/modules/hall-ui/public/instances-panel.js +24 -3
- package/modules/hall-ui/public/new-project-wizard.js +7 -5
- package/modules/hall-ui/public/style.css +168 -0
- package/modules/hall-ui/public/work.css +194 -0
- package/modules/hall-ui/public/work.html +46 -374
- package/modules/hall-ui/public/work.js +137 -102
- package/modules/lifecycle/criterion-suggest.js +80 -0
- package/modules/lifecycle/db.js +42 -5
- package/modules/lifecycle/routes/goals.js +26 -0
- package/modules/lifecycle/routes/tasks.js +21 -0
- package/modules/provisioning/CLAUDE.md +15 -0
- package/modules/provisioning/migrations/provisioning_001_tables.sql +160 -0
- package/modules/provisioning/migrations/provisioning_002_standalone_shape.sql +11 -0
- package/modules/provisioning/migrations/provisioning_003_github_app_manifest.sql +95 -0
- package/modules/provisioning/module.json +17 -0
- package/modules/provisioning/onboard-plan.js +37 -0
- package/modules/provisioning/provisioning.js +539 -0
- package/modules/provisioning/rate-limit.js +35 -0
- package/modules/provisioning/routes/provisioning.js +607 -0
- package/modules/provisioning/tests/provisioning.mjs +232 -0
- package/modules/provisioning/ui/.gitkeep +0 -0
- package/modules/security/secret-scrub.js +10 -0
- package/package-lock.json +2 -2
- package/package.json +7 -2
- package/scripts/discord/README.md +1 -1
- package/scripts/gds/claim.js +98 -48
- package/scripts/gds/claude-materialize.js +30 -9
- package/scripts/gds/cutover-codemod.js +241 -0
- package/scripts/gds/fitness.js +54 -0
- package/scripts/gds/init.js +59 -3
- package/scripts/gds/lint-infra-exec.js +70 -0
- package/scripts/gds/lint-workflow-exec.js +63 -0
- package/scripts/gds/mirror-lineage-check.js +14 -5
- package/scripts/gds/mirror-redact.js +8 -0
- package/scripts/gds/onboard.js +4 -0
- package/scripts/gds/package-core.js +18 -3
- package/scripts/gds/publish-manifest.js +60 -2
- package/scripts/gds/run-routine.js +51 -13
- package/scripts/gds/run-unit-tests.js +4 -0
- package/scripts/gds/update-channel.js +186 -0
- package/scripts/gds/upgrade.js +116 -9
- package/scripts/hall-preview/README.md +103 -0
- package/scripts/hall-preview/fixtures/access-requests.json +1 -0
- package/scripts/hall-preview/fixtures/achievements.json +76 -0
- package/scripts/hall-preview/fixtures/analytics__builder.json +251 -0
- package/scripts/hall-preview/fixtures/audit-log.json +1 -0
- package/scripts/hall-preview/fixtures/boxes__cost-ledger.json +1 -0
- package/scripts/hall-preview/fixtures/builders__active-claims.json +1 -0
- package/scripts/hall-preview/fixtures/builders__directory.json +81 -0
- package/scripts/hall-preview/fixtures/builders__roster.json +1 -0
- package/scripts/hall-preview/fixtures/goals.json +502 -0
- package/scripts/hall-preview/fixtures/goals__25.json +96 -0
- package/scripts/hall-preview/fixtures/goals__26.json +67 -0
- package/scripts/hall-preview/fixtures/goals__3.json +103 -0
- package/scripts/hall-preview/fixtures/goals__35.json +49 -0
- package/scripts/hall-preview/fixtures/goals__conflicts.json +154 -0
- package/scripts/hall-preview/fixtures/goals__detail.json +96 -0
- package/scripts/hall-preview/fixtures/goals__inbox.json +5 -0
- package/scripts/hall-preview/fixtures/goals__requests.json +3 -0
- package/scripts/hall-preview/fixtures/grades__by-builder.json +1 -0
- package/scripts/hall-preview/fixtures/inbox.json +330 -0
- package/scripts/hall-preview/fixtures/instance.json +124 -0
- package/scripts/hall-preview/fixtures/leaderboard.json +184 -0
- package/scripts/hall-preview/fixtures/me.json +476 -0
- package/scripts/hall-preview/fixtures/me__recent-ships.json +304 -0
- package/scripts/hall-preview/fixtures/override-requests.json +1 -0
- package/scripts/hall-preview/fixtures/provisioning__fleet.json +1 -0
- package/scripts/hall-preview/fixtures/provisioning__fleet__cost-ledger.json +1 -0
- package/scripts/hall-preview/fixtures/provisioning__instances.json +1 -0
- package/scripts/hall-preview/fixtures/public__analytics__ecosystem.json +516 -0
- package/scripts/hall-preview/fixtures/public__bounty-table.json +37 -0
- package/scripts/hall-preview/fixtures/public__cost-summary.json +742 -0
- package/scripts/hall-preview/fixtures/public__estimation-drift.json +41 -0
- package/scripts/hall-preview/fixtures/public__grades.json +50 -0
- package/scripts/hall-preview/fixtures/public__progress.json +124 -0
- package/scripts/hall-preview/fixtures/public__recent-shipped.json +426 -0
- package/scripts/hall-preview/fixtures/public__repo-health.json +160 -0
- package/scripts/hall-preview/fixtures/public__repo-info.json +5 -0
- package/scripts/hall-preview/fixtures/security__docs.json +1 -0
- package/scripts/hall-preview/fixtures/security__reports.json +1 -0
- package/scripts/hall-preview/fixtures/sessions__search.json +1 -0
- package/scripts/hall-preview/fixtures/tasks.json +2420 -0
- package/scripts/hall-preview/fixtures/tasks__claimable.json +2555 -0
- package/scripts/hall-preview/fixtures/tasks__detail.json +111 -0
- package/scripts/hall-preview/fixtures/tasks__peer-votes__feed.json +330 -0
- package/scripts/hall-preview/fixtures/versions.json +89 -0
- package/scripts/hall-preview/refresh-fixtures.js +77 -0
- package/scripts/hall-preview/server.js +178 -0
- package/scripts/migrate.sh +29 -4
- package/src/bongos/auth.js +14 -1
- package/src/bongos/optimizer.js +37 -2
- package/src/bongos/serve-internal.js +10 -1
- package/src/branding.js +1 -0
- package/src/module-api.js +12 -1
- package/src/module-loader/loader.js +36 -4
- package/src/module-loader/manifest-schema.js +16 -1
- package/tests/branding.mjs +11 -0
- package/tests/claim_error_surface.mjs +107 -0
- package/tests/claude_materialize.mjs +20 -0
- package/tests/consumer_layout_boot.mjs +302 -0
- package/tests/criterion_suggest.mjs +106 -0
- package/tests/cutover_codemod.mjs +184 -0
- package/tests/device_flow_start.mjs +25 -2
- package/tests/hook_core_resolve.mjs +125 -0
- package/tests/infra_exec_paths.mjs +104 -0
- package/tests/init.mjs +47 -0
- package/tests/migrate_root_resolution.mjs +97 -0
- package/tests/mirror_lineage_proof.mjs +14 -0
- package/tests/module_loader.mjs +42 -0
- package/tests/module_manifest.mjs +19 -0
- package/tests/onboard.mjs +13 -0
- package/tests/package_core.mjs +8 -0
- package/tests/provisioning_github_app_routes.mjs +15 -0
- package/tests/publish_manifest.mjs +52 -1
- package/tests/run_routine.mjs +26 -1
- package/tests/run_routine_two_root.mjs +77 -0
- package/tests/scrubber_corpus.mjs +17 -0
- package/tests/update_channel.mjs +186 -0
- package/tests/upgrade.mjs +131 -0
- package/tests/workflow_exec_paths.mjs +98 -0
- package/docs/design/container-exterior-tiles.md +0 -49
- package/docs/design/container-exterior.md +0 -81
- package/docs/design/container-interior.md +0 -77
- package/docs/design/world-map-scroll.md +0 -41
- package/docs/recipes/claude-gemini-bongos-doors.md +0 -155
- package/docs/recipes/cloudbongos-staging-gate.md +0 -139
- package/docs/recipes/cloudbongos-standup.md +0 -111
- package/docs/recipes/parallel-load-results-2026-05-30.md +0 -63
- package/docs/recipes/parallel-load-test.md +0 -32
- package/docs/recipes/pixel-art-pipeline.md +0 -411
- package/docs/recipes/staging-data.md +0 -50
- package/migrations/instance/018_pms_v3_planning_seed.sql +0 -131
- package/migrations/instance/080_gds_v4_planning_seed.sql +0 -75
- package/migrations/instance/110_medusa_planning_seed.sql +0 -70
- package/migrations/instance/120_bongos_v1_planning_seed.sql +0 -69
- package/migrations/instance/144_bongos_v1_module_system_criterion.sql +0 -26
- package/migrations/instance/159_bongos_v1_goal_hierarchy_criterion.sql +0 -29
- package/migrations/instance/172_v2_world_planning_seed.sql +0 -163
- package/migrations/instance/173_bongos_v1_c7_core_modularized.sql +0 -33
- package/migrations/instance/182_gdsv4_bongos_consolidation.sql +0 -132
- package/migrations/instance/183_gdsv4_carryover_themed_goals.sql +0 -116
- package/migrations/instance/186_bongos_v1_governance_planning_seed.sql +0 -69
- package/scripts/gds/art-stage.js +0 -152
- package/server.js +0 -212
- package/tests/art_key.mjs +0 -121
- package/tests/day_cycle.mjs +0 -197
- package/tests/snapshot_picker.mjs +0 -233
- package/tests/sprite_facing.mjs +0 -35
- package/tests/terrain_picker.mjs +0 -298
- package/tests/turn_in_place.mjs +0 -280
- package/tests/walkability.mjs +0 -188
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
-- provisioning_001_tables.sql — the `provisioning` module's DB slice (ADR 0111 §1,
|
|
2
|
+
-- task #1942 / BONGOS-V1 goal 32). Instance hosting + domains: the web-tier REQUEST
|
|
3
|
+
-- + STATE surface for standing up + operating a Cloud Bongos instance's own infra.
|
|
4
|
+
--
|
|
5
|
+
-- These three tables mirror the dev-box lifecycle ledger (migrations 067/070), one
|
|
6
|
+
-- layer up — a whole INSTANCE instead of a builder's box:
|
|
7
|
+
-- • provisioning_instances — one row per instance being provisioned/operated.
|
|
8
|
+
-- • provisioning_intents — the trust-boundary-safe request queue (the box_intents
|
|
9
|
+
-- analogue): the web tier only ENQUEUES; the control-plane
|
|
10
|
+
-- runner (scripts/gds/provision.js, task P3) drains it. The
|
|
11
|
+
-- web process holds NO cloud tokens (ADR 0111 §2 / ADR 0016).
|
|
12
|
+
-- • provisioning_events — an append-only audit ledger of provisioning actions
|
|
13
|
+
-- (direct control-plane infra mutations are project-state
|
|
14
|
+
-- changes too — CLAUDE.md hard rule — so they get a row).
|
|
15
|
+
--
|
|
16
|
+
-- Module migrations are ADDITIVE and NAMESPACED: every object lives under the
|
|
17
|
+
-- provisioning_ prefix, there is no down-migration, and the file itself is
|
|
18
|
+
-- provisioning_-prefixed (ADR 0108 §5) so its stem can never collide with a core /
|
|
19
|
+
-- instance / other-module migration across repos. `scripts/migrate.sh` discovers +
|
|
20
|
+
-- applies this ONLY when the provisioning module is enabled in config/modules.json.
|
|
21
|
+
--
|
|
22
|
+
-- Idempotent: safe to re-run.
|
|
23
|
+
|
|
24
|
+
-- ---------------------------------------------------------------------------
|
|
25
|
+
-- provisioning_instances — one row per instance an owner is provisioning/operating.
|
|
26
|
+
-- ---------------------------------------------------------------------------
|
|
27
|
+
CREATE TABLE IF NOT EXISTS provisioning_instances (
|
|
28
|
+
id bigserial PRIMARY KEY,
|
|
29
|
+
|
|
30
|
+
-- The owner (a builder in THIS GDS) who requested + operates this instance.
|
|
31
|
+
owner_builder_id bigint NOT NULL REFERENCES builders(id) ON DELETE CASCADE,
|
|
32
|
+
|
|
33
|
+
-- A DNS/db-safe slug naming the instance (e.g. 'mercury'). The stable key an
|
|
34
|
+
-- owner + the port reference it by; also the base for its DB name + hostname.
|
|
35
|
+
slug text NOT NULL UNIQUE,
|
|
36
|
+
|
|
37
|
+
-- The target repo/ref this instance runs (e.g. 'owner/repo'). Advisory metadata
|
|
38
|
+
-- the runner reads; NULL until supplied.
|
|
39
|
+
target_ref text,
|
|
40
|
+
|
|
41
|
+
-- Hosting shape (ADR 0111 §3/§6). Cheapest-first DNA:
|
|
42
|
+
-- co-tenant — a process + DB on an EXISTING box (the cloudbongos.com model, $0 extra)
|
|
43
|
+
-- dedicated — its own DigitalOcean droplet (only when justified)
|
|
44
|
+
hosting_shape text NOT NULL DEFAULT 'co-tenant'
|
|
45
|
+
CHECK (hosting_shape IN ('co-tenant', 'dedicated')),
|
|
46
|
+
|
|
47
|
+
-- Bring-your-own-domain first (ADR 0111 §4): the apex/host the owner already owns
|
|
48
|
+
-- (or a delegated zone). NULL until supplied. Registrar PURCHASE is deferred.
|
|
49
|
+
domain text,
|
|
50
|
+
|
|
51
|
+
-- The instance's own database name (createdb <db_name>; GDS-only migrate).
|
|
52
|
+
db_name text,
|
|
53
|
+
|
|
54
|
+
-- Allocated port for a co-tenant process (NULL for a dedicated droplet / unallocated).
|
|
55
|
+
port int,
|
|
56
|
+
|
|
57
|
+
-- The droplet size tier for a dedicated shape (a SIZE_CATALOG slug); NULL co-tenant.
|
|
58
|
+
tier text,
|
|
59
|
+
|
|
60
|
+
-- Lifecycle state machine (mirrored in modules/provisioning/provisioning.js
|
|
61
|
+
-- INSTANCE_STATES):
|
|
62
|
+
-- requested — the owner asked; a 'provision' intent is (or will be) enqueued
|
|
63
|
+
-- provisioning — the control-plane runner is standing it up
|
|
64
|
+
-- active — running + serving
|
|
65
|
+
-- tearing_down — a 'teardown' intent is being executed
|
|
66
|
+
-- torn_down — fully de-provisioned
|
|
67
|
+
-- error — a provisioning op failed; needs operator attention
|
|
68
|
+
status text NOT NULL DEFAULT 'requested'
|
|
69
|
+
CHECK (status IN ('requested', 'provisioning', 'active',
|
|
70
|
+
'tearing_down', 'torn_down', 'error')),
|
|
71
|
+
|
|
72
|
+
-- Monthly cost estimate (USD) for visibility (ADR 0111 §6). Co-tenant = 0;
|
|
73
|
+
-- dedicated = the tier's SIZE_CATALOG monthly rate. NOT a bill — just visibility.
|
|
74
|
+
cost_estimate_usd numeric(10,4) NOT NULL DEFAULT 0,
|
|
75
|
+
|
|
76
|
+
error_note text,
|
|
77
|
+
created_at timestamptz NOT NULL DEFAULT now(),
|
|
78
|
+
updated_at timestamptz NOT NULL DEFAULT now(),
|
|
79
|
+
provisioned_at timestamptz,
|
|
80
|
+
torn_down_at timestamptz
|
|
81
|
+
);
|
|
82
|
+
CREATE INDEX IF NOT EXISTS idx_provisioning_instances_owner
|
|
83
|
+
ON provisioning_instances (owner_builder_id);
|
|
84
|
+
CREATE INDEX IF NOT EXISTS idx_provisioning_instances_status
|
|
85
|
+
ON provisioning_instances (status);
|
|
86
|
+
|
|
87
|
+
-- ---------------------------------------------------------------------------
|
|
88
|
+
-- provisioning_intents — the provision / teardown request queue (the
|
|
89
|
+
-- trust-boundary-safe bridge between the web process and the control plane).
|
|
90
|
+
-- The web side only ever RECORDS a request here; scripts/gds/provision.js (task
|
|
91
|
+
-- P3, the sole holder of the DO/Cloudflare tokens) drains it. The web process
|
|
92
|
+
-- stays powerless over infra — it can ask, never act (ADR 0111 §2 / ADR 0016).
|
|
93
|
+
-- ---------------------------------------------------------------------------
|
|
94
|
+
CREATE TABLE IF NOT EXISTS provisioning_intents (
|
|
95
|
+
id bigserial PRIMARY KEY,
|
|
96
|
+
instance_id bigint NOT NULL REFERENCES provisioning_instances(id) ON DELETE CASCADE,
|
|
97
|
+
|
|
98
|
+
-- Only the two SAFE, owner/Archon-initiated ops are queueable from the web:
|
|
99
|
+
-- 'provision' (stand up) and 'teardown' (an explicit tear-down the owner/Archon
|
|
100
|
+
-- asked for). No implicit destructive op is ever queued.
|
|
101
|
+
action text NOT NULL CHECK (action IN ('provision', 'teardown')),
|
|
102
|
+
|
|
103
|
+
-- pending → waiting for the runner to pick it up
|
|
104
|
+
-- running → the runner claimed it and is doing the control-plane work
|
|
105
|
+
-- done → the op succeeded
|
|
106
|
+
-- error → the op failed (last_error carries why); the row is no longer "open"
|
|
107
|
+
-- so the partial unique index below lets a fresh intent (retry) through.
|
|
108
|
+
state text NOT NULL DEFAULT 'pending'
|
|
109
|
+
CHECK (state IN ('pending', 'running', 'done', 'error')),
|
|
110
|
+
|
|
111
|
+
-- Who asked. 'api:self' for an owner's own request; 'api:archon:<id>' for an
|
|
112
|
+
-- Archon force action; a runner/control-plane tag otherwise. Audit only.
|
|
113
|
+
requested_by text,
|
|
114
|
+
|
|
115
|
+
-- Retry accounting. The runner bumps attempts each claim; a small cap (enforced
|
|
116
|
+
-- in the runner, not here) stops a poison intent from looping forever.
|
|
117
|
+
attempts int NOT NULL DEFAULT 0,
|
|
118
|
+
last_error text,
|
|
119
|
+
|
|
120
|
+
created_at timestamptz NOT NULL DEFAULT now(),
|
|
121
|
+
updated_at timestamptz NOT NULL DEFAULT now(),
|
|
122
|
+
resolved_at timestamptz
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
-- At most ONE open (pending|running) intent per instance — a repeated request
|
|
126
|
+
-- collides here and the route returns the already-open intent instead of piling
|
|
127
|
+
-- up a redundant queue. Resolved (done|error) rows are exempt, so a retry after a
|
|
128
|
+
-- failure is always allowed (mirrors ux_box_intents_open).
|
|
129
|
+
CREATE UNIQUE INDEX IF NOT EXISTS ux_provisioning_intents_open
|
|
130
|
+
ON provisioning_intents (instance_id)
|
|
131
|
+
WHERE state IN ('pending', 'running');
|
|
132
|
+
|
|
133
|
+
-- The runner's hot path: "oldest pending intent". A partial index keeps it tiny
|
|
134
|
+
-- (it only ever indexes the unresolved tail, not the full history).
|
|
135
|
+
CREATE INDEX IF NOT EXISTS idx_provisioning_intents_pending
|
|
136
|
+
ON provisioning_intents (created_at)
|
|
137
|
+
WHERE state = 'pending';
|
|
138
|
+
|
|
139
|
+
-- ---------------------------------------------------------------------------
|
|
140
|
+
-- provisioning_events — append-only audit/log of provisioning actions. The HTTP
|
|
141
|
+
-- audit_log captures only API mutations; the real provisioning ops run on the
|
|
142
|
+
-- control-plane runner, so they record here (like box_events for the box lifecycle).
|
|
143
|
+
-- ---------------------------------------------------------------------------
|
|
144
|
+
CREATE TABLE IF NOT EXISTS provisioning_events (
|
|
145
|
+
id bigserial PRIMARY KEY,
|
|
146
|
+
instance_id bigint NOT NULL REFERENCES provisioning_instances(id) ON DELETE CASCADE,
|
|
147
|
+
owner_builder_id bigint REFERENCES builders(id) ON DELETE SET NULL,
|
|
148
|
+
-- request | provision | active | teardown | torn_down | cost | error | ...
|
|
149
|
+
event text NOT NULL,
|
|
150
|
+
detail text,
|
|
151
|
+
cost_usd numeric(10,4),
|
|
152
|
+
-- Who/what triggered it: 'api:self' | 'api:archon:<id>' | 'runner' | ...
|
|
153
|
+
actor text,
|
|
154
|
+
created_at timestamptz NOT NULL DEFAULT now()
|
|
155
|
+
);
|
|
156
|
+
CREATE INDEX IF NOT EXISTS idx_provisioning_events_instance
|
|
157
|
+
ON provisioning_events (instance_id, created_at DESC);
|
|
158
|
+
|
|
159
|
+
INSERT INTO schema_migrations (version) VALUES ('provisioning_001_tables')
|
|
160
|
+
ON CONFLICT (version) DO NOTHING;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
-- provisioning_002_standalone_shape.sql — widen provisioning_instances.hosting_shape
|
|
2
|
+
-- to allow 'standalone' (ADR 0108 / ADR 0111, BONGOS-V1 goal 32/35, task 1978).
|
|
3
|
+
--
|
|
4
|
+
-- A standalone instance runs from its OWN repo checkout with a pinned @cloudbongos/core
|
|
5
|
+
-- npm dep (the ADR 0108 destination model), distinct from the co-tenant shape (which
|
|
6
|
+
-- shares the control-plane checkout) and dedicated (its own droplet). Widening a CHECK
|
|
7
|
+
-- enum is ADDITIVE — it only permits MORE values; no existing row changes, no data is
|
|
8
|
+
-- lost — so it is safe under the module-owned-migration rule (ADR 0083 §Decision #5).
|
|
9
|
+
ALTER TABLE provisioning_instances DROP CONSTRAINT IF EXISTS provisioning_instances_hosting_shape_check;
|
|
10
|
+
ALTER TABLE provisioning_instances ADD CONSTRAINT provisioning_instances_hosting_shape_check
|
|
11
|
+
CHECK (hosting_shape IN ('co-tenant', 'dedicated', 'standalone'));
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
-- provisioning_003_github_app_manifest.sql — the GitHub App Manifest onboarding flow
|
|
2
|
+
-- (ADR 0133, BONGOS-V1 goal 35 / criterion 165, task 2080).
|
|
3
|
+
--
|
|
4
|
+
-- WHY. The last human friction in greenfield onboarding was: the owner had to hand-
|
|
5
|
+
-- create a GitHub OAuth App, generate a client secret, and hand it to the box
|
|
6
|
+
-- (oauth-secret.js). GitHub has NO API to create an OAuth App — but it DOES have the
|
|
7
|
+
-- GitHub App *Manifest* flow: the owner clicks ONE pre-filled link, approves on GitHub,
|
|
8
|
+
-- and GitHub returns a temporary `code` we exchange (control-plane-side) for the
|
|
9
|
+
-- client_id + client_secret automatically. The secret never touches the browser/chat.
|
|
10
|
+
--
|
|
11
|
+
-- The flow spans TWO processes across the trust boundary (ADR 0111 §2 / ADR 0016):
|
|
12
|
+
-- • the web tier mints a one-time `state` token + stores the row (this table), and
|
|
13
|
+
-- its public callback stores GitHub's `code` when the owner returns;
|
|
14
|
+
-- • the control-plane runner (scripts/gds/provision.js — the sole token-holder)
|
|
15
|
+
-- drains rows in status 'code_received', exchanges the code for creds, and places
|
|
16
|
+
-- them in /etc/<slug>/web.env (the oauth-secret.js path), then verifies /healthz.
|
|
17
|
+
-- Because the two processes don't share memory, the state/code lease is DB-backed (the
|
|
18
|
+
-- merge_lease / builder_sessions expires_at pattern), NOT the in-memory deviceFlows map.
|
|
19
|
+
--
|
|
20
|
+
-- Additive + idempotent + namespaced (ADR 0108 §5). Applied only when the provisioning
|
|
21
|
+
-- module is enabled (config/modules.json). Safe to re-run.
|
|
22
|
+
|
|
23
|
+
-- ---------------------------------------------------------------------------
|
|
24
|
+
-- (1) Widen provisioning_intents.action so the manifest conversion can ride the
|
|
25
|
+
-- existing intent queue if ever needed. Today the runner drains manifests by
|
|
26
|
+
-- scanning this table's status (drainOAuthManifests) — but widening the CHECK
|
|
27
|
+
-- keeps a future intent-driven path open and keeps INTENT_ACTIONS in lockstep.
|
|
28
|
+
-- Widening a CHECK enum is additive (permits MORE values; no row changes).
|
|
29
|
+
-- ---------------------------------------------------------------------------
|
|
30
|
+
ALTER TABLE provisioning_intents DROP CONSTRAINT IF EXISTS provisioning_intents_action_check;
|
|
31
|
+
ALTER TABLE provisioning_intents ADD CONSTRAINT provisioning_intents_action_check
|
|
32
|
+
CHECK (action IN ('provision', 'teardown', 'oauth-manifest'));
|
|
33
|
+
|
|
34
|
+
-- ---------------------------------------------------------------------------
|
|
35
|
+
-- (2) provisioning_oauth_manifests — one row per GitHub-App-Manifest onboarding
|
|
36
|
+
-- attempt for an instance. The `state` is the one-time CSRF token round-tripped
|
|
37
|
+
-- through GitHub; `github_code` is GitHub's temporary conversion code (single-use,
|
|
38
|
+
-- ~1h GitHub-side TTL) the control-plane runner exchanges for the client creds.
|
|
39
|
+
-- ---------------------------------------------------------------------------
|
|
40
|
+
CREATE TABLE IF NOT EXISTS provisioning_oauth_manifests (
|
|
41
|
+
id bigserial PRIMARY KEY,
|
|
42
|
+
instance_id bigint NOT NULL REFERENCES provisioning_instances(id) ON DELETE CASCADE,
|
|
43
|
+
|
|
44
|
+
-- The one-time CSRF `state` token minted by the web tier (crypto.randomBytes hex),
|
|
45
|
+
-- carried to GitHub in the manifest POST and returned on the callback. UNIQUE so a
|
|
46
|
+
-- callback maps to exactly one attempt. Unguessable (256-bit) — it is the callback's
|
|
47
|
+
-- only authorization (GitHub redirects the browser back unauthenticated).
|
|
48
|
+
state text NOT NULL UNIQUE,
|
|
49
|
+
|
|
50
|
+
-- Lifecycle:
|
|
51
|
+
-- pending — link minted; awaiting the owner's click + GitHub's redirect back
|
|
52
|
+
-- code_received — GitHub redirected back with a `code`; awaiting the control-plane runner
|
|
53
|
+
-- converting — the runner claimed the row and is exchanging the code with GitHub
|
|
54
|
+
-- done — creds fetched + placed in web.env; /healthz auth_configured verified
|
|
55
|
+
-- error — conversion or placement failed (last_error carries why)
|
|
56
|
+
-- expired — the `state` TTL passed before the owner completed the round-trip
|
|
57
|
+
status text NOT NULL DEFAULT 'pending'
|
|
58
|
+
CHECK (status IN ('pending', 'code_received', 'converting', 'done', 'error', 'expired')),
|
|
59
|
+
|
|
60
|
+
-- GitHub's temporary manifest-conversion code. Written by the web-tier callback;
|
|
61
|
+
-- consumed by the runner (POST /app-manifests/{code}/conversions). NEVER the secret
|
|
62
|
+
-- itself — only the short-lived code is web-tier-visible; the client_secret is fetched
|
|
63
|
+
-- by the control plane and written straight to web.env, never stored here.
|
|
64
|
+
github_code text,
|
|
65
|
+
|
|
66
|
+
-- The GitHub App id + slug GitHub assigned once converted (audit; the App the owner
|
|
67
|
+
-- created for their instance's sign-in). Filled by the runner on success.
|
|
68
|
+
app_id bigint,
|
|
69
|
+
app_slug text,
|
|
70
|
+
|
|
71
|
+
-- The builder who initiated the attempt (the signed-in owner on the mothership).
|
|
72
|
+
requested_by bigint REFERENCES builders(id) ON DELETE SET NULL,
|
|
73
|
+
|
|
74
|
+
-- Runner retry accounting (a poison conversion never loops forever) + last error.
|
|
75
|
+
attempts int NOT NULL DEFAULT 0,
|
|
76
|
+
last_error text,
|
|
77
|
+
|
|
78
|
+
-- The `state` token's TTL — the owner must complete the GitHub round-trip before this.
|
|
79
|
+
expires_at timestamptz NOT NULL,
|
|
80
|
+
created_at timestamptz NOT NULL DEFAULT now(),
|
|
81
|
+
updated_at timestamptz NOT NULL DEFAULT now(),
|
|
82
|
+
resolved_at timestamptz
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
-- The runner's hot path: "oldest manifest awaiting conversion" (status='code_received').
|
|
86
|
+
-- A partial index keeps it tiny (only the unresolved tail).
|
|
87
|
+
CREATE INDEX IF NOT EXISTS idx_provisioning_oauth_manifests_ready
|
|
88
|
+
ON provisioning_oauth_manifests (created_at)
|
|
89
|
+
WHERE status = 'code_received';
|
|
90
|
+
|
|
91
|
+
CREATE INDEX IF NOT EXISTS idx_provisioning_oauth_manifests_instance
|
|
92
|
+
ON provisioning_oauth_manifests (instance_id, created_at DESC);
|
|
93
|
+
|
|
94
|
+
INSERT INTO schema_migrations (version) VALUES ('provisioning_003_github_app_manifest')
|
|
95
|
+
ON CONFLICT (version) DO NOTHING;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"key": "provisioning",
|
|
3
|
+
"title": "Instance provisioning",
|
|
4
|
+
"description": "Stand up + operate a Cloud Bongos instance's own infrastructure (server, database, domain, DNS, TLS) via the API, so an owner does not manage infra by hand (ADR 0111). Owns the web-tier REQUEST + STATE surface only: it enqueues provisioning intents + reads instance state — it holds NO cloud-provider tokens and calls NO cloud API. A separate control-plane runner (scripts/gds/provision.js, task P3) is the sole token-holder that drains the intents. Distinct from the `hosting` module (ADR 0092), which brokers compute WORKLOADS.",
|
|
5
|
+
"coreVersion": "^1.14.0",
|
|
6
|
+
"default": false,
|
|
7
|
+
"author": "Off the Boats",
|
|
8
|
+
"origin": "Off the Boats (the first Cloud Bongos instance, amazonprimea.com)",
|
|
9
|
+
"license": "AGPL-3.0",
|
|
10
|
+
"maintainer": "Off the Boats maintainers",
|
|
11
|
+
"contributes": {
|
|
12
|
+
"routes": ["provisioning"],
|
|
13
|
+
"migrations": true
|
|
14
|
+
},
|
|
15
|
+
"provides": ["provisioning.instanceState"],
|
|
16
|
+
"consumes": []
|
|
17
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// modules/provisioning/onboard-plan.js — the CANONICAL onboarding step sequence.
|
|
2
|
+
//
|
|
3
|
+
// Goal 35 / criterion 165 names the sequence as the source of truth: "The canonical
|
|
4
|
+
// step sequence is the source of truth; skill/CLI/hall are forms over it." This file
|
|
5
|
+
// is that ONE source. The CLI (`bongos onboard`, scripts/gds/onboard.js), the branded
|
|
6
|
+
// /create landing page, and the hall's new-project wizard all read it — via a direct
|
|
7
|
+
// require (the CLI) or the public GET /provisioning/onboard-plan route (the web) — so
|
|
8
|
+
// the sequence can never drift between the forms (task 2085, anti-drift).
|
|
9
|
+
//
|
|
10
|
+
// PURE — no I/O, no core imports. Safe to require from a script, a route, or a test.
|
|
11
|
+
//
|
|
12
|
+
// Each step: { key, kind: 'auto' | 'human', label }. `kind: 'human'` marks the
|
|
13
|
+
// irreducibly-manual owner actions (create the GitHub repo, wire GitHub sign-in, first
|
|
14
|
+
// sign-in) that every form renders UI-first; `kind: 'auto'` steps the flow performs.
|
|
15
|
+
// The sequence branches at exactly ONE leg — scaffold — into greenfield (`bongos init`,
|
|
16
|
+
// a fresh empty repo) vs brownfield (`bongos init --adopt`, LAYER onto an existing repo;
|
|
17
|
+
// ADR 0121 §Decision 1 / task 2046). Every other leg is identical, so `mode` only
|
|
18
|
+
// relabels the github-repo / init / scaffold steps.
|
|
19
|
+
function onboardPlan(mode = 'greenfield') {
|
|
20
|
+
const adopt = mode === 'adopt';
|
|
21
|
+
return [
|
|
22
|
+
{ key: 'name-address', kind: 'auto', label: 'Decide name + address (interview)' },
|
|
23
|
+
{ key: 'github-repo', kind: 'human', label: adopt ? 'Use your EXISTING GitHub repository' : 'Create the empty GitHub repository' },
|
|
24
|
+
{ key: 'dns-preflight', kind: 'auto', label: 'DNS token preflight — before the address step (task 1980)' },
|
|
25
|
+
{ key: 'init', kind: 'auto', label: adopt ? 'bongos init --adopt — LAYER onto the existing repo (pre-flight + accept)' : 'bongos init — scaffold the instance config' },
|
|
26
|
+
{ key: 'scaffold', kind: 'auto', label: adopt ? 'Layer config + pinned @bongos/core onto the existing repo (no clobber)' : 'Scaffold the standalone repo (own repo + pinned @bongos/core)' },
|
|
27
|
+
{ key: 'provision', kind: 'auto', label: 'Provision core + DB + address + service (standalone, task 1978)' },
|
|
28
|
+
{ key: 'seed-version', kind: 'auto', label: 'Seed the first version (V1) so the instance can take tasks immediately (task 2119)' },
|
|
29
|
+
{ key: 'oauth-app', kind: 'human', label: 'Wire GitHub sign-in — one-click GitHub App (task 2080), or a manual OAuth app' },
|
|
30
|
+
{ key: 'oauth-place', kind: 'auto', label: 'Place the OAuth secret — auto via the Manifest flow, or verified manual (task 1979)' },
|
|
31
|
+
{ key: 'first-sign-in', kind: 'human', label: 'First sign-in (seats the founding Archon)' },
|
|
32
|
+
{ key: 'verify', kind: 'auto', label: 'Verify /healthz auth_configured' },
|
|
33
|
+
{ key: 'brand', kind: 'auto', label: 'Brand the instance look' },
|
|
34
|
+
];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
module.exports = { onboardPlan };
|