@bongos/core 1.21.113 → 1.21.114

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 (260) hide show
  1. package/.bongos-core.json +603 -183
  2. package/.claude/skills/ask-for-help/SKILL.md +1 -1
  3. package/.claude/skills/bongos-feedback/SKILL.md +1 -1
  4. package/.claude/skills/builder-sequence/SKILL.md +1 -1
  5. package/.claude/skills/builder-ship/SKILL.md +1 -0
  6. package/GOVERNMENT.md +128 -11
  7. package/clients/bongos-client/README.md +1 -1
  8. package/clients/bongos-client/bongos-client.global.js +28 -0
  9. package/clients/bongos-client/index.cjs +28 -0
  10. package/clients/bongos-client/index.d.ts +45 -2
  11. package/clients/bongos-client/index.mjs +28 -0
  12. package/docs/adr/0372-an-ask-is-stored-per-docket-matter-and-the-server-refuses-slop.md +33 -0
  13. package/docs/adr/0373-an-ai-session-files-a-blocker-with-an-ask.md +31 -0
  14. package/docs/adr/0374-a-building-lead-is-a-held-position-appointed-by-a-people-matter.md +30 -0
  15. package/docs/adr/0375-who-may-build-without-a-vote-comes-from-the-form-of-government.md +38 -0
  16. package/docs/adr/0376-every-ask-is-routed-to-a-real-seat-on-the-server.md +30 -0
  17. package/docs/adr/0377-governance-is-a-held-position-read-on-me.md +24 -0
  18. package/docs/adr/0378-a-leads-build-outs-are-rows-built-at-once-or-by-a-passed-vote.md +33 -0
  19. package/docs/adr/0379-the-treasury-is-pots-per-goal-a-reserve-and-borrowing-over-real-spend.md +32 -0
  20. package/docs/adr/0380-a-strictness-preset-is-a-bundle-of-laws-switched-by-one-laws-vote.md +26 -0
  21. package/docs/adr/README.md +10 -1
  22. package/docs/api/openapi.json +989 -87
  23. package/docs/api-reference.md +18 -4
  24. package/docs/copy-inventory.md +343 -262
  25. package/docs/copy-registry.json +1223 -426
  26. package/docs/file-map.md +2 -1
  27. package/docs/module-api-changelog.md +2 -0
  28. package/docs/packs/engineer.md +2 -1
  29. package/docs/page-inventory.json +91 -6
  30. package/docs/page-readings.json +5017 -4458
  31. package/modules/builder-settings/law-locks.js +202 -0
  32. package/modules/builder-settings/routes/settings.js +66 -6
  33. package/modules/builder-settings/settings.js +7 -0
  34. package/modules/discord/ship-broadcast.js +22 -13
  35. package/modules/government/asks-db.js +54 -0
  36. package/modules/government/asks.js +269 -0
  37. package/modules/government/board-idea-reads.js +68 -0
  38. package/modules/government/board.js +21 -57
  39. package/modules/government/build-rights.js +148 -0
  40. package/modules/government/buildouts.js +160 -0
  41. package/modules/government/counts.js +81 -0
  42. package/modules/government/db.js +242 -0
  43. package/modules/government/decision-board.js +234 -8
  44. package/modules/government/decision-rules.js +2 -0
  45. package/modules/government/docket.js +114 -6
  46. package/modules/government/law-board.js +131 -0
  47. package/modules/government/laws.js +241 -0
  48. package/modules/government/leads.js +170 -0
  49. package/modules/government/migrations/government_027_laws.sql +143 -0
  50. package/modules/government/migrations/government_028_asks.sql +57 -0
  51. package/modules/government/migrations/government_029_leads.sql +135 -0
  52. package/modules/government/migrations/government_030_buildouts.sql +111 -0
  53. package/modules/government/migrations/government_031_treasury.sql +107 -0
  54. package/modules/government/module.json +2 -1
  55. package/modules/government/pollers/treasury-borrow.js +62 -0
  56. package/modules/government/positions.js +107 -0
  57. package/modules/government/presets.js +149 -0
  58. package/modules/government/routes/government.js +425 -2
  59. package/modules/government/routing.js +154 -0
  60. package/modules/government/treasury-db.js +166 -0
  61. package/modules/government/treasury.js +241 -0
  62. package/modules/hall-ui/public/atlas.html +2 -2
  63. package/modules/hall-ui/public/blockers.html +2 -2
  64. package/modules/hall-ui/public/board-room.html +2 -2
  65. package/modules/hall-ui/public/board-room.js +2 -0
  66. package/modules/hall-ui/public/city-draw.js +604 -11
  67. package/modules/hall-ui/public/city.css +157 -1
  68. package/modules/hall-ui/public/city.html +37 -7
  69. package/modules/hall-ui/public/city.js +441 -21
  70. package/modules/hall-ui/public/city.states.json +110 -5
  71. package/modules/hall-ui/public/collab.html +2 -2
  72. package/modules/hall-ui/public/commands.html +2 -2
  73. package/modules/hall-ui/public/copy-desk.html +2 -2
  74. package/modules/hall-ui/public/craft-mode.js +112 -29
  75. package/modules/hall-ui/public/deploy.html +2 -2
  76. package/modules/hall-ui/public/diagram-viewer.css +12 -0
  77. package/modules/hall-ui/public/diagram-viewer.js +4 -0
  78. package/modules/hall-ui/public/diagrams.html +2 -2
  79. package/modules/hall-ui/public/drachmae.html +2 -2
  80. package/modules/hall-ui/public/fleet.html +2 -2
  81. package/modules/hall-ui/public/gate.html +2 -2
  82. package/modules/hall-ui/public/goal-map.html +2 -2
  83. package/modules/hall-ui/public/goals.html +2 -2
  84. package/modules/hall-ui/public/gov-feeds.js +141 -0
  85. package/modules/hall-ui/public/gov-living.js +1002 -0
  86. package/modules/hall-ui/public/gov-positions.js +97 -0
  87. package/modules/hall-ui/public/government.html +2 -2
  88. package/modules/hall-ui/public/hall-render.js +3 -0
  89. package/modules/hall-ui/public/idea.html +2 -2
  90. package/modules/hall-ui/public/ideas.html +2 -2
  91. package/modules/hall-ui/public/index.html +3 -3
  92. package/modules/hall-ui/public/modules.html +2 -2
  93. package/modules/hall-ui/public/my-agents.css +334 -0
  94. package/modules/hall-ui/public/my-agents.html +72 -0
  95. package/modules/hall-ui/public/my-agents.js +603 -0
  96. package/modules/hall-ui/public/my-agents.states.json +37 -0
  97. package/modules/hall-ui/public/primer.html +2 -2
  98. package/modules/hall-ui/public/profile-connections.js +40 -28
  99. package/modules/hall-ui/public/profile.html +2 -2
  100. package/modules/hall-ui/public/project-settings.html +2 -2
  101. package/modules/hall-ui/public/ranks.html +2 -2
  102. package/modules/hall-ui/public/roadmap.html +2 -2
  103. package/modules/hall-ui/public/room.css +8 -0
  104. package/modules/hall-ui/public/roster.html +2 -2
  105. package/modules/hall-ui/public/sessions.html +2 -2
  106. package/modules/hall-ui/public/settings.html +2 -2
  107. package/modules/hall-ui/public/shell.js +116 -16
  108. package/modules/hall-ui/public/street-card.js +18 -1
  109. package/modules/hall-ui/public/street-deck.css +299 -0
  110. package/modules/hall-ui/public/street-deck.js +1145 -0
  111. package/modules/hall-ui/public/street-depth.js +712 -0
  112. package/modules/hall-ui/public/street-desk.js +5 -2
  113. package/modules/hall-ui/public/street-draw.js +109 -16
  114. package/modules/hall-ui/public/street-inside.js +137 -22
  115. package/modules/hall-ui/public/street-office.js +705 -0
  116. package/modules/hall-ui/public/street.css +161 -11
  117. package/modules/hall-ui/public/street.html +41 -11
  118. package/modules/hall-ui/public/street.js +78 -66
  119. package/modules/hall-ui/public/street.states.json +129 -21
  120. package/modules/hall-ui/public/studio.html +2 -2
  121. package/modules/hall-ui/public/style.css +5 -1
  122. package/modules/hall-ui/public/task.html +2 -2
  123. package/modules/hall-ui/public/thinking.html +2 -2
  124. package/modules/hall-ui/public/tweak-editor.html +2 -2
  125. package/modules/hall-ui/public/watch.html +2 -2
  126. package/modules/hall-ui/public/watch.js +14 -1
  127. package/modules/hall-ui/public/work.html +2 -2
  128. package/modules/hall-ui/records/living-city.md +57 -0
  129. package/modules/hall-ui/records/my-agents.md +21 -0
  130. package/modules/hall-ui/records/oversight-family.md +1 -0
  131. package/modules/hall-ui/records/profile-connections.md +10 -0
  132. package/modules/hall-ui/records/reading-rooms.md +2 -0
  133. package/modules/ideas/routes/blockers.js +92 -3
  134. package/modules/lifecycle/module.json +2 -1
  135. package/modules/lifecycle/moving.js +17 -1
  136. package/modules/lifecycle/routes/moving.js +6 -0
  137. package/modules/lifecycle/routes/project-settings.js +23 -0
  138. package/modules/onboarding/approval-broadcast.js +8 -0
  139. package/modules/onboarding/routes/access-requests.js +16 -6
  140. package/modules/platform-identity/connections.js +13 -2
  141. package/modules/platform-identity/routes/connections.js +7 -1
  142. package/modules/public-landing/public/account-private.states.json +2 -2
  143. package/modules/public-landing/public/account.html +65 -5
  144. package/modules/public-landing/public/account.states.json +3 -3
  145. package/modules/public-landing/public/assets/world/r2-bongos-chrome-b.jpg.json +1 -1
  146. package/modules/public-landing/public/assets/world/r2-bongos-chrome-b.webp +0 -0
  147. package/modules/public-landing/public/assets/world/r2-bongos-chrome-b.webp.json +13 -0
  148. package/modules/public-landing/public/assets/world/r2-chrome-blob-one.jpg.json +1 -1
  149. package/modules/public-landing/public/assets/world/r2-chrome-blob-one.webp +0 -0
  150. package/modules/public-landing/public/assets/world/r2-chrome-blob-one.webp.json +13 -0
  151. package/modules/public-landing/public/assets/world/r2-chrome-blobs-set.jpg.json +1 -1
  152. package/modules/public-landing/public/assets/world/r2-chrome-blobs-set.webp +0 -0
  153. package/modules/public-landing/public/assets/world/r2-chrome-blobs-set.webp.json +13 -0
  154. package/modules/public-landing/public/assets/world.css +4 -4
  155. package/modules/public-landing/public/connections-empty.states.json +14 -0
  156. package/modules/public-landing/public/connections-inactive.states.json +14 -0
  157. package/modules/public-landing/public/connections.html +450 -0
  158. package/modules/public-landing/public/connections.probes.json +414 -0
  159. package/modules/public-landing/public/connections.states.json +17 -0
  160. package/modules/public-landing/public/contact.html +2 -2
  161. package/modules/public-landing/public/guild.html +2 -2
  162. package/modules/public-landing/public/index.html +2 -2
  163. package/modules/public-landing/public/invitations.html +2 -2
  164. package/modules/public-landing/public/privacy.html +2 -2
  165. package/modules/public-landing/public/projects.html +2 -2
  166. package/modules/public-landing/public/projects.probes.json +6 -2
  167. package/modules/public-landing/public/terms.html +2 -2
  168. package/modules/ui-design/kit/fixtures/connections-empty.json +12 -0
  169. package/modules/ui-design/kit/fixtures/connections-inactive.json +7 -0
  170. package/modules/ui-design/kit/fixtures/connections.json +22 -0
  171. package/modules/ui-design/kit/serve.js +95 -0
  172. package/package-lock.json +2 -2
  173. package/package.json +1 -1
  174. package/release-notes.json +122 -0
  175. package/scripts/discord/README.md +8 -5
  176. package/scripts/discord/post.js +12 -1
  177. package/scripts/gds/artifact-audit.js +20 -3
  178. package/scripts/gds/ask.js +164 -0
  179. package/scripts/gds/autobongos-verify.js +21 -2
  180. package/scripts/gds/government-walk.js +638 -4
  181. package/scripts/gds/pulse.js +9 -6
  182. package/scripts/gds/ship-escalation.js +22 -3
  183. package/scripts/gds/ship-finish.js +5 -4
  184. package/scripts/gds/ship-merge-gate.js +18 -6
  185. package/scripts/hall-preview/README.md +41 -1
  186. package/scripts/hall-preview/pref-writes.js +140 -0
  187. package/scripts/hall-preview/refresh-fixtures.js +101 -7
  188. package/scripts/hall-preview/scrub-identity.js +366 -7
  189. package/scripts/hall-preview/server.js +27 -1
  190. package/scripts/render-diagrams.sh +4 -2
  191. package/src/bongos/auth-idp.js +6 -1
  192. package/src/bongos/project-settings.js +41 -0
  193. package/src/bongos/route-rank-check.js +27 -0
  194. package/src/bongos/routes/me.js +68 -7
  195. package/src/bongos/serve-internal.js +5 -1
  196. package/src/module-api.js +7 -1
  197. package/src/platform-server.js +10 -0
  198. package/tests/application_lifecycle.mjs +47 -5
  199. package/tests/conductor_main_e2e.mjs +21 -0
  200. package/tests/connections_api.mjs +18 -0
  201. package/tests/craft_mode_nav.mjs +5 -3
  202. package/tests/craft_mode_tallies.mjs +52 -16
  203. package/tests/discord_approvals.mjs +11 -0
  204. package/tests/discord_channels.mjs +20 -0
  205. package/tests/fixtures/gov-seated.mjs +64 -0
  206. package/tests/fixtures/government-ask-cards.json +1284 -0
  207. package/tests/government_act_alone_buildings.mjs +1 -0
  208. package/tests/government_agent_asks.mjs +322 -0
  209. package/tests/government_asks.mjs +408 -0
  210. package/tests/government_build_rights.mjs +253 -0
  211. package/tests/government_buildouts.mjs +382 -0
  212. package/tests/government_counts.mjs +143 -0
  213. package/tests/government_decision_rules.mjs +5 -1
  214. package/tests/government_laws.mjs +488 -0
  215. package/tests/government_laws_session.mjs +321 -0
  216. package/tests/government_leads.mjs +375 -0
  217. package/tests/government_positions.mjs +127 -0
  218. package/tests/government_presets.mjs +215 -0
  219. package/tests/government_routes.mjs +8 -1
  220. package/tests/government_routing.mjs +118 -0
  221. package/tests/government_seed.mjs +5 -0
  222. package/tests/government_treasury.mjs +394 -0
  223. package/tests/governor_docket.mjs +26 -2
  224. package/tests/hall_buildouts.mjs +208 -0
  225. package/tests/hall_city.mjs +14 -6
  226. package/tests/hall_city_living.mjs +617 -0
  227. package/tests/hall_gov_counts.mjs +336 -0
  228. package/tests/hall_gov_living.mjs +636 -0
  229. package/tests/hall_gov_real_site.mjs +655 -0
  230. package/tests/hall_matter_card.mjs +6 -1
  231. package/tests/hall_my_agents.mjs +481 -0
  232. package/tests/hall_nav.mjs +107 -4
  233. package/tests/hall_page_gate_map.mjs +4 -0
  234. package/tests/hall_preview_governor_fixtures.mjs +30 -3
  235. package/tests/hall_preview_scrub.mjs +59 -1
  236. package/tests/hall_preview_security.mjs +169 -0
  237. package/tests/hall_reading_world.mjs +44 -0
  238. package/tests/hall_roster_world.mjs +6 -2
  239. package/tests/hall_street.mjs +18 -2
  240. package/tests/hall_street_amend.mjs +1 -1
  241. package/tests/hall_street_deck.mjs +609 -0
  242. package/tests/hall_street_depth.mjs +559 -0
  243. package/tests/hall_street_desk.mjs +1 -1
  244. package/tests/hall_street_inside.mjs +29 -5
  245. package/tests/hall_tweak_editor.mjs +4 -1
  246. package/tests/hub_account_page.mjs +94 -3
  247. package/tests/hub_connections_page.mjs +507 -0
  248. package/tests/hub_invite_badge.mjs +1 -1
  249. package/tests/idp_device_exchange.mjs +18 -0
  250. package/tests/landing_legal_pages.mjs +8 -5
  251. package/tests/landing_page.mjs +23 -4
  252. package/tests/nav_permission_atoms.mjs +4 -1
  253. package/tests/profile_connections_ui.mjs +88 -25
  254. package/tests/projects_hub.mjs +15 -0
  255. package/tests/render_check.mjs +2 -2
  256. package/tests/ship_broadcast_routing.mjs +57 -16
  257. package/tests/ship_broadcast_server.mjs +40 -7
  258. package/tests/ship_merge_gate.mjs +19 -0
  259. package/tests/ui_design_kit.mjs +2 -2
  260. package/tests/watch_applications_queue.mjs +23 -0
