@bongos/core 1.19.1026 → 1.19.1028

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 (39) hide show
  1. package/.bongos-core.json +77 -37
  2. package/clients/bongos-client/README.md +1 -1
  3. package/clients/bongos-client/bongos-client.global.js +38 -0
  4. package/clients/bongos-client/index.cjs +38 -0
  5. package/clients/bongos-client/index.d.ts +60 -0
  6. package/clients/bongos-client/index.mjs +38 -0
  7. package/docs/adr/0213-platform-terms-acceptance-is-the-hubs-own-witness.md +4 -2
  8. package/docs/api/openapi.json +1345 -182
  9. package/docs/api-reference.md +29 -2
  10. package/docs/copy-inventory.md +209 -201
  11. package/docs/copy-registry.json +329 -257
  12. package/docs/module-api-changelog.md +4 -0
  13. package/modules/hall-ui/public/builders.js +7 -4
  14. package/modules/platform-identity/connections.js +1 -0
  15. package/modules/platform-identity/guilds.js +705 -0
  16. package/modules/platform-identity/migrations/platform_identity_025_guilds.sql +100 -0
  17. package/modules/platform-identity/module.json +1 -1
  18. package/modules/platform-identity/read-rate-limit.js +3 -2
  19. package/modules/platform-identity/routes/guilds-public.js +57 -0
  20. package/modules/platform-identity/routes/guilds.js +393 -0
  21. package/modules/platform-identity/terms-acceptance.js +14 -5
  22. package/modules/public-landing/public/assets/cosmos.css +36 -0
  23. package/modules/public-landing/public/projects.html +229 -26
  24. package/modules/public-landing/public/terms.html +3 -3
  25. package/modules/ui-design/kit/fixtures/my-projects__invites.json +1 -0
  26. package/modules/ui-design/kit/serve.js +12 -1
  27. package/package-lock.json +2 -2
  28. package/package.json +1 -1
  29. package/scripts/gds/run-unit-tests.js +5 -0
  30. package/src/module-api.js +1 -1
  31. package/tests/card_apply_ui.mjs +8 -1
  32. package/tests/curve_controls_delegation.mjs +87 -0
  33. package/tests/guilds_api.mjs +521 -0
  34. package/tests/guilds_db.mjs +343 -0
  35. package/tests/my_projects_surface.mjs +26 -14
  36. package/tests/own_scope_guard.mjs +5 -0
  37. package/tests/public_landing_projects.mjs +40 -0
  38. package/tests/terms_acceptance.mjs +74 -28
  39. package/tests/terms_grandfather_db.mjs +2 -2
@@ -141,6 +141,14 @@
141
141
  "name": "grades",
142
142
  "description": "Endpoints under `/api/bongos/grades`."
143
143
  },
144
+ {
145
+ "name": "guild-requests",
146
+ "description": "Endpoints under `/api/bongos/guild-requests`."
147
+ },
148
+ {
149
+ "name": "guilds",
150
+ "description": "Endpoints under `/api/bongos/guilds`."
151
+ },
144
152
  {
145
153
  "name": "healthz",
146
154
  "description": "Endpoints under `/api/bongos/healthz`."
@@ -8276,51 +8284,34 @@
8276
8284
  ]
8277
8285
  }
8278
8286
  },
