@bongos/core 1.24.43 → 1.24.44
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.
- package/.bongos-core.json +70 -75
- package/docs/copy-inventory.md +33 -65
- package/docs/copy-registry.json +78 -437
- package/docs/file-map.md +1 -1
- package/docs/module-api-changelog.md +2 -0
- package/docs/page-inventory.json +8 -36
- package/docs/page-readings.json +188 -245
- package/modules/hall-ui/public/ai-studio.html +2 -2
- package/modules/hall-ui/public/atlas.html +2 -2
- package/modules/hall-ui/public/blockers.html +2 -2
- package/modules/hall-ui/public/board-room.html +2 -2
- package/modules/hall-ui/public/city.html +2 -2
- package/modules/hall-ui/public/collab.html +2 -2
- package/modules/hall-ui/public/commands.html +2 -2
- package/modules/hall-ui/public/copy-desk.html +2 -2
- package/modules/hall-ui/public/craft-mode.js +1 -1
- package/modules/hall-ui/public/deploy.html +2 -2
- package/modules/hall-ui/public/goal-map.html +2 -2
- package/modules/hall-ui/public/goals.html +14 -2
- package/modules/hall-ui/public/government.html +2 -2
- package/modules/hall-ui/public/idea.html +2 -2
- package/modules/hall-ui/public/ideas.html +2 -2
- package/modules/hall-ui/public/index.html +2 -2
- package/modules/hall-ui/public/market-watch-item.html +2 -2
- package/modules/hall-ui/public/market-watch-rules.html +2 -2
- package/modules/hall-ui/public/market-watch.html +2 -2
- package/modules/hall-ui/public/modules.html +2 -2
- package/modules/hall-ui/public/money.html +2 -2
- package/modules/hall-ui/public/my-agents.html +2 -2
- package/modules/hall-ui/public/primer.html +2 -2
- package/modules/hall-ui/public/profile.html +2 -2
- package/modules/hall-ui/public/project-settings.html +2 -2
- package/modules/hall-ui/public/roadmap.css +7 -138
- package/modules/hall-ui/public/roadmap.js +35 -293
- package/modules/hall-ui/public/roster.html +2 -2
- package/modules/hall-ui/public/settings.html +2 -2
- package/modules/hall-ui/public/shell.js +3 -3
- package/modules/hall-ui/public/street.html +2 -2
- package/modules/hall-ui/public/studio.html +2 -2
- package/modules/hall-ui/public/task.html +2 -2
- package/modules/hall-ui/public/thinking.html +2 -2
- package/modules/hall-ui/public/tweak-editor.html +2 -2
- package/modules/hall-ui/public/watch.html +2 -2
- package/modules/hall-ui/public/work.html +3 -3
- package/modules/onboarding/founding-mode.js +2 -1
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/release-notes.json +6 -0
- package/scripts/bongos/gen-hall-sitemap.js +1 -0
- package/src/bongos/serve-internal.js +6 -6
- package/src/module-api.js +1 -1
- package/tests/craft_mode_nav.mjs +2 -1
- package/tests/founding_mode.mjs +5 -3
- package/tests/hall_goals_band.mjs +88 -0
- package/tests/hall_kit_charts.mjs +4 -3
- package/tests/hall_nav.mjs +5 -2
- package/tests/hall_page_gate_map.mjs +5 -1
- package/tests/hall_reading_world.mjs +17 -18
- package/tests/hall_sitemap.mjs +2 -1
- package/tests/nav_permission_atoms.mjs +3 -2
- package/modules/hall-ui/public/roadmap.html +0 -58
- package/modules/hall-ui/public/roadmap.states.json +0 -31
|
@@ -1039,10 +1039,10 @@ function mountInternalSurfaces(app) {
|
|
|
1039
1039
|
return res.redirect(302, `${isBuildersHost(req) ? '' : '/builders'}/market-watch${qs}#settings`);
|
|
1040
1040
|
});
|
|
1041
1041
|
|
|
1042
|
-
// Pages folded into
|
|
1043
|
-
//
|
|
1044
|
-
const RETIRED_TO_SECTION = Object.freeze({ fleet: 'money#hosting', sessions: 'watch#sessions', gate: 'watch#autobongos' });
|
|
1045
|
-
const RETIRED_SECTION_RE = /^\/builders\/(fleet|sessions|gate)(?:\.html)?\/?$/;
|
|
1042
|
+
// Pages folded into another page; 302 and no gate, as above. Task 1005047: Fleet costs is
|
|
1043
|
+
// /money#hosting; 1005049: Sessions and Autobongos are Watch tabs; 1005051: Roadmap is Goals'.
|
|
1044
|
+
const RETIRED_TO_SECTION = Object.freeze({ fleet: 'money#hosting', sessions: 'watch#sessions', gate: 'watch#autobongos', roadmap: 'goals' });
|
|
1045
|
+
const RETIRED_SECTION_RE = /^\/builders\/(fleet|sessions|gate|roadmap)(?:\.html)?\/?$/;
|
|
1046
1046
|
app.use((req, res, next) => {
|
|
1047
1047
|
if (isModuleSurfaceHost(req)) return next();
|
|
1048
1048
|
if (req.method !== 'GET' && req.method !== 'HEAD') return next();
|
|
@@ -1050,7 +1050,7 @@ function mountInternalSurfaces(app) {
|
|
|
1050
1050
|
if (!m) return next();
|
|
1051
1051
|
const qs = req.url.includes('?') ? req.url.slice(req.url.indexOf('?')) : '';
|
|
1052
1052
|
const [page, section] = RETIRED_TO_SECTION[m[1]].split('#');
|
|
1053
|
-
return res.redirect(302, `${isBuildersHost(req) ? '' : '/builders'}/${page}${qs}
|
|
1053
|
+
return res.redirect(302, `${isBuildersHost(req) ? '' : '/builders'}/${page}${qs}${section ? `#${section}` : ''}`);
|
|
1054
1054
|
});
|
|
1055
1055
|
|
|
1056
1056
|
// task 1005046 (owner decision 2026-11-03, idea 1001311): ONE reading room. Ranks,
|
|
@@ -1348,7 +1348,7 @@ function mountInternalSurfaces(app) {
|
|
|
1348
1348
|
// whole gate; the governing reads it adds are gated by their own routes.
|
|
1349
1349
|
// task 1004921 `ai-studio` (the viewer's own routes).
|
|
1350
1350
|
const SIGNEDIN_BUILDERS_PAGE_RE =
|
|
1351
|
-
/^\/builders\/(?:work|settings|atlas|modules|goals|goal-map|
|
|
1351
|
+
/^\/builders\/(?:work|settings|atlas|modules|goals|goal-map|copy-desk|studio|ai-studio|tweak-editor|ideas|thinking|collab|task|idea|primer(?:\.md)?|my-agents|commands)(?:\.html)?\/?$/;
|
|
1352
1352
|
// The diagram image assets under /builders/diagrams/ ride the same tier as the
|
|
1353
1353
|
// page that embeds them — the Primer, since task 1005046 retired the Diagrams
|
|
1354
1354
|
// page (its URL now 302s to the Primer's first diagram, above).
|
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.
|
|
84
|
+
const CORE_VERSION = '1.24.44'; // 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');
|
package/tests/craft_mode_nav.mjs
CHANGED
|
@@ -146,7 +146,8 @@ test('THE ALWAYS-PRESENT LIST: one shared list, Builders first, then Collab and
|
|
|
146
146
|
|
|
147
147
|
test('every tab a mode names is a real NAV item, and every NAV item lives in some mode', () => {
|
|
148
148
|
const { craft } = boot();
|
|
149
|
-
|
|
149
|
+
// 24 since task 1005051 folded the Roadmap into Goals (a sanity floor, not a count).
|
|
150
|
+
assert.ok(NAV_IDS.length >= 24, `read ${NAV_IDS.length} NAV ids from shell.js`);
|
|
150
151
|
const named = new Set(CRAFTS.flatMap((m) => craft.tabsFor(m)));
|
|
151
152
|
for (const id of named) assert.ok(NAV_IDS.includes(id), `${id} is a NAV id`);
|
|
152
153
|
for (const id of NAV_IDS) assert.ok(named.has(id), `${id} is reachable from some mode's nav`);
|
package/tests/founding_mode.mjs
CHANGED
|
@@ -43,14 +43,16 @@ test('active with no stage yet is the decide pre-stage, and every room sleeps',
|
|
|
43
43
|
assert.equal(f.stage, 'decide');
|
|
44
44
|
assert.equal(f.stage_number, 0);
|
|
45
45
|
assert.equal(f.stage_count, 5);
|
|
46
|
-
|
|
46
|
+
// task 1005051: Roadmap folded into Goals; scope wakes Goals and its map.
|
|
47
|
+
for (const id of ['goals', 'goal-map', 'work', 'board-room', 'collab', 'roster']) {
|
|
47
48
|
assert.ok(id in f.asleep, `${id} sleeps while deciding`);
|
|
48
49
|
}
|
|
49
50
|
});
|
|
50
51
|
|
|
51
52
|
test('a room wakes once the stage that wakes it is behind', () => {
|
|
52
53
|
const f = fm.shapeFoundingMode({ active: 'true', stage: 'charter' });
|
|
53
|
-
for (const id of ['
|
|
54
|
+
for (const id of ['goals', 'goal-map', 'work']) assert.ok(!(id in f.asleep), `${id} woke`);
|
|
55
|
+
assert.ok(!('roadmap' in f.asleep), 'the folded Roadmap is no room to wake');
|
|
54
56
|
assert.equal(f.asleep['board-room'], 'charter');
|
|
55
57
|
// task 1005046: Economy and Ranks were the rooms legalize and legislation woke;
|
|
56
58
|
// they are Primer chapters now, and the Primer never sleeps.
|
|
@@ -121,7 +123,7 @@ class El {
|
|
|
121
123
|
}
|
|
122
124
|
|
|
123
125
|
function makeHall() {
|
|
124
|
-
const navIds = ['home', '
|
|
126
|
+
const navIds = ['home', 'goals', 'goal-map', 'work', 'board-room', 'collab', 'roster', 'profile'];
|
|
125
127
|
const nav = navIds.map((id) => { const a = new El('a'); a.id = 'nav-' + id; a.className = 'nav-item'; return a; });
|
|
126
128
|
const appBody = new El('div');
|
|
127
129
|
const topbar = new El('header'); topbar.id = 'app-topbar';
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
// tests/hall_goals_band.mjs — Roadmap folds into Goals (task 1005051, owner
|
|
2
|
+
// decision 2026-11-03, idea 1001315 item 4).
|
|
3
|
+
//
|
|
4
|
+
// Since one version is built at a time (task 1004821) the Roadmap page mostly
|
|
5
|
+
// repeated Goals. Goals now opens with the version's progress and the timeline:
|
|
6
|
+
//
|
|
7
|
+
// * THE BAND. goals.html carries #rm-root at the top of its list view, with
|
|
8
|
+
// roadmap.css, roadmap-timeline.js (still the drawing) and roadmap.js.
|
|
9
|
+
// * OLD LINKS LAND ON GOALS. /roadmap 302s to /goals (serve-internal.js
|
|
10
|
+
// RETIRED_TO_SECTION), query kept; the real middleware runs here.
|
|
11
|
+
// * NOTHING POINTS AT IT. No nav item, no Governing/Building tab, no founding
|
|
12
|
+
// room, and the Tasks board's "see the version" line names Goals.
|
|
13
|
+
//
|
|
14
|
+
// The band's own rendering (the timeline glue, a missing module, an undated
|
|
15
|
+
// version) is run in tests/hall_reading_world.mjs bootRoadmap.
|
|
16
|
+
//
|
|
17
|
+
// Run: node tests/hall_goals_band.mjs
|
|
18
|
+
|
|
19
|
+
import { test } from 'node:test';
|
|
20
|
+
import assert from 'node:assert/strict';
|
|
21
|
+
import fs from 'node:fs';
|
|
22
|
+
import http from 'node:http';
|
|
23
|
+
import path from 'node:path';
|
|
24
|
+
import { createRequire } from 'node:module';
|
|
25
|
+
import { fileURLToPath } from 'node:url';
|
|
26
|
+
|
|
27
|
+
const require = createRequire(import.meta.url);
|
|
28
|
+
const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
|
29
|
+
const HALL = path.join(ROOT, 'modules', 'hall-ui', 'public');
|
|
30
|
+
const read = (f) => fs.readFileSync(path.join(HALL, f), 'utf8');
|
|
31
|
+
|
|
32
|
+
async function withHall(fn) {
|
|
33
|
+
const express = require('express');
|
|
34
|
+
const { mountInternalSurfaces } = require('../src/bongos/serve-internal.js');
|
|
35
|
+
const app = express();
|
|
36
|
+
mountInternalSurfaces(app);
|
|
37
|
+
const server = app.listen(0, '127.0.0.1');
|
|
38
|
+
await new Promise((r) => server.once('listening', r));
|
|
39
|
+
const { port } = server.address();
|
|
40
|
+
const get = (p, host) => new Promise((resolve, reject) => {
|
|
41
|
+
http.get({ host: '127.0.0.1', port, path: p, headers: { host } }, (res) => {
|
|
42
|
+
res.resume();
|
|
43
|
+
res.on('end', () => resolve({ status: res.statusCode, location: res.headers.location || '' }));
|
|
44
|
+
}).on('error', reject);
|
|
45
|
+
});
|
|
46
|
+
try { await fn(get); } finally { server.close(); }
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
test('RUN: /roadmap 302s to /goals, in every spelling, with its query', async () => {
|
|
50
|
+
await withHall(async (get) => {
|
|
51
|
+
for (const form of ['/roadmap', '/roadmap/', '/roadmap.html']) {
|
|
52
|
+
const r = await get(form, 'builders.127.0.0.1');
|
|
53
|
+
assert.equal(r.status, 302, `${form} is a temporary redirect`);
|
|
54
|
+
assert.equal(r.location, '/goals', `${form} lands on Goals, with no stray fragment`);
|
|
55
|
+
}
|
|
56
|
+
assert.equal((await get('/roadmap?from=mail', 'builders.127.0.0.1')).location, '/goals?from=mail');
|
|
57
|
+
// the map it joined still carries its sections
|
|
58
|
+
assert.equal((await get('/sessions', 'builders.127.0.0.1')).location, '/watch#sessions');
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
test('Goals opens with the band, and loads what draws it', () => {
|
|
63
|
+
const html = read('goals.html');
|
|
64
|
+
const list = html.slice(html.indexOf('<section id="goals-list-view"'));
|
|
65
|
+
assert.ok(list.indexOf('id="rm-root"') > 0 && list.indexOf('id="rm-root"') < list.indexOf('class="scroll goals-panel"'),
|
|
66
|
+
'the band sits above the goals list');
|
|
67
|
+
assert.match(list, /<div id="rm-root"><div class="hall-loading" role="status">Loading the version…<\/div><\/div>/, 'with a Loading… line');
|
|
68
|
+
assert.match(html, /href="\/builders\/roadmap\.css"/);
|
|
69
|
+
const i = (s) => html.indexOf(s);
|
|
70
|
+
assert.ok(i('/builders/hall-kit.js') < i('/builders/roadmap-timeline.js'), 'the kit before the timeline');
|
|
71
|
+
assert.ok(i('/builders/roadmap-timeline.js') < i('/builders/roadmap.js'), 'the timeline before the band');
|
|
72
|
+
assert.ok(!fs.existsSync(path.join(HALL, 'roadmap.html')), 'the page itself is gone');
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
test('the band draws the version and the timeline, and no goal summary of its own', () => {
|
|
76
|
+
const js = read('roadmap.js');
|
|
77
|
+
assert.match(js, /function versionCard\(v\)/);
|
|
78
|
+
assert.match(js, /html \+= timelineHtml\(all, Date\.now\(\)\)/);
|
|
79
|
+
assert.ok(!/\/goals\?version=|goalSummary|goalsBlock/.test(js), 'Goals already reads the goals; the band does not read them again');
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
test('nothing points at the Roadmap any more', () => {
|
|
83
|
+
assert.ok(!/href: '\/roadmap'/.test(read('shell.js')), 'no nav item');
|
|
84
|
+
assert.ok(!/'roadmap'/.test(read('craft-mode.js')), 'no craft tab');
|
|
85
|
+
assert.ok(!/'roadmap'/.test(fs.readFileSync(path.join(ROOT, 'modules/onboarding/founding-mode.js'), 'utf8')), 'no founding room');
|
|
86
|
+
assert.ok(!/href="\/roadmap"/.test(read('work.html')), 'the Tasks board names Goals');
|
|
87
|
+
assert.match(read('work.html'), /See <a href="\/goals">Goals<\/a> for the version's progress/);
|
|
88
|
+
});
|
|
@@ -353,9 +353,10 @@ test('the kit is loaded before every page that draws through it', () => {
|
|
|
353
353
|
['watch.html', 'watch.js'],
|
|
354
354
|
['profile.html', 'profile-charts.js'],
|
|
355
355
|
// task 1003447: the roadmap's own series module reads the kit, and the page
|
|
356
|
-
// reads that. Both edges of the chain are ordered here
|
|
357
|
-
|
|
358
|
-
['
|
|
356
|
+
// reads that. Both edges of the chain are ordered here — on Goals since task
|
|
357
|
+
// 1005051 folded the Roadmap into its top.
|
|
358
|
+
['goals.html', 'roadmap-timeline.js'],
|
|
359
|
+
['goals.html', 'roadmap.js'],
|
|
359
360
|
]) {
|
|
360
361
|
// The loaded ORDER, read off the script tags — index.html's prose mentions
|
|
361
362
|
// hall-render.js ~90 lines above where it loads it, so a substring search
|
package/tests/hall_nav.mjs
CHANGED
|
@@ -291,8 +291,11 @@ test('sidebar groups read by audience, in order', () => {
|
|
|
291
291
|
// default-off market-watch module is not enabled (this boot reports no module state).
|
|
292
292
|
// task 1005071: the project group split three ways. Work is the project's state;
|
|
293
293
|
// Make is where things get made; Govern is the board's rooms.
|
|
294
|
-
|
|
294
|
+
// task 1005051: 'roadmap' left — the version's progress and timeline open Goals,
|
|
295
|
+
// and /roadmap redirects there (owner decision 2026-11-03, idea 1001315).
|
|
296
|
+
assert.deepEqual(nav[0].items.map((i) => i.id), ['home', 'work', 'goals', 'goal-map', 'blockers', 'thinking'],
|
|
295
297
|
'Work = the project itself (task 1005071 order)');
|
|
298
|
+
assert.ok(!nav.flatMap((g) => g.items).some((i) => i.href === '/roadmap'), 'no item points at the folded Roadmap');
|
|
296
299
|
assert.deepEqual(nav[1].items.map((i) => i.id), ['studio', 'market-watch'], 'Make = where things get made');
|
|
297
300
|
// task 1004685 (the living-city prototype, round-3 board 6): 'my-agents' joins You —
|
|
298
301
|
// how your own Claude works for you, the personal half of "the city steers
|
|
@@ -859,7 +862,7 @@ test('POSITION: ?as=nobody views the hall with no seat, and can only hide', asyn
|
|
|
859
862
|
assert.equal(b.navHidden('my-agents'), false);
|
|
860
863
|
// a xenos stand-in stays a xenos: the pretend rank never rises above the real one
|
|
861
864
|
const x = await seated({ builder: { id: '9', rank: 'xenos' }, positions: block([lead('planning', 'Planning Lead')]), search: '?as=nobody' });
|
|
862
|
-
assert.equal(x.navHidden('
|
|
865
|
+
assert.equal(x.navHidden('goal-map'), true, 'a member page stays hidden from a real xenos');
|
|
863
866
|
});
|
|
864
867
|
|
|
865
868
|
test('My agents draws its own glyph and lands on a real page', () => {
|
|
@@ -70,7 +70,9 @@ const ORACLE = {
|
|
|
70
70
|
// the URL now serves THE PROJECT SKY (the same page as /thinking, in its whole-project
|
|
71
71
|
// lens) on the same tier, and holds the nav slot under Goals the map was denied.
|
|
72
72
|
'/builders/goal-map': 'requireBuilderPage',
|
|
73
|
-
|
|
73
|
+
// Gone (task 1005051, owner decision 2026-11-03): the Roadmap is the top of Goals,
|
|
74
|
+
// and /builders/roadmap 302s there before any gate runs.
|
|
75
|
+
'/builders/roadmap': null,
|
|
74
76
|
// Gated at this tier all along, but with no row until task 1003448 walked the
|
|
75
77
|
// module's pages: copy-desk (task 1003113) and ideas (task 1002928) are open to
|
|
76
78
|
// every rank by design, and collab's reads (task 1003172) are scoped to the
|
|
@@ -365,6 +367,8 @@ const GONE_PAGES = {
|
|
|
365
367
|
// Task 1005049 — one oversight page: each is a tab on Watch, and the old URL 302s to it.
|
|
366
368
|
'/builders/sessions': 'task 1005049 — the session log is Watch\'s Sessions tab; /sessions redirects there',
|
|
367
369
|
'/builders/gate': 'task 1005049 — the runner panel is Watch\'s Autobongos tab; /gate redirects there',
|
|
370
|
+
// Task 1005051 — the version's progress and timeline open Goals; /roadmap redirects there.
|
|
371
|
+
'/builders/roadmap': 'task 1005051 — the roadmap is the top of Goals; /roadmap redirects there',
|
|
368
372
|
};
|
|
369
373
|
|
|
370
374
|
test('a row that is null because the page left the hall serves no page', () => {
|
|
@@ -74,7 +74,8 @@ const primerJs = read('primer.js');
|
|
|
74
74
|
const viewerJs = read('diagram-viewer.js');
|
|
75
75
|
const mdReaderJs = read('md-reader.js');
|
|
76
76
|
const primerHtml = read('primer.html');
|
|
77
|
-
|
|
77
|
+
// task 1005051: the Roadmap folded into the top of Goals; its band draws there.
|
|
78
|
+
const roadmapHtml = read('goals.html');
|
|
78
79
|
|
|
79
80
|
const decomment = (css) => css.replace(/\/\*[\s\S]*?\*\//g, '');
|
|
80
81
|
// The body of the first rule matching `selector {`, comments stripped. Naive on
|
|
@@ -106,12 +107,12 @@ test('no hall page sheet declares a :root of its own', () => {
|
|
|
106
107
|
'the pack :root is spliced at the end of <head> — a page-local one is outranked one way and defeats re-branding the other. Put page tokens on body.');
|
|
107
108
|
});
|
|
108
109
|
|
|
109
|
-
test('roadmap.css
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
110
|
+
test('roadmap.css keeps no page-local tokens and draws no shadow', () => {
|
|
111
|
+
// task 1005051: the two body tokens (--rm-plan, --rm-terra-weak) painted the
|
|
112
|
+
// goal summaries and the staged cards, which went with the page; nothing on the
|
|
113
|
+
// Goals band spends them, so they left with them rather than lingering unread.
|
|
114
|
+
assert.doesNotMatch(decomment(roadmapCss), /--rm-(plan|terra-weak)\s*:/, 'no unread page token left behind');
|
|
115
|
+
assert.doesNotMatch(decomment(roadmapCss), /:root\s*\{/, 'and never a page-local :root');
|
|
115
116
|
assert.doesNotMatch(decomment(roadmapCss), /--rm-shadow-soft/,
|
|
116
117
|
'v3 separates by TONE — a panel is never a drawn box and never a shadow');
|
|
117
118
|
assert.doesNotMatch(decomment(roadmapCss), /box-shadow\s*:\s*(?!inset)[^;]*(?:rgba|0 )/,
|
|
@@ -350,7 +351,7 @@ test('the viewer drops the white ground mermaid bakes into the SVG', () => {
|
|
|
350
351
|
// ---- 8. every room has exactly one h1 -------------------------------------
|
|
351
352
|
|
|
352
353
|
// task 1005046: diagrams.html and ranks.html folded into the primer's chapters.
|
|
353
|
-
const ROOMS = [['primer.html', primerHtml], ['
|
|
354
|
+
const ROOMS = [['primer.html', primerHtml], ['goals.html', roadmapHtml]];
|
|
354
355
|
|
|
355
356
|
// An HTML comment that mentions <h1> is prose, not markup — and these pages each
|
|
356
357
|
// carry one explaining why the heading is there at all.
|
|
@@ -369,7 +370,7 @@ test('the DOCS room takes the room voice; the deck takes the board\'s', () => {
|
|
|
369
370
|
assert.match(html, /class="page-head page-head--room"/, `${name} is a reading room`);
|
|
370
371
|
}
|
|
371
372
|
assert.match(roadmapHtml, /class="page-head page-head--board"/,
|
|
372
|
-
'the roadmap is a working surface whose figures are the thing to look at, so its own name stays quiet');
|
|
373
|
+
'Goals, which carries the roadmap band, is a working surface whose figures are the thing to look at, so its own name stays quiet');
|
|
373
374
|
});
|
|
374
375
|
|
|
375
376
|
test('the document\'s own h1 is suppressed, or the article would render a second one', () => {
|
|
@@ -418,19 +419,17 @@ test('no reading room carries an inline <style>, and none needs an audit excepti
|
|
|
418
419
|
// was the last page carrying a one-line block; task 1003440 deleted the page.)
|
|
419
420
|
});
|
|
420
421
|
|
|
421
|
-
test('
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
422
|
+
test('the version band\'s sub-24px link clears the floor', () => {
|
|
423
|
+
// task 1005051: the goal-row title (.rm-goal__t) went with the goal summaries
|
|
424
|
+
// when the Roadmap folded into Goals — the goals are the list right below — so
|
|
425
|
+
// the band's one small control left is its "View tasks" link.
|
|
426
|
+
assert.equal(rule(roadmapCss, '.rm-goal__t'), null, 'the goal rows are gone, and their rule with them');
|
|
425
427
|
const more = rule(roadmapCss, '.rm-gmore');
|
|
426
428
|
assert.ok(more, '.rm-gmore has a rule');
|
|
427
429
|
assert.match(more, /min-height:\s*24px/, 'measured 19px');
|
|
428
|
-
// the WIDTH half is the one that gets missed: at 320 the four fixed items in
|
|
429
|
-
// the row ate it and `flex: 1; min-width: 0` resolved the title to 0x26
|
|
430
|
-
assert.match(decomment(roadmapCss), /@media\s*\(max-width:400px\)[\s\S]*?\.rm-goal__t\s*\{[^}]*flex:\s*1 0 100%/,
|
|
431
|
-
'and the row wraps before the title can resolve to zero width');
|
|
432
430
|
});
|
|
433
431
|
|
|
432
|
+
|
|
434
433
|
// ---- 10. the parser, actually run -----------------------------------------
|
|
435
434
|
|
|
436
435
|
// md-reader.js is a browser IIFE that only touches `window` and `location`, so
|
|
@@ -709,7 +708,7 @@ test('RUN: a deck whose versions carry no dates renders every other section unha
|
|
|
709
708
|
versions: { versions: [{ id: 'BONGOS-V1', name: 'x', status: 'building', started_at: null, shipped_at: null }] },
|
|
710
709
|
});
|
|
711
710
|
assert.doesNotMatch(html, /In time</, 'no timeline section');
|
|
712
|
-
assert.match(html, /rm-
|
|
711
|
+
assert.match(html, /rm-card--feat/, 'but the version still renders');
|
|
713
712
|
assert.doesNotMatch(html, /NaN|undefined/);
|
|
714
713
|
});
|
|
715
714
|
|
package/tests/hall_sitemap.mjs
CHANGED
|
@@ -21,7 +21,8 @@ const model = gen.build();
|
|
|
21
21
|
test('the parse found the hall, so nothing below passes against an empty map', () => {
|
|
22
22
|
const files = fs.readdirSync(path.join(ROOT, 'modules/hall-ui/public')).filter((f) => f.endsWith('.html'));
|
|
23
23
|
assert.equal(model.pages.length, files.length, 'one row per page file');
|
|
24
|
-
|
|
24
|
+
// 24 since task 1005051 folded the Roadmap into Goals.
|
|
25
|
+
assert.ok(model.nav.length >= 24, `expected the shell's nav, found ${model.nav.length} items`);
|
|
25
26
|
for (const c of ['building', 'artistry', 'ideating', 'governing']) {
|
|
26
27
|
assert.ok(model.crafts.tabs[c].length > model.crafts.always.length, `${c} lists tabs of its own`);
|
|
27
28
|
}
|
|
@@ -98,8 +98,9 @@ test('the hall-preview fixture carries every atom /me resolves', () => {
|
|
|
98
98
|
// task 1005046: Ranks, Economy and Diagrams left Docs (one reading room, the Primer);
|
|
99
99
|
// task 1005049: Sessions and Autobongos left the sidebar (tabs on Watch);
|
|
100
100
|
// task 1005076: the setup flow's holdForSetup;
|
|
101
|
-
// task 1005050: Accomplishments left it (folded into Profile; its hashes redirect)
|
|
102
|
-
|
|
101
|
+
// task 1005050: Accomplishments left it (folded into Profile; its hashes redirect);
|
|
102
|
+
// task 1005051: Roadmap left it (folded into Goals; /roadmap redirects).
|
|
103
|
+
const SHELL_SHA = '5e52e0337239f532';
|
|
103
104
|
|
|
104
105
|
test('shell.js has not changed without its cache-bust being bumped', () => {
|
|
105
106
|
const actual = crypto.createHash('sha256').update(SHELL).digest('hex').slice(0, 16);
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
<!doctype html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="utf-8">
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
|
-
<title>Roadmap — {{worldName}}</title>
|
|
7
|
-
<meta name="description" content="How the whole build is doing — the program at a glance, then each version — {{worldName}}.">
|
|
8
|
-
<link rel="icon" href="data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'><text x='16' y='24' font-size='24' text-anchor='middle' font-family='sans-serif'>⌂</text></svg>">
|
|
9
|
-
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
10
|
-
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
11
|
-
<link rel="stylesheet" href="/builders/style.css?v=2026-07-24-deck1">
|
|
12
|
-
<link rel="stylesheet" href="/builders/roadmap.css">
|
|
13
|
-
</head>
|
|
14
|
-
<body data-page="roadmap" data-page-title="Roadmap">
|
|
15
|
-
|
|
16
|
-
<div class="app">
|
|
17
|
-
<aside class="app-sidebar" id="app-sidebar" aria-label="Primary"></aside>
|
|
18
|
-
<div class="app-scrim" id="app-scrim" hidden></div>
|
|
19
|
-
<div class="app-body">
|
|
20
|
-
<header class="app-topbar" id="app-topbar"></header>
|
|
21
|
-
<div class="app-content">
|
|
22
|
-
<!-- The page had no <h1> at all before task 1003306, so it failed
|
|
23
|
-
one-header-main-h1 on every render. The deck takes the BOARD voice,
|
|
24
|
-
not the reading room's: it is a working surface whose figures are the
|
|
25
|
-
thing to look at, and its own name is the quietest thing on it. -->
|
|
26
|
-
<div class="page-head page-head--board">
|
|
27
|
-
<h1 class="page-head__h">Roadmap</h1>
|
|
28
|
-
<p class="page-head__sub" id="roadmap-sub">Loading the roadmap…</p>
|
|
29
|
-
</div>
|
|
30
|
-
|
|
31
|
-
<main id="hall-main">
|
|
32
|
-
<div id="rm-root">
|
|
33
|
-
<div class="hall-loading hall-loading--page" role="status">Loading the roadmap…</div>
|
|
34
|
-
</div>
|
|
35
|
-
</main>
|
|
36
|
-
|
|
37
|
-
<footer class="app-foot" id="app-foot"></footer>
|
|
38
|
-
</div>
|
|
39
|
-
</div>
|
|
40
|
-
</div>
|
|
41
|
-
|
|
42
|
-
<div id="toast" class="toast" role="status" aria-live="polite" data-visible="0"></div>
|
|
43
|
-
|
|
44
|
-
<script src="/builders/dom-utils.js?v=2026-11-05-numbers"></script>
|
|
45
|
-
<script src="/builders/shell-trail.js?v=2026-11-05-numbers"></script>
|
|
46
|
-
<script src="/builders/craft-mode.js?v=2026-11-05-numbers"></script>
|
|
47
|
-
<script src="/builders/shell.js?v=2026-11-05-numbers"></script>
|
|
48
|
-
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
49
|
-
<script src="/builders/palette.js" defer></script>
|
|
50
|
-
<!-- The chart kit and the timeline's series builders (task 1003447). Both MUST
|
|
51
|
-
precede roadmap.js: the page reads window.OTBKit / window.OTBRoadmapTimeline
|
|
52
|
-
at render time, so loading either after would be a blank section in
|
|
53
|
-
production and a green unit suite. tests/hall_kit_charts.mjs pins the order. -->
|
|
54
|
-
<script src="/builders/hall-kit.js"></script>
|
|
55
|
-
<script src="/builders/roadmap-timeline.js"></script>
|
|
56
|
-
<script src="/builders/roadmap.js?v=2026-09-03-timeline"></script>
|
|
57
|
-
</body>
|
|
58
|
-
</html>
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"_": "The hall's roadmap deck through modules/ui-design/kit/render.js (task 1003306). The deck is the hall's densest figure surface — a hero band, four status groups and a summarised goal layer per version — so its floors are the 24px one (the goal rows are links in a tight list) and horizontal overflow at 320.",
|
|
3
|
-
"page": "/builders/roadmap",
|
|
4
|
-
"surface": "hall-ui",
|
|
5
|
-
"stub": { "prefix": "/builders/" },
|
|
6
|
-
"modeQuery": false,
|
|
7
|
-
"_feeds": "The kit's stub carries the public-landing fixtures, not the hall's versions/goals feeds, so the deck renders its EMPTY state here and the feed 404s are declared, never hidden. The populated deck is the hall-preview harness's job: node scripts/hall-preview/server.js --port 4612 --fixture-me, then this same file with --base-in/--base-out pointed at it.",
|
|
8
|
-
"ignoreRequests": [
|
|
9
|
-
"/api/(gds|bongos)/me$",
|
|
10
|
-
"/api/(gds|bongos)/me/",
|
|
11
|
-
"/api/(gds|bongos)/versions",
|
|
12
|
-
"/api/(gds|bongos)/goals",
|
|
13
|
-
"/api/(gds|bongos)/tasks",
|
|
14
|
-
"/api/(gds|bongos)/inbox/",
|
|
15
|
-
"/api/(gds|bongos)/public/"
|
|
16
|
-
],
|
|
17
|
-
"ignoreConsole": [
|
|
18
|
-
"/api/(gds|bongos)/",
|
|
19
|
-
"\\b401\\b",
|
|
20
|
-
"\\b404\\b",
|
|
21
|
-
"Unauthorized",
|
|
22
|
-
"Not Found",
|
|
23
|
-
"load failed",
|
|
24
|
-
"roadmap"
|
|
25
|
-
],
|
|
26
|
-
"states": {
|
|
27
|
-
"in": { "auth": true, "expect": { "visible": ["#rm-root"] } },
|
|
28
|
-
"out": { "auth": false }
|
|
29
|
-
},
|
|
30
|
-
"reducedMotion": { "auth": true }
|
|
31
|
-
}
|