@bongos/core 1.19.578 → 1.19.580

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 (37) hide show
  1. package/.bongos-core.json +68 -38
  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 +4 -0
  6. package/clients/bongos-client/index.mjs +2 -0
  7. package/docs/adr/0255-a-public-lists-ordering-is-part-of-its-payload.md +4 -1
  8. package/docs/adr/0259-a-projects-departure-from-the-public-list-is-public.md +128 -0
  9. package/docs/adr/0260-the-application-is-the-consent-and-the-echo-is-the-gate.md +146 -0
  10. package/docs/adr/README.md +2 -0
  11. package/docs/api/openapi.json +73 -3
  12. package/docs/api-reference.md +3 -2
  13. package/docs/copy-inventory.md +23 -21
  14. package/docs/copy-registry.json +51 -33
  15. package/docs/file-map.md +1 -0
  16. package/docs/module-api-changelog.md +4 -0
  17. package/modules/dev-box/app/src/vendor/bongos-client.cjs +2 -0
  18. package/modules/hall-ui/public/oversight.css +7 -0
  19. package/modules/hall-ui/public/watch.js +75 -0
  20. package/modules/onboarding/routes/access-requests.js +56 -1
  21. package/modules/platform-identity/applicant-profile.js +158 -0
  22. package/modules/platform-identity/application-echo.js +50 -0
  23. package/modules/platform-identity/recruiter-sliver.js +19 -0
  24. package/modules/platform-identity/routes/sso.js +126 -0
  25. package/modules/public-landing/public/projects.html +2 -2
  26. package/package-lock.json +2 -2
  27. package/package.json +1 -1
  28. package/src/bongos/auth-admission.js +61 -0
  29. package/src/bongos/auth.js +2 -1
  30. package/src/module-api.js +11 -1
  31. package/tests/adr_renumber_integrity.mjs +84 -0
  32. package/tests/applicant_profile_boundary.mjs +641 -0
  33. package/tests/applicant_profile_read_bounds.mjs +95 -0
  34. package/tests/module_api.mjs +1 -0
  35. package/tests/projects_hub.mjs +24 -0
  36. package/tests/recruiter_sliver_boundary.mjs +35 -2
  37. package/tests/watch_applications_queue.mjs +94 -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.578",
6
- "core_contract": "1.19.578",
7
- "source_commit": "a3f42dff6ab98712306ee86eaedf8191cafa3340",
5
+ "core_version": "1.19.580",
6
+ "core_contract": "1.19.580",
7
+ "source_commit": "23d256818bb7470aa5d203825abed34ab13f6fcf",
8
8
  "source_ref": "HEAD",
9
- "built_at": "2026-09-07T17:15:54.070Z",
9
+ "built_at": "2026-09-07T18:50:35.452Z",
10
10
  "redaction": {
11
11
  "model": "docs-redacted+functional-verbatim",
12
- "docs_redacted": 451,
12
+ "docs_redacted": 453,
13
13
  "agent_docs_stubbed": 24,
14
- "functional_verbatim": 2047,
14
+ "functional_verbatim": 2051,
15
15
  "rules": 3,
16
16
  "gate_literals": 3,
17
17
  "gate": "passed"
18
18
  },
