@bongos/core 1.19.417 → 1.19.419

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 (36) hide show
  1. package/.bongos-core.json +87 -32
  2. package/clients/bongos-client/README.md +1 -1
  3. package/clients/bongos-client/bongos-client.global.js +22 -0
  4. package/clients/bongos-client/index.cjs +22 -0
  5. package/clients/bongos-client/index.d.ts +33 -0
  6. package/clients/bongos-client/index.mjs +22 -0
  7. package/docs/adr/0206-own-scoped-session-revocation-no-absolute-ceiling.md +59 -0
  8. package/docs/adr/0207-connections-implementation-departures-and-honest-limits.md +90 -0
  9. package/docs/adr/README.md +2 -0
  10. package/docs/api/openapi.json +599 -3
  11. package/docs/api-reference.md +17 -2
  12. package/docs/architecture.md +1 -0
  13. package/docs/copy-inventory.md +51 -36
  14. package/docs/copy-registry.json +175 -40
  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 +22 -0
  18. package/modules/hall-ui/public/settings-sessions.js +119 -0
  19. package/modules/hall-ui/public/settings.css +25 -0
  20. package/modules/hall-ui/public/settings.html +22 -0
  21. package/modules/platform-identity/account-visibility.js +58 -0
  22. package/modules/platform-identity/connections.js +490 -0
  23. package/modules/platform-identity/migrations/platform_identity_015_connections.sql +78 -0
  24. package/modules/platform-identity/module.json +1 -1
  25. package/modules/platform-identity/routes/connections.js +236 -0
  26. package/package-lock.json +2 -2
  27. package/package.json +1 -1
  28. package/src/bongos/db.js +46 -0
  29. package/src/bongos/route-rank-check.js +10 -0
  30. package/src/bongos/routes/my-sessions.js +128 -0
  31. package/src/bongos/routes.js +5 -0
  32. package/src/module-api.js +1 -1
  33. package/tests/connections_api.mjs +568 -0
  34. package/tests/connections_ownership.mjs +313 -0
  35. package/tests/own_scope_guard.mjs +10 -0
  36. package/tests/own_session_revoke.mjs +410 -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.417",
6
- "core_contract": "1.19.417",
7
- "source_commit": "2ea84040287b365331cb8eb9278615dc4a0e5642",
5
+ "core_version": "1.19.419",
6
+ "core_contract": "1.19.419",
7
+ "source_commit": "d433ea7793766e404ce4b09ee9f652d5c09df897",
8
8
  "source_ref": "HEAD",
9
- "built_at": "2026-08-29T16:38:30.577Z",
9
+ "built_at": "2026-08-29T17:21:12.343Z",
10
10
  "redaction": {
11
11
  "model": "docs-redacted+functional-verbatim",
12
- "docs_redacted": 356,
12
+ "docs_redacted": 358,
13
13
  "agent_docs_stubbed": 23,
14
- "functional_verbatim": 1701,
14
+ "functional_verbatim": 1710,
15
15
  "rules": 3,
16
16
  "gate_literals": 3,
17
17
  "gate": "passed"
18
18
  },
19
- "file_count": 2080,
20
- "tree_sha256": "4d8a309a1363b0a74ea89df369c37d35b0af343cd3ed08d4361f8951165933b3",
19
+ "file_count": 2091,
20
+ "tree_sha256": "95da3db8c2006aa8998116a9f4679ee33c902f365d0aa3904d7af6d3412ac78d",
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": "80d3bb0a3dc011b0c2b16558b20c1ea2adc3e5345418a8d08f13a7cd2ac5eb9a"
355
+ "sha256": "d80581bbcb2577fe16cba30d6e0e1ff4ede4ca49dd08c306d1a3bcbfdf1d2cdc"
356
356
  },
357
357
  {
358
358
  "path": "clients/bongos-client/bongos-client.global.js",
359
359
  "mode": "0000644",
360
- "sha256": "833fecb6824cb535eb990a8f3a516528c6d560eee856323f5d824afe5bcf7932"
360
+ "sha256": "64cccfdbd4d3d86798bdb60dbcf336e474aeb6af3854225c0a87f9d466c86acd"
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": "bf528220a1990c760111ef291e6d6d6543b62440ab62c3962a8772e897218c69"
370
+ "sha256": "b11537927f1268e2e14d8307589fe2eb58ef01e245556decd0251efc17f707d3"
371
371
  },
372
372
  {
373
373
  "path": "clients/bongos-client/index.d.ts",
374
374
  "mode": "0000644",
375
- "sha256": "84fce1d4d0fba5b586f1a965a7b4b6818ad7d27e7bbce68818e9def0db85724b"
375
+ "sha256": "227105130a432d4e7a294b4359455e022beaaac87bcd4014855d9d34e2faeaf4"
376
376
  },
377
377
  {
378
378
  "path": "clients/bongos-client/index.mjs",
379
379
  "mode": "0000644",
380
- "sha256": "b07a09551c9af7e526aaf2416e5340b112f7b8b8ffc28c49afe252092a215f9c"
380
+ "sha256": "aaa84ab1bc5fd8054a85d36d6c70dd4667c8103c21e1c5a027de0b3806096029"
381
381
  },
382
382
  {
383
383
  "path": "clients/bongos-client/package.json",
@@ -1529,25 +1529,35 @@
1529
1529
  "mode": "0000644",
1530
1530
  "sha256": "dedf9285b041a0d4c54982a8372aca573e57eb3d89a5abf9381a922a8784ff7f"
1531
1531
  },
