@bongos/core 1.20.27 → 1.20.29
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 +75 -45
- 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 +2 -0
- package/clients/bongos-client/index.mjs +2 -0
- package/docs/adr/0335-an-invite-is-a-pre-approved-row-on-the-projects-own-instance.md +1 -1
- package/docs/adr/0353-a-hub-invite-is-a-notice-of-the-projects-own-invite.md +1 -1
- package/docs/adr/0356-a-recruit-invite-expires-30-days-after-it-is-sent-read-time.md +46 -0
- package/docs/adr/README.md +1 -0
- package/docs/api/openapi.json +51 -3
- package/docs/api-reference.md +3 -2
- package/docs/copy-inventory.md +20 -19
- package/docs/copy-registry.json +34 -25
- package/docs/module-api-changelog.md +5 -1
- package/docs/page-readings.json +9 -9
- package/migrations/core_266_access_requests_invited_login_idx.sql +31 -0
- package/modules/hall-ui/public/watch.js +9 -3
- package/modules/onboarding/routes/access-requests.js +43 -20
- package/modules/platform-identity/platform-identity.js +12 -8
- package/modules/platform-identity/tests/platform-identity.mjs +4 -2
- package/modules/provisioning/core-upgrade.js +70 -1
- package/modules/provisioning/migrations/provisioning_029_update_channel.sql +24 -0
- package/modules/provisioning/routes/core-upgrade.js +21 -1
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/release-notes.json +16 -0
- package/scripts/gds/fitness.js +4 -0
- package/scripts/gds/login.js +6 -0
- package/scripts/gds/provision-core-upgrade.js +17 -11
- package/scripts/gds/run-unit-tests.js +4 -0
- package/src/bongos/db-kernel.js +6 -3
- package/src/bongos/invite-expiry.js +47 -0
- package/src/module-api.js +10 -1
- package/tests/access_requests_invite.mjs +2 -1
- package/tests/application_lifecycle.mjs +164 -5
- package/tests/bongos_login.mjs +2 -0
- package/tests/core_upgrade_door.mjs +80 -1
- package/tests/core_upgrade_runner.mjs +54 -1
- package/tests/hub_invite_notices.mjs +5 -2
- package/tests/invite_expiry.mjs +37 -0
- package/tests/invite_expiry_db.mjs +196 -0
- package/tests/module_api.mjs +1 -0
- package/tests/project_admin_console_model.mjs +12 -5
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.20.
|
|
6
|
-
"core_contract": "1.20.
|
|
7
|
-
"source_commit": "
|
|
5
|
+
"core_version": "1.20.29",
|
|
6
|
+
"core_contract": "1.20.29",
|
|
7
|
+
"source_commit": "c6152c075da2e7e656381b46f3f9b561cf65f457",
|
|
8
8
|
"source_ref": "HEAD",
|
|
9
|
-
"built_at": "2026-09-
|
|
9
|
+
"built_at": "2026-09-30T20:49:43.614Z",
|
|
10
10
|
"redaction": {
|
|
11
11
|
"model": "docs-redacted+functional-verbatim",
|
|
12
|
-
"docs_redacted":
|
|
12
|
+
"docs_redacted": 562,
|
|
13
13
|
"agent_docs_stubbed": 25,
|
|
14
|
-
"functional_verbatim":
|
|
14
|
+
"functional_verbatim": 2660,
|
|
15
15
|
"rules": 3,
|
|
16
16
|
"gate_literals": 3,
|
|
17
17
|
"gate": "passed"
|
|
18
18
|
},
|
|
19
|
-
"file_count":
|
|
20
|
-
"tree_sha256": "
|
|
19
|
+
"file_count": 3248,
|
|
20
|
+
"tree_sha256": "91a5ebee3fc044967031c6f7dbb8e2a86b98fe305e68353f39c023c5ab042df9",
|
|
21
21
|
"files": [
|
|
22
22
|
{
|
|
23
23
|
"path": ".claude/skills/ask-for-help/SKILL.md",
|
|
@@ -327,12 +327,12 @@
|
|
|
327
327
|
{
|
|
328
328
|
"path": "clients/bongos-client/README.md",
|
|
329
329
|
"mode": "0000644",
|
|
330
|
-
"sha256": "
|
|
330
|
+
"sha256": "08c6eaeee75d4fa5a447578107738e5357ffe088bde7f64e946a5f82d1c06106"
|
|
331
331
|
},
|
|
332
332
|
{
|
|
333
333
|
"path": "clients/bongos-client/bongos-client.global.js",
|
|
334
334
|
"mode": "0000644",
|
|
335
|
-
"sha256": "
|
|
335
|
+
"sha256": "808fd2048e5260dd4cc518d0e4697636b99ec393c925caa1d858976da2590baf"
|
|
336
336
|
},
|
|
337
337
|
{
|
|
338
338
|
"path": "clients/bongos-client/examples/hello-world.mjs",
|
|
@@ -342,17 +342,17 @@
|
|
|
342
342
|
{
|
|
343
343
|
"path": "clients/bongos-client/index.cjs",
|
|
344
344
|
"mode": "0000644",
|
|
345
|
-
"sha256": "
|
|
345
|
+
"sha256": "d6484208dc9acee624ed01503c36ad9fa4f06bd1e7b51738e2c58c1fe251ace8"
|
|
346
346
|
},
|
|
347
347
|
{
|
|
348
348
|
"path": "clients/bongos-client/index.d.ts",
|
|
349
349
|
"mode": "0000644",
|
|
350
|
-
"sha256": "
|
|
350
|
+
"sha256": "6298f90c0b7849ca342dd5e5235df57686e36b666cedba8db2d9018e8acb60c1"
|
|
351
351
|
},
|
|
352
352
|
{
|
|
353
353
|
"path": "clients/bongos-client/index.mjs",
|
|
354
354
|
"mode": "0000644",
|
|
355
|
-
"sha256": "
|
|
355
|
+
"sha256": "eded947e375da51b79857e9d3452f21fbfca2136e774b2a3907d1a4d51436aa9"
|
|
356
356
|
},
|
|
357
357
|
{
|
|
358
358
|
"path": "clients/bongos-client/package.json",
|
|
@@ -2147,7 +2147,7 @@
|
|
|
2147
2147
|
{
|
|
2148
2148
|
"path": "docs/adr/0335-an-invite-is-a-pre-approved-row-on-the-projects-own-instance.md",
|
|
2149
2149
|
"mode": "0000644",
|
|
2150
|
-
"sha256": "
|
|
2150
|
+
"sha256": "826c6c6ae6e10af9383e518ff63196e2b947bc0ecfa0c1be0288895751bc1352"
|
|
2151
2151
|
},
|
|
2152
2152
|
{
|
|
2153
2153
|
"path": "docs/adr/0336-a-guilds-record-is-the-sum-of-what-its-members-already-show.md",
|
|
@@ -2237,7 +2237,7 @@
|
|
|
2237
2237
|
{
|
|
2238
2238
|
"path": "docs/adr/0353-a-hub-invite-is-a-notice-of-the-projects-own-invite.md",
|
|
2239
2239
|
"mode": "0000644",
|
|
2240
|
-
"sha256": "
|
|
2240
|
+
"sha256": "e4ee7809ea3f414ecfdbe0b3e6e4b435c1ccc25084fce9c3cfa3521943fe8b90"
|
|
2241
2241
|
},
|
|
2242
2242
|
{
|
|
2243
2243
|
"path": "docs/adr/0354-a-builder-hosts-one-project-free-and-more-takes-the-fleet-permission.md",
|
|
@@ -2249,20 +2249,25 @@
|
|
|
2249
2249
|
"mode": "0000644",
|
|
2250
2250
|
"sha256": "6ad8ab3bd8bcb4f55575232af651f108e3879a5965f5daaac42ab693d00a1f0a"
|
|
2251
2251
|
},
|
|
2252
|
+
{
|
|
2253
|
+
"path": "docs/adr/0356-a-recruit-invite-expires-30-days-after-it-is-sent-read-time.md",
|
|
2254
|
+
"mode": "0000644",
|
|
2255
|
+
"sha256": "ccbad5d4326b069381db47ea3fc165f9a4020485e3d6ce346393a2f6711ce1f0"
|
|
2256
|
+
},
|
|
2252
2257
|
{
|
|
2253
2258
|
"path": "docs/adr/README.md",
|
|
2254
2259
|
"mode": "0000644",
|
|
2255
|
-
"sha256": "
|
|
2260
|
+
"sha256": "d21d0eb8389864b4f7394ba0f4b0d0d809182f0bef82d9fc6824edd00e174b39"
|
|
2256
2261
|
},
|
|
2257
2262
|
{
|
|
2258
2263
|
"path": "docs/api-reference.md",
|
|
2259
2264
|
"mode": "0000644",
|
|
2260
|
-
"sha256": "
|
|
2265
|
+
"sha256": "60243a4cf43ee8c37a06dda28bac07a9797c96eaef126cbcbda4d89c9ec9b986"
|
|
2261
2266
|
},
|
|
2262
2267
|
{
|
|
2263
2268
|
"path": "docs/api/openapi.json",
|
|
2264
2269
|
"mode": "0000644",
|
|
2265
|
-
"sha256": "
|
|
2270
|
+
"sha256": "847818c90b206c7223114b868e32b1eb50e0cc9955ae4dd6b67c5614d1ab51d8"
|
|
2266
2271
|
},
|
|
2267
2272
|
{
|
|
2268
2273
|
"path": "docs/architecture.md",
|
|
@@ -2287,12 +2292,12 @@
|
|
|
2287
2292
|
{
|
|
2288
2293
|
"path": "docs/copy-inventory.md",
|
|
2289
2294
|
"mode": "0000644",
|
|
2290
|
-
"sha256": "
|
|
2295
|
+
"sha256": "ed9adfda17002adac03024b90ed8ee6a79a9c5a814ce88970bf6c1dfd6fa8e9f"
|
|
2291
2296
|
},
|
|
2292
2297
|
{
|
|
2293
2298
|
"path": "docs/copy-registry.json",
|
|
2294
2299
|
"mode": "0000644",
|
|
2295
|
-
"sha256": "
|
|
2300
|
+
"sha256": "68b59e9280240b604210d20279e64f47af0bddbac8e2c3344343b4ecf8e21e52"
|
|
2296
2301
|
},
|
|
2297
2302
|
{
|
|
2298
2303
|
"path": "docs/design/apex-pass-2-direction.md",
|
|
@@ -2797,7 +2802,7 @@
|
|
|
2797
2802
|
{
|
|
2798
2803
|
"path": "docs/module-api-changelog.md",
|
|
2799
2804
|
"mode": "0000644",
|
|
2800
|
-
"sha256": "
|
|
2805
|
+
"sha256": "7fab447c04933dbbe8ee8f154f854f15eb834163ae656799e5ff3c8f3756fdfc"
|
|
2801
2806
|
},
|
|
2802
2807
|
{
|
|
2803
2808
|
"path": "docs/modules-contract.md",
|
|
@@ -2887,7 +2892,7 @@
|
|
|
2887
2892
|
{
|
|
2888
2893
|
"path": "docs/page-readings.json",
|
|
2889
2894
|
"mode": "0000644",
|
|
2890
|
-
"sha256": "
|
|
2895
|
+
"sha256": "c9722a4284b34b8773b2fed801a256277bb314833da397ae89af674ebe46acee"
|
|
2891
2896
|
},
|
|
2892
2897
|
{
|
|
2893
2898
|
"path": "docs/project-context.template.md",
|
|
@@ -3979,6 +3984,11 @@
|
|
|
3979
3984
|
"mode": "0000644",
|
|
3980
3985
|
"sha256": "ea887c7bcd2863e69121bfcfa36cc62fedc77c5bd5a052e5868e2f7c99cbc103"
|
|
3981
3986
|
},
|
|
3987
|
+
{
|
|
3988
|
+
"path": "migrations/core_266_access_requests_invited_login_idx.sql",
|
|
3989
|
+
"mode": "0000644",
|
|
3990
|
+
"sha256": "e7dcf016492ab9d011bd0021ac866edd502bf68f2fe06a04365ecb2b49ccbfaa"
|
|
3991
|
+
},
|
|
3982
3992
|
{
|
|
3983
3993
|
"path": "modules/agents/CLAUDE.md",
|
|
3984
3994
|
"mode": "0000644",
|
|
@@ -5752,7 +5762,7 @@
|
|
|
5752
5762
|
{
|
|
5753
5763
|
"path": "modules/hall-ui/public/watch.js",
|
|
5754
5764
|
"mode": "0000644",
|
|
5755
|
-
"sha256": "
|
|
5765
|
+
"sha256": "6746170acdd097b14bdccce236ac236b4962bdd1679de2c5624ca1a10cf784d0"
|
|
5756
5766
|
},
|
|
5757
5767
|
{
|
|
5758
5768
|
"path": "modules/hall-ui/public/watch.states.json",
|
|
@@ -6842,7 +6852,7 @@
|
|
|
6842
6852
|
{
|
|
6843
6853
|
"path": "modules/onboarding/routes/access-requests.js",
|
|
6844
6854
|
"mode": "0000644",
|
|
6845
|
-
"sha256": "
|
|
6855
|
+
"sha256": "7e8a63d388816b1a65ec6b24fdc20390d42efa7afa5c33cdf164d0cfca1ad5d4"
|
|
6846
6856
|
},
|
|
6847
6857
|
{
|
|
6848
6858
|
"path": "modules/onboarding/routes/onboarding.js",
|
|
@@ -7092,7 +7102,7 @@
|
|
|
7092
7102
|
{
|
|
7093
7103
|
"path": "modules/platform-identity/platform-identity.js",
|
|
7094
7104
|
"mode": "0000644",
|
|
7095
|
-
"sha256": "
|
|
7105
|
+
"sha256": "8f293f2d70e61f90a381153248a748b12452d3bb984e5903f32610fad78d669f"
|
|
7096
7106
|
},
|
|
7097
7107
|
{
|
|
7098
7108
|
"path": "modules/platform-identity/pollers/code-sweep.js",
|
|
@@ -7222,7 +7232,7 @@
|
|
|
7222
7232
|
{
|
|
7223
7233
|
"path": "modules/platform-identity/tests/platform-identity.mjs",
|
|
7224
7234
|
"mode": "0000644",
|
|
7225
|
-
"sha256": "
|
|
7235
|
+
"sha256": "6dc7617a7d7615fc5ee51817ae77bba8089324c124a6cb1d0fe3ca9400454ee1"
|
|
7226
7236
|
},
|
|
7227
7237
|
{
|
|
7228
7238
|
"path": "modules/platform-identity/ui/.gitkeep",
|
|
@@ -7272,7 +7282,7 @@
|
|
|
7272
7282
|
{
|
|
7273
7283
|
"path": "modules/provisioning/core-upgrade.js",
|
|
7274
7284
|
"mode": "0000644",
|
|
7275
|
-
"sha256": "
|
|
7285
|
+
"sha256": "8adf8842f6058224aeac88f54202cf4e7ed26f0021c44cf9bf1f94098b12ce07"
|
|
7276
7286
|
},
|
|
7277
7287
|
{
|
|
7278
7288
|
"path": "modules/provisioning/cost-ledger.js",
|
|
@@ -7444,6 +7454,11 @@
|
|
|
7444
7454
|
"mode": "0000644",
|
|
7445
7455
|
"sha256": "9726682ff47916ca8ef999fe70ed5995c3bad7680b0821b87e4cab8a74d9f867"
|
|
7446
7456
|
},
|
|
7457
|
+
{
|
|
7458
|
+
"path": "modules/provisioning/migrations/provisioning_029_update_channel.sql",
|
|
7459
|
+
"mode": "0000644",
|
|
7460
|
+
"sha256": "b667ec5165e611bd6f0d86b09465c5d9e632de853becce139bac49f5a88e5c1e"
|
|
7461
|
+
},
|
|
7447
7462
|
{
|
|
7448
7463
|
"path": "modules/provisioning/module.json",
|
|
7449
7464
|
"mode": "0000644",
|
|
@@ -7537,7 +7552,7 @@
|
|
|
7537
7552
|
{
|
|
7538
7553
|
"path": "modules/provisioning/routes/core-upgrade.js",
|
|
7539
7554
|
"mode": "0000644",
|
|
7540
|
-
"sha256": "
|
|
7555
|
+
"sha256": "980f25a157dfde5bda6ed903c727fab944b922abdc34be05dc0ccdb5fb3650cc"
|
|
7541
7556
|
},
|
|
7542
7557
|
{
|
|
7543
7558
|
"path": "modules/provisioning/routes/disconnect.js",
|
|
@@ -8962,12 +8977,12 @@
|
|
|
8962
8977
|
{
|
|
8963
8978
|
"path": "package-lock.json",
|
|
8964
8979
|
"mode": "0000644",
|
|
8965
|
-
"sha256": "
|
|
8980
|
+
"sha256": "eb1cd0418a763ae11ad580a788df78980c6f19e4953d543e2111f4543d53a8ac"
|
|
8966
8981
|
},
|
|
8967
8982
|
{
|
|
8968
8983
|
"path": "package.json",
|
|
8969
8984
|
"mode": "0000644",
|
|
8970
|
-
"sha256": "
|
|
8985
|
+
"sha256": "3aefd305535d6f2fc5f8a09ca30b7a6ae323e7f120008618e01d1c772198a363"
|
|
8971
8986
|
},
|
|
8972
8987
|
{
|
|
8973
8988
|
"path": "public-docs/index.html",
|
|
@@ -8987,7 +9002,7 @@
|
|
|
8987
9002
|
{
|
|
8988
9003
|
"path": "release-notes.json",
|
|
8989
9004
|
"mode": "0000644",
|
|
8990
|
-
"sha256": "
|
|
9005
|
+
"sha256": "84ae8d8349b19fc436952c1455536f608f5804eca0a4b934d0b66555f72baef0"
|
|
8991
9006
|
},
|
|
8992
9007
|
{
|
|
8993
9008
|
"path": "scripts/bongos-mcp.js",
|
|
@@ -9557,7 +9572,7 @@
|
|
|
9557
9572
|
{
|
|
9558
9573
|
"path": "scripts/gds/fitness.js",
|
|
9559
9574
|
"mode": "0000644",
|
|
9560
|
-
"sha256": "
|
|
9575
|
+
"sha256": "11c013412eca59780987da1db3af9db4a16202b743e55675cb28812c4091f883"
|
|
9561
9576
|
},
|
|
9562
9577
|
{
|
|
9563
9578
|
"path": "scripts/gds/gate-review.js",
|
|
@@ -9782,7 +9797,7 @@
|
|
|
9782
9797
|
{
|
|
9783
9798
|
"path": "scripts/gds/login.js",
|
|
9784
9799
|
"mode": "0000644",
|
|
9785
|
-
"sha256": "
|
|
9800
|
+
"sha256": "75f3a83618340171dba4be280cf41515c341c0468f4cf5dd32e3db8adeb95c9d"
|
|
9786
9801
|
},
|
|
9787
9802
|
{
|
|
9788
9803
|
"path": "scripts/gds/main-audit.js",
|
|
@@ -9947,7 +9962,7 @@
|
|
|
9947
9962
|
{
|
|
9948
9963
|
"path": "scripts/gds/provision-core-upgrade.js",
|
|
9949
9964
|
"mode": "0000644",
|
|
9950
|
-
"sha256": "
|
|
9965
|
+
"sha256": "3adfb1d93ac59f1a057bcfc55fbeb1ac1cfcb6b8148c4ce6551de9bf743c878b"
|
|
9951
9966
|
},
|
|
9952
9967
|
{
|
|
9953
9968
|
"path": "scripts/gds/provision-disconnect.js",
|
|
@@ -10147,7 +10162,7 @@
|
|
|
10147
10162
|
{
|
|
10148
10163
|
"path": "scripts/gds/run-unit-tests.js",
|
|
10149
10164
|
"mode": "0000644",
|
|
10150
|
-
"sha256": "
|
|
10165
|
+
"sha256": "1060c8a67619c8e6c0d8168d6a26644b799ed8053ab4995fd9386b55af3660c9"
|
|
10151
10166
|
},
|
|
10152
10167
|
{
|
|
10153
10168
|
"path": "scripts/gds/runner-drift.js",
|
|
@@ -10817,7 +10832,7 @@
|
|
|
10817
10832
|
{
|
|
10818
10833
|
"path": "src/bongos/db-kernel.js",
|
|
10819
10834
|
"mode": "0000644",
|
|
10820
|
-
"sha256": "
|
|
10835
|
+
"sha256": "85032e00d05717fa4cde2d9db45c567d3f11772a549a458b2ae67a18274a0f91"
|
|
10821
10836
|
},
|
|
10822
10837
|
{
|
|
10823
10838
|
"path": "src/bongos/db.js",
|
|
@@ -10839,6 +10854,11 @@
|
|
|
10839
10854
|
"mode": "0000644",
|
|
10840
10855
|
"sha256": "5f2e9a548f7c0cd1c8b8245be4ba50e9066edb18d07ee7ded7d72f363040ba00"
|
|
10841
10856
|
},
|
|
10857
|
+
{
|
|
10858
|
+
"path": "src/bongos/invite-expiry.js",
|
|
10859
|
+
"mode": "0000644",
|
|
10860
|
+
"sha256": "64ae68b30656075c76f420a29e0f25b6499719d745c901580d5859f8c860ca78"
|
|
10861
|
+
},
|
|
10842
10862
|
{
|
|
10843
10863
|
"path": "src/bongos/live-channel.js",
|
|
10844
10864
|
"mode": "0000644",
|
|
@@ -11102,7 +11122,7 @@
|
|
|
11102
11122
|
{
|
|
11103
11123
|
"path": "src/module-api.js",
|
|
11104
11124
|
"mode": "0000644",
|
|
11105
|
-
"sha256": "
|
|
11125
|
+
"sha256": "e8f28de6e2a1dbb5dead24503e6da1e013dd36a4a27c0dea9382480fdfdbb7e6"
|
|
11106
11126
|
},
|
|
11107
11127
|
{
|
|
11108
11128
|
"path": "src/module-loader/catalog.js",
|
|
@@ -11177,7 +11197,7 @@
|
|
|
11177
11197
|
{
|
|
11178
11198
|
"path": "tests/access_requests_invite.mjs",
|
|
11179
11199
|
"mode": "0000644",
|
|
11180
|
-
"sha256": "
|
|
11200
|
+
"sha256": "22f633a9216457e37fa5da47b260ce6c7aa0d5b2c500c8170a476807c426c76b"
|
|
11181
11201
|
},
|
|
11182
11202
|
{
|
|
11183
11203
|
"path": "tests/accessibility_replay.mjs",
|
|
@@ -11397,7 +11417,7 @@
|
|
|
11397
11417
|
{
|
|
11398
11418
|
"path": "tests/application_lifecycle.mjs",
|
|
11399
11419
|
"mode": "0000644",
|
|
11400
|
-
"sha256": "
|
|
11420
|
+
"sha256": "f84e1b46315e57514f00545038eaa94a9617a83ebb8b5e4b55814fa3b063e155"
|
|
11401
11421
|
},
|
|
11402
11422
|
{
|
|
11403
11423
|
"path": "tests/architect.mjs",
|
|
@@ -11702,7 +11722,7 @@
|
|
|
11702
11722
|
{
|
|
11703
11723
|
"path": "tests/bongos_login.mjs",
|
|
11704
11724
|
"mode": "0000644",
|
|
11705
|
-
"sha256": "
|
|
11725
|
+
"sha256": "091ab59bc648f1ef11b309b09283ca2730635c6f3010adfcbf81053e1abb2055"
|
|
11706
11726
|
},
|
|
11707
11727
|
{
|
|
11708
11728
|
"path": "tests/branding.mjs",
|
|
@@ -12047,7 +12067,7 @@
|
|
|
12047
12067
|
{
|
|
12048
12068
|
"path": "tests/core_upgrade_door.mjs",
|
|
12049
12069
|
"mode": "0000644",
|
|
12050
|
-
"sha256": "
|
|
12070
|
+
"sha256": "0bbd0f6bcecfb8c88e69256470610f40eb64ec555a67502b3172d69a220fc12b"
|
|
12051
12071
|
},
|
|
12052
12072
|
{
|
|
12053
12073
|
"path": "tests/core_upgrade_owner_door.mjs",
|
|
@@ -12057,7 +12077,7 @@
|
|
|
12057
12077
|
{
|
|
12058
12078
|
"path": "tests/core_upgrade_runner.mjs",
|
|
12059
12079
|
"mode": "0000644",
|
|
12060
|
-
"sha256": "
|
|
12080
|
+
"sha256": "f55d142db2f3207eb1b1dc7e06c978cb22a282ff0d16792808d212948993640a"
|
|
12061
12081
|
},
|
|
12062
12082
|
{
|
|
12063
12083
|
"path": "tests/cosmos_token_contrast.mjs",
|
|
@@ -13432,7 +13452,7 @@
|
|
|
13432
13452
|
{
|
|
13433
13453
|
"path": "tests/hub_invite_notices.mjs",
|
|
13434
13454
|
"mode": "0000644",
|
|
13435
|
-
"sha256": "
|
|
13455
|
+
"sha256": "61a4467e59582bd8d640ba82c139089933a2fadf5c3e2bd570bdfb7b11ae26c7"
|
|
13436
13456
|
},
|
|
13437
13457
|
{
|
|
13438
13458
|
"path": "tests/hub_map_orb_states.mjs",
|
|
@@ -13724,6 +13744,16 @@
|
|
|
13724
13744
|
"mode": "0000644",
|
|
13725
13745
|
"sha256": "1e01a44dc1ef5d454643e81737f77b5061e577a9275a22f5b98bd05ac541f1d7"
|
|
13726
13746
|
},
|
|
13747
|
+
{
|
|
13748
|
+
"path": "tests/invite_expiry.mjs",
|
|
13749
|
+
"mode": "0000644",
|
|
13750
|
+
"sha256": "f4e7d57306b988aa5dadb9c2fe3c55f519beb2725980a7d360caa09416b03e8c"
|
|
13751
|
+
},
|
|
13752
|
+
{
|
|
13753
|
+
"path": "tests/invite_expiry_db.mjs",
|
|
13754
|
+
"mode": "0000644",
|
|
13755
|
+
"sha256": "9963890ca3f5ee6ab008079c1623e0dec11bf3ce696ff5f18621ad9e52f76a4d"
|
|
13756
|
+
},
|
|
13727
13757
|
{
|
|
13728
13758
|
"path": "tests/join_application_note.mjs",
|
|
13729
13759
|
"mode": "0000644",
|
|
@@ -14042,7 +14072,7 @@
|
|
|
14042
14072
|
{
|
|
14043
14073
|
"path": "tests/module_api.mjs",
|
|
14044
14074
|
"mode": "0000644",
|
|
14045
|
-
"sha256": "
|
|
14075
|
+
"sha256": "35a7e4c2e2afe2cd61e51318e7e3300e7629acd24683b515287aa9dcbe8501ae"
|
|
14046
14076
|
},
|
|
14047
14077
|
{
|
|
14048
14078
|
"path": "tests/module_api_lazy.mjs",
|
|
@@ -14512,7 +14542,7 @@
|
|
|
14512
14542
|
{
|
|
14513
14543
|
"path": "tests/project_admin_console_model.mjs",
|
|
14514
14544
|
"mode": "0000644",
|
|
14515
|
-
"sha256": "
|
|
14545
|
+
"sha256": "af3664d6b4ce861f126b7f9eca87abf423f25bb5126df36a93b80312c70a218c"
|
|
14516
14546
|
},
|
|
14517
14547
|
{
|
|
14518
14548
|
"path": "tests/project_catalog_backfill.mjs",
|
|
@@ -5,7 +5,7 @@ A **generated**, zero-dependency typed client for the Bongos API — produced fr
|
|
|
5
5
|
by hand; it regenerates when the spec changes, so it can never drift from the routes.
|
|
6
6
|
|
|
7
7
|
- API version: **v1** (served at `/api/bongos/v1`)
|
|
8
|
-
-
|
|
8
|
+
- 466 operations across 70 resource groups
|
|
9
9
|
|
|
10
10
|
## Use it from your project
|
|
11
11
|
|
|
@@ -843,6 +843,8 @@ function createClient(opts = {}) {
|
|
|
843
843
|
patchProvisioningInstancesIdSettings: (args) => request("PATCH", "/provisioning/instances/{id}/settings", { hasBody: true }, args),
|
|
844
844
|
// POST /provisioning/instances/{id}/teardown — rank: any-builder — POST /provisioning/instances/:id/teardown
|
|
845
845
|
postProvisioningInstancesIdTeardown: (args) => request("POST", "/provisioning/instances/{id}/teardown", { hasBody: true }, args),
|
|
846
|
+
// POST /provisioning/instances/{id}/update-channel — rank: archon — POST /provisioning/instances/:id/update-channel
|
|
847
|
+
postProvisioningInstancesIdUpdateChannel: (args) => request("POST", "/provisioning/instances/{id}/update-channel", { hasBody: true }, args),
|
|
846
848
|
// GET /provisioning/onboard-plan — rank: public — GET /provisioning/onboard-plan
|
|
847
849
|
getProvisioningOnboardPlan: (args) => request("GET", "/provisioning/onboard-plan", { hasBody: false }, args),
|
|
848
850
|
// GET /provisioning/recommendations — rank: public — GET /provisioning/recommendations
|
|
@@ -842,6 +842,8 @@ function createClient(opts = {}) {
|
|
|
842
842
|
patchProvisioningInstancesIdSettings: (args) => request("PATCH", "/provisioning/instances/{id}/settings", { hasBody: true }, args),
|
|
843
843
|
// POST /provisioning/instances/{id}/teardown — rank: any-builder — POST /provisioning/instances/:id/teardown
|
|
844
844
|
postProvisioningInstancesIdTeardown: (args) => request("POST", "/provisioning/instances/{id}/teardown", { hasBody: true }, args),
|
|
845
|
+
// POST /provisioning/instances/{id}/update-channel — rank: archon — POST /provisioning/instances/:id/update-channel
|
|
846
|
+
postProvisioningInstancesIdUpdateChannel: (args) => request("POST", "/provisioning/instances/{id}/update-channel", { hasBody: true }, args),
|
|
845
847
|
// GET /provisioning/onboard-plan — rank: public — GET /provisioning/onboard-plan
|
|
846
848
|
getProvisioningOnboardPlan: (args) => request("GET", "/provisioning/onboard-plan", { hasBody: false }, args),
|
|
847
849
|
// GET /provisioning/recommendations — rank: public — GET /provisioning/recommendations
|
|
@@ -1274,6 +1274,8 @@ export interface BongosClient {
|
|
|
1274
1274
|
patchProvisioningInstancesIdSettings(args?: RequestArgs): Promise<PatchProvisioningInstancesIdSettingsResponse>;
|
|
1275
1275
|
/** POST /provisioning/instances/{id}/teardown — rank: any-builder */
|
|
1276
1276
|
postProvisioningInstancesIdTeardown(args?: RequestArgs): Promise<PostProvisioningInstancesIdTeardownResponse>;
|
|
1277
|
+
/** POST /provisioning/instances/{id}/update-channel — rank: archon */
|
|
1278
|
+
postProvisioningInstancesIdUpdateChannel(args?: RequestArgs): Promise<ApiResponse>;
|
|
1277
1279
|
/** GET /provisioning/onboard-plan — rank: public */
|
|
1278
1280
|
getProvisioningOnboardPlan(args?: RequestArgs): Promise<GetProvisioningOnboardPlanResponse>;
|
|
1279
1281
|
/** GET /provisioning/recommendations — rank: public */
|
|
@@ -839,6 +839,8 @@ export function createClient(opts = {}) {
|
|
|
839
839
|
patchProvisioningInstancesIdSettings: (args) => request("PATCH", "/provisioning/instances/{id}/settings", { hasBody: true }, args),
|
|
840
840
|
// POST /provisioning/instances/{id}/teardown — rank: any-builder — POST /provisioning/instances/:id/teardown
|
|
841
841
|
postProvisioningInstancesIdTeardown: (args) => request("POST", "/provisioning/instances/{id}/teardown", { hasBody: true }, args),
|
|
842
|
+
// POST /provisioning/instances/{id}/update-channel — rank: archon — POST /provisioning/instances/:id/update-channel
|
|
843
|
+
postProvisioningInstancesIdUpdateChannel: (args) => request("POST", "/provisioning/instances/{id}/update-channel", { hasBody: true }, args),
|
|
842
844
|
// GET /provisioning/onboard-plan — rank: public — GET /provisioning/onboard-plan
|
|
843
845
|
getProvisioningOnboardPlan: (args) => request("GET", "/provisioning/onboard-plan", { hasBody: false }, args),
|
|
844
846
|
// GET /provisioning/recommendations — rank: public — GET /provisioning/recommendations
|
|
@@ -55,7 +55,7 @@ There is no new table. The sign-in gate (`hasInvitedAccessRequest` → `firstTim
|
|
|
55
55
|
2. **`created_by` → `builders(id)`, set on invite rows only.** This is the inviter. It needs its own column because a rescind overwrites `resolved_by_builder_id` (ADR 0201 D4.2 records whoever acted last). Without it, a rescinded invite forgets who sent it.
|
|
56
56
|
3. **`note` needs no new column.** The existing column holds the inviter's note on an invite row, and `kind` says whose words they are.
|
|
57
57
|
4. **The backfill is exact.** The current invite route sets `resolved_at = now()` in the same statement whose default fills `created_at`, so every row it wrote has `created_at = resolved_at`. No approved application can match that, because an application is always resolved after it was filed. So the migration sets `kind='invite'` and `created_by = resolved_by_builder_id` on `status='invited'` rows where `created_at = resolved_at`. The one case it cannot catch is a direct invite that was later rescinded, because the rescind changes `resolved_at`. That row stays `'application'`, which makes it look like a declined application. It admits nobody either way. The only effect comes after R3: a recruiter who holds `project.recruit` but not `access_request.review` and re-invites that login gets the D3.4 refusal, so a reviewer has to send the invite. That leaves the door stricter, never looser, and applies only to invites rescinded before R2 ships.
|
|
58
|
-
5. **`kind` and `created_by` never enter an admission read.** This is the same rule `core_230` set for the vouch column. An invite and an approved application admit through the identical `status = 'invited'` read. `tests/project_admin_console_model.mjs` checks this.
|
|
58
|
+
5. **`kind` and `created_by` never enter an admission read.** This is the same rule `core_230` set for the vouch column. An invite and an approved application admit through the identical `status = 'invited'` read. `tests/project_admin_console_model.mjs` checks this. **Amended by [ADR 0356](0356-a-recruit-invite-expires-30-days-after-it-is-sent-read-time.md) (task 1002969):** `kind` now enters admission in one place, the invite expiry, which can close an invite's door after 30 days and never opens one. `created_by` still never enters.
|
|
59
59
|
6. **Expiry is not part of this.** The 30-day read-time expiry (ADR 0201 D4.3) covers every invited row, whatever its `kind`. Task 1002969 owns it.
|
|
60
60
|
|
|
61
61
|
### D3 — One new grantable atom, `project.recruit` (floor archon), says which rank may recruit; the verdict stays with `access_request.review`
|
|
@@ -58,7 +58,7 @@ The two notice routes are **new**. An older hub answers 404, the sender swallows
|
|
|
58
58
|
- **Rows written before this change are untouched.** Pending rows the old hub invite wrote still render as **Open project →**, and on a door other than `open` they still lead to the project's gate. The invitee can decline them, and the project can clear one by inviting and then rescinding. Deleting them at deploy would need a data migration, and it would also delete notices that do work (on `open` doors). That is left to the owner (see the task's handoff), not done silently here. **Amended (task 1004408):** the owner chose to delete them. Migration `<redacted>` deletes every `pending` row older than the hub's first upgrade to core 1.20.22 (the first release carrying this ADR), read from the `core_upgrades` ledger, or every `pending` row if there is no such upgrade. Old rows on `open` doors go too; those invitees can still sign in to the project, and the inviter can re-invite from the project's hall. Proof: `tests/pending_invite_purge_db.mjs`.
|
|
59
59
|
- **The hub's invite now reaches people with no platform account.** The project's own invite takes any GitHub login, so the old `account_not_found` refusal is gone. Such an invitee sees no hub notice, because there is no account to show it to, but they are admitted when they sign in.
|
|
60
60
|
- **Three things still bypass the notice**, all by scope: the reviewer queue's approve (`PATCH` pending → invited), the Discord approval reaction, and R3's future recruiter rescind route. The first two are approvals of an application the applicant already knows about. R3 (task 1002815) must call the same port when it adds its rescind.
|
|
61
|
-
- **The 30-day invite expiry** (task 1002969) is read-time on the instance. An expired invite's hub notice stays until the invitee declines it or the project re-invites and rescinds. Task 1002969 owns closing that.
|
|
61
|
+
- **The 30-day invite expiry** (task 1002969) is read-time on the instance. An expired invite's hub notice stays until the invitee declines it or the project re-invites and rescinds. Task 1002969 owns closing that. **Closed by [ADR 0356](0356-a-recruit-invite-expires-30-days-after-it-is-sent-read-time.md):** the hub stops listing a notice 30 days after it was sent, and a re-invite restamps it.
|
|
62
62
|
|
|
63
63
|
## Alternatives considered
|
|
64
64
|
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# ADR 0356 — A recruit invite expires 30 days after it is sent, decided at read time
|
|
2
|
+
|
|
3
|
+
- **Status:** accepted
|
|
4
|
+
- **Date:** 2026-09-30
|
|
5
|
+
- **Task:** [task 1002969](https://cloudbongos.com/builders#/task/1002969) (goal 1000110)
|
|
6
|
+
- **Builds on:** privacy spec D4 (`docs/specs/<redacted>.md`; the owner signed the 30 days), [ADR 0335](0335-an-invite-is-a-pre-approved-row-on-the-projects-own-instance.md) D2 (an invite is a `kind='invite'` row on the project's own instance), [ADR 0353](0353-a-hub-invite-is-a-notice-of-the-projects-own-invite.md) (the hub's `pending` row is a notice of that invite)
|
|
7
|
+
- **Amends:** ADR 0335 D2.5 ("no admission path reads `kind`")
|
|
8
|
+
- **Decided with:** the owner split the original task on 2026-09-30. `seen_at` is [task 1004443](https://cloudbongos.com/builders#/task/1004443); the decline relay is [task 1004444](https://cloudbongos.com/builders#/task/1004444).
|
|
9
|
+
|
|
10
|
+
## Context
|
|
11
|
+
|
|
12
|
+
An invite writes an `invited` row, and the sign-in gate admits any login holding one. Nothing ever closed it, so an invite sent months ago still let its login walk in. Spec D4 says a recruit invite's door closes after 30 days, enforced when it is read: no sweeper and no cron. ADR 0353 left the hub side of the same question to this task, because an expired invite's hub notice still said "Open project →".
|
|
13
|
+
|
|
14
|
+
## Decision
|
|
15
|
+
|
|
16
|
+
**D1 — One definition, computed at read time.** `src/bongos/invite-expiry.js` holds `INVITE_EXPIRY_DAYS` (30) and the SQL for "this row is an invite past its window", `kind = 'invite' AND created_at <= now() - interval '30 days'`. The sign-in gate (`hasInvitedAccessRequest`), the waiting-page probe (`accessStateByLogin`), the onboarding routes and the hub all read it: core directly, and modules through the doorway's `inviteExpiry`. Nothing is stored, so the day a door closes cannot drift between readers, and nothing has to run for it to close.
|
|
17
|
+
|
|
18
|
+
**D2 — Only invites expire.** An approved application (`kind = 'application'`) stays open: its applicant asked, and D4 is about invites. Goal invites get no expiry either.
|
|
19
|
+
|
|
20
|
+
**D3 — The gate now reads `kind`, and only to be stricter (amends ADR 0335 D2.5).** D2.5 kept `kind` out of admission because it was descriptive. It is now read in one place, inside the expiry unit, and that unit can only close a door. A row that is anything but an invite behaves exactly as before, so a mis-kinded row fails toward the old gate and never past it. Only server code writes `kind`: the public POST cannot set it. `created_by` is still never read. `tests/application_lifecycle.mjs` enforces both: its admission statements may mention `kind` only inside the expiry unit.
|
|
21
|
+
|
|
22
|
+
**D4 — What an expired invite looks like.**
|
|
23
|
+
- The gate refuses it. The public "already approved?" check and the standing-invite probe no longer count it, so the invitee may apply and the recruiter can re-invite.
|
|
24
|
+
- A re-invite writes a fresh row, which opens a fresh door. The expired row stays as history.
|
|
25
|
+
- The queue marks it `expired` with `expires_at`. The outstanding-invite list keeps it so the sender knows to invite again, and drops it once a newer invite for that login is live. The hall's queue shows "Invite expired" and offers no rescind.
|
|
26
|
+
- The public status probe answers `expired` (`admitted: false`), and `bongos login` stops waiting on it. An older CLI treats an unknown status as "wait" and times out, which is no worse than before.
|
|
27
|
+
- A rescind that leaves only expired rows clears the hub notice.
|
|
28
|
+
|
|
29
|
+
**D5 — The hub's notice follows the door.** `listPendingInvitesForAccount` hides a `pending` notice older than the same 30 days (its `joined_at` is when the project sent the notice). `inviteToProject` restamps `joined_at` only on a `pending` row that is already past the window, so a re-invite shows again. A re-send while the invite is live changes nothing, and a real membership is never touched.
|
|
30
|
+
|
|
31
|
+
## Consequences
|
|
32
|
+
|
|
33
|
+
- **Invites already older than 30 days close at deploy.** That is the spec's rule applied to existing rows. Their senders re-invite.
|
|
34
|
+
- **Wire skew (ADR 0352).** A newer hub with an older instance hides a notice after 30 days while that instance's door stays open. Only the nudge is lost. An older hub with a newer instance keeps showing an expired notice, which is today's behaviour.
|
|
35
|
+
- **The hub's clock is the notice's, not the invite's.** A notice healed by a late re-send (the hub missed the first) can outlive its invite by up to the gap between them. A lost clear can hide a live notice early. In both cases the next re-invite fixes it.
|
|
36
|
+
- **The outstanding list's cost stays that of its own scan.** "Does this login have a live invite" is a window (`bool_or … OVER (PARTITION BY lower(github_login))`) over the rows the list already reads, not a correlated lookup per row: `access_requests` has no index on `lower(github_login)` outside pending rows, and invite rows are kept as history. The sender filter (`?mine=1`) sits outside the window. Migration `core_266` adds the index those reads lacked, partial on `status = 'invited'` over `lower(github_login)`, which serves the sign-in gate, the standing-invite probe and this list. The owner approved it on 2026-09-30 after a grader finding.
|
|
37
|
+
- **Declining still closes only the hub's notice.** The project's row stays open until it expires. Task 1004444 owns the relay.
|
|
38
|
+
|
|
39
|
+
## Alternatives considered
|
|
40
|
+
|
|
41
|
+
- **A sweeper that flips expired rows to `dismissed`.** Spec D4 rules it out. It would also mislabel an expiry as a decline in the history.
|
|
42
|
+
- **Expire every `invited` row, applications included.** That is wider than D4, and at deploy it would lock out every applicant approved more than 30 days ago.
|
|
43
|
+
- **Dismiss the expired row when re-inviting.** That keeps the list tidy, but the hall renders `dismissed` as "Declined", which would be false.
|
|
44
|
+
- **Carry the invite's `created_at` to the hub in a header, making its clock exact.** That is a new wire field on the notify route for an edge case a re-invite already heals.
|
|
45
|
+
|
|
46
|
+
Proof: `tests/invite_expiry.mjs` (the definition), `tests/application_lifecycle.mjs` (the gate, queues, probe, re-invite and notice clear, interpreted), `tests/invite_expiry_db.mjs` (the same statements on real Postgres, plus the hub's notice), `tests/hub_invite_notices.mjs` and `modules/platform-identity/tests/platform-identity.mjs` (the notice statement's shape), `tests/bongos_login.mjs` (the CLI stops on `expired`).
|
package/docs/adr/README.md
CHANGED
|
@@ -474,3 +474,4 @@ These 20 numbers are each shared by exactly two files. They are **accepted histo
|
|
|
474
474
|
| 0353 | [**A hub invite is a notice of the project's own invite, and signing in accepts it** ([task 1002818](https://cloudbongos.com/builders#/task/1002818), goal 1000110 — R6 of the admin console wave). The hub's own invite wrote a `pending` membership that no project reads, so an "accepted" invite met a locked door (new projects default to `apply`). **D1:** that row is now a NOTICE the PROJECT writes: its invite route calls `POST /sso/invites/notify` and a dismissal that leaves no invited row calls `/sso/invites/clear` (client credentials, pending rows only, always `{ ok: true }` so no account oracle); core's `notifyHubOfInvite` is fire-and-forget. **D2:** the hub-side accept route is deleted; signing in to the project accepts, and the hub's own sign-in witness turns the row into a membership. **D3 (owner):** `POST /projects/invite` writes nothing and answers `{ invited: false, invite_url }`, the project's hall invite link (`/builders/watch?invite=<login>`, which only pre-fills); the signed-assertion relay is deferred. **D4:** new routes, so an older hub 404s and only the notice is lost (ADR 0352).](0353-a-hub-invite-is-a-notice-of-the-projects-own-invite.md) | platform identity / federation |
|
|
475
475
|
| 0354 | [**A builder hosts one project for free, and more takes the fleet permission** ([task 1004412](https://cloudbongos.com/builders#/task/1004412), goal 1000106 — working area 1, the owner's ruling of 2026-09-30). The create wizard always asks for `cloud-host`, which task 1003370 had gated behind `provisioning.fleet.manage`, so every new (Xenos) user was refused at "Create my project" — against ADR 0345 decision 1. **D1:** a builder's first live `cloud-host` project needs no permission; a further one needs the fleet permission (a retry of your own slug is the same project; only `torn_down` frees the place; an unreadable count refuses). **D2:** one first-free request per builder at a time (409 `create_in_progress`), held as a Postgres advisory lock so it holds across processes. **D3:** the wizard states `permission_forbidden` and `box_full` in plain words. Nothing yet caps a hosted project's memory.](0354-a-builder-hosts-one-project-free-and-more-takes-the-fleet-permission.md) | provisioning / security / project creation |
|
|
476
476
|
| 0355 | [**A soft limit is a rule with a reason, and nobody enforces it** ([task 1004416](https://cloudbongos.com/builders#/task/1004416), goal 1000121 — BV2.PS02). The startup flow's seven planet-physics answers and what they rule out. **D1:** the answers are more provisioning `detail` keys under `team_shape`'s contract (no defaults, refused loudly, `null` un-answers), with two new kinds — a list (`many`) and a whole number (`count`); the country is a closed ISO list. **D2:** answers must agree only within one request, so a merge patch's edit order never matters. **D3:** one declarative soft-limit table (`soft-limits.js`) — data conditions, `hide`/`grey`/`note`, a reason on every rule — and every resolution says `enforced: false`. **D4:** screening is a seam (`screening.js`) with a deliberately small rule set; a stop is 422 `screened_out` before anything exists. **D5:** the edit route screens a new description too.](0355-a-soft-limit-is-a-rule-with-a-reason-and-nobody-enforces-it.md) | provisioning / project startup |
|
|
477
|
+
| 0356 | [**A recruit invite expires 30 days after it is sent, decided at read time** ([task 1002969](https://cloudbongos.com/builders#/task/1002969), goal 1000110 — privacy spec D4, owner-signed). **D1:** one definition, `src/bongos/invite-expiry.js` (`INVITE_EXPIRY_DAYS` + the SQL), read by the sign-in gate, the waiting-page probe, the onboarding routes and, through the doorway's `inviteExpiry`, the hub. Nothing is stored and nothing sweeps. **D2:** only `kind='invite'` rows expire; approved applications and goal invites do not. **D3:** amends ADR 0335 D2.5: the gate reads `kind` only inside the expiry unit, which can close a door and never open one. **D4:** an expired invite is refused, marked `expired` + `expires_at` in the queues, reported `expired` by the status probe (the CLI stops), and replaced by a re-invite's fresh row. **D5:** the hub hides a `pending` notice past 30 days and a re-invite restamps it. Split out: `seen_at` (task 1004443), the decline relay (task 1004444).](0356-a-recruit-invite-expires-30-days-after-it-is-sent-read-time.md) | platform identity / admission / invites |
|
package/docs/api/openapi.json
CHANGED
|
@@ -440,7 +440,7 @@
|
|
|
440
440
|
"access-requests"
|
|
441
441
|
],
|
|
442
442
|
"summary": "GET /access-requests/invites",
|
|
443
|
-
"description": "GET /access-requests/invites[?mine=1] — the outstanding invites: kind='invite', still 'invited' (not rescinded), and no builder row yet (not yet accepted by signing in), each naming its sender; ?mine=1 keeps only the caller's own (ADR 0335 D2; task 1002814). Rescind one with PATCH /access-requests/:id. rank: archon — it names logins that are not members yet.\n\n**Rank:** `archon` — Archon only (rank and identity management + the escalation keys — the trust boundary).\n\n**Permissions:** `access_request.review` (all required).",
|
|
443
|
+
"description": "GET /access-requests/invites[?mine=1] — the outstanding invites: kind='invite', still 'invited' (not rescinded), and no builder row yet (not yet accepted by signing in), each naming its sender; ?mine=1 keeps only the caller's own (ADR 0335 D2; task 1002814). Rescind one with PATCH /access-requests/:id. Each carries `expires_at`, and `expired` once its 30 days are up (task 1002969): listed so the sender knows to invite again, and dropped once a newer invite for the same login is live, since that one already replaced it. rank: archon — it names logins that are not members yet.\n\n**Rank:** `archon` — Archon only (rank and identity management + the escalation keys — the trust boundary).\n\n**Permissions:** `access_request.review` (all required).",
|
|
444
444
|
"x-rank": "archon",
|
|
445
445
|
"x-source": "modules/onboarding/routes/access-requests.js",
|
|
446
446
|
"x-permissions": [
|
|
@@ -481,7 +481,7 @@
|
|
|
481
481
|
"access-requests"
|
|
482
482
|
],
|
|
483
483
|
"summary": "GET /access-requests/status",
|
|
484
|
-
"description": "GET /access-requests/status?github_login=X — PUBLIC. The `bongos login` CLI polls this after filing a request: the device flow's not_approved is TERMINAL (the device_code is spent), so the CLI can't re-poll the flow — it polls this instead, then restarts sign-in once admitted. Exposes nothing the public POST above doesn't already reveal through its 409s (already_member / already_approved). status ∈ member | invited | pending | dismissed | none; admitted = member||invited. rank: public — a would-be builder is by definition outside the system. Declared BEFORE `GET /access-requests` so the literal `/status` path is matched as its own route (not swallowed as a query on the list route). RATE-LIMITED (task 1003339 / ADR 0209). Public + unthrottled, this was a login→membership oracle an attacker could script at line rate to learn who builds here. accountExistenceReadRateLimit is the doorway's SHARED 120/60s per-IP budget: core's GET /auth/web/admission-status (the boolean twin of this answer) mounts the very same instance, so the two cannot be alternated for double the rate. The limiter runs before the queries, so a refused probe costs no DB work. Whether the ANSWER should also collapse — so a caller who is not the subject cannot tell pending/dismissed/none apart — is the owner's call and is filed as a blocker, not decided here.\n\n**Rank:** `public` — No authentication — any caller.",
|
|
484
|
+
"description": "GET /access-requests/status?github_login=X — PUBLIC. The `bongos login` CLI polls this after filing a request: the device flow's not_approved is TERMINAL (the device_code is spent), so the CLI can't re-poll the flow — it polls this instead, then restarts sign-in once admitted. Exposes nothing the public POST above doesn't already reveal through its 409s (already_member / already_approved). status ∈ member | invited | expired | pending | dismissed | none; admitted = member||invited. `expired` is an invite past its 30 days (task 1002969): the door is shut, and the CLI stops waiting rather than polling a door that will not open. rank: public — a would-be builder is by definition outside the system. Declared BEFORE `GET /access-requests` so the literal `/status` path is matched as its own route (not swallowed as a query on the list route). RATE-LIMITED (task 1003339 / ADR 0209). Public + unthrottled, this was a login→membership oracle an attacker could script at line rate to learn who builds here. accountExistenceReadRateLimit is the doorway's SHARED 120/60s per-IP budget: core's GET /auth/web/admission-status (the boolean twin of this answer) mounts the very same instance, so the two cannot be alternated for double the rate. The limiter runs before the queries, so a refused probe costs no DB work. Whether the ANSWER should also collapse — so a caller who is not the subject cannot tell pending/dismissed/none apart — is the owner's call and is filed as a blocker, not decided here.\n\n**Rank:** `public` — No authentication — any caller.",
|
|
485
485
|
"x-rank": "public",
|
|
486
486
|
"x-source": "modules/onboarding/routes/access-requests.js",
|
|
487
487
|
"responses": {
|
|
@@ -15676,6 +15676,54 @@
|
|
|
15676
15676
|
]
|
|
15677
15677
|
}
|
|
15678
15678
|
},
|
|
15679
|
+
"/provisioning/instances/{id}/update-channel": {
|
|
15680
|
+
"post": {
|
|
15681
|
+
"operationId": "post_provisioning_instances_id_update_channel",
|
|
15682
|
+
"tags": [
|
|
15683
|
+
"provisioning"
|
|
15684
|
+
],
|
|
15685
|
+
"summary": "POST /provisioning/instances/:id/update-channel",
|
|
15686
|
+
"description": "POST /provisioning/instances/:id/update-channel — set the project's update rule (task 1004445). Body: { channel: \"pinned\" | \"patch\" | \"minor\" }. rank: `core.pin.move`, OR THE PROJECT'S OWN OWNER — the same two doors as the move, because the rule decides which moves the runner will perform: whoever may press Move may choose how far it reaches, and nobody else may. The platform's own row stays on the atom alone (OWNER_SHAPES excludes it), exactly as for the move.\n\n**Rank:** `archon` — Archon only (rank and identity management + the escalation keys — the trust boundary).\n\n**Permissions:** `core.pin.move` (all required).",
|
|
15687
|
+
"x-rank": "archon",
|
|
15688
|
+
"x-source": "modules/provisioning/routes/core-upgrade.js",
|
|
15689
|
+
"x-permissions": [
|
|
15690
|
+
"core.pin.move"
|
|
15691
|
+
],
|
|
15692
|
+
"parameters": [
|
|
15693
|
+
{
|
|
15694
|
+
"name": "id",
|
|
15695
|
+
"in": "path",
|
|
15696
|
+
"required": true,
|
|
15697
|
+
"schema": {
|
|
15698
|
+
"type": "string"
|
|
15699
|
+
},
|
|
15700
|
+
"description": "Path parameter `id`."
|
|
15701
|
+
}
|
|
15702
|
+
],
|
|
15703
|
+
"responses": {
|
|
15704
|
+
"200": {
|
|
15705
|
+
"description": "Success."
|
|
15706
|
+
},
|
|
15707
|
+
"400": {
|
|
15708
|
+
"$ref": "#/components/responses/BadRequest"
|
|
15709
|
+
},
|
|
15710
|
+
"401": {
|
|
15711
|
+
"$ref": "#/components/responses/Unauthorized"
|
|
15712
|
+
},
|
|
15713
|
+
"403": {
|
|
15714
|
+
"$ref": "#/components/responses/Forbidden"
|
|
15715
|
+
},
|
|
15716
|
+
"404": {
|
|
15717
|
+
"$ref": "#/components/responses/NotFound"
|
|
15718
|
+
}
|
|
15719
|
+
},
|
|
15720
|
+
"security": [
|
|
15721
|
+
{
|
|
15722
|
+
"builderSession": []
|
|
15723
|
+
}
|
|
15724
|
+
]
|
|
15725
|
+
}
|
|
15726
|
+
},
|
|
15679
15727
|
"/provisioning/onboard-plan": {
|
|
15680
15728
|
"get": {
|
|
15681
15729
|
"operationId": "get_provisioning_onboard_plan",
|
|
@@ -29763,7 +29811,7 @@
|
|
|
29763
29811
|
"description": "A required dependency/feature is not configured or is temporarily down."
|
|
29764
29812
|
}
|
|
29765
29813
|
},
|
|
29766
|
-
"x-endpoint-count":
|
|
29814
|
+
"x-endpoint-count": 466,
|
|
29767
29815
|
"x-schema-count": 498,
|
|
29768
29816
|
"x-undocumented-bodies": 12,
|
|
29769
29817
|
"x-response-schemas": 337,
|