@bongos/core 1.24.37 → 1.24.38

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 (51) hide show
  1. package/.bongos-core.json +55 -55
  2. package/docs/copy-inventory.md +21 -21
  3. package/docs/copy-registry.json +23 -23
  4. package/docs/module-api-changelog.md +2 -0
  5. package/docs/page-readings.json +340 -341
  6. package/modules/hall-ui/public/ai-studio.html +2 -2
  7. package/modules/hall-ui/public/atlas.html +2 -2
  8. package/modules/hall-ui/public/blockers.html +2 -2
  9. package/modules/hall-ui/public/board-room.html +2 -2
  10. package/modules/hall-ui/public/city.html +2 -2
  11. package/modules/hall-ui/public/collab.html +2 -2
  12. package/modules/hall-ui/public/commands.html +2 -2
  13. package/modules/hall-ui/public/copy-desk.html +2 -2
  14. package/modules/hall-ui/public/craft-mode.js +5 -3
  15. package/modules/hall-ui/public/deploy.html +2 -2
  16. package/modules/hall-ui/public/gate.html +2 -2
  17. package/modules/hall-ui/public/goal-map.html +2 -2
  18. package/modules/hall-ui/public/goals.html +2 -2
  19. package/modules/hall-ui/public/government.html +2 -2
  20. package/modules/hall-ui/public/idea.html +2 -2
  21. package/modules/hall-ui/public/ideas.html +2 -2
  22. package/modules/hall-ui/public/index.html +2 -2
  23. package/modules/hall-ui/public/market-watch-item.html +2 -2
  24. package/modules/hall-ui/public/market-watch-rules.html +2 -2
  25. package/modules/hall-ui/public/market-watch.html +2 -2
  26. package/modules/hall-ui/public/modules.html +2 -2
  27. package/modules/hall-ui/public/money.html +2 -2
  28. package/modules/hall-ui/public/my-agents.html +2 -2
  29. package/modules/hall-ui/public/primer.html +2 -2
  30. package/modules/hall-ui/public/profile.html +2 -2
  31. package/modules/hall-ui/public/project-settings.html +2 -2
  32. package/modules/hall-ui/public/roadmap.html +2 -2
  33. package/modules/hall-ui/public/roster.html +2 -2
  34. package/modules/hall-ui/public/sessions.html +2 -2
  35. package/modules/hall-ui/public/settings.html +2 -2
  36. package/modules/hall-ui/public/shell.js +106 -89
  37. package/modules/hall-ui/public/street.html +2 -2
  38. package/modules/hall-ui/public/studio.html +2 -2
  39. package/modules/hall-ui/public/task.html +2 -2
  40. package/modules/hall-ui/public/thinking.html +2 -2
  41. package/modules/hall-ui/public/tweak-editor.html +2 -2
  42. package/modules/hall-ui/public/watch.html +2 -2
  43. package/modules/hall-ui/public/work.html +2 -2
  44. package/package-lock.json +2 -2
  45. package/package.json +1 -1
  46. package/release-notes.json +6 -0
  47. package/src/module-api.js +1 -1
  48. package/tests/craft_mode_nav.mjs +12 -10
  49. package/tests/goal_map_page.mjs +5 -2
  50. package/tests/hall_nav.mjs +20 -13
  51. package/tests/nav_permission_atoms.mjs +1 -1
@@ -176,13 +176,27 @@
176
176
  // alongside it as sr-only text, because "3" alone in a link tells a screen
177
177
  // reader nothing about what is waiting.
178
178
  // task 2175: grouped by AUDIENCE of the data, so the sidebar reads in coherent
179
- // runs instead of one long list — the project (unlabeled), You, Community,
180
- // Docs, Government. A group's `gate` must match its most permissive item's, or the
179
+ // runs instead of one long list. Since task 1005071: Work, Make, Community, You,
180
+ // Govern, Run the project, Help. A group's `gate` must match its most permissive item's, or the
181
181
  // head renders over nothing.
