@bongos/core 1.20.26 → 1.20.28

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.
Files changed (54) hide show
  1. package/.bongos-core.json +117 -47
  2. package/clients/bongos-client/README.md +1 -1
  3. package/clients/bongos-client/bongos-client.global.js +2 -0
  4. package/clients/bongos-client/index.cjs +2 -0
  5. package/clients/bongos-client/index.d.ts +5 -1
  6. package/clients/bongos-client/index.mjs +2 -0
  7. package/docs/adr/0335-an-invite-is-a-pre-approved-row-on-the-projects-own-instance.md +1 -1
  8. package/docs/adr/0353-a-hub-invite-is-a-notice-of-the-projects-own-invite.md +2 -2
  9. package/docs/adr/0355-a-soft-limit-is-a-rule-with-a-reason-and-nobody-enforces-it.md +30 -0
  10. package/docs/adr/0356-a-recruit-invite-expires-30-days-after-it-is-sent-read-time.md +46 -0
  11. package/docs/adr/README.md +2 -0
  12. package/docs/api/openapi.json +105 -5
  13. package/docs/api-reference.md +3 -2
  14. package/docs/copy-inventory.md +37 -36
  15. package/docs/copy-registry.json +52 -43
  16. package/docs/module-api-changelog.md +4 -0
  17. package/docs/page-readings.json +70 -68
  18. package/migrations/core_266_access_requests_invited_login_idx.sql +31 -0
  19. package/modules/government/board.js +64 -7
  20. package/modules/government/charter.js +232 -0
  21. package/modules/government/routes/government.js +62 -0
  22. package/modules/hall-ui/public/government.js +11 -0
  23. package/modules/hall-ui/public/watch.js +9 -3
  24. package/modules/onboarding/routes/access-requests.js +43 -20
  25. package/modules/platform-identity/migrations/platform_identity_028_purge_pre_notice_invites.sql +65 -0
  26. package/modules/platform-identity/platform-identity.js +12 -8
  27. package/modules/platform-identity/tests/platform-identity.mjs +4 -2
  28. package/modules/provisioning/planet-physics.js +154 -0
  29. package/modules/provisioning/provisioning.js +29 -9
  30. package/modules/provisioning/routes/body-validators.js +25 -7
  31. package/modules/provisioning/routes/provisioning.js +8 -3
  32. package/modules/provisioning/screening.js +62 -0
  33. package/modules/provisioning/soft-limits.js +146 -0
  34. package/package-lock.json +2 -2
  35. package/package.json +1 -1
  36. package/release-notes.json +24 -0
  37. package/scripts/gds/fitness.js +4 -0
  38. package/scripts/gds/login.js +6 -0
  39. package/scripts/gds/run-unit-tests.js +8 -0
  40. package/src/bongos/db-kernel.js +6 -3
  41. package/src/bongos/invite-expiry.js +47 -0
  42. package/src/bongos/route-rank-check.js +3 -0
  43. package/src/module-api.js +10 -1
  44. package/tests/access_requests_invite.mjs +2 -1
  45. package/tests/application_lifecycle.mjs +164 -5
  46. package/tests/bongos_login.mjs +2 -0
  47. package/tests/government_charter_forms.mjs +283 -0
  48. package/tests/hub_invite_notices.mjs +5 -2
  49. package/tests/invite_expiry.mjs +37 -0
  50. package/tests/invite_expiry_db.mjs +196 -0
  51. package/tests/module_api.mjs +1 -0
  52. package/tests/pending_invite_purge_db.mjs +129 -0
  53. package/tests/project_admin_console_model.mjs +12 -5
  54. package/tests/provisioning_planet_physics.mjs +377 -0
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.26",
6
- "core_contract": "1.20.26",
7
- "source_commit": "7bf58c3913461c4383f40d27a2c2abe4b357ee85",
5
+ "core_version": "1.20.28",
6
+ "core_contract": "1.20.28",
7
+ "source_commit": "64dc694277165d8cd1227e09df2fda3dd99dd396",
8
8
  "source_ref": "HEAD",
9
- "built_at": "2026-09-30T19:12:54.558Z",
9
+ "built_at": "2026-09-30T20:23:58.237Z",
10
10
  "redaction": {
11
11
  "model": "docs-redacted+functional-verbatim",
12
- "docs_redacted": 560,
12
+ "docs_redacted": 562,
13
13
  "agent_docs_stubbed": 25,
14
- "functional_verbatim": 2647,
14
+ "functional_verbatim": 2659,
15
15
  "rules": 3,
16
16
  "gate_literals": 3,
17
17
  "gate": "passed"
18
18
  },
19
- "file_count": 3233,
20
- "tree_sha256": "6cc2f111dd67610b01e2286ded5cfef7db118cdbb5afe9d134262e29262f7ade",
19
+ "file_count": 3247,
20
+ "tree_sha256": "06c076a09a9c706567f32a447e0d1600e2e07a868b9bdd4be62088a290714985",
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": "6142e330ccbf058cfe2d266b80d1dab1419cdd9194f39933da2f410d6e20abb1"
330
+ "sha256": "8dde50025e6ac0a8e9742455d62495b72c1803b87044455c48b13b95209f59a2"
331
331
  },