8279
- "/healthz": {
8280
- "get": {
8281
- "operationId": "get_healthz",
8287
+ "/guild-requests/{id}": {
8288
+ "delete": {
8289
+ "operationId": "delete_guild_requests_id",
8282
8290
  "tags": [
8283
- "healthz"
8291
+ "guild-requests"
8284
8292
  ],
8285
- "summary": "GET /healthz",
8286
- "description": "liveness probe; the status dashboard (status.<apex>) hits this anonymously.\n\n**Rank:** `public` — No authentication — any caller.",
8287
- "x-rank": "public",
8288
- "x-source": "src/bongos/routes/healthz.js",
8289
- "responses": {
8290
- "200": {
8291
- "description": "Success.",
8292
- "content": {
8293
- "application/json": {
8294
- "schema": {
8295
- "$ref": "#/components/schemas/GetHealthzResponse"
8296
- }
8297
- }
8298
- }
8299
- },
8300
- "400": {
8301
- "$ref": "#/components/responses/BadRequest"
8293
+ "summary": "DELETE /guild-requests/:id",
8294
+ "description": "cancel a row I opened: my request, or (as owner) an invite my guild sent.\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
8295
+ "x-rank": "any-builder",
8296
+ "x-source": "modules/platform-identity/routes/guilds.js",
8297
+ "parameters": [
8298
+ {
8299
+ "name": "id",
8300
+ "in": "path",
8301
+ "required": true,
8302
+ "schema": {
8303
+ "type": "string"
8304
+ },
8305
+ "description": "Path parameter `id`."
8302
8306
  }
8303
- },
8304
- "security": []
8305
- }
8306
- },
8307
- "/help-requests": {
8308
- "get": {
8309
- "operationId": "get_help_requests",
8310
- "tags": [
8311
- "help-requests"
8312
8307
  ],
8313
- "summary": "GET /help-requests",
8314
- "description": "The BOARD read (task 1003942): every open ask in the project, newest first, for the Collab page's \"all open asks\" block. rank: any-builder — an ask is addressed inside this project and every reader here is a member; the route takes no craft and no builder from the caller, so there is nothing to widen.\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
8315
- "x-rank": "any-builder",
8316
- "x-source": "modules/lifecycle/routes/help-requests.js",
8317
8308
  "responses": {
8318
8309
  "200": {
8319
8310
  "description": "Success.",
8320
8311
  "content": {
8321
8312
  "application/json": {
8322
8313
  "schema": {
8323
- "$ref": "#/components/schemas/GetHelpRequestsResponse"
8314
+ "$ref": "#/components/schemas/DeleteGuildRequestsIdResponse"
8324
8315
  }
8325
8316
  }
8326
8317
  }
@@ -8333,6 +8324,9 @@
8333
8324
  },
8334
8325
  "403": {
8335
8326
  "$ref": "#/components/responses/Forbidden"
8327
+ },
8328
+ "404": {
8329
+ "$ref": "#/components/responses/NotFound"
8336
8330
  }
8337
8331
  },
8338
8332
  "security": [
@@ -8340,22 +8334,35 @@
8340
8334
  "builderSession": []
8341
8335
  }
8342
8336
  ]
8343
- },
8337
+ }
8338
+ },
8339
+ "/guild-requests/{id}/accept": {
8344
8340
  "post": {
8345
- "operationId": "post_help_requests",
8341
+ "operationId": "post_guild_requests_id_accept",
8346
8342
  "tags": [
8347
- "help-requests"
8343
+ "guild-requests"
8348
8344
  ],
8349
- "summary": "POST /help-requests",
8350
- "description": "asking for help is not a privileged act, and gating it would exclude exactly the newcomers most likely to be stuck.\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
8345
+ "summary": "POST /guild-requests/:id/accept",
8346
+ "description": "accept an invite addressed to ME, or (as the guild's owner) a request to join it. An invite accept must echo the visibility its card showed; if the guild changed since, 409 and the card re-renders (ADR 0336 D4 §3). Any row the caller may not accept is 404.\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
8351
8347
  "x-rank": "any-builder",
8352
- "x-source": "modules/lifecycle/routes/help-requests.js",
8348
+ "x-source": "modules/platform-identity/routes/guilds.js",
8349
+ "parameters": [
8350
+ {
8351
+ "name": "id",
8352
+ "in": "path",
8353
+ "required": true,
8354
+ "schema": {
8355
+ "type": "string"
8356
+ },
8357
+ "description": "Path parameter `id`."
8358
+ }
8359
+ ],
8353
8360
  "requestBody": {
8354
- "required": true,
8361
+ "required": false,
8355
8362
  "content": {
8356
8363
  "application/json": {
8357
8364
  "schema": {
8358
- "$ref": "#/components/schemas/PostHelpRequestsRequest"
8365
+ "$ref": "#/components/schemas/PostGuildRequestsIdAcceptRequest"
8359
8366
  }
8360
8367
  }
8361
8368
  },
@@ -8367,7 +8374,7 @@
8367
8374
  "content": {
8368
8375
  "application/json": {
8369
8376
  "schema": {
8370
- "$ref": "#/components/schemas/PostHelpRequestsResponse"
8377
+ "$ref": "#/components/schemas/PostGuildRequestsIdAcceptResponse"
8371
8378
  }
8372
8379
  }
8373
8380
  }
@@ -8380,6 +8387,9 @@
8380
8387
  },
8381
8388
  "403": {
8382
8389
  "$ref": "#/components/responses/Forbidden"
8390
+ },
8391
+ "404": {
8392
+ "$ref": "#/components/responses/NotFound"
8383
8393
  }
8384
8394
  },
8385
8395
  "security": [
@@ -8389,26 +8399,30 @@
8389
8399
  ]
8390
8400
  }
8391
8401
  },
8392
- "/help-requests/archive": {
8393
- "get": {
8394
- "operationId": "get_help_requests_archive",
8402
+ "/guild-requests/{id}/decline": {
8403
+ "post": {
8404
+ "operationId": "post_guild_requests_id_decline",
8395
8405
  "tags": [
8396
- "help-requests"
8406
+ "guild-requests"
8397
8407
  ],
8398
- "summary": "GET /help-requests/archive",
8399
- "description": "THE ARCHIVE (task 1004224, owner direction): what a settled ask becomes. Until now a settled ask simply vanished from Collab. That was tolerable while settling meant a person had decided the ask was done — they knew. It stops being tolerable the moment the LEDGER settles asks on its own: a row can now leave the page without anybody having watched it go, and a surface that silently disappears its own history is asking to be distrusted. TWO LISTS, NOT ONE, and the split is the owner's: asks made OF YOU and asks you made OF OTHERS are different questions with different follow-ups, and a merged list would need a per-row label to say which it was — which is the same information, said worse. ONE ROUTE FOR BOTH. They share a settle, a bound and a shape, and the page draws them side by side in one section; two routes would be two round trips for one collapsed block and two places for the projection to drift. rank: any-builder, and the scoping matches the open reads exactly — you see what was addressed to you and what you asked, and nothing else. `crafts` comes from `builders.preferred_disciplines` through craftsForBuilder, NEVER from the query string. That is not caution: a ?craft= param validated only against the enum is precisely the hole C01's grader found on the open read, and an archive is the larger prize because it is the whole history rather than today's board. This route accepts no craft, no builder and no status from the caller, so there is nothing here to narrow or widen.\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
8408
+ "summary": "POST /guild-requests/:id/decline",
8409
+ "description": "decline an invite to ME, or (as owner) a request to my guild. SILENT: 204, and the other side is never told.\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
8400
8410
  "x-rank": "any-builder",
8401
- "x-source": "modules/lifecycle/routes/help-requests.js",
8411
+ "x-source": "modules/platform-identity/routes/guilds.js",
8412
+ "parameters": [
8413
+ {
8414
+ "name": "id",
8415
+ "in": "path",
8416
+ "required": true,
8417
+ "schema": {
8418
+ "type": "string"
8419
+ },
8420
+ "description": "Path parameter `id`."
8421
+ }
8422
+ ],
8402
8423
  "responses": {
8403
8424
  "200": {
8404
- "description": "Success.",
8405
- "content": {
8406
- "application/json": {
8407
- "schema": {
8408
- "$ref": "#/components/schemas/GetHelpRequestsArchiveResponse"
8409
- }
8410
- }
8411
- }
8425
+ "description": "Success."
8412
8426
  },
8413
8427
  "400": {
8414
8428
  "$ref": "#/components/responses/BadRequest"
@@ -8418,6 +8432,9 @@
8418
8432
  },
8419
8433
  "403": {
8420
8434
  "$ref": "#/components/responses/Forbidden"
8435
+ },
8436
+ "404": {
8437
+ "$ref": "#/components/responses/NotFound"
8421
8438
  }
8422
8439
  },
8423
8440
  "security": [
@@ -8427,29 +8444,40 @@
8427
8444
  ]
8428
8445
  }
8429
8446
  },
8430
- "/help-requests/for-me": {
8431
- "get": {
8432
- "operationId": "get_help_requests_for_me",
8447
+ "/guilds": {
8448
+ "post": {
8449
+ "operationId": "post_guilds",
8433
8450
  "tags": [
8434
- "help-requests"
8451
+ "guilds"
8435
8452
  ],
8436
- "summary": "GET /help-requests/for-me",
8437
- "description": "The addressed read — C01's answer to \"and fires a notification\". A request is immediately visible to the person or craft it names. A true PUSH lives in the builder-needs feed (`builder-settings`), which is outside this goal's scope wall, so it is recorded as a gap rather than reached for. rank: any-builder — you only ever see what is addressed to you.\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
8453
+ "summary": "POST /guilds",
8454
+ "description": "create a guild. The creator becomes its one owner, and chooses its visibility: there is no default (ADR 0336 D1).\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
8438
8455
  "x-rank": "any-builder",
8439
- "x-source": "modules/lifecycle/routes/help-requests.js",
8456
+ "x-source": "modules/platform-identity/routes/guilds.js",
8457
+ "requestBody": {
8458
+ "required": true,
8459
+ "content": {
8460
+ "application/json": {
8461
+ "schema": {
8462
+ "$ref": "#/components/schemas/PostGuildsRequest"
8463
+ }
8464
+ }
8465
+ },
8466
+ "x-validated": true
8467
+ },
8440
8468
  "responses": {
8441
8469
  "200": {
8442
8470
  "description": "Success.",
8443
8471
  "content": {
8444
8472
  "application/json": {
8445
8473
  "schema": {
8446
- "$ref": "#/components/schemas/GetHelpRequestsForMeResponse"
8474
+ "$ref": "#/components/schemas/PostGuildsResponse"
8447
8475
  }
8448
8476
  }
8449
8477
  }
8450
8478
  },
8451
8479
  "400": {
8452
- "$ref": "#/components/responses/BadRequest"
8480
+ "$ref": "#/components/responses/ValidationFailed"
8453
8481
  },
8454
8482
  "401": {
8455
8483
  "$ref": "#/components/responses/Unauthorized"
@@ -8465,23 +8493,34 @@
8465
8493
  ]
8466
8494
  }
8467
8495
  },
8468
- "/help-requests/mine": {
8496
+ "/guilds/{slug}": {
8469
8497
  "get": {
8470
- "operationId": "get_help_requests_mine",
8498
+ "operationId": "get_guilds_slug",
8471
8499
  "tags": [
8472
- "help-requests"
8500
+ "guilds"
8501
+ ],
8502
+ "summary": "GET /guilds/:slug",
8503
+ "description": "a public guild's page data. The roster is the members who agreed to be shown AND whose own accounts are publicly visible (ADR 0336 D4); size is that roster's length. no-store: a hide or a visibility flip must beat every cache (ADR 0171 D5).\n\n**Rank:** `public` — No authentication — any caller.",
8504
+ "x-rank": "public",
8505
+ "x-source": "modules/platform-identity/routes/guilds-public.js",
8506
+ "parameters": [
8507
+ {
8508
+ "name": "slug",
8509
+ "in": "path",
8510
+ "required": true,
8511
+ "schema": {
8512
+ "type": "string"
8513
+ },
8514
+ "description": "Path parameter `slug`."
8515
+ }
8473
8516
  ],
8474
- "summary": "GET /help-requests/mine",
8475
- "description": "your own asks, so you can settle them.\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
8476
- "x-rank": "any-builder",
8477
- "x-source": "modules/lifecycle/routes/help-requests.js",
8478
8517
  "responses": {
8479
8518
  "200": {
8480
8519
  "description": "Success.",
8481
8520
  "content": {
8482
8521
  "application/json": {
8483
8522
  "schema": {
8484
- "$ref": "#/components/schemas/GetHelpRequestsMineResponse"
8523
+ "$ref": "#/components/schemas/GetGuildsSlugResponse"
8485
8524
  }
8486
8525
  }
8487
8526
  }
@@ -8489,47 +8528,38 @@
8489
8528
  "400": {
8490
8529
  "$ref": "#/components/responses/BadRequest"
8491
8530
  },
8492
- "401": {
8493
- "$ref": "#/components/responses/Unauthorized"
8494
- },
8495
- "403": {
8496
- "$ref": "#/components/responses/Forbidden"
8531
+ "404": {
8532
+ "$ref": "#/components/responses/NotFound"
8497
8533
  }
8498
8534
  },
8499
- "security": [
8500
- {
8501
- "builderSession": []
8502
- }
8503
- ]
8504
- }
8505
- },
8506
- "/help-requests/{id}": {
8535
+ "security": []
8536
+ },
8507
8537
  "patch": {
8508
- "operationId": "patch_help_requests_id",
8538
+ "operationId": "patch_guilds_slug",
8509
8539
  "tags": [
8510
- "help-requests"
8540
+ "guilds"
8511
8541
  ],
8512
- "summary": "PATCH /help-requests/:id",
8513
- "description": "THE ASKER OR THE ADDRESSEE settles the request: 'answered' when it has been dealt with, 'withdrawn' when the asker no longer needs it. ADR 0330 widened 'answered' to the person the request NAMES — once a reply puts the answer on the row itself, an addressee who has answered in the open and still cannot close it is a surface arguing with itself. 'withdrawn' stays the asker's alone: only the person who needed something can say they no longer need it. Nobody is assigned by being asked — closing an ask ends a question, it does not accept work (ADR 0187 §3). rank: any-builder — who may settle is enforced in the UPDATE's WHERE, not by rank. The caller's crafts come from THEIR OWN profile, never from the body, for the same reason the addressed read refuses a ?craft= it was handed.\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
8542
+ "summary": "PATCH /guilds/:slug",
8543
+ "description": "owner: edit name, description or visibility. The slug is fixed at creation (ADR 0336 D6), so it is not a field here.\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
8514
8544
  "x-rank": "any-builder",
8515
- "x-source": "modules/lifecycle/routes/help-requests.js",
8545
+ "x-source": "modules/platform-identity/routes/guilds.js",
8516
8546
  "parameters": [
8517
8547
  {
8518
- "name": "id",
8548
+ "name": "slug",
8519
8549
  "in": "path",
8520
8550
  "required": true,
8521
8551
  "schema": {
8522
8552
  "type": "string"
8523
8553
  },
8524
- "description": "Path parameter `id`."
8554
+ "description": "Path parameter `slug`."
8525
8555
  }
8526
8556
  ],
8527
8557
  "requestBody": {
8528
- "required": true,
8558
+ "required": false,
8529
8559
  "content": {
8530
8560
  "application/json": {
8531
8561
  "schema": {
8532
- "$ref": "#/components/schemas/PatchHelpRequestsIdRequest"
8562
+ "$ref": "#/components/schemas/PatchGuildsSlugRequest"
8533
8563
  }
8534
8564
  }
8535
8565
  },
@@ -8541,7 +8571,7 @@
8541
8571
  "content": {
8542
8572
  "application/json": {
8543
8573
  "schema": {
8544
- "$ref": "#/components/schemas/PatchHelpRequestsIdResponse"
8574
+ "$ref": "#/components/schemas/PatchGuildsSlugResponse"
8545
8575
  }
8546
8576
  }
8547
8577
  }
@@ -8564,27 +8594,25 @@
8564
8594
  "builderSession": []
8565
8595
  }
8566
8596
  ]
8567
- }
8568
- },
8569
- "/help-requests/{id}/replies": {
8570
- "get": {
8571
- "operationId": "get_help_requests_id_replies",
8597
+ },
8598
+ "delete": {
8599
+ "operationId": "delete_guilds_slug",
8572
8600
  "tags": [
8573
- "help-requests"
8601
+ "guilds"
8574
8602
  ],
8575
- "summary": "GET /help-requests/:id/replies",
8576
- "description": ", matching the board read this hangs under. AN UNKNOWN ID ANSWERS `[]`, NOT 404, and that asymmetry with the POST above is deliberate rather than an oversight (raised by the grader). This surface has already had one lesson about existence lookups: PATCH used to look a row up to say WHICH of three things was wrong, which let a caller enumerate ids by watching the refusal change. A 404 here would rebuild exactly that oracle on the cheapest possible request — a GET, repeatable, with nothing written. The POST can afford the 404 because it is a WRITE: it costs an attempt, it is rate-limited by being a write, and a reply to a phantom ask has to fail with a reason or fail as an FK 500 that tells the caller nothing useful. A read has no such excuse, and \"no replies\" is a true answer about an ask that does not exist.\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
8603
+ "summary": "DELETE /guilds/:slug",
8604
+ "description": "owner: dissolve. Hard delete, cascading to every membership and open request (ADR 0336 D2).\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
8577
8605
  "x-rank": "any-builder",
8578
- "x-source": "modules/lifecycle/routes/help-requests.js",
8606
+ "x-source": "modules/platform-identity/routes/guilds.js",
8579
8607
  "parameters": [
8580
8608
  {
8581
- "name": "id",
8609
+ "name": "slug",
8582
8610
  "in": "path",
8583
8611
  "required": true,
8584
8612
  "schema": {
8585
8613
  "type": "string"
8586
8614
  },
8587
- "description": "Path parameter `id`."
8615
+ "description": "Path parameter `slug`."
8588
8616
  }
8589
8617
  ],
8590
8618
  "responses": {
@@ -8593,7 +8621,7 @@
8593
8621
  "content": {
8594
8622
  "application/json": {
8595
8623
  "schema": {
8596
- "$ref": "#/components/schemas/GetHelpRequestsIdRepliesResponse"
8624
+ "$ref": "#/components/schemas/DeleteGuildsSlugResponse"
8597
8625
  }
8598
8626
  }
8599
8627
  }
@@ -8616,25 +8644,27 @@
8616
8644
  "builderSession": []
8617
8645
  }
8618
8646
  ]
8619
- },
8647
+ }
8648
+ },
8649
+ "/guilds/{slug}/invites": {
8620
8650
  "post": {
8621
- "operationId": "post_help_requests_id_replies",
8651
+ "operationId": "post_guilds_slug_invites",
8622
8652
  "tags": [
8623
- "help-requests"
8653
+ "guilds"
8624
8654
  ],
8625
- "summary": "POST /help-requests/:id/replies",
8626
- "description": "---- replies (task 1004216, ADR 0330) ------------------------------------- THE HALF THIS SURFACE SHIPPED WITHOUT. A builder could ask, and the asker could mark their own row answered; the person being ASKED had no write at all, so the answer happened somewhere Bongos could not see it. ANY BUILDER MAY REPLY, deliberately. The board read (GET /help-requests) is already project-wide, so every member can see every open ask — and a reply says nothing more private than the ask it hangs under. Restricting replies to the addressee would also break the common good case: somebody who is not who you asked turns out to know the answer. APPEND-ONLY, with no edit and no delete route. That is not an omission to fill in later: the table's own trigger refuses an UPDATE or a DELETE, and the restraint is what keeps this an answer surface rather than the chat surface ADR 0187 §4a declined to build here.\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
8655
+ "summary": "POST /guilds/:slug/invites",
8656
+ "description": "owner: invite up to INVITE_BATCH_MAX builders by handle, each an ordinary individual invite (ADR 0336 D3). Unlisted guilds take invites. count is the array's own length.\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
8627
8657
  "x-rank": "any-builder",
8628
- "x-source": "modules/lifecycle/routes/help-requests.js",
8658
+ "x-source": "modules/platform-identity/routes/guilds.js",
8629
8659
  "parameters": [
8630
8660
  {
8631
- "name": "id",
8661
+ "name": "slug",
8632
8662
  "in": "path",
8633
8663
  "required": true,
8634
8664
  "schema": {
8635
8665
  "type": "string"
8636
8666
  },
8637
- "description": "Path parameter `id`."
8667
+ "description": "Path parameter `slug`."
8638
8668
  }
8639
8669
  ],
8640
8670
  "requestBody": {
@@ -8642,7 +8672,7 @@
8642
8672
  "content": {
8643
8673
  "application/json": {
8644
8674
  "schema": {
8645
- "$ref": "#/components/schemas/PostHelpRequestsIdRepliesRequest"
8675
+ "$ref": "#/components/schemas/PostGuildsSlugInvitesRequest"
8646
8676
  }
8647
8677
  }
8648
8678
  },
@@ -8654,7 +8684,7 @@
8654
8684
  "content": {
8655
8685
  "application/json": {
8656
8686
  "schema": {
8657
- "$ref": "#/components/schemas/PostHelpRequestsIdRepliesResponse"
8687
+ "$ref": "#/components/schemas/PostGuildsSlugInvitesResponse"
8658
8688
  }
8659
8689
  }
8660
8690
  }
@@ -8679,23 +8709,34 @@
8679
8709
  ]
8680
8710
  }
8681
8711
  },
8682
- "/inbox": {
8712
+ "/guilds/{slug}/members": {
8683
8713
  "get": {
8684
- "operationId": "get_inbox",
8714
+ "operationId": "get_guilds_slug_members",
8685
8715
  "tags": [
8686
- "inbox"
8716
+ "guilds"
8687
8717
  ],
8688
- "summary": "GET /inbox",
8689
- "description": "read open ideas; skill-friction rows filtered by viewer rank.\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
8718
+ "summary": "GET /guilds/:slug/members",
8719
+ "description": "the members' roster, for members only (the own-scope door to an unlisted guild, ADR 0336 D4). A private member is listed here, to fellow members, and on no public page.\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
8690
8720
  "x-rank": "any-builder",
8691
- "x-source": "modules/ideas/routes/inbox.js",
8721
+ "x-source": "modules/platform-identity/routes/guilds.js",
8722
+ "parameters": [
8723
+ {
8724
+ "name": "slug",
8725
+ "in": "path",
8726
+ "required": true,
8727
+ "schema": {
8728
+ "type": "string"
8729
+ },
8730
+ "description": "Path parameter `slug`."
8731
+ }
8732
+ ],
8692
8733
  "responses": {
8693
8734
  "200": {
8694
8735
  "description": "Success.",
8695
8736
  "content": {
8696
8737
  "application/json": {
8697
8738
  "schema": {
8698
- "$ref": "#/components/schemas/GetInboxResponse"
8739
+ "$ref": "#/components/schemas/GetGuildsSlugMembersResponse"
8699
8740
  }
8700
8741
  }
8701
8742
  }
@@ -8708,6 +8749,9 @@
8708
8749
  },
8709
8750
  "403": {
8710
8751
  "$ref": "#/components/responses/Forbidden"
8752
+ },
8753
+ "404": {
8754
+ "$ref": "#/components/responses/NotFound"
8711
8755
  }
8712
8756
  },
8713
8757
  "security": [
@@ -8715,30 +8759,814 @@
8715
8759
  "builderSession": []
8716
8760
  }
8717
8761
  ]
8718
- },
8719
- "post": {
8720
- "operationId": "post_inbox",
8762
+ }
8763
+ },
8764
+ "/guilds/{slug}/members/{handle}": {
8765
+ "delete": {
8766
+ "operationId": "delete_guilds_slug_members_handle",
8721
8767
  "tags": [
8722
- "inbox"
8768
+ "guilds"
8723
8769
  ],
8724
- "summary": "POST /inbox",
8725
- "description": "for ordinary ideas; metic+ for kind='criterion-proposal'. Anyone can file a general contribution (the open-to-all path that idea-triage's \"Xenos can still file\" line guarantees). But kind= 'criterion-proposal' is the marker the /planning-session skill writes from Metic-mode, and a planning-session proposal reshapes the next version's scope-truth — that's a trusted-builder operation (V3.R87 / task 306). Gate it here so a Xenos can't slip a criterion proposal in via raw curl after the skill itself refuses to run for them.\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
8770
+ "summary": "DELETE /guilds/:slug/members/:handle",
8771
+ "description": "owner: remove a member (never the owner). Hard delete.\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
8726
8772
  "x-rank": "any-builder",
8727
- "x-source": "modules/ideas/routes/inbox.js",
8728
- "requestBody": {
8729
- "required": true,
8730
- "content": {
8731
- "application/json": {
8732
- "schema": {
8733
- "$ref": "#/components/schemas/PostInboxRequest"
8734
- }
8735
- }
8736
- },
8737
- "x-validated": true
8738
- },
8739
- "responses": {
8740
- "200": {
8741
- "description": "Success."
8773
+ "x-source": "modules/platform-identity/routes/guilds.js",
8774
+ "parameters": [
8775
+ {
8776
+ "name": "slug",
8777
+ "in": "path",
8778
+ "required": true,
8779
+ "schema": {
8780
+ "type": "string"
8781
+ },
8782
+ "description": "Path parameter `slug`."
8783
+ },
8784
+ {
8785
+ "name": "handle",
8786
+ "in": "path",
8787
+ "required": true,
8788
+ "schema": {
8789
+ "type": "string"
8790
+ },
8791
+ "description": "Path parameter `handle`."
8792
+ }
8793
+ ],
8794
+ "responses": {
8795
+ "200": {
8796
+ "description": "Success.",
8797
+ "content": {
8798
+ "application/json": {
8799
+ "schema": {
8800
+ "$ref": "#/components/schemas/DeleteGuildsSlugMembersHandleResponse"
8801
+ }
8802
+ }
8803
+ }
8804
+ },
8805
+ "400": {
8806
+ "$ref": "#/components/responses/BadRequest"
8807
+ },
8808
+ "401": {
8809
+ "$ref": "#/components/responses/Unauthorized"
8810
+ },
8811
+ "403": {
8812
+ "$ref": "#/components/responses/Forbidden"
8813
+ },
8814
+ "404": {
8815
+ "$ref": "#/components/responses/NotFound"
8816
+ }
8817
+ },
8818
+ "security": [
8819
+ {
8820
+ "builderSession": []
8821
+ }
8822
+ ]
8823
+ }
8824
+ },
8825
+ "/guilds/{slug}/membership": {
8826
+ "patch": {
8827
+ "operationId": "patch_guilds_slug_membership",
8828
+ "tags": [
8829
+ "guilds"
8830
+ ],
8831
+ "summary": "PATCH /guilds/:slug/membership",
8832
+ "description": "MY switches in one guild: shown on its public page (ADR 0336 D4) and counted in its totals (ADR 0337 D4.4). Each optional, at least one required, both keyed on the session.\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
8833
+ "x-rank": "any-builder",
8834
+ "x-source": "modules/platform-identity/routes/guilds.js",
8835
+ "parameters": [
8836
+ {
8837
+ "name": "slug",
8838
+ "in": "path",
8839
+ "required": true,
8840
+ "schema": {
8841
+ "type": "string"
8842
+ },
8843
+ "description": "Path parameter `slug`."
8844
+ }
8845
+ ],
8846
+ "requestBody": {
8847
+ "required": false,
8848
+ "content": {
8849
+ "application/json": {
8850
+ "schema": {
8851
+ "$ref": "#/components/schemas/PatchGuildsSlugMembershipRequest"
8852
+ }
8853
+ }
8854
+ },
8855
+ "x-validated": true
8856
+ },
8857
+ "responses": {
8858
+ "200": {
8859
+ "description": "Success."
8860
+ },
8861
+ "400": {
8862
+ "$ref": "#/components/responses/ValidationFailed"
8863
+ },
8864
+ "401": {
8865
+ "$ref": "#/components/responses/Unauthorized"
8866
+ },
8867
+ "403": {
8868
+ "$ref": "#/components/responses/Forbidden"
8869
+ },
8870
+ "404": {
8871
+ "$ref": "#/components/responses/NotFound"
8872
+ }
8873
+ },
8874
+ "security": [
8875
+ {
8876
+ "builderSession": []
8877
+ }
8878
+ ]
8879
+ },
8880
+ "delete": {
8881
+ "operationId": "delete_guilds_slug_membership",
8882
+ "tags": [
8883
+ "guilds"
8884
+ ],
8885
+ "summary": "DELETE /guilds/:slug/membership",
8886
+ "description": "leave. The owner must transfer first unless they are the last member, when leaving dissolves the guild (ADR 0336 D2).\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
8887
+ "x-rank": "any-builder",
8888
+ "x-source": "modules/platform-identity/routes/guilds.js",
8889
+ "parameters": [
8890
+ {
8891
+ "name": "slug",
8892
+ "in": "path",
8893
+ "required": true,
8894
+ "schema": {
8895
+ "type": "string"
8896
+ },
8897
+ "description": "Path parameter `slug`."
8898
+ }
8899
+ ],
8900
+ "responses": {
8901
+ "200": {
8902
+ "description": "Success.",
8903
+ "content": {
8904
+ "application/json": {
8905
+ "schema": {
8906
+ "$ref": "#/components/schemas/DeleteGuildsSlugMembershipResponse"
8907
+ }
8908
+ }
8909
+ }
8910
+ },
8911
+ "400": {
8912
+ "$ref": "#/components/responses/BadRequest"
8913
+ },
8914
+ "401": {
8915
+ "$ref": "#/components/responses/Unauthorized"
8916
+ },
8917
+ "403": {
8918
+ "$ref": "#/components/responses/Forbidden"
8919
+ },
8920
+ "404": {
8921
+ "$ref": "#/components/responses/NotFound"
8922
+ }
8923
+ },
8924
+ "security": [
8925
+ {
8926
+ "builderSession": []
8927
+ }
8928
+ ]
8929
+ }
8930
+ },
8931
+ "/guilds/{slug}/requests": {
8932
+ "get": {
8933
+ "operationId": "get_guilds_slug_requests",
8934
+ "tags": [
8935
+ "guilds"
8936
+ ],
8937
+ "summary": "GET /guilds/:slug/requests",
8938
+ "description": "owner: the join requests to decide and the invites still out. Stamps seen_at on the requests only.\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
8939
+ "x-rank": "any-builder",
8940
+ "x-source": "modules/platform-identity/routes/guilds.js",
8941
+ "parameters": [
8942
+ {
8943
+ "name": "slug",
8944
+ "in": "path",
8945
+ "required": true,
8946
+ "schema": {
8947
+ "type": "string"
8948
+ },
8949
+ "description": "Path parameter `slug`."
8950
+ }
8951
+ ],
8952
+ "responses": {
8953
+ "200": {
8954
+ "description": "Success.",
8955
+ "content": {
8956
+ "application/json": {
8957
+ "schema": {
8958
+ "$ref": "#/components/schemas/GetGuildsSlugRequestsResponse"
8959
+ }
8960
+ }
8961
+ }
8962
+ },
8963
+ "400": {
8964
+ "$ref": "#/components/responses/BadRequest"
8965
+ },
8966
+ "401": {
8967
+ "$ref": "#/components/responses/Unauthorized"
8968
+ },
8969
+ "403": {
8970
+ "$ref": "#/components/responses/Forbidden"
8971
+ },
8972
+ "404": {
8973
+ "$ref": "#/components/responses/NotFound"
8974
+ }
8975
+ },
8976
+ "security": [
8977
+ {
8978
+ "builderSession": []
8979
+ }
8980
+ ]
8981
+ },
8982
+ "post": {
8983
+ "operationId": "post_guilds_slug_requests",
8984
+ "tags": [
8985
+ "guilds"
8986
+ ],
8987
+ "summary": "POST /guilds/:slug/requests",
8988
+ "description": "ask to join. Only a PUBLIC guild takes requests, so an unlisted guild and an unknown slug are one 404 (ADR 0336 D3/D4). A request written and one swallowed by a decline cooldown answer identically.\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
8989
+ "x-rank": "any-builder",
8990
+ "x-source": "modules/platform-identity/routes/guilds.js",
8991
+ "parameters": [
8992
+ {
8993
+ "name": "slug",
8994
+ "in": "path",
8995
+ "required": true,
8996
+ "schema": {
8997
+ "type": "string"
8998
+ },
8999
+ "description": "Path parameter `slug`."
9000
+ }
9001
+ ],
9002
+ "requestBody": {
9003
+ "required": false,
9004
+ "content": {
9005
+ "application/json": {
9006
+ "schema": {
9007
+ "$ref": "#/components/schemas/PostGuildsSlugRequestsRequest"
9008
+ }
9009
+ }
9010
+ },
9011
+ "x-validated": true
9012
+ },
9013
+ "responses": {
9014
+ "200": {
9015
+ "description": "Success.",
9016
+ "content": {
9017
+ "application/json": {
9018
+ "schema": {
9019
+ "$ref": "#/components/schemas/PostGuildsSlugRequestsResponse"
9020
+ }
9021
+ }
9022
+ }
9023
+ },
9024
+ "400": {
9025
+ "$ref": "#/components/responses/ValidationFailed"
9026
+ },
9027
+ "401": {
9028
+ "$ref": "#/components/responses/Unauthorized"
9029
+ },
9030
+ "403": {
9031
+ "$ref": "#/components/responses/Forbidden"
9032
+ },
9033
+ "404": {
9034
+ "$ref": "#/components/responses/NotFound"
9035
+ }
9036
+ },
9037
+ "security": [
9038
+ {
9039
+ "builderSession": []
9040
+ }
9041
+ ]
9042
+ }
9043
+ },
9044
+ "/guilds/{slug}/transfer": {
9045
+ "post": {
9046
+ "operationId": "post_guilds_slug_transfer",
9047
+ "tags": [
9048
+ "guilds"
9049
+ ],
9050
+ "summary": "POST /guilds/:slug/transfer",
9051
+ "description": "owner: hand ownership to an existing member. Two statements in one transaction (ADR 0336 D2).\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
9052
+ "x-rank": "any-builder",
9053
+ "x-source": "modules/platform-identity/routes/guilds.js",
9054
+ "parameters": [
9055
+ {
9056
+ "name": "slug",
9057
+ "in": "path",
9058
+ "required": true,
9059
+ "schema": {
9060
+ "type": "string"
9061
+ },
9062
+ "description": "Path parameter `slug`."
9063
+ }
9064
+ ],
9065
+ "requestBody": {
9066
+ "required": true,
9067
+ "content": {
9068
+ "application/json": {
9069
+ "schema": {
9070
+ "$ref": "#/components/schemas/PostGuildsSlugTransferRequest"
9071
+ }
9072
+ }
9073
+ },
9074
+ "x-validated": true
9075
+ },
9076
+ "responses": {
9077
+ "200": {
9078
+ "description": "Success.",
9079
+ "content": {
9080
+ "application/json": {
9081
+ "schema": {
9082
+ "$ref": "#/components/schemas/PostGuildsSlugTransferResponse"
9083
+ }
9084
+ }
9085
+ }
9086
+ },
9087
+ "400": {
9088
+ "$ref": "#/components/responses/ValidationFailed"
9089
+ },
9090
+ "401": {
9091
+ "$ref": "#/components/responses/Unauthorized"
9092
+ },
9093
+ "403": {
9094
+ "$ref": "#/components/responses/Forbidden"
9095
+ },
9096
+ "404": {
9097
+ "$ref": "#/components/responses/NotFound"
9098
+ }
9099
+ },
9100
+ "security": [
9101
+ {
9102
+ "builderSession": []
9103
+ }
9104
+ ]
9105
+ }
9106
+ },
9107
+ "/healthz": {
9108
+ "get": {
9109
+ "operationId": "get_healthz",
9110
+ "tags": [
9111
+ "healthz"
9112
+ ],
9113
+ "summary": "GET /healthz",
9114
+ "description": "liveness probe; the status dashboard (status.<apex>) hits this anonymously.\n\n**Rank:** `public` — No authentication — any caller.",
9115
+ "x-rank": "public",
9116
+ "x-source": "src/bongos/routes/healthz.js",
9117
+ "responses": {
9118
+ "200": {
9119
+ "description": "Success.",
9120
+ "content": {
9121
+ "application/json": {
9122
+ "schema": {
9123
+ "$ref": "#/components/schemas/GetHealthzResponse"
9124
+ }
9125
+ }
9126
+ }
9127
+ },
9128
+ "400": {
9129
+ "$ref": "#/components/responses/BadRequest"
9130
+ }
9131
+ },
9132
+ "security": []
9133
+ }
9134
+ },
9135
+ "/help-requests": {
9136
+ "get": {
9137
+ "operationId": "get_help_requests",
9138
+ "tags": [
9139
+ "help-requests"
9140
+ ],
9141
+ "summary": "GET /help-requests",
9142
+ "description": "The BOARD read (task 1003942): every open ask in the project, newest first, for the Collab page's \"all open asks\" block. rank: any-builder — an ask is addressed inside this project and every reader here is a member; the route takes no craft and no builder from the caller, so there is nothing to widen.\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
9143
+ "x-rank": "any-builder",
9144
+ "x-source": "modules/lifecycle/routes/help-requests.js",
9145
+ "responses": {
9146
+ "200": {
9147
+ "description": "Success.",
9148
+ "content": {
9149
+ "application/json": {
9150
+ "schema": {
9151
+ "$ref": "#/components/schemas/GetHelpRequestsResponse"
9152
+ }
9153
+ }
9154
+ }
9155
+ },
9156
+ "400": {
9157
+ "$ref": "#/components/responses/BadRequest"
9158
+ },
9159
+ "401": {
9160
+ "$ref": "#/components/responses/Unauthorized"
9161
+ },
9162
+ "403": {
9163
+ "$ref": "#/components/responses/Forbidden"
9164
+ }
9165
+ },
9166
+ "security": [
9167
+ {
9168
+ "builderSession": []
9169
+ }
9170
+ ]
9171
+ },
9172
+ "post": {
9173
+ "operationId": "post_help_requests",
9174
+ "tags": [
9175
+ "help-requests"
9176
+ ],
9177
+ "summary": "POST /help-requests",
9178
+ "description": "asking for help is not a privileged act, and gating it would exclude exactly the newcomers most likely to be stuck.\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
9179
+ "x-rank": "any-builder",
9180
+ "x-source": "modules/lifecycle/routes/help-requests.js",
9181
+ "requestBody": {
9182
+ "required": true,
9183
+ "content": {
9184
+ "application/json": {
9185
+ "schema": {
9186
+ "$ref": "#/components/schemas/PostHelpRequestsRequest"
9187
+ }
9188
+ }
9189
+ },
9190
+ "x-validated": true
9191
+ },
9192
+ "responses": {
9193
+ "200": {
9194
+ "description": "Success.",
9195
+ "content": {
9196
+ "application/json": {
9197
+ "schema": {
9198
+ "$ref": "#/components/schemas/PostHelpRequestsResponse"
9199
+ }
9200
+ }
9201
+ }
9202
+ },
9203
+ "400": {
9204
+ "$ref": "#/components/responses/ValidationFailed"
9205
+ },
9206
+ "401": {
9207
+ "$ref": "#/components/responses/Unauthorized"
9208
+ },
9209
+ "403": {
9210
+ "$ref": "#/components/responses/Forbidden"
9211
+ }
9212
+ },
9213
+ "security": [
9214
+ {
9215
+ "builderSession": []
9216
+ }
9217
+ ]
9218
+ }
9219
+ },
9220
+ "/help-requests/archive": {
9221
+ "get": {
9222
+ "operationId": "get_help_requests_archive",
9223
+ "tags": [
9224
+ "help-requests"
9225
+ ],
9226
+ "summary": "GET /help-requests/archive",
9227
+ "description": "THE ARCHIVE (task 1004224, owner direction): what a settled ask becomes. Until now a settled ask simply vanished from Collab. That was tolerable while settling meant a person had decided the ask was done — they knew. It stops being tolerable the moment the LEDGER settles asks on its own: a row can now leave the page without anybody having watched it go, and a surface that silently disappears its own history is asking to be distrusted. TWO LISTS, NOT ONE, and the split is the owner's: asks made OF YOU and asks you made OF OTHERS are different questions with different follow-ups, and a merged list would need a per-row label to say which it was — which is the same information, said worse. ONE ROUTE FOR BOTH. They share a settle, a bound and a shape, and the page draws them side by side in one section; two routes would be two round trips for one collapsed block and two places for the projection to drift. rank: any-builder, and the scoping matches the open reads exactly — you see what was addressed to you and what you asked, and nothing else. `crafts` comes from `builders.preferred_disciplines` through craftsForBuilder, NEVER from the query string. That is not caution: a ?craft= param validated only against the enum is precisely the hole C01's grader found on the open read, and an archive is the larger prize because it is the whole history rather than today's board. This route accepts no craft, no builder and no status from the caller, so there is nothing here to narrow or widen.\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
9228
+ "x-rank": "any-builder",
9229
+ "x-source": "modules/lifecycle/routes/help-requests.js",
9230
+ "responses": {
9231
+ "200": {
9232
+ "description": "Success.",
9233
+ "content": {
9234
+ "application/json": {
9235
+ "schema": {
9236
+ "$ref": "#/components/schemas/GetHelpRequestsArchiveResponse"
9237
+ }
9238
+ }
9239
+ }
9240
+ },
9241
+ "400": {
9242
+ "$ref": "#/components/responses/BadRequest"
9243
+ },
9244
+ "401": {
9245
+ "$ref": "#/components/responses/Unauthorized"
9246
+ },
9247
+ "403": {
9248
+ "$ref": "#/components/responses/Forbidden"
9249
+ }
9250
+ },
9251
+ "security": [
9252
+ {
9253
+ "builderSession": []
9254
+ }
9255
+ ]
9256
+ }
9257
+ },
9258
+ "/help-requests/for-me": {
9259
+ "get": {
9260
+ "operationId": "get_help_requests_for_me",
9261
+ "tags": [
9262
+ "help-requests"
9263
+ ],
9264
+ "summary": "GET /help-requests/for-me",
9265
+ "description": "The addressed read — C01's answer to \"and fires a notification\". A request is immediately visible to the person or craft it names. A true PUSH lives in the builder-needs feed (`builder-settings`), which is outside this goal's scope wall, so it is recorded as a gap rather than reached for. rank: any-builder — you only ever see what is addressed to you.\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
9266
+ "x-rank": "any-builder",
9267
+ "x-source": "modules/lifecycle/routes/help-requests.js",
9268
+ "responses": {
9269
+ "200": {
9270
+ "description": "Success.",
9271
+ "content": {
9272
+ "application/json": {
9273
+ "schema": {
9274
+ "$ref": "#/components/schemas/GetHelpRequestsForMeResponse"
9275
+ }
9276
+ }
9277
+ }
9278
+ },
9279
+ "400": {
9280
+ "$ref": "#/components/responses/BadRequest"
9281
+ },
9282
+ "401": {
9283
+ "$ref": "#/components/responses/Unauthorized"
9284
+ },
9285
+ "403": {
9286
+ "$ref": "#/components/responses/Forbidden"
9287
+ }
9288
+ },
9289
+ "security": [
9290
+ {
9291
+ "builderSession": []
9292
+ }
9293
+ ]
9294
+ }
9295
+ },
9296
+ "/help-requests/mine": {
9297
+ "get": {
9298
+ "operationId": "get_help_requests_mine",
9299
+ "tags": [
9300
+ "help-requests"
9301
+ ],
9302
+ "summary": "GET /help-requests/mine",
9303
+ "description": "your own asks, so you can settle them.\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
9304
+ "x-rank": "any-builder",
9305
+ "x-source": "modules/lifecycle/routes/help-requests.js",
9306
+ "responses": {
9307
+ "200": {
9308
+ "description": "Success.",
9309
+ "content": {
9310
+ "application/json": {
9311
+ "schema": {
9312
+ "$ref": "#/components/schemas/GetHelpRequestsMineResponse"
9313
+ }
9314
+ }
9315
+ }
9316
+ },
9317
+ "400": {
9318
+ "$ref": "#/components/responses/BadRequest"
9319
+ },
9320
+ "401": {
9321
+ "$ref": "#/components/responses/Unauthorized"
9322
+ },
9323
+ "403": {
9324
+ "$ref": "#/components/responses/Forbidden"
9325
+ }
9326
+ },
9327
+ "security": [
9328
+ {
9329
+ "builderSession": []
9330
+ }
9331
+ ]
9332
+ }
9333
+ },
9334
+ "/help-requests/{id}": {
9335
+ "patch": {
9336
+ "operationId": "patch_help_requests_id",
9337
+ "tags": [
9338
+ "help-requests"
9339
+ ],
9340
+ "summary": "PATCH /help-requests/:id",
9341
+ "description": "THE ASKER OR THE ADDRESSEE settles the request: 'answered' when it has been dealt with, 'withdrawn' when the asker no longer needs it. ADR 0330 widened 'answered' to the person the request NAMES — once a reply puts the answer on the row itself, an addressee who has answered in the open and still cannot close it is a surface arguing with itself. 'withdrawn' stays the asker's alone: only the person who needed something can say they no longer need it. Nobody is assigned by being asked — closing an ask ends a question, it does not accept work (ADR 0187 §3). rank: any-builder — who may settle is enforced in the UPDATE's WHERE, not by rank. The caller's crafts come from THEIR OWN profile, never from the body, for the same reason the addressed read refuses a ?craft= it was handed.\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
9342
+ "x-rank": "any-builder",
9343
+ "x-source": "modules/lifecycle/routes/help-requests.js",
9344
+ "parameters": [
9345
+ {
9346
+ "name": "id",
9347
+ "in": "path",
9348
+ "required": true,
9349
+ "schema": {
9350
+ "type": "string"
9351
+ },
9352
+ "description": "Path parameter `id`."
9353
+ }
9354
+ ],
9355
+ "requestBody": {
9356
+ "required": true,
9357
+ "content": {
9358
+ "application/json": {
9359
+ "schema": {
9360
+ "$ref": "#/components/schemas/PatchHelpRequestsIdRequest"
9361
+ }
9362
+ }
9363
+ },
9364
+ "x-validated": true
9365
+ },
9366
+ "responses": {
9367
+ "200": {
9368
+ "description": "Success.",
9369
+ "content": {
9370
+ "application/json": {
9371
+ "schema": {
9372
+ "$ref": "#/components/schemas/PatchHelpRequestsIdResponse"
9373
+ }
9374
+ }
9375
+ }
9376
+ },
9377
+ "400": {
9378
+ "$ref": "#/components/responses/ValidationFailed"
9379
+ },
9380
+ "401": {
9381
+ "$ref": "#/components/responses/Unauthorized"
9382
+ },
9383
+ "403": {
9384
+ "$ref": "#/components/responses/Forbidden"
9385
+ },
9386
+ "404": {
9387
+ "$ref": "#/components/responses/NotFound"
9388
+ }
9389
+ },
9390
+ "security": [
9391
+ {
9392
+ "builderSession": []
9393
+ }
9394
+ ]
9395
+ }
9396
+ },
9397
+ "/help-requests/{id}/replies": {
9398
+ "get": {
9399
+ "operationId": "get_help_requests_id_replies",
9400
+ "tags": [
9401
+ "help-requests"
9402
+ ],
9403
+ "summary": "GET /help-requests/:id/replies",
9404
+ "description": ", matching the board read this hangs under. AN UNKNOWN ID ANSWERS `[]`, NOT 404, and that asymmetry with the POST above is deliberate rather than an oversight (raised by the grader). This surface has already had one lesson about existence lookups: PATCH used to look a row up to say WHICH of three things was wrong, which let a caller enumerate ids by watching the refusal change. A 404 here would rebuild exactly that oracle on the cheapest possible request — a GET, repeatable, with nothing written. The POST can afford the 404 because it is a WRITE: it costs an attempt, it is rate-limited by being a write, and a reply to a phantom ask has to fail with a reason or fail as an FK 500 that tells the caller nothing useful. A read has no such excuse, and \"no replies\" is a true answer about an ask that does not exist.\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
9405
+ "x-rank": "any-builder",
9406
+ "x-source": "modules/lifecycle/routes/help-requests.js",
9407
+ "parameters": [
9408
+ {
9409
+ "name": "id",
9410
+ "in": "path",
9411
+ "required": true,
9412
+ "schema": {
9413
+ "type": "string"
9414
+ },
9415
+ "description": "Path parameter `id`."
9416
+ }
9417
+ ],
9418
+ "responses": {
9419
+ "200": {
9420
+ "description": "Success.",
9421
+ "content": {
9422
+ "application/json": {
9423
+ "schema": {
9424
+ "$ref": "#/components/schemas/GetHelpRequestsIdRepliesResponse"
9425
+ }
9426
+ }
9427
+ }
9428
+ },
9429
+ "400": {
9430
+ "$ref": "#/components/responses/BadRequest"
9431
+ },
9432
+ "401": {
9433
+ "$ref": "#/components/responses/Unauthorized"
9434
+ },
9435
+ "403": {
9436
+ "$ref": "#/components/responses/Forbidden"
9437
+ },
9438
+ "404": {
9439
+ "$ref": "#/components/responses/NotFound"
9440
+ }
9441
+ },
9442
+ "security": [
9443
+ {
9444
+ "builderSession": []
9445
+ }
9446
+ ]
9447
+ },
9448
+ "post": {
9449
+ "operationId": "post_help_requests_id_replies",
9450
+ "tags": [
9451
+ "help-requests"
9452
+ ],
9453
+ "summary": "POST /help-requests/:id/replies",
9454
+ "description": "---- replies (task 1004216, ADR 0330) ------------------------------------- THE HALF THIS SURFACE SHIPPED WITHOUT. A builder could ask, and the asker could mark their own row answered; the person being ASKED had no write at all, so the answer happened somewhere Bongos could not see it. ANY BUILDER MAY REPLY, deliberately. The board read (GET /help-requests) is already project-wide, so every member can see every open ask — and a reply says nothing more private than the ask it hangs under. Restricting replies to the addressee would also break the common good case: somebody who is not who you asked turns out to know the answer. APPEND-ONLY, with no edit and no delete route. That is not an omission to fill in later: the table's own trigger refuses an UPDATE or a DELETE, and the restraint is what keeps this an answer surface rather than the chat surface ADR 0187 §4a declined to build here.\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
9455
+ "x-rank": "any-builder",
9456
+ "x-source": "modules/lifecycle/routes/help-requests.js",
9457
+ "parameters": [
9458
+ {
9459
+ "name": "id",
9460
+ "in": "path",
9461
+ "required": true,
9462
+ "schema": {
9463
+ "type": "string"
9464
+ },
9465
+ "description": "Path parameter `id`."
9466
+ }
9467
+ ],
9468
+ "requestBody": {
9469
+ "required": true,
9470
+ "content": {
9471
+ "application/json": {
9472
+ "schema": {
9473
+ "$ref": "#/components/schemas/PostHelpRequestsIdRepliesRequest"
9474
+ }
9475
+ }
9476
+ },
9477
+ "x-validated": true
9478
+ },
9479
+ "responses": {
9480
+ "200": {
9481
+ "description": "Success.",
9482
+ "content": {
9483
+ "application/json": {
9484
+ "schema": {
9485
+ "$ref": "#/components/schemas/PostHelpRequestsIdRepliesResponse"
9486
+ }
9487
+ }
9488
+ }
9489
+ },
9490
+ "400": {
9491
+ "$ref": "#/components/responses/ValidationFailed"
9492
+ },
9493
+ "401": {
9494
+ "$ref": "#/components/responses/Unauthorized"
9495
+ },
9496
+ "403": {
9497
+ "$ref": "#/components/responses/Forbidden"
9498
+ },
9499
+ "404": {
9500
+ "$ref": "#/components/responses/NotFound"
9501
+ }
9502
+ },
9503
+ "security": [
9504
+ {
9505
+ "builderSession": []
9506
+ }
9507
+ ]
9508
+ }
9509
+ },
9510
+ "/inbox": {
9511
+ "get": {
9512
+ "operationId": "get_inbox",
9513
+ "tags": [
9514
+ "inbox"
9515
+ ],
9516
+ "summary": "GET /inbox",
9517
+ "description": "read open ideas; skill-friction rows filtered by viewer rank.\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
9518
+ "x-rank": "any-builder",
9519
+ "x-source": "modules/ideas/routes/inbox.js",
9520
+ "responses": {
9521
+ "200": {
9522
+ "description": "Success.",
9523
+ "content": {
9524
+ "application/json": {
9525
+ "schema": {
9526
+ "$ref": "#/components/schemas/GetInboxResponse"
9527
+ }
9528
+ }
9529
+ }
9530
+ },
9531
+ "400": {
9532
+ "$ref": "#/components/responses/BadRequest"
9533
+ },
9534
+ "401": {
9535
+ "$ref": "#/components/responses/Unauthorized"
9536
+ },
9537
+ "403": {
9538
+ "$ref": "#/components/responses/Forbidden"
9539
+ }
9540
+ },
9541
+ "security": [
9542
+ {
9543
+ "builderSession": []
9544
+ }
9545
+ ]
9546
+ },
9547
+ "post": {
9548
+ "operationId": "post_inbox",
9549
+ "tags": [
9550
+ "inbox"
9551
+ ],
9552
+ "summary": "POST /inbox",
9553
+ "description": "for ordinary ideas; metic+ for kind='criterion-proposal'. Anyone can file a general contribution (the open-to-all path that idea-triage's \"Xenos can still file\" line guarantees). But kind= 'criterion-proposal' is the marker the /planning-session skill writes from Metic-mode, and a planning-session proposal reshapes the next version's scope-truth — that's a trusted-builder operation (V3.R87 / task 306). Gate it here so a Xenos can't slip a criterion proposal in via raw curl after the skill itself refuses to run for them.\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
9554
+ "x-rank": "any-builder",
9555
+ "x-source": "modules/ideas/routes/inbox.js",
9556
+ "requestBody": {
9557
+ "required": true,
9558
+ "content": {
9559
+ "application/json": {
9560
+ "schema": {
9561
+ "$ref": "#/components/schemas/PostInboxRequest"
9562
+ }
9563
+ }
9564
+ },
9565
+ "x-validated": true
9566
+ },
9567
+ "responses": {
9568
+ "200": {
9569
+ "description": "Success."
8742
9570
  },
8743
9571
  "400": {
8744
9572
  "$ref": "#/components/responses/ValidationFailed"
@@ -10156,12 +10984,99 @@
10156
10984
  ]
10157
10985
  },
10158
10986
  "patch": {
10159
- "operationId": "patch_me_display_name",
10987
+ "operationId": "patch_me_display_name",
10988
+ "tags": [
10989
+ "me"
10990
+ ],
10991
+ "summary": "PATCH /me/display-name",
10992
+ "description": "PATCH the display name. Body: { display_name: \"<new name>\" }. Validated + trimmed by display-name.js: empty/whitespace-only, control chars, and names over the length ceiling → 422 with an errors array; nothing is written when validation fails. Own-scoped — only the AUTHENTICATED builder's row is touched (api.requireBuilder + req.builder.id), never another builder. Uniqueness is NOT required (display names may collide).\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
10993
+ "x-rank": "any-builder",
10994
+ "x-source": "modules/builder-settings/routes/settings.js",
10995
+ "requestBody": {
10996
+ "required": false,
10997
+ "content": {
10998
+ "application/json": {
10999
+ "schema": {
11000
+ "type": "object",
11001
+ "additionalProperties": true
11002
+ }
11003
+ }
11004
+ },
11005
+ "x-validated": false,
11006
+ "x-body-undocumented": true
11007
+ },
11008
+ "responses": {
11009
+ "200": {
11010
+ "description": "Success.",
11011
+ "content": {
11012
+ "application/json": {
11013
+ "schema": {
11014
+ "$ref": "#/components/schemas/PatchMeDisplayNameResponse"
11015
+ }
11016
+ }
11017
+ }
11018
+ },
11019
+ "400": {
11020
+ "$ref": "#/components/responses/BadRequest"
11021
+ },
11022
+ "401": {
11023
+ "$ref": "#/components/responses/Unauthorized"
11024
+ },
11025
+ "403": {
11026
+ "$ref": "#/components/responses/Forbidden"
11027
+ }
11028
+ },
11029
+ "security": [
11030
+ {
11031
+ "builderSession": []
11032
+ }
11033
+ ]
11034
+ }
11035
+ },
11036
+ "/me/event-sound-prefs": {
11037
+ "get": {
11038
+ "operationId": "get_me_event_sound_prefs",
11039
+ "tags": [
11040
+ "me"
11041
+ ],
11042
+ "summary": "GET /me/event-sound-prefs",
11043
+ "description": "Per-builder per-event sound variant selection (task 582, migration 164). Returns each of the 5 build events with their available world-themed variants, the builder's current selection (or the default), and the resolved .wav file name. The local player uses a mirror written by fetch-sound-prefs.js. rank: any-builder — own profile config; mirrors the sound-prefs route.\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
11044
+ "x-rank": "any-builder",
11045
+ "x-source": "modules/builder-settings/routes/settings.js",
11046
+ "responses": {
11047
+ "200": {
11048
+ "description": "Success.",
11049
+ "content": {
11050
+ "application/json": {
11051
+ "schema": {
11052
+ "$ref": "#/components/schemas/GetMeEventSoundPrefsResponse"
11053
+ }
11054
+ }
11055
+ }
11056
+ },
11057
+ "400": {
11058
+ "$ref": "#/components/responses/BadRequest"
11059
+ },
11060
+ "401": {
11061
+ "$ref": "#/components/responses/Unauthorized"
11062
+ },
11063
+ "403": {
11064
+ "$ref": "#/components/responses/Forbidden"
11065
+ }
11066
+ },
11067
+ "security": [
11068
+ {
11069
+ "builderSession": []
11070
+ }
11071
+ ]
11072
+ },
11073
+ "patch": {
11074
+ "operationId": "patch_me_event_sound_prefs",
10160
11075
  "tags": [
10161
11076
  "me"
10162
11077
  ],
10163
- "summary": "PATCH /me/display-name",
10164
- "description": "PATCH the display name. Body: { display_name: \"<new name>\" }. Validated + trimmed by display-name.js: empty/whitespace-only, control chars, and names over the length ceiling → 422 with an errors array; nothing is written when validation fails. Own-scoped — only the AUTHENTICATED builder's row is touched (api.requireBuilder + req.builder.id), never another builder. Uniqueness is NOT required (display names may collide).\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
11078
+ "summary": "PATCH /me/event-sound-prefs",
11079
+ "description": "PATCH a partial set of event sound overrides. Body shape: { \"<event-id>\": \"<variant-id>\" | null, ... } null clears the override (falls back to the event's default). Unknown event IDs, non-string variants, or variants that don't belong to the event → 422. rank: any-builder — self-service profile edit; mirrors the sound-prefs route.\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
10165
11080
  "x-rank": "any-builder",
10166
11081
  "x-source": "modules/builder-settings/routes/settings.js",
10167
11082
  "requestBody": {
@@ -10183,7 +11098,7 @@
10183
11098
  "content": {
10184
11099
  "application/json": {
10185
11100
  "schema": {
10186
- "$ref": "#/components/schemas/PatchMeDisplayNameResponse"
11101
+ "$ref": "#/components/schemas/PatchMeEventSoundPrefsResponse"
10187
11102
  }
10188
11103
  }
10189
11104
  }
@@ -10205,23 +11120,23 @@
10205
11120
  ]
10206
11121
  }
10207
11122
  },
10208
- "/me/event-sound-prefs": {
11123
+ "/me/guild-requests": {
10209
11124
  "get": {
10210
- "operationId": "get_me_event_sound_prefs",
11125
+ "operationId": "get_me_guild_requests",
10211
11126
  "tags": [
10212
11127
  "me"
10213
11128
  ],
10214
- "summary": "GET /me/event-sound-prefs",
10215
- "description": "Per-builder per-event sound variant selection (task 582, migration 164). Returns each of the 5 build events with their available world-themed variants, the builder's current selection (or the default), and the resolved .wav file name. The local player uses a mirror written by fetch-sound-prefs.js. rank: any-builder — own profile config; mirrors the sound-prefs route.\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
11129
+ "summary": "GET /me/guild-requests",
11130
+ "description": "MY queue: invites addressed to me, each carrying the card (the guild's current visibility, which an accept must echo back), and the join requests I sent. Stamps seen_at on the invites.\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
10216
11131
  "x-rank": "any-builder",
10217
- "x-source": "modules/builder-settings/routes/settings.js",
11132
+ "x-source": "modules/platform-identity/routes/guilds.js",
10218
11133
  "responses": {
10219
11134
  "200": {
10220
11135
  "description": "Success.",
10221
11136
  "content": {
10222
11137
  "application/json": {
10223
11138
  "schema": {
10224
- "$ref": "#/components/schemas/GetMeEventSoundPrefsResponse"
11139
+ "$ref": "#/components/schemas/GetMeGuildRequestsResponse"
10225
11140
  }
10226
11141
  }
10227
11142
  }
@@ -10241,36 +11156,25 @@
10241
11156
  "builderSession": []
10242
11157
  }
10243
11158
  ]
10244
- },
10245
- "patch": {
10246
- "operationId": "patch_me_event_sound_prefs",
11159
+ }
11160
+ },
11161
+ "/me/guilds": {
11162
+ "get": {
11163
+ "operationId": "get_me_guilds",
10247
11164
  "tags": [
10248
11165
  "me"
10249
11166
  ],
10250
- "summary": "PATCH /me/event-sound-prefs",
10251
- "description": "PATCH a partial set of event sound overrides. Body shape: { \"<event-id>\": \"<variant-id>\" | null, ... } null clears the override (falls back to the event's default). Unknown event IDs, non-string variants, or variants that don't belong to the event → 422. rank: any-builder — self-service profile edit; mirrors the sound-prefs route.\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
11167
+ "summary": "GET /me/guilds",
11168
+ "description": "MY guilds, each with my own two switches. count is the array's own length.\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
10252
11169
  "x-rank": "any-builder",
10253
- "x-source": "modules/builder-settings/routes/settings.js",
10254
- "requestBody": {
10255
- "required": false,
10256
- "content": {
10257
- "application/json": {
10258
- "schema": {
10259
- "type": "object",
10260
- "additionalProperties": true
10261
- }
10262
- }
10263
- },
10264
- "x-validated": false,
10265
- "x-body-undocumented": true
10266
- },
11170
+ "x-source": "modules/platform-identity/routes/guilds.js",
10267
11171
  "responses": {
10268
11172
  "200": {
10269
11173
  "description": "Success.",
10270
11174
  "content": {
10271
11175
  "application/json": {
10272
11176
  "schema": {
10273
- "$ref": "#/components/schemas/PatchMeEventSoundPrefsResponse"
11177
+ "$ref": "#/components/schemas/GetMeGuildsResponse"
10274
11178
  }
10275
11179
  }
10276
11180
  }
@@ -19429,6 +20333,42 @@
19429
20333
  "removed"
19430
20334
  ]
19431
20335
  },
20336
+ "DeleteGuildRequestsIdResponse": {
20337
+ "type": "object",
20338
+ "properties": {
20339
+ "outcome": {}
20340
+ },
20341
+ "required": [
20342
+ "outcome"
20343
+ ]
20344
+ },
20345
+ "DeleteGuildsSlugMembersHandleResponse": {
20346
+ "type": "object",
20347
+ "properties": {
20348
+ "outcome": {}
20349
+ },
20350
+ "required": [
20351
+ "outcome"
20352
+ ]
20353
+ },
20354
+ "DeleteGuildsSlugMembershipResponse": {
20355
+ "type": "object",
20356
+ "properties": {
20357
+ "outcome": {}
20358
+ },
20359
+ "required": [
20360
+ "outcome"
20361
+ ]
20362
+ },
20363
+ "DeleteGuildsSlugResponse": {
20364
+ "type": "object",
20365
+ "properties": {
20366
+ "outcome": {}
20367
+ },
20368
+ "required": [
20369
+ "outcome"
20370
+ ]
20371
+ },
19432
20372
  "DeleteInboxIdSparkResponse": {
19433
20373
  "type": "object",
19434
20374
  "properties": {
@@ -20237,6 +21177,49 @@
20237
21177
  "builders"
20238
21178
  ]
20239
21179
  },
21180
+ "GetGuildsSlugMembersResponse": {
21181
+ "type": "object",
21182
+ "properties": {
21183
+ "guild": {},
21184
+ "you": {},
21185
+ "members": {},
21186
+ "count": {}
21187
+ },
21188
+ "required": [
21189
+ "guild",
21190
+ "you",
21191
+ "members",
21192
+ "count"
21193
+ ]
21194
+ },
21195
+ "GetGuildsSlugRequestsResponse": {
21196
+ "type": "object",
21197
+ "properties": {
21198
+ "incoming": {},
21199
+ "outgoing": {},
21200
+ "incoming_count": {},
21201
+ "outgoing_count": {}
21202
+ },
21203
+ "required": [
21204
+ "incoming",
21205
+ "outgoing",
21206
+ "incoming_count",
21207
+ "outgoing_count"
21208
+ ]
21209
+ },
21210
+ "GetGuildsSlugResponse": {
21211
+ "type": "object",
21212
+ "properties": {
21213
+ "guild": {},
21214
+ "members": {},
21215
+ "size": {}
21216
+ },
21217
+ "required": [
21218
+ "guild",
21219
+ "members",
21220
+ "size"
21221
+ ]
21222
+ },
20240
21223
  "GetHealthzResponse": {
20241
21224
  "type": "object",
20242
21225
  "properties": {
@@ -20479,6 +21462,32 @@
20479
21462
  "events"
20480
21463
  ]
20481
21464
  },
21465
+ "GetMeGuildRequestsResponse": {
21466
+ "type": "object",
21467
+ "properties": {
21468
+ "incoming": {},
21469
+ "outgoing": {},
21470
+ "incoming_count": {},
21471
+ "outgoing_count": {}
21472
+ },
21473
+ "required": [
21474
+ "incoming",
21475
+ "outgoing",
21476
+ "incoming_count",
21477
+ "outgoing_count"
21478
+ ]
21479
+ },
21480
+ "GetMeGuildsResponse": {
21481
+ "type": "object",
21482
+ "properties": {
21483
+ "guilds": {},
21484
+ "count": {}
21485
+ },
21486
+ "required": [
21487
+ "guilds",
21488
+ "count"
21489
+ ]
21490
+ },
20482
21491
  "GetMeRecentShipsResponse": {
20483
21492
  "type": "object",
20484
21493
  "properties": {
@@ -21630,6 +22639,41 @@
21630
22639
  "changed"
21631
22640
  ]
21632
22641
  },
22642
+ "PatchGuildsSlugMembershipRequest": {
22643
+ "type": "object",
22644
+ "properties": {
22645
+ "shown_publicly": {
22646
+ "type": "boolean"
22647
+ },
22648
+ "counted_in_totals": {}
22649
+ },
22650
+ "additionalProperties": false
22651
+ },
22652
+ "PatchGuildsSlugRequest": {
22653
+ "type": "object",
22654
+ "properties": {
22655
+ "name": {
22656
+ "type": "string",
22657
+ "minLength": 1
22658
+ },
22659
+ "description": {
22660
+ "type": "string"
22661
+ },
22662
+ "visibility": {
22663
+ "type": "string"
22664
+ }
22665
+ },
22666
+ "additionalProperties": false
22667
+ },
22668
+ "PatchGuildsSlugResponse": {
22669
+ "type": "object",
22670
+ "properties": {
22671
+ "guild": {}
22672
+ },
22673
+ "required": [
22674
+ "guild"
22675
+ ]
22676
+ },
21633
22677
  "PatchHelpRequestsIdRequest": {
21634
22678
  "type": "object",
21635
22679
  "properties": {
@@ -24133,6 +25177,125 @@
24133
25177
  "rank"
24134
25178
  ]
24135
25179
  },
25180
+ "PostGuildRequestsIdAcceptRequest": {
25181
+ "type": "object",
25182
+ "properties": {
25183
+ "visibility": {
25184
+ "type": "string"
25185
+ },
25186
+ "counted_in_totals": {}
25187
+ },
25188
+ "additionalProperties": false
25189
+ },
25190
+ "PostGuildRequestsIdAcceptResponse": {
25191
+ "type": "object",
25192
+ "properties": {
25193
+ "status": {}
25194
+ },
25195
+ "required": [
25196
+ "status"
25197
+ ]
25198
+ },
25199
+ "PostGuildsRequest": {
25200
+ "type": "object",
25201
+ "properties": {
25202
+ "slug": {
25203
+ "type": "string",
25204
+ "minLength": 1,
25205
+ "maxLength": 39
25206
+ },
25207
+ "name": {
25208
+ "type": "string",
25209
+ "minLength": 1
25210
+ },
25211
+ "description": {
25212
+ "type": "string"
25213
+ },
25214
+ "visibility": {
25215
+ "type": "string"
25216
+ }
25217
+ },
25218
+ "required": [
25219
+ "slug",
25220
+ "name",
25221
+ "visibility"
25222
+ ],
25223
+ "additionalProperties": false
25224
+ },
25225
+ "PostGuildsResponse": {
25226
+ "type": "object",
25227
+ "properties": {
25228
+ "guild": {}
25229
+ },
25230
+ "required": [
25231
+ "guild"
25232
+ ]
25233
+ },
25234
+ "PostGuildsSlugInvitesRequest": {
25235
+ "type": "object",
25236
+ "properties": {
25237
+ "handles": {
25238
+ "type": "array",
25239
+ "items": {
25240
+ "type": "string"
25241
+ }
25242
+ }
25243
+ },
25244
+ "required": [
25245
+ "handles"
25246
+ ],
25247
+ "additionalProperties": false
25248
+ },
25249
+ "PostGuildsSlugInvitesResponse": {
25250
+ "type": "object",
25251
+ "properties": {
25252
+ "results": {},
25253
+ "count": {}
25254
+ },
25255
+ "required": [
25256
+ "results",
25257
+ "count"
25258
+ ]
25259
+ },
25260
+ "PostGuildsSlugRequestsRequest": {
25261
+ "type": "object",
25262
+ "properties": {
25263
+ "counted_in_totals": {}
25264
+ },
25265
+ "additionalProperties": false
25266
+ },
25267
+ "PostGuildsSlugRequestsResponse": {
25268
+ "type": "object",
25269
+ "properties": {
25270
+ "status": {}
25271
+ },
25272
+ "required": [
25273
+ "status"
25274
+ ]
25275
+ },
25276
+ "PostGuildsSlugTransferRequest": {
25277
+ "type": "object",
25278
+ "properties": {
25279
+ "handle": {
25280
+ "type": "string",
25281
+ "minLength": 1,
25282
+ "maxLength": 39
25283
+ }
25284
+ },
25285
+ "required": [
25286
+ "handle"
25287
+ ],
25288
+ "additionalProperties": false
25289
+ },
25290
+ "PostGuildsSlugTransferResponse": {
25291
+ "type": "object",
25292
+ "properties": {
25293
+ "outcome": {}
25294
+ },
25295
+ "required": [
25296
+ "outcome"
25297
+ ]
25298
+ },
24136
25299
  "PostHelpRequestsIdRepliesRequest": {
24137
25300
  "type": "object",
24138
25301
  "properties": {
@@ -26619,9 +27782,9 @@
26619
27782
  "description": "A required dependency/feature is not configured or is temporarily down."
26620
27783
  }
26621
27784
  },
26622
- "x-endpoint-count": 420,
26623
- "x-schema-count": 457,
27785
+ "x-endpoint-count": 437,
27786
+ "x-schema-count": 479,
26624
27787
  "x-undocumented-bodies": 9,
26625
- "x-response-schemas": 312,
27788
+ "x-response-schemas": 327,
26626
27789
  "x-generated-by": "scripts/gds/gen-api-docs.js"
26627
27790
  }