@bongos/core 1.21.113 → 1.21.115

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 (265) hide show
  1. package/.bongos-core.json +608 -188
  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 +709 -626
  25. package/docs/copy-registry.json +1673 -858
  26. package/docs/file-map.md +2 -1
  27. package/docs/module-api-changelog.md +4 -0
  28. package/docs/packs/engineer.md +2 -1
  29. package/docs/page-inventory.json +91 -6
  30. package/docs/page-readings.json +4875 -4748
  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-hall-live.states.json +0 -5
  166. package/modules/public-landing/public/projects.html +169 -6
  167. package/modules/public-landing/public/projects.probes.json +10 -6
  168. package/modules/public-landing/public/projects.states.json +13 -13
  169. package/modules/public-landing/public/terms.html +2 -2
  170. package/modules/ui-design/kit/fixtures/connections-empty.json +12 -0
  171. package/modules/ui-design/kit/fixtures/connections-inactive.json +7 -0
  172. package/modules/ui-design/kit/fixtures/connections.json +22 -0
  173. package/modules/ui-design/kit/serve.js +95 -0
  174. package/package-lock.json +2 -2
  175. package/package.json +1 -1
  176. package/release-notes.json +128 -0
  177. package/scripts/discord/README.md +8 -5
  178. package/scripts/discord/post.js +12 -1
  179. package/scripts/gds/artifact-audit.js +20 -3
  180. package/scripts/gds/ask.js +164 -0
  181. package/scripts/gds/autobongos-verify.js +21 -2
  182. package/scripts/gds/government-walk.js +638 -4
  183. package/scripts/gds/pulse.js +9 -6
  184. package/scripts/gds/ship-escalation.js +22 -3
  185. package/scripts/gds/ship-finish.js +5 -4
  186. package/scripts/gds/ship-merge-gate.js +18 -6
  187. package/scripts/hall-preview/README.md +41 -1
  188. package/scripts/hall-preview/pref-writes.js +140 -0
  189. package/scripts/hall-preview/refresh-fixtures.js +101 -7
  190. package/scripts/hall-preview/scrub-identity.js +366 -7
  191. package/scripts/hall-preview/server.js +27 -1
  192. package/scripts/render-diagrams.sh +4 -2
  193. package/src/bongos/auth-idp.js +6 -1
  194. package/src/bongos/project-settings.js +41 -0
  195. package/src/bongos/route-rank-check.js +27 -0
  196. package/src/bongos/routes/me.js +68 -7
  197. package/src/bongos/serve-internal.js +5 -1
  198. package/src/module-api.js +7 -1
  199. package/src/platform-server.js +10 -0
  200. package/tests/application_lifecycle.mjs +47 -5
  201. package/tests/conductor_main_e2e.mjs +21 -0
  202. package/tests/connections_api.mjs +18 -0
  203. package/tests/craft_mode_nav.mjs +5 -3
  204. package/tests/craft_mode_tallies.mjs +52 -16
  205. package/tests/discord_approvals.mjs +11 -0
  206. package/tests/discord_channels.mjs +20 -0
  207. package/tests/fixtures/gov-seated.mjs +64 -0
  208. package/tests/fixtures/government-ask-cards.json +1284 -0
  209. package/tests/government_act_alone_buildings.mjs +1 -0
  210. package/tests/government_agent_asks.mjs +322 -0
  211. package/tests/government_asks.mjs +408 -0
  212. package/tests/government_build_rights.mjs +253 -0
  213. package/tests/government_buildouts.mjs +382 -0
  214. package/tests/government_counts.mjs +143 -0
  215. package/tests/government_decision_rules.mjs +5 -1
  216. package/tests/government_laws.mjs +488 -0
  217. package/tests/government_laws_session.mjs +321 -0
  218. package/tests/government_leads.mjs +375 -0
  219. package/tests/government_positions.mjs +127 -0
  220. package/tests/government_presets.mjs +215 -0
  221. package/tests/government_routes.mjs +8 -1
  222. package/tests/government_routing.mjs +118 -0
  223. package/tests/government_seed.mjs +5 -0
  224. package/tests/government_treasury.mjs +394 -0
  225. package/tests/governor_docket.mjs +26 -2
  226. package/tests/hall_buildouts.mjs +208 -0
  227. package/tests/hall_city.mjs +14 -6
  228. package/tests/hall_city_living.mjs +617 -0
  229. package/tests/hall_gov_counts.mjs +336 -0
  230. package/tests/hall_gov_living.mjs +636 -0
  231. package/tests/hall_gov_real_site.mjs +655 -0
  232. package/tests/hall_matter_card.mjs +6 -1
  233. package/tests/hall_my_agents.mjs +481 -0
  234. package/tests/hall_nav.mjs +107 -4
  235. package/tests/hall_page_gate_map.mjs +4 -0
  236. package/tests/hall_preview_governor_fixtures.mjs +30 -3
  237. package/tests/hall_preview_scrub.mjs +59 -1
  238. package/tests/hall_preview_security.mjs +169 -0
  239. package/tests/hall_reading_world.mjs +44 -0
  240. package/tests/hall_roster_world.mjs +6 -2
  241. package/tests/hall_street.mjs +18 -2
  242. package/tests/hall_street_amend.mjs +1 -1
  243. package/tests/hall_street_deck.mjs +609 -0
  244. package/tests/hall_street_depth.mjs +559 -0
  245. package/tests/hall_street_desk.mjs +1 -1
  246. package/tests/hall_street_inside.mjs +29 -5
  247. package/tests/hall_tweak_editor.mjs +4 -1
  248. package/tests/hub_account_page.mjs +94 -3
  249. package/tests/hub_connections_page.mjs +507 -0
  250. package/tests/hub_invite_badge.mjs +1 -1
  251. package/tests/idp_device_exchange.mjs +18 -0
  252. package/tests/landing_legal_pages.mjs +8 -5
  253. package/tests/landing_page.mjs +23 -4
  254. package/tests/nav_permission_atoms.mjs +4 -1
  255. package/tests/profile_connections_ui.mjs +88 -25
  256. package/tests/projects_hub.mjs +15 -0
  257. package/tests/projects_hub_pre_uat.mjs +4 -2
  258. package/tests/render_check.mjs +2 -2
  259. package/tests/ship_broadcast_routing.mjs +57 -16
  260. package/tests/ship_broadcast_server.mjs +40 -7
  261. package/tests/ship_merge_gate.mjs +19 -0
  262. package/tests/ui_design_kit.mjs +2 -2
  263. package/tests/watch_applications_queue.mjs +23 -0
  264. package/tests/wizard_physics.mjs +1 -1
  265. package/tests/wizard_physics_more.mjs +133 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bongos/core",