@@ -43,7 +43,7 @@
43
43
  "href": [
44
44
  [
45
45
  "#cityStart",
46
- "/builders/street"
46
+ "/builders/street#deck"
47
47
  ]
48
48
  ]
49
49
  }
@@ -56,6 +56,10 @@
56
56
  "wait",
57
57
  900
58
58
  ],
59
+ [
60
+ "clickIfVisible",
61
+ "[data-craft-close]"
62
+ ],
59
63
  [
60
64
  "click",
61
65
  "#fullscreen-toggle"
@@ -93,6 +97,10 @@
93
97
  "wait",
94
98
  600
95
99
  ],
100
+ [
101
+ "clickIfVisible",
102
+ "[data-craft-close]"
103
+ ],
96
104
  [
97
105
  "click",
98
106
  "#cityMode"
@@ -132,7 +140,7 @@
132
140
  },
133
141
  "pins": {
134
142
  "auth": true,
135
- "_": "The home city over the dense docket with the same pin tiers as the street (task 1004569): one pin per building, urgent largest and pulsing, needs you orange, moving small and ink, a count where a building holds more than one open matter.",
143
+ "_": "The home city over the dense docket with the same pin tiers as the street (task 1004569): one pin per building, needs you orange, moving small and ink, a count where a building holds more than one open matter. In the living city (task 1004685) salmon is only what waits on the viewer's own seat, with an age ring; the harness fixtures hold no ask on the viewer due within a day, so no pin is urgent here. Since task 1004705 a matter routed to another seat is not salmon, and over the harness fixtures (the real site since task 1004717) every building with an open matter holds one on the viewer, so no pin stands in the moving tier here (task 1004718 refreshed this).",
136
144
  "actions": [
137
145
  [
138
146
  "wait",
@@ -150,10 +158,107 @@
150
158
  "expect": {
151
159
  "visible": [
152
160
  "#cityPins",
153
- ".city-pin--urgent",
154
161
  ".city-pin--needs",
155
- ".city-pin--moving",
156
- ".city-pin__count"
162
+ ".city-pin__count",
163
+ ".city-pin__age"
164
+ ]
165
+ }
166
+ },
167
+ "living": {
168
+ "auth": true,
169
+ "_": "The living city (task 1004685) over the harness fixtures alone (task 1004717 deleted the prototype overlay): the plaque (form of government, laws, on you, this month's spend), one sky pod per active claim and the door reading 'decide N in a row'. The hub has no Lead, build-out or open sitting, so no capsule, site or shaft stands. The Lead plates show from 641px (on a phone they are in the card), and the buildings' buttons are the keyboard's (no pointer events), so neither is expected visible at every width.",
170
+ "actions": [
171
+ [
172
+ "wait",
173
+ 1200
174
+ ],
175
+ [
176
+ "clickIfVisible",
177
+ "[data-craft-close]"
178
+ ],
179
+ [
180
+ "wait",
181
+ 300
182
+ ]
183
+ ],
184
+ "expect": {
185
+ "visible": [
186
+ "#cityPlaque",
187
+ ".city-pod"
188
+ ],
189
+ "href": [
190
+ [
191
+ "#cityStart",
192
+ "/builders/street#deck"
193
+ ]
194
+ ]
195
+ }
196
+ },
197
+ "card": {
198
+ "auth": true,
199
+ "_": "A building opened from the keyboard (its button focused, Enter): Planning's card in place (who holds it, one fact, what waits on you, decide and enter; every answer is the deck's); a sheet along the foot on a phone. A pointer opens it from the building's own faces, its pin or its plate.",
200
+ "actions": [
201
+ [
202
+ "wait",
203
+ 1200
204
+ ],
205
+ [
206
+ "clickIfVisible",
207
+ "[data-craft-close]"
208
+ ],
209
+ [
210
+ "focus",
211
+ ".city-hit[data-building=\"planning\"]"
212
+ ],
213
+ [
214
+ "press",
215
+ "Enter"
216
+ ],
217
+ [
218
+ "wait",
219
+ 300
220
+ ]
221
+ ],
222
+ "expect": {
223
+ "visible": [
224
+ "#cityCard",
225
+ ".city-card__go",
226
+ ".city-card__enter"
227
+ ]
228
+ }
229
+ },
230
+ "card-ask": {
231
+ "auth": true,
232
+ "_": "A building's card answers its first ask in place (task 1004702, the owner's pick): the Treasury's real stored borrow ask inside the glass card, beside the building over a light hush, its two doors under it.",
233
+ "actions": [
234
+ [
235
+ "wait",
236
+ 1200
237
+ ],
238
+ [
239
+ "clickIfVisible",
240
+ "[data-craft-close]"
241
+ ],
242
+ [
243
+ "focus",
244
+ ".city-hit[data-building=\"treasury\"]"
245
+ ],
246
+ [
247
+ "press",
248
+ "Enter"
249
+ ],
250
+ [
251
+ "wait",
252
+ 400
253
+ ]
254
+ ],
255
+ "expect": {
256
+ "visible": [
257
+ "#cityCard",
258
+ ".city-ask",
259
+ ".ask__opt",
260
+ ".city-card__enter",
261
+ ".gov-halo"
157
262
  ]
158
263
  }
159
264
  }
@@ -149,8 +149,8 @@
149
149
  <div id="toast" class="toast" role="status" aria-live="polite" data-visible="0"></div>
150
150
 
151
151
  <script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
152
- <script src="/builders/craft-mode.js?v=2026-10-08-city-tab"></script>
153
- <script src="/builders/shell.js?v=2026-10-08-glyph-fix"></script>
152
+ <script src="/builders/craft-mode.js?v=2026-10-09-living3"></script>
153
+ <script src="/builders/shell.js?v=2026-10-10-hall-keys1"></script>
154
154
  <script src="/builders/palette.js" defer></script>
155
155
  <script src="/builders/dom-utils.js?v=2026-06-23-contrib"></script>
156
156
  <script src="/builders/collab-lib.js?v=2026-09-24-archive"></script>
@@ -55,8 +55,8 @@
55
55
  <div id="toast" class="toast" role="status" aria-live="polite" data-visible="0"></div>
56
56
 
57
57
  <script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
58
- <script src="/builders/craft-mode.js?v=2026-10-08-city-tab"></script>
59
- <script src="/builders/shell.js?v=2026-10-08-glyph-fix"></script>
58
+ <script src="/builders/craft-mode.js?v=2026-10-09-living3"></script>
59
+ <script src="/builders/shell.js?v=2026-10-10-hall-keys1"></script>
60
60
  <!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
61
61
  <script src="/builders/palette.js" defer></script>
62
62
  <script src="/builders/dom-utils.js?v=2026-06-14-domutils"></script>
@@ -178,8 +178,8 @@
178
178
  <div id="toast" class="toast" role="status" aria-live="polite" data-visible="0"></div>
179
179
 
180
180
  <script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
181
- <script src="/builders/craft-mode.js?v=2026-10-08-city-tab"></script>
182
- <script src="/builders/shell.js?v=2026-10-08-glyph-fix"></script>
181
+ <script src="/builders/craft-mode.js?v=2026-10-09-living3"></script>
182
+ <script src="/builders/shell.js?v=2026-10-10-hall-keys1"></script>
183
183
  <script src="/builders/palette.js" defer></script>
184
184
  <script src="/builders/dom-utils.js?v=2026-06-23-contrib"></script>
185
185
  <script src="/builders/hall-kit.js"></script>
@@ -47,6 +47,50 @@
47
47
  ];
48
48
  var IDS = MODES.map(function (m) { return m.id; });
49
49
 
50
+ // ---------- GOVERNING IS A SEAT (task 1004685, the living-city prototype) ----------
51
+ // Round-3 board 8: you pick a craft, but you HOLD a position or you don't. The
52
+ // shell tells this file which seats the viewer holds (setPositions, computed by
53
+ // gov-positions.js): with none, Governing is no longer offered — not in the switch,
54
+ // not in the picker, and a stored Governing reads as no mode; with one, the mode is
55
+ // named by the seat ("Planning Lead"). Not told (seat undefined) is today's picker,
56
+ // so a hall that cannot read the seats is unchanged. Cosmetic, like the mode itself.
57
+ var seat;
58
+ function seatName() { return typeof seat === 'string' ? seat : null; }
59
+ function offered(mode) { return mode !== 'governing' || seat !== null; }
60
+ function labelOf(m) { return m.id === 'governing' && seatName() ? seatName() : m.label; }
61
+ function lineOf(m) { return m.id === 'governing' && seatName() ? 'Your seat. ' + m.line : m.line; }
62
+ function paintSeat() {
63
+ var q = document.querySelector ? function (s) { return document.querySelector(s); } : function () { return null; };
64
+ var opt = q('#craft-switch [data-craft-opt="governing"]');
65
+ var gov = MODES[IDS.indexOf('governing')];
66
+ if (opt) {
67
+ if (offered('governing')) opt.removeAttribute('hidden'); else opt.setAttribute('hidden', '');
68
+ opt.setAttribute('title', labelOf(gov) + ' — ' + lineOf(gov));
69
+ var lab = opt.querySelector && opt.querySelector('.craft-switch__label');
70
+ if (lab) lab.textContent = labelOf(gov);
71
+ }
72
+ // An open picker is redrawn with the right doors, keeping its box and its focus.
73
+ if (picker) {
74
+ var keep = picker.querySelector('[data-craft-again]');
75
+ var again = !keep || keep.checked;
76
+ var inside = picker.contains && picker.contains(document.activeElement);
77
+ picker.innerHTML = pickerHtml(read());
78
+ var box = picker.querySelector('[data-craft-again]');
79
+ if (box) box.checked = again;
80
+ var pre = inside && (picker.querySelector('.craft-door--pre') || picker.querySelector('[data-craft-close]'));
81
+ if (pre && pre.focus) pre.focus();
82
+ }
83
+ }
84
+ function setPositions(p) {
85
+ seat = !p || p.known !== true ? undefined : (p.has_position ? (p.title || 'Governing') : null);
86
+ if (seat === null && stored() === 'governing') {
87
+ drop('sessionStorage', MODE_KEY);
88
+ if (get('localStorage', KEEP_KEY) === 'governing') drop('localStorage', KEEP_KEY);
89
+ if (document.documentElement && document.documentElement.dataset.craft === 'governing') apply(null);
90
+ }
91
+ paintSeat();
92
+ }
93
+
50
94
  // ---------- each mode's tabs (task 1004493) ----------
51
95
  // A mode shows only the nav items its craft needs, by NAV id (shell.js). ALWAYS
52
96
  // is the owner's list of tabs no mode may hide (2026-10-01: Builders first;
@@ -54,7 +98,9 @@
54
98
  // shows, exactly as the hall did before.
55
99
  // Government lives in Governing alone, and Governing is the shortest list.
56
100
  // Hiding is cosmetic: a hidden tab's page still opens by its URL (ADR 0016).
57
- var ALWAYS_TABS = ['roster', 'collab', 'profile'];
101
+ // task 1004685 (prototype, a proposal for the owner): My agents joins the list —
102
+ // every craft has agents, and board 6 pairs it with the city in every mode.
103
+ var ALWAYS_TABS = ['roster', 'collab', 'profile', 'my-agents'];
58
104
  var MODE_TABS = {
59
105
  building: ['home', 'roadmap', 'goals', 'goal-map', 'work', 'blockers', 'thinking', 'studio',
60
106
  'standing',
@@ -201,44 +247,71 @@
201
247
 
202
248
  // ---------- Governing's header tallies (task 1004563) ----------
203
249
  // "needs you N · moving M" beside the eyebrow, as on the four-mode prototype.
204
- // Needs you is the open-blocker total GET /blockers already carries; moving is
205
- // tasks being built or waiting to land (active + confirmed, owner 2026-10-08),
206
- // counted by the server at GET /moving. Read once per page. A figure that cannot
207
- // be read is LEFT OUT, never shown as 0: zero would say nothing waits on you.
208
- var TALLY_API = '/api/bongos';
250
+ // Since the living city (task 1004685) both are the city's own numbers, from
251
+ // ONE rule (gov-living.js countsOf) over ONE read per page (gov-feeds.js): needs you
252
+ // is every ask that waits on one of your seats; moving is tasks being built or
253
+ // waiting to land (active + confirmed, owner 2026-10-08, GET /moving). On the
254
+ // city and the street the page's own reads are shared, so the tally costs
255
+ // nothing more and follows every answer given there; on any other page the
256
+ // two scripts load once and read COUNT_FEEDS. A figure that cannot be read is
257
+ // LEFT OUT, never shown as 0: zero would say nothing waits on you.
209
258
  var tallyAsk = null;
210
- function readCount(path, pick) {
211
- if (typeof fetch !== 'function') return Promise.resolve(null);
212
- return fetch(TALLY_API + path, { credentials: 'same-origin', headers: { Accept: 'application/json' } })
213
- .then(function (r) { return r.ok ? r.json() : null; })
214
- .then(function (j) {
215
- var n = j ? pick(j) : null;
216
- return (typeof n === 'number' && isFinite(n) && n >= 0) ? n : null;
259
+ var tallyHooked = false;
260
+ function num(n) { return (typeof n === 'number' && isFinite(n) && n >= 0) ? n : null; }
261
+ // after the page's own scripts, so a page that carries gov-feeds.js shares its memo
262
+ function pageReady() {
263
+ if (typeof document === 'undefined' || document.readyState !== 'loading' || typeof document.addEventListener !== 'function') return Promise.resolve();
264
+ return new Promise(function (r) { document.addEventListener('DOMContentLoaded', function () { r(); }); });
265
+ }
266
+ function govScript(name, api) {
267
+ if (window[api]) return Promise.resolve(window[api]);
268
+ return loadTool({ script: name, api: api }).then(null, function () { return null; });
269
+ }
270
+ function govCounts() {
271
+ return pageReady()
272
+ .then(function () { return govScript('gov-living.js', 'GovLiving'); })
273
+ .then(function (L) { return L ? govScript('gov-feeds.js', 'GovFeeds') : null; })
274
+ .then(function (F) {
275
+ if (!F) return null;
276
+ if (!tallyHooked && typeof F.onChange === 'function') {
277
+ tallyHooked = true;
278
+ // an answer on this page, or a fresh read after an act: count again
279
+ F.onChange(function () { tallyAsk = null; applyTallies(document.documentElement.dataset.craft); });
280
+ }
281
+ return F.counts();
217
282
  }, function () { return null; });
218
283
  }
219
284
  function askTallies() {
220
285
  if (!tallyAsk) {
221
- tallyAsk = Promise.all([
222
- readCount('/blockers?limit=1', function (j) { return j.page && j.page.total; }),
223
- readCount('/moving', function (j) { return j.moving; }),
224
- ]).then(function (v) { return { needs: v[0], moving: v[1] }; });
286
+ tallyAsk = govCounts().then(function (c) {
287
+ return { needs: c ? num(c.on_you) : null, moving: c ? num(c.moving) : null };
288
+ }, function () { return { needs: null, moving: null }; });
225
289
  }
226
290
  return tallyAsk;
227
291
  }
228
292
  function tallyHtml(t) {
229
293
  var parts = [];
294
+ var W = window.GovLiving && window.GovLiving.countLabel;
230
295
  function one(label, n, due) {
231
296
  return '<span class="craft-tally' + (due ? ' craft-tally--due' : '') + '">'
232
297
  + '<span class="craft-tally__label">' + label + '</span> '
233
298
  + '<span class="craft-tally__n">' + n + '</span></span>';
234
299
  }
235
- if (t && t.needs != null) parts.push(one('needs you', t.needs, t.needs > 0));
236
- if (t && t.moving != null) parts.push(one('moving', t.moving, false));
300
+ if (t && t.needs != null) parts.push(one(W ? W('on_you') : 'to do', t.needs, t.needs > 0));
301
+ if (t && t.moving != null) parts.push(one(W ? W('moving') : 'moving', t.moving, false));
237
302
  return parts.join(' <span class="craft-tallies__sep" aria-hidden="true">·</span> ');
238
303
  }
304
+ // The top bar carries the tally on the city and the street only (owner ruling
305
+ // 2026-10-09, task 1004701): every other page asks the server for nothing.
306
+ var TALLY_PAGES = ['city', 'street'];
307
+ function tallyPage() {
308
+ var b = document.body;
309
+ var page = b && b.getAttribute ? b.getAttribute('data-page') : null;
310
+ return TALLY_PAGES.indexOf(page) >= 0;
311
+ }
239
312
  function applyTallies(mode) {
240
313
  var box = document.getElementById('craft-tallies');
241
- if (mode !== 'governing') { remove(box); return; }
314
+ if (mode !== 'governing' || !tallyPage()) { remove(box); return; }
242
315
  var mark = document.getElementById('craft-eyebrow');
243
316
  if (!box && mark && mark.parentNode) {
244
317
  box = document.createElement('span');
@@ -591,10 +664,15 @@
591
664
  }
592
665
 
593
666
  // The mode this session is in: chosen this session, else the one kept from an
594
- // earlier session. null = no mode, which is the hall as it always was.
595
- function read() {
667
+ // earlier session. null = no mode, which is the hall as it always was. A stored
668
+ // Governing reads as no mode for a builder known to hold no seat (task 1004685).
669
+ function stored() {
596
670
  return valid(get('sessionStorage', MODE_KEY)) || valid(get('localStorage', KEEP_KEY));
597
671
  }
672
+ function read() {
673
+ var m = stored();
674
+ return m && offered(m) ? m : null;
675
+ }
598
676
 
599
677
  // A page can say it never wears a mode: <body data-craft-mode="off">.
600
678
  function pageOptsOut() {
@@ -624,7 +702,7 @@
624
702
  // Choosing any mode, Artistry included, ends a review (task 1004686).
625
703
  function choose(mode, keep) {
626
704
  mode = valid(mode);
627
- if (!mode) return;
705
+ if (!mode || !offered(mode)) return;
628
706
  if (review) { drop('sessionStorage', REVIEW_KEY); review = null; closeReviewMenu(false); }
629
707
  set('sessionStorage', MODE_KEY, mode);
630
708
  set('sessionStorage', ASKED_KEY, '1');
@@ -642,8 +720,9 @@
642
720
  return '<div class="craft-switch' + (current ? '' : ' craft-switch--unset') + '" id="craft-switch" role="group" aria-label="Mode">' +
643
721
  MODES.map(function (m) {
644
722
  return '<button class="craft-switch__opt craft-switch__opt--' + m.id + '" type="button" data-craft-opt="' + m.id + '"' +
645
- ' aria-pressed="' + (m.id === current ? 'true' : 'false') + '" title="' + esc(m.label + ' — ' + m.line) + '">' +
646
- icon(m.id, 'craft-switch__icon') + '<span class="craft-switch__label">' + esc(m.short) + '</span></button>';
723
+ ' aria-pressed="' + (m.id === current ? 'true' : 'false') + '" title="' + esc(labelOf(m) + ' — ' + lineOf(m)) + '"' +
724
+ (offered(m.id) ? '' : ' hidden') + '>' +
725
+ icon(m.id, 'craft-switch__icon') + '<span class="craft-switch__label">' + esc(m.id === 'governing' && seatName() ? seatName() : m.short) + '</span></button>';
647
726
  }).join('') +
648
727
  // At phone width the options fold away and this one button opens the picker.
649
728
  '<button class="craft-switch__open" type="button" data-craft-open aria-haspopup="dialog" aria-label="Choose your mode" title="Choose your mode">' +
@@ -718,11 +797,12 @@
718
797
  return '<span class="craft-art craft-art--' + id + '" aria-hidden="true">' + html + '</span>';
719
798
  }
720
799
  function pickerHtml(preselect) {
721
- var doors = MODES.map(function (m) {
800
+ var shown = MODES.filter(function (m) { return offered(m.id); });
801
+ var doors = shown.map(function (m) {
722
802
  return '<button class="craft-door craft-door--' + m.id + (m.id === preselect ? ' craft-door--pre' : '') + '" type="button" data-craft-pick="' + m.id + '">' +
723
803
  artHtml(m.id) +
724
- '<span class="craft-door__head">' + icon(m.id, 'craft-door__icon') + '<span class="craft-door__name">' + esc(m.label) + '</span></span>' +
725
- '<span class="craft-door__line">' + esc(m.line) + '</span></button>';
804
+ '<span class="craft-door__head">' + icon(m.id, 'craft-door__icon') + '<span class="craft-door__name">' + esc(labelOf(m)) + '</span></span>' +
805
+ '<span class="craft-door__line">' + esc(lineOf(m)) + '</span></button>';
726
806
  }).join('');
727
807
  return '<div class="craft-picker__panel" role="dialog" aria-modal="true" aria-labelledby="craft-picker-title" aria-describedby="craft-picker-lede">' +
728
808
  '<button class="craft-picker__close" type="button" data-craft-close aria-label="Close without choosing">' +
@@ -730,7 +810,7 @@
730
810
  '<p class="craft-picker__eyebrow">Builders hall · this session</p>' +
731
811
  '<h2 class="craft-picker__title" id="craft-picker-title">What are you doing now?</h2>' +
732
812
  '<p class="craft-picker__lede" id="craft-picker-lede">Pick one. You can switch any time from the top bar.</p>' +
733
- '<div class="craft-picker__doors">' + doors + '</div>' +
813
+ '<div class="craft-picker__doors" data-doors="' + shown.length + '">' + doors + '</div>' +
734
814
  '<div class="craft-picker__foot">' +
735
815
  '<label class="craft-picker__again"><input type="checkbox" data-craft-again checked> Ask me again next session</label>' +
736
816
  (preselect === 'artistry' ? '<span class="craft-picker__hint">Artists start on Artistry.</span>' : '') +
@@ -840,5 +920,8 @@
840
920
  switchHtml: switchHtml,
841
921
  mount: mount,
842
922
  onAccess: onAccess,
923
+ // task 1004685 (prototype): the seats the viewer holds, and the Governing seat's name.
924
+ setPositions: setPositions,
925
+ seatName: seatName,
843
926
  };
844
927
  })();
@@ -75,8 +75,8 @@
75
75
  <div id="toast" class="toast" role="status" aria-live="polite" data-visible="0"></div>
76
76
 
77
77
  <script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
78
- <script src="/builders/craft-mode.js?v=2026-10-08-city-tab"></script>
79
- <script src="/builders/shell.js?v=2026-10-08-glyph-fix"></script>
78
+ <script src="/builders/craft-mode.js?v=2026-10-09-living3"></script>
79
+ <script src="/builders/shell.js?v=2026-10-10-hall-keys1"></script>
80
80
  <script src="/builders/palette.js" defer></script>
81
81
  <script src="/builders/dom-utils.js?v=2026-06-16-gate"></script>
82
82
  <script src="/builders/hall-kit.js"></script>
@@ -61,6 +61,18 @@
61
61
  .dgv__pan.is-smooth { transition: transform 0.16s ease-out; } /* button zoom / fit only */
62
62
  .dgv__pan svg { display: block; }
63
63
 
64
+ /* Dark: the figure follows the theme (task 1003639). mermaid-cli renders ONE
65
+ light figure per diagram, at deploy; a second, dark render of each would
66
+ double that work on a small host. On the hall's dark mode it was a white
67
+ plate on black. diagram-viewer.js drops the baked white ground, and here the
68
+ figure is inverted and its hues turned back round, so dark ink reads light
69
+ on a dark node and a purple edge stays purple. Written twice, byte-identical:
70
+ the [data-theme] switch shell.js owns, and the media block for first paint. */
71
+ html[data-theme="dark"] .dgv__pan svg { filter: invert(1) hue-rotate(180deg); }
72
+ @media (prefers-color-scheme: dark) {
73
+ html:not([data-theme]) .dgv__pan svg { filter: invert(1) hue-rotate(180deg); }
74
+ }
75
+
64
76
  /* Floating control bar — bottom-right of the canvas. Glass, like every other
65
77
  control the world floats over content. */
66
78
  .dgv__toolbar {
@@ -81,6 +81,10 @@
81
81
  const natW = vb[2] || 800;
82
82
  const natH = vb[3] || 600;
83
83
  parsed.style.maxWidth = 'none';
84
+ // mermaid-cli bakes its `-b white` into the root's inline style. The PNG and
85
+ // external embeds keep that ground; on the canvas it was a white plate on
86
+ // the hall's dark mode (task 1003639), so drop it and let the canvas show.
87
+ parsed.style.backgroundColor = '';
84
88
  parsed.setAttribute('width', natW);
85
89
  parsed.setAttribute('height', natH);
86
90
  parsed.setAttribute('preserveAspectRatio', 'xMidYMid meet');
@@ -98,8 +98,8 @@
98
98
  <!-- The app shell (sidebar + top bar + footer). Dependency-free; runs at parse
99
99
  time so the chrome exists before the deferred page scripts execute. -->
100
100
  <script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
101
- <script src="/builders/craft-mode.js?v=2026-10-08-city-tab"></script>
102
- <script src="/builders/shell.js?v=2026-10-08-glyph-fix"></script>
101
+ <script src="/builders/craft-mode.js?v=2026-10-09-living3"></script>
102
+ <script src="/builders/shell.js?v=2026-10-10-hall-keys1"></script>
103
103
  <!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
104
104
  <script src="/builders/palette.js" defer></script>
105
105
  <script src="/builders/diagram-viewer.js?v=2026-06-14-diagviewer-1" defer></script>
@@ -99,8 +99,8 @@
99
99
  <div id="toast" class="toast" role="status" aria-live="polite" data-visible="0"></div>
100
100
 
101
101
  <script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
102
- <script src="/builders/craft-mode.js?v=2026-10-08-city-tab"></script>
103
- <script src="/builders/shell.js?v=2026-10-08-glyph-fix"></script>
102
+ <script src="/builders/craft-mode.js?v=2026-10-09-living3"></script>
103
+ <script src="/builders/shell.js?v=2026-10-10-hall-keys1"></script>
104
104
  <!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
105
105
  <script src="/builders/palette.js" defer></script>
106
106
  <script src="/builders/md-reader.js?v=2026-09-02-mdreader-2"></script>
@@ -55,8 +55,8 @@
55
55
  <div id="toast" class="toast" role="status" aria-live="polite" data-visible="0"></div>
56
56
 
57
57
  <script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
58
- <script src="/builders/craft-mode.js?v=2026-10-08-city-tab"></script>
59
- <script src="/builders/shell.js?v=2026-10-08-glyph-fix"></script>
58
+ <script src="/builders/craft-mode.js?v=2026-10-09-living3"></script>
59
+ <script src="/builders/shell.js?v=2026-10-10-hall-keys1"></script>
60
60
  <script src="/builders/palette.js" defer></script>
61
61
  <script src="/builders/dom-utils.js?v=2026-06-16-gate"></script>
62
62
  <script src="/builders/hall-kit.js"></script>
@@ -78,8 +78,8 @@
78
78
  <div id="toast" class="toast" role="status" aria-live="polite" data-visible="0"></div>
79
79
 
80
80
  <script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
81
- <script src="/builders/craft-mode.js?v=2026-10-08-city-tab"></script>
82
- <script src="/builders/shell.js?v=2026-10-08-glyph-fix"></script>
81
+ <script src="/builders/craft-mode.js?v=2026-10-09-living3"></script>
82
+ <script src="/builders/shell.js?v=2026-10-10-hall-keys1"></script>
83
83
  <!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
84
84
  <script src="/builders/palette.js" defer></script>
85
85
  <script src="/builders/dom-utils.js?v=2026-06-16-gate"></script>
@@ -138,8 +138,8 @@
138
138
  </div>
139
139
 
140
140
  <script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
141
- <script src="/builders/craft-mode.js?v=2026-10-08-city-tab"></script>
142
- <script src="/builders/shell.js?v=2026-10-08-glyph-fix"></script>
141
+ <script src="/builders/craft-mode.js?v=2026-10-09-living3"></script>
142
+ <script src="/builders/shell.js?v=2026-10-10-hall-keys1"></script>
143
143
  <script src="/builders/palette.js" defer></script>
144
144
 
145
145
  <script src="/builders/idea-objects.js?v=2026-09-27-split"></script>
@@ -231,8 +231,8 @@
231
231
  <div id="toast" class="toast" role="status" aria-live="polite" data-visible="0"></div>
232
232
 
233
233
  <script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
234
- <script src="/builders/craft-mode.js?v=2026-10-08-city-tab"></script>
235
- <script src="/builders/shell.js?v=2026-10-08-glyph-fix"></script>
234
+ <script src="/builders/craft-mode.js?v=2026-10-09-living3"></script>
235
+ <script src="/builders/shell.js?v=2026-10-10-hall-keys1"></script>
236
236
  <!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
237
237
  <script src="/builders/palette.js" defer></script>
238
238
  <script src="/builders/dom-utils.js?v=2026-06-14-domutils"></script>