332
332
  {
333
333
  "path": "clients/bongos-client/bongos-client.global.js",
334
334
  "mode": "0000644",
335
- "sha256": "094ba492c058258352e891a1d418fbff5777d40176e21292a6c92c0ad4c55902"
335
+ "sha256": "77f3e9375343c45fd538d179928628a7422858ddea7540cc60cfbdfba95a8545"
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": "4b57358e758f2959d9564bd59dab8c8d4ecfddebba4ee972884dd19522eb0f6c"
345
+ "sha256": "2eea3743862e9ec173c63517b6f79073b25e71aa3cb2d0a2a19ecce95ef78ca0"
346
346
  },
347
347
  {
348
348
  "path": "clients/bongos-client/index.d.ts",
349
349
  "mode": "0000644",
350
- "sha256": "c8fab17a151038309beceb2ca3e07a4dfbaa8d79f82b2b314cb3f1440882c3b6"
350
+ "sha256": "065abbfa7d625aa5811ae9e6c27101ca5b9c824422a6a74bba22d92e3f5d53ae"
351
351
  },
352
352
  {
353
353
  "path": "clients/bongos-client/index.mjs",
354
354
  "mode": "0000644",
355
- "sha256": "007c35d80ca1e647157a3330d4791871119659228b4ad2fc8091d9f6b00b6e3b"
355
+ "sha256": "e2714285309adfdb0644e82319363fdcc6fc19ad9f5a2cf0e71e203da8c5e188"
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": "f22adac7e27f2e83ece9311e44fca35edb0bd571440f108d28a9088775d0b93c"
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,27 +2237,37 @@
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": "4445d9c306a22fb3b7e72467bedad262f4653c092bf4866f8a39410248da2724"
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",
2244
2244
  "mode": "0000644",
2245
2245
  "sha256": "962d868c0887244c53b53c58754f7232715a20df6feec694f30cbda707f9e17e"
2246
2246
  },
2247
+ {
2248
+ "path": "docs/adr/0355-a-soft-limit-is-a-rule-with-a-reason-and-nobody-enforces-it.md",
2249
+ "mode": "0000644",
2250
+ "sha256": "6ad8ab3bd8bcb4f55575232af651f108e3879a5965f5daaac42ab693d00a1f0a"
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
+ },
2247
2257
  {
2248
2258
  "path": "docs/adr/README.md",
2249
2259
  "mode": "0000644",
2250
- "sha256": "850168519d3ef7eaf6d9658b9e2b19a80402147e9f3e8fc5318c53b7647fa9b0"
2260
+ "sha256": "d21d0eb8389864b4f7394ba0f4b0d0d809182f0bef82d9fc6824edd00e174b39"
2251
2261
  },
2252
2262
  {
2253
2263
  "path": "docs/api-reference.md",
2254
2264
  "mode": "0000644",
2255
- "sha256": "0d81859e19436003332c5ee22b94c7e0a23636a61ac2a52118c15caae71fb31c"
2265
+ "sha256": "db03fd5370b7b592769a806607b9cd0880a56b53c64d8909ca24364feeff818e"
2256
2266
  },
2257
2267
  {
2258
2268
  "path": "docs/api/openapi.json",
2259
2269
  "mode": "0000644",
2260
- "sha256": "ce15358f33baf4ba95f59b2e2de9bfc4a5a4a0dddde5bfc91a0bfab09e4447f9"
2270
+ "sha256": "27b8f6be81f9703a96a68f917dbb01a65048cc02f13adf308b414e96fb022668"
2261
2271
  },