3
- "version": "1.21.113",
3
+ "version": "1.21.115",
4
4
  "description": "Cloud Bongos — the AI-first build platform core (GDS + platform surfaces + module system), installed as a versioned dependency (ADR 0108).",
5
5
  "license": "AGPL-3.0-or-later",
6
6
  "main": "src/platform-server.js",
@@ -9536,5 +9536,133 @@
9536
9536
  "id": "1004679",
9537
9537
  "text": "When a project turns automatic pickup on, the background runner now picks up the oldest page an artist submitted and applies it, before its other work, then leaves it waiting for the artist. It stops at the monthly limit, leav"
9538
9538
  }
9539
+ ],
9540
+ "1.21.114": [
9541
+ {
9542
+ "id": "1004722",
9543
+ "text": "New core releases can be cut again. Since the living-city prototype merged, every merge to main failed its release check, so no new core version went out and cloudbongos.com stayed on an old build. The cause was one security t"
9544
+ },
9545
+ {
9546
+ "id": "1004728",
9547
+ "text": "Shipping work from a project that keeps its Bongos core in a downloaded package no longer gets stuck at the final merge step."
9548
+ },
9549
+ {
9550
+ "id": "1004702",
9551
+ "text": "Decisions now open as light glass panels right where they belong, built to the mocks you approved. The deck no longer hides the street: each question sits beside the building that asks, with a thin line to its pin, the rest of"
9552
+ },
9553
+ {
9554
+ "id": "1002846",
9555
+ "text": "The ship-news channel is back on: it now gets one plain headline for each new feature or bug fix, while the builders' ship-feed keeps logging every ship."
9556
+ },
9557
+ {
9558
+ "id": "1004260",
9559
+ "text": "When you make your account private or hide your numbers, your account page now tells you that your guilds still count your numbers in their rounded totals, and links to each guild's page where you can switch that off."
9560
+ },
9561
+ {
9562
+ "id": "1004673",
9563
+ "text": "When a project's owner reviews people asking to join, a confirmed applicant's platform name now shows even if the platform is down, and the Discord approval prompt is re-posted with the real applicant's words when they take ov"
9564
+ },
9565
+ {
9566
+ "id": "1003649",
9567
+ "text": "The landing's dark mode now loads its chrome artwork about 200 KB lighter (447 KB down to 247 KB on first paint) with no visible change, so the page appears faster on slow connections."
9568
+ },
9569
+ {
9570
+ "id": "1003639",
9571
+ "text": "The onboarding diagrams now match the builders' hall in dark mode instead of sitting there as a bright white box, and they still look the same in light mode."
9572
+ },
9573
+ {
9574
+ "id": "1002536",
9575
+ "text": "Builders get a new #ai-news Discord channel for AI-tooling news from a short, curated list of feeds, at no running cost to us. An Archon switches it on by following the new setup guide."
9576
+ },
9577
+ {
9578
+ "id": "1003645",
9579
+ "text": "A check in the project page's test kit now really proves that \"Let the platform choose again\" resets a project's planet, instead of passing either way."
9580
+ },
9581
+ {
9582
+ "id": "1004279",
9583
+ "text": "On a project's hall, your profile's Connections tab now shows only the people you're connected with who also build on that project. Your requests and everyone else are one click away on your Connections page on the hub."
9584
+ },
9585
+ {
9586
+ "id": "1004278",
9587
+ "text": "You can now manage your connections on cloudbongos.com: a new Connections page (in your profile menu) shows who wants to connect, the builders you know across every project, and builders you may know, and lets you ask anyone b"
9588
+ },
9589
+ {
9590
+ "id": "1004590",
9591
+ "text": "The Projects menu now says \"Your projects: the ones you own\". The projects you help build moved to your Account page, so the old \"own or build on\" was only half true."
9592
+ },
9593
+ {
9594
+ "id": "1004720",
9595
+ "text": "The guide to your project's government now tells the whole story in plain words. It opens with the idea behind it: government is how a project steers its AI. A one-minute overview names the five parts: laws (the standing order"
9596
+ },
9597
+ {
9598
+ "id": "1004719",
9599
+ "text": "The government walk now proves the new government end to end: 169 checks, all passing, up from 123. It goes through the real routes for laws (passed by a vote, handed to every AI session, a locked setting refused and read back"
9600
+ },
9601
+ {
9602
+ "id": "1004718",
9603
+ "text": "The street and the city got their polish pass. On a wide screen the street now sits right on its six readings with no empty black sky above the skyline. Inside a building, the floor you pick is drawn in ink, not salmon, so sal"
9604
+ },
9605
+ {
9606
+ "id": "1004717",
9607
+ "text": "The city and the street now run on your project's real government only. The sample data the prototype leaned on is deleted: no invented Leads, laws, pots, building work or reworded questions, and no \"prototype\" tags or keys an"
9608
+ },
9609
+ {
9610
+ "id": "1004716",
9611
+ "text": "The government numbers now come from one place on the server. \"To do\", \"wait on others\", \"to decide\", \"agents working\" and \"moving\" are counted once by a new server read, and the city, the street header, the decision deck and"
9612
+ },
9613
+ {
9614
+ "id": "1004715",
9615
+ "text": "Strictness presets are real. A project can now pick how strict its AI agents run: Open workshop (one law: land only, going live waits for a person), Guild (the standard set: also \"stuck? note it and move on\" and agents stay on"
9616
+ },
9617
+ {
9618
+ "id": "1004714",
9619
+ "text": "When an AI agent needs a person to decide something, it now has to ask like a person: one short question, two or three answers to tap, its pick and why, who it waits on, and what happens if nobody answers. The server refuses a"
9620
+ },
9621
+ {
9622
+ "id": "1004712",
9623
+ "text": "The treasury is real. Whoever runs the Treasury (its Lead, or you while it has none) can give a goal a monthly pot. Each pot fills from the project's real AI spend on that goal's work this month. The reserve is last month's sp"
9624
+ },
9625
+ {
9626
+ "id": "1004711",
9627
+ "text": "Whoever holds a building (its Lead, or the owner when it has none) can now really grow it: a committee room, a new floor, an annex, or a district. If the form of government allows it, it goes up at once and the city shows scaf"
9628
+ },
9629
+ {
9630
+ "id": "1004713",
9631
+ "text": "Governing is now a seat you hold, not a craft you pick. The server works out which government seats each builder holds: the owner seat, a building Lead, a seat on a building's own sitting, or a board seat. It sends that list w"
9632
+ },
9633
+ {
9634
+ "id": "1004705",
9635
+ "text": "Every question an agent puts to a person now waits on a real seat. The server decides who each open matter is for: the building's Lead if it has one, the owner when it has none, the voters for a board vote, or whoever the agen"
9636
+ },
9637
+ {
9638
+ "id": "1004710",
9639
+ "text": "Whether a building can be built out without a vote now comes from your form of government, not from anything a Lead's charter says. Under a Monarchy whoever holds a building builds a room, floor or annex at once; under a Timoc"
9640
+ },
9641
+ {
9642
+ "id": "1004709",
9643
+ "text": "Each of the nine buildings in your project's city can now have a real Lead: one person in charge, with a one-line charter saying what they answer for. A Lead is appointed, replaced or removed only by a vote (a People matter)."
9644
+ },
9645
+ {
9646
+ "id": "1004704",
9647
+ "text": "AI agents now have to ask you things the way a person would. When an agent files something that is stuck on you, it must send a short card: one question of twelve words or fewer, two or three answers to tap, the answer it reco"
9648
+ },
9649
+ {
9650
+ "id": "1004707",
9651
+ "text": "Every AI session on your project now reads the project's laws first, before anyone's own settings. The server writes the words, so nobody's local files can change or drop them, and passing or repealing a law changes what the n"
9652
+ },
9653
+ {
9654
+ "id": "1004706",
9655
+ "text": "Your project can now have laws: short one-line rules every AI agent follows, like \"Ask like a human\". A law can also lock a personal setting it overrides. Laws change only the way the constitution does: someone proposes one (o"
9656
+ },
9657
+ {
9658
+ "id": "1004701",
9659
+ "text": "The living city is now the hall's base: the city, the street with depth, the decision deck, the government inside each building, and My agents. On a real project it shows only what the real data supports: no invented Leads, la"
9660
+ }
9661
+ ],
9662
+ "1.21.115": [
9663
+ {
9664
+ "id": "1004671",
9665
+ "text": "When you start a new project, \"Where are you?\" now starts on United States and is a search box instead of a long dropdown. Type a few letters and the list narrows to matching countries; capitals and accents don't matter, so \"c"
9666
+ }
9539
9667
  ]
