@bongos/core 1.19.1062 → 1.19.1064

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 (56) hide show
  1. package/.bongos-core.json +123 -48
  2. package/.claude/skills/grade-recover/SKILL.md +1 -0
  3. package/.claude/skills/tweak/SKILL.md +70 -0
  4. package/clients/bongos-client/README.md +1 -1
  5. package/clients/bongos-client/bongos-client.global.js +8 -0
  6. package/clients/bongos-client/index.cjs +8 -0
  7. package/clients/bongos-client/index.d.ts +12 -0
  8. package/clients/bongos-client/index.mjs +8 -0
  9. package/docs/api/openapi.json +301 -3
  10. package/docs/api-reference.md +7 -3
  11. package/docs/copy-inventory.md +44 -7
  12. package/docs/copy-registry.json +393 -26
  13. package/docs/file-map.md +1 -0
  14. package/docs/module-api-changelog.md +4 -0
  15. package/docs/page-inventory.json +36 -4
  16. package/docs/page-readings.json +34 -1
  17. package/modules/copy-desk/page-status.js +63 -0
  18. package/modules/copy-desk/pages.js +1 -0
  19. package/modules/copy-desk/routes/copy-desk.js +30 -0
  20. package/modules/hall-ui/public/tweak-editor-lib.js +137 -0
  21. package/modules/hall-ui/public/tweak-editor.css +437 -0
  22. package/modules/hall-ui/public/tweak-editor.html +111 -0
  23. package/modules/hall-ui/public/tweak-editor.js +447 -0
  24. package/modules/hall-ui/public/tweak-editor.states.json +99 -0
  25. package/modules/hall-ui/records/tweak-editor.md +32 -0
  26. package/modules/lifecycle/db-grade.js +16 -0
  27. package/modules/lifecycle/migrations/lifecycle_013_task_visual_slots.sql +52 -0
  28. package/modules/lifecycle/page-tweak-hold.js +74 -0
  29. package/modules/lifecycle/page-tweak-reads.js +33 -1
  30. package/modules/lifecycle/routes/tasks.js +4 -2
  31. package/modules/lifecycle/routes/visuals.js +82 -0
  32. package/modules/lifecycle/task-visual-db.js +40 -1
  33. package/modules/lifecycle/task-visuals.js +24 -0
  34. package/package-lock.json +2 -2
  35. package/package.json +1 -1
  36. package/release-notes.json +12 -0
  37. package/scripts/gds/copy-apply.js +277 -1
  38. package/scripts/gds/page-reader.js +2 -0
  39. package/scripts/gds/ship-finish.js +27 -2
  40. package/scripts/gds/ship-flow.js +17 -1
  41. package/scripts/gds/ship-land.js +30 -7
  42. package/scripts/gds/ship-merge.js +43 -15
  43. package/scripts/gds/strand-watch.js +41 -1
  44. package/scripts/gds/task.js +23 -5
  45. package/scripts/gds/tweak-renders.js +200 -0
  46. package/scripts/hall-preview/server.js +21 -0
  47. package/src/bongos/serve-internal.js +5 -1
  48. package/src/module-api.js +1 -1
  49. package/tests/copy_desk_page_editor.mjs +181 -0
  50. package/tests/hall_audit.mjs +5 -0
  51. package/tests/hall_page_gate_map.mjs +3 -0
  52. package/tests/hall_tweak_editor.mjs +432 -0
  53. package/tests/page_tweak_hold.mjs +265 -0
  54. package/tests/publish_status_branch.mjs +23 -0
  55. package/tests/task_visual_slots.mjs +161 -0
  56. package/tests/tweak_batch_apply.mjs +265 -0
@@ -23,6 +23,7 @@ export interface DeleteSpecialitiesIdDocumentsDocIdResponse { ok: boolean }
23
23
  export interface DeleteTasksIdCriteriaCriterionIdResponse { ok: boolean; removed: unknown }
24
24
  export interface DeleteTasksIdDependenciesDepIdResponse { ok: boolean; removed: unknown }
25
25
  export interface DeleteTasksIdVisualResponse { ok: boolean; visual_url: unknown }
