@bongos/core 1.20.58 → 1.20.60

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 (119) hide show
  1. package/.bongos-core.json +198 -108
  2. package/clients/bongos-client/README.md +1 -1
  3. package/clients/bongos-client/bongos-client.global.js +10 -0
  4. package/clients/bongos-client/index.cjs +10 -0
  5. package/clients/bongos-client/index.d.ts +15 -2
  6. package/clients/bongos-client/index.mjs +10 -0
  7. package/docs/adr/0358-a-hall-wears-a-look-and-its-night-takes-a-tint.md +52 -0
  8. package/docs/adr/README.md +1 -0
  9. package/docs/api/openapi.json +317 -6
  10. package/docs/api-reference.md +8 -3
  11. package/docs/architecture.md +1 -0
  12. package/docs/copy-inventory.md +339 -330
  13. package/docs/copy-registry.json +524 -439
  14. package/docs/module-api-changelog.md +4 -0
  15. package/docs/page-inventory.json +4 -1
  16. package/docs/page-readings.json +729 -678
  17. package/migrations/core_268_builders_main_discipline.sql +35 -0
  18. package/modules/copy-desk/artist-stats.js +56 -0
  19. package/modules/copy-desk/module.json +1 -1
  20. package/modules/copy-desk/page-status.js +39 -0
  21. package/modules/copy-desk/routes/copy-desk.js +7 -16
  22. package/modules/copy-desk/tests/copy_no_cms.mjs +10 -1
  23. package/modules/economy/credits-by-craft.js +208 -0
  24. package/modules/economy/reward.js +8 -0
  25. package/modules/hall-ui/public/atlas.html +1 -1
  26. package/modules/hall-ui/public/blockers.html +1 -1
  27. package/modules/hall-ui/public/board-room.html +1 -1
  28. package/modules/hall-ui/public/collab.html +1 -1
  29. package/modules/hall-ui/public/commands.html +1 -1
  30. package/modules/hall-ui/public/copy-desk.html +1 -1
  31. package/modules/hall-ui/public/deploy.html +1 -1
  32. package/modules/hall-ui/public/diagrams.html +1 -1
  33. package/modules/hall-ui/public/drachmae.html +1 -1
  34. package/modules/hall-ui/public/fleet.html +1 -1
  35. package/modules/hall-ui/public/gate.html +1 -1
  36. package/modules/hall-ui/public/goal-map.html +1 -1
  37. package/modules/hall-ui/public/goals.html +1 -1
  38. package/modules/hall-ui/public/government.html +1 -1
  39. package/modules/hall-ui/public/hall-render.js +2 -2
  40. package/modules/hall-ui/public/idea.html +1 -1
  41. package/modules/hall-ui/public/ideas.html +1 -1
  42. package/modules/hall-ui/public/index.html +1 -1
  43. package/modules/hall-ui/public/modules.html +1 -1
  44. package/modules/hall-ui/public/primer.html +1 -1
  45. package/modules/hall-ui/public/profile.html +1 -1
  46. package/modules/hall-ui/public/profile.js +1 -1
  47. package/modules/hall-ui/public/project-settings.html +1 -1
  48. package/modules/hall-ui/public/ranks.html +1 -1
  49. package/modules/hall-ui/public/roadmap.html +1 -1
  50. package/modules/hall-ui/public/roster.html +1 -1
  51. package/modules/hall-ui/public/sessions.html +1 -1
  52. package/modules/hall-ui/public/settings.html +1 -1
  53. package/modules/hall-ui/public/shell.js +5 -1
  54. package/modules/hall-ui/public/studio.html +1 -1
  55. package/modules/hall-ui/public/style.css +8 -0
  56. package/modules/hall-ui/public/task.html +1 -1
  57. package/modules/hall-ui/public/thinking.html +1 -1
  58. package/modules/hall-ui/public/tweak-editor.html +1 -1
  59. package/modules/hall-ui/public/watch.html +1 -1
  60. package/modules/hall-ui/public/work.html +1 -1
  61. package/modules/ideas/ideator-stats.js +149 -0
  62. package/modules/ideas/module.json +2 -1
  63. package/modules/ideas/routes/inbox.js +7 -0
  64. package/modules/lifecycle/activity.js +5 -2
  65. package/modules/lifecycle/db-analytics.js +4 -2
  66. package/modules/lifecycle/db-tasks.js +49 -1
  67. package/modules/lifecycle/db.js +3 -2
  68. package/modules/lifecycle/page-tweak-reads.js +23 -5
  69. package/modules/provisioning/look.js +169 -0
  70. package/modules/provisioning/migrations/provisioning_034_project_logo.sql +35 -0
  71. package/modules/provisioning/module.json +2 -1
  72. package/modules/provisioning/provisioning.js +4 -3
  73. package/modules/provisioning/routes/look.js +204 -0
  74. package/modules/provisioning/routes/provisioning.js +5 -59
  75. package/modules/provisioning/settings-push.js +76 -0
  76. package/modules/public-landing/public/assets/cosmos.css +1 -1
  77. package/modules/public-landing/public/projects.html +499 -28
  78. package/modules/public-landing/public/projects.probes.json +2 -2
  79. package/modules/public-landing/public/projects.states.json +6 -3
  80. package/modules/ui-design/kit/serve.js +50 -0
  81. package/package-lock.json +2 -2
  82. package/package.json +1 -1
  83. package/release-notes.json +12 -0
  84. package/scripts/gds/fitness.js +4 -0
  85. package/scripts/gds/run-unit-tests.js +5 -0
  86. package/src/bongos/db.js +44 -6
  87. package/src/bongos/role-stats.js +155 -0
  88. package/src/bongos/routes/builders.js +15 -2
  89. package/src/bongos/routes/me.js +11 -3
  90. package/src/bongos/routes.js +4 -1
  91. package/src/bongos/serve-internal.js +6 -0
  92. package/src/branding.js +26 -1
  93. package/src/hall-look.js +99 -0
  94. package/src/module-api.js +1 -1
  95. package/src/night-tint.js +26 -0
  96. package/tests/copy_desk_page_reads.mjs +1 -1
  97. package/tests/currency_label.mjs +7 -4
  98. package/tests/fixtures/page-ledger.mjs +1 -1
  99. package/tests/hall_tokens.mjs +10 -1
  100. package/tests/hall_tweak_editor.mjs +1 -1
  101. package/tests/look_night_tint.mjs +169 -0
  102. package/tests/main_discipline.mjs +81 -0
  103. package/tests/nav_permission_atoms.mjs +1 -1
  104. package/tests/profile_role_stats.mjs +416 -0
  105. package/tests/projects_hub.mjs +5 -4
  106. package/tests/projects_hub_app_status.mjs +1 -1
  107. package/tests/projects_hub_app_step.mjs +8 -7
  108. package/tests/projects_hub_look.mjs +255 -0
  109. package/tests/projects_hub_module_picker.mjs +2 -2
  110. package/tests/provision_settings_apply.mjs +12 -4
  111. package/tests/provisioning_look.mjs +376 -0
  112. package/tests/provisioning_settings.mjs +10 -7
  113. package/tests/provisioning_settings_apply.mjs +4 -4
  114. package/tests/provisioning_settings_env.mjs +4 -0
  115. package/tests/role_stats_db.mjs +237 -0
  116. package/tests/tweak_replaces_artist_review.mjs +1 -1
  117. package/tests/wizard_draft_resume.mjs +2 -2
  118. package/tests/wizard_front_door.mjs +2 -2
  119. package/tests/wizard_intent_resume.mjs +16 -15