1532
+ {
1533
+ "path": "docs/adr/0206-own-scoped-session-revocation-no-absolute-ceiling.md",
1534
+ "mode": "0000644",
1535
+ "sha256": "634404f2eb0d29386460e0ea008a826069d80bfbd42721aa7b2cd4d74cb4fa86"
1536
+ },
1537
+ {
1538
+ "path": "docs/adr/0207-connections-implementation-departures-and-honest-limits.md",
1539
+ "mode": "0000644",
1540
+ "sha256": "72c859bdfc70fd4fc0d104439985a43eaf60cce281bbaae8b8faaffb40546973"
1541
+ },
1532
1542
  {
1533
1543
  "path": "docs/adr/README.md",
1534
1544
  "mode": "0000644",
1535
- "sha256": "3d9a57147d8a7e8db350df79ecc457cf57bdadd77d08b41749dfa658c733c07c"
1545
+ "sha256": "0f92a7a74afdf213a1aba92da88ea5348878ba0df67c3fc9e33d06b8f7ebade9"
1536
1546
  },
1537
1547
  {
1538
1548
  "path": "docs/api-reference.md",
1539
1549
  "mode": "0000644",
1540
- "sha256": "dc283ca75e6aa5b2dcede50879f7c7f7beb151ae953282c917621b4dd6d6b2e1"
1550
+ "sha256": "e58b3d540eeaa8f38e028c72e64f4a2373c16c4c185edabc2d2538d247da9a29"
1541
1551
  },
1542
1552
  {
1543
1553
  "path": "docs/api/openapi.json",
1544
1554
  "mode": "0000644",
1545
- "sha256": "b0f8cab2aa5931ef9090bbee552ff00f3da37a86ce327225b11712f16cd25090"
1555
+ "sha256": "091c9eecdbec83a540fc5d92017525dfdfdf192604b39d8cf60ec2cfb3466819"
1546
1556
  },
1547
1557
  {
1548
1558
  "path": "docs/architecture.md",
1549
1559
  "mode": "0000644",
1550
- "sha256": "68d30a764a36e963d40e4271010c56b61a824b9e2fad61599fdc62ee1bc2fddf"
1560
+ "sha256": "d24b71683aab15bb19ffd110c3d214dade7f2be4c5cc81740153c92ea8ccc252"
1551
1561
  },
