@bongos/core 1.21.42 → 1.21.43

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 (52) hide show
  1. package/.bongos-core.json +56 -56
  2. package/docs/copy-inventory.md +10 -11
  3. package/docs/copy-registry.json +11 -20
  4. package/docs/design/craft-mode-direction.md +1 -1
  5. package/docs/module-api-changelog.md +2 -0
  6. package/docs/page-readings.json +3465 -3532
  7. package/modules/hall-ui/public/atlas.html +3 -3
  8. package/modules/hall-ui/public/blockers.html +3 -3
  9. package/modules/hall-ui/public/board-room.html +3 -3
  10. package/modules/hall-ui/public/city.html +3 -3
  11. package/modules/hall-ui/public/collab.html +3 -3
  12. package/modules/hall-ui/public/commands.html +3 -3
  13. package/modules/hall-ui/public/copy-desk.html +3 -3
  14. package/modules/hall-ui/public/craft-mode.js +10 -15
  15. package/modules/hall-ui/public/deploy.html +3 -3
  16. package/modules/hall-ui/public/diagrams.html +3 -3
  17. package/modules/hall-ui/public/drachmae.html +3 -3
  18. package/modules/hall-ui/public/fleet.html +3 -3
  19. package/modules/hall-ui/public/gate.html +3 -3
  20. package/modules/hall-ui/public/goal-map.html +3 -3
  21. package/modules/hall-ui/public/goals.html +3 -3
  22. package/modules/hall-ui/public/government.html +3 -3
  23. package/modules/hall-ui/public/idea.html +3 -3
  24. package/modules/hall-ui/public/ideas.html +3 -3
  25. package/modules/hall-ui/public/index.html +3 -3
  26. package/modules/hall-ui/public/modules.html +3 -3
  27. package/modules/hall-ui/public/primer.html +3 -3
  28. package/modules/hall-ui/public/profile.html +3 -3
  29. package/modules/hall-ui/public/project-settings.html +3 -3
  30. package/modules/hall-ui/public/ranks.html +3 -3
  31. package/modules/hall-ui/public/roadmap.html +3 -3
  32. package/modules/hall-ui/public/roster.html +3 -3
  33. package/modules/hall-ui/public/sessions.html +3 -3
  34. package/modules/hall-ui/public/settings.html +3 -3
  35. package/modules/hall-ui/public/street.html +3 -3
  36. package/modules/hall-ui/public/studio.html +3 -3
  37. package/modules/hall-ui/public/style.css +4 -22
  38. package/modules/hall-ui/public/task.html +3 -3
  39. package/modules/hall-ui/public/thinking.html +3 -3
  40. package/modules/hall-ui/public/tweak-editor.html +3 -3
  41. package/modules/hall-ui/public/watch.html +3 -3
  42. package/modules/hall-ui/public/work.html +3 -3
  43. package/modules/hall-ui/records/craft-mode.md +5 -5
  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.mjs +27 -10
  49. package/tests/craft_mode_looks.mjs +5 -5
  50. package/tests/craft_mode_nav.mjs +7 -7
  51. package/tests/hall_tweak_editor.mjs +1 -1
  52. package/tests/page_notes_panel.mjs +1 -1
@@ -142,9 +142,9 @@
142
142
 
143
143
  <div id="toast" class="toast" role="status" aria-live="polite" data-visible="0"></div>
144
144
 
145
- <script src="/builders/shell-trail.js?v=2026-10-04-palette"></script>
146
- <script src="/builders/craft-mode.js?v=2026-10-04-palette"></script>
147
- <script src="/builders/shell.js?v=2026-10-04-palette"></script>
145
+ <script src="/builders/shell-trail.js?v=2026-10-04-nolegacy"></script>
146
+ <script src="/builders/craft-mode.js?v=2026-10-04-nolegacy"></script>
147
+ <script src="/builders/shell.js?v=2026-10-04-nolegacy"></script>
148
148
  <script src="/builders/palette.js" defer></script>
