@bongos/core 1.19.532 → 1.19.534

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 +113 -48
  2. package/clients/bongos-client/index.d.ts +1 -1
  3. package/config/branding.neutral.json +3 -2
  4. package/docs/adr/0244-a-catalog-search-is-a-view-over-the-rows-never-an-edit-to-the-selection.md +116 -0
  5. package/docs/adr/0245-the-way-back-into-an-optional-step-is-that-step-s-own-answer-route.md +144 -0
  6. package/docs/adr/0246-catalog-membership-is-a-projection-not-a-federation-side-effect.md +96 -0
  7. package/docs/adr/0247-the-join-door-is-one-composed-answer-and-dark-matter-has-no-live-verdict-yet.md +202 -0
  8. package/docs/adr/README.md +5 -0
  9. package/docs/api/openapi.json +8 -1
  10. package/docs/api-reference.md +1 -1
  11. package/docs/copy-inventory.md +129 -124
  12. package/docs/copy-registry.json +205 -159
  13. package/docs/file-map.md +1 -0
  14. package/docs/module-api-changelog.md +16 -0
  15. package/modules/onboarding/module.json +1 -1
  16. package/modules/onboarding/routes/access-requests.js +21 -6
  17. package/modules/platform-identity/module.json +1 -1
  18. package/modules/platform-identity/project-catalog.js +202 -0
  19. package/modules/platform-identity/routes/my-projects.js +7 -2
  20. package/modules/platform-identity/routes/projects.js +6 -0
  21. package/modules/platform-identity/routes/sso.js +10 -0
  22. package/modules/provisioning/catalog-bridge.js +105 -0
  23. package/modules/provisioning/provisioning.js +28 -2
  24. package/modules/provisioning/routes/provisioning.js +45 -11
  25. package/modules/provisioning/tests/provisioning.mjs +11 -8
  26. package/modules/public-landing/public/assets/cosmos.css +15 -0
  27. package/modules/public-landing/public/projects.html +221 -2
  28. package/modules/public-landing/public/projects.states.json +2 -1
  29. package/modules/ui-design/kit/serve.js +1 -0
  30. package/package-lock.json +2 -2
  31. package/package.json +1 -1
  32. package/scripts/gds/fitness.js +9 -0
  33. package/scripts/gds/provision-net.js +7 -0
  34. package/src/bongos/project-door.js +138 -0
  35. package/src/branding.js +8 -0
  36. package/src/module-api.js +12 -1
  37. package/tests/access_requests_invite.mjs +2 -2
  38. package/tests/application_lifecycle.mjs +1 -0
  39. package/tests/catalog_only_client.mjs +242 -0
  40. package/tests/currency_label.mjs +8 -5
  41. package/tests/module_api.mjs +1 -0
  42. package/tests/project_catalog_bridge.mjs +355 -0
  43. package/tests/project_catalog_routes.mjs +213 -0
  44. package/tests/project_join_door.mjs +166 -0
  45. package/tests/project_join_door_route.mjs +206 -0
  46. package/tests/project_modules_ui.mjs +318 -0
  47. package/tests/projects_hub.mjs +28 -1
  48. package/tests/projects_hub_module_picker.mjs +207 -0
  49. package/tests/projects_hub_pre_uat.mjs +2 -2
  50. package/tests/provision_settings_apply.mjs +6 -5
  51. package/tests/provisioning_module_selection.mjs +164 -3
  52. package/tests/provisioning_settings.mjs +10 -7
  53. package/tests/provisioning_settings_apply.mjs +3 -3
  54. package/tests/provisioning_settings_env.mjs +7 -4
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.532",
6
- "core_contract": "1.19.532",
7
- "source_commit": "0d85f8047f3d27e733f38cbc564ee04e52ade1ba",
5
+ "core_version": "1.19.534",
6
+ "core_contract": "1.19.534",
7
+ "source_commit": "1eed1abe54c1a615fc751be7b5c5361ed183e701",
8
8
  "source_ref": "HEAD",
9
- "built_at": "2026-09-04T13:48:05.212Z",
9
+ "built_at": "2026-09-04T14:43:41.890Z",
10
10
  "redaction": {
11
11
  "model": "docs-redacted+functional-verbatim",
12
- "docs_redacted": 435,
12
+ "docs_redacted": 439,
13
13
  "agent_docs_stubbed": 24,
14
- "functional_verbatim": 1979,
14
+ "functional_verbatim": 1988,
15
15
  "rules": 3,
16
16
  "gate_literals": 3,
17
17
  "gate": "passed"
18
18
  },
