@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.
- package/.bongos-core.json +87 -32
- package/clients/bongos-client/README.md +1 -1
- package/clients/bongos-client/bongos-client.global.js +22 -0
- package/clients/bongos-client/index.cjs +22 -0
- package/clients/bongos-client/index.d.ts +33 -0
- package/clients/bongos-client/index.mjs +22 -0
- package/docs/adr/0206-own-scoped-session-revocation-no-absolute-ceiling.md +59 -0
- package/docs/adr/0207-connections-implementation-departures-and-honest-limits.md +90 -0
- package/docs/adr/README.md +2 -0
- package/docs/api/openapi.json +599 -3
- package/docs/api-reference.md +17 -2
- package/docs/architecture.md +1 -0
- package/docs/copy-inventory.md +51 -36
- package/docs/copy-registry.json +175 -40
- 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 +22 -0
- package/modules/hall-ui/public/settings-sessions.js +119 -0
- package/modules/hall-ui/public/settings.css +25 -0
- package/modules/hall-ui/public/settings.html +22 -0
- package/modules/platform-identity/account-visibility.js +58 -0
- package/modules/platform-identity/connections.js +490 -0
- package/modules/platform-identity/migrations/platform_identity_015_connections.sql +78 -0
- package/modules/platform-identity/module.json +1 -1
- package/modules/platform-identity/routes/connections.js +236 -0
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/src/bongos/db.js +46 -0
- package/src/bongos/route-rank-check.js +10 -0
- package/src/bongos/routes/my-sessions.js +128 -0
- package/src/bongos/routes.js +5 -0
- package/src/module-api.js +1 -1
- package/tests/connections_api.mjs +568 -0
- package/tests/connections_ownership.mjs +313 -0
- package/tests/own_scope_guard.mjs +10 -0
- 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.
|
|
6
|
-
"core_contract": "1.19.
|
|
7
|
-
"source_commit": "
|
|
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-
|
|
9
|
+
"built_at": "2026-08-29T17:21:12.343Z",
|
|
10
10
|
"redaction": {
|
|
11
11
|
"model": "docs-redacted+functional-verbatim",
|
|
12
|
-
"docs_redacted":
|
|
12
|
+
"docs_redacted": 358,
|
|
13
13
|
"agent_docs_stubbed": 23,
|
|
14
|
-
"functional_verbatim":
|
|
14
|
+
"functional_verbatim": 1710,
|
|
15
15
|
"rules": 3,
|
|
16
16
|
"gate_literals": 3,
|
|
17
17
|
"gate": "passed"
|
|
18
18
|
},
|
|
19
|
-
"file_count":
|
|
20
|
-
"tree_sha256": "
|
|
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": "
|
|
355
|
+
"sha256": "d80581bbcb2577fe16cba30d6e0e1ff4ede4ca49dd08c306d1a3bcbfdf1d2cdc"
|
|
356
356
|
},
|
|
357
357
|
{
|
|
358
358
|
"path": "clients/bongos-client/bongos-client.global.js",
|
|
359
359
|
"mode": "0000644",
|
|
360
|
-
"sha256": "
|
|
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": "
|
|
370
|
+
"sha256": "b11537927f1268e2e14d8307589fe2eb58ef01e245556decd0251efc17f707d3"
|
|
371
371
|
},
|
|
372
372
|
{
|
|
373
373
|
"path": "clients/bongos-client/index.d.ts",
|
|
374
374
|
"mode": "0000644",
|
|
375
|
-
"sha256": "
|
|
375
|
+
"sha256": "227105130a432d4e7a294b4359455e022beaaac87bcd4014855d9d34e2faeaf4"
|
|
376
376
|
},
|
|
377
377
|
{
|
|
378
378
|
"path": "clients/bongos-client/index.mjs",
|
|
379
379
|
"mode": "0000644",
|
|
380
|
-
"sha256": "
|
|
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": "
|
|
1545
|
+
"sha256": "0f92a7a74afdf213a1aba92da88ea5348878ba0df67c3fc9e33d06b8f7ebade9"
|
|
1536
1546
|
},
|
|
1537
1547
|
{
|
|
1538
1548
|
"path": "docs/api-reference.md",
|
|
1539
1549
|
"mode": "0000644",
|
|
1540
|
-
"sha256": "
|
|
1550
|
+
"sha256": "e58b3d540eeaa8f38e028c72e64f4a2373c16c4c185edabc2d2538d247da9a29"
|
|
1541
1551
|
},
|
|
1542
1552
|
{
|
|
1543
1553
|
"path": "docs/api/openapi.json",
|
|
1544
1554
|
"mode": "0000644",
|
|
1545
|
-
"sha256": "
|
|
1555
|
+
"sha256": "091c9eecdbec83a540fc5d92017525dfdfdf192604b39d8cf60ec2cfb3466819"
|
|
1546
1556
|
},
|
|
1547
1557
|
{
|
|
1548
1558
|
"path": "docs/architecture.md",
|
|
1549
1559
|
"mode": "0000644",
|
|
1550
|
-
"sha256": "
|
|
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": "
|
|
1580
|
+
"sha256": "3e70beb03c93a71f5068c407467deeeca3c69d5271372de04399a9094fa32dd9"
|
|
1571
1581
|
},
|
|
1572
1582
|
{
|
|
1573
1583
|
"path": "docs/copy-registry.json",
|
|
1574
1584
|
"mode": "0000644",
|
|
1575
|
-
"sha256": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
4165
|
+
"sha256": "d50ac6727dde53e91aef8daa5ce759edcc69924e43b786103800892d9b87fe4d"
|
|
4151
4166
|
},
|
|
4152
4167
|
{
|
|
4153
4168
|
"path": "modules/hall-ui/public/settings.html",
|
|
4154
4169
|
"mode": "0000644",
|
|
4155
|
-
"sha256": "
|
|
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": "
|
|
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": "
|
|
5470
|
+
"sha256": "9bcfa46cd421336fba313885ceb399c9f025a85f5c07759abdb9d653bbd34105"
|
|
5436
5471
|
},
|
|
5437
5472
|
{
|
|
5438
5473
|
"path": "package.json",
|
|
5439
5474
|
"mode": "0000644",
|
|
5440
|
-
"sha256": "
|
|
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": "
|
|
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": "
|
|
7455
|
+
"sha256": "96b884a69b7b709a256d220c97a972f9827d74a36a864c216a7b37db3fdf66be"
|
|
7421
7456
|
},
|
|
7422
7457
|
{
|
|
7423
7458
|
"path": "src/bongos/routes.js",
|
|
7424
7459
|
"mode": "0000644",
|
|
7425
|
-
"sha256": "
|
|
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": "
|
|
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": "
|
|
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
|
-
-
|
|
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.
|