149
149
  <script src="/builders/dom-utils.js?v=2026-06-23-contrib"></script>
150
150
  <script src="/builders/brand-holes.js?v=2026-09-29-aqfix"></script>
@@ -162,9 +162,9 @@
162
162
 
163
163
  <!-- The app shell (sidebar + top bar). Dependency-free; loaded FIRST so the
164
164
  chrome exists before the page script runs. -->
165
- <script src="/builders/shell-trail.js?v=2026-10-04-palette"></script>
166
- <script src="/builders/craft-mode.js?v=2026-10-04-palette"></script>
167
- <script src="/builders/shell.js?v=2026-10-04-palette"></script>
165
+ <script src="/builders/shell-trail.js?v=2026-10-04-nolegacy"></script>
166
+ <script src="/builders/craft-mode.js?v=2026-10-04-nolegacy"></script>
167
+ <script src="/builders/shell.js?v=2026-10-04-nolegacy"></script>
168
168
  <!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
169
169
  <script src="/builders/palette.js" defer></script>
170
170
  <!-- shared frontend toolkit (window.OTB) — loaded before watch.js, which pulls from it. -->
@@ -171,9 +171,9 @@
171
171
 
172
172
  <!-- The app shell (sidebar + top bar + footer). Dependency-free; runs at parse
173
173
  time so the chrome exists before the deferred page scripts execute. -->
174
- <script src="/builders/shell-trail.js?v=2026-10-04-palette"></script>
175
- <script src="/builders/craft-mode.js?v=2026-10-04-palette"></script>
176
- <script src="/builders/shell.js?v=2026-10-04-palette"></script>
174
+ <script src="/builders/shell-trail.js?v=2026-10-04-nolegacy"></script>
175
+ <script src="/builders/craft-mode.js?v=2026-10-04-nolegacy"></script>
176
+ <script src="/builders/shell.js?v=2026-10-04-nolegacy"></script>
177
177
  <!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
178
178
  <script src="/builders/palette.js" defer></script>
179
179
  <!-- shared frontend toolkit (window.OTB) — loaded FIRST so work.js can pull from it. -->
@@ -4,9 +4,9 @@ Covers: every shelled hall page (`craft-mode.js`, `shell.js`, `style.css`), and
4
4
 
5
5
  ## What it is
6
6
 