9540
9668
  }
@@ -45,8 +45,11 @@ node scripts/discord/post.js --channel ship_feed "shipped #607" # -> #shi
45
45
  echo "hello team" | node scripts/discord/post.js
46
46
  ```
47
47
 
48
- `scripts/gds/ship.js` calls this automatically with the task `--summary` once a
49
- ship is live on the droplet. The call is best-effort: a Discord failure logs a
50
- warning and never blocks the deploy. The broadcast runs on the operator's
51
- machine during `/builder-ship`, so the secret only needs to exist locally — the
52
- droplet never needs the webhook URL.
48
+ Ship announcements do **not** come through this CLI any more (task 1749): the
49
+ server posts them once the deploy lands, from
50
+ `modules/discord/ship-broadcast.js` — every ship to `#ship-feed`, and a plain
51
+ headline to `#ship-news` only for a feature or a bug fix (task 1002846). This
52
+ CLI carries the project's other news, which defaults to `#ship-news` (a builder
53
+ graduating, a rank change, an outage heads-up); builder housekeeping passes
54
+ `--channel ship_feed`. Every call is best-effort: a Discord failure logs a
55
+ warning and never blocks anything.
@@ -9,7 +9,18 @@
9
9
  //
10
10
  // Default channel: ship_news — the plain-language, business-facing feed that