1552
1562
  {
1553
1563
  "path": "docs/branding-contract.md",
@@ -1567,12 +1577,12 @@
1567
1577
  {
1568
1578
  "path": "docs/copy-inventory.md",
1569
1579
  "mode": "0000644",
1570
- "sha256": "c462f7be788726d0bbe0186dcaa7288fa81b23550057ce9f579bc5b3d6096f44"
1580
+ "sha256": "3e70beb03c93a71f5068c407467deeeca3c69d5271372de04399a9094fa32dd9"
1571
1581
  },
1572
1582
  {
1573
1583
  "path": "docs/copy-registry.json",
1574
1584
  "mode": "0000644",
1575
- "sha256": "429fbb99f080c8bb80c8b8fc9539eb632dab1a4f6bb0534170667c76e055001d"
1585
+ "sha256": "ae4ffbc86e556ea5463b8289754b70e9465a581e93a40f8713204c34d433e00a"
1576
1586
  },
1577
1587
  {
1578
1588
  "path": "docs/design/apex-pass-2-direction.md",
@@ -1907,7 +1917,7 @@
1907
1917
  {
1908
1918
  "path": "docs/file-map.md",
1909
1919
  "mode": "0000644",
1910
- "sha256": "76febc87dd3d8b6641673093df2efa7c699a33428e6a53bc1cf595e0f3daf558"
1920
+ "sha256": "2464bcb60656e263ef00002c928a2e6f0d4b812b7a7b8183c634535f1192e58d"
1911
1921
  },
1912
1922
  {
1913
1923
  "path": "docs/handoff-template.md",
@@ -1917,7 +1927,7 @@
1917
1927
  {
1918
1928
  "path": "docs/module-api-changelog.md",
1919
1929
  "mode": "0000644",
1920
- "sha256": "402fcd99a486b88a9c7e0acccd85d95effbbe263dec1f917f7bfc1e07349f46c"
1930
+ "sha256": "793b13d001dfdb2742b623d7f43d1c5850c67df8a8b12ffb469c675f15a109e2"
1921
1931
  },
1922
1932
  {
1923
1933
  "path": "docs/modules-contract.md",
@@ -3227,7 +3237,7 @@
3227
3237
  {
3228
3238
  "path": "modules/dev-box/app/src/vendor/bongos-client.cjs",
3229
3239
  "mode": "0000644",
3230
- "sha256": "bf528220a1990c760111ef291e6d6d6543b62440ab62c3962a8772e897218c69"
3240
+ "sha256": "b11537927f1268e2e14d8307589fe2eb58ef01e245556decd0251efc17f707d3"
3231
3241
  },
3232
3242
  {
3233
3243
  "path": "modules/dev-box/app/test/unit.mjs",
@@ -4144,15 +4154,20 @@
4144
4154
  "mode": "0000644",
4145
4155
  "sha256": "e99046a2c0e2cb6ce9f05711ddbe6ed9d2e7536086dca16496ef0e5e8cb9a041"
4146
4156
  },
4157
+ {
4158
+ "path": "modules/hall-ui/public/settings-sessions.js",
4159
+ "mode": "0000644",
4160
+ "sha256": "c0c207769631f027ca35d219105e2189e2d259e7b45bfeaa1245fd749d7e91e5"
4161
+ },
4147
4162
  {
4148
4163
  "path": "modules/hall-ui/public/settings.css",
4149
4164
  "mode": "0000644",
4150
- "sha256": "4ff2a298547ad65d92b2511b0ea98c4adfe8f173833585eb34197f29255086b7"
4165
+ "sha256": "d50ac6727dde53e91aef8daa5ce759edcc69924e43b786103800892d9b87fe4d"
4151
4166
  },
4152
4167
  {
4153
4168
  "path": "modules/hall-ui/public/settings.html",
4154
4169
  "mode": "0000644",
4155
- "sha256": "852ce177610c5bc49145333b157700d8c3566565d106dcf26c476d32b7105609"
4170
+ "sha256": "88886109031ceb77f4a4efbe133af5a2ac8e26ec5dd55e2e71a0bbe5152887bc"
4156
4171
  },
4157
4172
  {
4158
4173
  "path": "modules/hall-ui/public/settings.js",
@@ -4754,6 +4769,16 @@
4754
4769
  "mode": "0000644",
4755
4770
  "sha256": "7cb9dac9cb87b679e1ae50e4112b3a7928a38ebb9902c8947a74d17bec4d9009"
4756
4771
  },
4772
+ {
4773
+ "path": "modules/platform-identity/account-visibility.js",
4774
+ "mode": "0000644",
4775
+ "sha256": "744a7293bbdf4e2340baf0dc7f789df03a63ba7970741b8aef5922c02cb8910e"
4776
+ },
4777
+ {
4778
+ "path": "modules/platform-identity/connections.js",
4779
+ "mode": "0000644",
4780
+ "sha256": "3bdd5edf87ff2095035e8945afb7d3a0779cbb9f691e6e634f12a6500edeb21b"
4781
+ },
4757
4782
  {
4758
4783
  "path": "modules/platform-identity/hub-device.js",
4759
4784
  "mode": "0000644",
@@ -4844,10 +4869,15 @@
4844
4869
  "mode": "0000644",
4845
4870
  "sha256": "cf29832de04b2b31e1d36b5d595489bbbb09d14b12c86da7c5ac7557917475bf"
4846
4871
  },
4872
+ {
4873
+ "path": "modules/platform-identity/migrations/platform_identity_015_connections.sql",
4874
+ "mode": "0000644",
4875
+ "sha256": "edaced87ae340bb4c0a8c73d5dc40f8578bf7be0bd4064a02d6c4fcf0cf94be3"
4876
+ },
4847
4877
  {
4848
4878
  "path": "modules/platform-identity/module.json",
4849
4879
  "mode": "0000644",
4850
- "sha256": "c4c02577f7318e994301bbe700e20dfb24519e411fee04539755f7374a73590b"
4880
+ "sha256": "d7c74b8b41b3c0f6d0d072632f4a8d04f11b06c39203c6f759dcaf4e324fd9b0"
4851
4881
  },
4852
4882
  {
4853
4883
  "path": "modules/platform-identity/platform-identity.js",
@@ -4864,6 +4894,11 @@
4864
4894
  "mode": "0000644",
4865
4895
  "sha256": "2e898799632a2b5c2ead9cb44fa0b8029fcb6d217f7d5f26c8a39b34c75bbea7"
4866
4896
  },
4897
+ {
4898
+ "path": "modules/platform-identity/routes/connections.js",
4899
+ "mode": "0000644",
4900
+ "sha256": "d4b7ddb7ec100899e95e73428fba8dc5e3f41005e021fcf887ea80ba8ae0e1b6"
4901
+ },
4867
4902
  {
4868
4903
  "path": "modules/platform-identity/routes/my-projects.js",
4869
4904
  "mode": "0000644",
@@ -5432,12 +5467,12 @@
5432
5467
  {
5433
5468
  "path": "package-lock.json",
5434
5469
  "mode": "0000644",
5435
- "sha256": "64e99f4a6c987054fa4827a376eace859767c9f5edc34676a60b5e0e19cb1581"
5470
+ "sha256": "9bcfa46cd421336fba313885ceb399c9f025a85f5c07759abdb9d653bbd34105"
5436
5471
  },
5437
5472
  {
5438
5473
  "path": "package.json",
5439
5474
  "mode": "0000644",
5440
- "sha256": "29aa7a9418a4755ab9c7e20a439d84f12ea48407851c6634ff9669c809940332"
5475
+ "sha256": "cff6d489fea88ab0fe13b221de09f4bfa4b7d95ce5d8a1386de53ce94236b44e"
5441
5476
  },
5442
5477
  {
5443
5478
  "path": "public-docs/index.html",
@@ -7317,7 +7352,7 @@
7317
7352
  {
7318
7353
  "path": "src/bongos/db.js",
7319
7354
  "mode": "0000644",
7320
- "sha256": "3c34327680f89ae6a442bf6d75c1ac3ba570e0a08df2efa063d55b84727ba9ea"
7355
+ "sha256": "feff54089b6bae5845558d262c07ec30d9532419d42c04f1f113bc2fc95d9173"
7321
7356
  },
7322
7357
  {
7323
7358
  "path": "src/bongos/github-repos.js",
@@ -7417,12 +7452,12 @@
7417
7452
  {
7418
7453
  "path": "src/bongos/route-rank-check.js",
7419
7454
  "mode": "0000644",
7420
- "sha256": "ebdf0cb4cb521fbf5aa7809c39e89ad4f776e77b194c734042fae72226511674"
7455
+ "sha256": "96b884a69b7b709a256d220c97a972f9827d74a36a864c216a7b37db3fdf66be"
7421
7456
  },
7422
7457
  {
7423
7458
  "path": "src/bongos/routes.js",
7424
7459
  "mode": "0000644",
7425
- "sha256": "ede634ea623ec035a5ebab896f1f97e67e142c882cade5afaeb3e3c253fc28f8"
7460
+ "sha256": "074cded727667d864b1849d8d5505736895a69a6bdf7132375fd358d66c2e6fd"
7426
7461
  },
7427
7462
  {
7428
7463
  "path": "src/bongos/routes/CLAUDE.md",
@@ -7489,6 +7524,11 @@
7489
7524
  "mode": "0000644",
7490
7525
  "sha256": "54a42c37d4afd403a13aa5e9fda6a7d95cb0fca70dfe3cb4daef318c099a5f00"
7491
7526
  },
7527
+ {
7528
+ "path": "src/bongos/routes/my-sessions.js",
7529
+ "mode": "0000644",
7530
+ "sha256": "0e002104e2fedea2bb322826560aadf18b9885f21e214592c63b304b3ba9fd1e"
7531
+ },
7492
7532
  {
7493
7533
  "path": "src/bongos/routes/optimizer.js",
7494
7534
  "mode": "0000644",
@@ -7552,7 +7592,7 @@
7552
7592
  {
7553
7593
  "path": "src/module-api.js",
7554
7594
  "mode": "0000644",
7555
- "sha256": "0dce01d81ecb3f709416d11f10605ac834dbdb5ed9faea3f9459ddfceaa8389d"
7595
+ "sha256": "d70b98299c5a454682784d75bed90dc711525c826fb861bf11c8e5126ea0e155"
7556
7596
  },
7557
7597
  {
7558
7598
  "path": "src/module-loader/catalog.js",
@@ -8114,6 +8154,16 @@
8114
8154
  "mode": "0000644",
8115
8155
  "sha256": "69f4e40c66e49e4d2c58f1f41ec1c515b2cb44891e40b6192ed898484d10671d"
8116
8156
  },
8157
+ {
8158
+ "path": "tests/connections_api.mjs",
8159
+ "mode": "0000644",
8160
+ "sha256": "fe844d310fbe79e38f199dc623a96e0facd751967a9a247be5cbe9c15f80f13a"
8161
+ },
8162
+ {
8163
+ "path": "tests/connections_ownership.mjs",
8164
+ "mode": "0000644",
8165
+ "sha256": "1d716fc81ebdb81daedade019f5adcdda2161c06df40711c8fb78f3ec5d605b0"
8166
+ },
8117
8167
  {
8118
8168
  "path": "tests/consumer_layout_boot.mjs",
8119
8169
  "mode": "0000644",
@@ -9462,7 +9512,12 @@
9462
9512
  {
9463
9513
  "path": "tests/own_scope_guard.mjs",
9464
9514
  "mode": "0000644",
9465
- "sha256": "694002ebe39755fd01bdba57bf70e7077201b81a6938df92fff09b44027a29cc"
9515
+ "sha256": "074346fee8dbc4de221600d21a4066852125f4f3d0b4f792093e9546ba2cd900"
9516
+ },
9517
+ {
9518
+ "path": "tests/own_session_revoke.mjs",
9519
+ "mode": "0000644",
9520
+ "sha256": "756920320b74c9094d1be12108efb8ddbb39341b8d122afd9454ffd084a2efe5"
9466
9521
  },
9467
9522
  {
9468
9523
  "path": "tests/package_core.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
- - 327 operations across 52 resource groups
8
+ - 337 operations across 53 resource groups
9
9
 
10
10
  ## Install
11
11
 
@@ -264,6 +264,22 @@ function createClient(opts = {}) {
264
264
  // GET /closeness/with/{builderId} — rank: any-builder — GET /closeness/with/:builderId
265
265
  getClosenessWithBuilderId: (args) => request("GET", "/closeness/with/{builderId}", { hasBody: false }, args),
266
266
  },
267
+ "connections": {
268
+ // GET /connections — rank: any-builder — GET /connections
269
+ getConnections: (args) => request("GET", "/connections", { hasBody: false }, args),
270
+ // POST /connections — rank: any-builder — POST /connections
271
+ postConnections: (args) => request("POST", "/connections", { hasBody: true }, args),
272
+ // DELETE /connections/{id} — rank: any-builder — DELETE /connections/:id
273
+ deleteConnectionsId: (args) => request("DELETE", "/connections/{id}", { hasBody: false }, args),
274
+ // POST /connections/{id}/accept — rank: any-builder — POST /connections/:id/accept
275
+ postConnectionsIdAccept: (args) => request("POST", "/connections/{id}/accept", { hasBody: true }, args),
276
+ // POST /connections/{id}/decline — rank: any-builder — POST /connections/:id/decline
277
+ postConnectionsIdDecline: (args) => request("POST", "/connections/{id}/decline", { hasBody: true }, args),
278
+ // GET /connections/degree/{handle} — rank: any-builder — GET /connections/degree/:handle
279
+ getConnectionsDegreeHandle: (args) => request("GET", "/connections/degree/{handle}", { hasBody: false }, args),
280
+ // GET /connections/requests — rank: any-builder — GET /connections/requests
281
+ getConnectionsRequests: (args) => request("GET", "/connections/requests", { hasBody: false }, args),
282
+ },
267
283
  "copyDesk": {
268
284
  // POST /copy-desk/flags — rank: any-builder — POST /copy-desk/flags
269
285
  postCopyDeskFlags: (args) => request("POST", "/copy-desk/flags", { hasBody: true }, args),
@@ -523,6 +539,12 @@ function createClient(opts = {}) {
523
539
  getMeRender: (args) => request("GET", "/me/render", { hasBody: false }, args),
524
540
  // PATCH /me/render — rank: any-builder — PATCH /me/render
525
541
  patchMeRender: (args) => request("PATCH", "/me/render", { hasBody: true }, args),
542
+ // GET /me/sessions — rank: any-builder — GET /me/sessions
543
+ getMeSessions: (args) => request("GET", "/me/sessions", { hasBody: false }, args),
544
+ // POST /me/sessions/revoke — rank: any-builder — POST /me/sessions/revoke
545
+ postMeSessionsRevoke: (args) => request("POST", "/me/sessions/revoke", { hasBody: true }, args),
546
+ // POST /me/sessions/revoke-all — rank: any-builder — POST /me/sessions/revoke-all
547
+ postMeSessionsRevokeAll: (args) => request("POST", "/me/sessions/revoke-all", { hasBody: true }, args),
526
548
  // GET /me/skill-prefs — rank: any-builder — GET /me/skill-prefs
527
549
  getMeSkillPrefs: (args) => request("GET", "/me/skill-prefs", { hasBody: false }, args),
528
550
  // PATCH /me/skill-prefs — rank: any-builder — PATCH /me/skill-prefs
@@ -263,6 +263,22 @@ function createClient(opts = {}) {
263
263
  // GET /closeness/with/{builderId} — rank: any-builder — GET /closeness/with/:builderId
264
264
  getClosenessWithBuilderId: (args) => request("GET", "/closeness/with/{builderId}", { hasBody: false }, args),
265
265
  },
266
+ "connections": {
267
+ // GET /connections — rank: any-builder — GET /connections
268
+ getConnections: (args) => request("GET", "/connections", { hasBody: false }, args),
269
+ // POST /connections — rank: any-builder — POST /connections
270
+ postConnections: (args) => request("POST", "/connections", { hasBody: true }, args),
271
+ // DELETE /connections/{id} — rank: any-builder — DELETE /connections/:id
272
+ deleteConnectionsId: (args) => request("DELETE", "/connections/{id}", { hasBody: false }, args),
273
+ // POST /connections/{id}/accept — rank: any-builder — POST /connections/:id/accept
274
+ postConnectionsIdAccept: (args) => request("POST", "/connections/{id}/accept", { hasBody: true }, args),
275
+ // POST /connections/{id}/decline — rank: any-builder — POST /connections/:id/decline
276
+ postConnectionsIdDecline: (args) => request("POST", "/connections/{id}/decline", { hasBody: true }, args),
277
+ // GET /connections/degree/{handle} — rank: any-builder — GET /connections/degree/:handle
278
+ getConnectionsDegreeHandle: (args) => request("GET", "/connections/degree/{handle}", { hasBody: false }, args),
279
+ // GET /connections/requests — rank: any-builder — GET /connections/requests
280
+ getConnectionsRequests: (args) => request("GET", "/connections/requests", { hasBody: false }, args),
281
+ },
266
282
  "copyDesk": {
267
283
  // POST /copy-desk/flags — rank: any-builder — POST /copy-desk/flags
268
284
  postCopyDeskFlags: (args) => request("POST", "/copy-desk/flags", { hasBody: true }, args),
@@ -522,6 +538,12 @@ function createClient(opts = {}) {
522
538
  getMeRender: (args) => request("GET", "/me/render", { hasBody: false }, args),
523
539
  // PATCH /me/render — rank: any-builder — PATCH /me/render
524
540
  patchMeRender: (args) => request("PATCH", "/me/render", { hasBody: true }, args),
541
+ // GET /me/sessions — rank: any-builder — GET /me/sessions
542
+ getMeSessions: (args) => request("GET", "/me/sessions", { hasBody: false }, args),
543
+ // POST /me/sessions/revoke — rank: any-builder — POST /me/sessions/revoke
544
+ postMeSessionsRevoke: (args) => request("POST", "/me/sessions/revoke", { hasBody: true }, args),
545
+ // POST /me/sessions/revoke-all — rank: any-builder — POST /me/sessions/revoke-all
546
+ postMeSessionsRevokeAll: (args) => request("POST", "/me/sessions/revoke-all", { hasBody: true }, args),
525
547
  // GET /me/skill-prefs — rank: any-builder — GET /me/skill-prefs
526
548
  getMeSkillPrefs: (args) => request("GET", "/me/skill-prefs", { hasBody: false }, args),
527
549
  // PATCH /me/skill-prefs — rank: any-builder — PATCH /me/skill-prefs
@@ -6,6 +6,7 @@ export declare const DEFAULT_BASE_URL: string;
6
6
  // Request-body + shared types, generated from the OpenAPI components.schemas.
7
7
  export interface ApiErrorObject { code: string; message: string; details?: unknown }
8
8
  export interface DeleteBoxSshKeyIdResponse { ok: boolean; deleted: unknown }
9
+ export interface DeleteConnectionsIdResponse { outcome: unknown }
9
10
  export interface DeleteDependenciesResponse { ok: boolean }
10
11
  export interface DeleteGovernmentAssignmentsBuilderIdRankKeyResponse { ok: boolean; builder_id: unknown; rank_key: unknown; removed: unknown }
11
12
  export interface DeleteGovernmentRanksRankKeyPermissionsPermissionKeyResponse { ok: boolean; rank_key: unknown; permission_key: unknown; removed: unknown }
@@ -39,6 +40,9 @@ export interface GetBuildersRosterResponse { builders: unknown; stale_hours: unk
39
40
  export interface GetClosenessForMeResponse { closeness: unknown; count: unknown }
40
41
  export interface GetClosenessWeightsResponse { weights: unknown; window_days: unknown; note: unknown }
41
42
  export interface GetClosenessWithBuilderIdResponse { closeness: unknown; why: unknown }
43
+ export interface GetConnectionsDegreeHandleResponse { handle: unknown; degree: unknown; mutuals: unknown; mutual_count: unknown; truncated: unknown }
44
+ export interface GetConnectionsRequestsResponse { incoming: unknown; outgoing: unknown; incoming_count: unknown; outgoing_count: unknown }
45
+ export interface GetConnectionsResponse { connections: unknown; count: unknown }
42
46
  export interface GetDiscordChannelsPlanResponse { ok: boolean; guild_id: unknown; op_count: unknown; ops: unknown; warnings: unknown }
43
47
  export interface GetDoneWhenPendingReviewResponse { criteria: unknown; count: unknown }
44
48
  export interface GetGithubRepoResponse { ok: boolean; repo: unknown; private_deployable: boolean }
@@ -68,6 +72,7 @@ export interface GetMeCrossProjectResponse { hide_stats: boolean; profile_state:
68
72
  export interface GetMeDisplayNameResponse { display_name: unknown; max_length: unknown }
69
73
  export interface GetMeEventSoundPrefsResponse { prefs: unknown; effective: unknown; effective_wav: unknown; events: unknown }
70
74
  export interface GetMeRecentShipsResponse { ships: unknown }
75
+ export interface GetMeSessionsResponse { sessions: unknown }
71
76
  export interface GetMeSkillPrefsResponse { prefs: unknown; effective: unknown; defaults: unknown; known_skills: unknown; allowed_models: unknown }
72
77
  export interface GetMeSoundPrefsResponse { prefs: unknown; effective: unknown; effective_map: unknown; volume: unknown; defaults: unknown; known_sounds: unknown }
73
78
  export interface GetMemoryBfgBuildersBuilderIdFileResponse { builder_id: unknown; bfg_read: boolean; path: unknown; content: unknown; sha256: unknown; byte_len: unknown; mtime: unknown; updated_at: unknown; created_at: unknown }
@@ -215,6 +220,9 @@ export interface PostClaimsIdReleaseOnBehalfRequest { reason: string }
215
220
  export interface PostClaimsIdResolveRequest { outcome: "shipped" | "abandoned" | "partial"; notes_md?: string; value_summary?: string; verification?: Record<string, unknown>; force?: boolean; committed_files?: string[]; sandbox_review?: Record<string, unknown> }
216
221
  export interface PostClaimsRequest { task_id: StringifiableId; worktree_name?: string; head_sha?: string; bind_session?: boolean; enforce_touches?: boolean }
217
222
  export interface PostClaimsResponse { claim: unknown; task: unknown; just_unlocked: unknown; overlap_warning: unknown; reward: unknown }
223
+ export interface PostConnectionsIdAcceptResponse { status: unknown }
224
+ export interface PostConnectionsRequest { handle: string; note?: string }
225
+ export interface PostConnectionsResponse { status: unknown }
218
226
  export interface PostCopyDeskFlagsIdCloseRequest { status: string; resolution_note: string; resolved_task_id?: number }
219
227
  export interface PostCopyDeskFlagsIdCloseResponse { ok: boolean; flag: unknown }
220
228
  export interface PostCopyDeskFlagsRequest { scope?: string; surface: string; string_id?: string; reason: string; kind?: string }
@@ -283,6 +291,9 @@ export interface PostLlmCacheStoreRequest { spec?: unknown; result_stdout?: unkn
283
291
  export interface PostLlmCacheStoreResponse { stored: boolean; result_cost_usd?: unknown }
284
292
  export interface PostMeAnthropicLinkRequest { anthropic_email: string; anthropic_user_id: string }
285
293
  export interface PostMeAnthropicLinkResponse { linked: unknown }
294
+ export interface PostMeSessionsRevokeAllResponse { ok: boolean; revoked: unknown }
295
+ export interface PostMeSessionsRevokeRequest { session_id?: StringifiableId }
296
+ export interface PostMeSessionsRevokeResponse { ok: boolean; revoked: unknown }
286
297
  export interface PostMemoryBuildersBuilderIdBfgWriteRequest { kind?: string; slug?: string; title?: string; body_md?: string; rationale?: string; karma_delta?: unknown }
287
298
  export interface PostMemoryBuildersBuilderIdBfgWriteResponse { ok: boolean; builder_id: unknown; path: unknown; kind: unknown; author: unknown; audit_id: unknown; karma_id: unknown; sha256: unknown; byte_len: unknown; updated_at: unknown }
288
299
  export interface PostMemorySyncRequest { files?: unknown[] }
@@ -558,6 +569,22 @@ export interface BongosClient {
558
569
  /** GET /closeness/with/{builderId} — rank: any-builder */
559
570
  getClosenessWithBuilderId(args?: RequestArgs): Promise<GetClosenessWithBuilderIdResponse>;
560
571
  };
572
+ "connections": {
573
+ /** GET /connections — rank: any-builder */
574
+ getConnections(args?: RequestArgs): Promise<GetConnectionsResponse>;
575
+ /** POST /connections — rank: any-builder */
576
+ postConnections(args: RequestArgs & { body: PostConnectionsRequest }): Promise<PostConnectionsResponse>;
577
+ /** DELETE /connections/{id} — rank: any-builder */
578
+ deleteConnectionsId(args?: RequestArgs): Promise<DeleteConnectionsIdResponse>;
579
+ /** POST /connections/{id}/accept — rank: any-builder */
580
+ postConnectionsIdAccept(args?: RequestArgs): Promise<PostConnectionsIdAcceptResponse>;
581
+ /** POST /connections/{id}/decline — rank: any-builder */
582
+ postConnectionsIdDecline(args?: RequestArgs): Promise<ApiResponse>;
583
+ /** GET /connections/degree/{handle} — rank: any-builder */
584
+ getConnectionsDegreeHandle(args?: RequestArgs): Promise<GetConnectionsDegreeHandleResponse>;
585
+ /** GET /connections/requests — rank: any-builder */
586
+ getConnectionsRequests(args?: RequestArgs): Promise<GetConnectionsRequestsResponse>;
587
+ };
561
588
  "copyDesk": {
562
589
  /** POST /copy-desk/flags — rank: any-builder */
563
590
  postCopyDeskFlags(args: RequestArgs & { body: PostCopyDeskFlagsRequest }): Promise<PostCopyDeskFlagsResponse>;
@@ -817,6 +844,12 @@ export interface BongosClient {
817
844
  getMeRender(args?: RequestArgs): Promise<ApiResponse>;
818
845
  /** PATCH /me/render — rank: any-builder */
819
846
  patchMeRender(args?: RequestArgs): Promise<ApiResponse>;
847
+ /** GET /me/sessions — rank: any-builder */
848
+ getMeSessions(args?: RequestArgs): Promise<GetMeSessionsResponse>;
849
+ /** POST /me/sessions/revoke — rank: any-builder */
850
+ postMeSessionsRevoke(args?: RequestArgs & { body?: PostMeSessionsRevokeRequest }): Promise<PostMeSessionsRevokeResponse>;
851
+ /** POST /me/sessions/revoke-all — rank: any-builder */
852
+ postMeSessionsRevokeAll(args?: RequestArgs): Promise<PostMeSessionsRevokeAllResponse>;
820
853
  /** GET /me/skill-prefs — rank: any-builder */
821
854
  getMeSkillPrefs(args?: RequestArgs): Promise<GetMeSkillPrefsResponse>;
822
855
  /** PATCH /me/skill-prefs — rank: any-builder */
@@ -260,6 +260,22 @@ export function createClient(opts = {}) {
260
260
  // GET /closeness/with/{builderId} — rank: any-builder — GET /closeness/with/:builderId
261
261
  getClosenessWithBuilderId: (args) => request("GET", "/closeness/with/{builderId}", { hasBody: false }, args),
262
262
  },
263
+ "connections": {
264
+ // GET /connections — rank: any-builder — GET /connections
265
+ getConnections: (args) => request("GET", "/connections", { hasBody: false }, args),
266
+ // POST /connections — rank: any-builder — POST /connections
267
+ postConnections: (args) => request("POST", "/connections", { hasBody: true }, args),
268
+ // DELETE /connections/{id} — rank: any-builder — DELETE /connections/:id
269
+ deleteConnectionsId: (args) => request("DELETE", "/connections/{id}", { hasBody: false }, args),
270
+ // POST /connections/{id}/accept — rank: any-builder — POST /connections/:id/accept
271
+ postConnectionsIdAccept: (args) => request("POST", "/connections/{id}/accept", { hasBody: true }, args),
272
+ // POST /connections/{id}/decline — rank: any-builder — POST /connections/:id/decline
273
+ postConnectionsIdDecline: (args) => request("POST", "/connections/{id}/decline", { hasBody: true }, args),
274
+ // GET /connections/degree/{handle} — rank: any-builder — GET /connections/degree/:handle
275
+ getConnectionsDegreeHandle: (args) => request("GET", "/connections/degree/{handle}", { hasBody: false }, args),
276
+ // GET /connections/requests — rank: any-builder — GET /connections/requests
277
+ getConnectionsRequests: (args) => request("GET", "/connections/requests", { hasBody: false }, args),
278
+ },
263
279
  "copyDesk": {
264
280
  // POST /copy-desk/flags — rank: any-builder — POST /copy-desk/flags
265
281
  postCopyDeskFlags: (args) => request("POST", "/copy-desk/flags", { hasBody: true }, args),
@@ -519,6 +535,12 @@ export function createClient(opts = {}) {
519
535
  getMeRender: (args) => request("GET", "/me/render", { hasBody: false }, args),
520
536
  // PATCH /me/render — rank: any-builder — PATCH /me/render
521
537
  patchMeRender: (args) => request("PATCH", "/me/render", { hasBody: true }, args),
538
+ // GET /me/sessions — rank: any-builder — GET /me/sessions
539
+ getMeSessions: (args) => request("GET", "/me/sessions", { hasBody: false }, args),
540
+ // POST /me/sessions/revoke — rank: any-builder — POST /me/sessions/revoke
541
+ postMeSessionsRevoke: (args) => request("POST", "/me/sessions/revoke", { hasBody: true }, args),
542
+ // POST /me/sessions/revoke-all — rank: any-builder — POST /me/sessions/revoke-all
543
+ postMeSessionsRevokeAll: (args) => request("POST", "/me/sessions/revoke-all", { hasBody: true }, args),
522
544
  // GET /me/skill-prefs — rank: any-builder — GET /me/skill-prefs
523
545
  getMeSkillPrefs: (args) => request("GET", "/me/skill-prefs", { hasBody: false }, args),
524
546
  // PATCH /me/skill-prefs — rank: any-builder — PATCH /me/skill-prefs
@@ -0,0 +1,59 @@
1
+ # 0206 — A leaked bearer's remedy is the account holder's own revoke, not an absolute session ceiling
2
+
3
+ - **Status:** Accepted
4
+ - **Date:** 2026-08-29
5
+ - **Deciders:** Claude, building the own-scoped half of the session self-service. The ceiling question is the one the task named as "worth a decision either way".
6
+ - **Task:** task 1003341 (goal 1000045 — public builder profiles + account security, criterion `i-control-my-own-access-and-exposure`)
7
+ - **Interacts with:** [ADR 0016](<redacted>.md) (the DB enforces; a session is checked fresh per request, never cached), [ADR 0053](0053-scoped-dev-box-session.md) / [ADR 0151](<redacted>.md) §3 (the session-scope registry — scope is capability on the token, orthogonal to rank), migration `<redacted>.sql` (the 24h TTL + refresh-on-use it introduced, and the deliberate backfill grace that came with it).
8
+
9
+ ## Context
10
+
11
+ `db-kernel.js lookupSession` rewrites `expires_at = now() + 24h` on every authenticated request. That is refresh-on-use, and for a session in daily use it means the TTL never arrives: a CLI bearer sitting in `~/.config/otb/gds-session.json` is, in practice, immortal. If it leaks — committed to a repo, left on a shared dev box, copied off a stolen laptop — the holder keeps it alive simply by using it.
12
+
13
+ Until this task the account holder had no remedy of their own. `POST /auth/logout` revokes only the token presented on that same request, which is useless when the token you want dead is the one you no longer hold. The two endpoints that can kill somebody else's session — `POST /auth/revoke` and `POST /auth/revoke-all` — are gated on the admin `auth.session.revoke` atom, so the victim had to find an Archon and ask. On a self-hosted single-owner instance there may be no second Archon at all, which makes the remedy not merely slow but absent.
14
+
15
+ Two different fixes were on the table, and it matters that they are not the same fix:
16
+
17
+ 1. **Give the holder the remedy.** List your own live sessions, kill one, or sign out everywhere — no rank, no permission, no intermediary.
18
+ 2. **Cap the sliding window.** Stop `expires_at` at some absolute distance from `created_at`, so every session dies eventually whether anybody notices or not.
19
+
20
+ ## Decision
21
+
22
+ **Ship (1). Do not ship (2) — for now, and for stated reasons rather than by omission.**
23
+
24
+ The own-scoped routes land as `GET /me/sessions`, `POST /me/sessions/revoke` and `POST /me/sessions/revoke-all`, in their own file (`src/bongos/routes/my-sessions.js`), gated on `requireBuilder` alone. Every statement they issue carries `builder_id = <the caller's own id>`, taken from the session the caller presented and never from the query string, the body or the path. `revoke-all` deliberately includes the session making the request: this is the button somebody presses when they believe a token has leaked, and a sweep that spared one session would leave them wondering which. The token value is never selected, never logged and never returned.
25
+
26
+ **Why no absolute ceiling.** A ceiling and a revoke are aimed at different things, and only one of them was the gap:
27
+
28
+ - A ceiling is **unconditional**: it signs out every builder, every dev box, every long-running autonomous session on a timer, whether or not anything has gone wrong. Migration 035 already met this problem once, in the small — it backfilled a 24h grace *specifically* so the migration would not kill the session running it — and a ceiling reintroduces that class of breakage permanently rather than once.
29
+ - A ceiling is **slow where it matters**: any cap loose enough not to be a daily nuisance (30 days, 90 days) leaves a leaked token live for weeks. The victim who knows their token leaked does not want it to expire eventually; they want it dead now. That is exactly what (1) gives them, in one request.
30
+ - A ceiling has **no owner-visible upside** once (1) exists. Its remaining value is against a leak nobody ever notices — real, but strictly weaker than the visibility this task also ships: the list surfaces `created_at` beside `last_used_at`, so a session that has been alive for three months is now something a person can *see* and act on, which is the compounding half of the fix.
31
+ - Rank changes already do the sweeping a ceiling would do. `setBuilderRank` calls `revokeAllSessionsForBuilder` on any demotion, and `requireBuilder` denies a deactivated builder on the hot path regardless of a live token, so the authority-drift case a ceiling is often justified by is already closed by other means.
32
+
33
+ The ceiling stays deliberately unbuilt, not forgotten. What would change the answer is stated below.
34
+
35
+ ### Rejected
36
+
37
+ - **An absolute `created_at + N` cap now.** Breaks every long-lived box and autonomous session on a timer for a threat the revoke answers faster; and any N large enough to be tolerable is too large to be a remedy.
38
+ - **A shorter TTL.** Same objection, worse: it punishes ordinary use continuously and still does nothing the moment a token is in someone else's hands.
39
+ - **Three more routes inside `routes/auth.js`.** That file is the largest in `src/bongos/routes/` and its admin pair legitimately reads a caller-named target from the request body. Keeping the own-scoped half separate is what lets `tests/own_session_revoke.mjs` assert the no-caller-named-owner rule over a whole file, with no carve-out for a neighbour to hide behind.
40
+ - **A `keep_current` flag on revoke-all.** Configurability nobody asked for: somebody who wants to keep one session revokes the others individually — the list marks which one is current.
41
+ - **404 on a session id that is not yours.** It would confirm which ids exist. A miss answers `revoked: 0`, identically to an id that never existed.
42
+ - **Lowering the `auth.session.revoke` floor instead.** That widens an admin atom to reach *other people's* sessions, which is the opposite of what a self-serve remedy needs.
43
+
44
+ ## Consequences
45
+
46
+ - A builder at any rank — `xenos` included — can see and kill their own sessions without an Archon. The cross-builder admin pair is untouched and still permission-gated; this is an addition, not a replacement.
47
+ - A session in continuous use still never expires on its own. That is now a *visible* property (the list shows how old each session is) with a one-click remedy, rather than an invisible one with no remedy.
48
+ - The three routes are pinned to `any-builder` in `EXPECTED_RANKS`, so both a later rank gate *and* a later widening to public fail the route-rank auditor loudly.
49
+ - The hall's Settings page grows an "Active sessions" panel with a per-session revoke and a "Sign out everywhere" button. Signing out everywhere from the browser ends that browser session too, so the page sends the builder back to sign-in.
50
+
51
+ ## When to revisit
52
+
53
+ Add the ceiling if any of these become true:
54
+
55
+ - Instances start issuing sessions to principals that cannot be asked to notice a leak (machine identities, embedded devices) — those want a cap, because nobody is watching the list.
56
+ - A compliance or hosting requirement names a maximum session age.
57
+ - The session list shows, in practice, that long-lived sessions accumulate faster than people prune them — i.e. the visibility half of this decision turns out not to work.
58
+
59
+ If it is added, it belongs on `created_at` (a true ceiling), not on the TTL, and it needs the same grace treatment migration 035 gave the 24h TTL, or it will sign out the session that deploys it.