2262
2272
  {
2263
2273
  "path": "docs/architecture.md",
@@ -2282,12 +2292,12 @@
2282
2292
  {
2283
2293
  "path": "docs/copy-inventory.md",
2284
2294
  "mode": "0000644",
2285
- "sha256": "cc3d3c2334fabc860be82ea509588681ca03cdd34da374011e2b0d5a646b8c9a"
2295
+ "sha256": "ed9adfda17002adac03024b90ed8ee6a79a9c5a814ce88970bf6c1dfd6fa8e9f"
2286
2296
  },
2287
2297
  {
2288
2298
  "path": "docs/copy-registry.json",
2289
2299
  "mode": "0000644",
2290
- "sha256": "efedc6e640a54a117e108ae85654fec0385580a108918c62a8ec96fc3b927daa"
2300
+ "sha256": "68b59e9280240b604210d20279e64f47af0bddbac8e2c3344343b4ecf8e21e52"
2291
2301
  },
2292
2302
  {
2293
2303
  "path": "docs/design/apex-pass-2-direction.md",
@@ -2792,7 +2802,7 @@
2792
2802
  {
2793
2803
  "path": "docs/module-api-changelog.md",
2794
2804
  "mode": "0000644",
2795
- "sha256": "7ceae0d7b1f9b1305c7dbec25e411f80c7700a128bbcf140ae65da98d73323c9"
2805
+ "sha256": "8de783d8efc2109b60de3758da0dfd4fecaf4d4a65dc364dacd1c17e8dac4a7d"
2796
2806
  },
2797
2807
  {
2798
2808
  "path": "docs/modules-contract.md",
@@ -2882,7 +2892,7 @@
2882
2892
  {
2883
2893
  "path": "docs/page-readings.json",
2884
2894
  "mode": "0000644",
2885
- "sha256": "e9b2c838868e4b23789112734c976ecae722ee3dcc4bea948482666e7a17863a"
2895
+ "sha256": "c9722a4284b34b8773b2fed801a256277bb314833da397ae89af674ebe46acee"
2886
2896
  },
2887
2897
  {
2888
2898
  "path": "docs/project-context.template.md",
@@ -3974,6 +3984,11 @@
3974
3984
  "mode": "0000644",
3975
3985
  "sha256": "ea887c7bcd2863e69121bfcfa36cc62fedc77c5bd5a052e5868e2f7c99cbc103"
3976
3986
  },
3987
+ {
3988
+ "path": "migrations/core_266_access_requests_invited_login_idx.sql",
3989
+ "mode": "0000644",
3990
+ "sha256": "e7dcf016492ab9d011bd0021ac866edd502bf68f2fe06a04365ecb2b49ccbfaa"
3991
+ },
3977
3992
  {
3978
3993
  "path": "modules/agents/CLAUDE.md",
3979
3994
  "mode": "0000644",
@@ -4527,13 +4542,18 @@
4527
4542
  {
4528
4543
  "path": "modules/government/board.js",
4529
4544
  "mode": "0000644",
4530
- "sha256": "f620a9c3cfe606955aa4b6b7dd0d194c1160bab99ee6ffc81a801edf6b3db4a6"
4545
+ "sha256": "afb73887cf5fa3f2c3b1d963e3fd501b5d2251fe1cbe0b28ca1baacb2690410d"
4531
4546
  },
4532
4547
  {
4533
4548
  "path": "modules/government/catalog.js",
4534
4549
  "mode": "0000644",
4535
4550
  "sha256": "0559d78f54b4b8a89ac4e6924d6dad4e2693a7e54f943532e83e4ac966868b76"
4536
4551
  },
4552
+ {
4553
+ "path": "modules/government/charter.js",
4554
+ "mode": "0000644",
4555
+ "sha256": "5b0707da0b679b6b34bcca6f28354de1f4f1b31bc5255bcbca2b74eec5eaf67c"
4556
+ },
4537
4557
  {
4538
4558
  "path": "modules/government/config.js",
4539
4559
  "mode": "0000644",
@@ -4717,7 +4737,7 @@
4717
4737
  {
4718
4738
  "path": "modules/government/routes/government.js",
4719
4739
  "mode": "0000644",
4720
- "sha256": "58415db3a65d68f1e30f626cab20882fc324c2575226b8d6f0a82b8f018694c4"
4740
+ "sha256": "9e98696154986f67d20a6563d71da353359b1acd8af7d29fe98d60973c5856e4"
4721
4741
  },
4722
4742
  {
4723
4743
  "path": "modules/government/routes/rank-sync.js",
@@ -5237,7 +5257,7 @@
5237
5257
  {
5238
5258
  "path": "modules/hall-ui/public/government.js",
5239
5259
  "mode": "0000644",
5240
- "sha256": "4e527b94cf239b219b309d1fe7d8a7d907f42f1f610b0ef3d7edb6d4b23ab6c6"
5260
+ "sha256": "0d584e177a095a53449611feffee2eb9a2a35751154f329e985c8102f7b4fa02"
5241
5261
  },
5242
5262
  {
5243
5263
  "path": "modules/hall-ui/public/government.states.json",
@@ -5742,7 +5762,7 @@
5742
5762
  {
5743
5763
  "path": "modules/hall-ui/public/watch.js",
5744
5764
  "mode": "0000644",
5745
- "sha256": "7a5ef4f34be6b0ab7f5b3fa34bf1666c17164a6331031cc908c2791109585b89"
5765
+ "sha256": "6746170acdd097b14bdccce236ac236b4962bdd1679de2c5624ca1a10cf784d0"
5746
5766
  },
5747
5767
  {
5748
5768
  "path": "modules/hall-ui/public/watch.states.json",
@@ -6832,7 +6852,7 @@
6832
6852
  {
6833
6853
  "path": "modules/onboarding/routes/access-requests.js",
6834
6854
  "mode": "0000644",
6835
- "sha256": "1eaac1f70a519ca5a0ea71bb56ab6d33b582f5ff002faf5811fa6c1700480057"
6855
+ "sha256": "7e8a63d388816b1a65ec6b24fdc20390d42efa7afa5c33cdf164d0cfca1ad5d4"
6836
6856
  },
6837
6857
  {
6838
6858
  "path": "modules/onboarding/routes/onboarding.js",
@@ -7064,6 +7084,11 @@
7064
7084
  "mode": "0000644",
7065
7085
  "sha256": "9b263f91ce6df19640ef8ae413f3eb40cc17589924fdf21256da7647b55631c1"
7066
7086
  },
7087
+ {
7088
+ "path": "modules/platform-identity/migrations/platform_identity_028_purge_pre_notice_invites.sql",
7089
+ "mode": "0000644",
7090
+ "sha256": "7af1d5f5deeae675247ace4a796482ce5a606c871d611f90e2dade905b70a5c1"
7091
+ },
7067
7092
  {
7068
7093
  "path": "modules/platform-identity/module.json",
7069
7094
  "mode": "0000644",
@@ -7077,7 +7102,7 @@
7077
7102
  {
7078
7103
  "path": "modules/platform-identity/platform-identity.js",
7079
7104
  "mode": "0000644",
7080
- "sha256": "9877fd84f74545d96473651cca9d00a76712507e76962c1891d3dd0c3d47e7b2"
7105
+ "sha256": "8f293f2d70e61f90a381153248a748b12452d3bb984e5903f32610fad78d669f"
7081
7106
  },
7082
7107
  {
7083
7108
  "path": "modules/platform-identity/pollers/code-sweep.js",
@@ -7207,7 +7232,7 @@
7207
7232
  {
7208
7233
  "path": "modules/platform-identity/tests/platform-identity.mjs",
7209
7234
  "mode": "0000644",
7210
- "sha256": "d9164f9ae4188a313ce55ebc7c670531aa4e47128f85571aaa55730dbabd1dd3"
7235
+ "sha256": "6dc7617a7d7615fc5ee51817ae77bba8089324c124a6cb1d0fe3ca9400454ee1"
7211
7236
  },
7212
7237
  {
7213
7238
  "path": "modules/platform-identity/ui/.gitkeep",
@@ -7444,6 +7469,11 @@
7444
7469
  "mode": "0000644",
7445
7470
  "sha256": "aad8d8e8a641ebcbff9aeeed765e6c1657fa5896dc9cc3e84aa32f6d327b7db2"
7446
7471
  },
7472
+ {
7473
+ "path": "modules/provisioning/planet-physics.js",
7474
+ "mode": "0000644",
7475
+ "sha256": "e3b0539fff5af52fc24ea171fb6a7ee537c2952608ab59b59dc20596cfbee045"
7476
+ },
7447
7477
  {
7448
7478
  "path": "modules/provisioning/pollers/app-liveness.js",
7449
7479
  "mode": "0000644",
@@ -7472,7 +7502,7 @@
7472
7502
  {
7473
7503
  "path": "modules/provisioning/provisioning.js",
7474
7504
  "mode": "0000644",
7475
- "sha256": "92e9a12c0d07d87a16f0d036369967a60c2dfaca3fb1bce78fab97ad54dac0bf"
7505
+ "sha256": "f2dd673e30cf17abbfbadd3c0142616a1c40b3b680c865b57db8330933816405"
7476
7506
  },
7477
7507
  {
7478
7508
  "path": "modules/provisioning/public-refusal.js",
@@ -7507,7 +7537,7 @@
7507
7537
  {
7508
7538
  "path": "modules/provisioning/routes/body-validators.js",
7509
7539
  "mode": "0000644",
7510
- "sha256": "c59c59f842a0bab6bc45370a902d6db4a1b0e39a902eb115a12abaa59fc48dc9"
7540
+ "sha256": "fdb68a0cf1717b861aabfb9d9b843e9cf3cc28dc4c60a58242597c821c4f8fba"
7511
7541
  },
7512
7542
  {
7513
7543
  "path": "modules/provisioning/routes/callback-page.js",
@@ -7532,7 +7562,7 @@
7532
7562
  {
7533
7563
  "path": "modules/provisioning/routes/provisioning.js",
7534
7564
  "mode": "0000644",
7535
- "sha256": "d0a1e16b8ba6cb03bfadf95c7a3b688007309d173812e34b4e69d6e4dc33d21f"
7565
+ "sha256": "6269c57fd10238a0660beae9df2ab686ea62a8e777eee04bc64d15e03ca503b0"
7536
7566
  },
7537
7567
  {
7538
7568
  "path": "modules/provisioning/routes/render-standup.js",
@@ -7544,11 +7574,21 @@
7544
7574
  "mode": "0000644",
7545
7575
  "sha256": "6189883417ca5703c67be2a66c687d8cdf45053ed28d72ac3775f2d3770d1106"
7546
7576
  },
7577
+ {
7578
+ "path": "modules/provisioning/screening.js",
7579
+ "mode": "0000644",
7580
+ "sha256": "7c707281978f54483029743268f2280b77f3ebcd12a083dce51f81a1d9cfb963"
7581
+ },
7547
7582
  {
7548
7583
  "path": "modules/provisioning/seams.js",
7549
7584
  "mode": "0000644",
7550
7585
  "sha256": "68ba324773bbd9a347ef682c5b1f105b447c6760f24595b8850590ed6d64d78e"
7551
7586
  },
7587
+ {
7588
+ "path": "modules/provisioning/soft-limits.js",
7589
+ "mode": "0000644",
7590
+ "sha256": "03991cd9683c3fc2b4a9fda9e359dcd40a1e782800884b33b49b1d6e1fd9637d"
7591
+ },
7552
7592
  {
7553
7593
  "path": "modules/provisioning/starter-bundles.js",
7554
7594
  "mode": "0000644",
@@ -8932,12 +8972,12 @@
8932
8972
  {
8933
8973
  "path": "package-lock.json",
8934
8974
  "mode": "0000644",
8935
- "sha256": "60d6f4672fc29b5851546d35e5a6f14c6323d7e5946908d1c2bbe301bb3a0dfa"
8975
+ "sha256": "cf64ad1f380ccd8f68a30f1f5b72aa8c03681fc37f044093ae435b7886529cc8"
8936
8976
  },
8937
8977
  {
8938
8978
  "path": "package.json",
8939
8979
  "mode": "0000644",
8940
- "sha256": "9bb1f16462f06299a105da0895a24faac4f1c5bb689c5c9045deeb4bb97fb5bc"
8980
+ "sha256": "d79bd6231aed473960ba8f6c644b69f2c930850a0937a504635e657aa733ea89"
8941
8981
  },
8942
8982
  {
8943
8983
  "path": "public-docs/index.html",
@@ -8957,7 +8997,7 @@
8957
8997
  {
8958
8998
  "path": "release-notes.json",
8959
8999
  "mode": "0000644",
8960
- "sha256": "1e79c9b3c2692c720aac6166d50e881f8069d94be738e57e6eef882ea2ec9d4a"
9000
+ "sha256": "2ec3010abecc3e0ed0d2a9bda13ccad173d34e91d80a13bc4ff4aecace0944e8"
8961
9001
  },
8962
9002
  {
8963
9003
  "path": "scripts/bongos-mcp.js",
@@ -9527,7 +9567,7 @@
9527
9567
  {
9528
9568
  "path": "scripts/gds/fitness.js",
9529
9569
  "mode": "0000644",
9530
- "sha256": "dee3e8db3ad7fff3c1e30a59aa58bab00972cba9710bd463e10ab8a3edc71e38"
9570
+ "sha256": "11c013412eca59780987da1db3af9db4a16202b743e55675cb28812c4091f883"
9531
9571
  },
9532
9572
  {
9533
9573
  "path": "scripts/gds/gate-review.js",
@@ -9752,7 +9792,7 @@
9752
9792
  {
9753
9793
  "path": "scripts/gds/login.js",
9754
9794
  "mode": "0000644",
9755
- "sha256": "0d719e43955fdbcc40aee500438db5b31c6c006490e90d99caadf31b215196f7"
9795
+ "sha256": "75f3a83618340171dba4be280cf41515c341c0468f4cf5dd32e3db8adeb95c9d"
9756
9796
  },
9757
9797
  {
9758
9798
  "path": "scripts/gds/main-audit.js",
@@ -10117,7 +10157,7 @@
10117
10157
  {
10118
10158
  "path": "scripts/gds/run-unit-tests.js",
10119
10159
  "mode": "0000644",
10120
- "sha256": "8a7b0e6b5d899bc2706d952d2383ee5b45758810b7f7d5bd5b7ebc2fc547e43e"
10160
+ "sha256": "1060c8a67619c8e6c0d8168d6a26644b799ed8053ab4995fd9386b55af3660c9"
10121
10161
  },
10122
10162
  {
10123
10163
  "path": "scripts/gds/runner-drift.js",
@@ -10787,7 +10827,7 @@
10787
10827
  {
10788
10828
  "path": "src/bongos/db-kernel.js",
10789
10829
  "mode": "0000644",
10790
- "sha256": "f224d17792980308b3db2762e06fbbdf265bcf50c7d651662f91b818ae5ce146"
10830
+ "sha256": "85032e00d05717fa4cde2d9db45c567d3f11772a549a458b2ae67a18274a0f91"
10791
10831
  },
10792
10832
  {
10793
10833
  "path": "src/bongos/db.js",
@@ -10809,6 +10849,11 @@
10809
10849
  "mode": "0000644",
10810
10850
  "sha256": "5f2e9a548f7c0cd1c8b8245be4ba50e9066edb18d07ee7ded7d72f363040ba00"
10811
10851
  },
10852
+ {
10853
+ "path": "src/bongos/invite-expiry.js",
10854
+ "mode": "0000644",
10855
+ "sha256": "64ae68b30656075c76f420a29e0f25b6499719d745c901580d5859f8c860ca78"
10856
+ },
10812
10857
  {
10813
10858
  "path": "src/bongos/live-channel.js",
10814
10859
  "mode": "0000644",
@@ -10927,7 +10972,7 @@
10927
10972
  {
10928
10973
  "path": "src/bongos/route-rank-check.js",
10929
10974
  "mode": "0000644",
10930
- "sha256": "0a4448143b5673781ab21a3ec982a3a183c410caeb7e3afd3ba5d69586de06b2"
10975
+ "sha256": "c7809ca26bf270ff260b79bf83f9c7dec27616c375ff8e9db78867a2a26a63eb"
10931
10976
  },
10932
10977
  {
10933
10978
  "path": "src/bongos/routes.js",
@@ -11072,7 +11117,7 @@
11072
11117
  {
11073
11118
  "path": "src/module-api.js",
11074
11119
  "mode": "0000644",
11075
- "sha256": "3e5ca31fb6e6c2fc7f351aa64ef4946c206050c6c34df748946a794011cd6f66"
11120
+ "sha256": "40910d211c287582e7066d72f651ff79862d9f5776be6086cd2c931e648136fd"
11076
11121
  },
11077
11122
  {
11078
11123
  "path": "src/module-loader/catalog.js",
@@ -11147,7 +11192,7 @@
11147
11192
  {
11148
11193
  "path": "tests/access_requests_invite.mjs",
11149
11194
  "mode": "0000644",
11150
- "sha256": "1044d48504923ec03a8a08303fa12612b2fc02abed32d85be26bf8d5615807ad"
11195
+ "sha256": "22f633a9216457e37fa5da47b260ce6c7aa0d5b2c500c8170a476807c426c76b"
11151
11196
  },
11152
11197
  {
11153
11198
  "path": "tests/accessibility_replay.mjs",
@@ -11367,7 +11412,7 @@
11367
11412
  {
11368
11413
  "path": "tests/application_lifecycle.mjs",
11369
11414
  "mode": "0000644",
11370
- "sha256": "d35db1b125eaee28d3e0af9c1354b36f589a74bca922b22b507fc29b48bb38c4"
11415
+ "sha256": "f84e1b46315e57514f00545038eaa94a9617a83ebb8b5e4b55814fa3b063e155"
11371
11416
  },
11372
11417
  {
11373
11418
  "path": "tests/architect.mjs",
@@ -11672,7 +11717,7 @@
11672
11717
  {
11673
11718
  "path": "tests/bongos_login.mjs",
11674
11719
  "mode": "0000644",
11675
- "sha256": "1e95957f3c780b4054128000e0deefc76e4df41c3076da76d2fbd187b47c95d2"
11720
+ "sha256": "091ab59bc648f1ef11b309b09283ca2730635c6f3010adfcbf81053e1abb2055"
11676
11721
  },
11677
11722
  {
11678
11723
  "path": "tests/branding.mjs",
@@ -12874,6 +12919,11 @@
12874
12919
  "mode": "0000644",
12875
12920
  "sha256": "ba1c95ca55d8d8e256ba03f2543e44cee4272b9652742343617e35cebefe3ab9"
12876
12921
  },
12922
+ {
12923
+ "path": "tests/government_charter_forms.mjs",
12924
+ "mode": "0000644",
12925
+ "sha256": "0e6e006ad15a39e34b22793be7c6987a8602690f48b65998da04358fd8be3449"
12926
+ },
12877
12927
  {
12878
12928
  "path": "tests/government_charter_library.mjs",
12879
12929
  "mode": "0000644",
@@ -13397,7 +13447,7 @@
13397
13447
  {
13398
13448
  "path": "tests/hub_invite_notices.mjs",
13399
13449
  "mode": "0000644",
13400
- "sha256": "c79b4101c944110166da2e158bada2192235897887b65bbb7b1f9fae3c61eb13"
13450
+ "sha256": "61a4467e59582bd8d640ba82c139089933a2fadf5c3e2bd570bdfb7b11ae26c7"
13401
13451
  },
13402
13452
  {
13403
13453
  "path": "tests/hub_map_orb_states.mjs",
@@ -13689,6 +13739,16 @@
13689
13739
  "mode": "0000644",
13690
13740
  "sha256": "1e01a44dc1ef5d454643e81737f77b5061e577a9275a22f5b98bd05ac541f1d7"
13691
13741
  },
13742
+ {
13743
+ "path": "tests/invite_expiry.mjs",
13744
+ "mode": "0000644",
13745
+ "sha256": "f4e7d57306b988aa5dadb9c2fe3c55f519beb2725980a7d360caa09416b03e8c"
13746
+ },
13747
+ {
13748
+ "path": "tests/invite_expiry_db.mjs",
13749
+ "mode": "0000644",
13750
+ "sha256": "9963890ca3f5ee6ab008079c1623e0dec11bf3ce696ff5f18621ad9e52f76a4d"
13751
+ },
13692
13752
  {
13693
13753
  "path": "tests/join_application_note.mjs",
13694
13754
  "mode": "0000644",
@@ -14007,7 +14067,7 @@
14007
14067
  {
14008
14068
  "path": "tests/module_api.mjs",
14009
14069
  "mode": "0000644",
14010
- "sha256": "be32afe74b2ecd47f136a824c9997b54274b72d41dfe5cd8d1e540e9a05f83f4"
14070
+ "sha256": "35a7e4c2e2afe2cd61e51318e7e3300e7629acd24683b515287aa9dcbe8501ae"
14011
14071
  },
14012
14072
  {
14013
14073
  "path": "tests/module_api_lazy.mjs",
@@ -14349,6 +14409,11 @@
14349
14409
  "mode": "0000644",
14350
14410
  "sha256": "6c623a5abe9aadf4821ad8ca291fb5d7805a7a5bc874bfc3cd7e51e83de289d2"
14351
14411
  },
14412
+ {
14413
+ "path": "tests/pending_invite_purge_db.mjs",
14414
+ "mode": "0000644",
14415
+ "sha256": "afc10a1fa260b41133399037cc7c6b1acdde91f9ffac5d62fa7d84f680138b8b"
14416
+ },
14352
14417
  {
14353
14418
  "path": "tests/permission_path.mjs",
14354
14419
  "mode": "0000644",
@@ -14472,7 +14537,7 @@
14472
14537
  {
14473
14538
  "path": "tests/project_admin_console_model.mjs",
14474
14539
  "mode": "0000644",
14475
- "sha256": "5afd92ab7143b332572adcff8ddec69b544e5607b64b16ba14075d9160eec7a9"
14540
+ "sha256": "af3664d6b4ce861f126b7f9eca87abf423f25bb5126df36a93b80312c70a218c"
14476
14541
  },
14477
14542
  {
14478
14543
  "path": "tests/project_catalog_backfill.mjs",
@@ -14754,6 +14819,11 @@
14754
14819
  "mode": "0000644",
14755
14820
  "sha256": "c9fa4aa59e6e47c139277e3c57298ca441180c4d4752ca6994c72678219df8c8"
14756
14821
  },
14822
+ {
14823
+ "path": "tests/provisioning_planet_physics.mjs",
14824
+ "mode": "0000644",
14825
+ "sha256": "febbdbf82e7521ef80fb00d48a0a5fa9edf063ec20efbb39ddf59051c5cad4b2"
14826
+ },
14757
14827
  {
14758
14828
  "path": "tests/provisioning_public_refusal.mjs",
14759
14829
  "mode": "0000644",
@@ -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
- - 464 operations across 70 resource groups
8
+ - 465 operations across 70 resource groups
9
9
 
10
10
  ## Use it from your project
11
11
 
@@ -465,6 +465,8 @@ function createClient(opts = {}) {
465
465
  postGovernmentAssignments: (args) => request("POST", "/government/assignments", { hasBody: true }, args),
466
466
  // DELETE /government/assignments/{builderId}/{rankKey} — rank: archon — DELETE /government/assignments/:builderId/:rankKey
467
467
  deleteGovernmentAssignmentsBuilderIdRankKey: (args) => request("DELETE", "/government/assignments/{builderId}/{rankKey}", { hasBody: false }, args),
468
+ // POST /government/board/charter — rank: metic+archon — POST /government/board/charter
469
+ postGovernmentBoardCharter: (args) => request("POST", "/government/board/charter", { hasBody: true }, args),
468
470
  // GET /government/board/genesis-stages — rank: any-builder — GET /government/board/genesis-stages
469
471
  getGovernmentBoardGenesisStages: (args) => request("GET", "/government/board/genesis-stages", { hasBody: false }, args),
470
472
  // GET /government/board/items — rank: any-builder — GET /government/board/items
@@ -464,6 +464,8 @@ function createClient(opts = {}) {
464
464
  postGovernmentAssignments: (args) => request("POST", "/government/assignments", { hasBody: true }, args),
465
465
  // DELETE /government/assignments/{builderId}/{rankKey} — rank: archon — DELETE /government/assignments/:builderId/:rankKey
466
466
  deleteGovernmentAssignmentsBuilderIdRankKey: (args) => request("DELETE", "/government/assignments/{builderId}/{rankKey}", { hasBody: false }, args),
467
+ // POST /government/board/charter — rank: metic+archon — POST /government/board/charter
468
+ postGovernmentBoardCharter: (args) => request("POST", "/government/board/charter", { hasBody: true }, args),
467
469
  // GET /government/board/genesis-stages — rank: any-builder — GET /government/board/genesis-stages
468
470
  getGovernmentBoardGenesisStages: (args) => request("GET", "/government/board/genesis-stages", { hasBody: false }, args),
469
471
  // GET /government/board/items — rank: any-builder — GET /government/board/items
@@ -219,7 +219,7 @@ export interface PatchProjectsIdFeaturedResponse { project: unknown }
219
219
  export interface PatchProjectsIdStatusRequest { status: string }
220
220
  export interface PatchProjectsIdStatusResponse { project: unknown }
221
221
  export interface PatchProvisioningInstancesIdDetailRequest { description?: string; detail?: Record<string, unknown>; modules?: string[]; type?: string }
222
- export interface PatchProvisioningInstancesIdDetailResponse { ok: boolean; description: unknown; detail: unknown; options: unknown; publish: unknown; modules: unknown; type: unknown }
222
+ export interface PatchProvisioningInstancesIdDetailResponse { ok: boolean; description: unknown; detail: unknown; options: unknown; soft_limits: unknown; publish: unknown; modules: unknown; type: unknown }
223
223
  export interface PatchProvisioningInstancesIdEnvManifestVarIdRequest { name?: string; description?: string; environments?: unknown[]; required?: boolean }
224
224
  export interface PatchProvisioningInstancesIdEnvManifestVarIdResponse { ok: boolean; env_var: unknown; values_held: boolean }
225
225
  export interface PatchProvisioningInstancesIdSettingsResponse { ok: boolean; saved: unknown; planet: unknown; push: unknown }
@@ -330,6 +330,8 @@ export interface PostGoalsReorderResponse { ok: boolean; goals: unknown }
330
330
  export interface PostGoalsRequest { version_id: string; title: string; subtitle?: string; description?: string; scope_modules?: string[]; succeeds_goal_id?: number; category_id?: number; admit_reason?: string }
331
331
  export interface PostGoalsResponse { ok: boolean; goal: unknown; succeeds_goal_id: unknown; category_advisory: unknown; admitted: unknown }
332
332
  export interface PostGovernmentAssignmentsRequest { builder_id: number; rank_key: string }
333
+ export interface PostGovernmentBoardCharterRequest { form?: string; franchise?: string; council_rank?: string; pass_rule?: string; rationale_md?: string; acknowledge_self_removal?: boolean }
334
+ export interface PostGovernmentBoardCharterResponse { ok: boolean; amendment: unknown; item: unknown; reads_as: unknown }
333
335
  export interface PostGovernmentBoardItemsItemIdVotesRequest { direction: string; reason_md?: string; section_key?: string }
334
336
  export interface PostGovernmentBoardItemsRequest { subject_type: string; proposal: Record<string, unknown>; rationale_md?: string; acknowledge_self_removal?: boolean }
335
337
  export interface PostGovernmentBoardItemsResponse { ok: boolean; amendment: unknown; item: unknown }
@@ -894,6 +896,8 @@ export interface BongosClient {
894
896
  postGovernmentAssignments(args: RequestArgs & { body: PostGovernmentAssignmentsRequest }): Promise<ApiResponse>;
895
897
  /** DELETE /government/assignments/{builderId}/{rankKey} — rank: archon */
896
898
  deleteGovernmentAssignmentsBuilderIdRankKey(args?: RequestArgs): Promise<DeleteGovernmentAssignmentsBuilderIdRankKeyResponse>;
899
+ /** POST /government/board/charter — rank: metic+archon */
900
+ postGovernmentBoardCharter(args?: RequestArgs & { body?: PostGovernmentBoardCharterRequest }): Promise<PostGovernmentBoardCharterResponse>;
897
901
  /** GET /government/board/genesis-stages — rank: any-builder */
898
902
  getGovernmentBoardGenesisStages(args?: RequestArgs): Promise<ApiResponse>;
899
903
  /** GET /government/board/items — rank: any-builder */
@@ -461,6 +461,8 @@ export function createClient(opts = {}) {
461
461
  postGovernmentAssignments: (args) => request("POST", "/government/assignments", { hasBody: true }, args),
462
462
  // DELETE /government/assignments/{builderId}/{rankKey} — rank: archon — DELETE /government/assignments/:builderId/:rankKey
463
463
  deleteGovernmentAssignmentsBuilderIdRankKey: (args) => request("DELETE", "/government/assignments/{builderId}/{rankKey}", { hasBody: false }, args),
464
+ // POST /government/board/charter — rank: metic+archon — POST /government/board/charter
465
+ postGovernmentBoardCharter: (args) => request("POST", "/government/board/charter", { hasBody: true }, args),
464
466
  // GET /government/board/genesis-stages — rank: any-builder — GET /government/board/genesis-stages
465
467
  getGovernmentBoardGenesisStages: (args) => request("GET", "/government/board/genesis-stages", { hasBody: false }, args),
466
468
  // GET /government/board/items — rank: any-builder — GET /government/board/items
@@ -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`
@@ -55,10 +55,10 @@ The two notice routes are **new**. An older hub answers 404, the sender swallows
55
55
  ## Consequences
56
56
 
57
57
  - **The done-when holds for every invite created from now on.** A hub notice exists only because the project wrote an `invited` row, and a rescind that closes the door removes the notice. The hub's own invite creates no row at all.
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.
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,30 @@
1
+ # ADR 0355 — A soft limit is a rule with a reason, and nobody enforces it
2
+
3
+ - **Status:** accepted
4
+ - **Date:** 2026-09-30
5
+ - **Task:** [task 1004416](https://cloudbongos.com/builders#/task/1004416) (BV2.PS02, goal 1000121)
6
+ - **Interacts with:** [ADR 0239](0239-a-recommendation-is-a-table-that-carries-its-own-reason.md) (a recommendation is a table that carries its own reason), the spec [`docs/specs/<redacted>.md`](../specs/<redacted>.md) decision D6
7
+
8
+ ## Context
9
+
10
+ The new startup flow asks seven "planet physics" questions before any technical setup: state, geography, ages, entity, builders, rewards and framing. The answers carry legal weight. An individual has no shares to give, cash payouts to EU builders are not available yet, and 13 to 15 year olds join non-monetary tracks only. Spec decision D6 says the flow should grey or hide options that clearly do not apply, each with a line saying why. It also says nothing enforces these limits yet, and no screen may claim otherwise.
11
+
12
+ The flow also needs a stop screen: a project whose description is something Cloud Bongos will not help build is stopped before anything is created. The real classifier is out of scope.
13
+
14
+ ## Decision
15
+
16
+ **D1: The answers are more `detail` keys.** They ride the provisioning `detail` jsonb under the same contract as `team_shape`: no defaults, an unknown value refused loudly at the route, and `null` to un-answer. Two new kinds of question join the closed single answer. A `many` question takes a list of members, stored de-duplicated in the vocabulary's order. A `count` question takes a whole number in a range. `PROJECT_DETAIL_QUESTIONS` is the whole contract. `PROJECT_DETAIL_VOCAB` stays the closed answer lists, so every existing reader and the `options` reply keep their shape. The country is a closed ISO 3166-1 list rather than a two-letter pattern, so a typo like `ZZ` is refused instead of stored.
17
+
18
+ **D2: Answers must agree only within one request.** The main kind of work must be one of the existing kinds, and the region must be inside the country, when both arrive in the same body. A merge patch may change one half now and the other later, and refusing a write because it disagrees with a stored answer would make the order of edits matter.
19
+
20
+ **D3: The soft limits are one declarative table, and every resolution says `enforced: false`.** Each rule has a `when` (data, never a function), the options it names, an effect (`hide`, `grey` or `note`) and an owner-facing reason. Because conditions are data, a test can check every rule against the vocabulary, and a browser could evaluate the same table. An unanswered key never matches, so no rule fires on an answer nobody gave. `note` exists because some options apply only in part: cash is still available to builders outside the EU, so greying it would be wrong. The resolution rides every owner read of a project and the `PATCH …/detail` reply. A test fails any reason worded as if the limit were enforced.
21
+
22
+ **D4: Screening is a seam with a deliberately small rule set.** `screenProject(texts, rules)` takes the project's own words and returns `{ stop }`. The real classifier replaces the rules or the function body, and no caller changes. A keyword rule that stops an honest project is worse than one that misses a bad one, so each rule names something no legitimate project is built to be. An `unless` lets a defensive project through (a ransomware detector, a phishing-awareness course). A stop is a 422 `screened_out` with the canvas's own sentence. Nothing in the reply names the rule, because a gate that says which rule it tripped teaches a caller how to reword around it. Whoever answers "contact us" reads the description itself.
23
+
24
+ **D5: The screen runs on the edit route too.** The stop happens on create before any row or intent exists. `PATCH …/detail` screens a new description as well. Otherwise a project could be created with no description and given the stopped one straight afterwards.
25
+
26
+ ## Consequences
27
+
28
+ - No migration: `detail` is a dumb jsonb store, so new questions cost none.
29
+ - The age tiers and payout geography are stored facts, not policy. Server-side enforcement is a later goal, and it will read these keys.
30
+ - The screen's false positives are the risk to watch. Until the classifier exists, a rule should be added only when it cannot plausibly describe an honest project.