11
11
  // replaced the Google Chat broadcast. Exits non-zero on failure so callers can
12
- // treat the post as best-effort (ship.js does).
12
+ // treat the post as best-effort.
13
+ //
14
+ // The default stays ship_news on purpose (task 1002846). SHIP announcements
15
+ // never pass through here: the server posts them from
16
+ // modules/discord/ship-broadcast.js, whose kind filter decides which ships are
17
+ // news. What does pass through here is the project's own news in plain words,
18
+ // which is what #ship-news promises: a builder graduating
19
+ // (modules/onboarding/onboarding-state.js), a rank change
20
+ // (src/bongos/routes/builders.js), an outage heads-up
21
+ // (modules/provisioning/pollers/liveness-notify.js) and the style-guide audit
22
+ // (scripts/cron/style_guide_audit.sh). Builder housekeeping names its channel:
23
+ // scripts/gds/pulse.js's reclaim nudge passes --channel ship_feed.
13
24
 
14
25
  const fs = require('node:fs');
15
26
  const { postWebhook } = require('./lib');
@@ -55,6 +55,7 @@
55
55
  const { execFileSync } = require('node:child_process');
56
56
  const { apiCall, arg, hasFlag } = require('./cli-lib');
57
57
  const { TASK_LIST_MAX_LIMIT, buildTaskPageQuery } = require('../../modules/lifecycle/task-list-limits.js');