26
+ export interface DeleteTasksIdVisualsSlotResponse { ok: boolean; slot: unknown; visual_url: unknown }
26
27
  export interface ErrorEnvelope { error: ApiErrorObject }
27
28
  export interface GetAccessRequestsInvitesResponse { invites: unknown }
28
29
  export interface GetAccessRequestsResponse { requests: unknown }
@@ -170,6 +171,7 @@ export interface GetTasksClaimableResponse { claimable: unknown; claimable_total
170
171
  export interface GetTasksIdCriteriaResponse { criteria: unknown }
171
172
  export interface GetTasksIdDependenciesResponse { dependencies: unknown; dependents: unknown }
172
173
  export interface GetTasksIdRecommendationsResponse { recommendations: unknown; count: unknown }
174
+ export interface GetTasksIdVisualsResponse { ok: boolean; task_id: unknown; slots: unknown }
173
175
  export interface GetTasksNewcomerFloorResponse { disciplines: unknown }
174
176
  export interface GetTasksPeerVotesFeedResponse { tasks: unknown; can_vote: unknown }
175
177
  export interface GetTasksResponse { tasks: unknown }
@@ -471,6 +473,8 @@ export interface PostTasksIdPublishBranchRequest { branch: string; head_sha: str
471
473
  export interface PostTasksIdShipResponse { ok: boolean; task: unknown }
472
474
  export interface PostTasksIdVisualRequest { image_b64: string; content_type: string; alt?: string }
473
475
  export interface PostTasksIdVisualResponse { ok: boolean; visual_url: unknown; visual_alt: unknown; bytes: unknown }
476
+ export interface PostTasksIdVisualsSlotRequest { image_b64: string; content_type: string; alt?: string }
477
+ export interface PostTasksIdVisualsSlotResponse { ok: boolean; slot: unknown; visual_url: unknown; visual_alt: unknown; bytes: unknown }
474
478
  export interface PostTasksIdVoteRequest { vote: -1 | 0 | 1 }
475
479
  export interface PostTasksIdVoteResponse { ok: boolean; task_id: unknown; my_vote: unknown; net_votes: unknown; total_votes: unknown }
476
480
  export interface PostTasksNewcomerRestockResponse { ok: boolean; stamped: unknown; results: unknown }
@@ -773,6 +777,8 @@ export interface BongosClient {
773
777
  postCopyDeskPagesPageIdAsks(args: RequestArgs & { body: PostCopyDeskPagesPageIdAsksRequest }): Promise<ApiResponse>;
774
778
  /** POST /copy-desk/pages/{pageId}/claim — rank: any-builder */
775
779
  postCopyDeskPagesPageIdClaim(args?: RequestArgs): Promise<ApiResponse>;
780
+ /** GET /copy-desk/pages/{pageId}/draft — rank: any-builder */
781
+ getCopyDeskPagesPageIdDraft(args?: RequestArgs): Promise<ApiResponse>;
776
782
  /** PUT /copy-desk/pages/{pageId}/draft — rank: any-builder */
777
783
  putCopyDeskPagesPageIdDraft(args: RequestArgs & { body: PutCopyDeskPagesPageIdDraftRequest }): Promise<PutCopyDeskPagesPageIdDraftResponse>;
778
784
  /** GET /copy-desk/pages/{pageId}/draft.docx — rank: any-builder */
@@ -1505,6 +1511,12 @@ export interface BongosClient {
1505
1511
  deleteTasksIdVisual(args?: RequestArgs): Promise<DeleteTasksIdVisualResponse>;
1506
1512
  /** POST /tasks/{id}/visual — rank: any-builder */
1507
1513
  postTasksIdVisual(args: RequestArgs & { body: PostTasksIdVisualRequest }): Promise<PostTasksIdVisualResponse>;
1514
+ /** GET /tasks/{id}/visuals — rank: any-builder */
1515
+ getTasksIdVisuals(args?: RequestArgs): Promise<GetTasksIdVisualsResponse>;
1516
+ /** DELETE /tasks/{id}/visuals/{slot} — rank: any-builder */
1517
+ deleteTasksIdVisualsSlot(args?: RequestArgs): Promise<DeleteTasksIdVisualsSlotResponse>;
1518
+ /** POST /tasks/{id}/visuals/{slot} — rank: any-builder */
1519
+ postTasksIdVisualsSlot(args: RequestArgs & { body: PostTasksIdVisualsSlotRequest }): Promise<PostTasksIdVisualsSlotResponse>;
1508
1520
  /** POST /tasks/{id}/vote — rank: metic+archon */
1509
1521
  postTasksIdVote(args: RequestArgs & { body: PostTasksIdVoteRequest }): Promise<PostTasksIdVoteResponse>;
1510
1522
  /** POST /tasks/{id}/water — rank: any-builder */
@@ -349,6 +349,8 @@ export function createClient(opts = {}) {
349
349
  postCopyDeskPagesPageIdAsks: (args) => request("POST", "/copy-desk/pages/{pageId}/asks", { hasBody: true }, args),
350
350
  // POST /copy-desk/pages/{pageId}/claim — rank: any-builder — POST /copy-desk/pages/:pageId/claim
351
351
  postCopyDeskPagesPageIdClaim: (args) => request("POST", "/copy-desk/pages/{pageId}/claim", { hasBody: true }, args),
352
+ // GET /copy-desk/pages/{pageId}/draft — rank: any-builder — GET /copy-desk/pages/:pageId/draft
353
+ getCopyDeskPagesPageIdDraft: (args) => request("GET", "/copy-desk/pages/{pageId}/draft", { hasBody: false }, args),
352
354
  // PUT /copy-desk/pages/{pageId}/draft — rank: any-builder — PUT /copy-desk/pages/:pageId/draft
353
355
  putCopyDeskPagesPageIdDraft: (args) => request("PUT", "/copy-desk/pages/{pageId}/draft", { hasBody: true }, args),
354
356
  // GET /copy-desk/pages/{pageId}/draft.docx — rank: any-builder — GET /copy-desk/pages/:pageId/draft.docx
@@ -1081,6 +1083,12 @@ export function createClient(opts = {}) {
1081
1083
  deleteTasksIdVisual: (args) => request("DELETE", "/tasks/{id}/visual", { hasBody: false }, args),
1082
1084
  // POST /tasks/{id}/visual — rank: any-builder — POST /tasks/:id/visual
1083
1085
  postTasksIdVisual: (args) => request("POST", "/tasks/{id}/visual", { hasBody: true }, args),
1086
+ // GET /tasks/{id}/visuals — rank: any-builder — GET /tasks/:id/visuals
1087
+ getTasksIdVisuals: (args) => request("GET", "/tasks/{id}/visuals", { hasBody: false }, args),
1088
+ // DELETE /tasks/{id}/visuals/{slot} — rank: any-builder — DELETE /tasks/:id/visuals/:slot
1089
+ deleteTasksIdVisualsSlot: (args) => request("DELETE", "/tasks/{id}/visuals/{slot}", { hasBody: false }, args),
1090
+ // POST /tasks/{id}/visuals/{slot} — rank: any-builder — POST /tasks/:id/visuals/:slot
1091
+ postTasksIdVisualsSlot: (args) => request("POST", "/tasks/{id}/visuals/{slot}", { hasBody: true }, args),
1084
1092
  // POST /tasks/{id}/vote — rank: metic+archon — POST /tasks/:id/vote
1085
1093
  postTasksIdVote: (args) => request("POST", "/tasks/{id}/vote", { hasBody: true }, args),
1086
1094
  // POST /tasks/{id}/water — rank: any-builder — POST /tasks/:id/water
@@ -5312,6 +5312,49 @@
5312
5312
  }
5313
5313
  },
5314
5314
  "/copy-desk/pages/{pageId}/draft": {
5315
+ "get": {
5316
+ "operationId": "get_copy_desk_pages_pageId_draft",
5317
+ "tags": [
5318
+ "copy-desk"
5319
+ ],
5320
+ "summary": "GET /copy-desk/pages/:pageId/draft",
5321
+ "description": "------------------------------------------------------------------------- GET /copy-desk/pages/:pageId/draft — what the tweak editor opens on (task 1004321 / BV2.TW10, ADR 0341 D4): every line of the page reading in page order with its margin note, the open round and whether the caller holds it, and the saved draft (only on the current reading). The read the PUT below saves over, and the .docx download's own data as JSON. rank: any signed-in builder, as the download: the words are the page's own and the draft sits on a task every builder can read. -------------------------------------------------------------------------\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
5322
+ "x-rank": "any-builder",
5323
+ "x-source": "modules/copy-desk/routes/copy-desk.js",
5324
+ "parameters": [
5325
+ {
5326
+ "name": "pageId",
5327
+ "in": "path",
5328
+ "required": true,
5329
+ "schema": {
5330
+ "type": "string"
5331
+ },
5332
+ "description": "Path parameter `pageId`."
5333
+ }
5334
+ ],
5335
+ "responses": {
5336
+ "200": {
5337
+ "description": "Success."
5338
+ },
5339
+ "400": {
5340
+ "$ref": "#/components/responses/BadRequest"
5341
+ },
5342
+ "401": {
5343
+ "$ref": "#/components/responses/Unauthorized"
5344
+ },
5345
+ "403": {
5346
+ "$ref": "#/components/responses/Forbidden"
5347
+ },
5348
+ "404": {
5349
+ "$ref": "#/components/responses/NotFound"
5350
+ }
5351
+ },
5352
+ "security": [
5353
+ {
5354
+ "builderSession": []
5355
+ }
5356
+ ]
5357
+ },
5315
5358
  "put": {
5316
5359
  "operationId": "put_copy_desk_pages_pageId_draft",
5317
5360
  "tags": [
@@ -20412,6 +20455,189 @@
20412
20455
  ]
20413
20456
  }
20414
20457
  },
20458
+ "/tasks/{id}/visuals": {
20459
+ "get": {
20460
+ "operationId": "get_tasks_id_visuals",
20461
+ "tags": [
20462
+ "tasks"
20463
+ ],
20464
+ "summary": "GET /tasks/:id/visuals",
20465
+ "description": "GET /tasks/:id/visuals — the task's named visuals. Any signed-in builder: it lists URLs only, and each image is still served under its own task's audience.\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
20466
+ "x-rank": "any-builder",
20467
+ "x-source": "modules/lifecycle/routes/visuals.js",
20468
+ "parameters": [
20469
+ {
20470
+ "name": "id",
20471
+ "in": "path",
20472
+ "required": true,
20473
+ "schema": {
20474
+ "type": "string"
20475
+ },
20476
+ "description": "Path parameter `id`."
20477
+ }
20478
+ ],
20479
+ "responses": {
20480
+ "200": {
20481
+ "description": "Success.",
20482
+ "content": {
20483
+ "application/json": {
20484
+ "schema": {
20485
+ "$ref": "#/components/schemas/GetTasksIdVisualsResponse"
20486
+ }
20487
+ }
20488
+ }
20489
+ },
20490
+ "400": {
20491
+ "$ref": "#/components/responses/BadRequest"
20492
+ },
20493
+ "401": {
20494
+ "$ref": "#/components/responses/Unauthorized"
20495
+ },
20496
+ "403": {
20497
+ "$ref": "#/components/responses/Forbidden"
20498
+ },
20499
+ "404": {
20500
+ "$ref": "#/components/responses/NotFound"
20501
+ }
20502
+ },
20503
+ "security": [
20504
+ {
20505
+ "builderSession": []
20506
+ }
20507
+ ]
20508
+ }
20509
+ },
20510
+ "/tasks/{id}/visuals/{slot}": {
20511
+ "post": {
20512
+ "operationId": "post_tasks_id_visuals_slot",
20513
+ "tags": [
20514
+ "tasks"
20515
+ ],
20516
+ "summary": "POST /tasks/:id/visuals/:slot",
20517
+ "description": "POST /tasks/:id/visuals/:slot — attach (or replace) one named visual.\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
20518
+ "x-rank": "any-builder",
20519
+ "x-source": "modules/lifecycle/routes/visuals.js",
20520
+ "parameters": [
20521
+ {
20522
+ "name": "id",
20523
+ "in": "path",
20524
+ "required": true,
20525
+ "schema": {
20526
+ "type": "string"
20527
+ },
20528
+ "description": "Path parameter `id`."
20529
+ },
20530
+ {
20531
+ "name": "slot",
20532
+ "in": "path",
20533
+ "required": true,
20534
+ "schema": {
20535
+ "type": "string"
20536
+ },
20537
+ "description": "Path parameter `slot`."
20538
+ }
20539
+ ],
20540
+ "requestBody": {
20541
+ "required": true,
20542
+ "content": {
20543
+ "application/json": {
20544
+ "schema": {
20545
+ "$ref": "#/components/schemas/PostTasksIdVisualsSlotRequest"
20546
+ }
20547
+ }
20548
+ },
20549
+ "x-validated": true
20550
+ },
20551
+ "responses": {
20552
+ "200": {
20553
+ "description": "Success.",
20554
+ "content": {
20555
+ "application/json": {
20556
+ "schema": {
20557
+ "$ref": "#/components/schemas/PostTasksIdVisualsSlotResponse"
20558
+ }
20559
+ }
20560
+ }
20561
+ },
20562
+ "400": {
20563
+ "$ref": "#/components/responses/ValidationFailed"
20564
+ },
20565
+ "401": {
20566
+ "$ref": "#/components/responses/Unauthorized"
20567
+ },
20568
+ "403": {
20569
+ "$ref": "#/components/responses/Forbidden"
20570
+ },
20571
+ "404": {
20572
+ "$ref": "#/components/responses/NotFound"
20573
+ }
20574
+ },
20575
+ "security": [
20576
+ {
20577
+ "builderSession": []
20578
+ }
20579
+ ]
20580
+ },
20581
+ "delete": {
20582
+ "operationId": "delete_tasks_id_visuals_slot",
20583
+ "tags": [
20584
+ "tasks"
20585
+ ],
20586
+ "summary": "DELETE /tasks/:id/visuals/:slot",
20587
+ "description": "DELETE /tasks/:id/visuals/:slot — remove one named visual. Idempotent.\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
20588
+ "x-rank": "any-builder",
20589
+ "x-source": "modules/lifecycle/routes/visuals.js",
20590
+ "parameters": [
20591
+ {
20592
+ "name": "id",
20593
+ "in": "path",
20594
+ "required": true,
20595
+ "schema": {
20596
+ "type": "string"
20597
+ },
20598
+ "description": "Path parameter `id`."
20599
+ },
20600
+ {
20601
+ "name": "slot",
20602
+ "in": "path",
20603
+ "required": true,
20604
+ "schema": {
20605
+ "type": "string"
20606
+ },
20607
+ "description": "Path parameter `slot`."
20608
+ }
20609
+ ],
20610
+ "responses": {
20611
+ "200": {
20612
+ "description": "Success.",
20613
+ "content": {
20614
+ "application/json": {
20615
+ "schema": {
20616
+ "$ref": "#/components/schemas/DeleteTasksIdVisualsSlotResponse"
20617
+ }
20618
+ }
20619
+ }
20620
+ },
20621
+ "400": {
20622
+ "$ref": "#/components/responses/BadRequest"
20623
+ },
20624
+ "401": {
20625
+ "$ref": "#/components/responses/Unauthorized"
20626
+ },
20627
+ "403": {
20628
+ "$ref": "#/components/responses/Forbidden"
20629
+ },
20630
+ "404": {
20631
+ "$ref": "#/components/responses/NotFound"
20632
+ }
20633
+ },
20634
+ "security": [
20635
+ {
20636
+ "builderSession": []
20637
+ }
20638
+ ]
20639
+ }
20640
+ },
20415
20641
  "/tasks/{id}/vote": {
20416
20642
  "post": {
20417
20643
  "operationId": "post_tasks_id_vote",
@@ -21239,6 +21465,21 @@
21239
21465
  "visual_url"
21240
21466
  ]
21241
21467
  },
21468
+ "DeleteTasksIdVisualsSlotResponse": {
21469
+ "type": "object",
21470
+ "properties": {
21471
+ "ok": {
21472
+ "type": "boolean"
21473
+ },
21474
+ "slot": {},
21475
+ "visual_url": {}
21476
+ },
21477
+ "required": [
21478
+ "ok",
21479
+ "slot",
21480
+ "visual_url"
21481
+ ]
21482
+ },
21242
21483
  "ErrorEnvelope": {
21243
21484
  "type": "object",
21244
21485
  "required": [
@@ -23160,6 +23401,21 @@
23160
23401
  "count"
23161
23402
  ]
23162
23403
  },
23404
+ "GetTasksIdVisualsResponse": {
23405
+ "type": "object",
23406
+ "properties": {
23407
+ "ok": {
23408
+ "type": "boolean"
23409
+ },
23410
+ "task_id": {},
23411
+ "slots": {}
23412
+ },
23413
+ "required": [
23414
+ "ok",
23415
+ "task_id",
23416
+ "slots"
23417
+ ]
23418
+ },
23163
23419
  "GetTasksNewcomerFloorResponse": {
23164
23420
  "type": "object",
23165
23421
  "properties": {
@@ -28136,6 +28392,48 @@
28136
28392
  "bytes"
28137
28393
  ]
28138
28394
  },
28395
+ "PostTasksIdVisualsSlotRequest": {
28396
+ "type": "object",
28397
+ "properties": {
28398
+ "image_b64": {
28399
+ "type": "string",
28400
+ "minLength": 1,
28401
+ "maxLength": 7340032
28402
+ },
28403
+ "content_type": {
28404
+ "type": "string",
28405
+ "minLength": 1,
28406
+ "maxLength": 100
28407
+ },
28408
+ "alt": {
28409
+ "type": "string"
28410
+ }
28411
+ },
28412
+ "required": [
28413
+ "image_b64",
28414
+ "content_type"
28415
+ ],
28416
+ "additionalProperties": false
28417
+ },
28418
+ "PostTasksIdVisualsSlotResponse": {
28419
+ "type": "object",
28420
+ "properties": {
28421
+ "ok": {
28422
+ "type": "boolean"
28423
+ },
28424
+ "slot": {},
28425
+ "visual_url": {},
28426
+ "visual_alt": {},
28427
+ "bytes": {}
28428
+ },
28429
+ "required": [
28430
+ "ok",
28431
+ "slot",
28432
+ "visual_url",
28433
+ "visual_alt",
28434
+ "bytes"
28435
+ ]
28436
+ },
28139
28437
  "PostTasksIdVoteRequest": {
28140
28438
  "type": "object",
28141
28439
  "properties": {
@@ -28675,9 +28973,9 @@
28675
28973
  "description": "A required dependency/feature is not configured or is temporarily down."
28676
28974
  }
28677
28975
  },
28678
- "x-endpoint-count": 453,
28679
- "x-schema-count": 487,
28976
+ "x-endpoint-count": 457,
28977
+ "x-schema-count": 491,
28680
28978
  "x-undocumented-bodies": 10,
28681
- "x-response-schemas": 333,
28979
+ "x-response-schemas": 336,
28682
28980
  "x-generated-by": "scripts/gds/gen-api-docs.js"
28683
28981
  }
@@ -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. 453 endpoints across 76 route files.
5
+ > **Generated from the live route files** — the route file is authoritative. 457 endpoints across 76 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/0016-trust-boundary-server-enforced-permissions.md)): `public` < `any-builder` < `metic+archon` < `archon`.
@@ -210,7 +210,7 @@ Base path: `/api/bongos`. Ranks (enforced server-side, [ADR 0016](adr/0016-trust
210
210
  | GET | `/api/bongos/connections/requests` | `any-builder` | — | MY pending requests, both directions (own data). |
211
211
  | GET | `/api/bongos/connections/suggestions` | `any-builder` | — | "builders you may know" (R21, task 1002297; ADR 0202 D5). |
212
212
 
213
- ## `copy-desk` (15)
213
+ ## `copy-desk` (16)
214
214
 
215
215
  | Method | Path | Rank | Body | Description |
216
216
  |---|---|---|---|---|
@@ -221,6 +221,7 @@ Base path: `/api/bongos`. Ranks (enforced server-side, [ADR 0016](adr/0016-trust
221
221
  | GET | `/api/bongos/copy-desk/pages/:pageId` | `any-builder` | — | ------------------------------------------------------------------------- GET /copy-desk/pages/:pageId — one page: status, changelog, the… |
222
222
  | POST | `/api/bongos/copy-desk/pages/:pageId/asks` | `any-builder` | `reason` | ------------------------------------------------------------------------- POST /copy-desk/pages/:pageId/asks — ask for a page (task 10043… |
223
223
  | POST | `/api/bongos/copy-desk/pages/:pageId/claim` | `any-builder` | validated | ------------------------------------------------------------------------- POST /copy-desk/pages/:pageId/claim — claim a page's tweak (tas… |
224
+ | GET | `/api/bongos/copy-desk/pages/:pageId/draft` | `any-builder` | — | ------------------------------------------------------------------------- GET /copy-desk/pages/:pageId/draft — what the tweak editor open… |
224
225
  | PUT | `/api/bongos/copy-desk/pages/:pageId/draft` | `any-builder` | `reading_hash`, `lines` | ------------------------------------------------------------------------- PUT /copy-desk/pages/:pageId/draft — autosave the artist's draf… |
225
226
  | GET | `/api/bongos/copy-desk/pages/:pageId/draft.docx` | `any-builder` | — | ------------------------------------------------------------------------- GET /copy-desk/pages/:pageId/draft.docx — download the page's w… |
226
227
  | POST | `/api/bongos/copy-desk/pages/:pageId/draft.docx` | `any-builder` | _undocumented_ | ------------------------------------------------------------------------- POST /copy-desk/pages/:pageId/draft.docx — upload the Word file… |
@@ -742,7 +743,7 @@ Base path: `/api/bongos`. Ranks (enforced server-side, [ADR 0016](adr/0016-trust
742
743
  |---|---|---|---|---|
743
744
  | GET | `/api/bongos/task-visuals/:name` | `public` | — | the WIDEST path this route can take, declared honestly. |
744
745
 
745
- ## `tasks` (32)
746
+ ## `tasks` (35)
746
747
 
747
748
  | Method | Path | Rank | Body | Description |
748
749
  |---|---|---|---|---|
@@ -771,6 +772,9 @@ Base path: `/api/bongos`. Ranks (enforced server-side, [ADR 0016](adr/0016-trust
771
772
  | POST | `/api/bongos/tasks/:id/ship` | `any-builder` | validated | confirmed → shipped. |
772
773
  | POST | `/api/bongos/tasks/:id/visual` | `any-builder` | `image_b64`, `content_type`, `alt` | POST /tasks/:id/visual — attach (or replace) this task's ship-time visual. |
773
774
  | DELETE | `/api/bongos/tasks/:id/visual` | `any-builder` | — | DELETE /tasks/:id/visual — remove it again. |
775
+ | GET | `/api/bongos/tasks/:id/visuals` | `any-builder` | — | GET /tasks/:id/visuals — the task's named visuals. |
776
+ | POST | `/api/bongos/tasks/:id/visuals/:slot` | `any-builder` | `image_b64`, `content_type`, `alt` | POST /tasks/:id/visuals/:slot — attach (or replace) one named visual. |
777
+ | DELETE | `/api/bongos/tasks/:id/visuals/:slot` | `any-builder` | — | DELETE /tasks/:id/visuals/:slot — remove one named visual. |
774
778
  | POST | `/api/bongos/tasks/:id/vote` | `metic+archon` | `vote` | POST /tasks/:id/vote { vote: 1 \| -1 \| 0 } — cast/change/clear a peer vote on a confirmed/shipped task. |
775
779
  | POST | `/api/bongos/tasks/:id/water` | `any-builder` | — | POST /tasks/:id/water — reset a rotting task's clock. |
776
780
  | GET | `/api/bongos/tasks/claimable` | `any-builder` | — | NOTE: /tasks/claimable must come BEFORE /tasks/:id or Express will route 'claimable' to the :id param. |