@bongos/core 1.19.171 → 1.19.173

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 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.171",
6
- "core_contract": "1.19.171",
7
- "source_commit": "d102a0205fd62edcc81a804a8c439af4cde60606",
5
+ "core_version": "1.19.173",
6
+ "core_contract": "1.19.173",
7
+ "source_commit": "dfc63944c504d88bf4ebb93b033c06b7b3b472a7",
8
8
  "source_ref": "HEAD",
9
- "built_at": "2026-08-16T19:20:36.950Z",
9
+ "built_at": "2026-08-16T19:48:53.327Z",
10
10
  "redaction": {
11
11
  "model": "docs-redacted+functional-verbatim",
12
12
  "docs_redacted": 305,
13
13
  "agent_docs_stubbed": 21,
14
- "functional_verbatim": 1269,
14
+ "functional_verbatim": 1272,
15
15
  "rules": 3,
16
16
  "gate_literals": 3,
17
17
  "gate": "passed"
18
18
  },
19
- "file_count": 1595,
20
- "tree_sha256": "1596294ffbb9fe146a18ced51823d4b074c23b5dd47601619bcd16752c5eaf04",
19
+ "file_count": 1598,
20
+ "tree_sha256": "ac7b1f942e74709cb79d331fe15d21c4fcfdb8c30c8f0d88fd199404d06462b1",
21
21
  "files": [
22
22
  {
23
23
  "path": ".claude/skills/blocker-review/SKILL.md",
@@ -347,12 +347,12 @@
347
347
  {
348
348
  "path": "clients/bongos-client/README.md",
349
349
  "mode": "0000644",
350
- "sha256": "d6d6163164f98c96a8e25dfe84825669bf8324f1f1b98adb0674781ad235ad10"
350
+ "sha256": "6b865314ad2d5e2e3e0e017a6bed7ae435ecfbca3859bdf763b59411a1d3d9f8"
351
351
  },
352
352
  {
353
353
  "path": "clients/bongos-client/bongos-client.global.js",
354
354
  "mode": "0000644",
355
- "sha256": "386706d0ef3d09c5e074bdc45bfc0de869d732eb1cb2a2280472f02f797f2b74"
355
+ "sha256": "c137a0e79a5e9065b071f87150639bff98cbda8f0d50a27027b42fa48ae200f6"
356
356
  },
357
357
  {
358
358
  "path": "clients/bongos-client/examples/hello-world.mjs",
@@ -362,17 +362,17 @@
362
362
  {
363
363
  "path": "clients/bongos-client/index.cjs",
364
364
  "mode": "0000644",
365
- "sha256": "7d462b5b80c9db9159981406398fc62c5ba71043c6a3b9433852d06d612bf2b0"
365
+ "sha256": "2fef3ad1be5b853de1d6df155bb5717b581cf8b6afa3851add9ea81032c159a6"
366
366
  },
367
367
  {
368
368
  "path": "clients/bongos-client/index.d.ts",
369
369
  "mode": "0000644",
370
- "sha256": "4acb1dde6f894ba37cff7e27e0110f12ae30c7cb6e4d972d6e85d2877489b6d0"
370
+ "sha256": "52dbea93e7039796ebf579e816bd3ed54727077e5383d27a348d36572a85b90d"
371
371
  },
372
372
  {
373
373
  "path": "clients/bongos-client/index.mjs",
374
374
  "mode": "0000644",
375
- "sha256": "4c7679ef258644ab12db1b8fe412b388f96f4296c6aae45d6ab637a8f3b9a037"
375
+ "sha256": "b2d21163a9fb149a98051dfde08e1cee81969194e74d3e272bb7779da9461c1b"
376
376
  },
377
377
  {
378
378
  "path": "clients/bongos-client/package.json",
@@ -1347,12 +1347,12 @@
1347
1347
  {
1348
1348
  "path": "docs/api-reference.md",
1349
1349
  "mode": "0000644",
1350
- "sha256": "ccf59372e0456f36d83154d6dff4dbf5382e8d69023bee82b318b8e9cfb2c50b"
1350
+ "sha256": "74ee845dae6f2757b564c1a760042391f3eb3af21dd3abe4a8590b3c3f88c4b3"
1351
1351
  },
1352
1352
  {
1353
1353
  "path": "docs/api/openapi.json",
1354
1354
  "mode": "0000644",
1355
- "sha256": "4deac83a1d7c12e1a24109e856d9a6fef6b539afafdca55a525ab6786fe4e235"
1355
+ "sha256": "1c8b42344fa248bd6e38d370cc117c5017fdd58071ba9cb2ca6e55a1678c5e56"
1356
1356
  },
1357
1357
  {
1358
1358
  "path": "docs/architecture.md",
@@ -2662,7 +2662,7 @@
2662
2662
  {
2663
2663
  "path": "modules/dev-box/app/src/vendor/bongos-client.cjs",
2664
2664
  "mode": "0000644",
2665
- "sha256": "7d462b5b80c9db9159981406398fc62c5ba71043c6a3b9433852d06d612bf2b0"
2665
+ "sha256": "2fef3ad1be5b853de1d6df155bb5717b581cf8b6afa3851add9ea81032c159a6"
2666
2666
  },
2667
2667
  {
2668
2668
  "path": "modules/dev-box/app/test/unit.mjs",
@@ -3789,15 +3789,20 @@
3789
3789
  "mode": "0000644",
3790
3790
  "sha256": "cce2f971f030aa628f9d7855f2e421595ea71cb314e90965206dbe970b7beded"
3791
3791
  },
3792
+ {
3793
+ "path": "modules/platform-identity/migrations/platform_identity_008_handle.sql",
3794
+ "mode": "0000644",
3795
+ "sha256": "f78eb8f7b6ee1ea3ddd789d6019b9715ae193ff0cb7890aeb24d8473033a911a"
3796
+ },
3792
3797
  {
3793
3798
  "path": "modules/platform-identity/module.json",
3794
3799
  "mode": "0000644",
3795
- "sha256": "e993fb26e61249bf89c0b0a5977c60e9d974810ffe1b67e94d909e8b52e00d5e"
3800
+ "sha256": "c4c02577f7318e994301bbe700e20dfb24519e411fee04539755f7374a73590b"
3796
3801
  },
3797
3802
  {
3798
3803
  "path": "modules/platform-identity/platform-identity.js",
3799
3804
  "mode": "0000644",
3800
- "sha256": "96907af1af78c472118ecf5ed9f269d6d2ce940b09535aae3b3df4de4d2337c1"
3805
+ "sha256": "59d9ef7d052890fdf09fd0a9f04432ab1baddc7c8dfe49950893b9dd67b89d66"
3801
3806
  },
3802
3807
  {
3803
3808
  "path": "modules/platform-identity/pollers/code-sweep.js",
@@ -3817,13 +3822,18 @@
3817
3822
  {
3818
3823
  "path": "modules/platform-identity/routes/profile.js",
3819
3824
  "mode": "0000644",
3820
- "sha256": "6ea29b4f07417fa925b7987dd7fbe8a0262b7fec83ceffade9fccbc220289bba"
3825
+ "sha256": "29e7f6304b4215fd79c35662c48370a04a5a9ffa2c3c4ae3d1fabf277d407eb2"
3821
3826
  },
3822
3827
  {
3823
3828
  "path": "modules/platform-identity/routes/projects.js",
3824
3829
  "mode": "0000644",
3825
3830
  "sha256": "a3e25369ad9edc6aed1a8a6997d6b6cb794dce14abb3605954d535525af1a93a"
3826
3831
  },
3832
+ {
3833
+ "path": "modules/platform-identity/routes/public-profile.js",
3834
+ "mode": "0000644",
3835
+ "sha256": "9032ff152e6440187f0f9bd2b1a3bb9ea24167c9f6d79ae3345a26a0e2fdc356"
3836
+ },
3827
3837
  {
3828
3838
  "path": "modules/platform-identity/routes/scouting.js",
3829
3839
  "mode": "0000644",
@@ -3837,7 +3847,7 @@
3837
3847
  {
3838
3848
  "path": "modules/platform-identity/tests/platform-identity.mjs",
3839
3849
  "mode": "0000644",
3840
- "sha256": "18bf8d0cb42d76bc5413c760b13837fe439a6e719b88a84db96f143b829e67d5"
3850
+ "sha256": "53b5bdd5c9eb4a14695289dd1396231d29e0f53c8709bd591dc328362da88072"
3841
3851
  },
3842
3852
  {
3843
3853
  "path": "modules/platform-identity/ui/.gitkeep",
@@ -4212,12 +4222,12 @@
4212
4222
  {
4213
4223
  "path": "package-lock.json",
4214
4224
  "mode": "0000644",
4215
- "sha256": "90e1fc07f655eb2874620b5a85f965e4f32cc20aeddb552dbc8885c4681150d9"
4225
+ "sha256": "6c8e9ca33aba6a1b42addf6f862daad54f2e0ba87a43090129a2afe23edc53e6"
4216
4226
  },
4217
4227
  {
4218
4228
  "path": "package.json",
4219
4229
  "mode": "0000644",
4220
- "sha256": "2b1408849261b93418e448820da8081a7ec83fa6b5c2a51b9e1aa5dca7456efb"
4230
+ "sha256": "1c163fb61de2b5c9024266f6b1bd494687307421fb05370874842e67639e0311"
4221
4231
  },
4222
4232
  {
4223
4233
  "path": "public-docs/index.html",
@@ -5822,7 +5832,7 @@
5822
5832
  {
5823
5833
  "path": "src/module-api.js",
5824
5834
  "mode": "0000644",
5825
- "sha256": "17202c8572c75ca1af5cd2eee1c8dd1ba4b6ea4c5fd7cd757eaf97907d26a268"
5835
+ "sha256": "479f80926d0dfcd56bfb6b47dfe8fac208ce8ce3c873e6a016c4af0e5f015edd"
5826
5836
  },
5827
5837
  {
5828
5838
  "path": "src/module-loader/catalog.js",
@@ -6904,6 +6914,11 @@
6904
6914
  "mode": "0000644",
6905
6915
  "sha256": "82bf1cc68150c247c108308d360d6408511f31a7af11d5e7a4721e7ea282f2bb"
6906
6916
  },
6917
+ {
6918
+ "path": "tests/handle_machinery.mjs",
6919
+ "mode": "0000644",
6920
+ "sha256": "a86e615af8b148572abf562b3c7b0d556076286e76e2d8d576f782a90ba3d457"
6921
+ },
6907
6922
  {
6908
6923
  "path": "tests/helpers.mjs",
6909
6924
  "mode": "0000644",
@@ -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
- - 273 operations across 45 resource groups
8
+ - 275 operations across 46 resource groups
9
9
 
10
10
  ## Install
11
11
 
@@ -423,6 +423,8 @@ function createClient(opts = {}) {
423
423
  getMeEventSoundPrefs: (args) => request("GET", "/me/event-sound-prefs", { hasBody: false }, args),
424
424
  // PATCH /me/event-sound-prefs — rank: any-builder — PATCH /me/event-sound-prefs
425
425
  patchMeEventSoundPrefs: (args) => request("PATCH", "/me/event-sound-prefs", { hasBody: true }, args),
426
+ // PATCH /me/handle — rank: any-builder — PATCH /me/handle
427
+ patchMeHandle: (args) => request("PATCH", "/me/handle", { hasBody: true }, args),
426
428
  // GET /me/interaction — rank: any-builder — GET /me/interaction
427
429
  getMeInteraction: (args) => request("GET", "/me/interaction", { hasBody: false }, args),
428
430
  // PATCH /me/interaction — rank: any-builder — PATCH /me/interaction
@@ -500,6 +502,10 @@ function createClient(opts = {}) {
500
502
  // POST /override-requests/{id}/decide — rank: metic+archon — POST /override-requests/:id/decide
501
503
  postOverrideRequestsIdDecide: (args) => request("POST", "/override-requests/{id}/decide", { hasBody: true }, args),
502
504
  },
505
+ "profiles": {
506
+ // GET /profiles/{handle} — rank: public — GET /profiles/:handle
507
+ getProfilesHandle: (args) => request("GET", "/profiles/{handle}", { hasBody: false }, args),
508
+ },
503
509
  "projects": {
504
510
  // GET /projects — rank: metic+archon — GET /projects
505
511
  getProjects: (args) => request("GET", "/projects", { hasBody: false }, args),
@@ -422,6 +422,8 @@ function createClient(opts = {}) {
422
422
  getMeEventSoundPrefs: (args) => request("GET", "/me/event-sound-prefs", { hasBody: false }, args),
423
423
  // PATCH /me/event-sound-prefs — rank: any-builder — PATCH /me/event-sound-prefs
424
424
  patchMeEventSoundPrefs: (args) => request("PATCH", "/me/event-sound-prefs", { hasBody: true }, args),
425
+ // PATCH /me/handle — rank: any-builder — PATCH /me/handle
426
+ patchMeHandle: (args) => request("PATCH", "/me/handle", { hasBody: true }, args),
425
427
  // GET /me/interaction — rank: any-builder — GET /me/interaction
426
428
  getMeInteraction: (args) => request("GET", "/me/interaction", { hasBody: false }, args),
427
429
  // PATCH /me/interaction — rank: any-builder — PATCH /me/interaction
@@ -499,6 +501,10 @@ function createClient(opts = {}) {
499
501
  // POST /override-requests/{id}/decide — rank: metic+archon — POST /override-requests/:id/decide
500
502
  postOverrideRequestsIdDecide: (args) => request("POST", "/override-requests/{id}/decide", { hasBody: true }, args),
501
503
  },
504
+ "profiles": {
505
+ // GET /profiles/{handle} — rank: public — GET /profiles/:handle
506
+ getProfilesHandle: (args) => request("GET", "/profiles/{handle}", { hasBody: false }, args),
507
+ },
502
508
  "projects": {
503
509
  // GET /projects — rank: metic+archon — GET /projects
504
510
  getProjects: (args) => request("GET", "/projects", { hasBody: false }, args),
@@ -51,7 +51,7 @@ export interface GetInboxResponse { ideas: unknown; open_count: unknown }
51
51
  export interface GetLeaderboardResponse { leaderboard: unknown; page: unknown }
52
52
  export interface GetLearningsResponse { learnings: unknown }
53
53
  export interface GetMeAchievementsResponse { unlocked: unknown }
54
- export interface GetMeCrossProjectResponse { hide_stats: boolean; profile_state: unknown; cross_project: unknown }
54
+ export interface GetMeCrossProjectResponse { hide_stats: boolean; profile_state: unknown; handle: unknown; cross_project: unknown }
55
55
  export interface GetMeDisplayNameResponse { display_name: unknown; max_length: unknown }
56
56
  export interface GetMeEventSoundPrefsResponse { prefs: unknown; effective: unknown; effective_wav: unknown; events: unknown }
57
57
  export interface GetMeRecentShipsResponse { ships: unknown }
@@ -68,6 +68,7 @@ export interface GetModulesSubmissionsResponse { submissions: unknown }
68
68
  export interface GetMyProjectsInvitesResponse { invites: unknown }
69
69
  export interface GetMyProjectsResponse { owned: unknown; building: unknown }
70
70
  export interface GetOverrideRequestsResponse { requests: unknown }
71
+ export interface GetProfilesHandleResponse { account: unknown; cross_project: unknown }
71
72
  export interface GetProjectsFeaturedResponse { projects: unknown }
72
73
  export interface GetProjectsResponse { projects: unknown }
73
74
  export interface GetProvisioningFleetResponse { instances: unknown }
@@ -131,6 +132,8 @@ export interface PatchMeDisciplinesRequest { preferred_disciplines: string[] }
131
132
  export interface PatchMeDisciplinesResponse { builder: unknown; onboarding: unknown }
132
133
  export interface PatchMeDisplayNameResponse { display_name: unknown; max_length: unknown }
133
134
  export interface PatchMeEventSoundPrefsResponse { prefs: unknown; effective: unknown; effective_wav: unknown; events: unknown }
135
+ export interface PatchMeHandleRequest { handle: string }
136
+ export interface PatchMeHandleResponse { handle: unknown; previous_handle: unknown }
134
137
  export interface PatchMeSkillPrefsResponse { prefs: unknown; effective: unknown; defaults: unknown; known_skills: unknown; allowed_models: unknown }
135
138
  export interface PatchMeSoundPrefsResponse { prefs: unknown; effective: unknown; effective_map: unknown; volume: unknown; defaults: unknown; known_sounds: unknown }
136
139
  export interface PatchProjectsIdFeaturedRequest { featured: boolean }
@@ -662,6 +665,8 @@ export interface BongosClient {
662
665
  getMeEventSoundPrefs(args?: RequestArgs): Promise<GetMeEventSoundPrefsResponse>;
663
666
  /** PATCH /me/event-sound-prefs — rank: any-builder */
664
667
  patchMeEventSoundPrefs(args?: RequestArgs): Promise<PatchMeEventSoundPrefsResponse>;
668
+ /** PATCH /me/handle — rank: any-builder */
669
+ patchMeHandle(args: RequestArgs & { body: PatchMeHandleRequest }): Promise<PatchMeHandleResponse>;
665
670
  /** GET /me/interaction — rank: any-builder */
666
671
  getMeInteraction(args?: RequestArgs): Promise<ApiResponse>;
667
672
  /** PATCH /me/interaction — rank: any-builder */
@@ -739,6 +744,10 @@ export interface BongosClient {
739
744
  /** POST /override-requests/{id}/decide — rank: metic+archon */
740
745
  postOverrideRequestsIdDecide(args: RequestArgs & { body: PostOverrideRequestsIdDecideRequest }): Promise<ApiResponse>;
741
746
  };
747
+ "profiles": {
748
+ /** GET /profiles/{handle} — rank: public */
749
+ getProfilesHandle(args?: RequestArgs): Promise<GetProfilesHandleResponse>;
750
+ };
742
751
  "projects": {
743
752
  /** GET /projects — rank: metic+archon */
744
753
  getProjects(args?: RequestArgs): Promise<GetProjectsResponse>;
@@ -419,6 +419,8 @@ export function createClient(opts = {}) {
419
419
  getMeEventSoundPrefs: (args) => request("GET", "/me/event-sound-prefs", { hasBody: false }, args),
420
420
  // PATCH /me/event-sound-prefs — rank: any-builder — PATCH /me/event-sound-prefs
421
421
  patchMeEventSoundPrefs: (args) => request("PATCH", "/me/event-sound-prefs", { hasBody: true }, args),
422
+ // PATCH /me/handle — rank: any-builder — PATCH /me/handle
423
+ patchMeHandle: (args) => request("PATCH", "/me/handle", { hasBody: true }, args),
422
424
  // GET /me/interaction — rank: any-builder — GET /me/interaction
423
425
  getMeInteraction: (args) => request("GET", "/me/interaction", { hasBody: false }, args),
424
426
  // PATCH /me/interaction — rank: any-builder — PATCH /me/interaction
@@ -496,6 +498,10 @@ export function createClient(opts = {}) {
496
498
  // POST /override-requests/{id}/decide — rank: metic+archon — POST /override-requests/:id/decide
497
499
  postOverrideRequestsIdDecide: (args) => request("POST", "/override-requests/{id}/decide", { hasBody: true }, args),
498
500
  },
501
+ "profiles": {
502
+ // GET /profiles/{handle} — rank: public — GET /profiles/:handle
503
+ getProfilesHandle: (args) => request("GET", "/profiles/{handle}", { hasBody: false }, args),
504
+ },
499
505
  "projects": {
500
506
  // GET /projects — rank: metic+archon — GET /projects
501
507
  getProjects: (args) => request("GET", "/projects", { hasBody: false }, args),
@@ -157,6 +157,10 @@
157
157
  "name": "override-requests",
158
158
  "description": "Endpoints under `/api/bongos/override-requests`."
159
159
  },
160
+ {
161
+ "name": "profiles",
162
+ "description": "Endpoints under `/api/bongos/profiles`."
163
+ },
160
164
  {
161
165
  "name": "projects",
162
166
  "description": "Endpoints under `/api/bongos/projects`."
@@ -6575,6 +6579,55 @@
6575
6579
  ]
6576
6580
  }
6577
6581
  },
6582
+ "/me/handle": {
6583
+ "patch": {
6584
+ "operationId": "patch_me_handle",
6585
+ "tags": [
6586
+ "me"
6587
+ ],
6588
+ "summary": "PATCH /me/handle",
6589
+ "description": "rename the caller's OWN handle (own data, keyed on the authenticated github_id). Rules live in setAccountHandle: canonical form, reserved words refused, one rename per window, previous handle kept for the 301 window. Upsert-first (the setAccountHideStats precedent) so a hub builder who never federated can still claim a handle — never demotes consent.\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
6590
+ "x-rank": "any-builder",
6591
+ "x-source": "modules/platform-identity/routes/profile.js",
6592
+ "requestBody": {
6593
+ "required": true,
6594
+ "content": {
6595
+ "application/json": {
6596
+ "schema": {
6597
+ "$ref": "#/components/schemas/PatchMeHandleRequest"
6598
+ }
6599
+ }
6600
+ },
6601
+ "x-validated": true
6602
+ },
6603
+ "responses": {
6604
+ "200": {
6605
+ "description": "Success.",
6606
+ "content": {
6607
+ "application/json": {
6608
+ "schema": {
6609
+ "$ref": "#/components/schemas/PatchMeHandleResponse"
6610
+ }
6611
+ }
6612
+ }
6613
+ },
6614
+ "400": {
6615
+ "$ref": "#/components/responses/ValidationFailed"
6616
+ },
6617
+ "401": {
6618
+ "$ref": "#/components/responses/Unauthorized"
6619
+ },
6620
+ "403": {
6621
+ "$ref": "#/components/responses/Forbidden"
6622
+ }
6623
+ },
6624
+ "security": [
6625
+ {
6626
+ "builderSession": []
6627
+ }
6628
+ ]
6629
+ }
6630
+ },
6578
6631
  "/me/interaction": {
6579
6632
  "get": {
6580
6633
  "operationId": "get_me_interaction",
@@ -8114,6 +8167,48 @@
8114
8167
  ]
8115
8168
  }
8116
8169
  },
8170
+ "/profiles/{handle}": {
8171
+ "get": {
8172
+ "operationId": "get_profiles_handle",
8173
+ "tags": [
8174
+ "profiles"
8175
+ ],
8176
+ "summary": "GET /profiles/:handle",
8177
+ "description": "a handle-addressed public profile. Every field is already world-readable on the numeric profile route + the leaderboard; the handle is just the rename-proof address (spec Decision 3). Whitelisting happens inside the module (getPublicProfileByHandle); no-store because the payload embeds cross_project and hide must beat the cache (ADR 0171 D5).\n\n**Rank:** `public` — No authentication — any caller.",
8178
+ "x-rank": "public",
8179
+ "x-source": "modules/platform-identity/routes/public-profile.js",
8180
+ "parameters": [
8181
+ {
8182
+ "name": "handle",
8183
+ "in": "path",
8184
+ "required": true,
8185
+ "schema": {
8186
+ "type": "string"
8187
+ },
8188
+ "description": "Path parameter `handle`."
8189
+ }
8190
+ ],
8191
+ "responses": {
8192
+ "200": {
8193
+ "description": "Success.",
8194
+ "content": {
8195
+ "application/json": {
8196
+ "schema": {
8197
+ "$ref": "#/components/schemas/GetProfilesHandleResponse"
8198
+ }
8199
+ }
8200
+ }
8201
+ },
8202
+ "400": {
8203
+ "$ref": "#/components/responses/BadRequest"
8204
+ },
8205
+ "404": {
8206
+ "$ref": "#/components/responses/NotFound"
8207
+ }
8208
+ },
8209
+ "security": []
8210
+ }
8211
+ },
8117
8212
  "/projects": {
8118
8213
  "get": {
8119
8214
  "operationId": "get_projects",
@@ -12942,11 +13037,13 @@
12942
13037
  "type": "boolean"
12943
13038
  },
12944
13039
  "profile_state": {},
13040
+ "handle": {},
12945
13041
  "cross_project": {}
12946
13042
  },
12947
13043
  "required": [
12948
13044
  "hide_stats",
12949
13045
  "profile_state",
13046
+ "handle",
12950
13047
  "cross_project"
12951
13048
  ]
12952
13049
  },
@@ -13202,6 +13299,17 @@
13202
13299
  "requests"
13203
13300
  ]
13204
13301
  },
13302
+ "GetProfilesHandleResponse": {
13303
+ "type": "object",
13304
+ "properties": {
13305
+ "account": {},
13306
+ "cross_project": {}
13307
+ },
13308
+ "required": [
13309
+ "account",
13310
+ "cross_project"
13311
+ ]
13312
+ },
13205
13313
  "GetProjectsFeaturedResponse": {
13206
13314
  "type": "object",
13207
13315
  "properties": {
@@ -13984,6 +14092,31 @@
13984
14092
  "events"
13985
14093
  ]
13986
14094
  },
14095
+ "PatchMeHandleRequest": {
14096
+ "type": "object",
14097
+ "properties": {
14098
+ "handle": {
14099
+ "type": "string",
14100
+ "minLength": 1,
14101
+ "maxLength": 39
14102
+ }
14103
+ },
14104
+ "required": [
14105
+ "handle"
14106
+ ],
14107
+ "additionalProperties": false
14108
+ },
14109
+ "PatchMeHandleResponse": {
14110
+ "type": "object",
14111
+ "properties": {
14112
+ "handle": {},
14113
+ "previous_handle": {}
14114
+ },
14115
+ "required": [
14116
+ "handle",
14117
+ "previous_handle"
14118
+ ]
14119
+ },
13987
14120
  "PatchMeSkillPrefsResponse": {
13988
14121
  "type": "object",
13989
14122
  "properties": {
@@ -17222,9 +17355,9 @@
17222
17355
  "description": "A required dependency/feature is not configured or is temporarily down."
17223
17356
  }
17224
17357
  },
17225
- "x-endpoint-count": 273,
17226
- "x-schema-count": 306,
17358
+ "x-endpoint-count": 275,
17359
+ "x-schema-count": 309,
17227
17360
  "x-undocumented-bodies": 8,
17228
- "x-response-schemas": 207,
17361
+ "x-response-schemas": 209,
17229
17362
  "x-generated-by": "scripts/gds/gen-api-docs.js"
17230
17363
  }
@@ -2,7 +2,7 @@
2
2
 
3
3
  # Bongos API reference
4
4
 
5
- > **Generated from the live route files** — the route file is authoritative. 273 endpoints across 45 route files.
5
+ > **Generated from the live route files** — the route file is authoritative. 275 endpoints across 46 route files.
6
6
  > Machine-readable spec: [`docs/api/openapi.json`](api/openapi.json) (OpenAPI 3.1). Rendered docs site: **`/docs`** (e.g. `cloudbongos.com/docs`).
7
7
 
8
8
  Base path: `/api/bongos`. Ranks (enforced server-side, [ADR 0016](adr/<redacted>.md)): `public` < `any-builder` < `metic+archon` < `archon`.
@@ -282,7 +282,7 @@ Base path: `/api/bongos`. Ranks (enforced server-side, [ADR 0016](adr/<redacted>
282
282
  | POST | `/api/bongos/llm-cache/lookup` | `metic+archon` | `cache_key`, `tokens_saved_est` | POST /llm-cache/lookup — hit/miss + atomic hit_count bump. |
283
283
  | POST | `/api/bongos/llm-cache/store` | `metic+archon` | `spec`, `result_stdout`, `result_cost_usd` | POST /llm-cache/store — upsert a freshly-produced result. |
284
284
 
285
- ## `me` (23)
285
+ ## `me` (24)
286
286
 
287
287
  | Method | Path | Rank | Body | Description |
288
288
  |---|---|---|---|---|
@@ -296,6 +296,7 @@ Base path: `/api/bongos`. Ranks (enforced server-side, [ADR 0016](adr/<redacted>
296
296
  | PATCH | `/api/bongos/me/display-name` | `any-builder` | _undocumented_ | PATCH the display name. |
297
297
  | GET | `/api/bongos/me/event-sound-prefs` | `any-builder` | — | Per-builder per-event sound variant selection (task 582, migration 164). |
298
298
  | PATCH | `/api/bongos/me/event-sound-prefs` | `any-builder` | _undocumented_ | PATCH a partial set of event sound overrides. |
299
+ | PATCH | `/api/bongos/me/handle` | `any-builder` | `handle` | rename the caller's OWN handle (own data, keyed on the authenticated github_id). |
299
300
  | GET | `/api/bongos/me/interaction` | `any-builder` | — | Per-builder INTERACTION PROFILE (task 2010, shares the behavior_prefs jsonb / migration 119). |
300
301
  | PATCH | `/api/bongos/me/interaction` | `any-builder` | _undocumented_ | PATCH the interaction profile. |
301
302
  | GET | `/api/bongos/me/model-allocation` | `any-builder` | — | |
@@ -351,6 +352,12 @@ Base path: `/api/bongos`. Ranks (enforced server-side, [ADR 0016](adr/<redacted>
351
352
  | GET | `/api/bongos/override-requests` | `metic+archon` | — | GET /override-requests?status=open — Archon queue. |
352
353
  | POST | `/api/bongos/override-requests/:id/decide` | `metic+archon` | `decision`, `note` | POST /override-requests/:id/decide — body: { decision: 'approve'\|'deny', note? } On approve, atomically flips the task completed→confirme… |
353
354
 
355
+ ## `profiles` (1)
356
+
357
+ | Method | Path | Rank | Body | Description |
358
+ |---|---|---|---|---|
359
+ | GET | `/api/bongos/profiles/:handle` | `public` | — | a handle-addressed public profile. |
360
+
354
361
  ## `projects` (5)
355
362
 
356
363
  | Method | Path | Rank | Body | Description |
@@ -422,6 +422,8 @@ function createClient(opts = {}) {
422
422
  getMeEventSoundPrefs: (args) => request("GET", "/me/event-sound-prefs", { hasBody: false }, args),
423
423
  // PATCH /me/event-sound-prefs — rank: any-builder — PATCH /me/event-sound-prefs
424
424
  patchMeEventSoundPrefs: (args) => request("PATCH", "/me/event-sound-prefs", { hasBody: true }, args),
425
+ // PATCH /me/handle — rank: any-builder — PATCH /me/handle
426
+ patchMeHandle: (args) => request("PATCH", "/me/handle", { hasBody: true }, args),
425
427
  // GET /me/interaction — rank: any-builder — GET /me/interaction
426
428
  getMeInteraction: (args) => request("GET", "/me/interaction", { hasBody: false }, args),
427
429
  // PATCH /me/interaction — rank: any-builder — PATCH /me/interaction
@@ -499,6 +501,10 @@ function createClient(opts = {}) {
499
501
  // POST /override-requests/{id}/decide — rank: metic+archon — POST /override-requests/:id/decide
500
502
  postOverrideRequestsIdDecide: (args) => request("POST", "/override-requests/{id}/decide", { hasBody: true }, args),
501
503
  },
504
+ "profiles": {
505
+ // GET /profiles/{handle} — rank: public — GET /profiles/:handle
506
+ getProfilesHandle: (args) => request("GET", "/profiles/{handle}", { hasBody: false }, args),
507
+ },
502
508
  "projects": {
503
509
  // GET /projects — rank: metic+archon — GET /projects
504
510
  getProjects: (args) => request("GET", "/projects", { hasBody: false }, args),
@@ -0,0 +1,70 @@
1
+ -- platform_identity_008_handle.sql — the builder handle (P01, task 1002797 /
2
+ -- goal 1000045; profile-page spec Decision 3, ratified ADR 0171 D8).
3
+ --
4
+ -- The canonical profile URL must not hang on github_login: a login is mutable,
5
+ -- so every GitHub rename would silently 404 the builder's shared links. The
6
+ -- handle is presentation only — github_id stays the join key everywhere.
7
+ --
8
+ -- handle — unique case-insensitively; seeded from github_login.
9
+ -- previous_handle — the single-slot 301 window: kept on rename until the
10
+ -- next rename. R05's resolver 301s it to the current
11
+ -- handle (an exact current-handle match always wins).
12
+ -- handle_changed_at — set on RENAME only, never on seed; the low rate limit
13
+ -- reads it (one rename per window — setAccountHandle).
14
+ --
15
+ -- Seeding walks accounts oldest-first with exactly the go-forward JS algorithm
16
+ -- (ensureHandle in platform-identity.js): lowercase the login, strip anything
17
+ -- outside [a-z0-9-], trim hyphens; empty → builder-<github_id>; reserved or
18
+ -- taken → numeric suffix -2, -3, … . Sequential plpgsql on purpose: a set-based
19
+ -- ROW_NUMBER pass can manufacture collisions against its own suffixes (a
20
+ -- literal foo-2 login vs foo's second seed), and a failed prod migration costs
21
+ -- more than a slow loop over a small table. The reserved list below mirrors
22
+ -- RESERVED_HANDLES in platform-identity.js — keep them in lockstep.
23
+ --
24
+ -- Additive + platform_identity_-namespaced (ADR 0083 §5). Idempotent: the
25
+ -- handle IS NULL guard makes a re-run a no-op.
26
+
27
+ BEGIN;
28
+
29
+ ALTER TABLE platform_identity_accounts
30
+ ADD COLUMN IF NOT EXISTS handle text,
31
+ ADD COLUMN IF NOT EXISTS previous_handle text,
32
+ ADD COLUMN IF NOT EXISTS handle_changed_at timestamptz;
33
+
34
+ CREATE UNIQUE INDEX IF NOT EXISTS platform_identity_accounts_handle_uniq
35
+ ON platform_identity_accounts (lower(handle)) WHERE handle IS NOT NULL;
36
+
37
+ -- The 301-window lookup path (R05 resolves previous handles too).
38
+ CREATE INDEX IF NOT EXISTS platform_identity_accounts_prev_handle_idx
39
+ ON platform_identity_accounts (lower(previous_handle)) WHERE previous_handle IS NOT NULL;
40
+
41
+ DO $$
42
+ DECLARE
43
+ r RECORD;
44
+ base text;
45
+ cand text;
46
+ n int;
47
+ BEGIN
48
+ FOR r IN
49
+ SELECT github_id, github_login
50
+ FROM platform_identity_accounts
51
+ WHERE handle IS NULL
52
+ ORDER BY created_at, id
53
+ LOOP
54
+ base := trim(both '-' from regexp_replace(lower(coalesce(r.github_login, '')), '[^a-z0-9-]', '', 'g'));
55
+ IF base = '' THEN
56
+ base := 'builder-' || r.github_id;
57
+ END IF;
58
+ cand := base;
59
+ n := 1;
60
+ WHILE cand IN ('me', 'new', 'edit', 'settings', 'admin', 'api', 'u')
61
+ OR EXISTS (SELECT 1 FROM platform_identity_accounts WHERE lower(handle) = lower(cand))
62
+ LOOP
63
+ n := n + 1;
64
+ cand := base || '-' || n;
65
+ END LOOP;
66
+ UPDATE platform_identity_accounts SET handle = cand WHERE github_id = r.github_id;
67
+ END LOOP;
68
+ END $$;
69
+
70
+ COMMIT;
@@ -10,7 +10,7 @@
10
10
  "maintainer": "Cloud Bongos maintainers",
11
11
  "maintenance": { "status": "core-maintained" },
12
12
  "contributes": {
13
- "routes": ["sso", "projects", "my-projects", "scouting", "profile"],
13
+ "routes": ["sso", "projects", "my-projects", "scouting", "profile", "public-profile"],
14
14
  "migrations": true,
15
15
  "pollers": ["code-sweep"]
16
16
  },