19
- "file_count": 2522,
20
- "tree_sha256": "96be19d76442ed1b3e663525652a70c6ef60434e80d4ad907df8e294be5f38fe",
19
+ "file_count": 2528,
20
+ "tree_sha256": "293d3e0eb2f7b0d375fde65d1b6e75816035857c06a98f69f91d0e213a21f8ad",
21
21
  "files": [
22
22
  {
23
23
  "path": ".claude/skills/blocker-review/SKILL.md",
@@ -372,12 +372,12 @@
372
372
  {
373
373
  "path": "clients/bongos-client/README.md",
374
374
  "mode": "0000644",
375
- "sha256": "f94a07e3c135a5d6c41a2d16f722e86b990362996042dc2a5e05b2020f8cf376"
375
+ "sha256": "48a76d533215b8c0885fa77f59fc0e8915262db6b57029f6850692882e6e7455"
376
376
  },
377
377
  {
378
378
  "path": "clients/bongos-client/bongos-client.global.js",
379
379
  "mode": "0000644",
380
- "sha256": "06d1814637fe2898f0d93a3870726d53102d02feeae4611fcca80f195e2e26e4"
380
+ "sha256": "c7fe87ceb18e7e1c10e629d002fb6f322ee540606c3ec9f6d38741dac7a55e0f"
381
381
  },
382
382
  {
383
383
  "path": "clients/bongos-client/examples/hello-world.mjs",
@@ -387,17 +387,17 @@
387
387
  {
388
388
  "path": "clients/bongos-client/index.cjs",
389
389
  "mode": "0000644",
390
- "sha256": "ee0e25848a938f675e7a2e6e0a48983308117ecafe93ca219f4f1df49cf7ea51"
390
+ "sha256": "d80b05be7a602fa825f5f45e5b7f2bc002473a4731e2530df19fa3043f0c07fc"
391
391
  },
392
392
  {
393
393
  "path": "clients/bongos-client/index.d.ts",
394
394
  "mode": "0000644",
395
- "sha256": "adaa20c8ce6bee76dc289f10929014382aa89d7373f94ddafc84f4c87eeb0ed4"
395
+ "sha256": "e5cfa78c545e60771166ae4118e18f5c7bcf911db649c115c2831a028de3562b"
396
396
  },
397
397
  {
398
398
  "path": "clients/bongos-client/index.mjs",
399
399
  "mode": "0000644",
400
- "sha256": "6a3e4df57180f3c182fbadabe94030d06f125373c9336a7a4160015f1df5b11e"
400
+ "sha256": "47ae66627693378c276031754aca717ecc01e8e5038c4cf98ed844e5c03ee524"
401
401
  },
402
402
  {
403
403
  "path": "clients/bongos-client/package.json",
@@ -1792,7 +1792,7 @@
1792
1792
  {
1793
1793
  "path": "docs/adr/0255-a-public-lists-ordering-is-part-of-its-payload.md",
1794
1794
  "mode": "0000644",
1795
- "sha256": "2c82050a733a0a82dde5079bbc486fc3378b2be954817a811aab92b9e46c9c5b"
1795
+ "sha256": "9240caa363815ca9bbd49993bd73ecda85c6f91280ac152f344f69c77928bd22"
1796
1796
  },
1797
1797
  {
1798
1798
  "path": "docs/adr/0256-the-visibility-ceiling-is-the-sign-in-gate-too-and-the-reader-moves-to-the-composer.md",
@@ -1809,20 +1809,30 @@
1809
1809
  "mode": "0000644",
1810
1810
  "sha256": "28f3644d3d9dcd2985b7e3f42cf2135af86203eee35b6e509d1ff98f630f1228"
1811
1811
  },
1812
+ {
1813
+ "path": "docs/adr/0259-a-projects-departure-from-the-public-list-is-public.md",
1814
+ "mode": "0000644",
1815
+ "sha256": "772b9153d882f6bbd5000ee90b83e05d550ee4f04d4f5392db36e223d9a58c59"
1816
+ },
1817
+ {
1818
+ "path": "docs/adr/0260-the-application-is-the-consent-and-the-echo-is-the-gate.md",
1819
+ "mode": "0000644",
1820
+ "sha256": "fa04f8d71fff8186ae975a949c045ca7481bd0f22f395cb8c7397bbe03ddd449"
1821
+ },
1812
1822
  {
1813
1823
  "path": "docs/adr/README.md",
1814
1824
  "mode": "0000644",
1815
- "sha256": "30bb35e65ebd2dc8c5eb0aad7e30d5875d0c764265f398547abd545b62ee7d7c"
1825
+ "sha256": "1fa7dcf1456d26896e5cec77026ace0f08db8bed65527dee563cd7fdd2d07525"
1816
1826
  },
1817
1827
  {
1818
1828
  "path": "docs/api-reference.md",
1819
1829
  "mode": "0000644",
1820
- "sha256": "0a622847ab68980279beba2e1a54813b2393107144f88dd31228fe4dfd248b90"
1830
+ "sha256": "450613589b6b480ba2d6789731003794749c0dd972fcd8636380fa5814d68807"
1821
1831
  },
1822
1832
  {
1823
1833
  "path": "docs/api/openapi.json",
1824
1834
  "mode": "0000644",
1825
- "sha256": "60ca0b131c661df16fb993182d2085d0b04ea15a4d91bec4318c3413fb8dc311"
1835
+ "sha256": "c3a329219460b2508d51009ff8f77bdc4733f3a17ad2776553dc7bce483555c4"
1826
1836
  },
1827
1837
  {
1828
1838
  "path": "docs/architecture.md",
@@ -1847,12 +1857,12 @@
1847
1857
  {
1848
1858
  "path": "docs/copy-inventory.md",
1849
1859
  "mode": "0000644",
1850
- "sha256": "8bdf39ea0b8ed9583f9ef68b0edae767eec9c2825f8ef355d678b3db3d08b5e1"
1860
+ "sha256": "c4b6557f79a876b18cfc020ea4d45b8dfa419c9c37cab3fb2c629d85939bd75d"
1851
1861
  },
1852
1862
  {
1853
1863
  "path": "docs/copy-registry.json",
1854
1864
  "mode": "0000644",
1855
- "sha256": "cd51497ccca735bf1f8178291b427f4166aff79870a080a4a9d036238f0ff90c"
1865
+ "sha256": "867399ce0002d6a1f509969544ad9589db6769352597471b495c66749271bb3c"
1856
1866
  },
1857
1867
  {
1858
1868
  "path": "docs/design/apex-pass-2-direction.md",
@@ -2687,7 +2697,7 @@
2687
2697
  {
2688
2698
  "path": "docs/file-map.md",
2689
2699
  "mode": "0000644",
2690
- "sha256": "f43e8946ecb5c96dc7af0bcee49010245df577eee62381701d2aef1c67455662"
2700
+ "sha256": "dd0684364a3ccd656f8201367e23775d578a84b385f49a901f7fc4205312b344"
2691
2701
  },
2692
2702
  {
2693
2703
  "path": "docs/handoff-template.md",
@@ -2697,7 +2707,7 @@
2697
2707
  {
2698
2708
  "path": "docs/module-api-changelog.md",
2699
2709
  "mode": "0000644",
2700
- "sha256": "072128c45a7036c0d01bc029a1267bf34ff7bd175226e83d691b8001e4a8eefa"
2710
+ "sha256": "2237a99993338a480835d8cf8c62bc0925585d46d01a9859b5ba3afa108af5d1"
2701
2711
  },
2702
2712
  {
2703
2713
  "path": "docs/modules-contract.md",
@@ -4097,7 +4107,7 @@
4097
4107
  {
4098
4108
  "path": "modules/dev-box/app/src/vendor/bongos-client.cjs",
4099
4109
  "mode": "0000644",
4100
- "sha256": "ee0e25848a938f675e7a2e6e0a48983308117ecafe93ca219f4f1df49cf7ea51"
4110
+ "sha256": "d80b05be7a602fa825f5f45e5b7f2bc002473a4731e2530df19fa3043f0c07fc"
4101
4111
  },
4102
4112
  {
4103
4113
  "path": "modules/dev-box/app/test/unit.mjs",
@@ -4987,7 +4997,7 @@
4987
4997
  {
4988
4998
  "path": "modules/hall-ui/public/oversight.css",
4989
4999
  "mode": "0000644",
4990
- "sha256": "9aa3fd3f662274571e049eb9931f8dd575eef527a624bc6a5d57102061f54936"
5000
+ "sha256": "13d46f29e77ba9ca30ab52de2e0413f2fcb68bfec44de032730d4d135530e4ba"
4991
5001
  },
4992
5002
  {
4993
5003
  "path": "modules/hall-ui/public/pair.css",
@@ -5307,7 +5317,7 @@
5307
5317
  {
5308
5318
  "path": "modules/hall-ui/public/watch.js",
5309
5319
  "mode": "0000644",
5310
- "sha256": "66a3fc7edf59112c1126c6c1c96244ac3cae1c0aea99f946c96b202d14f2cbac"
5320
+ "sha256": "058f25fcef75b3db5410ea7fa6b09515b0b7fddc64a7698c1a1c44e753c8a651"
5311
5321
  },
5312
5322
  {
5313
5323
  "path": "modules/hall-ui/public/watch.states.json",
@@ -5912,7 +5922,7 @@
5912
5922
  {
5913
5923
  "path": "modules/onboarding/routes/access-requests.js",
5914
5924
  "mode": "0000644",
5915
- "sha256": "ebebd2ce84727de2dff8411a6279aefb3792de51577a5ba04dc7d565cbce5494"
5925
+ "sha256": "3c66a404347ef1b93edcf5c63a902c9561b0a3f9bd9bc6c17e8a2a1f1b5f6707"
5916
5926
  },
5917
5927
  {
5918
5928
  "path": "modules/onboarding/routes/onboarding.js",
@@ -5929,10 +5939,15 @@
5929
5939
  "mode": "0000644",
5930
5940
  "sha256": "020279ae50f2f9e7a004fe571e5ca14493ad26bd22c395cc4805f759f5560b72"
5931
5941
  },
5942
+ {
5943
+ "path": "modules/platform-identity/applicant-profile.js",
5944
+ "mode": "0000644",
5945
+ "sha256": "12c1d00965d2d386480bdf94673ab6f140c8ee6ba44a5995a2d1b9593c012d20"
5946
+ },
5932
5947
  {
5933
5948
  "path": "modules/platform-identity/application-echo.js",
5934
5949
  "mode": "0000644",
5935
- "sha256": "3793f588d62eaa96a74da6bceb55043e8a9de35bc120dbe63f26bcc2b7e904da"
5950
+ "sha256": "8217660dc23b57ba0fb54d6375aca9aec190c7abb1d70f9d44d4e290da272c64"
5936
5951
  },
5937
5952
  {
5938
5953
  "path": "modules/platform-identity/canonical-profile.js",
@@ -6112,7 +6127,7 @@
6112
6127
  {
6113
6128
  "path": "modules/platform-identity/recruiter-sliver.js",
6114
6129
  "mode": "0000644",
6115
- "sha256": "e1385b83ac5bb82d13ffbe5070043c2fd0ca20385b3d62e8331ef917d9fca496"
6130
+ "sha256": "4f6854050e3c7459f698c550577fa97958a573d7f1981c9de4d29417af2669c0"
6116
6131
  },
6117
6132
  {
6118
6133
  "path": "modules/platform-identity/routes/connections.js",
@@ -6147,7 +6162,7 @@
6147
6162
  {
6148
6163
  "path": "modules/platform-identity/routes/sso.js",
6149
6164
  "mode": "0000644",
6150
- "sha256": "dbc8eeab6b1911b7fdc8b29e3d10871d355d2dead926a0742e9a816a72215dba"
6165
+ "sha256": "6921323c299eee14e2db75b2c1716e35c245f7c971e6aec57c2b339b106f4d87"
6151
6166
  },
6152
6167
  {
6153
6168
  "path": "modules/platform-identity/scouting-authz.js",
@@ -6812,7 +6827,7 @@
6812
6827
  {
6813
6828
  "path": "modules/public-landing/public/projects.html",
6814
6829
  "mode": "0000644",
6815
- "sha256": "22201cd63fde334156b40954707d836f8c65a8380a3f346fe7c77abb03ed3b51"
6830
+ "sha256": "0154fab4db489db2eb1955bffdd9b0585ff7fe28607897e75c26d83c7edfc3e0"
6816
6831
  },
6817
6832
  {
6818
6833
  "path": "modules/public-landing/public/projects.probes.json",
@@ -7557,12 +7572,12 @@
7557
7572
  {
7558
7573
  "path": "package-lock.json",
7559
7574
  "mode": "0000644",
7560
- "sha256": "e5249bc21a0842ce0e47203e1b7052aa146161702db57b1c50740d409a7347b2"
7575
+ "sha256": "28db9a2f030a69e041ee0c0d277238e7f5f7be0ba8a9bd370ffc2fc644a3c1d1"
7561
7576
  },
7562
7577
  {
7563
7578
  "path": "package.json",
7564
7579
  "mode": "0000644",
7565
- "sha256": "d328d1b9a42a9003642815e8a17cc14f648d53a996c2c6db92a8d1250c570ea8"
7580
+ "sha256": "cbec2151e643d5ff302e5d98166488c6298669395eafe9e037a2f39ea23db5c9"
7566
7581
  },
7567
7582
  {
7568
7583
  "path": "public-docs/index.html",
@@ -8977,7 +8992,7 @@
8977
8992
  {
8978
8993
  "path": "src/bongos/auth-admission.js",
8979
8994
  "mode": "0000644",
8980
- "sha256": "8dc4cc0ab956d387b8044c22e83fce883f2f0129ed27c03503f7348e9d4f00bb"
8995
+ "sha256": "aaa113f476a1d8196324379f8fd78aab22f577455fa0378bac3200b98e6a887f"
8981
8996
  },
8982
8997
  {
8983
8998
  "path": "src/bongos/auth-config.js",
@@ -9002,7 +9017,7 @@
9002
9017
  {
9003
9018
  "path": "src/bongos/auth.js",
9004
9019
  "mode": "0000644",
9005
- "sha256": "517e25a2ca9b9adafa993725802af9e7fc1708f0a5609102ddce593e82478ca2"
9020
+ "sha256": "eeb1831ab3d033598e0bcd57c30589cac583a1259c98b2dd49fbd9bb7725e11b"
9006
9021
  },
9007
9022
  {
9008
9023
  "path": "src/bongos/cascade-dispatch.js",
@@ -9267,7 +9282,7 @@
9267
9282
  {
9268
9283
  "path": "src/module-api.js",
9269
9284
  "mode": "0000644",
9270
- "sha256": "71207830c631f2604b55d9e2e6a2db08b0d129499249c4db009c00e871fc2fd7"
9285
+ "sha256": "a3e2c3a0b4099d54d8cd5c309186feb8a0c7073074095c4d10861f71e9f36ce4"
9271
9286
  },
9272
9287
  {
9273
9288
  "path": "src/module-loader/catalog.js",
@@ -9359,6 +9374,11 @@
9359
9374
  "mode": "0000644",
9360
9375
  "sha256": "125edcec8c7d7536365b9675daa1fceb9fe072a30e2a4a68ee2911cd258a8c10"
9361
9376
  },
9377
+ {
9378
+ "path": "tests/adr_renumber_integrity.mjs",
9379
+ "mode": "0000644",
9380
+ "sha256": "bdc9d3678e12dee3f3252785ca82e06071421762c7146cbc1591d3fc2ec72180"
9381
+ },
9362
9382
  {
9363
9383
  "path": "tests/agents_spawn.mjs",
9364
9384
  "mode": "0000644",
@@ -9419,6 +9439,16 @@
9419
9439
  "mode": "0000644",
9420
9440
  "sha256": "ac84c8d8b1e2f54ef278506570ed657e68d2da4e136968b0df31b51f943af4bb"
9421
9441
  },
9442
+ {
9443
+ "path": "tests/applicant_profile_boundary.mjs",
9444
+ "mode": "0000644",
9445
+ "sha256": "beefe27f5f753185cf3513f6576e55ee44680760ff2d8eed4ced93d56ec92b77"
9446
+ },
9447
+ {
9448
+ "path": "tests/applicant_profile_read_bounds.mjs",
9449
+ "mode": "0000644",
9450
+ "sha256": "185fed67d8b3e65121af637e37392c21d4bcd892bb2b305704479f42ff5987c7"
9451
+ },
9422
9452
  {
9423
9453
  "path": "tests/application_echo.mjs",
9424
9454
  "mode": "0000644",
@@ -11287,7 +11317,7 @@
11287
11317
  {
11288
11318
  "path": "tests/module_api.mjs",
11289
11319
  "mode": "0000644",
11290
- "sha256": "39812c560bcd88e3b3a7938ed2447fbd4ab24b0f925e9662b375910bcbe7f1da"
11320
+ "sha256": "157d551b9a99320198f22d32ce335fa4166414dc1818d11ef23a0ea05ac80a76"
11291
11321
  },
11292
11322
  {
11293
11323
  "path": "tests/module_api_lazy.mjs",
@@ -11647,7 +11677,7 @@
11647
11677
  {
11648
11678
  "path": "tests/projects_hub.mjs",
11649
11679
  "mode": "0000644",
11650
- "sha256": "ec536c7bcfe2c9ea29d0df8a0dcbbb5c2764b4f60e0d14218aa0a10bf6afb469"
11680
+ "sha256": "d32fd31e368acdaaf1d4f31b775f62ef8e20ea4f5810a37fddb8ef1dba1487b6"
11651
11681
  },
11652
11682
  {
11653
11683
  "path": "tests/projects_hub_module_picker.mjs",
@@ -11852,7 +11882,7 @@
11852
11882
  {
11853
11883
  "path": "tests/recruiter_sliver_boundary.mjs",
11854
11884
  "mode": "0000644",
11855
- "sha256": "cad269f556293e0caa234561f5764f90998a5d133b1e0147a5bbf22403c55e3a"
11885
+ "sha256": "a9ad552e7060898e5c94db8af29e63d7cad568294c240c48bef78859a0558ec6"
11856
11886
  },
11857
11887
  {
11858
11888
  "path": "tests/redteam_followup_kind.mjs",
@@ -12587,7 +12617,7 @@
12587
12617
  {
12588
12618
  "path": "tests/watch_applications_queue.mjs",
12589
12619
  "mode": "0000644",
12590
- "sha256": "b1f7df5aa40b89f8737c76d94def15c539514f7f439cca79a034bf37b922158d"
12620
+ "sha256": "52c5c056c33b0b2ee91076b29e24ea5b650a0148c603fdde5136e60d6c6e926a"
12591
12621
  },
12592
12622
  {
12593
12623
  "path": "tests/web_admission_status.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
- - 358 operations across 55 resource groups
8
+ - 359 operations across 55 resource groups
9
9
 
10
10
  ## Install
11
11
 
@@ -793,6 +793,8 @@ function createClient(opts = {}) {
793
793
  "sso": {
794
794
  // POST /sso/activity/rollup — rank: public — POST /sso/activity/rollup
795
795
  postSsoActivityRollup: (args) => request("POST", "/sso/activity/rollup", { hasBody: true }, args),
796
+ // POST /sso/applicant-profile — rank: public — POST /sso/applicant-profile
797
+ postSsoApplicantProfile: (args) => request("POST", "/sso/applicant-profile", { hasBody: true }, args),
796
798
  // GET /sso/authorize — rank: public — GET /sso/authorize
797
799
  getSsoAuthorize: (args) => request("GET", "/sso/authorize", { hasBody: false }, args),
798
800
  // POST /sso/device/poll — rank: public — POST /sso/device/poll
@@ -792,6 +792,8 @@ function createClient(opts = {}) {
792
792
  "sso": {
793
793
  // POST /sso/activity/rollup — rank: public — POST /sso/activity/rollup
794
794
  postSsoActivityRollup: (args) => request("POST", "/sso/activity/rollup", { hasBody: true }, args),
795
+ // POST /sso/applicant-profile — rank: public — POST /sso/applicant-profile
796
+ postSsoApplicantProfile: (args) => request("POST", "/sso/applicant-profile", { hasBody: true }, args),
795
797
  // GET /sso/authorize — rank: public — GET /sso/authorize
796
798
  getSsoAuthorize: (args) => request("GET", "/sso/authorize", { hasBody: false }, args),
797
799
  // POST /sso/device/poll — rank: public — POST /sso/device/poll
@@ -355,6 +355,8 @@ export interface PostSessionsRequest { session_id: string; task_ids?: number[];
355
355
  export interface PostSessionsResponse { skipped?: boolean; reason?: unknown; session?: unknown; token_reward?: unknown }
356
356
  export interface PostSsoActivityRollupRequest { client_id: string; client_secret: string; github_id: StringifiableId; credits?: number; tasks_shipped?: number; karma?: number; rank?: string; disciplines?: unknown; recent_ships?: unknown }
357
357
  export interface PostSsoActivityRollupResponse { ok: boolean }
358
+ export interface PostSsoApplicantProfileRequest { client_id: string; client_secret: string; github_id: StringifiableId }
359
+ export interface PostSsoApplicantProfileResponse { profile: unknown }
358
360
  export interface PostSsoDevicePollRequest { device_code: string }
359
361
  export interface PostSsoDeviceStartRequest { origin: string }
360
362
  export interface PostSsoMembershipCheckInRequest { client_id: string; client_secret: string; github_id: StringifiableId; github_login: string; display_name?: string; avatar_url?: string; membership_kind?: string; role?: string }
@@ -1119,6 +1121,8 @@ export interface BongosClient {
1119
1121
  "sso": {
1120
1122
  /** POST /sso/activity/rollup — rank: public */
1121
1123
  postSsoActivityRollup(args: RequestArgs & { body: PostSsoActivityRollupRequest }): Promise<PostSsoActivityRollupResponse>;
1124
+ /** POST /sso/applicant-profile — rank: public */
1125
+ postSsoApplicantProfile(args: RequestArgs & { body: PostSsoApplicantProfileRequest }): Promise<PostSsoApplicantProfileResponse>;
1122
1126
  /** GET /sso/authorize — rank: public */
1123
1127
  getSsoAuthorize(args?: RequestArgs): Promise<ApiResponse>;
1124
1128
  /** POST /sso/device/poll — rank: public */
@@ -789,6 +789,8 @@ export function createClient(opts = {}) {
789
789
  "sso": {
790
790
  // POST /sso/activity/rollup — rank: public — POST /sso/activity/rollup
791
791
  postSsoActivityRollup: (args) => request("POST", "/sso/activity/rollup", { hasBody: true }, args),
792
+ // POST /sso/applicant-profile — rank: public — POST /sso/applicant-profile
793
+ postSsoApplicantProfile: (args) => request("POST", "/sso/applicant-profile", { hasBody: true }, args),
792
794
  // GET /sso/authorize — rank: public — GET /sso/authorize
793
795
  getSsoAuthorize: (args) => request("GET", "/sso/authorize", { hasBody: false }, args),
794
796
  // POST /sso/device/poll — rank: public — POST /sso/device/poll
@@ -150,7 +150,10 @@ Stated plainly, because a privacy fix that oversells itself is worse than none:
150
150
  than the ordering one and it is untouched here: it is inherent in publishing a named list
151
151
  at all, and closing it needs a different mechanism (a delay, a decoy, or accepting that a
152
152
  project's *departure* from the public list is public). Filed separately rather than
153
- silently implied to be fixed.
153
+ silently implied to be fixed — and **now decided**: the owner chose to accept it and say
154
+ so in the copy ([ADR 0259](<redacted>.md),
155
+ [task 1003672](https://cloudbongos.com/builders#/task/1003672)), which also carries the
156
+ §6.3 residual below.
154
157
  3. **Position is stable within one epoch.** Two snapshots taken the same day can still tell
155
158
  black holes apart, though not name them. The rotation bounds this to the epoch.
156
159
 
@@ -0,0 +1,128 @@
1
+ # ADR 0259 — A project's departure from the public list is public, and the copy says so
2
+
3
+ - **Status:** accepted
4
+ - **Date:** 2026-09-07
5
+ - **Task:** [task 1003672](https://cloudbongos.com/builders#/task/1003672) (BONGOS-V1, goal 1000046 — *Project creation*)
6
+ - **Deciders:** the owner (choosing between accept / delay / decoys), Claude
7
+ - **Related:** [ADR 0255](<redacted>.md) §6.2 (which filed this leak rather than implying it fixed) · [ADR 0182](<redacted>.md) D2a (the stealth redaction and its `STEALTH_ANONYMOUS_KEEPS` allow-list) · [ADR 0253](<redacted>.md) (the `visibility_source` provenance this feed joins)
8
+
9
+ ---
10
+
11
+ ## 1. The channel
12
+
13
+ The public projects feed publishes a named list plus a count of anonymous rows. When a
14
+ project flips to stealth, its named row **leaves the identified block** and the anonymous
15
+ count **rises by one**. An observer who keeps yesterday's feed and diffs it against today's
16
+ reads that off directly:
17
+
18
+ > *Mercury is gone, and there is one more black hole.*
19
+
20
+ That names the project that went stealth, and the moment it happened, with no reference to
21
+ ordering at all.
22
+
23
+ **Everything ADR 0182 D2a does is defeated by it.** That ADR takes real trouble to keep any
24
+ stable per-project key off an anonymous row — `STEALTH_ANONYMOUS_KEEPS = ['state', 'orb']`
25
+ is an allow-list precisely so a column added next year is anonymous without anyone
26
+ remembering to come back to it. But the identity was never carried *on* the anonymous row.
27
+ It is carried by the **absence** of the named row that used to sit beside it.
28
+
29
+ **It is larger than the leak [ADR 0255](<redacted>.md)
30
+ closed.** The ordering channel needed repeated sampling and correlation to be useful. This
31
+ one is a single diff of two snapshots and it is exact.
32
+
33
+ ## 2. Why no ordering fix reaches it
34
+
35
+ It is not an ordering property, so no `ORDER BY` change touches it. It is inherent in
36
+ publishing a named list at all: any list that names its members leaks a member's departure
37
+ to anyone who read it twice. The three ways out are all product decisions with visible
38
+ costs, which is why 0255 filed this rather than fixing it:
39
+
40
+ | Option | Cost |
41
+ |---|---|
42
+ | **Accept it, and say so** | An observer archiving the list learns who went stealth, and when. |
43
+ | **Delay** — keep the named row for a window | A privacy control that takes days to take effect, which is the wrong direction for a privacy control. |
44
+ | **Decoys** — pad the anonymous block | The count stops being truthful. It is truthful today. |
45
+
46
+ ## 3. Decision
47
+
48
+ **Accept it, and make the copy say so.**
49
+
50
+ The promise stealth actually keeps is about the project's *contents*, not about the
51
+ *transition*. An anonymous row stays anonymous: no name, no tagline, no art, no origin, no
52
+ stable key, nothing that survives to the next snapshot. What is not private is the act of
53
+ stepping off the named list, because the named list is published and readers may keep
54
+ copies of it.
55
+
56
+ Two reasons this is the right end of the trade, and not merely the cheapest:
57
+
58
+ 1. **It is already the honest reading of the existing promise.** ADR 0182 D2a made existence
59
+ and count public *by design* — the map shows that hidden projects are there. A count that
60
+ is public and truthful is a count whose changes are public. Delay and decoys both work by
61
+ making a currently-honest number less honest.
62
+
63
+ 2. **The alternatives damage the control they defend.** A delay means an owner clicks the
64
+ privacy setting and is not private yet, which is a worse failure than the one it fixes —
65
+ the owner believes they are hidden while they are not. Decoys spend the count's
66
+ truthfulness on a guarantee that is still only probabilistic.
67
+
68
+ ### 3.1 What "say so" means concretely
69
+
70
+ The owner-facing copy for Stealth previously read:
71
+
72
+ > The map shows only that something is there. Its name, and everything else about it, stay
73
+ > yours — and nobody can ask to join.
74
+
75
+ Every clause is true and the paragraph as a whole still oversells, because a reader takes
76
+ "its name stays yours" to cover the switch itself. The copy now names the boundary in both
77
+ places an owner meets this setting — the choice's blurb and the explanatory fold — in the
78
+ plain register [ADR 0182](<redacted>.md)'s interview fixed for this
79
+ card (the space metaphor belongs to the drawn orb, never to the words).
80
+
81
+ **A privacy control that oversells is worse than one that admits a limit**, which is the
82
+ same standard 0255 §6 set for itself.
83
+
84
+ ## 4. What a future fix must not do
85
+
86
+ Recorded so a later attempt does not undo the two guarantees that *are* held:
87
+
88
+ - **No stable per-project key on an anonymous row** — the `STEALTH_ANONYMOUS_KEEPS`
89
+ allow-list ([ADR 0182](<redacted>.md) D2a). A decoy scheme that
90
+ needs to tell its own padding apart from real rows is the classic way this gets
91
+ reintroduced.
92
+ - **No anonymous ordering an observer can predict or correlate**
93
+ ([ADR 0255](<redacted>.md) §3) — the trailing
94
+ block's keyed, rotating permutation.
95
+
96
+ ## 5. The residual this does not address either
97
+
98
+ Within one 24h epoch the anonymous block's permutation is stable, so two snapshots taken the
99
+ same day can tell black holes apart — though not name them. Bounded by the rotation, and
100
+ carried here from [ADR 0255](<redacted>.md) §6.3 so
101
+ both residuals live in one place. Accepted on the same reasoning: the fix is a per-request
102
+ permutation, which breaks pagination exactly the way `ORDER BY random()` was rejected for in
103
+ 0255.
104
+
105
+ ## 6. Consequences
106
+
107
+ - No behaviour changes in `modules/platform-identity/projects-feed.js`. The feed, the
108
+ redaction allow-list and the permutation are all untouched — this ADR decides that they
109
+ are *finished*, not that they need more.
110
+ - The Stealth copy carries the boundary in both surfaces, and
111
+ `tests/projects_hub.mjs` pins that it does, so the sentence cannot quietly drop out of a
112
+ future copy edit and leave the page overselling again.
113
+ - [ADR 0255](<redacted>.md) §6.2's "filed
114
+ separately" is now resolved, and points here.
115
+
116
+ ## Alternatives rejected
117
+
118
+ - **A delay window before the named row is dropped.** Rejected: the setting would not take
119
+ effect when the owner sets it, and the owner would not know that. It converts an
120
+ information leak into a false belief, which is worse.
121
+ - **Decoy rows padding the anonymous block.** Rejected: it spends the count's honesty, and a
122
+ decoy scheme needs some way to distinguish padding from real rows — the exact stable key
123
+ D2a forbids.
124
+ - **Dropping the named list.** Rejected: the map's whole purpose is showing what is being
125
+ built here; a list nobody can read protects a privacy nobody asked for at the cost of the
126
+ feature.
127
+ - **Saying nothing and leaving the copy as it was.** Rejected: the copy would keep implying a
128
+ guarantee the system does not make. That is the failure mode this ADR exists to close.