7
- - On entering the hall, once per browser session, a signed-in builder is asked **"What are you doing now?"**: Building, Artistry, Ideating, Governing, or **Legacy mode** (the owner's fifth choice, 2026-10-01: the hall exactly as it was). The approved prototype is the design canvas linked on the task; the doors carry its four scenes (the work desk, the night room, the sky, the governor city).
8
- - The answer is ONE attribute, `html[data-craft="building|artistry|ideating|governing|legacy"]`, readable by every hall page. Every change also fires `otb:craft` on `document` with `{ detail: { mode } }`, so a page can react without polling.
9
- - The top bar carries a switch with all five; pressing one changes the mode without a reload. Under 1180px it drops the words; at phone width only the current mode shows (or a "Choose your mode" button when there is none), and tapping it opens the picker.
7
+ - On entering the hall, once per browser session, a signed-in builder is asked **"What are you doing now?"**: Building, Artistry, Ideating or Governing. A fifth choice, **Legacy mode** (2026-10-01: the hall exactly as it was), was removed in task 1004567 (owner, 2026-10-04: "builder has all those tabs anyways"); a browser that still has `legacy` stored reads it as no mode, because `valid()` ignores any id that is not a mode. The approved prototype is the design canvas linked on the task; the doors carry its four scenes (the work desk, the night room, the sky, the governor city).
8
+ - The answer is ONE attribute, `html[data-craft="building|artistry|ideating|governing"]`, readable by every hall page. Every change also fires `otb:craft` on `document` with `{ detail: { mode } }`, so a page can react without polling.
9
+ - The top bar carries a switch with all four; pressing one changes the mode without a reload. Under 1180px it drops the words; at phone width only the current mode shows (or a "Choose your mode" button when there is none), and tapping it opens the picker.
10
10
  - Artistry is pre-selected for a builder whose `main_discipline` is `artist` (or, with no main role, whose first craft is).
11
11
 
12
12
  ## The rules an edit here must keep
@@ -23,14 +23,14 @@ Covers: every shelled hall page (`craft-mode.js`, `shell.js`, `style.css`), and
23
23
 
24
24
  ## The nav follows the mode (task 1004493)
25
25
 
26
- - **Each craft has a named tab list**, `MODE_TABS` in `craft-mode.js`, by NAV id. `ALWAYS_TABS` is the owner's list of tabs no mode may hide (2026-10-01: Builders, NAV id `roster`, first), and every mode's list is `ALWAYS_TABS` plus its own. Legacy and no mode have no entry, so they show every tab, as before.
26
+ - **Each craft has a named tab list**, `MODE_TABS` in `craft-mode.js`, by NAV id. `ALWAYS_TABS` is the owner's list of tabs no mode may hide (2026-10-01: Builders, NAV id `roster`, first), and every mode's list is `ALWAYS_TABS` plus its own. No mode has no entry, so it shows every tab, as before.
27
27
  - **Government shows only in Governing**, and outside that group Governing is the shortest list (Blockers, Board Room). Building is every tab except Government and the Board Room; Artistry is Studio, Goals, Your thinking; Ideating is Sky, Your thinking, Goals. The prototype names rooms that do not exist yet (Store, Page reviews, Treasury); a list names only real NAV items, and `tests/craft_mode_nav.mjs` requires every NAV item to sit in some mode.
28
28
  - **The mode only ever takes away, and never through `hidden`.** The access gate owns `hidden`; `applyNav()` marks what the mode leaves out with `[data-craft-off]`, which `style.css` hides. So a mode can never show a tab the gate hid, and switching mode just moves the attribute. A group head goes too once nothing under it shows.
29
29
  - **Two callers.** `apply()` runs it on every mode change (live, no reload), and `shell.js` `applyAccess` runs it right after its gate loop, so a later `/me` answer (a promotion, a permission) brings a head back with its tabs. Hidden tabs still open by their URL; nothing is enforced (ADR 0016).
30
30
 
31
31
  ## Each mode's look (task 1004495)
32
32
 
33
- - **Three modes wear a look; Building, Legacy and no mode wear none.** Artistry, Ideating and Governing each set `--craft` (where you are) and `--craft-on` (text on it) on `html[data-craft="<mode>"]`, with a dark twin on `html[data-theme="dark"][data-craft="<mode>"]` that also darkens the ground and tints the glass (Artistry, Ideating). Values and contrast are the direction's, `docs/design/craft-mode-direction.md`. No rule in `style.css` names `building` or `legacy`, and none matches any mode at all; `tests/craft_mode_looks.mjs` pins both, and re-measures every colour pair.
33
+ - **Three modes wear a look; Building and no mode wear none.** Artistry, Ideating and Governing each set `--craft` (where you are) and `--craft-on` (text on it) on `html[data-craft="<mode>"]`, with a dark twin on `html[data-theme="dark"][data-craft="<mode>"]` that also darkens the ground and tints the glass (Artistry, Ideating). Values and contrast are the direction's, `docs/design/craft-mode-direction.md`. No rule in `style.css` names `building`, and none matches any mode at all; `tests/craft_mode_looks.mjs` pins both, and re-measures every colour pair.
34
34
  - **The accent stays the action colour.** `--craft` paints only the switch's current pill, the current tab (tint, icon, label, marker) and the top bar's hairline.
35
35
  - **Two pieces are drawn by `craft-mode.js` `applyLook()`, on every mode change:** the eyebrow beside `#topbar-title` (`LOOKS`: "the studio · night", "the sky", "the city"; hidden at <=640px, where it overflowed phones) and the scene plate under `.app-sidebar__brand` (40px closed rail, 64px open). The plate's markup IS `artHtml(mode)`, the picker's door art, exported rather than copied; light mode recolours it to each scene's day (the city is the dark one through `invert(1) hue-rotate(180deg)`). It does not animate.
36
36
  - **Always-present tabs widened** (owner, 2026-10-03): `ALWAYS_TABS` is Builders, Collab and Profile, so every mode keeps the You and Community groups.
package/package-lock.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@bongos/core",
3
- "version": "1.21.42",
3
+ "version": "1.21.43",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@bongos/core",
9
- "version": "1.21.42",
9
+ "version": "1.21.43",
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.21.42",
3
+ "version": "1.21.43",
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",
@@ -9016,5 +9016,11 @@
9016
9016
  "id": "1004568",
9017
9017
  "text": "Street cards are now only as tall as their words need. Long titles, reasons and lines are cut short with an ellipsis at a whole word, and the full text is one tap away under \"more\". The automation card no longer stretches: its"
9018
9018
  }
