@bongos/core 1.19.512 → 1.19.513

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 (35) hide show
  1. package/.bongos-core.json +62 -37
  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 +3 -0
  6. package/clients/bongos-client/index.mjs +2 -0
  7. package/docs/adr/0239-a-recommendation-is-a-table-that-carries-its-own-reason.md +177 -0
  8. package/docs/adr/README.md +1 -0
  9. package/docs/api/openapi.json +40 -3
  10. package/docs/api-reference.md +3 -2
  11. package/docs/copy-inventory.md +36 -35
  12. package/docs/copy-registry.json +93 -74
  13. package/docs/module-api-changelog.md +2 -0
  14. package/modules/dev-box/app/src/vendor/bongos-client.cjs +2 -0
  15. package/modules/hall-ui/public/hall-kit.js +309 -0
  16. package/modules/hall-ui/public/hall-render.js +10 -38
  17. package/modules/hall-ui/public/profile-charts.js +58 -65
  18. package/modules/hall-ui/public/profile.css +9 -18
  19. package/modules/hall-ui/public/style.css +101 -15
  20. package/modules/hall-ui/public/watch.css +6 -14
  21. package/modules/hall-ui/public/watch.html +1 -1
  22. package/modules/hall-ui/public/watch.js +139 -54
  23. package/modules/provisioning/recommendations.js +260 -0
  24. package/modules/provisioning/routes/provisioning.js +29 -0
  25. package/package-lock.json +2 -2
  26. package/package.json +1 -1
  27. package/src/module-api.js +1 -1
  28. package/tests/hall_audit.mjs +84 -0
  29. package/tests/hall_kit_charts.mjs +328 -0
  30. package/tests/hall_profile_world.mjs +27 -6
  31. package/tests/helpers.mjs +161 -0
  32. package/tests/joinability_invite_only.mjs +10 -2
  33. package/tests/provisioning_recommendations.mjs +448 -0
  34. package/tests/task_detail_ui.mjs +1 -153
  35. package/tests/watch_applications_queue.mjs +381 -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.19.512",
6
- "core_contract": "1.19.512",
7
- "source_commit": "b80dfcced279a5dc071290fdc22ea3aeec3dfd70",
5
+ "core_version": "1.19.513",
6
+ "core_contract": "1.19.513",
7
+ "source_commit": "9e6d801ba8dcecaefcb3b75033642211d8275198",
8
8
  "source_ref": "HEAD",
9
- "built_at": "2026-09-03T18:54:15.905Z",
9
+ "built_at": "2026-09-03T19:22:17.457Z",
10
10
  "redaction": {
11
11
  "model": "docs-redacted+functional-verbatim",
12
- "docs_redacted": 429,
12
+ "docs_redacted": 430,
13
13
  "agent_docs_stubbed": 24,
14
- "functional_verbatim": 1952,
14
+ "functional_verbatim": 1956,
15
15
  "rules": 3,
16
16
  "gate_literals": 3,
17
17
  "gate": "passed"
18
18
  },
