@bongos/core 1.19.950 → 1.19.952
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 +50 -35
- package/docs/module-api-changelog.md +4 -0
- package/modules/provisioning/capacity-gate.js +7 -1
- package/modules/provisioning/capacity.js +7 -1
- package/modules/provisioning/migrations/provisioning_021_byo_host_shape.sql +37 -0
- package/modules/provisioning/onboard-plan.js +11 -4
- package/modules/provisioning/paid-shape-gate.js +37 -8
- package/modules/provisioning/provisioning.js +6 -6
- package/modules/provisioning/routes/provisioning.js +15 -5
- package/modules/public-landing/public/projects.html +17 -2
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/scripts/gds/adopt-preflight.js +1 -1
- package/scripts/gds/device-flow-help.js +1 -1
- package/scripts/gds/init.js +25 -10
- package/scripts/gds/login.js +1 -1
- package/scripts/gds/provision-byo-host.js +68 -0
- package/scripts/gds/provision.js +2 -0
- package/scripts/gds/setup.js +1 -1
- package/src/module-api.js +1 -1
- package/tests/adopt_preflight.mjs +1 -1
- package/tests/bongos_login.mjs +1 -1
- package/tests/discord_approvals.mjs +1 -1
- package/tests/init.mjs +9 -7
- package/tests/module_api.mjs +1 -1
- package/tests/projects_hub_pre_uat.mjs +5 -1
- package/tests/provision_byo_host.mjs +122 -0
- package/tests/provisioning_capacity.mjs +5 -0
- package/tests/provisioning_capacity_gate.mjs +27 -7
- package/tests/provisioning_module_selection.mjs +9 -9
- package/tests/provisioning_onboard_mode.mjs +5 -5
- package/tests/provisioning_paid_shape_gate.mjs +76 -6
package/.bongos-core.json
CHANGED
|
@@ -2,22 +2,22 @@
|
|
|
2
2
|
"artifact": "bongos-core",
|
|
3
3
|
"manifest_schema": 1,
|
|
4
4
|
"generator": "scripts/gds/package-core.js",
|
|
5
|
-
"core_version": "1.19.
|
|
6
|
-
"core_contract": "1.19.
|
|
7
|
-
"source_commit": "
|
|
5
|
+
"core_version": "1.19.952",
|
|
6
|
+
"core_contract": "1.19.952",
|
|
7
|
+
"source_commit": "76560f7026937d8fcb87e98f1cbb582781a7852a",
|
|
8
8
|
"source_ref": "HEAD",
|
|
9
|
-
"built_at": "2026-09-
|
|
9
|
+
"built_at": "2026-09-22T04:20:21.435Z",
|
|
10
10
|
"redaction": {
|
|
11
11
|
"model": "docs-redacted+functional-verbatim",
|
|
12
12
|
"docs_redacted": 513,
|
|
13
13
|
"agent_docs_stubbed": 26,
|
|
14
|
-
"functional_verbatim":
|
|
14
|
+
"functional_verbatim": 2350,
|
|
15
15
|
"rules": 3,
|
|
16
16
|
"gate_literals": 3,
|
|
17
17
|
"gate": "passed"
|
|
18
18
|
},
|
|
19
|
-
"file_count":
|
|
20
|
-
"tree_sha256": "
|
|
19
|
+
"file_count": 2889,
|
|
20
|
+
"tree_sha256": "b5e1b32c4cf3b07a161044a90c080241342270c91f71fcc551b02670ad0dd720",
|
|
21
21
|
"files": [
|
|
22
22
|
{
|
|
23
23
|
"path": ".claude/skills/ask-for-help/SKILL.md",
|
|
@@ -2687,7 +2687,7 @@
|
|
|
2687
2687
|
{
|
|
2688
2688
|
"path": "docs/module-api-changelog.md",
|
|
2689
2689
|
"mode": "0000644",
|
|
2690
|
-
"sha256": "
|
|
2690
|
+
"sha256": "961a09f17879832bc7fa1e4607a41bddcc1a2d08e0c9ce55c1e5de6ba5af822e"
|
|
2691
2691
|
},
|
|
2692
2692
|
{
|
|
2693
2693
|
"path": "docs/modules-contract.md",
|
|
@@ -6517,12 +6517,12 @@
|
|
|
6517
6517
|
{
|
|
6518
6518
|
"path": "modules/provisioning/capacity-gate.js",
|
|
6519
6519
|
"mode": "0000644",
|
|
6520
|
-
"sha256": "
|
|
6520
|
+
"sha256": "5d0d3eb34c68620b785803a40df416872e6a606cf6e144a9d2793f88bc231cb8"
|
|
6521
6521
|
},
|
|
6522
6522
|
{
|
|
6523
6523
|
"path": "modules/provisioning/capacity.js",
|
|
6524
6524
|
"mode": "0000644",
|
|
6525
|
-
"sha256": "
|
|
6525
|
+
"sha256": "56a2be9188fa0d8785174e6e91547c10266c3b6859fcad00aebd5739de4f366f"
|
|
6526
6526
|
},
|
|
6527
6527
|
{
|
|
6528
6528
|
"path": "modules/provisioning/catalog-bridge.js",
|
|
@@ -6649,6 +6649,11 @@
|
|
|
6649
6649
|
"mode": "0000644",
|
|
6650
6650
|
"sha256": "cdc3e8992d1e4273a472b826f208736235c8a3b16a700de33a7705cdae99ef9e"
|
|
6651
6651
|
},
|
|
6652
|
+
{
|
|
6653
|
+
"path": "modules/provisioning/migrations/provisioning_021_byo_host_shape.sql",
|
|
6654
|
+
"mode": "0000644",
|
|
6655
|
+
"sha256": "cde8a3a4c66c17d17c4e18866f11600a06073377de41d5ed70cd93185cd78d6d"
|
|
6656
|
+
},
|
|
6652
6657
|
{
|
|
6653
6658
|
"path": "modules/provisioning/module.json",
|
|
6654
6659
|
"mode": "0000644",
|
|
@@ -6657,12 +6662,12 @@
|
|
|
6657
6662
|
{
|
|
6658
6663
|
"path": "modules/provisioning/onboard-plan.js",
|
|
6659
6664
|
"mode": "0000644",
|
|
6660
|
-
"sha256": "
|
|
6665
|
+
"sha256": "c67f592415bb9c81e3eef658a7352c2bc47dfb4056b2cdef52f772e5021d28cf"
|
|
6661
6666
|
},
|
|
6662
6667
|
{
|
|
6663
6668
|
"path": "modules/provisioning/paid-shape-gate.js",
|
|
6664
6669
|
"mode": "0000644",
|
|
6665
|
-
"sha256": "
|
|
6670
|
+
"sha256": "cceda07080d1175a3629ebb2105e36220a2c2728768f2c6eb691f0269479a002"
|
|
6666
6671
|
},
|
|
6667
6672
|
{
|
|
6668
6673
|
"path": "modules/provisioning/pollers/catalog-backfill.js",
|
|
@@ -6682,7 +6687,7 @@
|
|
|
6682
6687
|
{
|
|
6683
6688
|
"path": "modules/provisioning/provisioning.js",
|
|
6684
6689
|
"mode": "0000644",
|
|
6685
|
-
"sha256": "
|
|
6690
|
+
"sha256": "82bb265d63bb882468bbb609faa60a783ccf7dfeec5cd4595550586c37131bda"
|
|
6686
6691
|
},
|
|
6687
6692
|
{
|
|
6688
6693
|
"path": "modules/provisioning/rate-limit.js",
|
|
@@ -6717,7 +6722,7 @@
|
|
|
6717
6722
|
{
|
|
6718
6723
|
"path": "modules/provisioning/routes/provisioning.js",
|
|
6719
6724
|
"mode": "0000644",
|
|
6720
|
-
"sha256": "
|
|
6725
|
+
"sha256": "a10d9ac50f6be584c33a6bb559ad9d0431c2ac7f4655c23fcdf47baedf540cd2"
|
|
6721
6726
|
},
|
|
6722
6727
|
{
|
|
6723
6728
|
"path": "modules/provisioning/seams.js",
|
|
@@ -7242,7 +7247,7 @@
|
|
|
7242
7247
|
{
|
|
7243
7248
|
"path": "modules/public-landing/public/projects.html",
|
|
7244
7249
|
"mode": "0000644",
|
|
7245
|
-
"sha256": "
|
|
7250
|
+
"sha256": "dab97906f2db723c0ec00aaf1a7930b7e0051098e6102704f65a6d0c705543ff"
|
|
7246
7251
|
},
|
|
7247
7252
|
{
|
|
7248
7253
|
"path": "modules/public-landing/public/projects.probes.json",
|
|
@@ -8042,12 +8047,12 @@
|
|
|
8042
8047
|
{
|
|
8043
8048
|
"path": "package-lock.json",
|
|
8044
8049
|
"mode": "0000644",
|
|
8045
|
-
"sha256": "
|
|
8050
|
+
"sha256": "09603574afd51f32c16292e9b19bd8bd8c8c57927721d5187229f414aeae1144"
|
|
8046
8051
|
},
|
|
8047
8052
|
{
|
|
8048
8053
|
"path": "package.json",
|
|
8049
8054
|
"mode": "0000644",
|
|
8050
|
-
"sha256": "
|
|
8055
|
+
"sha256": "7a932995f95a2d638f25c48b9b1312f29682ac863cf8b35b4ebe58e515cd42f1"
|
|
8051
8056
|
},
|
|
8052
8057
|
{
|
|
8053
8058
|
"path": "public-docs/index.html",
|
|
@@ -8122,7 +8127,7 @@
|
|
|
8122
8127
|
{
|
|
8123
8128
|
"path": "scripts/gds/adopt-preflight.js",
|
|
8124
8129
|
"mode": "0000644",
|
|
8125
|
-
"sha256": "
|
|
8130
|
+
"sha256": "9b16bbd8ceb60b801f042ad955b22b67c5703ce6dc8505bf333cefffbd3f37ae"
|
|
8126
8131
|
},
|
|
8127
8132
|
{
|
|
8128
8133
|
"path": "scripts/gds/adr-namespace.js",
|
|
@@ -8502,7 +8507,7 @@
|
|
|
8502
8507
|
{
|
|
8503
8508
|
"path": "scripts/gds/device-flow-help.js",
|
|
8504
8509
|
"mode": "0000644",
|
|
8505
|
-
"sha256": "
|
|
8510
|
+
"sha256": "843c7ec13103f121b5ff0056ba8d547dd20da837b5a04ef37c74bf4069411c38"
|
|
8506
8511
|
},
|
|
8507
8512
|
{
|
|
8508
8513
|
"path": "scripts/gds/diagnose-achievements.js",
|
|
@@ -8767,7 +8772,7 @@
|
|
|
8767
8772
|
{
|
|
8768
8773
|
"path": "scripts/gds/init.js",
|
|
8769
8774
|
"mode": "0000644",
|
|
8770
|
-
"sha256": "
|
|
8775
|
+
"sha256": "529a6af81068f10cd8eeb4738f4d2fd17aec41f40c4dd3195909828e4656fe28"
|
|
8771
8776
|
},
|
|
8772
8777
|
{
|
|
8773
8778
|
"path": "scripts/gds/install-git-hooks.js",
|
|
@@ -8842,7 +8847,7 @@
|
|
|
8842
8847
|
{
|
|
8843
8848
|
"path": "scripts/gds/login.js",
|
|
8844
8849
|
"mode": "0000644",
|
|
8845
|
-
"sha256": "
|
|
8850
|
+
"sha256": "a5502a11527ac903446e13536e78900c3af82b3382757a547e2561761ef7e396"
|
|
8846
8851
|
},
|
|
8847
8852
|
{
|
|
8848
8853
|
"path": "scripts/gds/main-audit.js",
|
|
@@ -8974,6 +8979,11 @@
|
|
|
8974
8979
|
"mode": "0000644",
|
|
8975
8980
|
"sha256": "b0e2c14720e8258eba4d4ef7f69cc2bcbb26c3be312deb891383dce7a1dbf71e"
|
|
8976
8981
|
},
|
|
8982
|
+
{
|
|
8983
|
+
"path": "scripts/gds/provision-byo-host.js",
|
|
8984
|
+
"mode": "0000644",
|
|
8985
|
+
"sha256": "92ef1fa760b90ece9781abe6d3c75abf84ff39cbb8b42194cca367bab7821269"
|
|
8986
|
+
},
|
|
8977
8987
|
{
|
|
8978
8988
|
"path": "scripts/gds/provision-capacity.js",
|
|
8979
8989
|
"mode": "0000644",
|
|
@@ -9027,7 +9037,7 @@
|
|
|
9027
9037
|
{
|
|
9028
9038
|
"path": "scripts/gds/provision.js",
|
|
9029
9039
|
"mode": "0000644",
|
|
9030
|
-
"sha256": "
|
|
9040
|
+
"sha256": "1d92b6cbbfb544328a8bacd29cb492445508617298c251872d846bb7ab5a180a"
|
|
9031
9041
|
},
|
|
9032
9042
|
{
|
|
9033
9043
|
"path": "scripts/gds/publish-credential-check.js",
|
|
@@ -9352,7 +9362,7 @@
|
|
|
9352
9362
|
{
|
|
9353
9363
|
"path": "scripts/gds/setup.js",
|
|
9354
9364
|
"mode": "0000644",
|
|
9355
|
-
"sha256": "
|
|
9365
|
+
"sha256": "edbebc4a0f4557cc8fc9dd0eb7115379a2fd0e34247725180cfb8eccb1cb0a18"
|
|
9356
9366
|
},
|
|
9357
9367
|
{
|
|
9358
9368
|
"path": "scripts/gds/ship-check.js",
|
|
@@ -10047,7 +10057,7 @@
|
|
|
10047
10057
|
{
|
|
10048
10058
|
"path": "src/module-api.js",
|
|
10049
10059
|
"mode": "0000644",
|
|
10050
|
-
"sha256": "
|
|
10060
|
+
"sha256": "e780332ee4be93e25030115f0a32c91e121aa0f9080e8f2abb0df1c0f3064eb0"
|
|
10051
10061
|
},
|
|
10052
10062
|
{
|
|
10053
10063
|
"path": "src/module-loader/catalog.js",
|
|
@@ -10167,7 +10177,7 @@
|
|
|
10167
10177
|
{
|
|
10168
10178
|
"path": "tests/adopt_preflight.mjs",
|
|
10169
10179
|
"mode": "0000644",
|
|
10170
|
-
"sha256": "
|
|
10180
|
+
"sha256": "c31b72a08ca2007497e6c44108f0de35aaea6d3cd1fd1a54e65162a8bf555012"
|
|
10171
10181
|
},
|
|
10172
10182
|
{
|
|
10173
10183
|
"path": "tests/adr_renumber_integrity.mjs",
|
|
@@ -10602,7 +10612,7 @@
|
|
|
10602
10612
|
{
|
|
10603
10613
|
"path": "tests/bongos_login.mjs",
|
|
10604
10614
|
"mode": "0000644",
|
|
10605
|
-
"sha256": "
|
|
10615
|
+
"sha256": "1e95957f3c780b4054128000e0deefc76e4df41c3076da76d2fbd187b47c95d2"
|
|
10606
10616
|
},
|
|
10607
10617
|
{
|
|
10608
10618
|
"path": "tests/box_access.mjs",
|
|
@@ -11137,7 +11147,7 @@
|
|
|
11137
11147
|
{
|
|
11138
11148
|
"path": "tests/discord_approvals.mjs",
|
|
11139
11149
|
"mode": "0000644",
|
|
11140
|
-
"sha256": "
|
|
11150
|
+
"sha256": "6f5e924b108a8738f3c7d4a97057049167a7a88a6f4af997321cd8585df3038b"
|
|
11141
11151
|
},
|
|
11142
11152
|
{
|
|
11143
11153
|
"path": "tests/discord_autojoin.mjs",
|
|
@@ -12277,7 +12287,7 @@
|
|
|
12277
12287
|
{
|
|
12278
12288
|
"path": "tests/init.mjs",
|
|
12279
12289
|
"mode": "0000644",
|
|
12280
|
-
"sha256": "
|
|
12290
|
+
"sha256": "9feeee7dbc2f1ae59a0af7eadbb521b74f114ce83e3f45ffdef59c1f8fdf25ec"
|
|
12281
12291
|
},
|
|
12282
12292
|
{
|
|
12283
12293
|
"path": "tests/instance_config.mjs",
|
|
@@ -12617,7 +12627,7 @@
|
|
|
12617
12627
|
{
|
|
12618
12628
|
"path": "tests/module_api.mjs",
|
|
12619
12629
|
"mode": "0000644",
|
|
12620
|
-
"sha256": "
|
|
12630
|
+
"sha256": "868942895e19730936594efb9f0fb69e4e511397ed738c05e0b27073c01846f7"
|
|
12621
12631
|
},
|
|
12622
12632
|
{
|
|
12623
12633
|
"path": "tests/module_api_lazy.mjs",
|
|
@@ -13062,7 +13072,7 @@
|
|
|
13062
13072
|
{
|
|
13063
13073
|
"path": "tests/projects_hub_pre_uat.mjs",
|
|
13064
13074
|
"mode": "0000644",
|
|
13065
|
-
"sha256": "
|
|
13075
|
+
"sha256": "19e1b68463ddccb1a1155e1adfb3d4c130711745030183fb1d27650f1bfe5444"
|
|
13066
13076
|
},
|
|
13067
13077
|
{
|
|
13068
13078
|
"path": "tests/promote_deps_gate.mjs",
|
|
@@ -13104,6 +13114,11 @@
|
|
|
13104
13114
|
"mode": "0000644",
|
|
13105
13115
|
"sha256": "9f62eea1b43a478334a83df52d0e81a3b3b67f4c4eea54680d2d8db3b25ee513"
|
|
13106
13116
|
},
|
|
13117
|
+
{
|
|
13118
|
+
"path": "tests/provision_byo_host.mjs",
|
|
13119
|
+
"mode": "0000644",
|
|
13120
|
+
"sha256": "79c33863862966ef0d7a0f4d9dc2290596a4f98da2796083b9319c24a6bfc26e"
|
|
13121
|
+
},
|
|
13107
13122
|
{
|
|
13108
13123
|
"path": "tests/provision_caddy_wiring.mjs",
|
|
13109
13124
|
"mode": "0000644",
|
|
@@ -13137,12 +13152,12 @@
|
|
|
13137
13152
|
{
|
|
13138
13153
|
"path": "tests/provisioning_capacity.mjs",
|
|
13139
13154
|
"mode": "0000644",
|
|
13140
|
-
"sha256": "
|
|
13155
|
+
"sha256": "7a48fb54dce89efa207d7dd254a8a5ef70c6b1958b6ed2be198a73e76bb74327"
|
|
13141
13156
|
},
|
|
13142
13157
|
{
|
|
13143
13158
|
"path": "tests/provisioning_capacity_gate.mjs",
|
|
13144
13159
|
"mode": "0000644",
|
|
13145
|
-
"sha256": "
|
|
13160
|
+
"sha256": "363405d0f78714e9e3c29ee6ce64a1735a96fdaa95c631930743019daf8e26ff"
|
|
13146
13161
|
},
|
|
13147
13162
|
{
|
|
13148
13163
|
"path": "tests/provisioning_credential_preflight.mjs",
|
|
@@ -13182,17 +13197,17 @@
|
|
|
13182
13197
|
{
|
|
13183
13198
|
"path": "tests/provisioning_module_selection.mjs",
|
|
13184
13199
|
"mode": "0000644",
|
|
13185
|
-
"sha256": "
|
|
13200
|
+
"sha256": "8eaa3b40b38cbc294836ac3c4905f6a0a7c4a04e9c68d443e503f479a735c839"
|
|
13186
13201
|
},
|
|
13187
13202
|
{
|
|
13188
13203
|
"path": "tests/provisioning_onboard_mode.mjs",
|
|
13189
13204
|
"mode": "0000644",
|
|
13190
|
-
"sha256": "
|
|
13205
|
+
"sha256": "96c7ea0d646151393767061f042082f006007390ff652c7c649fd9151ab2ed61"
|
|
13191
13206
|
},
|
|
13192
13207
|
{
|
|
13193
13208
|
"path": "tests/provisioning_paid_shape_gate.mjs",
|
|
13194
13209
|
"mode": "0000644",
|
|
13195
|
-
"sha256": "
|
|
13210
|
+
"sha256": "859a44a139cfc7a52bc534dac8dc52f1203d60d5bdaac34e64834b6838e128fe"
|
|
13196
13211
|
},
|
|
13197
13212
|
{
|
|
13198
13213
|
"path": "tests/provisioning_recommendations.mjs",
|
|
@@ -2374,5 +2374,9 @@ is load-bearing: the script throws rather than guess if it is missing, and
|
|
|
2374
2374
|
landed since 1.19.948 with no explicit bump. run 35675336642. (task 1002620)
|
|
2375
2375
|
1.19.950 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
2376
2376
|
landed since 1.19.949 with no explicit bump. run 35683452297. (task 1002620)
|
|
2377
|
+
1.19.951 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
2378
|
+
landed since 1.19.950 with no explicit bump. run 35685346231. (task 1002620)
|
|
2379
|
+
1.19.952 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
2380
|
+
landed since 1.19.951 with no explicit bump. run 35686469735. (task 1002620)
|
|
2377
2381
|
---------------------------------------------------------------------------
|
|
2378
2382
|
```
|
|
@@ -26,7 +26,13 @@ function requireRoomOnBox(db, log) {
|
|
|
26
26
|
return async function capacityGate(req, res, next) {
|
|
27
27
|
const body = req.body || {};
|
|
28
28
|
// The handler's own default and validation: a malformed request gets its 400 there.
|
|
29
|
-
|
|
29
|
+
// The absent-shape default MUST match createInstance's coercion and the paid-shape
|
|
30
|
+
// gate's, or this gate prices a request against a shape the row will not take. It
|
|
31
|
+
// was 'co-tenant' until ADR 0323; that shape lands on the control plane, so after the
|
|
32
|
+
// default moved to 'byo-host' — which runs on the OWNER's machine and takes no slot
|
|
33
|
+
// here — a shapeless create on a full box would have been refused box_full for
|
|
34
|
+
// capacity it never consumes. Three places default this; they agree deliberately.
|
|
35
|
+
const shape = body.hosting_shape || 'byo-host';
|
|
30
36
|
const slug = String(body.slug || '').trim().toLowerCase();
|
|
31
37
|
if (!provisioning.HOSTING_SHAPES.includes(shape) || !provisioning.isValidSlug(slug)) return next();
|
|
32
38
|
const target = capacity.placementBox(shape, { remoteHost: process.env.PROVISION_REMOTE_HOST || null });
|
|
@@ -68,8 +68,14 @@ function parseMeminfo(text) {
|
|
|
68
68
|
// local (task 2074); a co-tenant runs on the remote co-hosting box only when the
|
|
69
69
|
// runner is in remote-exec mode (ADR 0130), else here. A dedicated droplet is its
|
|
70
70
|
// own box and has no shared ceiling → null (no preflight).
|
|
71
|
+
//
|
|
72
|
+
// A 'byo-host' (ADR 0323) also answers null, for a stronger reason than dedicated's:
|
|
73
|
+
// the owner supplies the machine, so the platform has no box to place it on and no
|
|
74
|
+
// memory of its own to spend. It can never be refused for capacity, and it must never
|
|
75
|
+
// consume a slot that a cloud-host would otherwise get — which is what returning null
|
|
76
|
+
// here buys, since PLACED_STATES counting keys off the shapes a box declares.
|
|
71
77
|
function placementBox(hostingShape, { remoteHost = null } = {}) {
|
|
72
|
-
if (hostingShape === 'dedicated') return null;
|
|
78
|
+
if (hostingShape === 'dedicated' || hostingShape === 'byo-host') return null;
|
|
73
79
|
if (hostingShape === 'co-tenant' && remoteHost) {
|
|
74
80
|
return { box: 'overflow', shapes: ['co-tenant'], fixedMb: FIXED_MB.overflow };
|
|
75
81
|
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
-- provisioning_021 — admit the 'byo-host' hosting shape (ADR 0323, task 1004141).
|
|
2
|
+
--
|
|
3
|
+
-- "Bring your own host": the OWNER runs the instance on their own machine, VPS or
|
|
4
|
+
-- platform account. The platform stands up nothing and reaches into nothing, so the
|
|
5
|
+
-- row is a record of an instance we do not operate — liveness is the ADR 0252 pull
|
|
6
|
+
-- against an owner-supplied origin.
|
|
7
|
+
--
|
|
8
|
+
-- A CHECK-ENUM WIDENING, and nothing else. `DROP CONSTRAINT IF EXISTS` paired with a
|
|
9
|
+
-- re-`ADD CONSTRAINT` of the SAME name in the SAME migration only ever PERMITS more
|
|
10
|
+
-- values: no existing row changes and no data is lost, which is why fitness.js
|
|
11
|
+
-- (isConstraintWidening) treats this exact shape as additive rather than destructive.
|
|
12
|
+
-- The precedent is provisioning_002, which admitted 'standalone' the same way.
|
|
13
|
+
--
|
|
14
|
+
-- 'co-tenant' STAYS IN THE SET even though ADR 0323 retires it. Retirement closes the
|
|
15
|
+
-- DOOR, not the record: one torn-down row still carries that value, and dropping it
|
|
16
|
+
-- from the constraint would make a historical row violate its own table. The door is
|
|
17
|
+
-- closed in code instead — paid-shape-gate.js lists it UNREQUESTABLE, so no new row can
|
|
18
|
+
-- ever take it, while the old one stays readable. A shape that is storable but never
|
|
19
|
+
-- grantable again is exactly what that set is for.
|
|
20
|
+
--
|
|
21
|
+
-- The two managed shapes keep their OLD stored spellings ('standalone', 'dedicated')
|
|
22
|
+
-- on purpose. ADR 0323 renames them owner-facing to "cloud host" and "dedicated cloud
|
|
23
|
+
-- host", but about half the code reading those values is landlord machinery that task
|
|
24
|
+
-- 1004142 deletes when it moves them to a managed platform, and renaming a call site a
|
|
25
|
+
-- task before deleting it is work done twice. That task carries the data rename with
|
|
26
|
+
-- those files already open.
|
|
27
|
+
|
|
28
|
+
ALTER TABLE provisioning_instances DROP CONSTRAINT IF EXISTS provisioning_instances_hosting_shape_check;
|
|
29
|
+
ALTER TABLE provisioning_instances ADD CONSTRAINT provisioning_instances_hosting_shape_check
|
|
30
|
+
CHECK (hosting_shape IN ('byo-host', 'co-tenant', 'dedicated', 'standalone', 'control-plane'));
|
|
31
|
+
|
|
32
|
+
-- The COLUMN default was 'co-tenant' (provisioning_001), which is now a retired shape.
|
|
33
|
+
-- Every insert today goes through createInstance, which always passes an explicit shape,
|
|
34
|
+
-- so nothing currently relies on this default — which is exactly why it is worth moving
|
|
35
|
+
-- now rather than leaving a loaded gun for the first insert that ever omits the column.
|
|
36
|
+
-- Changing a DEFAULT rewrites no existing row.
|
|
37
|
+
ALTER TABLE provisioning_instances ALTER COLUMN hosting_shape SET DEFAULT 'byo-host';
|
|
@@ -34,11 +34,18 @@
|
|
|
34
34
|
// `shapes` (task 1002696; direction §7 — a surface renders only steps somebody real
|
|
35
35
|
// will perform on THIS instance's shape). The control-plane shapes (standalone /
|
|
36
36
|
// co-tenant / dedicated) have the platform's runner performing every 'auto' leg;
|
|
37
|
-
// '
|
|
38
|
-
// a
|
|
39
|
-
// with no `shapes` apply everywhere. Filter with stepsForShape().
|
|
37
|
+
// 'byo-host' has no runner, so the runner-performed legs are absent from its plan —
|
|
38
|
+
// a bring-your-own-host form must never promise them (QA walk finding, task 1002717).
|
|
39
|
+
// Steps with no `shapes` apply everywhere. Filter with stepsForShape().
|
|
40
|
+
//
|
|
41
|
+
// 'byo-host' REPLACED the plan-only spelling 'self-host' here (ADR 0323, task 1004141).
|
|
42
|
+
// That value was this file's own invention and had no callers anywhere else, so it was
|
|
43
|
+
// a second vocabulary for a concept the hosting shapes now name directly — and two words
|
|
44
|
+
// for one thing is how a filter starts silently matching nothing. The shape is absent
|
|
45
|
+
// from CONTROL_PLANE_SHAPES, which is what drops the runner-performed legs from its plan
|
|
46
|
+
// BY CONSTRUCTION rather than by a list someone has to remember to update.
|
|
40
47
|
const CONTROL_PLANE_SHAPES = ['standalone', 'co-tenant', 'dedicated'];
|
|
41
|
-
const ALL_SHAPES = [...CONTROL_PLANE_SHAPES, '
|
|
48
|
+
const ALL_SHAPES = [...CONTROL_PLANE_SHAPES, 'byo-host'];
|
|
42
49
|
|
|
43
50
|
function onboardPlan(mode = 'greenfield', opts = {}) {
|
|
44
51
|
const adopt = mode === 'adopt';
|
|
@@ -13,8 +13,15 @@
|
|
|
13
13
|
// the shapes it accepts is actually that front door. The others each hand the caller
|
|
14
14
|
// something the platform pays for or trusts:
|
|
15
15
|
//
|
|
16
|
-
//
|
|
17
|
-
//
|
|
16
|
+
// byo-host — the front door since ADR 0323. The OWNER supplies the host, so the
|
|
17
|
+
// platform pays nothing and runs none of the caller's code. No
|
|
18
|
+
// authority required, ever. This is the shape that replaced 'co-tenant'
|
|
19
|
+
// as the free option, and it is a STRONGER front door than co-tenant
|
|
20
|
+
// was: co-tenant was free of charge but still ran on our box, whereas
|
|
21
|
+
// this one never touches it.
|
|
22
|
+
// co-tenant — RETIRED (ADR 0323). Was the free front door; ran on the platform's
|
|
23
|
+
// own box, which is why the name could not be carried over to
|
|
24
|
+
// bring-your-own-host. Now UNREQUESTABLE — see below.
|
|
18
25
|
// dedicated — allocates a real droplet (`scripts/gds/provision.js`), billed
|
|
19
26
|
// monthly, defaulting to s-2vcpu-4gb when no tier is named.
|
|
20
27
|
// standalone — runs the caller's OWN repo on the platform's box. The unit's
|
|
@@ -61,11 +68,11 @@
|
|
|
61
68
|
const provisioning = require('./provisioning.js');
|
|
62
69
|
|
|
63
70
|
// The shapes any authenticated builder may request with no permission at all. This is
|
|
64
|
-
// the whole allow-list, and it is deliberately one entry long:
|
|
71
|
+
// the whole allow-list, and it is deliberately one entry long: byo-host is the front
|
|
65
72
|
// door, and the front door is the only thing that should be free. `tests/
|
|
66
73
|
// provisioning_paid_shape_gate.mjs` pins HOSTING_SHAPES against this set so a new shape
|
|
67
74
|
// cannot be added without someone deciding, in writing, which side of the line it is on.
|
|
68
|
-
const OPEN_SHAPES = Object.freeze(new Set(['
|
|
75
|
+
const OPEN_SHAPES = Object.freeze(new Set(['byo-host']));
|
|
69
76
|
|
|
70
77
|
// Shapes that are not requestable through this route AT ALL — no permission admits them,
|
|
71
78
|
// because there is no rank at which "ask the API for a second control plane" is a
|
|
@@ -75,7 +82,13 @@ const OPEN_SHAPES = Object.freeze(new Set(['co-tenant']));
|
|
|
75
82
|
// `WHERE hosting_shape = 'control-plane' LIMIT 1`, so a second row makes "which machine
|
|
76
83
|
// is the control plane" a question with a caller-influenced answer. Refused by name, at
|
|
77
84
|
// the door, for the same reason control-plane-guard.js refuses by name.
|
|
78
|
-
|
|
85
|
+
// 'co-tenant' joins it for a different reason (ADR 0323): it is RETIRED, not secret.
|
|
86
|
+
// It remains a valid stored value because a torn-down row still carries it, so it cannot
|
|
87
|
+
// simply leave HOSTING_SHAPES without making that row's history unreadable — and a shape
|
|
88
|
+
// that is storable but must never be granted again is exactly what 'unrequestable' means.
|
|
89
|
+
// Refusing it here rather than deleting the value is what makes the retirement complete
|
|
90
|
+
// without rewriting the past.
|
|
91
|
+
const UNREQUESTABLE_SHAPES = Object.freeze(new Set(['control-plane', 'co-tenant']));
|
|
79
92
|
|
|
80
93
|
// shapeAuthority — what does this wire value demand? PURE. Returns one of:
|
|
81
94
|
// 'open' → admit with no permission
|
|
@@ -88,7 +101,7 @@ const UNREQUESTABLE_SHAPES = Object.freeze(new Set(['control-plane']));
|
|
|
88
101
|
//
|
|
89
102
|
// 'defer' is safe despite looking like a hole: the validator runs immediately after this
|
|
90
103
|
// middleware and refuses anything outside HOSTING_SHAPES, and `createInstance` coerces an
|
|
91
|
-
// unrecognised shape to '
|
|
104
|
+
// unrecognised shape to 'byo-host' rather than storing it. There is no path by which a
|
|
92
105
|
// deferred value becomes a privileged row.
|
|
93
106
|
//
|
|
94
107
|
// Matches the exact wire value — a case or whitespace variant of a privileged shape is
|
|
@@ -96,7 +109,7 @@ const UNREQUESTABLE_SHAPES = Object.freeze(new Set(['control-plane']));
|
|
|
96
109
|
// admitted as a cheap one.
|
|
97
110
|
function shapeAuthority(rawShape) {
|
|
98
111
|
const shape = rawShape === undefined || rawShape === null || rawShape === ''
|
|
99
|
-
? '
|
|
112
|
+
? 'byo-host' // an absent shape is the documented default, and it is the open one
|
|
100
113
|
: rawShape;
|
|
101
114
|
if (typeof shape !== 'string') return 'defer';
|
|
102
115
|
if (!provisioning.HOSTING_SHAPES.includes(shape)) return 'defer';
|
|
@@ -115,9 +128,25 @@ function requireAuthorityForShape(requirePermission) {
|
|
|
115
128
|
const verdict = shapeAuthority(req.body && req.body.hosting_shape);
|
|
116
129
|
if (verdict === 'open' || verdict === 'defer') return next();
|
|
117
130
|
if (verdict === 'unrequestable') {
|
|
131
|
+
// Two shapes land here for different reasons, so the message names which.
|
|
132
|
+
//
|
|
133
|
+
// It names STORED VALUES and never an owner-facing label, deliberately. The
|
|
134
|
+
// stored value → owner-facing name translation lives in exactly one place —
|
|
135
|
+
// SHAPE_LABEL in modules/public-landing/public/projects.html (ADR 0323, and this
|
|
136
|
+
// module's CLAUDE.md says so) — and an API error string is the worst possible
|
|
137
|
+
// second copy of it: the next person to rename the product renames the label map
|
|
138
|
+
// and a wizard heading, and this sentence keeps selling a name that no longer
|
|
139
|
+
// exists. The right register for a 403 is the wire vocabulary the caller sent,
|
|
140
|
+
// which is also what `details.requestable` already hands them; a UI that wants to
|
|
141
|
+
// say it in product words has SHAPE_LABEL for exactly that. The guard against it
|
|
142
|
+
// creeping back is an assertion, not this comment — see
|
|
143
|
+
// ../../tests/provisioning_paid_shape_gate.mjs.
|
|
144
|
+
const retired = req.body.hosting_shape === 'co-tenant';
|
|
118
145
|
return res.fail('shape_not_requestable', {
|
|
119
146
|
status: 403,
|
|
120
|
-
message:
|
|
147
|
+
message: retired
|
|
148
|
+
? "That hosting shape has been retired and can no longer be requested. Ask for one of the shapes in `requestable` instead: `byo-host` runs on a host you supply, and the rest are stood up for you."
|
|
149
|
+
: 'The control plane enrolls its own row; it cannot be requested through this route.',
|
|
121
150
|
details: { hosting_shape: req.body.hosting_shape, requestable: [...provisioning.HOSTING_SHAPES].filter((s) => !UNREQUESTABLE_SHAPES.has(s)) },
|
|
122
151
|
});
|
|
123
152
|
}
|
|
@@ -24,11 +24,8 @@ const { normalizeModuleSelection, effectiveModules } = require('./starter-bundle
|
|
|
24
24
|
// Constants (mirror the CHECK constraints in provisioning_001_tables.sql)
|
|
25
25
|
// ---------------------------------------------------------------------------
|
|
26
26
|
const INSTANCE_STATES = ['requested', 'provisioning', 'active', 'tearing_down', 'torn_down', 'error'];
|
|
27
|
-
//
|
|
28
|
-
|
|
29
|
-
// standalone — its OWN repo checkout + pinned @cloudbongos/core npm dep, co-located on
|
|
30
|
-
// the box (ADR 0108 destination model; owner-hosted, $0). See provision.js.
|
|
31
|
-
const HOSTING_SHAPES = ['co-tenant', 'dedicated', 'standalone', 'control-plane'];
|
|
27
|
+
// Shapes, owner-facing names + why the spellings differ: ADR 0323 + this module's CLAUDE.md.
|
|
28
|
+
const HOSTING_SHAPES = ['byo-host', 'co-tenant', 'dedicated', 'standalone', 'control-plane'];
|
|
32
29
|
// How the instance's repo was onboarded (migration provisioning_004, ADR 0121):
|
|
33
30
|
// greenfield — a fresh EMPTY repo; the runner scaffolds it and pushes the first commit
|
|
34
31
|
// adopt — a repo the owner ALREADY has; the runner must LAYER onto it, preserving
|
|
@@ -1061,7 +1058,10 @@ async function listAllInstances(db, { status } = {}) {
|
|
|
1061
1058
|
// decide (same owner → idempotent re-request; different owner → 409). Never
|
|
1062
1059
|
// silently reassigns ownership.
|
|
1063
1060
|
async function createInstance(db, { ownerBuilderId, slug, targetRef, hostingShape, domain, dbName, port, tier, onboardMode, type, description, detail, modules }) {
|
|
1064
|
-
|
|
1061
|
+
// Unknown/absent coerces to the shape that costs nothing and trusts nothing. Was
|
|
1062
|
+
// 'co-tenant' (then the free front door); that shape is now retired + unrequestable,
|
|
1063
|
+
// so coercing to it would mint a row no caller is allowed to ask for.
|
|
1064
|
+
const shape = HOSTING_SHAPES.includes(hostingShape) ? hostingShape : 'byo-host';
|
|
1065
1065
|
// Unknown/absent → 'greenfield', matching the column default. Falling back to the
|
|
1066
1066
|
// SAFE mode matters: greenfield refuses to push over existing history (no --force
|
|
1067
1067
|
// anywhere), whereas defaulting an unknown value to 'adopt' would put the layering
|
|
@@ -12,10 +12,12 @@
|
|
|
12
12
|
//
|
|
13
13
|
// own-scoped (requireBuilder — the caller's OWN instances):
|
|
14
14
|
// POST /provisioning/instances — request a new instance
|
|
15
|
-
// (only `
|
|
16
|
-
// shape ALSO
|
|
17
|
-
//
|
|
18
|
-
//
|
|
15
|
+
// (only `byo-host` is free — ADR 0323 made it
|
|
16
|
+
// the front door; every other shape ALSO
|
|
17
|
+
// needs provisioning.fleet.manage, and
|
|
18
|
+
// `control-plane` and the RETIRED `co-tenant`
|
|
19
|
+
// are not requestable at all;
|
|
20
|
+
// ../paid-shape-gate.js.
|
|
19
21
|
// An `adopt` ALSO passes the credential
|
|
20
22
|
// preflight — ../credential-preflight.js,
|
|
21
23
|
// task 1002909; greenfield is exempt; a full box → 409, ../capacity-gate.js)
|
|
@@ -331,7 +333,15 @@ module.exports = function provisioningRoutes() {
|
|
|
331
333
|
if (!provisioning.isValidSlug(slug)) {
|
|
332
334
|
return res.fail('bad_slug', 400, { reason: 'lowercase, 2–40 chars of [a-z0-9-], no leading/trailing/double dash' });
|
|
333
335
|
}
|
|
334
|
-
|
|
336
|
+
// FOURTH and last place that resolves an absent shape, and they must all agree:
|
|
337
|
+
// this route, paid-shape-gate.js's authority lookup, capacity-gate.js's placement
|
|
338
|
+
// lookup, and createInstance's coercion. Until ADR 0323 they agreed on 'co-tenant'.
|
|
339
|
+
// When that shape was retired this line was the hole: the gate admits an absent
|
|
340
|
+
// shape as 'byo-host' (open), and then a stale default here would hand createInstance
|
|
341
|
+
// a literal 'co-tenant' — which IS in HOSTING_SHAPES, so the coercion never fires and
|
|
342
|
+
// the validator never complains, and a shapeless create quietly stores the one shape
|
|
343
|
+
// no caller is allowed to request. Nothing would have errored.
|
|
344
|
+
const shape = body.hosting_shape || 'byo-host';
|
|
335
345
|
if (!provisioning.HOSTING_SHAPES.includes(shape)) {
|
|
336
346
|
return res.fail('bad_hosting_shape', 400, { valid: provisioning.HOSTING_SHAPES });
|
|
337
347
|
}
|
|
@@ -3934,7 +3934,9 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
3934
3934
|
['Address', resolvedDomain()
|
|
3935
3935
|
? '<code>' + esc(resolvedDomain()) + '</code>'
|
|
3936
3936
|
: '<em style="font-weight:600;color:var(--warn)">none — sign-in stays locked until it has one</em>'],
|
|
3937
|
-
|
|
3937
|
+
/* The wizard creates hosting_shape 'standalone', whose owner-facing name is
|
|
3938
|
+
"cloud host" (ADR 0323) — we stand it up and run it for them. */
|
|
3939
|
+
['Shape', 'Cloud host — we stand it up and run it for you, on the platform’s current release']
|
|
3938
3940
|
];
|
|
3939
3941
|
$('reviewList').innerHTML = rows.map(function (r) {
|
|
3940
3942
|
return '<li><span class="k">' + r[0] + '</span><span class="v">' + r[1] + '</span></li>';
|
|
@@ -5205,7 +5207,20 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
5205
5207
|
|
|
5206
5208
|
/* ── rendering ───────────────────────────────────────────────────────── */
|
|
5207
5209
|
|
|
5208
|
-
|
|
5210
|
+
/* The owner-facing name of each hosting shape (ADR 0323). This map IS the translation
|
|
5211
|
+
between the stored value and the word the owner reads: 'standalone' and 'dedicated'
|
|
5212
|
+
keep their old spellings in the database on purpose (task 1004142 renames the data),
|
|
5213
|
+
so this is the ONLY place that difference should ever be visible. Read as a noun
|
|
5214
|
+
phrase — it lands in a meta list and in the "server" ledger row.
|
|
5215
|
+
'co-tenant' is retired and unrequestable, but one torn-down row still carries it,
|
|
5216
|
+
so it keeps a label rather than falling through to the raw value. */
|
|
5217
|
+
var SHAPE_LABEL = {
|
|
5218
|
+
'byo-host': 'your own host',
|
|
5219
|
+
standalone: 'cloud host',
|
|
5220
|
+
dedicated: 'dedicated cloud host',
|
|
5221
|
+
'co-tenant': 'shared server (retired)',
|
|
5222
|
+
'control-plane': 'the control plane'
|
|
5223
|
+
};
|
|
5209
5224
|
/* what a teardown ACTUALLY does, per hosting shape (F17 — the DECIDED policy:
|
|
5210
5225
|
retention is deliberate on shared boxes; a dedicated machine takes its
|
|
5211
5226
|
database with it). Copy follows the runner, never the other way around. */
|
package/package-lock.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bongos/core",
|
|
3
|
-
"version": "1.19.
|
|
3
|
+
"version": "1.19.952",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@bongos/core",
|
|
9
|
-
"version": "1.19.
|
|
9
|
+
"version": "1.19.952",
|
|
10
10
|
"license": "AGPL-3.0-or-later",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"express": "^4.21.2",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bongos/core",
|
|
3
|
-
"version": "1.19.
|
|
3
|
+
"version": "1.19.952",
|
|
4
4
|
"description": "Cloud Bongos — the AI-first build platform core (GDS + platform surfaces + module system), installed as a versioned dependency (ADR 0108).",
|
|
5
5
|
"license": "AGPL-3.0-or-later",
|
|
6
6
|
"main": "src/platform-server.js",
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
// • CI collisions — the repo's workflows vs core's expected unit/secret-scan/
|
|
13
13
|
// gate-review checks.
|
|
14
14
|
// • IGNORED incoming files — a pre-existing .gitignore rule that would swallow what
|
|
15
|
-
// adopt is about to commit (task
|
|
15
|
+
// adopt is about to commit (task 1003881). This is the check that was missing when
|
|
16
16
|
// Cloud Bongos was adopted onto a repo whose .gitignore already carried `.claude/`:
|
|
17
17
|
// the skills, hooks and settings.json were materialized onto disk and then dropped
|
|
18
18
|
// by `git add`, so the adopt commit landed 8 files with no methodology surface at
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
'use strict';
|
|
3
3
|
// scripts/gds/device-flow-help.js — the one explanation of a Device-Flow refusal, shared
|
|
4
|
-
// by `bongos setup` and `bongos login` (task
|
|
4
|
+
// by `bongos setup` and `bongos login` (task 1003881).
|
|
5
5
|
//
|
|
6
6
|
// WHY IT EXISTS AT ALL. GitHub creates an App from a manifest with Device Flow OFF and
|
|
7
7
|
// exposes no API to switch it on — only a checkbox in the App's settings. So on every
|