182
182
  var NAV = [
183
- { group: '', items: [
183
+ // task 1005071 (goal 1000095; owner decision 2026-11-04, from the sitemap audit): the
184
+ // project group was eleven items under no heading, mixing the work, the artist's
185
+ // room, an add-on and two governing surfaces. It is labelled now and split by what
186
+ // you DO there: Work (the project's state, everyone), Make (where you build things),
187
+ // Govern (the board's rooms). 'always' because Home is.
188
+ { group: 'Work', gate: 'always', items: [
184
189
  { id: 'home', label: 'Home', icon: 'home', href: '/', view: 'home', gate: 'always' },
185
- { id: 'roadmap', label: 'Roadmap', icon: 'roadmap', href: '/roadmap', gate: 'member' },
190
+ // task 1966: Tasks (the board formerly labelled "Work") is visible to ANY
191
+ // signed-in builder (incl. newcomer Xenos). Claimability is controlled
192
+ // per-task, not by hiding the page — every row carries a rank tag and the
193
+ // server enforces requires_rank on the claim. This reverses task #833's
194
+ // newcomer hide (the 'work' gate below is now unused).
195
+ // task 1002425: relabelled Work → Tasks and moved below Roadmap/Goals. The
196
+ // id ('work') and href ('/work') are deliberately UNCHANGED so deep links,
197
+ // active-nav detection (#nav-work), the 'work' gate case, and the server
198
+ // page-gate all keep working — only the visible label and order change.
199
+ { id: 'work', label: 'Tasks', icon: 'work', href: '/work', gate: 'signed' },
186
200
  { id: 'goals', label: 'Goals', icon: 'goals', href: '/goals', gate: 'member' },
187
201
  // task 1004232 (sky part 4 of 5, goal 1000095; ADR 0227 §11, ADR 0331):
188
202
  // THE PROJECT SKY — the whole project drawn from the ledger, at the URL
@@ -195,16 +209,7 @@
195
209
  // because the href does: Goals' own "see which goals wait on each other"
196
210
  // link and every bookmark land here unchanged.
197
211
  { id: 'goal-map', label: 'Sky', icon: 'sky', href: '/goal-map', gate: 'member' },
198
- // task 1966: Tasks (the board formerly labelled "Work") is visible to ANY
199
- // signed-in builder (incl. newcomer Xenos). Claimability is controlled
200
- // per-task, not by hiding the page — every row carries a rank tag and the
201
- // server enforces requires_rank on the claim. This reverses task #833's
202
- // newcomer hide (the 'work' gate below is now unused).
203
- // task 1002425: relabelled Work → Tasks and moved below Roadmap/Goals. The
204
- // id ('work') and href ('/work') are deliberately UNCHANGED so deep links,
205
- // active-nav detection (#nav-work), the 'work' gate case, and the server
206
- // page-gate all keep working — only the visible label and order change.
207
- { id: 'work', label: 'Tasks', icon: 'work', href: '/work', gate: 'signed' },
212
+ { id: 'roadmap', label: 'Roadmap', icon: 'roadmap', href: '/roadmap', gate: 'member' },
208
213
  // task 1003455 (goal 1000089): the open-blocker queue — what's stuck on the
209
214
  // owner. Lives with the project's own state (Roadmap/Goals/Tasks), not You
210
215
  // or Community, because its subject is the project, not a person. Its one
@@ -214,40 +219,6 @@
214
219
  // fronts, showing the link to signed-in builders while a stranger who
215
220
  // already has the URL can still open it.
216
221
  { id: 'blockers', label: 'Blockers', icon: 'blockers', href: '/blockers', gate: 'signed' },
217
- // task 1003744 (goal 1000111): the Board Room lives HERE, in the project's
218
- // own group, and gates on the atom its page gates on.
219
- //
220
- // WHY IT LEFT GOVERNMENT. ADR 0266 carved the room out of /government, so
221
- // the item first landed in the Government group and read that group's metic
222
- // floor — the closest rank the shell could then express. Its real wall is
223
- // `board.vote.cast` (auth.js requireBoardVotePage), which floors at XENOS on
224
- // purpose so that WIDENING the board works (modules/government/board.js). The
225
- // moment an instance seats a sub-Metic member — the config change ADR 0175 §6
226
- // exists to make — that member could reach the room by URL and by the
227
- // board_votes need's deep link, with no sidebar entry.
228
- //
229
- // Fixing the gate alone would have put a wider item under a metic group head,
230
- // so a newcomer board member would see a group labelled "Government" holding
231
- // one link — more authority than they hold. The owner's call (2026-09-09) was
232
- // to move it instead: a sitting is work the project does, beside Goals and
233
- // Tasks, not a monitoring surface. The Government group's audience and floor
234
- // are unchanged.
235
- //
236
- // Cosmetic only, as every gate here is — the page gate is the wall (ADR 0016).
237
- // task 1003737: the badge's first consumer. The owner's ask was to see that
238
- // a sitting waits WITHOUT opening the room, and the count is already on
239
- // /me (boardVotesNeed), pre-filtered to what the vote route would accept —
240
- // so the badge counts ballots this viewer can actually cast, never "items
241
- // open somewhere".
242
- // task 1004685: `position: true` narrows the gate to seat holders (GOVERNING IS A POSITION).
243
- { id: 'board-room', label: 'Board Room', icon: 'boardroom', href: '/board-room', gate: 'perm:board.vote.cast', count: 'board_votes', position: true },
244
- // The governor city (task 1004524): the owner put it on the sidebar on
245
- // 2026-10-08, reversing "leave it off". It is the Governing mode's lead tab
246
- // (craft-mode.js folds that mode's other tabs into a dropdown under it).
247
- // Gated on the atom its page is (requireBoardVotePage), and it sits in this
248
- // head-less group for the reason the Board Room does: the atom floors below
249
- // any rank head. Cosmetic only (ADR 0016).
250
- { id: 'city', label: 'City', icon: 'city', href: '/city', gate: 'perm:board.vote.cast', position: true },
251
222
  // task 1004326 (BV2.TW15 of goal 1000095): the Ideas board (/ideas, task
252
223
  // 1002928) and the Copy desk (/copy-desk, task 1003113) are ARCHIVED — off
253
224
  // the nav on the owner's call of 2026-09-27, NOT deleted. Both pages and
@@ -269,6 +240,9 @@
269
240
  // thought, and the route reads the VIEWER's own trail, so there is
270
241
  // nothing here a rank could protect.
271
242
  { id: 'thinking', label: 'Your thinking', icon: 'thinking', href: '/thinking', gate: 'signed' },
243
+ ] },
244
+ // task 1005071: where things get made. Studio and the module-gated Market Watch.
245
+ { group: 'Make', gate: 'signed', items: [
272
246
  // task 1003117 (R06 of goal 1000074): the Studio — artist mode, "a place an
273
247
  // artist wants to be, not a form". Here and not in Docs (a place you ACT,
274
248
  // not reference) or You (its subject is the product, not a person).
@@ -279,21 +253,6 @@
279
253
  { id: 'studio', label: 'Studio', icon: 'studio', href: '/studio', gate: 'signed' },
280
254
  { id: 'market-watch', label: 'Market Watch', icon: 'marketwatch', href: '/market-watch', gate: 'signed', module: 'market-watch' }, // task 1004939: 'signed' is its page floor; dropped where the module is off
281
255
  ] },
282
- // Your own numbers. task 2174 folded Achievements into Standing and this task
283
- // retires its nav entry; VIEW_ALIASES still routes #achievements here, so old
284
- // bookmarks and the stat tiles keep landing on the section.
285
- { group: 'You', gate: 'signed', items: [
286
- { id: 'standing', label: 'Accomplishments', icon: 'accomplishments', href: '/#accomplishments', view: 'standing', gate: 'signed' },
287
- // task 1467: the viewable, shareable builder profile. The nav link points at
288
- // the viewer's OWN profile (profile.js defaults to self when no ?id=). gate is
289
- // cosmetic only — the /profile PAGE is public (a portfolio others can open via
290
- // /profile?id=N from the leaderboard); 'signed' just means "show this 'my
291
- // profile' shortcut once you're signed in".
292
- { id: 'profile', label: 'Profile', icon: 'profile', href: '/profile', gate: 'signed' },
293
- // task 1004685 (prototype, board 6): MY AGENTS — how your own Claude works for you
294
- // and which settings the project's laws lock. 'signed' is its page's real floor.
295
- { id: 'my-agents', label: 'My agents', icon: 'agents', href: '/my-agents', gate: 'signed' },
296
- ] },
297
256
  // task 1003442 (goal 1000075): Community is Collab + Builders, and NEITHER
298
257
  // carries a rank flag any more. Both items and this head read 'member'
299
258
  // (authed && rank !== 'xenos') until now, which hid them from the newcomer
@@ -329,33 +288,68 @@
329
288
  // call 2026-09-25, ADR 0337 D5). Cross-project discovery is the hub's, and
330
289
  // /people redirects to /roster.
331
290
  ] },
332
- { group: 'Docs', gate: 'signed', items: [
333
- // task 1002710: primer (and the old diagrams page) were gate:'member' (rank
334
- // !== xenos) to mirror the old thetes+ page gate. That gate is gone — the
335
- // reading room is for the first-session newcomer above all — so the link
336
- // follows it down to 'signed'. Leaving them at 'member' would have ungated the pages
337
- // while still hiding them from the only readers the change was for.
338
- { id: 'primer', label: 'Primer', icon: 'primer', href: '/primer', gate: 'signed' },
339
- // task 1005046 (owner decision 2026-11-03, idea 1001311): ONE reading room.
340
- // Ranks, Economy and Diagrams were three more pages explaining what the
341
- // Primer already explained, so the copies drifted. They are Primer
342
- // chapters now, each with its diagram beside it; /ranks, /drachmae and
343
- // /diagrams 302 to the matching chapter (serve-internal.js), and the
344
- // personal "Where you stand" card moved to Accomplishments.
345
- // task 1004473: every skill and every bongos CLI verb, read live. Its page and
346
- // both reads behind it are sign-in gated, so 'signed' is the real floor here.
347
- { id: 'commands', label: 'Commands', icon: 'commands', href: '/commands', gate: 'signed' },
348
- { id: 'atlas', label: 'Repo Atlas', icon: 'atlas', href: '/atlas', gate: 'member' },
349
- { id: 'modules', label: 'Modules', icon: 'modules', href: '/modules', gate: 'member' },
350
- // The rendered OpenAPI reference lives on the APEX (/docs), not this builders
351
- // subdomain — external so the rewrite shim doesn't turn it into /builders/docs.
352
- { id: 'apidocs', label: 'API docs', icon: 'apidocs', href: '/docs', gate: 'signed', external: true },
291
+ // Your own numbers. task 2174 folded Achievements into Standing and this task
292
+ // retires its nav entry; VIEW_ALIASES still routes #achievements here, so old
293
+ // bookmarks and the stat tiles keep landing on the section.
294
+ { group: 'You', gate: 'signed', items: [
295
+ { id: 'standing', label: 'Accomplishments', icon: 'accomplishments', href: '/#accomplishments', view: 'standing', gate: 'signed' },
296
+ // task 1467: the viewable, shareable builder profile. The nav link points at
297
+ // the viewer's OWN profile (profile.js defaults to self when no ?id=). gate is
298
+ // cosmetic only — the /profile PAGE is public (a portfolio others can open via
299
+ // /profile?id=N from the leaderboard); 'signed' just means "show this 'my
300
+ // profile' shortcut once you're signed in".
301
+ { id: 'profile', label: 'Profile', icon: 'profile', href: '/profile', gate: 'signed' },
302
+ // task 1004685 (prototype, board 6): MY AGENTS — how your own Claude works for you
303
+ // and which settings the project's laws lock. 'signed' is its page's real floor.
304
+ { id: 'my-agents', label: 'My agents', icon: 'agents', href: '/my-agents', gate: 'signed' },
305
+ ] },
306
+ // task 1005071: the board's own rooms get a head of their own. Gated on the SAME
307
+ // atom as both items (perm:, which floors below any rank), so the head can never
308
+ // be narrower than an item under it — the reason task 1003744 kept them out of a
309
+ // rank-gated group. The street stays off the sidebar (owner, kept 2026-11-05):
310
+ // the city is the way in, and it is Governing's Home.
311
+ { group: 'Govern', gate: 'perm:board.vote.cast', position: true, items: [
312
+ // The governor city (task 1004524): the owner put it on the sidebar on
313
+ // 2026-10-08, reversing "leave it off". It is the Governing mode's lead tab
314
+ // (craft-mode.js folds that mode's other tabs into a dropdown under it).
315
+ // Gated on the atom its page is (requireBoardVotePage), and it sits in this
316
+ // head-less group for the reason the Board Room does: the atom floors below
317
+ // any rank head. Cosmetic only (ADR 0016).
318
+ { id: 'city', label: 'City', icon: 'city', href: '/city', gate: 'perm:board.vote.cast', position: true },
319
+ // task 1003744 (goal 1000111): the Board Room lives HERE, in the project's
320
+ // own group, and gates on the atom its page gates on.
321
+ //
322
+ // WHY IT LEFT GOVERNMENT. ADR 0266 carved the room out of /government, so
323
+ // the item first landed in the Government group and read that group's metic
324
+ // floor — the closest rank the shell could then express. Its real wall is
325
+ // `board.vote.cast` (auth.js requireBoardVotePage), which floors at XENOS on
326
+ // purpose so that WIDENING the board works (modules/government/board.js). The
327
+ // moment an instance seats a sub-Metic member — the config change ADR 0175 §6
328
+ // exists to make — that member could reach the room by URL and by the
329
+ // board_votes need's deep link, with no sidebar entry.
330
+ //
331
+ // Fixing the gate alone would have put a wider item under a metic group head,
332
+ // so a newcomer board member would see a group labelled "Government" holding
333
+ // one link — more authority than they hold. The owner's call (2026-09-09) was
334
+ // to move it instead: a sitting is work the project does, beside Goals and
335
+ // Tasks, not a monitoring surface. The Government group's audience and floor
336
+ // are unchanged.
337
+ //
338
+ // Cosmetic only, as every gate here is — the page gate is the wall (ADR 0016).
339
+ // task 1003737: the badge's first consumer. The owner's ask was to see that
340
+ // a sitting waits WITHOUT opening the room, and the count is already on
341
+ // /me (boardVotesNeed), pre-filtered to what the vote route would accept —
342
+ // so the badge counts ballots this viewer can actually cast, never "items
343
+ // open somewhere".
344
+ // task 1004685: `position: true` narrows the gate to seat holders (GOVERNING IS A POSITION).
345
+ { id: 'board-room', label: 'Board Room', icon: 'boardroom', href: '/board-room', gate: 'perm:board.vote.cast', count: 'board_votes', position: true },
353
346
  ] },
354
347
  // Relabeled 'Archon' → 'Governance' in ADR 0157, then → 'Government' by ADR 0174: these pages are no longer
355
348
  // Archon-only, so a group header reading "Archon" over items a Metic can open
356
349
  // would misdescribe the ladder to the builders most likely to be learning it.
357
350
  // task 1004685: a governing surface throughout, so head and items carry `position`.
358
- { group: 'Government', gate: 'government', position: true, items: [
351
+ // task 1005071: 'Government' → 'Run the project' — the operator surfaces.
352
+ { group: 'Run the project', gate: 'government', position: true, items: [
359
353
  // The Board Room was FIRST here from the ADR 0266 carve until task 1003744
360
354
  // moved it into the project group — its wall is an ATOM (`board.vote.cast`,
361
355
  // xenos floor) rather than this group's rank, and a group whose audience is
@@ -395,14 +389,36 @@
395
389
  // reading 'Ranks' beside it is the confusion this rename exists to remove. This tab
396
390
  // is where a rank's permissions are granted, so it says what it does.,
397
391
  ] },
392
+ // task 1005071: 'Docs' → 'Help', and every craft shows it (craft-mode.js ALWAYS_TABS).
393
+ { group: 'Help', gate: 'signed', items: [
394
+ // task 1002710: primer (and the old diagrams page) were gate:'member' (rank
395
+ // !== xenos) to mirror the old thetes+ page gate. That gate is gone — the
396
+ // reading room is for the first-session newcomer above all — so the link
397
+ // follows it down to 'signed'. Leaving them at 'member' would have ungated the pages
398
+ // while still hiding them from the only readers the change was for.
399
+ { id: 'primer', label: 'Primer', icon: 'primer', href: '/primer', gate: 'signed' },
400
+ // task 1005046 (owner decision 2026-11-03, idea 1001311): ONE reading room.
401
+ // Ranks, Economy and Diagrams were three more pages explaining what the
402
+ // Primer already explained, so the copies drifted. They are Primer
403
+ // chapters now, each with its diagram beside it; /ranks, /drachmae and
404
+ // /diagrams 302 to the matching chapter (serve-internal.js), and the
405
+ // personal "Where you stand" card moved to Accomplishments.
406
+ // task 1004473: every skill and every bongos CLI verb, read live. Its page and
407
+ // both reads behind it are sign-in gated, so 'signed' is the real floor here.
408
+ { id: 'commands', label: 'Commands', icon: 'commands', href: '/commands', gate: 'signed' },
409
+ { id: 'atlas', label: 'Repo Atlas', icon: 'atlas', href: '/atlas', gate: 'member' },
410
+ { id: 'modules', label: 'Modules', icon: 'modules', href: '/modules', gate: 'member' },
411
+ // The rendered OpenAPI reference lives on the APEX (/docs), not this builders
412
+ // subdomain — external so the rewrite shim doesn't turn it into /builders/docs.
413
+ { id: 'apidocs', label: 'API docs', icon: 'apidocs', href: '/docs', gate: 'signed', external: true },
414
+ ] },
398
415
  ];
399
416
 
400
417
  // ---------- nav group collapse (labeled groups only) ----------
401
418
  // Mirrors the THEME_KEY localStorage pattern: per-group collapsed state,
402
419
  // survives reloads and carries across every hall page (shell.js runs on all
403
- // of them). Only labeled groups get a toggle — the unlabeled main group
404
- // (Home/Roadmap/Goals/Tasks) is core nav and always stays expanded. Keys are
405
- // the lowercased group label, so a regroup renames the key and a group reverts
420
+ // of them). Every group is labeled (task 1005071), so every group gets a toggle.
421
+ // Keys are the group label, lowercased and hyphenated, so a regroup renames the key and a group reverts
406
422
  // to expanded once — acceptable for a cosmetic preference.
407
423
  var NAV_COLLAPSE_KEY = 'hall-nav-collapsed';
408
424
 
@@ -435,7 +451,8 @@
435
451
  // source renderFoot() uses, so the core carries no hardcoded identity.
436
452
  var platformName = (brand.identity && (brand.identity.productName || brand.identity.worldName)) || 'projects';
437
453
  var groups = NAV.map(function (g) {
438
- var groupId = g.group ? g.group.toLowerCase() : '';
454
+ // A label can have spaces ('Run the project'); an id cannot, or aria-controls breaks.
455
+ var groupId = g.group ? g.group.toLowerCase().replace(/\s+/g, '-') : '';
439
456
  var collapsible = !!g.group;
440
457
  var collapsed = collapsible && isGroupCollapsed(groupId);
441
458
  var items = g.items.map(function (it) {
@@ -230,8 +230,8 @@
230
230
 
231
231
  <script src="/builders/dom-utils.js?v=2026-10-25-escape"></script>
232
232
  <script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
233
- <script src="/builders/craft-mode.js?v=2026-11-04-money"></script>
234
- <script src="/builders/shell.js?v=2026-11-04-money"></script>
233
+ <script src="/builders/craft-mode.js?v=2026-11-05-sections"></script>
234
+ <script src="/builders/shell.js?v=2026-11-05-sections"></script>
235
235
  <script src="/builders/palette.js" defer></script>
236
236
  <script src="/builders/gov-living.js?v=2026-10-09-positions1"></script>
237
237
  <script src="/builders/gov-feeds.js?v=2026-10-09-living3"></script>
@@ -224,8 +224,8 @@
224
224
 
225
225
  <script src="/builders/dom-utils.js?v=2026-10-25-escape"></script>
226
226
  <script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
227
- <script src="/builders/craft-mode.js?v=2026-11-04-money"></script>
228
- <script src="/builders/shell.js?v=2026-11-04-money"></script>
227
+ <script src="/builders/craft-mode.js?v=2026-11-05-sections"></script>
228
+ <script src="/builders/shell.js?v=2026-11-05-sections"></script>
229
229
  <script src="/builders/palette.js" defer></script>
230
230
  <!-- The kit, for its ONE renderer: the full-size ship-time visual figure
231
231
  (task 1003829), which the older reviews still show. -->
@@ -58,8 +58,8 @@
58
58
  time so the chrome exists before the deferred page scripts execute. -->
59
59
  <script src="/builders/dom-utils.js?v=2026-10-25-escape"></script>
60
60
  <script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
61
- <script src="/builders/craft-mode.js?v=2026-11-04-money"></script>
62
- <script src="/builders/shell.js?v=2026-11-04-money"></script>
61
+ <script src="/builders/craft-mode.js?v=2026-11-05-sections"></script>
62
+ <script src="/builders/shell.js?v=2026-11-05-sections"></script>
63
63
  <!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
64
64
  <script src="/builders/palette.js" defer></script>
65
65
  <!-- task-detail.js still owns the #/idea/N and #/blocker/N deep-link overlay
@@ -140,8 +140,8 @@
140
140
 
141
141
  <script src="/builders/dom-utils.js?v=2026-10-25-escape"></script>
142
142
  <script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
143
- <script src="/builders/craft-mode.js?v=2026-11-04-money"></script>
144
- <script src="/builders/shell.js?v=2026-11-04-money"></script>
143
+ <script src="/builders/craft-mode.js?v=2026-11-05-sections"></script>
144
+ <script src="/builders/shell.js?v=2026-11-05-sections"></script>
145
145
  <script src="/builders/palette.js" defer></script>
146
146
 
147
147
  <script src="/builders/idea-objects.js?v=2026-09-27-split"></script>
@@ -144,8 +144,8 @@
144
144
 
145
145
  <script src="/builders/dom-utils.js?v=2026-10-25-escape"></script>
146
146
  <script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
147
- <script src="/builders/craft-mode.js?v=2026-11-04-money"></script>
148
- <script src="/builders/shell.js?v=2026-11-04-money"></script>
147
+ <script src="/builders/craft-mode.js?v=2026-11-05-sections"></script>
148
+ <script src="/builders/shell.js?v=2026-11-05-sections"></script>
149
149
  <script src="/builders/palette.js" defer></script>
150
150
  <script src="/builders/brand-holes.js?v=2026-09-29-aqfix"></script>
151
151
  <script src="/builders/tweak-editor-lib.js?v=2026-09-29-tw27"></script>
@@ -167,8 +167,8 @@
167
167
  chrome exists before the page script runs. -->
168
168
  <script src="/builders/dom-utils.js?v=2026-10-25-escape"></script>
169
169
  <script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
170
- <script src="/builders/craft-mode.js?v=2026-11-04-money"></script>
171
- <script src="/builders/shell.js?v=2026-11-04-money"></script>
170
+ <script src="/builders/craft-mode.js?v=2026-11-05-sections"></script>
171
+ <script src="/builders/shell.js?v=2026-11-05-sections"></script>
172
172
  <!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
173
173
  <script src="/builders/palette.js" defer></script>
174
174
  <!-- shared component kit (window.OTBKit) — tabs, ledger, pager (task 2166). -->
@@ -173,8 +173,8 @@
173
173
  time so the chrome exists before the deferred page scripts execute. -->
174
174
  <script src="/builders/dom-utils.js?v=2026-10-25-escape"></script>
175
175
  <script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
176
- <script src="/builders/craft-mode.js?v=2026-11-04-money"></script>
177
- <script src="/builders/shell.js?v=2026-11-04-money"></script>
176
+ <script src="/builders/craft-mode.js?v=2026-11-05-sections"></script>
177
+ <script src="/builders/shell.js?v=2026-11-05-sections"></script>
178
178
  <!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
179
179
  <script src="/builders/palette.js" defer></script>
180
180
  <!-- task 1004727: the ONE karma vote control every task/idea list renders -->
package/package-lock.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@bongos/core",
3
- "version": "1.24.37",
3
+ "version": "1.24.38",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@bongos/core",
9
- "version": "1.24.37",
9
+ "version": "1.24.38",
10
10
  "license": "AGPL-3.0-or-later",
11
11
  "dependencies": {
12
12
  "express": "^4.21.2",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bongos/core",
3
- "version": "1.24.37",
3
+ "version": "1.24.38",
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",
@@ -11185,5 +11185,11 @@
11185
11185
  "id": "1005047",
11186
11186
  "text": "Owners now have one Money page in the Government group: what the project spent and paid out, its treasury, and what each hosted project costs, all in one place. Project settings and the Primer link to it instead of repeating t"
11187
11187
  }
11188
+ ],
11189
+ "1.24.38": [
11190
+ {
11191
+ "id": "1005071",
11192
+ "text": "The hall sidebar is now seven labelled sections (Work, Make, Community, You, Govern, Run the project, Help), and every craft can reach Help."
11193
+ }
11188
11194
  ]
11189
11195
  }
package/src/module-api.js CHANGED
@@ -81,7 +81,7 @@ const { sleep } = require('./sleep');
81
81
  // MAJOR (see allowBoxScope below): passes the request through untouched.
82
82
  function deprecatedNoopMiddleware(_req, _res, next) { next(); }
83
83
 
84
- const CORE_VERSION = '1.24.37'; // CI auto-patch carrier (ADR 0161); changelog: docs/module-api-changelog.md
84
+ const CORE_VERSION = '1.24.38'; // CI auto-patch carrier (ADR 0161); changelog: docs/module-api-changelog.md
85
85
 
86
86
  // A namespaced logger so a module's log lines are attributable + consistent.
87
87
  // Usage: const log = api.logger('discord'); log.info('mounted');
@@ -25,7 +25,7 @@ const CRAFT = read('craft-mode.js');
25
25
 
26
26
  // Every NAV id, and the Government group's, read from shell.js itself.
27
27
  const NAV_IDS = [...SHELL.matchAll(/\{ id: '([a-z-]+)', label:/g)].map((m) => m[1]);
28
- const GOV_BLOCK = SHELL.slice(SHELL.indexOf("{ group: 'Government'"));
28
+ const GOV_BLOCK = SHELL.slice(SHELL.indexOf("{ group: 'Run the project'"));
29
29
  const GOV_IDS = [...GOV_BLOCK.slice(0, GOV_BLOCK.indexOf('] }')).matchAll(/\{ id: '([a-z-]+)'/g)].map((m) => m[1]);
30
30
 
31
31
  // A small element. Elements parsed from the sidebar's markup are built ONCE, so
@@ -132,8 +132,9 @@ test('THE ALWAYS-PRESENT LIST: one shared list, Builders first, then Collab and
132
132
  const { craft } = boot();
133
133
  // task 1004685 (the living-city prototype): My agents joins as a PROPOSAL for the
134
134
  // owner — every craft has agents, and round-3 board 6 pairs it with the city.
135
- assert.deepEqual([...craft.ALWAYS_TABS], ['roster', 'collab', 'profile', 'my-agents'],
136
- 'Builders (NAV id roster) heads the list (owner, 2026-10-01); Collab and Profile join it (owner, 2026-10-03); My agents (prototype, task 1004685)');
135
+ // task 1005071 (owner, 2026-11-04): Help — the old Docs group — joins, so every craft has the Primer.
136
+ assert.deepEqual([...craft.ALWAYS_TABS], ['roster', 'collab', 'profile', 'my-agents', 'primer', 'commands', 'atlas', 'modules', 'apidocs'],
137
+ 'Builders (NAV id roster) heads the list (owner, 2026-10-01); Collab and Profile join it (owner, 2026-10-03); My agents (prototype, task 1004685); Help (task 1005071)');
137
138
  for (const m of CRAFTS) {
138
139
  const tabs = craft.tabsFor(m);
139
140
  assert.ok(Array.isArray(tabs), `${m} has a named tab list`);
@@ -180,7 +181,7 @@ test('each mode shows its own tabs, and switching updates the nav live', () => {
180
181
  assert.equal(p.root.dataset.craft, m);
181
182
  assert.deepEqual(new Set(p.showing()), new Set(p.craft.tabsFor(m)), `${m} shows exactly its list`);
182
183
  for (const id of ['roster', 'collab', 'profile']) assert.ok(p.showing().includes(id), `${id} stays in ${m}`);
183
- assert.equal(p.headShowing('government'), m === 'governing', `the Government head shows only where its tabs do (${m})`);
184
+ assert.equal(p.headShowing('run-the-project'), m === 'governing', `the Government head shows only where its tabs do (${m})`);
184
185
  }
185
186
  p.craft.choose('building');
186
187
  assert.deepEqual(new Set(p.showing()), new Set(p.craft.tabsFor('building')), 'back to Building, its tabs return without a reload');
@@ -190,11 +191,12 @@ test('a mode never shows a tab the gate hid, and a later gate pass keeps the mod
190
191
  const p = boot({ session: { 'hall-craft': 'governing' } });
191
192
  p.signIn('thetes');
192
193
  assert.ok(!p.showing().includes('watch'), 'a thetes in Governing does not get the metic-floored Watch tab');
193
- assert.ok(!p.headShowing('government'), 'nor its group head');
194
- assert.deepEqual(p.showing(), ['blockers', 'board-room', 'city', 'profile', 'my-agents', 'collab', 'roster'], 'what a thetes board member in Governing sees');
194
+ assert.ok(!p.headShowing('run-the-project'), 'nor its group head');
195
+ // task 1005071: sidebar order — Work, Community, You, Govern, then Help (every craft).
196
+ assert.deepEqual(p.showing(), ['blockers', 'collab', 'roster', 'profile', 'my-agents', 'city', 'board-room', 'primer', 'commands', 'atlas', 'modules', 'apidocs'], 'what a thetes board member in Governing sees');
195
197
  p.signIn('archon');
196
198
  assert.ok(p.showing().includes('watch'), 'promoted, the gate lets it through and the mode keeps it');
197
- assert.ok(p.headShowing('government'), 'and its group head comes back with it, which only a mode pass after the gate can know');
199
+ assert.ok(p.headShowing('run-the-project'), 'and its group head comes back with it, which only a mode pass after the gate can know');
198
200
  assert.ok(!p.showing().includes('work'), 'and the gate pass did not bring back a tab the mode left out');
199
201
  });
200
202
 
@@ -257,9 +259,9 @@ function bootTree({ mode = null, activeId = null } = {}) {
257
259
  let into = group;
258
260
  if (label) {
259
261
  const head = el('BUTTON', 'nav-group__head');
260
- head.dataset.group = label.toLowerCase();
262
+ head.dataset.group = label.toLowerCase().replace(/\s+/g, '-');
261
263
  group.appendChild(head);
262
- into = group.appendChild(el('DIV', 'nav-items', 'nav-items-' + label.toLowerCase()));
264
+ into = group.appendChild(el('DIV', 'nav-items', 'nav-items-' + label.toLowerCase().replace(/\s+/g, '-')));
263
265
  }
264
266
  for (const m of block.matchAll(/\{ id: '([a-z-]+)', label:/g)) {
265
267
  into.appendChild(el('A', 'nav-item' + (m[1] === activeId ? ' nav-item--active' : ''), 'nav-' + m[1]));
@@ -306,7 +308,7 @@ test('GOVERNING LEADS WITH THE CITY: its other tabs fold into one dropdown right
306
308
  assert.equal(head.getAttribute('aria-controls'), 'nav-items-craft-fold', 'the head names the region it opens');
307
309
  assert.match(head.innerHTML, /More governing/);
308
310
  assert.ok(head.hasAttribute('data-craft-off') === false, 'its head shows while a tab inside does');
309
- assert.ok(p.sidebar.querySelectorAll('.nav-group__head').find((h) => h.dataset.group === 'government').hasAttribute('data-craft-off'),
311
+ assert.ok(p.sidebar.querySelectorAll('.nav-group__head').find((h) => h.dataset.group === 'run-the-project').hasAttribute('data-craft-off'),
310
312
  'the emptied Government head hides, so no label sits over nothing');
311
313
  p.craft.choose('building');
312
314
  assert.equal(p.fold(), null, 'leaving Governing removes the dropdown');
@@ -415,8 +415,11 @@ await test('Sky sits directly under Goals in the nav, member-gated, at the URL G
415
415
  const shell = read('shell.js');
416
416
  const item = shell.indexOf("{ id: 'goal-map', label: 'Sky', icon: 'sky', href: '/goal-map', gate: 'member' }");
417
417
  assert.ok(item > -1, 'the nav item, with the slot the map was denied (ADR 0227 §11)');
418
- const goals = shell.indexOf("{ id: 'goals', label: 'Goals'"); const work = shell.indexOf("{ id: 'work', label: 'Tasks'");
419
- assert.ok(goals > -1 && goals < item && item < work, 'under Goals, above Tasks');
418
+ // task 1005071 moved Tasks up to second in Work (owner, 2026-11-04); Sky stays the
419
+ // item straight after Goals.
420
+ const goals = shell.indexOf("{ id: 'goals', label: 'Goals'");
421
+ const between = shell.slice(goals, item);
422
+ assert.ok(goals > -1 && goals < item && (between.match(/\{ id: '/g) || []).length === 1, 'directly under Goals');
420
423
  assert.match(read('goals.html'), /href="\/builders\/goal-map"/, 'Goals still links to it');
421
424
  });
422
425