58
+ const { postWithAsk } = require('./ask.js');
58
59
 
59
60
  // The statuses where a claimed artifact is supposed to already exist. `shipped` is the one the
60
61
  // reconciler never revisits, and the reason this file exists.
@@ -172,7 +173,7 @@ module.exports = {
172
173
  auditArtifacts, declaresArtifact, taskIdsIn,
173
174
  AUDITED_STATUSES, ASSURANCE_GATE_DATE, TASK_REF,
174
175
  messageEvidence, contentEvidence, fetchAuditedTasks,
175
- blockerSourceRef, blockerBody, fileBlocker,
176
+ blockerSourceRef, blockerBody, blockerAsk, fileBlocker,
176
177
  };
177
178
 
178
179
  // ---- the human surface ------------------------------------------------------------------
@@ -206,14 +207,30 @@ function blockerBody(stranded) {
206
207
  return lines.join('\n');
207
208
  }
208
209
 
210
+ // The card a person answers (task 1004704): the finding as an ask, short enough
211
+ // to decide at a glance; the body above carries the list.
212
+ function blockerAsk(stranded) {
213
+ const n = stranded.length;
214
+ return {
215
+ question: `Check by hand the ${n} shipped task${n === 1 ? '' : 's'} nothing on main names?`,
216
+ options: [
217
+ { key: 'check', label: 'Check each', result: 'Someone reads each by hand before anything is reopened.', act: 'go ahead' },
218
+ { key: 'accept', label: 'Accept them', result: 'They stay shipped and credited as they are.', act: 'not now' },
219
+ ],
220
+ recommend: { key: 'check', why: 'A credited task with no code may be paid work that does not exist.' },
221
+ waits_on: 'lead:review',
222
+ if_nobody_answers: 'They stay shipped and credited, unchecked.',
223
+ };
224
+ }
225
+
209
226
  async function fileBlocker(stranded, { call = apiCall } = {}) {
210
227
  if (!stranded.length) return { filed: false, reason: 'nothing to report' };
211
- const r = await call('POST', '/api/bongos/blockers', {
228
+ const r = await postWithAsk((body) => call('POST', '/api/bongos/blockers', body), {
212
229
  title: `${stranded.length} shipped task(s) claim an artifact nothing on main names`,
213
230
  body_md: blockerBody(stranded),
214
231
  source: 'artifact-audit',
215
232
  source_ref: blockerSourceRef(stranded),
216
- });
233
+ }, blockerAsk(stranded));
217
234
  if (!r || !r.ok) return { filed: false, reason: `POST /blockers → ${r && r.status}` };
218
235
  if (r.data && r.data.skipped) return { filed: false, reason: 'already filed for this exact finding set' };
219
236
  return { filed: true, id: r.data && r.data.blocker && r.data.blocker.id };
@@ -0,0 +1,164 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+ //
4
+ // scripts/gds/ask.js — the rewrite helper an agent runs BEFORE it asks a person
5
+ // anything (task 1004704, goal 1000111: "agents must ask like humans").
6
+ //
7
+ // WHY. The owner's ruling: an AI agent asks a person the way a person would —
8
+ // short, decidable, no slop. The shape is the ask (modules/government/asks.js,
9
+ // task 1004703): one question of at most twelve words, two or three tap answers
10
+ // each with a one-line result, a pick and why, the seat it waits on, what
11
+ // happens if nobody answers; the long text rides along as `detail`. The server
12
+ // refuses anything else, and a blocker an AI session files by hand without one
13
+ // is refused too (`ask_required`). This helper is the loop that turns prose into
14
+ // a card: write the card, check it, read every fix the server names, rewrite,
15
+ // check again — and only then file it, or print it.
16
+ //
17
+ // node scripts/gds/ask.js template a blank card to fill in
18
+ // node scripts/gds/ask.js check <file|-> the server's verdict; on a pass,
19
+ // the card as a person reads it
20
+ //
21
+ // `check` asks the server (POST /government/asks/check, the dry run: nothing is
22
+ // stored). With no session, or a server that cannot answer, it checks with the
23
+ // same rules locally and says so. The file holds the ask bare or as { ask }, so
24
+ // the body you will POST to /blockers can be checked as it is.
25
+ //
26
+ // The printed card is also what an agent puts in CHAT for an ask that is not a
27
+ // stored matter: the "please confirm" list at the end of a run, a review
28
+ // request, a help request. Same shape everywhere a person reads it.
29
+ //
30
+ // For scripts that file templated blockers: `checkedAsk` and `postWithAsk`
31
+ // below. A templated card is checked here before it is sent, and a filing whose
32
+ // card is refused is re-sent without it — a script's blocker always files.
33
+
34
+ const fs = require('node:fs');
35
+ const path = require('node:path');
36
+
37
+ const asks = require(path.join(__dirname, '..', '..', 'modules', 'government', 'asks.js'));
38
+
39
+ const TEMPLATE = Object.freeze({
40
+ question: 'One question, twelve words at most?',
41
+ options: [
42
+ { key: 'yes', label: 'Do it', result: 'One line: what happens if they pick this.' },
43
+ { key: 'no', label: 'Leave it', result: 'One line: what happens if they pick this.' },
44
+ ],
45
+ recommend: { key: 'yes', why: 'One line: why you would pick it.' },
46
+ waits_on: 'owner',
47
+ if_nobody_answers: 'One line: what happens if nobody answers.',
48
+ detail: 'Optional. The long text rides along here; it is never the ask.',
49
+ });
50
+
51
+ // The ask in a body: bare, or as { ask } (the shape POST /blockers takes).
52
+ function askOf(body) {
53
+ return body && typeof body === 'object' && !Array.isArray(body) && body.ask !== undefined ? body.ask : body;
54
+ }
55
+
56
+ // A templated card, checked with the server's own rules. → the stored form, or
57
+ // null when it breaks a rule (the caller files without it rather than not at all).
58
+ function checkedAsk(ask) {
59
+ const r = asks.checkAsk(ask);
60
+ return r.ok ? r.ask : null;
61
+ }
62
+
63
+ // File a blocker with its card. `post(body)` → { ok, status, data } (the shape
64
+ // cli-lib's apiCall and the generated client both answer). A card that breaks a
65
+ // rule is never sent; a server that refuses the card or cannot check it gets the
66
+ // same blocker again without it, so the filing never depends on the card.
67
+ const CARD_REFUSALS = new Set(['ask_refused', 'asks_unavailable', 'validation_failed']);
68
+ async function postWithAsk(post, body, ask) {
69
+ const card = ask ? checkedAsk(ask) : null;
70
+ if (!card) return post(body);
71
+ const r = await post({ ...body, ask: card });
72
+ const code = r && r.data && r.data.error && r.data.error.code;
73
+ if (r && !r.ok && (r.status === 400 || r.status === 503) && CARD_REFUSALS.has(code)) return post(body);
74
+ return r;
75
+ }
76
+
77
+ // The verdict as plain lines. ok → the card; refused → the refusal and each fix.
78
+ function verdictLines({ ok, ask, message, errors, where }) {
79
+ const out = [];
80
+ if (ok) {
81
+ out.push(`✓ This ask has the shape${where === 'local' ? ' (checked here; the server could not be asked)' : ''}. As a person reads it:`);
82
+ out.push('');
83
+ out.push(asks.cardText(ask));
84
+ return out;
85
+ }
86
+ out.push(`✗ ${message || asks.refusalLine(errors)}`);
87
+ if (where === 'local') out.push(' (checked here; the server could not be asked)');
88
+ const list = Array.isArray(errors) ? errors : [];
89
+ if (list.length) {
90
+ out.push('');
91
+ out.push('Fix each, then check again:');
92
+ for (const e of list) out.push(` - ${e.field}: ${e.message}`);
93
+ }
94
+ return out;
95
+ }
96
+
97
+ function readJson(file) {
98
+ const raw = file === '-' ? fs.readFileSync(0, 'utf8') : fs.readFileSync(file, 'utf8');
99
+ return JSON.parse(raw.replace(/^/, ''));
100
+ }
101
+
102
+ // The server's verdict, or null when it could not give one (no session, offline,
103
+ // no government module, not allowed) — the caller then checks locally.
104
+ async function serverVerdict(ask, { client } = {}) {
105
+ let api = client;
106
+ try {
107
+ if (!api) {
108
+ const lib = require('./cli-lib');
109
+ if (!lib.readSessionToken()) return null;
110
+ api = await lib.cliClient({ allowUnauthenticated: true });
111
+ }
112
+ const r = await api.request('POST', '/government/asks/check', { body: { ask } });
113
+ if (r && r.ok && r.data && r.data.ok) return { ok: true, ask: r.data.ask, where: 'server' };
114
+ const err = r && r.data && r.data.error;
115
+ if (r && r.status === 400 && err && err.code === 'ask_refused') {
116
+ return { ok: false, message: err.message, errors: (err.details && err.details.errors) || [], where: 'server' };
117
+ }
118
+ return null;
119
+ } catch (_) {
120
+ return null;
121
+ }
122
+ }
123
+
124
+ async function check(file, deps = {}) {
125
+ let body;
126
+ try { body = readJson(file); } catch (e) {
127
+ return { code: 2, lines: [`ask: could not read the card as JSON (${e.message}). Start from: node scripts/gds/ask.js template`] };
128
+ }
129
+ const ask = askOf(body);
130
+ let v = deps.local ? null : await serverVerdict(ask, deps);
131
+ if (!v) {
132
+ const r = asks.checkAsk(ask);
133
+ v = { ok: r.ok, ask: r.ask, errors: r.errors, where: 'local' };
134
+ }
135
+ return { code: v.ok ? 0 : 1, lines: verdictLines(v) };
136
+ }
137
+
138
+ const USAGE = [
139
+ 'usage:',
140
+ ' node scripts/gds/ask.js template print a blank card to fill in',
141
+ ' node scripts/gds/ask.js check <file|-> check a card; on a pass, print it as a person reads it',
142
+ ' --local check with the rules here, without the server',
143
+ ].join('\n');
144
+
145
+ async function main(argv = process.argv.slice(2)) {
146
+ const cmd = argv[0];
147
+ if (cmd === 'template') {
148
+ console.log(JSON.stringify(TEMPLATE, null, 2));
149
+ return 0;
150
+ }
151
+ if (cmd === 'check' && argv[1]) {
152
+ const r = await check(argv[1], { local: argv.includes('--local') });
153
+ console.log(r.lines.join('\n'));
154
+ return r.code;
155
+ }
156
+ console.error(USAGE);
157
+ return 2;
158
+ }
159
+
160
+ if (require.main === module) {
161
+ main().then((code) => { process.exitCode = code; }, (e) => { console.error(`ask: ${e && e.message}`); process.exitCode = 1; });
162
+ }
163
+
164
+ module.exports = { TEMPLATE, askOf, checkedAsk, postWithAsk, verdictLines, serverVerdict, check, main };
@@ -39,6 +39,7 @@ const path = require('node:path');
39
39
  const { execFile } = require('node:child_process');
40
40
 
41
41
  const { classifyStrand, WATCHED } = require('./strand-watch.js');
42
+ const { postWithAsk } = require('./ask.js');
42
43
 
43
44
  // failureReason — what a failed child process said, fit for one run-log field
44
45
  // (task 1004180).
@@ -264,6 +265,23 @@ function blockerFor(v, { taskId, taskTitle = null, worker = null } = {}) {
264
265
  body_md: lines.join('\n'),
265
266
  source: 'autobongos',
266
267
  source_ref: `task-${taskId}-${v.shape}`,
268
+ ask: blockerAsk(v, { taskId }),
269
+ };
270
+ }
271
+
272
+ // The card a person answers (task 1004704): the shape as one decidable question.
273
+ // fileBlocker sends it beside the row and files without it if it is refused.
274
+ function blockerAsk(v, { taskId }) {
275
+ const shape = String((v && v.shape) || 'unfinished').replace(/_/g, ' ');
276
+ return {
277
+ question: `Requeue task ${taskId}, which came back ${shape}?`,
278
+ options: [
279
+ { key: 'requeue', label: 'Requeue it', result: 'The blocker closes and a runner may pick it up again.', act: 'go ahead' },
280
+ { key: 'keep', label: 'Keep it out', result: 'It stays out of the pool until someone looks.', act: 'not now' },
281
+ ],
282
+ recommend: { key: 'keep', why: 'Read the run log first; a second run may fail the same way.' },
283
+ waits_on: 'lead:automation',
284
+ if_nobody_answers: 'The task stays out of the pool.',
267
285
  };
268
286
  }
269
287
 
@@ -351,7 +369,8 @@ async function fetchTask(api, taskId) {
351
369
  async function fileBlocker(api, row, { taskId, link }) {
352
370
  let created = null;
353
371
  try {
354
- const r = await api.blockers.postBlockers({ body: row });
372
+ const { ask, ...body } = row;
373
+ const r = await postWithAsk((b) => api.blockers.postBlockers({ body: b }), body, ask);
355
374
  if (!r || !r.ok) return { filed: false, reason: `POST /blockers → ${r ? r.status : 'no response'}`, linked: false };
356
375
  if (r.data && r.data.skipped) return { filed: false, duplicate: true, reason: 'this task already carries a blocker of this shape', linked: false };
357
376
  created = r.data && r.data.blocker;
@@ -594,6 +613,6 @@ if (require.main === module) {
594
613
  }
595
614
 
596
615
  module.exports = {
597
- classifyLedger, blockerFor, probeArtifact, fileBlocker, verifyShip, failureReason,
616
+ classifyLedger, blockerFor, blockerAsk, probeArtifact, fileBlocker, verifyShip, failureReason,
598
617
  LAND_GRACE_MS, namesTask, pendingLandIds, recheckLands,
599
618
  };