@bongos/core 1.19.429 → 1.19.431
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.bongos-core.json +71 -51
- package/clients/bongos-client/README.md +1 -1
- package/clients/bongos-client/bongos-client.global.js +2 -0
- package/clients/bongos-client/index.cjs +2 -0
- package/clients/bongos-client/index.d.ts +6 -3
- package/clients/bongos-client/index.mjs +2 -0
- package/docs/adr/0215-the-recruiter-sliver-is-a-ceiling-not-a-step.md +116 -0
- package/docs/adr/README.md +1 -0
- package/docs/api/openapi.json +74 -3
- package/docs/api-reference.md +4 -3
- package/docs/copy-inventory.md +162 -154
- package/docs/copy-registry.json +271 -198
- package/docs/design/mocks/hub/picker.html +421 -0
- package/docs/design/projects-hub-direction-v2.md +22 -0
- package/docs/file-map.md +1 -0
- package/docs/module-api-changelog.md +4 -0
- package/modules/dev-box/app/src/vendor/bongos-client.cjs +2 -0
- package/modules/hall-ui/public/settings.html +1 -1
- package/modules/hall-ui/public/settings.js +17 -8
- package/modules/platform-identity/account-visibility.js +47 -0
- package/modules/platform-identity/platform-identity.js +4 -4
- package/modules/platform-identity/recruiter-sliver.js +197 -0
- package/modules/platform-identity/routes/projects.js +24 -0
- package/modules/platform-identity/routes/scouting.js +58 -0
- package/modules/provisioning/module.json +1 -1
- package/modules/provisioning/provisioning.js +63 -2
- package/modules/provisioning/routes/provisioning.js +28 -6
- package/modules/provisioning/tests/provisioning.mjs +34 -0
- package/modules/ui-design/kit/fixtures/featured-hub.json +1 -1
- package/modules/ui-design/kit/fixtures/featured.json +1 -1
- package/modules/ui-design/kit/fixtures/provisioning-instances.json +1 -1
- package/modules/ui-design/kit/serve.js +28 -4
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/public-landing/assets/cosmos.css +37 -0
- package/public-landing/projects.html +164 -5
- package/public-landing/projects.probes.json +12 -0
- package/public-landing/projects.states.json +3 -2
- package/src/module-api.js +1 -1
- package/tests/account_privacy_flags.mjs +115 -9
- package/tests/effective_visibility_predicate.mjs +58 -1
- package/tests/government_require_permission.mjs +22 -0
- package/tests/profile_route.mjs +6 -0
- package/tests/projects_hub.mjs +122 -7
- package/tests/provisioning_settings.mjs +81 -2
- package/tests/provisioning_settings_env.mjs +6 -0
- package/tests/recruiter_sliver_boundary.mjs +841 -0
- package/tests/scouting_owner_access_and_reach.mjs +4 -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.
|
|
6
|
-
"core_contract": "1.19.
|
|
7
|
-
"source_commit": "
|
|
5
|
+
"core_version": "1.19.431",
|
|
6
|
+
"core_contract": "1.19.431",
|
|
7
|
+
"source_commit": "4fd9f0748403564b999e3e0459d44c169c751d4b",
|
|
8
8
|
"source_ref": "HEAD",
|
|
9
|
-
"built_at": "2026-08-
|
|
9
|
+
"built_at": "2026-08-29T21:48:51.014Z",
|
|
10
10
|
"redaction": {
|
|
11
11
|
"model": "docs-redacted+functional-verbatim",
|
|
12
|
-
"docs_redacted":
|
|
12
|
+
"docs_redacted": 365,
|
|
13
13
|
"agent_docs_stubbed": 23,
|
|
14
|
-
"functional_verbatim":
|
|
14
|
+
"functional_verbatim": 1740,
|
|
15
15
|
"rules": 3,
|
|
16
16
|
"gate_literals": 3,
|
|
17
17
|
"gate": "passed"
|
|
18
18
|
},
|
|
19
|
-
"file_count":
|
|
20
|
-
"tree_sha256": "
|
|
19
|
+
"file_count": 2128,
|
|
20
|
+
"tree_sha256": "bc4e3ea3fba769c809456cccf0abb0abcc8d513d047083307f7431afbc38f780",
|
|
21
21
|
"files": [
|
|
22
22
|
{
|
|
23
23
|
"path": ".claude/skills/blocker-review/SKILL.md",
|
|
@@ -352,12 +352,12 @@
|
|
|
352
352
|
{
|
|
353
353
|
"path": "clients/bongos-client/README.md",
|
|
354
354
|
"mode": "0000644",
|
|
355
|
-
"sha256": "
|
|
355
|
+
"sha256": "6ad13168a2196e29e37c2810108686b3c24f30f739691634f9085ebfcd1fc804"
|
|
356
356
|
},
|
|
357
357
|
{
|
|
358
358
|
"path": "clients/bongos-client/bongos-client.global.js",
|
|
359
359
|
"mode": "0000644",
|
|
360
|
-
"sha256": "
|
|
360
|
+
"sha256": "dfaca6bbdd87f2d32b1684bbddd7bb4454367ccf1624a9bd5b38b571dd3708db"
|
|
361
361
|
},
|
|
362
362
|
{
|
|
363
363
|
"path": "clients/bongos-client/examples/hello-world.mjs",
|
|
@@ -367,17 +367,17 @@
|
|
|
367
367
|
{
|
|
368
368
|
"path": "clients/bongos-client/index.cjs",
|
|
369
369
|
"mode": "0000644",
|
|
370
|
-
"sha256": "
|
|
370
|
+
"sha256": "92bcaf81301220166e1126d65492ecc011b3b2fac94e594bf22f8049aa45aece"
|
|
371
371
|
},
|
|
372
372
|
{
|
|
373
373
|
"path": "clients/bongos-client/index.d.ts",
|
|
374
374
|
"mode": "0000644",
|
|
375
|
-
"sha256": "
|
|
375
|
+
"sha256": "3ab2c5433e9a59032143ad2bc90dd9e4bad51ccaa9a2029034f0e53d199472ce"
|
|
376
376
|
},
|
|
377
377
|
{
|
|
378
378
|
"path": "clients/bongos-client/index.mjs",
|
|
379
379
|
"mode": "0000644",
|
|
380
|
-
"sha256": "
|
|
380
|
+
"sha256": "cf02ec862ca9fcf7700ed2566c2e148c83c763d9194a450a09cb3d191ad4c90b"
|
|
381
381
|
},
|
|
382
382
|
{
|
|
383
383
|
"path": "clients/bongos-client/package.json",
|
|
@@ -1569,20 +1569,25 @@
|
|
|
1569
1569
|
"mode": "0000644",
|
|
1570
1570
|
"sha256": "b964e1674d615cb4525e94bb4cac63d4ac0813e3c1ea9236620bf030d7c53124"
|
|
1571
1571
|
},
|
|
1572
|
+
{
|
|
1573
|
+
"path": "docs/adr/0215-the-recruiter-sliver-is-a-ceiling-not-a-step.md",
|
|
1574
|
+
"mode": "0000644",
|
|
1575
|
+
"sha256": "8c248b7e041f21da26ef55cb79c8bcaf20713d3e271ea7ee0de851d452c19e58"
|
|
1576
|
+
},
|
|
1572
1577
|
{
|
|
1573
1578
|
"path": "docs/adr/README.md",
|
|
1574
1579
|
"mode": "0000644",
|
|
1575
|
-
"sha256": "
|
|
1580
|
+
"sha256": "5cf8b81ec623dd3614683c2114c1fee38ddc5c3a1bf73e2c69ac4fe8ef79ff25"
|
|
1576
1581
|
},
|
|
1577
1582
|
{
|
|
1578
1583
|
"path": "docs/api-reference.md",
|
|
1579
1584
|
"mode": "0000644",
|
|
1580
|
-
"sha256": "
|
|
1585
|
+
"sha256": "c20be8f4ab3d66c348c6c2d4d4f45c3390a4078899459831fc4851d51a740ea2"
|
|
1581
1586
|
},
|
|
1582
1587
|
{
|
|
1583
1588
|
"path": "docs/api/openapi.json",
|
|
1584
1589
|
"mode": "0000644",
|
|
1585
|
-
"sha256": "
|
|
1590
|
+
"sha256": "8998dc287e00a54bfd206d427a923700874dc34db5a459671f8c90d8b6ec117c"
|
|
1586
1591
|
},
|
|
1587
1592
|
{
|
|
1588
1593
|
"path": "docs/architecture.md",
|
|
@@ -1607,12 +1612,12 @@
|
|
|
1607
1612
|
{
|
|
1608
1613
|
"path": "docs/copy-inventory.md",
|
|
1609
1614
|
"mode": "0000644",
|
|
1610
|
-
"sha256": "
|
|
1615
|
+
"sha256": "cd0071623f3a81620e356ad59ff90d68ab4f5a5630dff9399856bfd8ab0de508"
|
|
1611
1616
|
},
|
|
1612
1617
|
{
|
|
1613
1618
|
"path": "docs/copy-registry.json",
|
|
1614
1619
|
"mode": "0000644",
|
|
1615
|
-
"sha256": "
|
|
1620
|
+
"sha256": "c4ebb37c87a7416aa4005812702980a084f39f69fe336d3676baf3dc8f0e6530"
|
|
1616
1621
|
},
|
|
1617
1622
|
{
|
|
1618
1623
|
"path": "docs/design/apex-pass-2-direction.md",
|
|
@@ -1704,6 +1709,11 @@
|
|
|
1704
1709
|
"mode": "0000644",
|
|
1705
1710
|
"sha256": "5de484be1af673bdb91eaf9b9221f8dbca9a47f0c8dad098a0898cd10721b497"
|
|
1706
1711
|
},
|
|
1712
|
+
{
|
|
1713
|
+
"path": "docs/design/mocks/hub/picker.html",
|
|
1714
|
+
"mode": "0000644",
|
|
1715
|
+
"sha256": "357fedc874862a929590b7f7fb3177770ce0ad77f3683813b5e816181b67e88b"
|
|
1716
|
+
},
|
|
1707
1717
|
{
|
|
1708
1718
|
"path": "docs/design/mocks/hub/planets.html",
|
|
1709
1719
|
"mode": "0000644",
|
|
@@ -1907,7 +1917,7 @@
|
|
|
1907
1917
|
{
|
|
1908
1918
|
"path": "docs/design/projects-hub-direction-v2.md",
|
|
1909
1919
|
"mode": "0000644",
|
|
1910
|
-
"sha256": "
|
|
1920
|
+
"sha256": "b72f9c3989e6c66e275124b43ad0d36aa718bd2d670696d0053cb2e0653c0632"
|
|
1911
1921
|
},
|
|
1912
1922
|
{
|
|
1913
1923
|
"path": "docs/design/projects-hub-direction.md",
|
|
@@ -1957,7 +1967,7 @@
|
|
|
1957
1967
|
{
|
|
1958
1968
|
"path": "docs/file-map.md",
|
|
1959
1969
|
"mode": "0000644",
|
|
1960
|
-
"sha256": "
|
|
1970
|
+
"sha256": "b0b9355c79b2f1caa965baf8afd645140d341f30a56483a3724697611e20322a"
|
|
1961
1971
|
},
|
|
1962
1972
|
{
|
|
1963
1973
|
"path": "docs/handoff-template.md",
|
|
@@ -1967,7 +1977,7 @@
|
|
|
1967
1977
|
{
|
|
1968
1978
|
"path": "docs/module-api-changelog.md",
|
|
1969
1979
|
"mode": "0000644",
|
|
1970
|
-
"sha256": "
|
|
1980
|
+
"sha256": "bd4bbd81fbdd0cbffbcc882bb8bd876caf4aacc863a0e4ae3b331ee8133053e6"
|
|
1971
1981
|
},
|
|
1972
1982
|
{
|
|
1973
1983
|
"path": "docs/modules-contract.md",
|
|
@@ -3282,7 +3292,7 @@
|
|
|
3282
3292
|
{
|
|
3283
3293
|
"path": "modules/dev-box/app/src/vendor/bongos-client.cjs",
|
|
3284
3294
|
"mode": "0000644",
|
|
3285
|
-
"sha256": "
|
|
3295
|
+
"sha256": "92bcaf81301220166e1126d65492ecc011b3b2fac94e594bf22f8049aa45aece"
|
|
3286
3296
|
},
|
|
3287
3297
|
{
|
|
3288
3298
|
"path": "modules/dev-box/app/test/unit.mjs",
|
|
@@ -4222,12 +4232,12 @@
|
|
|
4222
4232
|
{
|
|
4223
4233
|
"path": "modules/hall-ui/public/settings.html",
|
|
4224
4234
|
"mode": "0000644",
|
|
4225
|
-
"sha256": "
|
|
4235
|
+
"sha256": "3760dd190ea83370de2d45f74b152f8bd24abe2a8761d5bb681d26600fdbd29e"
|
|
4226
4236
|
},
|
|
4227
4237
|
{
|
|
4228
4238
|
"path": "modules/hall-ui/public/settings.js",
|
|
4229
4239
|
"mode": "0000644",
|
|
4230
|
-
"sha256": "
|
|
4240
|
+
"sha256": "3d5881896057de05daba30382b7ebf5aeb9f61cba55aae75916594ed3dc1a80f"
|
|
4231
4241
|
},
|
|
4232
4242
|
{
|
|
4233
4243
|
"path": "modules/hall-ui/public/shell.js",
|
|
@@ -4827,7 +4837,7 @@
|
|
|
4827
4837
|
{
|
|
4828
4838
|
"path": "modules/platform-identity/account-visibility.js",
|
|
4829
4839
|
"mode": "0000644",
|
|
4830
|
-
"sha256": "
|
|
4840
|
+
"sha256": "020279ae50f2f9e7a004fe571e5ca14493ad26bd22c395cc4805f759f5560b72"
|
|
4831
4841
|
},
|
|
4832
4842
|
{
|
|
4833
4843
|
"path": "modules/platform-identity/application-echo.js",
|
|
@@ -4957,7 +4967,7 @@
|
|
|
4957
4967
|
{
|
|
4958
4968
|
"path": "modules/platform-identity/platform-identity.js",
|
|
4959
4969
|
"mode": "0000644",
|
|
4960
|
-
"sha256": "
|
|
4970
|
+
"sha256": "1542edccc61a1cdb77540f5b6521a91477234af03cdde9178a1ed5516363e1fd"
|
|
4961
4971
|
},
|
|
4962
4972
|
{
|
|
4963
4973
|
"path": "modules/platform-identity/pollers/code-sweep.js",
|
|
@@ -4969,6 +4979,11 @@
|
|
|
4969
4979
|
"mode": "0000644",
|
|
4970
4980
|
"sha256": "2e898799632a2b5c2ead9cb44fa0b8029fcb6d217f7d5f26c8a39b34c75bbea7"
|
|
4971
4981
|
},
|
|
4982
|
+
{
|
|
4983
|
+
"path": "modules/platform-identity/recruiter-sliver.js",
|
|
4984
|
+
"mode": "0000644",
|
|
4985
|
+
"sha256": "e1385b83ac5bb82d13ffbe5070043c2fd0ca20385b3d62e8331ef917d9fca496"
|
|
4986
|
+
},
|
|
4972
4987
|
{
|
|
4973
4988
|
"path": "modules/platform-identity/routes/connections.js",
|
|
4974
4989
|
"mode": "0000644",
|
|
@@ -4987,7 +5002,7 @@
|
|
|
4987
5002
|
{
|
|
4988
5003
|
"path": "modules/platform-identity/routes/projects.js",
|
|
4989
5004
|
"mode": "0000644",
|
|
4990
|
-
"sha256": "
|
|
5005
|
+
"sha256": "7620a816ab376f77be6e46c8fe99c355ba323727fe7a6b2bfbf55b8b953626f3"
|
|
4991
5006
|
},
|
|
4992
5007
|
{
|
|
4993
5008
|
"path": "modules/platform-identity/routes/public-profile.js",
|
|
@@ -4997,7 +5012,7 @@
|
|
|
4997
5012
|
{
|
|
4998
5013
|
"path": "modules/platform-identity/routes/scouting.js",
|
|
4999
5014
|
"mode": "0000644",
|
|
5000
|
-
"sha256": "
|
|
5015
|
+
"sha256": "0f898c038abc6c0aceb2f5649008cdc7fc66bc1b7f83129aae3da65f1eb33c15"
|
|
5001
5016
|
},
|
|
5002
5017
|
{
|
|
5003
5018
|
"path": "modules/platform-identity/routes/sso.js",
|
|
@@ -5097,7 +5112,7 @@
|
|
|
5097
5112
|
{
|
|
5098
5113
|
"path": "modules/provisioning/module.json",
|
|
5099
5114
|
"mode": "0000644",
|
|
5100
|
-
"sha256": "
|
|
5115
|
+
"sha256": "26a6d752e610ac46f8306aa707f0229bf83ec9b0cb6c128ec723b7cc55b2b977"
|
|
5101
5116
|
},
|
|
5102
5117
|
{
|
|
5103
5118
|
"path": "modules/provisioning/onboard-plan.js",
|
|
@@ -5112,7 +5127,7 @@
|
|
|
5112
5127
|
{
|
|
5113
5128
|
"path": "modules/provisioning/provisioning.js",
|
|
5114
5129
|
"mode": "0000644",
|
|
5115
|
-
"sha256": "
|
|
5130
|
+
"sha256": "114210686cfe2f287d4d29ee603a443b2794e2065709ff60d2cd2c7530c60cad"
|
|
5116
5131
|
},
|
|
5117
5132
|
{
|
|
5118
5133
|
"path": "modules/provisioning/rate-limit.js",
|
|
@@ -5122,7 +5137,7 @@
|
|
|
5122
5137
|
{
|
|
5123
5138
|
"path": "modules/provisioning/routes/provisioning.js",
|
|
5124
5139
|
"mode": "0000644",
|
|
5125
|
-
"sha256": "
|
|
5140
|
+
"sha256": "f3ee76de08591eb957c1e533f8b96d4cb9c716eb5f89ceda1875b97d84bd2246"
|
|
5126
5141
|
},
|
|
5127
5142
|
{
|
|
5128
5143
|
"path": "modules/provisioning/tests/liveness.mjs",
|
|
@@ -5132,7 +5147,7 @@
|
|
|
5132
5147
|
{
|
|
5133
5148
|
"path": "modules/provisioning/tests/provisioning.mjs",
|
|
5134
5149
|
"mode": "0000644",
|
|
5135
|
-
"sha256": "
|
|
5150
|
+
"sha256": "559ae0d8025693a997a16012758236dbe895f28621de1a1a591d2a43fb21ff00"
|
|
5136
5151
|
},
|
|
5137
5152
|
{
|
|
5138
5153
|
"path": "modules/provisioning/ui/.gitkeep",
|
|
@@ -5462,12 +5477,12 @@
|
|
|
5462
5477
|
{
|
|
5463
5478
|
"path": "modules/ui-design/kit/fixtures/featured-hub.json",
|
|
5464
5479
|
"mode": "0000644",
|
|
5465
|
-
"sha256": "
|
|
5480
|
+
"sha256": "1c3ca6573b3e7b08269ca885bfcb79cb27bb623501066cace9e2575fefff9e1b"
|
|
5466
5481
|
},
|
|
5467
5482
|
{
|
|
5468
5483
|
"path": "modules/ui-design/kit/fixtures/featured.json",
|
|
5469
5484
|
"mode": "0000644",
|
|
5470
|
-
"sha256": "
|
|
5485
|
+
"sha256": "569038c7cbe3a1ff12d361111d062715f38aebd73317816a87c400fa96c12b04"
|
|
5471
5486
|
},
|
|
5472
5487
|
{
|
|
5473
5488
|
"path": "modules/ui-design/kit/fixtures/leaderboard.json",
|
|
@@ -5497,7 +5512,7 @@
|
|
|
5497
5512
|
{
|
|
5498
5513
|
"path": "modules/ui-design/kit/fixtures/provisioning-instances.json",
|
|
5499
5514
|
"mode": "0000644",
|
|
5500
|
-
"sha256": "
|
|
5515
|
+
"sha256": "35db35629d80420c5d816dff040934d69f5713dcf5ffbae2211d12172904dd8e"
|
|
5501
5516
|
},
|
|
5502
5517
|
{
|
|
5503
5518
|
"path": "modules/ui-design/kit/fixtures/recent-shipped.json",
|
|
@@ -5527,7 +5542,7 @@
|
|
|
5527
5542
|
{
|
|
5528
5543
|
"path": "modules/ui-design/kit/serve.js",
|
|
5529
5544
|
"mode": "0000644",
|
|
5530
|
-
"sha256": "
|
|
5545
|
+
"sha256": "f42b175e75905d1fdd854bd13a76899e7ee83e9d0b8683325fff138eee78b07c"
|
|
5531
5546
|
},
|
|
5532
5547
|
{
|
|
5533
5548
|
"path": "modules/ui-design/module.json",
|
|
@@ -5572,12 +5587,12 @@
|
|
|
5572
5587
|
{
|
|
5573
5588
|
"path": "package-lock.json",
|
|
5574
5589
|
"mode": "0000644",
|
|
5575
|
-
"sha256": "
|
|
5590
|
+
"sha256": "bf42d45381a85e4f5794f08f0deaf9e7baee6787599cbb0f034153c03e06affb"
|
|
5576
5591
|
},
|
|
5577
5592
|
{
|
|
5578
5593
|
"path": "package.json",
|
|
5579
5594
|
"mode": "0000644",
|
|
5580
|
-
"sha256": "
|
|
5595
|
+
"sha256": "b2c2d95bd1b8ef2a9d5c6dfa42362827ddf2e50beddbc8765460885ecabd4cf5"
|
|
5581
5596
|
},
|
|
5582
5597
|
{
|
|
5583
5598
|
"path": "public-docs/index.html",
|
|
@@ -5817,7 +5832,7 @@
|
|
|
5817
5832
|
{
|
|
5818
5833
|
"path": "public-landing/assets/cosmos.css",
|
|
5819
5834
|
"mode": "0000644",
|
|
5820
|
-
"sha256": "
|
|
5835
|
+
"sha256": "761b196a29b7d25d0ff1b2480e9462fd01ea2a4c57d889cd1689c6f4fbe9ca4d"
|
|
5821
5836
|
},
|
|
5822
5837
|
{
|
|
5823
5838
|
"path": "public-landing/assets/verro-medallion.png",
|
|
@@ -6037,17 +6052,17 @@
|
|
|
6037
6052
|
{
|
|
6038
6053
|
"path": "public-landing/projects.html",
|
|
6039
6054
|
"mode": "0000644",
|
|
6040
|
-
"sha256": "
|
|
6055
|
+
"sha256": "5cdf9caf7e376f89d0092f289cf8430211e3f1ac3bbbfdb1f0e516babc970851"
|
|
6041
6056
|
},
|
|
6042
6057
|
{
|
|
6043
6058
|
"path": "public-landing/projects.probes.json",
|
|
6044
6059
|
"mode": "0000644",
|
|
6045
|
-
"sha256": "
|
|
6060
|
+
"sha256": "3bc7cea614031e2c04246274adc8375b5f54d0a043e1bf4da0a564a10964db82"
|
|
6046
6061
|
},
|
|
6047
6062
|
{
|
|
6048
6063
|
"path": "public-landing/projects.states.json",
|
|
6049
6064
|
"mode": "0000644",
|
|
6050
|
-
"sha256": "
|
|
6065
|
+
"sha256": "3217f46d975bd4bed7c17ee6d87b5150e81130f75a780371cb4cffb558a07373"
|
|
6051
6066
|
},
|
|
6052
6067
|
{
|
|
6053
6068
|
"path": "public-landing/terms.html",
|
|
@@ -7707,7 +7722,7 @@
|
|
|
7707
7722
|
{
|
|
7708
7723
|
"path": "src/module-api.js",
|
|
7709
7724
|
"mode": "0000644",
|
|
7710
|
-
"sha256": "
|
|
7725
|
+
"sha256": "a5f2a1e430a0dc50156d93a88ed4bd1b6c6bc232eed2ea1aab4ae017ee768777"
|
|
7711
7726
|
},
|
|
7712
7727
|
{
|
|
7713
7728
|
"path": "src/module-loader/catalog.js",
|
|
@@ -7767,7 +7782,7 @@
|
|
|
7767
7782
|
{
|
|
7768
7783
|
"path": "tests/account_privacy_flags.mjs",
|
|
7769
7784
|
"mode": "0000644",
|
|
7770
|
-
"sha256": "
|
|
7785
|
+
"sha256": "ab99d502635f87dd4021ecdd0badb88f842889b1b8902919fe6511aa363457b1"
|
|
7771
7786
|
},
|
|
7772
7787
|
{
|
|
7773
7788
|
"path": "tests/achievements_reconcile.mjs",
|
|
@@ -8577,7 +8592,7 @@
|
|
|
8577
8592
|
{
|
|
8578
8593
|
"path": "tests/effective_visibility_predicate.mjs",
|
|
8579
8594
|
"mode": "0000644",
|
|
8580
|
-
"sha256": "
|
|
8595
|
+
"sha256": "88ff4b377f71785545e3aed908df70b505af40453f47695646a9f72bf7250ab0"
|
|
8581
8596
|
},
|
|
8582
8597
|
{
|
|
8583
8598
|
"path": "tests/est_advisory.mjs",
|
|
@@ -8952,7 +8967,7 @@
|
|
|
8952
8967
|
{
|
|
8953
8968
|
"path": "tests/government_require_permission.mjs",
|
|
8954
8969
|
"mode": "0000644",
|
|
8955
|
-
"sha256": "
|
|
8970
|
+
"sha256": "a2711b93fcb7e6a602d22fbc864676f5dfdc6c503cc6551badc32e36facb723c"
|
|
8956
8971
|
},
|
|
8957
8972
|
{
|
|
8958
8973
|
"path": "tests/government_resolver.mjs",
|
|
@@ -9762,7 +9777,7 @@
|
|
|
9762
9777
|
{
|
|
9763
9778
|
"path": "tests/profile_route.mjs",
|
|
9764
9779
|
"mode": "0000644",
|
|
9765
|
-
"sha256": "
|
|
9780
|
+
"sha256": "ab6881bf65742f82dcb748daa5b8665c3a852a8fcc5aedb0a7040cafd6a3bdf4"
|
|
9766
9781
|
},
|
|
9767
9782
|
{
|
|
9768
9783
|
"path": "tests/profile_ui_cross_project.mjs",
|
|
@@ -9782,7 +9797,7 @@
|
|
|
9782
9797
|
{
|
|
9783
9798
|
"path": "tests/projects_hub.mjs",
|
|
9784
9799
|
"mode": "0000644",
|
|
9785
|
-
"sha256": "
|
|
9800
|
+
"sha256": "293c92d90457da1a3bd164f96bc897409275a7772c92c76b0b5b9bb6db8337e1"
|
|
9786
9801
|
},
|
|
9787
9802
|
{
|
|
9788
9803
|
"path": "tests/projects_hub_pre_uat.mjs",
|
|
@@ -9842,7 +9857,7 @@
|
|
|
9842
9857
|
{
|
|
9843
9858
|
"path": "tests/provisioning_settings.mjs",
|
|
9844
9859
|
"mode": "0000644",
|
|
9845
|
-
"sha256": "
|
|
9860
|
+
"sha256": "ffea349b46de6b790884eddcefbf7f756215c281f7d726ad43a81e22edcd4679"
|
|
9846
9861
|
},
|
|
9847
9862
|
{
|
|
9848
9863
|
"path": "tests/provisioning_settings_apply.mjs",
|
|
@@ -9852,7 +9867,7 @@
|
|
|
9852
9867
|
{
|
|
9853
9868
|
"path": "tests/provisioning_settings_env.mjs",
|
|
9854
9869
|
"mode": "0000644",
|
|
9855
|
-
"sha256": "
|
|
9870
|
+
"sha256": "4c8f1c7bdec5a063bcd3e76f4d43245c9491e3b8529593cdfaf33a3fbc85e319"
|
|
9856
9871
|
},
|
|
9857
9872
|
{
|
|
9858
9873
|
"path": "tests/provisioning_slug_available.mjs",
|
|
@@ -9954,6 +9969,11 @@
|
|
|
9954
9969
|
"mode": "0000644",
|
|
9955
9970
|
"sha256": "6d82e99c69d23a4dd7a844ffdd7f239ea70c94d9c509e2fc8e1a672cd9f05a28"
|
|
9956
9971
|
},
|
|
9972
|
+
{
|
|
9973
|
+
"path": "tests/recruiter_sliver_boundary.mjs",
|
|
9974
|
+
"mode": "0000644",
|
|
9975
|
+
"sha256": "cad269f556293e0caa234561f5764f90998a5d133b1e0147a5bbf22403c55e3a"
|
|
9976
|
+
},
|
|
9957
9977
|
{
|
|
9958
9978
|
"path": "tests/redteam_patrol.mjs",
|
|
9959
9979
|
"mode": "0000644",
|
|
@@ -10042,7 +10062,7 @@
|
|
|
10042
10062
|
{
|
|
10043
10063
|
"path": "tests/scouting_owner_access_and_reach.mjs",
|
|
10044
10064
|
"mode": "0000644",
|
|
10045
|
-
"sha256": "
|
|
10065
|
+
"sha256": "db4aa5ab365d1d2e9884b2c5a3f2abc40942e123844b7d5434434ddce680fd13"
|
|
10046
10066
|
},
|
|
10047
10067
|
{
|
|
10048
10068
|
"path": "tests/scouting_page_gate.mjs",
|
|
@@ -5,7 +5,7 @@ A **generated**, zero-dependency typed client for the Bongos API — produced fr
|
|
|
5
5
|
by hand; it regenerates when the spec changes, so it can never drift from the routes.
|
|
6
6
|
|
|
7
7
|
- API version: **v1** (served at `/api/bongos/v1`)
|
|
8
|
-
-
|
|
8
|
+
- 339 operations across 53 resource groups
|
|
9
9
|
|
|
10
10
|
## Install
|
|
11
11
|
|
|
@@ -705,6 +705,8 @@ function createClient(opts = {}) {
|
|
|
705
705
|
"scouting": {
|
|
706
706
|
// GET /scouting — rank: metic+archon — GET /scouting
|
|
707
707
|
getScouting: (args) => request("GET", "/scouting", { hasBody: false }, args),
|
|
708
|
+
// GET /scouting/{handle} — rank: archon — GET /scouting/:handle
|
|
709
|
+
getScoutingHandle: (args) => request("GET", "/scouting/{handle}", { hasBody: false }, args),
|
|
708
710
|
},
|
|
709
711
|
"search": {
|
|
710
712
|
// POST /search — rank: any-builder — POST /search
|
|
@@ -704,6 +704,8 @@ function createClient(opts = {}) {
|
|
|
704
704
|
"scouting": {
|
|
705
705
|
// GET /scouting — rank: metic+archon — GET /scouting
|
|
706
706
|
getScouting: (args) => request("GET", "/scouting", { hasBody: false }, args),
|
|
707
|
+
// GET /scouting/{handle} — rank: archon — GET /scouting/:handle
|
|
708
|
+
getScoutingHandle: (args) => request("GET", "/scouting/{handle}", { hasBody: false }, args),
|
|
707
709
|
},
|
|
708
710
|
"search": {
|
|
709
711
|
// POST /search — rank: any-builder — POST /search
|
|
@@ -93,7 +93,7 @@ export interface GetProvisioningFleetResponse { instances: unknown }
|
|
|
93
93
|
export interface GetProvisioningGithubAppStatusResponse { ok: boolean; status: unknown; ready: unknown; terminal: unknown; domain: unknown; instance_status: unknown; app_slug: unknown }
|
|
94
94
|
export interface GetProvisioningHealthResponse { module: unknown; ok: boolean; coreVersion: unknown }
|
|
95
95
|
export interface GetProvisioningInstancesIdResponse { instance: unknown; open_intent: unknown; github_app: unknown }
|
|
96
|
-
export interface GetProvisioningInstancesIdSettingsResponse { ok: boolean; settings: unknown; options: unknown }
|
|
96
|
+
export interface GetProvisioningInstancesIdSettingsResponse { ok: boolean; settings: unknown; planet: unknown; options: unknown }
|
|
97
97
|
export interface GetProvisioningInstancesResponse { instances: unknown }
|
|
98
98
|
export interface GetProvisioningOnboardPlanResponse { mode: unknown; steps: unknown }
|
|
99
99
|
export interface GetProvisioningSlugAvailableResponse { slug: unknown; available: unknown; reason: unknown; address: unknown }
|
|
@@ -110,6 +110,7 @@ export interface GetPublicRepoInfoResponse { blob_base: unknown; tree_base: unkn
|
|
|
110
110
|
export interface GetPublicTasksIdResponse { task: unknown }
|
|
111
111
|
export interface GetPublicUptimeResponse { services: unknown }
|
|
112
112
|
export interface GetPublicVersionsResponse { versions: unknown; page: PageInfo }
|
|
113
|
+
export interface GetScoutingHandleResponse { sliver: unknown }
|
|
113
114
|
export interface GetScoutingResponse { builders: unknown }
|
|
114
115
|
export interface GetSecurityDocsResponse { docs: unknown }
|
|
115
116
|
export interface GetSecurityDocsSlugResponse { doc: unknown }
|
|
@@ -168,8 +169,8 @@ export interface PatchProjectsIdFeaturedRequest { featured: boolean }
|
|
|
168
169
|
export interface PatchProjectsIdFeaturedResponse { project: unknown }
|
|
169
170
|
export interface PatchProvisioningInstancesIdDetailRequest { description?: string; detail?: Record<string, unknown> }
|
|
170
171
|
export interface PatchProvisioningInstancesIdDetailResponse { ok: boolean; description: unknown; detail: unknown; options: unknown }
|
|
171
|
-
export interface PatchProvisioningInstancesIdSettingsRequest { platform_visibility?: string; joinability?: string }
|
|
172
|
-
export interface PatchProvisioningInstancesIdSettingsResponse { ok: boolean; saved: unknown; push: unknown }
|
|
172
|
+
export interface PatchProvisioningInstancesIdSettingsRequest { platform_visibility?: string; joinability?: string; planet_template?: string; planet_accent?: string }
|
|
173
|
+
export interface PatchProvisioningInstancesIdSettingsResponse { ok: boolean; saved: unknown; planet: unknown; push: unknown }
|
|
173
174
|
export interface PatchTaskRecommendationsIdRequest { status: "declined" | "withdrawn" }
|
|
174
175
|
export interface PatchTaskRecommendationsIdResponse { ok: boolean; recommendation: unknown }
|
|
175
176
|
export interface PatchTasksIdRequest { kind?: string; discipline?: string; requires_rank?: string; module_key?: string; goal_id?: number; parent_task_id?: StringifiableId; parallel_safe?: unknown; newcomer_friendly?: boolean; xenos_claimable?: boolean; security_sensitive?: boolean; automation_tag?: string; needs_migration?: boolean; description?: string; title?: string; status?: unknown }
|
|
@@ -1012,6 +1013,8 @@ export interface BongosClient {
|
|
|
1012
1013
|
"scouting": {
|
|
1013
1014
|
/** GET /scouting — rank: metic+archon */
|
|
1014
1015
|
getScouting(args?: RequestArgs): Promise<GetScoutingResponse>;
|
|
1016
|
+
/** GET /scouting/{handle} — rank: archon */
|
|
1017
|
+
getScoutingHandle(args?: RequestArgs): Promise<GetScoutingHandleResponse>;
|
|
1015
1018
|
};
|
|
1016
1019
|
"search": {
|
|
1017
1020
|
/** POST /search — rank: any-builder */
|
|
@@ -701,6 +701,8 @@ export function createClient(opts = {}) {
|
|
|
701
701
|
"scouting": {
|
|
702
702
|
// GET /scouting — rank: metic+archon — GET /scouting
|
|
703
703
|
getScouting: (args) => request("GET", "/scouting", { hasBody: false }, args),
|
|
704
|
+
// GET /scouting/{handle} — rank: archon — GET /scouting/:handle
|
|
705
|
+
getScoutingHandle: (args) => request("GET", "/scouting/{handle}", { hasBody: false }, args),
|
|
704
706
|
},
|
|
705
707
|
"search": {
|
|
706
708
|
// POST /search — rank: any-builder — POST /search
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# ADR 0215 — The pre-accept recruiter sliver is a CEILING, not a step: a whitelist keyed by consent-and-reach, on the recruiting surface's own door
|
|
2
|
+
|
|
3
|
+
- **Status:** accepted
|
|
4
|
+
- **Date:** 2026-08-29
|
|
5
|
+
- **Task:** [task 1002968](https://cloudbongos.com/builders#/task/1002968) (PV3, goal 1000045 — Public builder profiles, criteria C2/C5)
|
|
6
|
+
- **Relates to:** `docs/specs/<redacted>.md` **D3** (the owner-signed sliver, 2026-08-16) and D1/D2 (the two privacy axes), [ADR 0171](<redacted>.md) D2/D4/D5 (rollup consent, no partial numbers, no-store), [ADR 0210](<redacted>.md) D2/D4 (the recruiting door; reach composed but not folded down), [ADR 0201](<redacted>.md) D3 (the `project.recruit` atom belongs to the console wave), [ADR 0016](<redacted>.md) (cross-project numbers are descriptive, never authority), [ADR 0202](<redacted>.md) D4 (one shared effective-visibility predicate)
|
|
7
|
+
|
|
8
|
+
> 0213 and 0214 are held by sessions in flight; this ADR takes 0215 rather than race them (the ADR 0199 / 0202 / 0207 / 0210 precedent).
|
|
9
|
+
|
|
10
|
+
## Context
|
|
11
|
+
|
|
12
|
+
Privacy spec D2 has a row that nothing could serve: **private · discoverable**. A builder who wants no public profile page but does want to be found for work sets `account_visibility = 'private'` and `recruiter_discoverable = true`, and until now that combination bought them exactly nothing — [ADR 0210](<redacted>.md) D4 says so in as many words: *"a private account is absent from the directory on purpose: the full rollup is never its disclosure — the D3 sliver is."* The sliver was the unbuilt half.
|
|
13
|
+
|
|
14
|
+
Two consequences had accumulated around that gap. The Settings toggle's copy was deliberately **narrowed** by task 1002290 to "the People directory", because the sliver was unbuilt and no guard could hold a wider promise. And [ADR 0201](<redacted>.md) had to ship the cross-project application queue showing a private applicant's *name, handle and note only*, deferring the richer record to "the sliver half, sequenced behind the recruiter port".
|
|
15
|
+
|
|
16
|
+
The design question is not what to show. The owner signed that on 2026-08-16 and it is short: **handle, display name, avatar, the disciplines union, and a coarse "active in the last 30 days" boolean — nothing else**; name-only under `hide_stats`; never for a provisional account; never a profile-page link. The question is what *kind of thing* the sliver is, and everything below follows from one answer: **it is a ceiling, not a step.** Nothing a recruiter holds after reading it gets them closer to the record it withholds.
|
|
17
|
+
|
|
18
|
+
## Decision
|
|
19
|
+
|
|
20
|
+
### D1 — The sliver's audience predicate is CONSENT **and** REACH, and it deliberately omits the EXISTENCE axis
|
|
21
|
+
|
|
22
|
+
`recruiterSliverVisibleSql` / `isRecruiterSliverVisible` join `modules/platform-identity/account-visibility.js`, the sole owner of every effective-visibility answer (ADR 0202 D4). Like `rollupVisibleSql` and `scoutingListableSql` it is **composed**, never restated:
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
recruiterSliverVisibleSql = accountActiveSql AND recruiterReachSql
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
It is the one composed answer in that file that does **not** contain `accountVisibleSql`, and that omission is the decision. Every other public read floors on `account_visibility = 'public'`; ANDing it here would empty the sliver of precisely the account it exists to serve, leaving a poorer, redundant copy of the directory.
|
|
29
|
+
|
|
30
|
+
**Dropping the existence axis is safe only because the reach half is an explicit opt-IN for a private account.** `recruiterReachSql` is `COALESCE(recruiter_discoverable, account_visibility = 'public')`: for a private account the `NULL` default resolves to **false**, so a private account reaches this surface only when its owner set the flag by hand. The widening is therefore not the platform's; it is the account's. Consent, not a relaxed floor.
|
|
31
|
+
|
|
32
|
+
`profile_state = 'active'` still floors it — a provisional account is never recruiter-visible, exactly as spec D3 says out loud — and `hide_stats` appears nowhere in the predicate, because hiding changes the **shape** of the sliver, never who appears in it.
|
|
33
|
+
|
|
34
|
+
**And the opt-in has to be the one they MEANT — which needed a write-path change, not only a predicate.** That safety argument holds only if an explicit `recruiter_discoverable = true` on a private account was given *as* a private account, and it need not have been. Toggle discoverability off and on again while **public** and the column stops being `NULL`: it becomes an explicit `true` meaning *"recruiters may see my public profile"*. Set the profile to Private later — reading a row that promises the page answers "not found" to every visitor — and that stale `true` used to be **inert**, because every recruiting surface floored on the existence axis. This ADR's own predicate is what would have activated it: silently, with no re-consent and no notice. So `setAccountPrivacy` now resets `recruiter_discoverable` to `NULL` — back to "follow visibility" — whenever a PATCH turns an account private **without naming reach**; naming it in the same PATCH *is* the re-consent and stands. The D2 "private · discoverable" row still exists; it now takes two deliberate moves instead of one forgotten one. (Found in adversarial review. The write's D2 matrix is resolved from the statement's own `CASE` in `tests/account_privacy_flags.mjs`, so deleting the arm reds it.)
|
|
35
|
+
|
|
36
|
+
Because that predicate is the only shared answer missing the existence axis, `tests/effective_visibility_predicate.mjs` **pins it to its one reader**. Naming it in that guard's `ADOPTS` list is what lets the sliver's own query pass the adoption rule, and that would otherwise be a hole: a future public read joining it would look adopted while quietly serving private accounts.
|
|
37
|
+
|
|
38
|
+
### D2 — The projection is a literal whitelist, `hide_stats` decides its SHAPE, and the hidden case never fetches what it will not show
|
|
39
|
+
|
|
40
|
+
`modules/platform-identity/recruiter-sliver.js` builds the object key by key. No row is ever spread, so a column added to either query cannot ride along. Two shapes, and only two:
|
|
41
|
+
|
|
42
|
+
| | keys |
|
|
43
|
+
|---|---|
|
|
44
|
+
| full | `handle`, `display_name`, `avatar_url`, `disciplines`, `active_recently` |
|
|
45
|
+
| `hide_stats` | `handle`, `display_name`, `avatar_url` |
|
|
46
|
+
|
|
47
|
+
The two rollup-derived keys are **absent, not null** — the sliver does not carry an empty box where a number used to be — and for a hidden account **the activity query is never issued at all**. Dropping the fields after fetching them would be equivalent today and strictly worse tomorrow: the cheapest way for a later edit to leak a number is for the number to already be in hand.
|
|
48
|
+
|
|
49
|
+
Four absences are load-bearing rather than incidental:
|
|
50
|
+
|
|
51
|
+
- **credits / works shipped / karma / project names / project count** — the post-accept record. "The aggregate is not the leak, the name is" (ADR 0171 D6), and a count beside a hidden total is a leak by subtraction, so there is no count either.
|
|
52
|
+
- **`last_active` as a timestamp.** The comparison to the 30-day window happens **in SQL** and only the boolean returns, so the date never enters the process and no later refactor can serialize it. A date is a behavioural trace; a boolean is a yes/no.
|
|
53
|
+
- **`github_id` and `github_login` as FIELDS.** Neither is a key of the sliver, and D3 names the *handle*, not the login. **The limit, stated rather than glossed:** the avatar D3 grants is GitHub's own URL — `https://avatars.githubusercontent.com/u/<github_id>?v=4` — so granting the avatar grants the account id inside it, and that id resolves through GitHub's public API to a login. Granting the avatar is the owner's decision, already made; pretending the id does not ride along was this ADR's. The proof now pins *where* it may appear (inside that URL and nowhere else) instead of asserting an absence the code does not deliver — an earlier draft claimed "the join key stays internal" while its fixture used an invented avatar host, so the sentinel could not have caught it.
|
|
54
|
+
- **any profile-page URL**, which spec D3 forbids outright.
|
|
55
|
+
|
|
56
|
+
### D3 — The handle is an ADDRESS, not a door — which is what "pre-accept" means operationally
|
|
57
|
+
|
|
58
|
+
The sliver hands a recruiter a handle, and the handle opens nothing: `GET /profiles/:handle` joins `accountVisibleSql` and answers **404** for exactly the private account whose sliver the recruiter just read. That is the whole claim of this ADR reduced to one assertion, and it is asserted — with a control proving the same page renders 200 for a publicly-visible builder, so the 404 cannot pass by the route simply being broken.
|
|
59
|
+
|
|
60
|
+
A **previous** handle resolves to nothing here either, deliberately unlike `resolveHandle`'s 301. The public page redirects so a *shared link* survives a rename; a recruiting read has no shared links to keep working, and resolving one would confirm to a recruiter that the account renamed — a disclosure the sliver never grants. (This was the one mutation the first draft of the proof did not catch; the rule was documented in the source and unheld by a test.)
|
|
61
|
+
|
|
62
|
+
### D4 — The sliver holds spec D3's **archon floor**; the directory's wider door is not reused, and the audience goes to the owner
|
|
63
|
+
|
|
64
|
+
`GET /scouting/:handle` sits in `modules/platform-identity/routes/scouting.js` beside `GET /scouting`, and the two do **not** share a gate. The sliver is `requireBuilder` → `api.requireRank('archon')`; the directory keeps `requireScoutingReader({ curateGate: requirePermission('project.curate') })`. Each gate is spelled in its own route's middleware list, so `route-rank-check.js` and `gen-api-docs.js` classify each from its real floor rather than recording a privileged route as `any-builder`.
|
|
65
|
+
|
|
66
|
+
Spec D3 says the sliver is "gated at the route by `project.recruit`" — and that atom **does not exist**. ADR 0201 D3 and ADR 0210 both refuse to mint it, on the same grounds: it belongs to the project-admin-console wave ([spike 1002786](https://cloudbongos.com/builders#/task/1002786) R3), which defines it, and minting it in a third place would fork its definition across three waves before any had shipped. **So which door does it use meanwhile?** The first draft reused the directory's, and that was wrong in the dangerous direction. Spec D1 declares the missing atom's shape — **floor archon**, widenable per instance through the governance tab — while the directory admits `project.curate` at the **metic** floor (ADR 0157) **OR any project owner**, who is typically a bare `xenos` on the hub (ADR 0210 D2). That door is *wider* than the signed floor on both halves. Reusing it would have widened an owner-signed privacy decision by implementation convenience, on the first surface that discloses a private account — and narrowing after people have been disclosed is not a recoverable move, while widening later is. So the sliver holds D3's declared floor, by rank, until the atom exists.
|
|
67
|
+
|
|
68
|
+
**The audience is the owner's call, and it is filed rather than taken.** [Blocker 1000126](https://cloudbongos.com/builders#/blocker/1000126) asks whether the wider recruiting audience is authorized here, with the evidence and a recommendation (hold the floor; let `project.recruit` — grantable per instance — settle it, which is exactly the knob the question wants). Answering it moves **one line**, and the tests that pin the floor flip with it. Goal 1000045 C5 (*"project owners, not only Archons, browse builder profiles to recruit"*) pulls the other way, and that tension is what the blocker carries: C5 was written about the DIRECTORY, which shows public builders; this surface shows private ones.
|
|
69
|
+
|
|
70
|
+
The refusal for an unreachable *builder* is **404, never 403**: a 403 would confirm the handle exists, which is precisely the disclosure the opt-out removes. (A refusal of the *caller* is an ordinary rank 403 naming the floor it wanted, so the hall can render why.) And `Cache-Control: no-store`, the `/profiles/:handle` posture, because the rollup half is live-derived and hide must beat any cache (ADR 0171 D5) — the directory route gained the same header here, having been the last rollup read without it.
|
|
71
|
+
|
|
72
|
+
### D5 — The sliver grants nothing (ADR 0016), and that is enforced structurally
|
|
73
|
+
|
|
74
|
+
Being visible to a recruiter confers no rank, no permission, no claim right, and nothing consults the sliver to decide anything: the module is required by **exactly one** first-party server file, the route that serializes it, enumerated from source so a second reader fails the build. The response carries no rank, role, permission or membership under any name. The reverse holds too and is the point of the reach axis: a builder's recruiting opt-out changes who can *see* them and grants or denies them nothing.
|
|
75
|
+
|
|
76
|
+
### D6 — The Settings copy widens back to name **both** recruiting surfaces, held by a guard rather than by good intentions
|
|
77
|
+
|
|
78
|
+
Task 1002290 narrowed the discoverable toggle from "every recruiting view" to "the People directory" on the copy rule that *a toggle may promise exactly what is enforced* — the sliver was unbuilt, so no guard could hold the wider claim. It is built and gated now, so the row names both: *"removes you from both recruiting surfaces — the People directory, and a recruiter's look-up of one builder — straight away."*
|
|
79
|
+
|
|
80
|
+
"Both" rather than "every", and that word choice is the decision. `tests/account_privacy_flags.mjs` asserts that `routes/scouting.js` mounts **exactly two** routes and that `scoutingListableSql` and `recruiterSliverVisibleSql` each compose `recruiterReachSql`. A third recruiting read in that file, or either reader dropping the reach axis, reds it. "Every recruiting view" would be an open-ended promise no guard can hold, and it stays banned.
|
|
81
|
+
|
|
82
|
+
**The half that was actually wrong, though, was the GRANT.** Spec D3 makes stating it a MUST — *"the discoverable toggle's settings copy must state exactly this grant"* — and the shipped copy was false: it told a hidden account it would show *"your name and nothing else"* while `SLIVER_KEYS_HIDDEN` also ships the **avatar**, and the shown branch never mentioned the picture at all. Neither branch told a *private* account that this is the one thing a recruiter sees while their page answers "not found". All three are fixed, and the guard no longer checks transcribed phrases: it iterates `SLIVER_KEYS` / `SLIVER_KEYS_HIDDEN` from the module itself, so a sixth granted field cannot ship without the copy being made to name it.
|
|
83
|
+
|
|
84
|
+
### D7 — No migration, and no new file in `platform-identity.js`
|
|
85
|
+
|
|
86
|
+
Both columns exist (migration `<redacted>.sql`); the activity table's `(github_id)` index already serves both reads. Spec D3 asks for the port "beside `getPublicProfileExtras`" and it is beside it *in the module*, not in the file: `platform-identity.js` sits on the 1500-line ratchet with no headroom — the `account-visibility.js` / `scouting-authz.js` / `application-echo.js` precedent, now five sessions deep.
|
|
87
|
+
|
|
88
|
+
## Consequences
|
|
89
|
+
|
|
90
|
+
- Privacy spec **D2's "private · discoverable" row is finally served**, and [task 1002972](https://cloudbongos.com/builders#/task/1002972) — the application queue rendering a private applicant's record — has the port it was sequenced behind. Its own half of the problem is unchanged and still real: ADR 0201 notes the hub cannot check an *instance* permission from a cross-origin browser read, so how the reviewer's browser reaches this route is that task's decision, not this one's.
|
|
91
|
+
- The recruiting surface now has two reads and one door. When `project.recruit` lands, it replaces `project.curate` in one expression and both routes move together.
|
|
92
|
+
- **The directory is unchanged.** A private account — discoverable or not — is still absent from `GET /scouting`, and a public leaderboard must still join `rollupVisibleSql`, never `scoutingListableSql` (ADR 0210 D4). Reach still governs the recruiting surface only.
|
|
93
|
+
|
|
94
|
+
⚠ **Honest limits, recorded rather than fixed:**
|
|
95
|
+
|
|
96
|
+
- **No UI consumes the sliver yet.** This ships the port, the route and the proof; the recruiting *view* is the console wave's (spec D6, `<redacted>.md` CT6) and the application queue's (task 1002972). The route is reachable and gated today; nothing in the hall calls it.
|
|
97
|
+
- **The audience is UNRESOLVED, not settled** ([blocker 1000126](https://cloudbongos.com/builders#/blocker/1000126)). The archon floor is the conservative reading of an owner-signed spec, not a call this ADR is entitled to make — and it is *narrower* than goal C5 describes, so project owners cannot use the sliver today. An earlier draft of this section called the shipped gate "narrower than the spec's atom" and "not a widening in any direction"; both were wrong, and wrong in the dangerous direction, because the SUBJECT set strictly grows: private accounts were on no recruiter surface at all before this.
|
|
98
|
+
- **The rank gate is a documented HOLDOUT against the module-gate migration rule** (BV1.R105/R107, ADR 0151): `modules/*/routes` gates are supposed to be permission atoms, and `tests/government_require_permission.mjs` enforces it from source. This route is listed in that test's `RETAINED` set with its full argument — the atom it wants is specified and owned by another wave, minting it forks the definition, borrowing a different archon atom would name the wrong authority on a privacy surface, and the sibling's door is wider than the signed floor. It is temporary by construction: spike 1002786 R3 removes the entry.
|
|
99
|
+
- **The two gates are spelled twice, on purpose.** An earlier draft called them "one gate expression … a one-line change reaching both"; they never were one, and now they are deliberately different.
|
|
100
|
+
- **A recruiting read added in another FILE would not trip the two-route guard.** D6's count is over `routes/scouting.js` alone, so the "both recruiting surfaces" copy could become false without reddening. Sweeping every route file for reach-joining reads is a structural guard of its own and belongs with the shared-predicate work, not here.
|
|
101
|
+
- **`getRecruiterSliver` (the by-id port spec D3 names) has no production caller yet** — [task 1002972](https://cloudbongos.com/builders#/task/1002972) is its consumer. The route uses the by-handle sibling; the proof exercises both.
|
|
102
|
+
- **`active_recently` is coarse by design and coarse in practice.** It is derived from `max(last_active)` across the rollup, which is refreshed on federated sign-in and on ship — so a builder active only on a project that never reports will read as inactive. That understates rather than overstates, which is the safe direction for a privacy surface.
|
|
103
|
+
- **This route is not rate-limited, and there is an asymmetry worth naming.** `GET /profiles/:handle` carries a per-IP read limiter precisely so the handle→identity mapping cannot be scripted at line rate (task 1002798), and `GET /scouting/:handle` — which is authenticated and permission-gated, so it starts from a much stronger position — has none. The asymmetry that remains is specific: a reader of this surface can probe guessed handles unmetered and learn *which private accounts opted into recruiting*, a set no other surface publishes. It is bounded by needing to guess a private account's handle (nothing publishes it) and by the audience already holding the full rollup of every public builder, so it is a widening of degree, not of kind. It is **not** fixable by reusing `accountExistenceReadRateLimit`: ADR 0209's whole decision is one budget per oracle, and this is a different oracle — sharing it would hand an enumerator the sum of two budgets on the route it cares about. The right fix is a dedicated budget behind a doorway-exported factory, which is a decision about the doorway rather than about the sliver; filed rather than smuggled in here.
|
|
104
|
+
|
|
105
|
+
**Rejected:**
|
|
106
|
+
|
|
107
|
+
- **Flooring the sliver on `accountVisibleSql`** — it would empty the surface of the exact account D3 exists to serve.
|
|
108
|
+
- **Folding reach into `rollupVisibleSql`** so the sliver could reuse it — ADR 0210 D4's reason stands: it would silently empty a future public leaderboard of every opted-out builder.
|
|
109
|
+
- **Minting `project.recruit` here** — ADR 0201 D3 and ADR 0210 both refuse it; it belongs to the console wave that defines it.
|
|
110
|
+
- **A second route file** for one route — the two recruiting reads live in one file (they share consent machinery and a reader's mental model); what they deliberately do NOT share is a gate.
|
|
111
|
+
- **Reusing the directory's door for the sliver** — wider than the owner-signed floor on both halves, on the one surface that discloses a private account.
|
|
112
|
+
- **Leaving a stale `recruiter_discoverable = true` to be read as consent** after the account went private.
|
|
113
|
+
- **Returning the rollup-derived keys as `null` under `hide_stats`** — an empty box is still a box, and it means the numbers were fetched.
|
|
114
|
+
- **Returning a profile URL, `github_login`, a project count, or `last_active`** — each forbidden by spec D3 or by ADR 0171 D4's leak-by-subtraction rule.
|
|
115
|
+
- **301-ing a previous handle**, the way the public page does — a recruiting read has no shared links to preserve, and the redirect would confirm a rename.
|
|
116
|
+
- **403 for a non-discoverable builder** — it confirms the handle exists.
|