19
- "file_count": 2405,
20
- "tree_sha256": "382fde42e266c00ccb3f8289a487a709a55e3e606c5fc80a395a49c667f42e96",
19
+ "file_count": 2410,
20
+ "tree_sha256": "a794da9ad6fee320c375a0fe3bea353d508f6d1fe6cba0dd1761da71a9ef5f32",
21
21
  "files": [
22
22
  {
23
23
  "path": ".claude/skills/blocker-review/SKILL.md",
@@ -362,12 +362,12 @@
362
362
  {
363
363
  "path": "clients/bongos-client/README.md",
364
364
  "mode": "0000644",
365
- "sha256": "146ce9d114ec7d5a90413713b8604843c42eac060dd943648412868e214a1a6e"
365
+ "sha256": "546f5670b4637aa1d4c492a8616d5189a971c79e8e2e163d12fe11276292faa6"
366
366
  },
367
367
  {
368
368
  "path": "clients/bongos-client/bongos-client.global.js",
369
369
  "mode": "0000644",
370
- "sha256": "0e3fb901fd7110352e0edb686cfd8824d71687b88bd7e42269d0fe855177ac9f"
370
+ "sha256": "ae151ff268d04dced73fae1136c682215a02e59bae5edb68a3d6001c0143dd57"
371
371
  },
372
372
  {
373
373
  "path": "clients/bongos-client/examples/hello-world.mjs",
@@ -377,17 +377,17 @@
377
377
  {
378
378
  "path": "clients/bongos-client/index.cjs",
379
379
  "mode": "0000644",
380
- "sha256": "19f11ecf8c9eda49cd1f2ac2425f1d3d9772ad46495305d9ae4bdeadf4695ea2"
380
+ "sha256": "72d841c53787c5ad83b214c2ac816fd4cb9c97b47329eb0417b80e660a9f6b02"
381
381
  },
382
382
  {
383
383
  "path": "clients/bongos-client/index.d.ts",
384
384
  "mode": "0000644",
385
- "sha256": "4ced11579608e8fdb481a07b5555c41b3cbf3018cb3a8bd7697fb58368283bf0"
385
+ "sha256": "07554254c8559f81ec5cf45807ddccd8488732b228a618167455c932e7f05750"
386
386
  },
387
387
  {
388
388
  "path": "clients/bongos-client/index.mjs",
389
389
  "mode": "0000644",
390
- "sha256": "3d5868d134bce56923b8f0270fbb2e988dea5b6a5ea1a00b96ff8bcde06bb40e"
390
+ "sha256": "c4b04368e61803e2fe36f26ba3757aa75ada7e465384baf3e53cd012c9ce8423"
391
391
  },
392
392
  {
393
393
  "path": "clients/bongos-client/package.json",
@@ -1699,20 +1699,25 @@
1699
1699
  "mode": "0000644",
1700
1700
  "sha256": "fb05e36eb48861f2b32a38da04eba839f8141bd52ff9d913070bc589c115f9d5"
1701
1701
  },
1702
+ {
1703
+ "path": "docs/adr/0239-a-recommendation-is-a-table-that-carries-its-own-reason.md",
1704
+ "mode": "0000644",
1705
+ "sha256": "42b20cd6d2e8a8d76c980df73087fd404487e4c479034dbe34d8297677bd9387"
1706
+ },
1702
1707
  {
1703
1708
  "path": "docs/adr/README.md",
1704
1709
  "mode": "0000644",
1705
- "sha256": "1ec64297bc6f1858e1315b049d143de5390fb5b5843e0414f536d4fa2a42d7d5"
1710
+ "sha256": "cef542ef427dd81632465f17c6343c6b27f3ab69436eba2130c4fa4b5c9bc4ae"
1706
1711
  },
1707
1712
  {
1708
1713
  "path": "docs/api-reference.md",
1709
1714
  "mode": "0000644",
1710
- "sha256": "f9a893262b5112e48a8bffa455c8e1a7ce8aed663e34141ef9c48117882a2ad7"
1715
+ "sha256": "af226ff669081accc330b8797ec6ac766bef9066a9fc97e834c66ad61fcec22c"
1711
1716
  },
1712
1717
  {
1713
1718
  "path": "docs/api/openapi.json",
1714
1719
  "mode": "0000644",
1715
- "sha256": "ec2d400cae26a7b89f644e978840927fd0fb88fc0b7b94e9f0d00dd19955aaf2"
1720
+ "sha256": "34cd50bf2154126c9a402235972642f4430281434852977c4e7277febc959a18"
1716
1721
  },
1717
1722
  {
1718
1723
  "path": "docs/architecture.md",
@@ -1737,12 +1742,12 @@
1737
1742
  {
1738
1743
  "path": "docs/copy-inventory.md",
1739
1744
  "mode": "0000644",
1740
- "sha256": "519630f4bda79510d5bc3f131d28ad1915517b05ec4f8dadf3081d0845bb9440"
1745
+ "sha256": "0cc8ccfda8d8e3e7b518fae7a7584bb368d7d2eac6703518404d30f0b6ead30d"
1741
1746
  },
1742
1747
  {
1743
1748
  "path": "docs/copy-registry.json",
1744
1749
  "mode": "0000644",
1745
- "sha256": "b920c2349d109b9c75c22396095d011c90edc2614f844ac27a4b3f116c805278"
1750
+ "sha256": "1003ea51740a5f71af49e05c66ba088c337185680dd92a391c959e8ea76a3f40"
1746
1751
  },
1747
1752
  {
1748
1753
  "path": "docs/design/apex-pass-2-direction.md",
@@ -2587,7 +2592,7 @@
2587
2592
  {
2588
2593
  "path": "docs/module-api-changelog.md",
2589
2594
  "mode": "0000644",
2590
- "sha256": "26d8b7f65d94927b0f382674b0421d8b5694856fd619b5c8fc57f1147f17b20d"
2595
+ "sha256": "326d065772f944339af791ceb779b2724c0feef4d4937d1aa9e13c9bc5b8a38e"
2591
2596
  },
2592
2597
  {
2593
2598
  "path": "docs/modules-contract.md",
@@ -3957,7 +3962,7 @@
3957
3962
  {
3958
3963
  "path": "modules/dev-box/app/src/vendor/bongos-client.cjs",
3959
3964
  "mode": "0000644",
3960
- "sha256": "19f11ecf8c9eda49cd1f2ac2425f1d3d9772ad46495305d9ae4bdeadf4695ea2"
3965
+ "sha256": "72d841c53787c5ad83b214c2ac816fd4cb9c97b47329eb0417b80e660a9f6b02"
3961
3966
  },
3962
3967
  {
3963
3968
  "path": "modules/dev-box/app/test/unit.mjs",
@@ -4707,12 +4712,12 @@
4707
4712
  {
4708
4713
  "path": "modules/hall-ui/public/hall-kit.js",
4709
4714
  "mode": "0000644",
4710
- "sha256": "e392af98c2d310bfe80ccc560895dc2729abbe416087fcc7609d22dd4593484c"
4715
+ "sha256": "9fdd4fa659a6ff1f36159a89a5bab9d12009b1624f7d72f8d1296d1dffff0d3f"
4711
4716
  },
4712
4717
  {
4713
4718
  "path": "modules/hall-ui/public/hall-render.js",
4714
4719
  "mode": "0000644",
4715
- "sha256": "d3ec5ebd2a4b60f0e87d82304920905021c6ee992e6a371516317da02f78ac3e"
4720
+ "sha256": "e06761bf930a2b7bf8b0c4a3eba0532edb1a6f0d49d366b6889ebba9101e5d4f"
4716
4721
  },
4717
4722
  {
4718
4723
  "path": "modules/hall-ui/public/hall-widgets.js",
@@ -4907,7 +4912,7 @@
4907
4912
  {
4908
4913
  "path": "modules/hall-ui/public/profile-charts.js",
4909
4914
  "mode": "0000644",
4910
- "sha256": "865df71a66dd944006b01dfb1317778a1d733d9320b4486efd8ee1ed3ea76f19"
4915
+ "sha256": "6eb791bb5d73e869f1af1dbabe6fbd04eccf970b54696a89a4cd1d28e6e705df"
4911
4916
  },
4912
4917
  {
4913
4918
  "path": "modules/hall-ui/public/profile-connections.js",
@@ -4922,7 +4927,7 @@
4922
4927
  {
4923
4928
  "path": "modules/hall-ui/public/profile.css",
4924
4929
  "mode": "0000644",
4925
- "sha256": "81712abfa291664378581139a3611acaff0ebdcd2cb77d641e8543d653080c30"
4930
+ "sha256": "18d65cb2bab78487a4cbf2447154a69674291972d15256d338123c2a437abc87"
4926
4931
  },
4927
4932
  {
4928
4933
  "path": "modules/hall-ui/public/profile.html",
@@ -5057,7 +5062,7 @@
5057
5062
  {
5058
5063
  "path": "modules/hall-ui/public/style.css",
5059
5064
  "mode": "0000644",
5060
- "sha256": "287e9d4c4a2f57e812051dc6613d4c5ef493924c1a3de1b15fa91072128fa46e"
5065
+ "sha256": "801d467a63d65c24877cac2741308590b9cd66530231f77bdf7230d1c4ebe513"
5061
5066
  },
5062
5067
  {
5063
5068
  "path": "modules/hall-ui/public/task-detail.js",
@@ -5097,17 +5102,17 @@
5097
5102
  {
5098
5103
  "path": "modules/hall-ui/public/watch.css",
5099
5104
  "mode": "0000644",
5100
- "sha256": "0c877cf6decf1b7291c877ec2e6c0603c5170cfecabf0d6be15a793b6858dad8"
5105
+ "sha256": "ea2f7870bdd9383cfded8b2b09724486faa0793438dfa17bc52af189c8a81c6f"
5101
5106
  },
5102
5107
  {
5103
5108
  "path": "modules/hall-ui/public/watch.html",
5104
5109
  "mode": "0000644",
5105
- "sha256": "b20c001318da04ee5ca731702356479b0c7e4bffdd5784be9b1984db31d30777"
5110
+ "sha256": "60ffce27ce4250223dc6bbaa22e1b7b9dfb4f689bd78b6ca1c75445088c5ddb9"
5106
5111
  },
5107
5112
  {
5108
5113
  "path": "modules/hall-ui/public/watch.js",
5109
5114
  "mode": "0000644",
5110
- "sha256": "0576fa65e1ac51a3928e1ac584532b9e4db1102513d35acc5e31c1afef66c32c"
5115
+ "sha256": "f5d264fde6898c3cf82387d042d26fb434bbd8e60657c376b452f89b0a85435c"
5111
5116
  },
5112
5117
  {
5113
5118
  "path": "modules/hall-ui/public/watch.states.json",
@@ -5984,10 +5989,15 @@
5984
5989
  "mode": "0000644",
5985
5990
  "sha256": "27046325beffad5d1edfcc91c331048038900ef7d32f1d38796755c7990ba202"
5986
5991
  },
5992
+ {
5993
+ "path": "modules/provisioning/recommendations.js",
5994
+ "mode": "0000644",
5995
+ "sha256": "8c4b2d8d17b80229c371b82ac9a5a2cf2fa979683ac586e8b833ca0a309a92fc"
5996
+ },
5987
5997
  {
5988
5998
  "path": "modules/provisioning/routes/provisioning.js",
5989
5999
  "mode": "0000644",
5990
- "sha256": "338e135f492e584aa4539d4a64d7c881b964c9ffa8428ff3359ad96d80b82a5c"
6000
+ "sha256": "9285f3f2d426305c060eef4b3b98ae64fc386e4ce487f99d9ad59d9921dc493e"
5991
6001
  },
5992
6002
  {
5993
6003
  "path": "modules/provisioning/starter-bundles.js",
@@ -7247,12 +7257,12 @@
7247
7257
  {
7248
7258
  "path": "package-lock.json",
7249
7259
  "mode": "0000644",
7250
- "sha256": "63c01590a251d6ec16dde2e0be5d843e12ff40955733268f6d322718f1e807be"
7260
+ "sha256": "afcb15b2197925baf012e363e7af8de096c9e2f6bbdd6cf50015b4039a2e0441"
7251
7261
  },
7252
7262
  {
7253
7263
  "path": "package.json",
7254
7264
  "mode": "0000644",
7255
- "sha256": "4bbced9436a337f2b2ea9fe5445bf6f9f94354ffeda4d1b1766cd12f4e9f74d9"
7265
+ "sha256": "a9827319a035ff87ca5805284b7296d80d1148390a3bb99ae03f46307a6952e8"
7256
7266
  },
7257
7267
  {
7258
7268
  "path": "public-docs/index.html",
@@ -8922,7 +8932,7 @@
8922
8932
  {
8923
8933
  "path": "src/module-api.js",
8924
8934
  "mode": "0000644",
8925
- "sha256": "379afd7239016bc0e504bc3b73596c35cb71a074a6b743f32c76c5a24493a44e"
8935
+ "sha256": "86d6ba39dbe1e2b39067a2fd2328284fd950a9f9060450f87e55b3be84f5fef9"
8926
8936
  },
8927
8937
  {
8928
8938
  "path": "src/module-loader/catalog.js",
@@ -10302,7 +10312,7 @@
10302
10312
  {
10303
10313
  "path": "tests/hall_audit.mjs",
10304
10314
  "mode": "0000644",
10305
- "sha256": "7df5602bb92b44186613870501ecb4e959c9288f8d103cfc8075a3a24d51d840"
10315
+ "sha256": "0b30e949b0479adb4b436aa32e741c9f2ab3925a1ac4327daf6e8a95700a8c14"
10306
10316
  },
10307
10317
  {
10308
10318
  "path": "tests/hall_board_world.mjs",
@@ -10324,6 +10334,11 @@
10324
10334
  "mode": "0000644",
10325
10335
  "sha256": "1d9c1d345a6fe25eacf810703a3e7f9f3b33f8e982aef49364e19eb4469de668"
10326
10336
  },
10337
+ {
10338
+ "path": "tests/hall_kit_charts.mjs",
10339
+ "mode": "0000644",
10340
+ "sha256": "475c712af2b45fed7863b486c3d2ed3b96e955dccb9acc5909999db3990843d5"
10341
+ },
10327
10342
  {
10328
10343
  "path": "tests/hall_nav.mjs",
10329
10344
  "mode": "0000644",
@@ -10352,7 +10367,7 @@
10352
10367
  {
10353
10368
  "path": "tests/hall_profile_world.mjs",
10354
10369
  "mode": "0000644",
10355
- "sha256": "9e5047b39d55875e167c992157c6c04a9a766ec331c1a3bf343fe7ea194a8309"
10370
+ "sha256": "b35d647c4cb7b90be70dee8e7245396cc901479992fafbf19ceef734d8195399"
10356
10371
  },
10357
10372
  {
10358
10373
  "path": "tests/hall_reading_world.mjs",
@@ -10402,7 +10417,7 @@
10402
10417
  {
10403
10418
  "path": "tests/helpers.mjs",
10404
10419
  "mode": "0000644",
10405
- "sha256": "89d0ebdf842108bcf807bd08663e9f83566d9b0ae80e72ba038f8d4f0b30b0f8"
10420
+ "sha256": "b3f0a87c51c9e655c712db00a0a8763e2fc08e4de3c6904c6080385e7c7dad14"
10406
10421
  },
10407
10422
  {
10408
10423
  "path": "tests/hierarchy-config.mjs",
@@ -10632,7 +10647,7 @@
10632
10647
  {
10633
10648
  "path": "tests/joinability_invite_only.mjs",
10634
10649
  "mode": "0000644",
10635
- "sha256": "082693b5e07c1c25cec17cde7f93a8716aafa94ead9b1cee76b1643f30edff79"
10650
+ "sha256": "5311e076e8a72b993a235e57ebc54c9ecd529ccd31b65609432677a12e15e85d"
10636
10651
  },
10637
10652
  {
10638
10653
  "path": "tests/joinability_open.mjs",
@@ -11174,6 +11189,11 @@
11174
11189
  "mode": "0000644",
11175
11190
  "sha256": "97d04ee39cc06b720d4a5b42f3e3cc614f64d9462b27471a1af7598b5e2929be"
11176
11191
  },
11192
+ {
11193
+ "path": "tests/provisioning_recommendations.mjs",
11194
+ "mode": "0000644",
11195
+ "sha256": "0557876002c1f0efde5a8e7c87702fa57df3a9efb26ea93b077969bcc10e3637"
11196
+ },
11177
11197
  {
11178
11198
  "path": "tests/provisioning_restart.mjs",
11179
11199
  "mode": "0000644",
@@ -11847,7 +11867,7 @@
11847
11867
  {
11848
11868
  "path": "tests/task_detail_ui.mjs",
11849
11869
  "mode": "0000644",
11850
- "sha256": "5e7150f8651a3c147b17f51800f5f8afa1e9534b3ec545584e5c37792475b2aa"
11870
+ "sha256": "d7b12d56b50a0412d50f3558065c681d92c0c631edfef5553164e646979e6fa5"
11851
11871
  },
11852
11872
  {
11853
11873
  "path": "tests/task_goal_link.mjs",
@@ -12004,6 +12024,11 @@
12004
12024
  "mode": "0000644",
12005
12025
  "sha256": "745a868a2e13f34afd29f96840102205792bac810f2fd911c7da00f6a5695242"
12006
12026
  },
12027
+ {
12028
+ "path": "tests/watch_applications_queue.mjs",
12029
+ "mode": "0000644",
12030
+ "sha256": "b1f7df5aa40b89f8737c76d94def15c539514f7f439cca79a034bf37b922158d"
12031
+ },
12007
12032
  {
12008
12033
  "path": "tests/web_admission_status.mjs",
12009
12034
  "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
- - 346 operations across 53 resource groups
8
+ - 347 operations across 53 resource groups
9
9
 
10
10
  ## Install
11
11
 
@@ -669,6 +669,8 @@ function createClient(opts = {}) {
669
669
  postProvisioningInstancesIdTeardown: (args) => request("POST", "/provisioning/instances/{id}/teardown", { hasBody: true }, args),
670
670
  // GET /provisioning/onboard-plan — rank: public — GET /provisioning/onboard-plan
671
671
  getProvisioningOnboardPlan: (args) => request("GET", "/provisioning/onboard-plan", { hasBody: false }, args),
672
+ // GET /provisioning/recommendations — rank: public — GET /provisioning/recommendations
673
+ getProvisioningRecommendations: (args) => request("GET", "/provisioning/recommendations", { hasBody: false }, args),
672
674
  // GET /provisioning/slug-available — rank: any-builder — GET /provisioning/slug-available
673
675
  getProvisioningSlugAvailable: (args) => request("GET", "/provisioning/slug-available", { hasBody: false }, args),
674
676
  // GET /provisioning/starter-bundles — rank: public — GET /provisioning/starter-bundles
@@ -668,6 +668,8 @@ function createClient(opts = {}) {
668
668
  postProvisioningInstancesIdTeardown: (args) => request("POST", "/provisioning/instances/{id}/teardown", { hasBody: true }, args),
669
669
  // GET /provisioning/onboard-plan — rank: public — GET /provisioning/onboard-plan
670
670
  getProvisioningOnboardPlan: (args) => request("GET", "/provisioning/onboard-plan", { hasBody: false }, args),
671
+ // GET /provisioning/recommendations — rank: public — GET /provisioning/recommendations
672
+ getProvisioningRecommendations: (args) => request("GET", "/provisioning/recommendations", { hasBody: false }, args),
671
673
  // GET /provisioning/slug-available — rank: any-builder — GET /provisioning/slug-available
672
674
  getProvisioningSlugAvailable: (args) => request("GET", "/provisioning/slug-available", { hasBody: false }, args),
673
675
  // GET /provisioning/starter-bundles — rank: public — GET /provisioning/starter-bundles
@@ -97,6 +97,7 @@ export interface GetProvisioningInstancesIdResponse { instance: unknown; open_in
97
97
  export interface GetProvisioningInstancesIdSettingsResponse { ok: boolean; settings: unknown; planet: unknown; options: unknown }
98
98
  export interface GetProvisioningInstancesResponse { instances: unknown }
99
99
  export interface GetProvisioningOnboardPlanResponse { mode: unknown; steps: unknown }
100
+ export interface GetProvisioningRecommendationsResponse { recommendations: unknown }
100
101
  export interface GetProvisioningSlugAvailableResponse { slug: unknown; available: unknown; reason: unknown; address: unknown }
101
102
  export interface GetProvisioningStarterBundlesResponse { core: unknown; bundles: unknown }
102
103
  export interface GetPublicBlockersIdResponse { blocker: unknown }
@@ -980,6 +981,8 @@ export interface BongosClient {
980
981
  postProvisioningInstancesIdTeardown(args?: RequestArgs): Promise<PostProvisioningInstancesIdTeardownResponse>;
981
982
  /** GET /provisioning/onboard-plan — rank: public */
982
983
  getProvisioningOnboardPlan(args?: RequestArgs): Promise<GetProvisioningOnboardPlanResponse>;
984
+ /** GET /provisioning/recommendations — rank: public */
985
+ getProvisioningRecommendations(args?: RequestArgs): Promise<GetProvisioningRecommendationsResponse>;
983
986
  /** GET /provisioning/slug-available — rank: any-builder */
984
987
  getProvisioningSlugAvailable(args?: RequestArgs): Promise<GetProvisioningSlugAvailableResponse>;
985
988
  /** GET /provisioning/starter-bundles — rank: public */
@@ -665,6 +665,8 @@ export function createClient(opts = {}) {
665
665
  postProvisioningInstancesIdTeardown: (args) => request("POST", "/provisioning/instances/{id}/teardown", { hasBody: true }, args),
666
666
  // GET /provisioning/onboard-plan — rank: public — GET /provisioning/onboard-plan
667
667
  getProvisioningOnboardPlan: (args) => request("GET", "/provisioning/onboard-plan", { hasBody: false }, args),
668
+ // GET /provisioning/recommendations — rank: public — GET /provisioning/recommendations
669
+ getProvisioningRecommendations: (args) => request("GET", "/provisioning/recommendations", { hasBody: false }, args),
668
670
  // GET /provisioning/slug-available — rank: any-builder — GET /provisioning/slug-available
669
671
  getProvisioningSlugAvailable: (args) => request("GET", "/provisioning/slug-available", { hasBody: false }, args),
670
672
  // GET /provisioning/starter-bundles — rank: public — GET /provisioning/starter-bundles
@@ -0,0 +1,177 @@
1
+ # 0239 — A recommendation is a table that carries its own reason; governance is a preview and invites are a seam
2
+
3
+ - **Status:** Accepted
4
+ - **Date:** 2026-09-03
5
+ - **Tasks:** [#1002336](https://cloudbongos.com/builders#/task/1002336) (this decision — BV1.R17)
6
+ - **Goal:** [#1000046](https://cloudbongos.com/builders#/goal/1000046) — Project creation: visibility and
7
+ customization; criteria `proj-module-select` ("additional modules are recommended (rule-based) from the
8
+ project's details"), `proj-governance-reco` ("a recommended governance setup … derived from its details"),
9
+ `proj-invite-builders` ("the owner can optionally invite guilds or top builders")
10
+ - **Related:** [ADR 0237](<redacted>.md)
11
+ (R19, the per-type preset this adjusts), [ADR 0182](<redacted>.md) D4 (skipping the
12
+ interview is a supported answer), [ADR 0083](<redacted>.md) (the
13
+ one-way import rule that makes the invite lookup a seam),
14
+ task [#1002334](https://cloudbongos.com/builders#/task/1002334) (R15, the interview whose answer this reads),
15
+ task [#1002772](https://cloudbongos.com/builders#/task/1002772) (the declared project type),
16
+ task [#1003500](https://cloudbongos.com/builders#/task/1003500) / idea 1000552 (the deferred AI layer)
17
+
18
+ ## 1. The problem
19
+
20
+ Three of goal 1000046's criteria ask the same question in three places: after an
21
+ owner answers the optional project-detail interview, what do we *recommend* — which
22
+ modules, which governance setup, which builders to invite. The goal's own text pins
23
+ the near term: "near-term recommendations are rule-based and module search is
24
+ lexical; the AI/embeddings layer … is a deferred follow-up captured in the idea
25
+ inbox."
26
+
27
+ R19 ([ADR 0237](<redacted>.md))
28
+ already answered the type half — a starter bundle per declared project type — and
29
+ said explicitly that it is "a declaration and not a rule engine … R17/R22 own the
30
+ layer that reasons." This is that layer.
31
+
32
+ ## 2. Two inputs, and the description is not one of them
33
+
34
+ The engine reads exactly two things, and they arrive separately because they are
35
+ stored separately: `type` is a column (the closed set task 1002772 fixed —
36
+ `game · research · business · non-profit · not-sure`) and `team_shape` is the one
37
+ closed-answer key the R15 interview collects (`PROJECT_DETAIL_VOCAB.team_shape ∈
38
+ solo | small-team | community`). The interview deliberately does not re-ask the type
39
+ (ADR 0237 §2), so `recommendationsForDetails({ type, team_shape })` is the file that
40
+ puts the two back together, and a caller holding a row passes
41
+ `{ type: row.type, ...projectDetail(row) }`.
42
+
43
+ The interview's *third* answer — the free-text `description` — is deliberately
44
+ **not** read. Inferring a bundle from prose is the deferred semantic layer
45
+ ([#1003500](https://cloudbongos.com/builders#/task/1003500), idea 1000552), and ADR
46
+ 0237 §7 already rejected it once for the same reason.
47
+
48
+ ## 3. A table, and every row carries the sentence that explains it
49
+
50
+ The engine is three frozen tables and a resolver over them — not a scorer, not a
51
+ weighting, not a model:
52
+
53
+ | table | keyed on | effect |
54
+ |---|---|---|
55
+ | `TEAM_SHAPE_RULES` | `team_shape` | add/remove ONE opt-in module from the type's bundle |
56
+ | `GOVERNANCE_RULES` | `team_shape` | a named preset out of `GOVERNANCE_PRESETS` |
57
+ | `INVITE_RULES` | `team_shape` | a `seeking` descriptor, or `null` for "suggest nobody" |
58
+
59
+ Every row carries a `reason` — one sentence in the owner's own words, shipped
60
+ alongside the effect rather than reconstructed by whichever surface renders it. That
61
+ is the constraint that makes the whole thing auditable: a recommendation an owner
62
+ cannot be told the reason for is one they cannot disagree with, and a reason written
63
+ separately from the rule drifts from it the first time either changes.
64
+
65
+ The three bundle rules today: `community` **adds** `discord` (somewhere for it to
66
+ gather); `small-team` **adds** `dev-box` (one shared environment); `solo` **removes**
67
+ `dev-box` (your own machine is the setup). They are few for the reason ADR 0237 §4
68
+ gave — today's opt-in catalog is three modules wide, and a preselect an owner must
69
+ audit is worse than none. The rules' job is to correct a preset the owner's answer
70
+ contradicts, not to re-derive it.
71
+
72
+ ## 4. `adjustments` is a delta — a rule that changes nothing claims nothing
73
+
74
+ `bundle.adjustments` lists only the rules that ACTUALLY moved the module list. The
75
+ game bundle already carries `discord`, so a `community` answer records no adjustment
76
+ even though its condition matched; the non-profit bundle has no `dev-box`, so a
77
+ `solo` answer removes nothing and says nothing.
78
+
79
+ The alternative — record the reason whenever the condition matches — was rejected
80
+ because it conflates two different sentences: "discord is on because your project is
81
+ a game" (the bundle, R19's opinion) and "we switched discord on because you said
82
+ community" (the rule). A picker rendering the second over a module the owner would
83
+ have had anyway is telling them something they can check and find false.
84
+
85
+ ## 5. Governance is a named preview, never an applied setting
86
+
87
+ Criterion `proj-governance-reco` says it out loud: the recommendation "depends on the
88
+ governance module (goal 1000030), which is planned but not yet built." So a preset
89
+ here is a **name plus one sentence of what living under it feels like** — `owner-only`
90
+ / `trusted-team` / `open-contribution` — and never a set of roles or permissions,
91
+ because there is nowhere to put them.
92
+
93
+ Every recommendation carries `governance.applied: false`. A constant field looks
94
+ redundant until you count the surfaces that otherwise hardcode the same fact: R25's
95
+ preview step ([#1002344](https://cloudbongos.com/builders#/task/1002344)), R18's proof
96
+ ([#1002337](https://cloudbongos.com/builders#/task/1002337)), the wizard and the
97
+ project page. One flag flips when goal 1000030 lands; a test pins it false until then.
98
+
99
+ ## 6. Invites are a seam, because the leaderboard is a sibling module
100
+
101
+ `invites.suggested` is **always empty**, and that is a decision rather than an
102
+ unfinished edge. Ranking builders means querying the leaderboard, which lives in
103
+ `economy` — a sibling module `provisioning` may not import (the one-way rule, ADR
104
+ 0083). Making the route do it instead would cost the engine's purity, put a database
105
+ read behind a public endpoint, and duplicate work
106
+ [#1002347](https://cloudbongos.com/builders#/task/1002347) (R28) already owns and
107
+ whose dependency is R27, not R17.
108
+
109
+ So the engine emits what to look for — `invites.seeking = { kind: 'top-builders',
110
+ limit }`, or `null` for "suggest nobody" — and R28 turns it into names. `null` is a
111
+ real answer here: a solo builder is suggested nobody on purpose, which is a different
112
+ statement from an empty list nobody has filled yet.
113
+
114
+ ## 7. Skipping is an answer, and every default is the narrowest one
115
+
116
+ The interview is optional (ADR 0182 D4), so every table has a stated default for
117
+ "nobody said" and each is deliberately the narrowest option: the type's own bundle
118
+ unadjusted, `owner-only` governance, and no invites. Widening later costs one
119
+ setting; a project that quietly granted strangers a role it was never asked to grant
120
+ is not recovered by setting it back.
121
+
122
+ An **off-vocabulary** `team_shape` — absent, misspelled, or a value that has since
123
+ left the vocabulary — reads as *no answer*, exactly as `normalizeProjectDetail` drops
124
+ it on the way in. The route follows the same rule: a missing or unusable query value
125
+ returns 200 with the defaults, never a 400, because refusing the request would make
126
+ the supported path an error.
127
+
128
+ `tailored: boolean` is the machine-readable half of criterion
129
+ `proj-detail-interview`'s split ("completing it produces tailored recommendations;
130
+ skipping produces sensible defaults") — false exactly when no detail answer shaped
131
+ anything. R18 is the live proof of that line.
132
+
133
+ ## 8. The read surface
134
+
135
+ `GET /provisioning/recommendations?type=&team_shape=` returns
136
+ `{ recommendations: { type, teamShape, tailored, bundle, governance, invites } }`.
137
+ `bundle` is ADR 0237 §5's shape with `adjustments` added, so R20's picker
138
+ ([#1002339](https://cloudbongos.com/builders#/task/1002339)) and this engine resolve
139
+ through the same `bundleForProjectType` and can never name different modules — a test
140
+ asserts that against the live `starter-bundles` route.
141
+
142
+ `rank: public`, the same absent gate as `starter-bundles` and `onboard-plan`: the
143
+ signed-out wizard asks while the owner is still answering, *before* any row exists to
144
+ be own-scoped against, and the answer is a declaration that names nothing private.
145
+ The route touches no database, and the test proves it by stubbing `pool` to throw.
146
+
147
+ ## 9. Consequences
148
+
149
+ - **The UI is not wired here.** R20 renders the picker, R22
150
+ ([#1002341](https://cloudbongos.com/builders#/task/1002341)) surfaces these
151
+ recommendations inside it, and R18 proves the details→recs / skip→defaults split.
152
+ The creation wizard currently hardcodes a `TEAM_META` copy table in
153
+ `modules/public-landing/public/projects.html` that says roughly what
154
+ `governance.preview` now says — R22 should collapse that duplicate into this route
155
+ rather than leave one sentence written twice.
156
+ - **Adding a fourth team-shape answer is a two-file change.** The interview vocabulary
157
+ and this file, and `tests/provisioning_recommendations.mjs` fails the build if a
158
+ vocabulary value has no governance rule and no invite rule.
159
+ - **A recommendation is still never a publish precondition** (ADR 0182 D4 — the bar is
160
+ name + description alone), and taking or declining one cannot move a project's
161
+ dark-matter state.
162
+
163
+ ## 10. Rejected
164
+
165
+ - **Reading the free-text description** — that is the deferred AI/semantic layer
166
+ ([#1003500](https://cloudbongos.com/builders#/task/1003500)), and the goal pins the
167
+ near term as rule-based.
168
+ - **Filling `invites.suggested` from `GET /public/leaderboard`** — the route exists and
169
+ is public, but reaching it means importing a sibling module, and R28 owns that work
170
+ behind a different dependency.
171
+ - **A scoring function over weighted signals** — with two inputs and three opt-in
172
+ modules there is nothing to weigh, and a score cannot be shown to an owner as a
173
+ sentence they can disagree with.
174
+ - **Recording a reason for every matched condition** — see §4; it makes a claim the
175
+ owner can check and find false.
176
+ - **Refusing an unknown `team_shape` with a 400** — skipping is the supported path, so
177
+ the shape of a skipped answer must not be an error.
@@ -326,5 +326,6 @@ This keeps the decision history honest and traceable.
326
326
  | 0236 | [**Many ideas → one task: the lineage key is the pair** ([task 1003515](https://cloudbongos.com/builders#/task/1003515) · goal 1000071, "Idea routing" — promoted from idea 1000815; the table was built by [task 1002997](https://cloudbongos.com/builders#/task/1002997)). `ideas_task_lineage.task_id` was the PRIMARY KEY on the reasoning that "a task descends from at most one idea", and `linkIdeaTask` wrote `ON CONFLICT (task_id) DO UPDATE SET idea_id = EXCLUDED.idea_id` — so promoting a SECOND idea into a task that already had a link **silently replaced the first idea's lineage**: no error, no warning, no log line. Two ordinary triage promotes at one task were enough, and it happened on prod on 2026-08-21 (ideas 1000811 + 1000812 → task 1003150). Because this table is the rail [ADR 0172](<redacted>.md) stream 1 pays against, an overwritten row is an **ideator not paid** for work their idea produced, with nothing recording it — and it makes merging duplicate reports into one task a LOSSY move, which is the triage the inbox exists to encourage. The R01 grader named this shape and was told it was unreachable; it was unreachable on the ROUTING path examined and fully reachable on the ordinary PROMOTE path. **Decision: many ideas → one task is a real relation, so the key is the pair** — `ideas_006` re-adds `ideas_task_lineage_pkey` as `PRIMARY KEY (task_id, idea_id)` and both INSERT sites `DO UPDATE SET origin`, never `idea_id`. Refusing the second link would turn a legitimate merge into an error; logging the replacement keeps a lossy ledger. **Where one row is still required the EARLIEST link wins** (`ORDER BY created_at, idea_id`, stated in SQL rather than left to the planner): `sourceIdeaForTask`, `credits.awardIdeaTaskShipCredit`, and the nod queue's one-row-per-task predicate — one constant shared by the list and its count, so the pill can never disagree with the rows. Consequences: a task subsumed from N ideas **counts once toward each idea's** shipped-task credit (and cannot double-count within one — the pair is unique); the per-ship payout still names one idea, the earliest, because paying every co-source ideator is a decision about total worth, not a bug fix; the migration **backfills** from `idea_inbox.promoted_to_task_id`, the weaker pointer that survived each overwrite, labelling restored rows `origin='promote'`; and `updateIdea` still swallows a lineage failure but now reports it as a `LINEAGE GAP` through `api.logger` — a silent swallow on top of a silent overwrite was two layers of one mistake.](<redacted>.md) | ideas / economy |
327
327
  | 0238 | [**The join door is a provisioning SETTINGS key, and the hub column stays the cache** ([task 1002324](https://cloudbongos.com/builders#/task/1002324) · goal 1000046, criterion `proj-visibility-states` — R05). [ADR 0182](<redacted>.md) D5 says R05 "moves host — an instance surface, not a hub one", and on the tree both halves of that sentence pointed at nothing: `platform_identity_projects.visibility` (which R04 shipped) is written by **no route** — every write on `routes/projects.js` is the `project.curate` CURATION gate with no ownership check, `upsertProject` deliberately omits the column, and `owner_github_id` there is documented "advisory attribution (not an authority)" — while "the project's own hall settings" is a page that does not exist (`settings.html` is per-BUILDER; the hall's my-projects page was deleted by task 1003308). **Decision: the door is a key in `provisioning.SETTINGS_VOCAB`** (`visibility ∈ public|private|stealth`, default `public`), set through the existing own-scoped `PATCH /provisioning/instances/:id/settings` and rendered as one more `.mSec` section on the manage view an owner already uses. One line in the vocabulary buys the whole task from machinery already proven: `instanceAccessDenied` (own-scoped, Archon override, **404** not 403 — no existence leak), a validator that IS the vocabulary (so an off-list value 400s and a key can never drift out of the schema), a `provisioning_events` audit row, the `<PREFIX>_VISIBILITY` env the runner patches into `web.env`, and `src/branding.js` mapping it onto `project.visibility` in the public manifest. It is a **POLICY** key, not a platform-drawn one like the planet, for two reasons that outlive today: ADR 0182 D6 makes the door the CEILING `joinability` may only narrow and D1/D5 put admission authority on the instance — a door the instance cannot read cannot be a ceiling — and a key with a DEFAULT belongs in the defaulted vocabulary (`PLANET_VOCAB` keys are nullable because null means "the platform picks", and there is no such thing as the platform picking your join door). Nothing here writes the hub column: it stays ADR 0182 D5's cache, and R08 is the report that will feed it — so today an owner's pick is stored, validated, audited and delivered to their instance, and does not yet move the orb (that gap is R06/R08's, named so the next builder does not hunt a bug). The section deliberately ships **no "what your project runs" read-back line**, unlike its two siblings: a deployed project reports no door until it takes a release carrying the field, and a line that could only ever say "this project's server doesn't report this yet" is worse than none. Rejected: a new owner-scoped write route on the hub catalog (D5 forbids the hub authorising the change); a new instance-side settings page on its own (right long-run home, but today a control with no consumer while R08 is unshipped); a `visibility` COLUMN beside `description` (that one earned a column as half the publish gate and is read by SQL — a closed-vocabulary knob is what the jsonb store exists for); and `PLANET_VOCAB` to dodge the restart (a quieter save today, the ceiling rule lost tomorrow).](<redacted>.md) | provisioning / public-landing |
328
328
  | 0237 | [**A starter bundle is a preset over the always-on core, keyed by the declared project type** ([task 1002338](https://cloudbongos.com/builders#/task/1002338) · goal 1000046, criterion `proj-module-select`). "During setup a default set of modules is pre-selected" can only mean the OPT-IN modules, since every instance already boots with the same sixteen `default: true` core-domain ones — so a bundle is a short list of opt-in module keys layered on that floor, preselected and freely toggled off by R20's picker ([task 1002339](https://cloudbongos.com/builders#/task/1002339)). **The key is the DECLARED type, and the seeded vocabulary is stale:** the task text (2026-07-17) names *Game / SaaS-Tool / Community*, but task [1002772](https://cloudbongos.com/builders#/task/1002772)'s owner decision (2026-08-13) fixed the live closed set as `game · research · business · non-profit · not-sure` — two CHECK constraints, two `PROJECT_TYPES` constants and five wizard buttons — and "community" survives only as a `team_shape`. Two constraints ride the key: the arrow runs **type → modules, never back** (1002772 rejected inferring type from module flags, which flip all through setup), and the R15 interview must **not re-ask** what `type` declares, so R19 adds no `PROJECT_DETAIL_VOCAB` key and no migration. `not-sure` and *undeclared* resolve to the same modules but are deliberately different answers — `type` is nullable precisely so "nobody said" is never back-filled with a guess, and the resolver returns `type: null` with its own copy. **The declaration is pinned by a test, not a runtime catalog read:** a module may not import `src/module-loader/catalog.js` (the one-way rule, [ADR 0083](<redacted>.md)), so `modules/provisioning/starter-bundles.js` stays PURE like `onboard-plan.js` beside it and `tests/provisioning_starter_bundles.mjs` reads every `modules/*/module.json` off disk — failing the build if a bundle names a module that does not exist, if `ALWAYS_ON_CORE` drifts from the manifests' `default: true` set, if a bundle names an always-on module (a preselect that toggles nothing), or if it names one of the two hub-only modules. The bundles are `game → dev-box, discord`; `research → agents`; `business → agents, dev-box`; `non-profit → discord`; `not-sure → —`, and they are SHORT because today's opt-in catalog is three modules wide and a preselect an owner must audit is worse than none. Served whole at public `GET /provisioning/starter-bundles` (`{ core, bundles }`, same absent gate as `onboard-plan`) so the picker re-preselects without a refetch and R17's recommendations read the same shape. A bundle is **never a publish precondition** — [ADR 0182](<redacted>.md) D4 fixes that bar at name + description alone. Rejected: a runtime catalog read, a `bundle` key in the interview vocabulary, inferring the bundle from the description (the deferred AI layer, [task 1003500](https://cloudbongos.com/builders#/task/1003500)), and keeping the seeded Game/SaaS-Tool/Community triple.](<redacted>.md) | provisioning / project creation |
329
+ | 0239 | [**A recommendation is a table that carries its own reason; governance is a preview and invites are a seam** ([task 1002336](https://cloudbongos.com/builders#/task/1002336) · goal 1000046, criteria `proj-module-select` / `proj-governance-reco` / `proj-invite-builders`). R19 ([ADR 0237](<redacted>.md)) declared the per-type starter bundle and said outright it is "a declaration and not a rule engine — R17/R22 own the layer that reasons"; this is that layer, and the goal pins it **rule-based**, with the AI/embeddings pass deferred ([task 1003500](https://cloudbongos.com/builders#/task/1003500), idea 1000552). **Two inputs, and the free-text description is not one of them:** the DECLARED `type` (a column) and `team_shape` (the one closed-answer key the R15 interview collects, [task 1002334](https://cloudbongos.com/builders#/task/1002334)) — inferring from prose is the deferred layer ADR 0237 §7 already rejected once. The engine is three frozen tables (`TEAM_SHAPE_RULES` add/remove ONE opt-in module; `GOVERNANCE_RULES` name a preset; `INVITE_RULES` emit a seek) and **every row carries its own `reason` sentence**, shipped with the effect rather than reconstructed by whichever surface renders it — a recommendation an owner cannot be told the reason for is one they cannot disagree with. `bundle.adjustments` is a **DELTA**: a rule whose condition matched but whose module the bundle already carried records NOTHING, because "we switched discord on because you said community" over a module a game would have had anyway is a claim the owner can check and find false. **Governance is a named preview, never a setting** — the governance module is planned and unbuilt (goal 1000030), so a preset is a name plus one sentence of what it feels like (`owner-only` / `trusted-team` / `open-contribution`) and every result carries `applied: false`, one flag instead of the same fact hardcoded in R25, R18, the wizard and the project page. **Invites are a SEAM**: `suggested` is always `[]` because ranking builders means querying the leaderboard in the sibling `economy` module, which the one-way rule ([ADR 0083](<redacted>.md)) forbids importing — the engine emits `seeking: { kind: 'top-builders', limit }` (or `null` = suggest nobody, a real answer) and R28 ([task 1002347](https://cloudbongos.com/builders#/task/1002347)) turns it into names. **Skipping is an answer:** every table states a default and each is the NARROWEST option (widening later costs one setting; a role granted to strangers is not recovered by setting it back), an off-vocabulary `team_shape` reads as no answer exactly as `normalizeProjectDetail` drops it, and the route answers 200-with-defaults rather than 400 — refusing would make the supported path ([ADR 0182](<redacted>.md) D4) an error. `tailored: boolean` is the machine-readable half of `proj-detail-interview`'s details-vs-skip split that R18 ([task 1002337](https://cloudbongos.com/builders#/task/1002337)) proves. Served at public `GET /provisioning/recommendations?type=&team_shape=` (same absent gate as `starter-bundles`; no database, pinned by a `pool`-throws stub), returning ADR 0237 §5's bundle shape plus `adjustments` so a recommendation and R20's preselect can never name different modules. Rejected: reading the description, filling `suggested` from `GET /public/leaderboard`, a weighted scoring function, a reason per matched condition, and a 400 on an unknown shape.](<redacted>.md) | provisioning / project creation |
329
330
 
330
331
  > ⚠️ **Numbering collisions are now machine-enforced, not narrated.** Twenty numbers are shared by two ADRs each — assigned in parallel sessions before anything checked. The files keep their filenames (renumbering would break every existing citation, and a number once assigned is never reused), and this table disambiguates each pair as `NNNN-a` / `NNNN-b`. The authoritative list is `LEGACY_DUPLICATE_ADRS` in [`scripts/gds/adr-namespace.js`](../../scripts/gds/adr-namespace.js), frozen by exact filename: a **new** collision — or a third file joining a legacy number, or a rename of either half — hard-fails the `unit` CI gate, as does an index row that points at no file or an ADR with no row. The list may only shrink. This paragraph used to narrate the collisions one by one and had fallen eight behind reality; see [ADR 0195](<redacted>.md) for why the check exists and why the pairs are grandfathered rather than renumbered.
@@ -11690,6 +11690,34 @@
11690
11690
  "security": []
11691
11691
  }
11692
11692
  },
11693
+ "/provisioning/recommendations": {
11694
+ "get": {
11695
+ "operationId": "get_provisioning_recommendations",
11696
+ "tags": [
11697
+ "provisioning"
11698
+ ],
11699
+ "summary": "GET /provisioning/recommendations",
11700
+ "description": "GET /provisioning/recommendations?type=<project type>&team_shape=<interview answer> — the RULE-BASED recommendation for one set of creation answers (BV1.R17, task 1002336; goal 1000046 criteria `proj-module-select`, `proj-governance-reco`, `proj-invite-builders`). Returns `{ recommendations: { type, teamShape, tailored, bundle, governance, invites } }` — the starter bundle adjusted by the interview answer with a `reason` per adjustment, a named governance preset with its preview (`applied: false` until the governance module ships, goal 1000030), and the invite SEEK that R28 (task 1002347) turns into names. The two answers arrive separately because they are stored separately: `type` is a column and `team_shape` a key of the `detail` jsonb, so a caller passes back exactly what it holds. Both are optional and neither is validated by rejection — an absent or off-vocabulary value reads as NO ANSWER and yields the stated defaults, which is the supported path (ADR 0182 D4: skipping the interview is a real answer), never a 400. A pure read over modules/provisioning/recommendations.js — no database, no per-request state. rank: public — the same absent gate as `starter-bundles` and `onboard-plan` above: the signed-out hub wizard (/projects?view=new) asks while the owner is still answering, before any row exists to be own-scoped against, and the answer is a declaration that names nothing private.\n\n**Rank:** `public` — No authentication — any caller.",
11701
+ "x-rank": "public",
11702
+ "x-source": "modules/provisioning/routes/provisioning.js",
11703
+ "responses": {
11704
+ "200": {
11705
+ "description": "Success.",
11706
+ "content": {
11707
+ "application/json": {
11708
+ "schema": {
11709
+ "$ref": "#/components/schemas/GetProvisioningRecommendationsResponse"
11710
+ }
11711
+ }
11712
+ }
11713
+ },
11714
+ "400": {
11715
+ "$ref": "#/components/responses/BadRequest"
11716
+ }
11717
+ },
11718
+ "security": []
11719
+ }
11720
+ },
11693
11721
  "/provisioning/slug-available": {
11694
11722
  "get": {
11695
11723
  "operationId": "get_provisioning_slug_available",
@@ -16997,6 +17025,15 @@
16997
17025
  "steps"
16998
17026
  ]
16999
17027
  },
17028
+ "GetProvisioningRecommendationsResponse": {
17029
+ "type": "object",
17030
+ "properties": {
17031
+ "recommendations": {}
17032
+ },
17033
+ "required": [
17034
+ "recommendations"
17035
+ ]
17036
+ },
17000
17037
  "GetProvisioningSlugAvailableResponse": {
17001
17038
  "type": "object",
17002
17039
  "properties": {
@@ -21797,9 +21834,9 @@
21797
21834
  "description": "A required dependency/feature is not configured or is temporarily down."
21798
21835
  }
21799
21836
  },
21800
- "x-endpoint-count": 346,
21801
- "x-schema-count": 378,
21837
+ "x-endpoint-count": 347,
21838
+ "x-schema-count": 379,
21802
21839
  "x-undocumented-bodies": 9,
21803
- "x-response-schemas": 258,
21840
+ "x-response-schemas": 259,
21804
21841
  "x-generated-by": "scripts/gds/gen-api-docs.js"
21805
21842
  }