19
- "file_count": 2438,
20
- "tree_sha256": "e9a3a6c31479fe08db5016d877a886d2a957224c77830e643951589e59a5fa7f",
19
+ "file_count": 2451,
20
+ "tree_sha256": "1d0ba8602e73d9b01a0bf440739e615efce023edf6cd5db2a27e12021eac8fda",
21
21
  "files": [
22
22
  {
23
23
  "path": ".claude/skills/blocker-review/SKILL.md",
@@ -387,7 +387,7 @@
387
387
  {
388
388
  "path": "clients/bongos-client/index.d.ts",
389
389
  "mode": "0000644",
390
- "sha256": "ae23995907a851acd2b2dbae901280926e3041ce64e16407d47ed5ba998d7c74"
390
+ "sha256": "22ae4bdb9bf36dfc3ce19fe38e64e8dded029087dac16d3ea20ccdbe1d860788"
391
391
  },
392
392
  {
393
393
  "path": "clients/bongos-client/index.mjs",
@@ -402,7 +402,7 @@
402
402
  {
403
403
  "path": "config/branding.neutral.json",
404
404
  "mode": "0000644",
405
- "sha256": "c33b285d6a88d38eb15e062e0da845d29ec2aa7e6bfc5a4d321a3a49e0b7b2f9"
405
+ "sha256": "af8b7eea98085e2ec1365e3e4bdaaffe35df17e753c8891265b3839dc2a8d42b"
406
406
  },
407
407
  {
408
408
  "path": "config/design-tokens.neutral.json",
@@ -1729,20 +1729,40 @@
1729
1729
  "mode": "0000644",
1730
1730
  "sha256": "17a0018cfa4f42364a1567bee6bc98f8cf84311ce8344b218d4de9eab870b496"
1731
1731
  },
1732
+ {
1733
+ "path": "docs/adr/0244-a-catalog-search-is-a-view-over-the-rows-never-an-edit-to-the-selection.md",
1734
+ "mode": "0000644",
1735
+ "sha256": "a115ba411ec945223b0de36514fcbfb253205b79c2125c232081f35af3ec9a45"
1736
+ },
1737
+ {
1738
+ "path": "docs/adr/0245-the-way-back-into-an-optional-step-is-that-step-s-own-answer-route.md",
1739
+ "mode": "0000644",
1740
+ "sha256": "eb4e39132264f6a4515276b470d6d431ccc3b38f3f14927080d7bc67e3aba57e"
1741
+ },
1742
+ {
1743
+ "path": "docs/adr/0246-catalog-membership-is-a-projection-not-a-federation-side-effect.md",
1744
+ "mode": "0000644",
1745
+ "sha256": "4440a267f36bb1b22815a0fd192dd96f4dbd236ec5c73e108f9462a31f2a7ad9"
1746
+ },
1747
+ {
1748
+ "path": "docs/adr/0247-the-join-door-is-one-composed-answer-and-dark-matter-has-no-live-verdict-yet.md",
1749
+ "mode": "0000644",
1750
+ "sha256": "f46ee74d7b83ad4422e1832fdba68a8b9ea0deccb425ab3083d4c8fbfd06eb02"
1751
+ },
1732
1752
  {
1733
1753
  "path": "docs/adr/README.md",
1734
1754
  "mode": "0000644",
1735
- "sha256": "fb28cbf7bb03cc69deb895b5e25956a440449c11f1fd977ee09655116e3fc3b0"
1755
+ "sha256": "d1bb4772b43b56cf1efa16fa99f255535bd736910c4c0ead94249f19862c7152"
1736
1756
  },
1737
1757
  {
1738
1758
  "path": "docs/api-reference.md",
1739
1759
  "mode": "0000644",
1740
- "sha256": "b137673ee16cd6f7d32b0b24d12b6c8e844a2e6e415a8118a4d458c382e5724f"
1760
+ "sha256": "44555316c4fd8655bd48185820784f8a351ddc1a874e6d905c38865c330e6be1"
1741
1761
  },
1742
1762
  {
1743
1763
  "path": "docs/api/openapi.json",
1744
1764
  "mode": "0000644",
1745
- "sha256": "46e8c08e1e7b5bfa6fe2e709308a466f3764ed320702c93dbe74d5523bb1d74b"
1765
+ "sha256": "59f85c4841c3e884ea88d03a8385b37d104e0b0bcf561c87412bc30912490831"
1746
1766
  },
1747
1767
  {
1748
1768
  "path": "docs/architecture.md",
@@ -1767,12 +1787,12 @@
1767
1787
  {
1768
1788
  "path": "docs/copy-inventory.md",
1769
1789
  "mode": "0000644",
1770
- "sha256": "729633c41036ec0026d3ef1ac787f68cb6fb7ab77e3eb578f855b5ec2d63280f"
1790
+ "sha256": "63719647c69dd90bafa957a9e24b772324b49a09c8e615cc4bc6eac65996e540"
1771
1791
  },
1772
1792
  {
1773
1793
  "path": "docs/copy-registry.json",
1774
1794
  "mode": "0000644",
1775
- "sha256": "344a451940b630b1f6db2f97acb45eb387616311675b243dcc4381dc604ef77d"
1795
+ "sha256": "c951cedd4efe1050dadb15f8bda65e0bd1e6f59aa775e2a407c9b676c27a7d5d"
1776
1796
  },
1777
1797
  {
1778
1798
  "path": "docs/design/apex-pass-2-direction.md",
@@ -2607,7 +2627,7 @@
2607
2627
  {
2608
2628
  "path": "docs/file-map.md",
2609
2629
  "mode": "0000644",
2610
- "sha256": "c7f035d61e8a45f2354256ae5fbbc16794ce6108ab3b5b712b054ade924df4ea"
2630
+ "sha256": "6085fdda80f0c961067a044b890358fa148415638854029e63f764e262594aeb"
2611
2631
  },
2612
2632
  {
2613
2633
  "path": "docs/handoff-template.md",
@@ -2617,7 +2637,7 @@
2617
2637
  {
2618
2638
  "path": "docs/module-api-changelog.md",
2619
2639
  "mode": "0000644",
2620
- "sha256": "6ca40faade53a38c1de107d3bd73b9abb9ababfa89642ff49f42c2453fe8dcbb"
2640
+ "sha256": "93a1f84761363805e0950743fa35a6b755957ef1a8621baa51705ba70f83ddd4"
2621
2641
  },
2622
2642
  {
2623
2643
  "path": "docs/modules-contract.md",
@@ -5707,7 +5727,7 @@
5707
5727
  {
5708
5728
  "path": "modules/onboarding/module.json",
5709
5729
  "mode": "0000644",
5710
- "sha256": "36800847c9cc9d239bb4d0ec910b35b547f8c67e5db5cb1cd5aa63d801e4bf02"
5730
+ "sha256": "6d27c15d955095fb278db240d7e68da87abbdab14b4dd10f98dfd0753746a3c1"
5711
5731
  },
5712
5732
  {
5713
5733
  "path": "modules/onboarding/newcomer-restock.js",
@@ -5732,7 +5752,7 @@
5732
5752
  {
5733
5753
  "path": "modules/onboarding/routes/access-requests.js",
5734
5754
  "mode": "0000644",
5735
- "sha256": "41729b14813c7f9d7ed93d8e9cc272f8ec6a97c610318ac5cb0fa2ff870a74c0"
5755
+ "sha256": "ebebd2ce84727de2dff8411a6279aefb3792de51577a5ba04dc7d565cbce5494"
5736
5756
  },
5737
5757
  {
5738
5758
  "path": "modules/onboarding/routes/onboarding.js",
@@ -5872,7 +5892,7 @@
5872
5892
  {
5873
5893
  "path": "modules/platform-identity/module.json",
5874
5894
  "mode": "0000644",
5875
- "sha256": "ea0ef93145343658eb46421ebc435181fe7233c35be7bc73a7cac229f53f6c08"
5895
+ "sha256": "b798cbc2c6f4106c4eb94c9f7219ad1643bfb5ec9449e0384bf87b3f7ecccc30"
5876
5896
  },
5877
5897
  {
5878
5898
  "path": "modules/platform-identity/platform-identity.js",
@@ -5884,6 +5904,11 @@
5884
5904
  "mode": "0000644",
5885
5905
  "sha256": "b6eea95dbe66a3126fc2c73d93237cf38dd648a803e910eb88fbd5c780ccef62"
5886
5906
  },
5907
+ {
5908
+ "path": "modules/platform-identity/project-catalog.js",
5909
+ "mode": "0000644",
5910
+ "sha256": "2f83a6c37f3cabb5ef04d20f0d6e92a39218528bad214a5e61e07eb3bba1468e"
5911
+ },
5887
5912
  {
5888
5913
  "path": "modules/platform-identity/project-stats.js",
5889
5914
  "mode": "0000644",
@@ -5912,7 +5937,7 @@
5912
5937
  {
5913
5938
  "path": "modules/platform-identity/routes/my-projects.js",
5914
5939
  "mode": "0000644",
5915
- "sha256": "9f3a833a455c14ea535910ec09d86a2c5bfb5419678274cb5d6ea8d790dd7883"
5940
+ "sha256": "70148631797a5b75a033861f696bf43535f81e8d1f44284a1d935b741a0f6304"
5916
5941
  },
5917
5942
  {
5918
5943
  "path": "modules/platform-identity/routes/profile.js",
@@ -5922,7 +5947,7 @@
5922
5947
  {
5923
5948
  "path": "modules/platform-identity/routes/projects.js",
5924
5949
  "mode": "0000644",
5925
- "sha256": "ec297f39a3d7f23b05b24ea6837bb9bfd07a12f99734788e9332769c59acc7b7"
5950
+ "sha256": "f90fbe23065310a09769bc46fdb0703e460f402d5a4e0cc490eba70cf67965ea"
5926
5951
  },
5927
5952
  {
5928
5953
  "path": "modules/platform-identity/routes/public-profile.js",
@@ -5937,7 +5962,7 @@
5937
5962
  {
5938
5963
  "path": "modules/platform-identity/routes/sso.js",
5939
5964
  "mode": "0000644",
5940
- "sha256": "dc3eaa8789a28a389ddeaac88f5cd514db8bf10705f430839f0bf164fc963674"
5965
+ "sha256": "6f89a384bfe46027ac330324b933255c2d55764b53df0c06571ecfbce6b98c23"
5941
5966
  },
5942
5967
  {
5943
5968
  "path": "modules/platform-identity/scouting-authz.js",
@@ -5964,6 +5989,11 @@
5964
5989
  "mode": "0000644",
5965
5990
  "sha256": "7cb9dac9cb87b679e1ae50e4112b3a7928a38ebb9902c8947a74d17bec4d9009"
5966
5991
  },
5992
+ {
5993
+ "path": "modules/provisioning/catalog-bridge.js",
5994
+ "mode": "0000644",
5995
+ "sha256": "35a3c70ebe49b37a18044d6756d97b9caea87917a9fdbe0198fa05be25f5457a"
5996
+ },
5967
5997
  {
5968
5998
  "path": "modules/provisioning/migrations/provisioning_001_tables.sql",
5969
5999
  "mode": "0000644",
@@ -6052,7 +6082,7 @@
6052
6082
  {
6053
6083
  "path": "modules/provisioning/provisioning.js",
6054
6084
  "mode": "0000644",
6055
- "sha256": "8745258599d655b34204e5878b413308ae48a012b0306bde3297e98e452b3686"
6085
+ "sha256": "d3d376a0aafc52dda55d9d2f2dcdc3d5baf9370a766cd4328cd00b314e897c99"
6056
6086
  },
6057
6087
  {
6058
6088
  "path": "modules/provisioning/rate-limit.js",
@@ -6072,7 +6102,7 @@
6072
6102
  {
6073
6103
  "path": "modules/provisioning/routes/provisioning.js",
6074
6104
  "mode": "0000644",
6075
- "sha256": "e08199bc9146bd3122ca038637a0e390b9f5e636a102fa290dba414cf6cafdc1"
6105
+ "sha256": "3528d699cb9c0f396eeda2e9fc26eb9b89c02e0b0ca34beeb20fd84c832f5241"
6076
6106
  },
6077
6107
  {
6078
6108
  "path": "modules/provisioning/starter-bundles.js",
@@ -6087,7 +6117,7 @@
6087
6117
  {
6088
6118
  "path": "modules/provisioning/tests/provisioning.mjs",
6089
6119
  "mode": "0000644",
6090
- "sha256": "03e4ba2a5625ac321a95392c91b8e90cc6f7e235dc9a0c4bbcb742cbd459b083"
6120
+ "sha256": "4dceb82f4dbeb39128c66d666df0642aacb38988f7c6d01c55f6515bcd8ad798"
6091
6121
  },
6092
6122
  {
6093
6123
  "path": "modules/provisioning/ui/.gitkeep",
@@ -6327,7 +6357,7 @@
6327
6357
  {
6328
6358
  "path": "modules/public-landing/public/assets/cosmos.css",
6329
6359
  "mode": "0000644",
6330
- "sha256": "f10975893b3522accc6592246af0b07645c8d910c7637ecc5a006064a0988057"
6360
+ "sha256": "8da9101c633ea363802a4ac2831fe55d182308573a923bec50b4ce00e4f8254b"
6331
6361
  },
6332
6362
  {
6333
6363
  "path": "modules/public-landing/public/assets/verro-medallion.png",
@@ -6587,7 +6617,7 @@
6587
6617
  {
6588
6618
  "path": "modules/public-landing/public/projects.html",
6589
6619
  "mode": "0000644",
6590
- "sha256": "7147ff51b2eaa3487557fff35f4fc7c3e4f6164fd8054e41c76064bcfe932e08"
6620
+ "sha256": "456100c301325c4d303061a00804fa67f7dfc7d4494b15aea190641541db6531"
6591
6621
  },
6592
6622
  {
6593
6623
  "path": "modules/public-landing/public/projects.probes.json",
@@ -6597,7 +6627,7 @@
6597
6627
  {
6598
6628
  "path": "modules/public-landing/public/projects.states.json",
6599
6629
  "mode": "0000644",
6600
- "sha256": "16fbd27a36c9c32696539c74a815dc9b3f187f5b539b393e3bee7f7dabc4e2a6"
6630
+ "sha256": "2cd5e5598d59e8dbf813658c950821bbb9a34b57823bdfb3be7f61d834bf7714"
6601
6631
  },
6602
6632
  {
6603
6633
  "path": "modules/public-landing/public/terms.html",
@@ -7022,7 +7052,7 @@
7022
7052
  {
7023
7053
  "path": "modules/ui-design/kit/serve.js",
7024
7054
  "mode": "0000644",
7025
- "sha256": "4c52462cf61559e9a424107398eca58aa56b3783338827dda6110200fcdfd00a"
7055
+ "sha256": "e0d76468a01c6e76c0f106714b31bc42f6b3cb12cf2b73a5739253fab1b45b90"
7026
7056
  },
7027
7057
  {
7028
7058
  "path": "modules/ui-design/kit/tells.js",
@@ -7332,12 +7362,12 @@
7332
7362
  {
7333
7363
  "path": "package-lock.json",
7334
7364
  "mode": "0000644",
7335
- "sha256": "9f7a9f1769483872e239544ecd2a8c5900dd84cde6a846c974593acc3dc2c7b8"
7365
+ "sha256": "468fe9079df95bf33112f63df0b3e72ce952db87b121b4127156e6c615eb2bbb"
7336
7366
  },
7337
7367
  {
7338
7368
  "path": "package.json",
7339
7369
  "mode": "0000644",
7340
- "sha256": "b5ecef3b6c7a8d52cfdae026ae1fe9b805e97e7c5c6f015b668aed8e7bcef684"
7370
+ "sha256": "ac5e20798f6621e686013476b57d4034f1ce36d5562e684e7f3c6bee0747c759"
7341
7371
  },
7342
7372
  {
7343
7373
  "path": "public-docs/index.html",
@@ -7772,7 +7802,7 @@
7772
7802
  {
7773
7803
  "path": "scripts/gds/fitness.js",
7774
7804
  "mode": "0000644",
7775
- "sha256": "c6a11cbffff99b725d60dff415622ff3ade8e9c56ede14edc01828ebb80d8415"
7805
+ "sha256": "172f890f2a4297d287008f0ba11bc04fc801ea21a52728855967b178e2875373"
7776
7806
  },
7777
7807
  {
7778
7808
  "path": "scripts/gds/gate-review.js",
@@ -8092,7 +8122,7 @@
8092
8122
  {
8093
8123
  "path": "scripts/gds/provision-net.js",
8094
8124
  "mode": "0000644",
8095
- "sha256": "01b6ef89cbef4d898934c1802dec416c6085f0dde5ae49012bd2fa7a14bb9589"
8125
+ "sha256": "86c308f807a27f448a1f90f4257e74238c177b885468b95b89d379c7249366fa"
8096
8126
  },
8097
8127
  {
8098
8128
  "path": "scripts/gds/provision-repo.js",
@@ -8864,6 +8894,11 @@
8864
8894
  "mode": "0000644",
8865
8895
  "sha256": "c9edcf9cb1f027ca122388beabae488d2b771b9e7aee2cd12fbdb48ea6f0ded8"
8866
8896
  },
8897
+ {
8898
+ "path": "src/bongos/project-door.js",
8899
+ "mode": "0000644",
8900
+ "sha256": "045c0edceb0f71c3b488471ffb3a1c20c58014d0592c9ac44572245a7eb08960"
8901
+ },
8867
8902
  {
8868
8903
  "path": "src/bongos/project-settings.js",
8869
8904
  "mode": "0000644",
@@ -8997,7 +9032,7 @@
8997
9032
  {
8998
9033
  "path": "src/branding.js",
8999
9034
  "mode": "0000644",
9000
- "sha256": "e603fa0fabe63b7150f649db1ecaa50ef0908a803396e808cf212f4378cbb053"
9035
+ "sha256": "8885ee12599cdfdaf9bdb073185c83a5532bdc46d07edaeab42e36ccdc12f8e1"
9001
9036
  },
9002
9037
  {
9003
9038
  "path": "src/build-info.js",
@@ -9017,7 +9052,7 @@
9017
9052
  {
9018
9053
  "path": "src/module-api.js",
9019
9054
  "mode": "0000644",
9020
- "sha256": "dcab3a87e36bb416a45b58bacfc472980145fefeeff6049beb8a9f72aabb0884"
9055
+ "sha256": "e97c60a63ed6befae3e842e86f97cf592bb58f45cdbe488d13cb0f5e576c75b0"
9021
9056
  },
9022
9057
  {
9023
9058
  "path": "src/module-loader/catalog.js",
@@ -9072,7 +9107,7 @@
9072
9107
  {
9073
9108
  "path": "tests/access_requests_invite.mjs",
9074
9109
  "mode": "0000644",
9075
- "sha256": "4d8435e7f8b949715ee40843beddc1868105edd9c67b269cfa8f510a192e9212"
9110
+ "sha256": "7229451a9a9cb74049b7fea808458423d8a2754c213e6974593811cd1b4322b1"
9076
9111
  },
9077
9112
  {
9078
9113
  "path": "tests/account_existence_rate_limit.mjs",
@@ -9172,7 +9207,7 @@
9172
9207
  {
9173
9208
  "path": "tests/application_lifecycle.mjs",
9174
9209
  "mode": "0000644",
9175
- "sha256": "ac8128aa0834f420ee744e057cd2baa01569611052d199dba9e5d28986ff1166"
9210
+ "sha256": "249c97a172d0b77dae22dc561dc7c02dd48b636956df296647d62d7c6e213727"
9176
9211
  },
9177
9212
  {
9178
9213
  "path": "tests/architect.mjs",
@@ -9499,6 +9534,11 @@
9499
9534
  "mode": "0000644",
9500
9535
  "sha256": "de9d8f8c1daab1e48122febd16699ac519890b6e1296edb7966d835434851786"
9501
9536
  },
9537
+ {
9538
+ "path": "tests/catalog_only_client.mjs",
9539
+ "mode": "0000644",
9540
+ "sha256": "2eb721978e016514ef53cf5083dbbc5d38a2db57cd75786fdd6b6a12e5488dff"
9541
+ },
9502
9542
  {
9503
9543
  "path": "tests/category_advisory_guard.mjs",
9504
9544
  "mode": "0000644",
@@ -9722,7 +9762,7 @@
9722
9762
  {
9723
9763
  "path": "tests/currency_label.mjs",
9724
9764
  "mode": "0000644",
9725
- "sha256": "09a937b9a9550b77659c0e60b3bc44c45378fdb3545c510d7579d4711518a733"
9765
+ "sha256": "b88f7ab55948f0bfbf0e6982cc96465ff2c34d76b143f40b86f933c323b8ff1d"
9726
9766
  },
9727
9767
  {
9728
9768
  "path": "tests/cutover_codemod.mjs",
@@ -10957,7 +10997,7 @@
10957
10997
  {
10958
10998
  "path": "tests/module_api.mjs",
10959
10999
  "mode": "0000644",
10960
- "sha256": "839cbdc51d53f6719671ff1f2caa431d52a8b76636cd7973350000510510779b"
11000
+ "sha256": "c7eadd36ae57c2f8976bf30bbd4c5d6ac3db0c1a8f67319860b3e4f85b5b5bc1"
10961
11001
  },
10962
11002
  {
10963
11003
  "path": "tests/module_catalog.mjs",
@@ -11229,11 +11269,36 @@
11229
11269
  "mode": "0000644",
11230
11270
  "sha256": "6a7a223a678b56333befaed017429e5b9d8a81e4405efae72a23355902517d9d"
11231
11271
  },
11272
+ {
11273
+ "path": "tests/project_catalog_bridge.mjs",
11274
+ "mode": "0000644",
11275
+ "sha256": "f4c023348054679885b8aefb8dcb700d23f3a67316e898f02e7cb0ecda75e9ff"
11276
+ },
11277
+ {
11278
+ "path": "tests/project_catalog_routes.mjs",
11279
+ "mode": "0000644",
11280
+ "sha256": "5918d1ce7c106e5d7baa9cb989d52f3e82ac2aaf45a89f9a9bb154066106dccc"
11281
+ },
11232
11282
  {
11233
11283
  "path": "tests/project_door_ui.mjs",
11234
11284
  "mode": "0000644",
11235
11285
  "sha256": "29f59ab64b231a7ec5d17a3e784d451f75d80c19efd4cb6a523d263e8f88b581"
11236
11286
  },
11287
+ {
11288
+ "path": "tests/project_join_door.mjs",
11289
+ "mode": "0000644",
11290
+ "sha256": "c0313968f5c6b07061443cfdbb0d928ba3067fb118cdd6fcf5892788189d22f7"
11291
+ },
11292
+ {
11293
+ "path": "tests/project_join_door_route.mjs",
11294
+ "mode": "0000644",
11295
+ "sha256": "9da8c3416b4d06f82fdf8254aec216d8e7a7368b697f151f5d58f1c286f86639"
11296
+ },
11297
+ {
11298
+ "path": "tests/project_modules_ui.mjs",
11299
+ "mode": "0000644",
11300
+ "sha256": "e728a4c1d13ea3a54910d0a706522a780db138783202a09f300900b8c661ae2e"
11301
+ },
11237
11302
  {
11238
11303
  "path": "tests/project_stats.mjs",
11239
11304
  "mode": "0000644",
@@ -11247,17 +11312,17 @@
11247
11312
  {
11248
11313
  "path": "tests/projects_hub.mjs",
11249
11314
  "mode": "0000644",
11250
- "sha256": "f8e557372a86d42dc0433414a1d5821a350dc545056fcc8104aa151b51e939f7"
11315
+ "sha256": "2ef099cea46b1ffa0841d1845dedf00de047de4f9c6844baaabdcd317a5eebac"
11251
11316
  },
11252
11317
  {
11253
11318
  "path": "tests/projects_hub_module_picker.mjs",
11254
11319
  "mode": "0000644",
11255
- "sha256": "55b7912d1985ea1e02874b479c9d0453c25df48bfad6287ba9402df50326d6ed"
11320
+ "sha256": "44981254fda6a07522d650210127fae6d65ed4d06e539f8a555c860c74de8c64"
11256
11321
  },
11257
11322
  {
11258
11323
  "path": "tests/projects_hub_pre_uat.mjs",
11259
11324
  "mode": "0000644",
11260
- "sha256": "fef872ed80c7efdbf37e0672067f555c76aa17368a515afb99b1fa7e7ca3c4b4"
11325
+ "sha256": "294ecd72fa9e1c67cba9c2411c57447e459426682586c099adcd93b606530def"
11261
11326
  },
11262
11327
  {
11263
11328
  "path": "tests/promote_goal_id.mjs",
@@ -11282,7 +11347,7 @@
11282
11347
  {
11283
11348
  "path": "tests/provision_settings_apply.mjs",
11284
11349
  "mode": "0000644",
11285
- "sha256": "9a04386b3047177bb55b6d392db88764f06f92e5c0b20c16ed9e0f8ce520b07d"
11350
+ "sha256": "9a09eb9bd47ff36a991b7208d0bada1fb91e3f8f03fe36a3ac4b5549b56b48ca"
11286
11351
  },
11287
11352
  {
11288
11353
  "path": "tests/provisioning_callback_page.mjs",
@@ -11307,7 +11372,7 @@
11307
11372
  {
11308
11373
  "path": "tests/provisioning_module_selection.mjs",
11309
11374
  "mode": "0000644",
11310
- "sha256": "4a27e1641d949f261a8ba1b72816a8b077fc8a55862c4eef4091b453b7cfd45c"
11375
+ "sha256": "a8cb68c1f21a7c6547ef382b4641b80c1c9e46a2aad415f75dbfde36224079fd"
11311
11376
  },
11312
11377
  {
11313
11378
  "path": "tests/provisioning_onboard_mode.mjs",
@@ -11327,17 +11392,17 @@
11327
11392
  {
11328
11393
  "path": "tests/provisioning_settings.mjs",
11329
11394
  "mode": "0000644",
11330
- "sha256": "6f78a45d0c68a0da780d40c602f23bca3d48a80524218d4d7d311b2f8574dbee"
11395
+ "sha256": "a7ec1145f695ed066c322bbd88f5f1dd3f3b47620ca4314e57860876a7394fe7"
11331
11396
  },
11332
11397
  {
11333
11398
  "path": "tests/provisioning_settings_apply.mjs",
11334
11399
  "mode": "0000644",
11335
- "sha256": "c453bab3768953257be481cb8df700530f964e167fdca073cf4ae69892930a79"
11400
+ "sha256": "7fc80fc5576aba1dd10c0416899ade5fa2c9380ea8c1a995aaa99745aa56c29c"
11336
11401
  },
11337
11402
  {
11338
11403
  "path": "tests/provisioning_settings_env.mjs",
11339
11404
  "mode": "0000644",
11340
- "sha256": "4f51ea07fe3d80d52d6998547b028bec0a97267210faeffd75d9a47f7b5643e8"
11405
+ "sha256": "a941c67c8b5640bdbacc0b5078fadacc79d1332befeb40bc3ebe82cd36764552"
11341
11406
  },
11342
11407
  {
11343
11408
  "path": "tests/provisioning_slug_available.mjs",
@@ -171,7 +171,7 @@ export interface PatchMeSkillPrefsResponse { prefs: unknown; effective: unknown;
171
171
  export interface PatchMeSoundPrefsResponse { prefs: unknown; effective: unknown; effective_map: unknown; volume: unknown; defaults: unknown; known_sounds: unknown }
172
172
  export interface PatchProjectsIdFeaturedRequest { featured: boolean }
173
173
  export interface PatchProjectsIdFeaturedResponse { project: unknown }
174
- export interface PatchProvisioningInstancesIdDetailRequest { description?: string; detail?: Record<string, unknown> }
174
+ export interface PatchProvisioningInstancesIdDetailRequest { description?: string; detail?: Record<string, unknown>; modules?: string[] }
175
175
  export interface PatchProvisioningInstancesIdDetailResponse { ok: boolean; description: unknown; detail: unknown; options: unknown; publish: unknown; modules: unknown }
176
176
  export interface PatchProvisioningInstancesIdSettingsResponse { ok: boolean; saved: unknown; planet: unknown; push: unknown }
177
177
  export interface PatchTaskRecommendationsIdRequest { status: "declined" | "withdrawn" }
@@ -27,10 +27,11 @@
27
27
  "idp": false
28
28
  },
29
29
  "project": {
30
- "_note": "Per-project policy the PLATFORM decides and this instance OBEYS (task 1003139, goal 1000058). Stored on the platform's provisioning_instances.settings; written here as <PREFIX>_PLATFORM_VISIBILITY / <PREFIX>_JOINABILITY / <PREFIX>_VISIBILITY by the provisioning runner, which re-writes web.env and restarts the service when the owner changes one. The defaults are TODAY's behavior, so an instance that never receives a push — a self-hosted one, or one provisioned before this channel — keeps behaving exactly as it does now. platformVisibility (who may READ this instance's own pages): public | gated. joinability (HOW someone becomes a member): open | apply | invite_only. visibility (the join door, ADR 0182 D1 — how this project stands on the platform's map): public | private | stealth; it does NOT decide whether the project is on the map, publishability does.",
30
+ "_note": "Per-project policy the PLATFORM decides and this instance OBEYS (task 1003139, goal 1000058). Stored on the platform's provisioning_instances.settings; written here as <PREFIX>_PLATFORM_VISIBILITY / <PREFIX>_JOINABILITY / <PREFIX>_VISIBILITY by the provisioning runner, which re-writes web.env and restarts the service when the owner changes one. The defaults are TODAY's behavior, so an instance that never receives a push — a self-hosted one, or one provisioned before this channel — keeps behaving exactly as it does now. platformVisibility (who may READ this instance's own pages): public | gated. joinability (HOW someone becomes a member): open | apply | invite_only. visibility (the join door, ADR 0182 D1 — how this project stands on the platform's map): public | private | stealth; it does NOT decide whether the project is on the map, publishability does. joinGrant (what a PUBLIC join GRANTS): view | apply | full — the ceiling joinability may only narrow (ADR 0182 D6 / ADR 0245); `full` narrows nothing, which is why it is the default.",
31
31
  "platformVisibility": "public",
32
32
  "joinability": "apply",
33
- "visibility": "public"
33
+ "visibility": "public",
34
+ "joinGrant": "full"
34
35
  },
35
36
  "repo": {
36
37
  "owner": "",
@@ -0,0 +1,116 @@
1
+ # 0244 — A catalog search is a view over the rows, never an edit to the selection
2
+
3
+ - **Status:** Accepted
4
+ - **Date:** 2026-09-04
5
+ - **Tasks:** [#1002340](https://cloudbongos.com/builders#/task/1002340) (this decision — BV1.R21)
6
+ - **Goal:** [#1000046](https://cloudbongos.com/builders#/goal/1000046) — Project creation, criterion
7
+ `proj-module-select` ("during setup a default set of modules is pre-selected…")
8
+ - **Related:** [ADR 0237](<redacted>.md)
9
+ (R19 — the per-type presets, and the file that already said "R21 searches the catalog"),
10
+ [ADR 0240](<redacted>.md)
11
+ (R20 — the picker, and the three-valued `modules` column whose `null` this must not disturb),
12
+ [ADR 0243](<redacted>.md)
13
+ (R22 — the tailored preselect the search now filters)
14
+
15
+ ## 1. The problem
16
+
17
+ The picker paints one row per optional module. The catalog is three rows today
18
+ and is meant to grow — the module system's whole point is that an instance adds
19
+ modules — so R21 asks for a keyword search over it.
20
+
21
+ A search over a list of *links* is trivial. A search over a list of **toggles**
22
+ is not, because the list is also an answer. Two things can go wrong the moment a
23
+ row can be hidden:
24
+
25
+ 1. **The filter edits the answer.** The natural implementation of "show only the
26
+ matching rows" is to narrow the array the panel renders *and* the array it
27
+ reads back — at which point typing `discord` and pressing Next files a project
28
+ with one module instead of three. The bug is silent: every screen looks right.
29
+ 2. **The filter lies about the answer.** Even a filter that only narrows the
30
+ *render* leaves a switched-on module off screen. The owner sees one row, sees
31
+ it unticked, and reasonably concludes nothing else is on. ADR 0237's standard
32
+ for the preselect — "a preselect an owner cannot see the reason for is one
33
+ they have to audit" — applies here in its harsher form: a preselect they
34
+ cannot **see at all** is one they cannot audit.
35
+
36
+ ## 2. Decision
37
+
38
+ **The search is a view. `state.modules` is the answer. The view may not write to
39
+ it.**
40
+
41
+ Concretely, in `modules/public-landing/public/projects.html`'s picker block:
42
+
43
+ - `moduleQuery` is a plain variable that holds what is typed. It is **not** part
44
+ of the draft — `saveDraft()` is never called from the input handler — so a
45
+ resumed draft never comes back mid-search, and a search can never be the thing
46
+ that turns an untouched picker into an answered one (ADR 0240's `null`).
47
+ - `visibleModules()` derives, per render, the rows the current query leaves.
48
+ `pickedModules()`, `modulesForCreate()` and `extrasRow()` are untouched and
49
+ keep reading the whole catalog, so what rides the create request and what the
50
+ review names are both independent of what is on screen.
51
+ - **The panel states the part the filter is hiding.** One line under the field:
52
+ `Showing 1 of 3. 2 extras are switched on, including any this search is
53
+ hiding.` It is silent with an empty query, and it counts what is *on*, not what
54
+ is *visible* — which is the whole point of it existing.
55
+ - An empty query is not a search: every row shows, and the line goes quiet. So
56
+ does a query of nothing but spaces.
57
+
58
+ ## 3. What "matching" means, and what it deliberately does not
59
+
60
+ `moduleMatches(mod, terms)` is a pure function over one catalog row:
61
+
62
+ > lower-case the row's **label + summary + key** into one haystack; every
63
+ > whitespace-separated term must appear in it as a **substring**.
64
+
65
+ - **AND across terms.** An owner adding a word is saying the list is still too
66
+ long; OR would grow it, which is the opposite of what they asked for.
67
+ - **Substring, not word-boundary.** A half-typed word must still find its module,
68
+ because the field filters on every keystroke and a filter that shows nothing
69
+ until you finish typing reads as a broken one.
70
+ - **The key is searchable even though it is never shown.** It costs nothing and
71
+ it is what a returning owner (or a support answer, or our own docs) actually
72
+ names a module by.
73
+ - **No ranking, no fuzziness, no synonyms.** The catalog is small enough that
74
+ order is the catalog's order, and a rank that reorders toggles under a typing
75
+ hand is a worse experience than a filter that does not.
76
+ - **Not semantic.** "Somewhere for people to chat" finds nothing, and that is the
77
+ scope line: search by meaning is deferred to idea 1000552 with the rest of the
78
+ AI layer for project creation. A lexical filter that admits it is lexical is
79
+ honest; one that half-guesses is not.
80
+
81
+ The whole matcher is a named function on the page precisely so the vm harness in
82
+ `tests/projects_hub_module_picker.mjs` can run it directly — the same reason
83
+ `bundleForAnswers` is a function and not an inline expression.
84
+
85
+ ## 4. Consequences
86
+
87
+ - The picker scales past the point where the band is scannable, with no server
88
+ work: the catalog already arrives whole in the one `GET
89
+ /provisioning/starter-bundles` read (ADR 0237), so typing costs no round trip
90
+ and adds no failure mode.
91
+ - BV1.R24's proof path — *create → bundle preselected → search + add → enabled* —
92
+ works because a toggle made while filtered still re-derives the answer in
93
+ **catalog order**, exactly as an unfiltered toggle does.
94
+ - When the catalog fails to load the field is hidden rather than disabled: a
95
+ search box over a list that is not there can only disappoint.
96
+ - A future by-meaning search replaces `moduleMatches` and nothing else. The
97
+ view/answer split is what makes that swap safe.
98
+
99
+ ## 5. Alternatives considered
100
+
101
+ - **Filtering the array the panel reads back** (the "obvious" implementation) —
102
+ rejected: it makes the search an editor of the answer, which is failure mode 1
103
+ above, and it is silent.
104
+ - **Hiding matched-out rows with CSS instead of not rendering them** — same
105
+ outcome for the owner, but it puts `aria-pressed` toggles in the accessibility
106
+ tree that a sighted owner cannot see, and the empty-result case still needs its
107
+ own line. Rendering fewer rows is the simpler truth.
108
+ - **Keeping switched-on rows pinned at the top regardless of the query** — it
109
+ makes the count line unnecessary, but it means a search sometimes shows rows
110
+ that do not match, which is a filter that lies in the other direction. The
111
+ count says the same thing without breaking the band's one rule.
112
+ - **Persisting the query in the draft** — a search is a way of looking, not a
113
+ decision. Restoring one on a resumed draft would hide most of the catalog from
114
+ an owner who did not ask for that.
115
+ - **Debouncing the input** — the filter is a pass over three-to-a-few-dozen rows
116
+ of already-loaded data. A delay would only make the field feel slower.