@@ -5,7 +5,7 @@ A **generated**, zero-dependency typed client for the Bongos API — produced fr
5
5
  by hand; it regenerates when the spec changes, so it can never drift from the routes.
6
6
 
7
7
  - API version: **v1** (served at `/api/bongos/v1`)
8
- - 478 operations across 73 resource groups
8
+ - 483 operations across 73 resource groups
9
9
 
10
10
  ## Use it from your project
11
11
 
@@ -855,6 +855,14 @@ function createClient(opts = {}) {
855
855
  postProvisioningInstancesIdGithubApp: (args) => request("POST", "/provisioning/instances/{id}/github-app", { hasBody: true }, args),
856
856
  // GET /provisioning/instances/{id}/invite-suggestions — rank: any-builder — GET /provisioning/instances/:id/invite-suggestions
857
857
  getProvisioningInstancesIdInviteSuggestions: (args) => request("GET", "/provisioning/instances/{id}/invite-suggestions", { hasBody: false }, args),
858
+ // DELETE /provisioning/instances/{id}/logo — rank: any-builder — DELETE /provisioning/instances/:id/logo
859
+ deleteProvisioningInstancesIdLogo: (args) => request("DELETE", "/provisioning/instances/{id}/logo", { hasBody: true }, args),
860
+ // PUT /provisioning/instances/{id}/logo — rank: any-builder — PUT /provisioning/instances/:id/logo
861
+ putProvisioningInstancesIdLogo: (args) => request("PUT", "/provisioning/instances/{id}/logo", { hasBody: true }, args),
862
+ // GET /provisioning/instances/{id}/look — rank: any-builder — GET /provisioning/instances/:id/look
863
+ getProvisioningInstancesIdLook: (args) => request("GET", "/provisioning/instances/{id}/look", { hasBody: false }, args),
864
+ // PATCH /provisioning/instances/{id}/look — rank: any-builder — PATCH /provisioning/instances/:id/look
865
+ patchProvisioningInstancesIdLook: (args) => request("PATCH", "/provisioning/instances/{id}/look", { hasBody: true }, args),
858
866
  // GET /provisioning/instances/{id}/render — rank: any-builder — GET /provisioning/instances/:id/render
859
867
  getProvisioningInstancesIdRender: (args) => request("GET", "/provisioning/instances/{id}/render", { hasBody: false }, args),
860
868
  // POST /provisioning/instances/{id}/render — rank: any-builder — POST /provisioning/instances/:id/render
@@ -871,6 +879,8 @@ function createClient(opts = {}) {
871
879
  postProvisioningInstancesIdTeardown: (args) => request("POST", "/provisioning/instances/{id}/teardown", { hasBody: true }, args),
872
880
  // POST /provisioning/instances/{id}/update-channel — rank: archon — POST /provisioning/instances/:id/update-channel
873
881
  postProvisioningInstancesIdUpdateChannel: (args) => request("POST", "/provisioning/instances/{id}/update-channel", { hasBody: true }, args),
882
+ // GET /provisioning/logos/{file} — rank: public — GET /provisioning/logos/:file
883
+ getProvisioningLogosFile: (args) => request("GET", "/provisioning/logos/{file}", { hasBody: false }, args),
874
884
  // GET /provisioning/onboard-plan — rank: public — GET /provisioning/onboard-plan
875
885
  getProvisioningOnboardPlan: (args) => request("GET", "/provisioning/onboard-plan", { hasBody: false }, args),
876
886
  // GET /provisioning/recommendations — rank: public — GET /provisioning/recommendations
@@ -854,6 +854,14 @@ function createClient(opts = {}) {
854
854
  postProvisioningInstancesIdGithubApp: (args) => request("POST", "/provisioning/instances/{id}/github-app", { hasBody: true }, args),
855
855
  // GET /provisioning/instances/{id}/invite-suggestions — rank: any-builder — GET /provisioning/instances/:id/invite-suggestions
856
856
  getProvisioningInstancesIdInviteSuggestions: (args) => request("GET", "/provisioning/instances/{id}/invite-suggestions", { hasBody: false }, args),
857
+ // DELETE /provisioning/instances/{id}/logo — rank: any-builder — DELETE /provisioning/instances/:id/logo
858
+ deleteProvisioningInstancesIdLogo: (args) => request("DELETE", "/provisioning/instances/{id}/logo", { hasBody: true }, args),
859
+ // PUT /provisioning/instances/{id}/logo — rank: any-builder — PUT /provisioning/instances/:id/logo
860
+ putProvisioningInstancesIdLogo: (args) => request("PUT", "/provisioning/instances/{id}/logo", { hasBody: true }, args),
861
+ // GET /provisioning/instances/{id}/look — rank: any-builder — GET /provisioning/instances/:id/look
862
+ getProvisioningInstancesIdLook: (args) => request("GET", "/provisioning/instances/{id}/look", { hasBody: false }, args),
863
+ // PATCH /provisioning/instances/{id}/look — rank: any-builder — PATCH /provisioning/instances/:id/look
864
+ patchProvisioningInstancesIdLook: (args) => request("PATCH", "/provisioning/instances/{id}/look", { hasBody: true }, args),
857
865
  // GET /provisioning/instances/{id}/render — rank: any-builder — GET /provisioning/instances/:id/render
858
866
  getProvisioningInstancesIdRender: (args) => request("GET", "/provisioning/instances/{id}/render", { hasBody: false }, args),
859
867
  // POST /provisioning/instances/{id}/render — rank: any-builder — POST /provisioning/instances/:id/render
@@ -870,6 +878,8 @@ function createClient(opts = {}) {
870
878
  postProvisioningInstancesIdTeardown: (args) => request("POST", "/provisioning/instances/{id}/teardown", { hasBody: true }, args),
871
879
  // POST /provisioning/instances/{id}/update-channel — rank: archon — POST /provisioning/instances/:id/update-channel
872
880
  postProvisioningInstancesIdUpdateChannel: (args) => request("POST", "/provisioning/instances/{id}/update-channel", { hasBody: true }, args),
881
+ // GET /provisioning/logos/{file} — rank: public — GET /provisioning/logos/:file
882
+ getProvisioningLogosFile: (args) => request("GET", "/provisioning/logos/{file}", { hasBody: false }, args),
873
883
  // GET /provisioning/onboard-plan — rank: public — GET /provisioning/onboard-plan
874
884
  getProvisioningOnboardPlan: (args) => request("GET", "/provisioning/onboard-plan", { hasBody: false }, args),
875
885
  // GET /provisioning/recommendations — rank: public — GET /provisioning/recommendations
@@ -43,7 +43,7 @@ export interface GetBuildersDirectoryResponse { builders: unknown }
43
43
  export interface GetBuildersIdActiveClaimsResponse { builder_id: unknown; claims: unknown; stale_hours: unknown; stale_hours_source: unknown }
44
44
  export interface GetBuildersIdActivityResponse { builder_id: unknown; section: unknown; role: unknown; rows: unknown; total: unknown }
45
45
  export interface GetBuildersIdOnboardingResponse { builder_id: unknown; onboarding: unknown }
46
- export interface GetBuildersIdProfileResponse { builder: unknown; shipped_count: unknown; recent_ships: unknown; achievements: unknown; cross_project?: unknown; handle?: unknown }
46
+ export interface GetBuildersIdProfileResponse { builder: unknown; shipped_count: unknown; recent_ships: unknown; achievements: unknown; roles: unknown; cross_project?: unknown; handle?: unknown }
47
47
  export interface GetBuildersMePendingRankChangeResponse { change: unknown; greeting?: unknown }
48
48
  export interface GetBuildersRosterResponse { builders: unknown; stale_hours: unknown; stale_hours_source: unknown }
49
49
  export interface GetCliCommandsResponse { version: unknown; groups: unknown }
@@ -124,6 +124,7 @@ export interface GetProvisioningGithubAppStatusResponse { ok: boolean; status: u
124
124
  export interface GetProvisioningHealthResponse { module: unknown; ok: boolean; coreVersion: unknown }
125
125
  export interface GetProvisioningInstancesIdEnvManifestResponse { instance: unknown; env_vars: unknown; environments: unknown; values_held: boolean; note: unknown }
126
126
  export interface GetProvisioningInstancesIdInviteSuggestionsResponse { suggested: unknown; seeking: unknown; reason: unknown; unavailable?: unknown }
127
+ export interface GetProvisioningInstancesIdLookResponse { ok: boolean; look: unknown; options: unknown; logo_max_bytes: unknown }
127
128
  export interface GetProvisioningInstancesIdRenderResponse { ok: boolean; app: unknown; env_vars: unknown; values_held: boolean }
128
129
  export interface GetProvisioningInstancesIdResponse { instance: unknown; open_intent: unknown; github_app: unknown }
129
130
  export interface GetProvisioningInstancesIdSettingsResponse { ok: boolean; settings: unknown; planet: unknown; options: unknown }
@@ -204,7 +205,7 @@ export interface PatchInboxIdRequest { status?: "open" | "promoted" | "discarded
204
205
  export interface PatchInboxIdResponse { idea: unknown }
205
206
  export interface PatchMeCrossProjectRequest { hide_stats?: boolean; account_visibility?: string; recruiter_discoverable?: boolean }
206
207
  export interface PatchMeCrossProjectResponse { hide_stats: boolean; account_visibility: unknown; recruiter_discoverable: unknown; recruiter_discoverable_effective: unknown }
207
- export interface PatchMeDisciplinesRequest { preferred_disciplines: string[] }
208
+ export interface PatchMeDisciplinesRequest { preferred_disciplines: string[]; main_discipline?: string }
208
209
  export interface PatchMeDisciplinesResponse { builder: unknown; onboarding: unknown }
209
210
  export interface PatchMeDisplayNameResponse { display_name: unknown; max_length: unknown }
210
211
  export interface PatchMeEventSoundPrefsResponse { prefs: unknown; effective: unknown; effective_wav: unknown; events: unknown }
@@ -224,6 +225,7 @@ export interface PatchProvisioningInstancesIdDetailRequest { description?: strin
224
225
  export interface PatchProvisioningInstancesIdDetailResponse { ok: boolean; description: unknown; detail: unknown; options: unknown; soft_limits: unknown; publish: unknown; modules: unknown; type: unknown }
225
226
  export interface PatchProvisioningInstancesIdEnvManifestVarIdRequest { name?: string; description?: string; environments?: unknown[]; required?: boolean }
226
227
  export interface PatchProvisioningInstancesIdEnvManifestVarIdResponse { ok: boolean; env_var: unknown; values_held: boolean }
228
+ export interface PatchProvisioningInstancesIdLookRequest { look?: string; night_tint?: string; accent?: string }
227
229
  export interface PatchProvisioningInstancesIdSettingsResponse { ok: boolean; saved: unknown; planet: unknown; push: unknown }
228
230
  export interface PatchSpecialitiesIdRequest { name?: string; summary?: string; contract_md?: string; visibility?: string; sellable?: boolean; skills?: string[] }
229
231
  export interface PatchSpecialitiesIdResponse { speciality: unknown }
@@ -503,6 +505,7 @@ export interface PutGovernmentRanksRankKeyPermissionsPermissionKeyResponse { ok:
503
505
  export interface PutMingleOptInRequest { opted_in: boolean }
504
506
  export interface PutMingleOptInResponse { opted_in: unknown; updated_at: unknown }
505
507
  export interface PutMingleProjectRequest { enabled: boolean }
508
+ export interface PutProvisioningInstancesIdLogoRequest { image_b64: string; content_type: string }
506
509
  export interface PutRenderDeployAppRequest { ownerId?: string; serviceId?: string }
507
510
  export interface PutRenderDeployAppResponse { app: unknown }
508
511
  export interface PutSpecialitiesIdSkillsRequest { enabled_skills: string[] }
@@ -1294,6 +1297,14 @@ export interface BongosClient {
1294
1297
  postProvisioningInstancesIdGithubApp(args?: RequestArgs & { body?: PostProvisioningInstancesIdGithubAppRequest }): Promise<PostProvisioningInstancesIdGithubAppResponse>;
1295
1298
  /** GET /provisioning/instances/{id}/invite-suggestions — rank: any-builder */
1296
1299
  getProvisioningInstancesIdInviteSuggestions(args?: RequestArgs): Promise<GetProvisioningInstancesIdInviteSuggestionsResponse>;
1300
+ /** DELETE /provisioning/instances/{id}/logo — rank: any-builder */
1301
+ deleteProvisioningInstancesIdLogo(args?: RequestArgs): Promise<ApiResponse>;
1302
+ /** PUT /provisioning/instances/{id}/logo — rank: any-builder */
1303
+ putProvisioningInstancesIdLogo(args: RequestArgs & { body: PutProvisioningInstancesIdLogoRequest }): Promise<ApiResponse>;
1304
+ /** GET /provisioning/instances/{id}/look — rank: any-builder */
1305
+ getProvisioningInstancesIdLook(args?: RequestArgs): Promise<GetProvisioningInstancesIdLookResponse>;
1306
+ /** PATCH /provisioning/instances/{id}/look — rank: any-builder */
1307
+ patchProvisioningInstancesIdLook(args?: RequestArgs & { body?: PatchProvisioningInstancesIdLookRequest }): Promise<ApiResponse>;
1297
1308
  /** GET /provisioning/instances/{id}/render — rank: any-builder */
1298
1309
  getProvisioningInstancesIdRender(args?: RequestArgs): Promise<GetProvisioningInstancesIdRenderResponse>;
1299
1310
  /** POST /provisioning/instances/{id}/render — rank: any-builder */
@@ -1310,6 +1321,8 @@ export interface BongosClient {
1310
1321
  postProvisioningInstancesIdTeardown(args?: RequestArgs): Promise<PostProvisioningInstancesIdTeardownResponse>;
1311
1322
  /** POST /provisioning/instances/{id}/update-channel — rank: archon */
1312
1323
  postProvisioningInstancesIdUpdateChannel(args?: RequestArgs): Promise<ApiResponse>;
1324
+ /** GET /provisioning/logos/{file} — rank: public */
1325
+ getProvisioningLogosFile(args?: RequestArgs): Promise<ApiResponse>;
1313
1326
  /** GET /provisioning/onboard-plan — rank: public */
1314
1327
  getProvisioningOnboardPlan(args?: RequestArgs): Promise<GetProvisioningOnboardPlanResponse>;
1315
1328
  /** GET /provisioning/recommendations — rank: public */
@@ -851,6 +851,14 @@ export function createClient(opts = {}) {
851
851
  postProvisioningInstancesIdGithubApp: (args) => request("POST", "/provisioning/instances/{id}/github-app", { hasBody: true }, args),
852
852
  // GET /provisioning/instances/{id}/invite-suggestions — rank: any-builder — GET /provisioning/instances/:id/invite-suggestions
853
853
  getProvisioningInstancesIdInviteSuggestions: (args) => request("GET", "/provisioning/instances/{id}/invite-suggestions", { hasBody: false }, args),
854
+ // DELETE /provisioning/instances/{id}/logo — rank: any-builder — DELETE /provisioning/instances/:id/logo
855
+ deleteProvisioningInstancesIdLogo: (args) => request("DELETE", "/provisioning/instances/{id}/logo", { hasBody: true }, args),
856
+ // PUT /provisioning/instances/{id}/logo — rank: any-builder — PUT /provisioning/instances/:id/logo
857
+ putProvisioningInstancesIdLogo: (args) => request("PUT", "/provisioning/instances/{id}/logo", { hasBody: true }, args),
858
+ // GET /provisioning/instances/{id}/look — rank: any-builder — GET /provisioning/instances/:id/look
859
+ getProvisioningInstancesIdLook: (args) => request("GET", "/provisioning/instances/{id}/look", { hasBody: false }, args),
860
+ // PATCH /provisioning/instances/{id}/look — rank: any-builder — PATCH /provisioning/instances/:id/look
861
+ patchProvisioningInstancesIdLook: (args) => request("PATCH", "/provisioning/instances/{id}/look", { hasBody: true }, args),
854
862
  // GET /provisioning/instances/{id}/render — rank: any-builder — GET /provisioning/instances/:id/render
855
863
  getProvisioningInstancesIdRender: (args) => request("GET", "/provisioning/instances/{id}/render", { hasBody: false }, args),
856
864
  // POST /provisioning/instances/{id}/render — rank: any-builder — POST /provisioning/instances/:id/render
@@ -867,6 +875,8 @@ export function createClient(opts = {}) {
867
875
  postProvisioningInstancesIdTeardown: (args) => request("POST", "/provisioning/instances/{id}/teardown", { hasBody: true }, args),
868
876
  // POST /provisioning/instances/{id}/update-channel — rank: archon — POST /provisioning/instances/:id/update-channel
869
877
  postProvisioningInstancesIdUpdateChannel: (args) => request("POST", "/provisioning/instances/{id}/update-channel", { hasBody: true }, args),
878
+ // GET /provisioning/logos/{file} — rank: public — GET /provisioning/logos/:file
879
+ getProvisioningLogosFile: (args) => request("GET", "/provisioning/logos/{file}", { hasBody: false }, args),
870
880
  // GET /provisioning/onboard-plan — rank: public — GET /provisioning/onboard-plan
871
881
  getProvisioningOnboardPlan: (args) => request("GET", "/provisioning/onboard-plan", { hasBody: false }, args),
872
882
  // GET /provisioning/recommendations — rank: public — GET /provisioning/recommendations
@@ -0,0 +1,52 @@
1
+ # ADR 0358 — A hall wears a look, and its night takes a tint of it
2
+
3
+ - **Status:** accepted
4
+ - **Date:** 2026-09-30
5
+ - **Task:** [task 1004421](https://cloudbongos.com/builders#/task/1004421) (BV2.PS06, goal 1000121 — project startup; spec `docs/specs/<redacted>.md` D2 and D8)
6
+ - **Amends:** [ADR 0219](0219-a-look-is-a-branding-pack-the-style-library.md) Context §2 and the rejected "dark tier" alternative (a look could not carry a dark ground), and `DESIGN.md`'s "Pure black in dark" rule, for halls only
7
+ - **Keeps:** [ADR 0204](0204-the-apex-is-dark-only.md) (the platform's own apex is dark-only, pure black), [ADR 0062 §3](0062-medusa-instance-model-decoupling.md) (the branding contract; still thirteen colours and two faces)
8
+ - **Decided with:** the owner, 2026-09-30 — D2 in the planning session (the tint is allowed and on by default), and "a custom look is one accent used in both modes" the same day.
9
+
10
+ ## Context
11
+
12
+ The project-startup flow lets a founder give a new project a look, so that a builder who works in several projects always knows which hall they are in. ADR 0219 already made a look a branding pack: thirteen colours and two font stacks, laid over the instance's pack. But it left two things out:
13
+
14
+ 1. **Nothing let the platform set a hall's look.** A look was a file an instance owner copied into `config/branding.json` by hand.
15
+ 2. **Every look's night was the same pure black.** The pack is one-mode, so in dark mode only the accent told one hall from another.
16
+
17
+ The second is a world rule (`DESIGN.md`: "Pure black in dark"). It exists because the chrome sculpture's rendered plates composite into `#000000` with `lighten` and leave no seam. The owner decided (D2) that a hall may give that up: each look gets a subtle tinted night, on by default, and the founder can switch it off.
18
+
19
+ ## Decision
20
+
21
+ **D1. The night tint is derived, never authored.** When a hall wears a look with the tint on, its four dark grounds take a small share of the look's own accent:
22
+
23
+ | token | tinted night |
24
+ |---|---|
25
+ | `--bg`, `--bg-deep` | `color-mix(in srgb, var(--accent) 6%, #000000)` |
26
+ | `--bg-frame` | `color-mix(in srgb, var(--accent) 6%, #08080a)` |
27
+ | `--bg-card` | `color-mix(in srgb, var(--accent) 5%, #101012)` |
28
+
29
+ The card's share is the smaller because the hall's info chip (`--info` on `--info-weak`, both mixed from the card) was the thinnest pair under a tint, and at 8% it fell to 4.37:1; 5% clears every look. No look carries a dark palette and no token is added: the tint is a formula over the thirteen, so the contract stays at fifteen and a custom accent gets its own night for free. The table lives once, in `src/night-tint.js`; `themeMarkup()` emits it after the hall's sheet as the two dark twins the sheet already writes (`html[data-theme="dark"]` and the `prefers-color-scheme` block), at equal specificity, so it wins on order. The inks, the status vocabulary and every derived recipe stay the sheet's.
30
+
31
+ **D2. The tint is on by default, and only a look turns it on.** A hall that has never chosen a look renders exactly as it does today, pure black included, whatever the tint setting says. The founder's switch puts a looked hall back on pure black.
32
+
33
+ **D3. The apex and the hub stay pure black.** This decision is about a project's hall. The platform's own surfaces (ADR 0204) keep the world rule, and `DESIGN.md` says so where it states the rule.
34
+
35
+ **D4. A custom look is one accent, used in both modes, nudged until it reads.** The founder picks one colour. It is laid over the chrome world's palette as `accent`. If it fails any of the pairs the hall paints with it (dark ink on an accent fill; the accent as text on the black and tinted grounds; the light mode's derived accent ink on paper), its lightness moves, the hue staying put, to the nearest value that passes. The preview shows the adjusted colour. There is no separate dark accent and no sixteenth token. The nudge is one algorithm, `lookAdjustAccent`, in `modules/provisioning/look.js`; the create wizard carries a copy that a test pins to it.
36
+
37
+ **D5. The look travels the settings road.** `look` (the four library looks, `custom`, or `own` = the instance's own pack) and `night_tint` (`on` | `off`) join the provisioning settings vocabulary, so they reach a running hall the way every other policy does: written to `web.env`, applied by a restart (the pack is memoised). The adjusted accent and the logo's address ride as companion variables. `src/branding.js` resolves the look from the style library on the instance itself, so the platform never sends a palette, only a name.
38
+
39
+ **D6. A logo is an image the platform keeps.** PNG, JPEG or WebP only, at most 256 KB, checked by its magic bytes, never SVG (an SVG is a document that can carry script). The platform stores it and serves it at a content-addressed public address; the hall shows it in its mark and the browser tab uses it as the favicon. Without a logo, a looked hall's favicon is drawn in the look's own colours.
40
+
41
+ ## Consequences
42
+
43
+ - A founder picks a look, a night and a logo at creation, and an existing project's owner picks the same three on its manage page (D8). Both save through the platform; the hall restarts once to wear it.
44
+ - Contrast is measured, not hoped for: `tests/look_night_tint.mjs` runs the hall's own token suite under every look with the tint on, and under custom accents across the hue wheel.
45
+ - A hall with a tinted night loses the seamless `lighten` composite for any rendered plate. The hall ships no plate today (`--plate: none`), so nothing shows a seam; a hall that adds one later must switch the tint off or re-shoot it.
46
+
47
+ ## Alternatives considered
48
+
49
+ - **Each look authors its own dark palette** (the mocks' approach). Rejected: a dark tier in the pack is the contract change ADR 0219 refused, for every sheet and drift test, and a custom accent would have no night.
50
+ - **Two custom accents, light and dark** (the canvas). Superseded by the owner: one accent the platform makes readable is less to get wrong.
51
+ - **Refuse an unreadable custom accent.** Rejected by the task: adjust, do not refuse.
52
+ - **Send the full palette from the platform.** Rejected: thirteen colours and two quoted font stacks in an env file is fragile to quote, and the instance already ships the library.
@@ -476,3 +476,4 @@ These 20 numbers are each shared by exactly two files. They are **accepted histo
476
476
  | 0355 | [**A soft limit is a rule with a reason, and nobody enforces it** ([task 1004416](https://cloudbongos.com/builders#/task/1004416), goal 1000121 — BV2.PS02). The startup flow's seven planet-physics answers and what they rule out. **D1:** the answers are more provisioning `detail` keys under `team_shape`'s contract (no defaults, refused loudly, `null` un-answers), with two new kinds — a list (`many`) and a whole number (`count`); the country is a closed ISO list. **D2:** answers must agree only within one request, so a merge patch's edit order never matters. **D3:** one declarative soft-limit table (`soft-limits.js`) — data conditions, `hide`/`grey`/`note`, a reason on every rule — and every resolution says `enforced: false`. **D4:** screening is a seam (`screening.js`) with a deliberately small rule set; a stop is 422 `screened_out` before anything exists. **D5:** the edit route screens a new description too.](0355-a-soft-limit-is-a-rule-with-a-reason-and-nobody-enforces-it.md) | provisioning / project startup |
477
477
  | 0356 | [**A recruit invite expires 30 days after it is sent, decided at read time** ([task 1002969](https://cloudbongos.com/builders#/task/1002969), goal 1000110 — privacy spec D4, owner-signed). **D1:** one definition, `src/bongos/invite-expiry.js` (`INVITE_EXPIRY_DAYS` + the SQL), read by the sign-in gate, the waiting-page probe, the onboarding routes and, through the doorway's `inviteExpiry`, the hub. Nothing is stored and nothing sweeps. **D2:** only `kind='invite'` rows expire; approved applications and goal invites do not. **D3:** amends ADR 0335 D2.5: the gate reads `kind` only inside the expiry unit, which can close a door and never open one. **D4:** an expired invite is refused, marked `expired` + `expires_at` in the queues, reported `expired` by the status probe (the CLI stops), and replaced by a re-invite's fresh row. **D5:** the hub hides a `pending` notice past 30 days and a re-invite restamps it. Split out: `seen_at` (task 1004443), the decline relay (task 1004444).](0356-a-recruit-invite-expires-30-days-after-it-is-sent-read-time.md) | platform identity / admission / invites |
478
478
  | 0357 | [**The update rule set on /deploy is the one the sweep follows** ([task 1004468](https://cloudbongos.com/builders#/task/1004468), goal 1000090 — BONGOS-V2, owner's ruling 2026-09-30). Amends [ADR 0136](0136-update-channel-subscription-policy.md)'s rejected DB-column alternative. **D1:** for a roster entry whose slug matches a `provisioning_instances` row, the unattended sweep uses that row's `update_channel` (set on /deploy, task 1004445). **D2:** the roster's `channel` is only the fallback — no matching row, or the database unreadable; enrollment and topology stay in the roster. **D3:** the sweep logs each entry's channel and its source, naming an overridden roster value. **D4:** read over psql from the sweep's own `DATABASE_URL`/`PGDATABASE`, never an entry's `env`. **D5:** nothing is copied; a row never changed is `patch`. Delivery to cloudbongos.com waits on the frozen sweep checkout (task 1004307). Rejected: roster stays in charge; stricter-of-the-two; copying roster values into rows.](0357-the-update-rule-set-on-deploy-is-the-one-the-sweep-follows.md) | distribution / updates |
479
+ | 0358 | [**A hall wears a look, and its night takes a tint of it** ([task 1004421](https://cloudbongos.com/builders#/task/1004421), goal 1000121 — BV2.PS06; owner D2 + D8, 2026-09-30). Amends [ADR 0219](0219-a-look-is-a-branding-pack-the-style-library.md) (a look could not carry a dark ground) and DESIGN.md's pure-black rule, for halls only. **D1:** the night tint is a formula over the thirteen — the four dark grounds take 5–6% of the look's accent (src/night-tint.js), emitted after the sheet as both dark twins; no token added. **D2:** on by default, and only a chosen look turns it on — a hall with no look is unchanged. **D3:** the apex and hub stay pure black (ADR 0204). **D4:** a custom look is ONE accent for both modes, its lightness nudged until every pair the hall paints with it reads (lookAdjustAccent, client copy test-pinned). **D5:** look + night_tint join the provisioning settings vocabulary; the accent and logo address ride as companion env; the instance resolves the look from the style library. **D6:** a logo is PNG/JPEG/WebP ≤256 KB, magic-sniffed, never SVG, served content-addressed; it is the hall mark and the favicon. Rejected: per-look dark palettes, two custom accents, refusing an unreadable accent, sending the palette over env.](0358-a-hall-wears-a-look-and-its-night-takes-a-tint.md) | hall / branding / design world |
@@ -2939,7 +2939,7 @@
2939
2939
  "builders"
2940
2940
  ],
2941
2941
  "summary": "GET /builders/:id/profile",
2942
- "description": "GET /builders/:id/profile — the viewable builder profile page's read (task 1467, goal 25 \"bx-identity\"). Returns ONE builder's public portfolio: identity + rank + economy counters + shipped-work count + recent ships + unlocked achievements. Backs the shareable /builders/profile page. rank: public — every field returned here is ALREADY world-readable: the leaderboard (GET /public/leaderboard, no auth) exposes rank, total_credits, karma, and the top achievement ids; GET /builders/:id/onboarding is likewise an unauthenticated roster-visible read. This route is a per-builder re- presentation of the SAME already-public data, so a portfolio link is shareable without a sign-in wall (that IS the feature). It deliberately WHITELISTS the public column subset off the full builder row — the private columns getBuilderById also returns (anthropic_email / anthropic_user_id / monthly_budget_usd / system_role) are NEVER spread into the JSON. A leak-prevention unit test (tests/profile_route.mjs) asserts their absence + the 404-on-unknown-id behaviour. THROTTLED since task 1002804. The global limiter meters WRITES only (rateLimitMiddleware returns early for GET) and the public read limiter is mounted under /public/*, which this is not — so this route answered at line rate. That was tolerable while it re-presented leaderboard data; it is not now that it also carries `handle`, because an id walk then yields the builder → canonical-profile-handle map in one call per builder. modules/platform-identity/routes/public-profile.js caps /profiles/:handle for exactly that mapping, so the two routes that publish it get the same ceiling. The EXISTING shared /public/* budget (120/60s per IP), not a new one — ADR 0209's rule that routes answering one question spend one budget.\n\n**Rank:** `public` — No authentication — any caller.",
2942
+ "description": "GET /builders/:id/profile — the viewable builder profile page's read (task 1467, goal 25 \"bx-identity\"). Returns ONE builder's public portfolio: identity + rank + economy counters + shipped-work count + recent ships + unlocked achievements. Backs the shareable /builders/profile page. rank: public — every field returned here is ALREADY world-readable: the leaderboard (GET /public/leaderboard, no auth) exposes rank, total_credits, karma, and the top achievement ids; GET /builders/:id/onboarding is likewise an unauthenticated roster-visible read. This route is a per-builder re- presentation of the SAME already-public data, so a portfolio link is shareable without a sign-in wall (that IS the feature). It deliberately WHITELISTS the public column subset off the full builder row — the private columns getBuilderById also returns (anthropic_email / anthropic_user_id / monthly_budget_usd / system_role) are NEVER spread into the JSON. A leak-prevention unit test (tests/profile_route.mjs) asserts their absence + the 404-on-unknown-id behaviour. `roles` (task 1004433) is the one block that is NOT a re-presentation of the leaderboard: per-craft counts and sums. The owner made them public on 2026-09-30 (RP01 decision (a): the tally and By the numbers stay public, the trail, the earnings and every Activity tab need a sign-in), so the block carries counts only — no idea title, no page wording, no task list. THROTTLED since task 1002804. The global limiter meters WRITES only (rateLimitMiddleware returns early for GET) and the public read limiter is mounted under /public/*, which this is not — so this route answered at line rate. That was tolerable while it re-presented leaderboard data; it is not now that it also carries `handle`, because an id walk then yields the builder → canonical-profile-handle map in one call per builder. modules/platform-identity/routes/public-profile.js caps /profiles/:handle for exactly that mapping, so the two routes that publish it get the same ceiling. The EXISTING shared /public/* budget (120/60s per IP), not a new one — ADR 0209's rule that routes answering one question spend one budget.\n\n**Rank:** `public` — No authentication — any caller.",
2943
2943
  "x-rank": "public",
2944
2944
  "x-source": "src/bongos/routes/builders.js",
2945
2945
  "parameters": [
@@ -11561,7 +11561,7 @@
11561
11561
  "me"
11562
11562
  ],
11563
11563
  "summary": "PATCH /me/disciplines",
11564
- "description": "Self-service edit of the authenticated builder's preferred disciplines (migrations 027 + 086 / V3.R80). Body: { preferred_disciplines: [\"artist\", ...] }. Valid elements are whatever enabledDisciplines() offers — engineer|ideator core plus any enabled module's (artist, ui); [] clears the preference (a multi-element set just means several lanes). No rank gate — a builder owns their own profile. 422 invalid_discipline if any element is out of range. rank: any-builder — self-service profile edit; documented \"no rank gate\" in the handler comment above (a builder owns their own preference).\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
11564
+ "description": "Self-service edit of the authenticated builder's preferred disciplines (migrations 027 + 086 / V3.R80). Body: { preferred_disciplines: [\"artist\", ...] }. Valid elements are whatever enabledDisciplines() offers — engineer|ideator core plus any enabled module's (artist, ui); [] clears the preference (a multi-element set just means several lanes). No rank gate — a builder owns their own profile. 422 invalid_discipline if any element is out of range. rank: any-builder — self-service profile edit; documented \"no rank gate\" in the handler comment above (a builder owns their own preference). `main_discipline` (optional, task 1004433): the builder's own MAIN role, one of the crafts in the same body; null clears it, absent keeps it (see db.updateBuilderDisciplines). 422 invalid_main_discipline otherwise.\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
11565
11565
  "x-rank": "any-builder",
11566
11566
  "x-source": "src/bongos/routes/me.js",
11567
11567
  "requestBody": {
@@ -15681,6 +15681,223 @@
15681
15681
  ]
15682
15682
  }
15683
15683
  },
15684
+ "/provisioning/instances/{id}/logo": {
15685
+ "put": {
15686
+ "operationId": "put_provisioning_instances_id_logo",
15687
+ "tags": [
15688
+ "provisioning"
15689
+ ],
15690
+ "summary": "PUT /provisioning/instances/:id/logo",
15691
+ "description": "PUT …/logo — rank: any authenticated builder (own resource; archon may change any). The image is screened by its bytes, stored, and the hall told its new address.\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
15692
+ "x-rank": "any-builder",
15693
+ "x-source": "modules/provisioning/routes/look.js",
15694
+ "parameters": [
15695
+ {
15696
+ "name": "id",
15697
+ "in": "path",
15698
+ "required": true,
15699
+ "schema": {
15700
+ "type": "string"
15701
+ },
15702
+ "description": "Path parameter `id`."
15703
+ }
15704
+ ],
15705
+ "requestBody": {
15706
+ "required": true,
15707
+ "content": {
15708
+ "application/json": {
15709
+ "schema": {
15710
+ "$ref": "#/components/schemas/PutProvisioningInstancesIdLogoRequest"
15711
+ }
15712
+ }
15713
+ },
15714
+ "x-validated": true
15715
+ },
15716
+ "responses": {
15717
+ "200": {
15718
+ "description": "Success."
15719
+ },
15720
+ "400": {
15721
+ "$ref": "#/components/responses/ValidationFailed"
15722
+ },
15723
+ "401": {
15724
+ "$ref": "#/components/responses/Unauthorized"
15725
+ },
15726
+ "403": {
15727
+ "$ref": "#/components/responses/Forbidden"
15728
+ },
15729
+ "404": {
15730
+ "$ref": "#/components/responses/NotFound"
15731
+ }
15732
+ },
15733
+ "security": [
15734
+ {
15735
+ "builderSession": []
15736
+ }
15737
+ ]
15738
+ },
15739
+ "delete": {
15740
+ "operationId": "delete_provisioning_instances_id_logo",
15741
+ "tags": [
15742
+ "provisioning"
15743
+ ],
15744
+ "summary": "DELETE /provisioning/instances/:id/logo",
15745
+ "description": "DELETE …/logo — rank: any authenticated builder (own resource; archon may change any).\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
15746
+ "x-rank": "any-builder",
15747
+ "x-source": "modules/provisioning/routes/look.js",
15748
+ "parameters": [
15749
+ {
15750
+ "name": "id",
15751
+ "in": "path",
15752
+ "required": true,
15753
+ "schema": {
15754
+ "type": "string"
15755
+ },
15756
+ "description": "Path parameter `id`."
15757
+ }
15758
+ ],
15759
+ "requestBody": {
15760
+ "required": false,
15761
+ "content": {
15762
+ "application/json": {
15763
+ "schema": {
15764
+ "type": "object",
15765
+ "additionalProperties": true
15766
+ }
15767
+ }
15768
+ },
15769
+ "x-validated": true
15770
+ },
15771
+ "responses": {
15772
+ "200": {
15773
+ "description": "Success."
15774
+ },
15775
+ "400": {
15776
+ "$ref": "#/components/responses/ValidationFailed"
15777
+ },
15778
+ "401": {
15779
+ "$ref": "#/components/responses/Unauthorized"
15780
+ },
15781
+ "403": {
15782
+ "$ref": "#/components/responses/Forbidden"
15783
+ },
15784
+ "404": {
15785
+ "$ref": "#/components/responses/NotFound"
15786
+ }
15787
+ },
15788
+ "security": [
15789
+ {
15790
+ "builderSession": []
15791
+ }
15792
+ ]
15793
+ }
15794
+ },
15795
+ "/provisioning/instances/{id}/look": {
15796
+ "get": {
15797
+ "operationId": "get_provisioning_instances_id_look",
15798
+ "tags": [
15799
+ "provisioning"
15800
+ ],
15801
+ "summary": "GET /provisioning/instances/:id/look",
15802
+ "description": "GET — rank: any authenticated builder (own resource; archon may read any).\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
15803
+ "x-rank": "any-builder",
15804
+ "x-source": "modules/provisioning/routes/look.js",
15805
+ "parameters": [
15806
+ {
15807
+ "name": "id",
15808
+ "in": "path",
15809
+ "required": true,
15810
+ "schema": {
15811
+ "type": "string"
15812
+ },
15813
+ "description": "Path parameter `id`."
15814
+ }
15815
+ ],
15816
+ "responses": {
15817
+ "200": {
15818
+ "description": "Success.",
15819
+ "content": {
15820
+ "application/json": {
15821
+ "schema": {
15822
+ "$ref": "#/components/schemas/GetProvisioningInstancesIdLookResponse"
15823
+ }
15824
+ }
15825
+ }
15826
+ },
15827
+ "400": {
15828
+ "$ref": "#/components/responses/BadRequest"
15829
+ },
15830
+ "401": {
15831
+ "$ref": "#/components/responses/Unauthorized"
15832
+ },
15833
+ "403": {
15834
+ "$ref": "#/components/responses/Forbidden"
15835
+ },
15836
+ "404": {
15837
+ "$ref": "#/components/responses/NotFound"
15838
+ }
15839
+ },
15840
+ "security": [
15841
+ {
15842
+ "builderSession": []
15843
+ }
15844
+ ]
15845
+ },
15846
+ "patch": {
15847
+ "operationId": "patch_provisioning_instances_id_look",
15848
+ "tags": [
15849
+ "provisioning"
15850
+ ],
15851
+ "summary": "PATCH /provisioning/instances/:id/look",
15852
+ "description": "PATCH — rank: any authenticated builder (own resource; archon may change any). A custom look needs an accent, sent now or already stored; the stored one is the ADJUSTED colour, and `adjusted` in the reply says when it differs from what came in.\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
15853
+ "x-rank": "any-builder",
15854
+ "x-source": "modules/provisioning/routes/look.js",
15855
+ "parameters": [
15856
+ {
15857
+ "name": "id",
15858
+ "in": "path",
15859
+ "required": true,
15860
+ "schema": {
15861
+ "type": "string"
15862
+ },
15863
+ "description": "Path parameter `id`."
15864
+ }
15865
+ ],
15866
+ "requestBody": {
15867
+ "required": false,
15868
+ "content": {
15869
+ "application/json": {
15870
+ "schema": {
15871
+ "$ref": "#/components/schemas/PatchProvisioningInstancesIdLookRequest"
15872
+ }
15873
+ }
15874
+ },
15875
+ "x-validated": true
15876
+ },
15877
+ "responses": {
15878
+ "200": {
15879
+ "description": "Success."
15880
+ },
15881
+ "400": {
15882
+ "$ref": "#/components/responses/ValidationFailed"
15883
+ },
15884
+ "401": {
15885
+ "$ref": "#/components/responses/Unauthorized"
15886
+ },
15887
+ "403": {
15888
+ "$ref": "#/components/responses/Forbidden"
15889
+ },
15890
+ "404": {
15891
+ "$ref": "#/components/responses/NotFound"
15892
+ }
15893
+ },
15894
+ "security": [
15895
+ {
15896
+ "builderSession": []
15897
+ }
15898
+ ]
15899
+ }
15900
+ },
15684
15901
  "/provisioning/instances/{id}/render": {
15685
15902
  "get": {
15686
15903
  "operationId": "get_provisioning_instances_id_render",
@@ -16124,6 +16341,41 @@
16124
16341
  ]
16125
16342
  }
16126
16343
  },
16344
+ "/provisioning/logos/{file}": {
16345
+ "get": {
16346
+ "operationId": "get_provisioning_logos_file",
16347
+ "tags": [
16348
+ "provisioning"
16349
+ ],
16350
+ "summary": "GET /provisioning/logos/:file",
16351
+ "description": "a logo is shown on a public hall, and its address is its own sha256, so it names no project and cannot be guessed. Served as an image only: nosniff, a sandboxing CSP, and a cache that never goes stale because a new image is a new name.\n\n**Rank:** `public` — No authentication — any caller.",
16352
+ "x-rank": "public",
16353
+ "x-source": "modules/provisioning/routes/look.js",
16354
+ "parameters": [
16355
+ {
16356
+ "name": "file",
16357
+ "in": "path",
16358
+ "required": true,
16359
+ "schema": {
16360
+ "type": "string"
16361
+ },
16362
+ "description": "Path parameter `file`."
16363
+ }
16364
+ ],
16365
+ "responses": {
16366
+ "200": {
16367
+ "description": "Success."
16368
+ },
16369
+ "400": {
16370
+ "$ref": "#/components/responses/BadRequest"
16371
+ },
16372
+ "404": {
16373
+ "$ref": "#/components/responses/NotFound"
16374
+ }
16375
+ },
16376
+ "security": []
16377
+ }
16378
+ },
16127
16379
  "/provisioning/onboard-plan": {
16128
16380
  "get": {
16129
16381
  "operationId": "get_provisioning_onboard_plan",
@@ -22844,6 +23096,7 @@
22844
23096
  "shipped_count": {},
22845
23097
  "recent_ships": {},
22846
23098
  "achievements": {},
23099
+ "roles": {},
22847
23100
  "cross_project": {},
22848
23101
  "handle": {}
22849
23102
  },
@@ -22851,7 +23104,8 @@
22851
23104
  "builder",
22852
23105
  "shipped_count",
22853
23106
  "recent_ships",
22854
- "achievements"
23107
+ "achievements",
23108
+ "roles"
22855
23109
  ]
22856
23110
  },
22857
23111
  "GetBuildersMePendingRankChangeResponse": {
@@ -23949,6 +24203,23 @@
23949
24203
  "reason"
23950
24204
  ]
23951
24205
  },
24206
+ "GetProvisioningInstancesIdLookResponse": {
24207
+ "type": "object",
24208
+ "properties": {
24209
+ "ok": {
24210
+ "type": "boolean"
24211
+ },
24212
+ "look": {},
24213
+ "options": {},
24214
+ "logo_max_bytes": {}
24215
+ },
24216
+ "required": [
24217
+ "ok",
24218
+ "look",
24219
+ "options",
24220
+ "logo_max_bytes"
24221
+ ]
24222
+ },
23952
24223
  "GetProvisioningInstancesIdRenderResponse": {
23953
24224
  "type": "object",
23954
24225
  "properties": {
@@ -24972,6 +25243,10 @@
24972
25243
  "type": "string"
24973
25244
  },
24974
25245
  "maxItems": 16
25246
+ },
25247
+ "main_discipline": {
25248
+ "type": "string",
25249
+ "maxLength": 32
24975
25250
  }
24976
25251
  },
24977
25252
  "required": [
@@ -25254,6 +25529,22 @@
25254
25529
  "values_held"
25255
25530
  ]
25256
25531
  },
25532
+ "PatchProvisioningInstancesIdLookRequest": {
25533
+ "type": "object",
25534
+ "properties": {
25535
+ "look": {
25536
+ "type": "string"
25537
+ },
25538
+ "night_tint": {
25539
+ "type": "string"
25540
+ },
25541
+ "accent": {
25542
+ "type": "string",
25543
+ "maxLength": 16
25544
+ }
25545
+ },
25546
+ "additionalProperties": false
25547
+ },
25257
25548
  "PatchProvisioningInstancesIdSettingsResponse": {
25258
25549
  "type": "object",
25259
25550
  "properties": {
@@ -30272,6 +30563,26 @@
30272
30563
  ],
30273
30564
  "additionalProperties": false
30274
30565
  },
30566
+ "PutProvisioningInstancesIdLogoRequest": {
30567
+ "type": "object",
30568
+ "properties": {
30569
+ "image_b64": {
30570
+ "type": "string",
30571
+ "minLength": 1,
30572
+ "maxLength": 368640
30573
+ },
30574
+ "content_type": {
30575
+ "type": "string",
30576
+ "minLength": 1,
30577
+ "maxLength": 100
30578
+ }
30579
+ },
30580
+ "required": [
30581
+ "image_b64",
30582
+ "content_type"
30583
+ ],
30584
+ "additionalProperties": false
30585
+ },
30275
30586
  "PutRenderDeployAppRequest": {
30276
30587
  "type": "object",
30277
30588
  "properties": {
@@ -30470,9 +30781,9 @@
30470
30781
  "description": "A required dependency/feature is not configured or is temporarily down."
30471
30782
  }
30472
30783
  },
30473
- "x-endpoint-count": 478,
30474
- "x-schema-count": 506,
30784
+ "x-endpoint-count": 483,
30785
+ "x-schema-count": 509,
30475
30786
  "x-undocumented-bodies": 12,
30476
- "x-response-schemas": 340,
30787
+ "x-response-schemas": 341,
30477
30788
  "x-generated-by": "scripts/gds/gen-api-docs.js"
30478
30789
  }