9019
+ ],
9020
+ "1.21.43": [
9021
+ {
9022
+ "id": "1004567",
9023
+ "text": "Legacy mode is gone from the builders hall. The mode picker now offers four doors (Building, Artistry, Ideating, Governing) and the top-bar switch shows those four. Anyone who still had Legacy saved simply lands with no mode c"
9024
+ }
9019
9025
  ]
9020
9026
  }
package/src/module-api.js CHANGED
@@ -75,7 +75,7 @@ const { responsibilityFor, ROLE_RESPONSIBILITIES } = require('./role-responsibil
75
75
  // MAJOR (see allowBoxScope below): passes the request through untouched.
76
76
  function deprecatedNoopMiddleware(_req, _res, next) { next(); }
77
77
 
78
- const CORE_VERSION = '1.21.42'; // CI auto-patch carrier (ADR 0161); changelog: docs/module-api-changelog.md
78
+ const CORE_VERSION = '1.21.43'; // CI auto-patch carrier (ADR 0161); changelog: docs/module-api-changelog.md
79
79
 
80
80
  // A namespaced logger so a module's log lines are attributable + consistent.
81
81
  // Usage: const log = api.logger('discord'); log.info('mounted');
@@ -1,7 +1,7 @@
1
1
  // tests/craft_mode.mjs — the hall's craft mode picker (task 1004492, goal 1000095 WA6).
2
2
  //
3
3
  // On entering the hall a picker asks once per session "What are you doing
4
- // now?" (Building, Artistry, Ideating, Governing, or Legacy mode); the answer is
4
+ // now?" (Building, Artistry, Ideating or Governing); the answer is
5
5
  // html[data-craft], and a switch in the top bar changes it without a reload.
6
6
  // These cases boot the REAL shell-trail.js + craft-mode.js + shell.js in a DOM
7
7
  // stub, in the order every hall page loads them, and drive them the way a
@@ -142,7 +142,7 @@ function boot({ craft = true, session = {}, store = {}, throws = false, optOut =
142
142
  picker,
143
143
  signIn: (builder = { id: 7, rank: 'thetes' }) => shell.applyAccess({ authed: true, rank: builder.rank, builder }),
144
144
  signOut: () => shell.applyAccess({ authed: false }),
145
- // Press a picker button: a door, Legacy, or the close button.
145
+ // Press a picker button: a door or the close button.
146
146
  pick(attr, value, { askAgain = true } = {}) {
147
147
  const p = picker();
148
148
  const box = p.querySelector('[data-craft-again]');
@@ -161,7 +161,7 @@ function boot({ craft = true, session = {}, store = {}, throws = false, optOut =
161
161
  };
162
162
  }
163
163
 
164
- const MODES = ['building', 'artistry', 'ideating', 'governing', 'legacy'];
164
+ const MODES = ['building', 'artistry', 'ideating', 'governing'];
165
165
  const noSwitch = (html) => html.replace(/<div class="craft-switch[\s\S]*?<\/div>/, '');
166
166
 
167
167
  test('NO MODE IS THE HALL AS TODAY: with no mode chosen, nothing but the switch differs from a hall without craft modes', () => {
@@ -184,7 +184,8 @@ test('a signed-in builder is asked ONCE per session, and a reload does not ask a
184
184
  assert.match(html, /role="dialog" aria-modal="true"/);
185
185
  assert.match(html, /What are you doing now\?/);
186
186
  for (const m of ['building', 'artistry', 'ideating', 'governing']) assert.match(html, new RegExp(`data-craft-pick="${m}"`), `a ${m} door`);
187
- assert.match(html, /data-craft-pick="legacy"[^>]*>Legacy mode/, 'Legacy mode is the fifth choice (owner, 2026-10-01)');
187
+ assert.equal([...html.matchAll(/data-craft-pick="/g)].length, 4, 'four doors and nothing else to pick');
188
+ assert.doesNotMatch(html, /legacy/i, 'Legacy mode is gone (owner, 2026-10-04: Building has all those tabs anyway)');
188
189
  p.escape();
189
190
  assert.equal(p.picker(), null, 'Escape closes it without choosing');
190
191
  assert.equal(p.mode(), undefined, 'and leaves the hall with no mode');
@@ -229,17 +230,33 @@ test('unticking "Ask me again next session" keeps the mode for later sessions',
229
230
  assert.equal(tomorrow.picker(), null, 'and nobody is asked');
230
231
  });
231
232
 
232
- test('THE HEADER SWITCH changes the mode without a reload, and offers all five', () => {
233
+ test('THE HEADER SWITCH changes the mode without a reload, and offers the four crafts', () => {
233
234
  const p = boot();
234
235
  const opts = [...p.topbar.innerHTML.matchAll(/data-craft-opt="([a-z]+)"/g)].map((m) => m[1]);
235
- assert.deepEqual(opts, MODES, 'the four crafts, then Legacy');
236
+ assert.deepEqual(opts, MODES, 'the four crafts, and no Legacy');
236
237
  p.press('artistry');
237
238
  assert.equal(p.mode(), 'artistry');
238
- p.press('legacy');
239
- assert.equal(p.mode(), 'legacy', 'anyone can go back to the old view at any time');
240
- assert.deepEqual(p.pressed(), ['legacy']);
239
+ p.press('building');
240
+ assert.equal(p.mode(), 'building', 'anyone can switch at any time');
241
+ assert.deepEqual(p.pressed(), ['building']);
241
242
  assert.equal(p.location.reloads, 0, 'no navigation happened');
242
- assert.equal(p.session['hall-craft'], 'legacy', 'and the session remembers it');
243
+ assert.equal(p.session['hall-craft'], 'building', 'and the session remembers it');
244
+ });
245
+
246
+ test('a browser that still has Legacy stored falls back to NO MODE (task 1004567)', () => {
247
+ const session = { 'hall-craft': 'legacy', 'hall-craft-asked': '1' };
248
+ const store = { 'hall-craft-keep': 'legacy' };
249
+ const p = boot({ session, store });
250
+ p.signIn();
251
+ assert.equal(p.mode(), undefined, 'no html[data-craft]: the hall with every tab');
252
+ assert.deepEqual(p.pressed(), [], 'no switch option lit');
253
+ assert.equal(p.picker(), null, 'this session already saw the picker, so it is not asked again');
254
+ const kept = boot({ store });
255
+ kept.signIn();
256
+ assert.equal(kept.mode(), undefined, 'a kept Legacy from an earlier session is no mode too');
257
+ assert.ok(kept.picker(), 'and a new session is asked to pick one of the four');
258
+ p.press('building');
259
+ assert.equal(p.mode(), 'building', 'and any of the four can be chosen from there');
243
260
  });
244
261
 
245
262
  test('on a phone the switch shows only the current mode, and tapping it opens the picker', () => {
@@ -3,7 +3,7 @@
3
3
  //
4
4
  // Artistry, Ideating and Governing each wear a look: --craft / --craft-on tokens
5
5
  // (light + dark twins) in style.css, the header eyebrow beside the page title and
6
- // the door's scene framed under the brand. Building, Legacy and no mode wear
6
+ // the door's scene framed under the brand. Building and no mode wear
7
7
  // NOTHING — the hall as it always was. These cases run the REAL craft-mode.js over
8
8
  // a small DOM and read the REAL style.css, so a look that leaks into Building, a
9
9
  // plate that is a second copy of the art, or a colour that loses its contrast reds.
@@ -94,11 +94,11 @@ test('each looked mode frames its own door scene under the brand, and names itse
94
94
  }
95
95
  });
96
96
 
97
- test('BUILDING, LEGACY AND NO MODE WEAR NO LOOK: no plate, no eyebrow, and switching to them takes the look away', () => {
97
+ test('BUILDING AND NO MODE WEAR NO LOOK: no plate, no eyebrow, and switching to them takes the look away', () => {
98
98
  const none = boot();
99
99
  assert.equal(none.root.dataset.craft, undefined);
100
100
  assert.equal(none.plates().length + none.marks().length, 0, 'no mode draws nothing');
101
- for (const m of ['building', 'legacy']) {
101
+ for (const m of ['building']) {
102
102
  const p = boot({ 'hall-craft': m });
103
103
  assert.equal(p.plates().length + p.marks().length, 0, `${m} at boot draws nothing`);
104
104
  p.craft.choose('governing');
@@ -118,10 +118,10 @@ test('the art is drawn once: craft-mode.js has one artHtml and exports it', () =
118
118
  // Every selector in style.css that names a craft mode.
119
119
  const CRAFT_SELECTORS = [...CSS.matchAll(/data-craft="([a-z]+)"/g)].map((m) => m[1]);
120
120
 
121
- test('style.css names only the three looked modes — Building and Legacy have no rule at all', () => {
121
+ test('style.css names only the three looked modes — Building has no rule at all', () => {
122
122
  assert.ok(CRAFT_SELECTORS.length >= 12, `found ${CRAFT_SELECTORS.length} craft selectors`);
123
123
  for (const m of CRAFT_SELECTORS) assert.ok(LOOKED.includes(m), `a rule names data-craft="${m}"`);
124
- assert.doesNotMatch(CSS, /data-craft="(building|legacy)"/);
124
+ assert.doesNotMatch(CSS, /data-craft="building"/);
125
125
  assert.doesNotMatch(CSS, /data-craft\]/, 'no rule matches ANY mode, which would dress Building too');
126
126
  });
127
127
 
@@ -1,8 +1,8 @@
1
1
  // tests/craft_mode_nav.mjs — the hall nav follows the craft mode (task 1004493,
2
2
  // goal 1000095 WA6).
3
3
  //
4
- // Each craft mode shows only the tabs its craft needs; Legacy mode and no mode
5
- // show every tab, exactly as before. The owner's rule (2026-10-01): some tabs
4
+ // Each craft mode shows only the tabs its craft needs; no mode
5
+ // shows every tab, exactly as before. The owner's rule (2026-10-01): some tabs
6
6
  // stay in EVERY mode, Builders first among them, written down as ONE shared list
7
7
  // that each mode's list adds to; on 2026-10-03 Collab and Profile joined it. These cases boot the REAL shell-trail.js +
8
8
  // craft-mode.js + shell.js and read the sidebar the shell actually rendered, so a
@@ -157,15 +157,15 @@ test('Government shows only in Governing, and Governing is the shortest list', (
157
157
  assert.equal(Math.min(...lengths), lengths[CRAFTS.indexOf('governing')], 'outside its own Government group, Governing shows the fewest tabs');
158
158
  });
159
159
 
160
- test('NO MODE AND LEGACY ARE TODAY\'S NAV: every tab the gate allows, nothing marked', () => {
160
+ test('NO MODE IS TODAY\'S NAV: every tab the gate allows, nothing marked — and a stored Legacy is no mode', () => {
161
161
  const none = boot();
162
162
  none.signIn();
163
163
  const all = none.showing();
164
164
  assert.deepEqual(all, NAV_IDS, 'an archon with no mode sees every tab');
165
165
  const legacy = boot({ session: { 'hall-craft': 'legacy' } });
166
166
  legacy.signIn();
167
- assert.deepEqual(legacy.showing(), all, 'Legacy mode shows exactly the same');
168
- assert.equal(legacy.craft.tabsFor('legacy'), null);
167
+ assert.equal(legacy.root.dataset.craft, undefined, 'Legacy was removed (task 1004567), so it reads as no mode');
168
+ assert.deepEqual(legacy.showing(), all, 'and shows exactly the same');
169
169
  });
170
170
 
171
171
  test('each mode shows its own tabs, and switching updates the nav live', () => {
@@ -178,8 +178,8 @@ test('each mode shows its own tabs, and switching updates the nav live', () => {
178
178
  for (const id of ['roster', 'collab', 'profile']) assert.ok(p.showing().includes(id), `${id} stays in ${m}`);
179
179
  assert.equal(p.headShowing('government'), m === 'governing', `the Government head shows only where its tabs do (${m})`);
180
180
  }
181
- p.craft.choose('legacy');
182
- assert.deepEqual(p.showing(), NAV_IDS, 'back to Legacy, every tab returns without a reload');
181
+ p.craft.choose('building');
182
+ assert.deepEqual(new Set(p.showing()), new Set(p.craft.tabsFor('building')), 'back to Building, its tabs return without a reload');
183
183
  });
184
184
 
185
185
  test('a mode never shows a tab the gate hid, and a later gate pass keeps the mode', () => {
@@ -635,7 +635,7 @@ try {
635
635
  assert.match(HTML, /<body data-page="tweak-editor"[^>]*data-fullscreen-switch/);
636
636
  assert.equal((HTML.match(/<h1\b/g) || []).length, 1);
637
637
  assert.ok(HTML.indexOf('tweak-editor-lib.js') < HTML.indexOf('tweak-editor.js?'), 'the lib loads first');
638
- assert.match(HTML, /shell\.js\?v=2026-10-04-palette/);
638
+ assert.match(HTML, /shell\.js\?v=2026-10-04-nolegacy/);
639
639
  assert.equal(/fonts\.googleapis\.com\/css/.test(HTML), false);
640
640
  for (const id of ['tw-bar', 'tw-counter', 'tw-open', 'tw-open-more', 'tw-divider', 'tw-openwrap', 'tw-open-menu', 'tw-open-tab', 'tw-open-split', 'tw-frame', 'tw-frame-view', 'tw-split-close', 'tw-download', 'tw-upload', 'tw-file', 'tw-submit', 'tw-paper', 'tw-doc', 'tw-notice', 'tw-done', 'tw-take', 'tw-pick', 'tw-picks', 'tw-refused', 'tw-refused-title', 'tw-refused-list', 'tw-refused-next', 'tw-refused-download', 'tw-refused-close']) {
641
641
  assert.ok(new RegExp(`id="${id}"`).test(HTML), `#${id} is in the markup`);
@@ -79,7 +79,7 @@ test('THE PALETTE: in the top bar in Artistry alone, right before the switch, an
79
79
  assert.deepEqual(p.tools().map((t) => t.id), ['craft-tool-palette']);
80
80
  assert.equal(p.tools()[0].nextSibling, p.sw, 'it sits right before the mode switch');
81
81
  assert.equal(p.tools()[0].getAttribute('aria-label'), 'Write feedback on this page');
82
- for (const m of ['building', 'ideating', 'governing', 'legacy']) {
82
+ for (const m of ['building', 'ideating', 'governing']) {
83
83
  p.craft.choose(m);
84
84
  assert.equal(p.tools().length, 0, `no palette in ${m}`);
85
85
  }