@bongos/core 1.24.36 → 1.24.37
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 +90 -85
- package/docs/copy-inventory.md +58 -57
- package/docs/copy-registry.json +163 -166
- package/docs/module-api-changelog.md +2 -0
- package/docs/onboarding/primer.md +2 -0
- package/docs/page-inventory.json +34 -34
- package/docs/page-readings.json +684 -680
- 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/fleet-costs.js +3 -2
- package/modules/hall-ui/public/gate.html +2 -2
- package/modules/hall-ui/public/goal-map.html +2 -2
- package/modules/hall-ui/public/goals.html +2 -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 +92 -0
- package/modules/hall-ui/public/money.js +302 -0
- package/modules/hall-ui/public/money.states.json +15 -0
- package/modules/hall-ui/public/my-agents.html +2 -2
- package/modules/hall-ui/public/palette.js +9 -2
- package/modules/hall-ui/public/primer-live.js +18 -105
- package/modules/hall-ui/public/primer.html +7 -8
- package/modules/hall-ui/public/primer.js +16 -18
- package/modules/hall-ui/public/profile.html +2 -2
- package/modules/hall-ui/public/project-settings.css +2 -1
- package/modules/hall-ui/public/project-settings.html +6 -16
- package/modules/hall-ui/public/project-settings.js +2 -142
- package/modules/hall-ui/public/roadmap.html +2 -2
- package/modules/hall-ui/public/roster.html +2 -2
- package/modules/hall-ui/public/sessions.html +2 -2
- package/modules/hall-ui/public/settings.html +2 -2
- package/modules/hall-ui/public/shell.js +7 -5
- 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 +2 -2
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/release-notes.json +6 -0
- package/src/bongos/auth.js +0 -8
- package/src/bongos/serve-internal.js +15 -6
- package/src/module-api.js +1 -1
- package/tests/auth_resolve_failure.mjs +5 -4
- package/tests/fleet_cost_view.mjs +2 -18
- package/tests/hall_loading.mjs +1 -1
- package/tests/hall_money_page.mjs +272 -0
- package/tests/hall_nav.mjs +5 -4
- package/tests/hall_oversight_world.mjs +1 -1
- package/tests/hall_page_gate_map.mjs +3 -2
- package/tests/hall_reading_room.mjs +21 -62
- package/tests/nav_permission_atoms.mjs +1 -1
- package/modules/hall-ui/public/fleet.html +0 -69
- package/modules/hall-ui/public/fleet.js +0 -41
- package/modules/hall-ui/public/fleet.states.json +0 -14
|
@@ -49,19 +49,9 @@
|
|
|
49
49
|
server resolved it through, and markup that could drift from that is the
|
|
50
50
|
thing this page exists to end. -->
|
|
51
51
|
<div id="ps-rows"><span class="kit-skel"></span></div>
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
read (payout.approve, the owner), so every other reader of this page never
|
|
56
|
-
sees an empty panel. Written by project-settings.js; every figure is the
|
|
57
|
-
server's, summed from records that already exist. -->
|
|
58
|
-
<section class="scroll" id="ps-money" aria-labelledby="ps-money-h" hidden>
|
|
59
|
-
<h2 class="scroll__h" id="ps-money-h">Where the money went</h2>
|
|
60
|
-
<p class="scroll__lede">
|
|
61
|
-
What this project has spent, what each builder has been paid, and what it has
|
|
62
|
-
promised but not paid yet. A balance only means something after those promises.
|
|
63
|
-
</p>
|
|
64
|
-
<div id="ps-money-body"></div>
|
|
52
|
+
<!-- task 1005047: the money figures this page drew ("Where the money went",
|
|
53
|
+
task 1003184) moved to the one money page; this page keeps its knobs. -->
|
|
54
|
+
<p class="ps-prov" id="ps-money-link">What this project has spent and paid out, its treasury and its hosting bills are on the <a href="/builders/money">Money</a> page.</p>
|
|
65
55
|
</section>
|
|
66
56
|
<!-- Danger zone (task 1004570): where this project's OWNER takes it offline or
|
|
67
57
|
disconnects it. Both controls live on the platform that hosts the project,
|
|
@@ -86,11 +76,11 @@
|
|
|
86
76
|
|
|
87
77
|
<script src="/builders/dom-utils.js?v=2026-10-25-escape"></script>
|
|
88
78
|
<script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
|
|
89
|
-
<script src="/builders/craft-mode.js?v=2026-11-04-
|
|
90
|
-
<script src="/builders/shell.js?v=2026-11-04-
|
|
79
|
+
<script src="/builders/craft-mode.js?v=2026-11-04-money"></script>
|
|
80
|
+
<script src="/builders/shell.js?v=2026-11-04-money"></script>
|
|
91
81
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
92
82
|
<script src="/builders/palette.js" defer></script>
|
|
93
83
|
<script src="/builders/hall-kit.js"></script>
|
|
94
|
-
<script src="/builders/project-settings.js?v=2026-11-
|
|
84
|
+
<script src="/builders/project-settings.js?v=2026-11-04-money"></script>
|
|
95
85
|
</body>
|
|
96
86
|
</html>
|
|
@@ -417,148 +417,8 @@
|
|
|
417
417
|
$('ps-danger').hidden = false;
|
|
418
418
|
}
|
|
419
419
|
|
|
420
|
-
//
|
|
421
|
-
//
|
|
422
|
-
// The owner's outflow view. The server sums every figure (modules/economy/outflow.js);
|
|
423
|
-
// this only draws it. It leads with what is left AFTER what is owed, because a balance
|
|
424
|
-
// that looks healthy while it owes three payouts is the trap the view exists to show.
|
|
425
|
-
// Any outcome but a 200 leaves the section hidden: the read is the payout authority's,
|
|
426
|
-
// and everyone else on this page has nothing to see here, not an error.
|
|
427
|
-
|
|
428
|
-
const money = (micro) => {
|
|
429
|
-
const usd = Number(micro || 0) / 1e6;
|
|
430
|
-
const abs = Math.abs(usd).toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 });
|
|
431
|
-
return `${usd < 0 ? '−' : ''}$${abs}`;
|
|
432
|
-
};
|
|
433
|
-
const monthLabel = (ym) => {
|
|
434
|
-
const [y, m] = String(ym).split('-').map(Number);
|
|
435
|
-
return new Date(Date.UTC(y, m - 1, 1)).toLocaleDateString(undefined, { month: 'short', year: 'numeric', timeZone: 'UTC' });
|
|
436
|
-
};
|
|
437
|
-
const dayLabel = (iso) => (iso ? new Date(iso).toLocaleDateString() : '');
|
|
438
|
-
|
|
439
|
-
function moneyFiguresHtml(out) {
|
|
440
|
-
const c = out.committed;
|
|
441
|
-
const after = out.balance.after_commitments_micro;
|
|
442
|
-
const fig = (label, value, note, tone) => `<div class="ps-money__fig${tone ? ` ps-money__fig--${tone}` : ''}">
|
|
443
|
-
<span class="ps-money__label">${escapeHtml(label)}</span>
|
|
444
|
-
<strong class="ps-money__value">${escapeHtml(value)}</strong>
|
|
445
|
-
<span class="ps-money__note">${escapeHtml(note)}</span>
|
|
446
|
-
</div>`;
|
|
447
|
-
const owedNote = c.owed_count === 1 ? '1 payment' : `${c.owed_count} payments`;
|
|
448
|
-
const apprNote = c.approved_count === 1 ? '1 approval' : `${c.approved_count} approvals`;
|
|
449
|
-
return `<div class="ps-money__figs">
|
|
450
|
-
${fig('Balance', money(out.balance.available_micro), c.held_micro ? `after ${money(c.held_micro)} held` : 'on our record')}
|
|
451
|
-
${fig('Owed but not paid', money(c.owed_micro), owedNote, c.owed_micro ? 'warn' : '')}
|
|
452
|
-
${fig('Approved, not started', money(c.approved_micro), apprNote, c.approved_micro ? 'warn' : '')}
|
|
453
|
-
${fig('Left after all of that', money(after), after < 0 ? 'the project owes more than it holds' : 'what is really free', after < 0 ? 'bad' : '')}
|
|
454
|
-
</div>${c.other_currency_count ? `<p class="ps-prov">${c.other_currency_count} more in a currency other than US dollars, not added in.</p>` : ''}`;
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
// The payout's latest try in words. A reason is either the processor's own sentence, shown
|
|
458
|
-
// as it is, or one of core's held codes (builder-payouts.js HELD_WORDS). The codes an owner
|
|
459
|
-
// can act on get a short phrase here; any other code is left out rather than shown as a slug.
|
|
460
|
-
const TRY_WORDS = { held: 'Waiting', failed: 'Did not go through' };
|
|
461
|
-
const REASON_WORDS = {
|
|
462
|
-
no_processor: 'no payment processor connected yet',
|
|
463
|
-
recipient_gated: 'this person cannot be paid right now',
|
|
464
|
-
guardian_cosign_missing: 'a guardian has not co-signed yet',
|
|
465
|
-
currency_not_supported: 'not in US dollars',
|
|
466
|
-
};
|
|
467
|
-
function lastTryWords(r) {
|
|
468
|
-
if (!r.last_outcome) return 'Not tried yet';
|
|
469
|
-
const reason = String(r.last_reason || '');
|
|
470
|
-
const why = REASON_WORDS[reason] || (/^[a-z_]+$/.test(reason) ? '' : reason);
|
|
471
|
-
return `${TRY_WORDS[r.last_outcome] || r.last_outcome}${why ? ` — ${why}` : ''}`;
|
|
472
|
-
}
|
|
473
|
-
|
|
474
|
-
function owedHtml(out) {
|
|
475
|
-
const rows = out.committed.owed;
|
|
476
|
-
if (!rows.length) return '';
|
|
477
|
-
return `<h3 class="ps-money__h">Owed but not paid</h3>
|
|
478
|
-
<div class="ps-money__wrap"><table class="ledger">
|
|
479
|
-
<thead><tr><th>Builder</th><th>Task</th><th>Amount</th><th>Owed since</th><th>Last try</th></tr></thead>
|
|
480
|
-
<tbody>${rows.map((r) => `<tr>
|
|
481
|
-
<td>${escapeHtml(r.builder_name || `builder ${r.builder_id}`)}</td>
|
|
482
|
-
<td><a href="/builders/task/${encodeURIComponent(r.task_id)}">${escapeHtml(r.task_title || `task ${r.task_id}`)}</a></td>
|
|
483
|
-
<td>${escapeHtml(money(r.amount_micro))}</td>
|
|
484
|
-
<td>${escapeHtml(dayLabel(r.since))}</td>
|
|
485
|
-
<td>${escapeHtml(lastTryWords(r))}</td>
|
|
486
|
-
</tr>`).join('')}</tbody>
|
|
487
|
-
</table></div>`;
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
function buildersHtml(out) {
|
|
491
|
-
const rows = out.by_builder;
|
|
492
|
-
if (!rows.length) return '';
|
|
493
|
-
return `<h3 class="ps-money__h">By builder</h3>
|
|
494
|
-
<div class="ps-money__wrap"><table class="ledger">
|
|
495
|
-
<thead><tr><th>Builder</th><th>Spent</th><th>Paid</th><th>Owed</th><th>Approved</th></tr></thead>
|
|
496
|
-
<tbody>${rows.map((b) => `<tr>
|
|
497
|
-
<td>${escapeHtml(b.builder_name || `builder ${b.builder_id}`)}</td>
|
|
498
|
-
<td>${escapeHtml(money(b.spend_micro))}</td>
|
|
499
|
-
<td>${escapeHtml(money(b.paid_micro))}</td>
|
|
500
|
-
<td>${escapeHtml(money(b.owed_micro))}</td>
|
|
501
|
-
<td>${escapeHtml(money(b.approved_micro))}</td>
|
|
502
|
-
</tr>`).join('')}</tbody>
|
|
503
|
-
</table></div>
|
|
504
|
-
<p class="ps-prov">Spent is the recorded cost of each builder’s sessions (API, compute). Paid, owed and approved are payouts.</p>`;
|
|
505
|
-
}
|
|
506
|
-
|
|
507
|
-
function burnHtml(out) {
|
|
508
|
-
const months = out.burn.months;
|
|
509
|
-
if (!months.some((m) => m.total_micro > 0)) return '';
|
|
510
|
-
const bars = window.OTBKit.barSeriesHtml(
|
|
511
|
-
months.map((m) => ({ label: monthLabel(m.month), value: m.total_micro, valueLabel: money(m.total_micro) })),
|
|
512
|
-
{ list: true, ariaLabel: 'Money out by month', valueWidth: '96px' });
|
|
513
|
-
return `<h3 class="ps-money__h">Money out, by month</h3>${bars}
|
|
514
|
-
<p class="ps-prov">Each month is recorded spend (${escapeHtml(money(months.reduce((s, m) => s + m.spend_micro, 0)))} over these ${months.length} months) plus payouts and fees out of the project account. Read from the cost log and the account’s own record.</p>`;
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
// The daily check of our record against the processor's (task 1004912). The newest check
|
|
518
|
-
// in words, and on a difference each one with both amounts. The blocker it raises is public
|
|
519
|
-
// and carries no numbers, so this is where the owner reads them.
|
|
520
|
-
const CHECK_WORDS = {
|
|
521
|
-
clean: 'Our records and the payment processor’s agree.',
|
|
522
|
-
drift: 'Our records and the payment processor’s differ.',
|
|
523
|
-
unchecked: 'Not checked: no payment processor is connected yet, so there is nothing to compare with.',
|
|
524
|
-
error: 'Could not check: the payment processor could not be read.',
|
|
525
|
-
};
|
|
526
|
-
function ledgerCheckHtml(out) {
|
|
527
|
-
const c = out && out.checks && out.checks[0];
|
|
528
|
-
if (!c) return '';
|
|
529
|
-
const words = out.kind_words || {};
|
|
530
|
-
const amt = (v) => (v === null || v === undefined ? '—' : money(v));
|
|
531
|
-
const rows = (c.findings || []).map((f) => `<tr>
|
|
532
|
-
<td>${escapeHtml(words[f.kind] || f.kind)}</td>
|
|
533
|
-
<td>${escapeHtml(f.ref || 'the project balance')}</td>
|
|
534
|
-
<td>${escapeHtml(amt(f.ours_micro))}</td>
|
|
535
|
-
<td>${escapeHtml(amt(f.theirs_micro))}</td>
|
|
536
|
-
</tr>`).join('');
|
|
537
|
-
return `<h3 class="ps-money__h">Daily check against the payment processor</h3>
|
|
538
|
-
<p class="ps-prov">${escapeHtml(dayLabel(c.created_at))}: ${escapeHtml(CHECK_WORDS[c.outcome] || c.outcome)}${c.outcome === 'clean' || c.outcome === 'drift' ? ` ${c.refs_compared} ${c.refs_compared === 1 ? 'movement' : 'movements'} compared.` : ''}</p>
|
|
539
|
-
${rows ? `<div class="ps-money__wrap"><table class="ledger">
|
|
540
|
-
<thead><tr><th>Difference</th><th>Reference</th><th>Our record</th><th>Processor</th></tr></thead>
|
|
541
|
-
<tbody>${rows}</tbody>
|
|
542
|
-
</table></div>` : ''}`;
|
|
543
|
-
}
|
|
544
|
-
|
|
545
|
-
async function loadMoney() {
|
|
546
|
-
let out = null;
|
|
547
|
-
try {
|
|
548
|
-
const res = await api.request('GET', `${API}/project-account/outflow`);
|
|
549
|
-
out = res.ok ? res.data : null;
|
|
550
|
-
} catch (_) { out = null; }
|
|
551
|
-
if (!out || !out.balance || !out.committed) return;
|
|
552
|
-
let checks = null;
|
|
553
|
-
try {
|
|
554
|
-
const res = await api.request('GET', `${API}/project-account/ledger-checks?limit=1`);
|
|
555
|
-
checks = res.ok ? res.data : null;
|
|
556
|
-
} catch (_) { checks = null; }
|
|
557
|
-
$('ps-money-body').innerHTML = moneyFiguresHtml(out) + ledgerCheckHtml(checks) + owedHtml(out) + buildersHtml(out) + burnHtml(out);
|
|
558
|
-
$('ps-money').hidden = false;
|
|
559
|
-
}
|
|
560
|
-
|
|
420
|
+
// task 1005047: "Where the money went" (task 1003184) moved to money.js, the one
|
|
421
|
+
// money page; the section's link is in project-settings.html.
|
|
561
422
|
load();
|
|
562
|
-
loadMoney();
|
|
563
423
|
loadDanger();
|
|
564
424
|
})();
|
|
@@ -43,8 +43,8 @@
|
|
|
43
43
|
|
|
44
44
|
<script src="/builders/dom-utils.js?v=2026-10-25-escape"></script>
|
|
45
45
|
<script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
|
|
46
|
-
<script src="/builders/craft-mode.js?v=2026-11-04-
|
|
47
|
-
<script src="/builders/shell.js?v=2026-11-04-
|
|
46
|
+
<script src="/builders/craft-mode.js?v=2026-11-04-money"></script>
|
|
47
|
+
<script src="/builders/shell.js?v=2026-11-04-money"></script>
|
|
48
48
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
49
49
|
<script src="/builders/palette.js" defer></script>
|
|
50
50
|
<!-- The chart kit and the timeline's series builders (task 1003447). Both MUST
|
|
@@ -55,8 +55,8 @@
|
|
|
55
55
|
chrome exists before the page script runs. -->
|
|
56
56
|
<script src="/builders/dom-utils.js?v=2026-10-25-escape"></script>
|
|
57
57
|
<script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
|
|
58
|
-
<script src="/builders/craft-mode.js?v=2026-11-04-
|
|
59
|
-
<script src="/builders/shell.js?v=2026-11-04-
|
|
58
|
+
<script src="/builders/craft-mode.js?v=2026-11-04-money"></script>
|
|
59
|
+
<script src="/builders/shell.js?v=2026-11-04-money"></script>
|
|
60
60
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
61
61
|
<script src="/builders/palette.js" defer></script>
|
|
62
62
|
<!-- the branding pack's currency label, loaded BEFORE roster.js. -->
|
|
@@ -113,8 +113,8 @@
|
|
|
113
113
|
chrome exists before the page script runs. -->
|
|
114
114
|
<script src="/builders/dom-utils.js?v=2026-10-25-escape"></script>
|
|
115
115
|
<script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
|
|
116
|
-
<script src="/builders/craft-mode.js?v=2026-11-04-
|
|
117
|
-
<script src="/builders/shell.js?v=2026-11-04-
|
|
116
|
+
<script src="/builders/craft-mode.js?v=2026-11-04-money"></script>
|
|
117
|
+
<script src="/builders/shell.js?v=2026-11-04-money"></script>
|
|
118
118
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
119
119
|
<script src="/builders/palette.js" defer></script>
|
|
120
120
|
<script src="/builders/task-detail.js?v=2026-07-03-taskdetail"></script>
|
|
@@ -393,8 +393,8 @@
|
|
|
393
393
|
chrome exists before the page scripts run. -->
|
|
394
394
|
<script src="/builders/dom-utils.js?v=2026-10-25-escape"></script>
|
|
395
395
|
<script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
|
|
396
|
-
<script src="/builders/craft-mode.js?v=2026-11-04-
|
|
397
|
-
<script src="/builders/shell.js?v=2026-11-04-
|
|
396
|
+
<script src="/builders/craft-mode.js?v=2026-11-04-money"></script>
|
|
397
|
+
<script src="/builders/shell.js?v=2026-11-04-money"></script>
|
|
398
398
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
399
399
|
<script src="/builders/palette.js" defer></script>
|
|
400
400
|
<!-- shared component kit (window.OTBKit) — section rail (task 2166). -->
|
|
@@ -122,7 +122,7 @@
|
|
|
122
122
|
sessions: '<path d="M7 5h8M7 9h8M7 13h8"/><circle cx="3.8" cy="5" r=".7" fill="currentColor"/><circle cx="3.8" cy="9" r=".7" fill="currentColor"/><circle cx="3.8" cy="13" r=".7" fill="currentColor"/>',
|
|
123
123
|
settings: '<circle cx="9" cy="9" r="2.5"/><path d="M9 2.5v2m0 9v2M2.5 9h2m9 0h2M4.4 4.4l1.4 1.4m6.4 6.4 1.4 1.4m0-9.2-1.4 1.4M5.8 12.2l-1.4 1.4"/>',
|
|
124
124
|
deploy: '<path d="M9 12V3M5.5 6.5 9 3l3.5 3.5M3 12.5v2a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1v-2"/>',
|
|
125
|
-
|
|
125
|
+
money: '<path d="M4 2.5h10v13l-1.7-1-1.6 1-1.7-1-1.7 1-1.6-1-1.7 1v-13Z"/><path d="M6.5 6h5M6.5 9h5M6.5 12h3"/>',
|
|
126
126
|
permissions: '<circle cx="6" cy="12" r="3.5"/><path d="M8.5 9.5 15 3M12.5 5.5l2 2M10.5 7.5l1.5 1.5"/>',
|
|
127
127
|
// The governor city: a pediment over columns, the Governing mode's own glyph.
|
|
128
128
|
city: '<path d="M2.5 7 9 3l6.5 4M4 7.5v6.5M7 7.5v6.5M11 7.5v6.5M14 7.5v6.5M2.5 15.5h13"/>',
|
|
@@ -367,6 +367,12 @@
|
|
|
367
367
|
// The project's own fundamentals (task 1003280, goal 1000072). Mirrors the
|
|
368
368
|
// server's requireGovernmentPage floor; cosmetic only, as every item here is.
|
|
369
369
|
{ id: 'project-settings', label: 'Project settings', icon: 'settings', href: '/project-settings', gate: 'government', position: true },
|
|
370
|
+
// task 1005047 (owner decision 2026-11-03, idea 1001312): the owner's one money page —
|
|
371
|
+
// spend and payouts (once on Project settings), the treasury (once the Economy page)
|
|
372
|
+
// and the hosting bills (once 'Fleet costs', /fleet, which now redirects to its
|
|
373
|
+
// #hosting section). It mirrors the server's requireGovernmentPage floor; every
|
|
374
|
+
// section on it is hidden unless its own read answers, so the wall stays per route.
|
|
375
|
+
{ id: 'money', label: 'Money', icon: 'money', href: '/money', gate: 'government', position: true },
|
|
370
376
|
// The deploy door (task 1003159, ADR 0293). Gated 'archon' here to mirror the
|
|
371
377
|
// `core.pin.move` atom its page and both its routes check — cosmetic only, as
|
|
372
378
|
// every item in this list is; the wall is server-side.
|
|
@@ -377,10 +383,6 @@
|
|
|
377
383
|
// is the platform hall's page alone, and every other hall takes its update from
|
|
378
384
|
// Settings → Software update, whose Update button carries the hub hand-off.
|
|
379
385
|
{ id: 'deploy', label: 'Deploy', icon: 'deploy', href: '/deploy', gate: 'archon', module: 'provisioning render-deploy', position: true },
|
|
380
|
-
// task 1001949: what each hosted project costs. 'government' mirrors the metic floor
|
|
381
|
-
// of `provisioning.fleet.manage`, the atom its page and its one read check (the
|
|
382
|
-
// Deploy precedent above); dropped where the provisioning module is not enabled.
|
|
383
|
-
{ id: 'fleet', label: 'Fleet costs', icon: 'fleet', href: '/fleet', gate: 'government', module: 'provisioning', position: true },
|
|
384
386
|
// task 1005045: the owner's Market Watch settings (task 1004938) are an owner-only tab on
|
|
385
387
|
// /market-watch now, so the sidebar says "Market Watch" once (owner decision 2026-11-03).
|
|
386
388
|
// BV1.R113: the roles-and-permissions tab (ADR 0151). The one genuinely
|
|
@@ -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-
|
|
234
|
-
<script src="/builders/shell.js?v=2026-11-04-
|
|
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>
|
|
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-
|
|
228
|
-
<script src="/builders/shell.js?v=2026-11-04-
|
|
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>
|
|
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-
|
|
62
|
-
<script src="/builders/shell.js?v=2026-11-04-
|
|
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>
|
|
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-
|
|
144
|
-
<script src="/builders/shell.js?v=2026-11-04-
|
|
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>
|
|
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-
|
|
148
|
-
<script src="/builders/shell.js?v=2026-11-04-
|
|
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>
|
|
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-
|
|
171
|
-
<script src="/builders/shell.js?v=2026-11-04-
|
|
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>
|
|
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-
|
|
177
|
-
<script src="/builders/shell.js?v=2026-11-04-
|
|
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>
|
|
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.
|
|
3
|
+
"version": "1.24.37",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@bongos/core",
|
|
9
|
-
"version": "1.24.
|
|
9
|
+
"version": "1.24.37",
|
|
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.
|
|
3
|
+
"version": "1.24.37",
|
|
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",
|
package/release-notes.json
CHANGED
|
@@ -11179,5 +11179,11 @@
|
|
|
11179
11179
|
"id": "1005046",
|
|
11180
11180
|
"text": "The Docs section now has one reading room instead of four pages: ranks, credits and karma, and the five diagrams all live in the Primer, each topic explained once with its picture beside it. Old links to Ranks, Economy and Dia"
|
|
11181
11181
|
}
|
|
11182
|
+
],
|
|
11183
|
+
"1.24.37": [
|
|
11184
|
+
{
|
|
11185
|
+
"id": "1005047",
|
|
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
|
+
}
|
|
11182
11188
|
]
|
|
11183
11189
|
}
|
package/src/bongos/auth.js
CHANGED
|
@@ -406,10 +406,6 @@ const PAGE_GATES = Object.freeze({
|
|
|
406
406
|
// live project; which project they may read or move is still the routes' question,
|
|
407
407
|
// asked per request against that project's row.
|
|
408
408
|
requireCorePinPage: Object.freeze({ permission: 'core.pin.move', deniedTo: '/builders', alsoAdmits: 'isProjectOwner' }),
|
|
409
|
-
// The /fleet cost page (task 1001949) — on `provisioning.fleet.manage`, the SAME atom
|
|
410
|
-
// its one read (GET /provisioning/fleet/cost-ledger) checks: every owner's projects
|
|
411
|
-
// and what they cost, so the page reaches exactly as far as the data does.
|
|
412
|
-
requireFleetPage: Object.freeze({ permission: 'provisioning.fleet.manage', deniedTo: '/builders' }),
|
|
413
409
|
});
|
|
414
410
|
|
|
415
411
|
// The `alsoAdmits` door — "is this visitor the page's OTHER audience?", asked of
|
|
@@ -568,9 +564,6 @@ async function requireBoardVotePage(req, res, next) {
|
|
|
568
564
|
async function requireCorePinPage(req, res, next) {
|
|
569
565
|
return runPageGate('requireCorePinPage', req, res, next);
|
|
570
566
|
}
|
|
571
|
-
async function requireFleetPage(req, res, next) {
|
|
572
|
-
return runPageGate('requireFleetPage', req, res, next);
|
|
573
|
-
}
|
|
574
567
|
|
|
575
568
|
// ---------------------------------------------------------------------------
|
|
576
569
|
// Route-gate inventory (V3.R06 #231) — the canonical "who can call what" list.
|
|
@@ -862,7 +855,6 @@ module.exports = {
|
|
|
862
855
|
requireGovernmentPage,
|
|
863
856
|
requireBoardVotePage,
|
|
864
857
|
requireCorePinPage,
|
|
865
|
-
requireFleetPage,
|
|
866
858
|
requireRank,
|
|
867
859
|
rankMeetsThreshold,
|
|
868
860
|
requirePermission,
|
|
@@ -1010,8 +1010,9 @@ function mountInternalSurfaces(app) {
|
|
|
1010
1010
|
// statically, and a comment in that gap makes the page test as UNGATED while
|
|
1011
1011
|
// looking gated here. Prose goes above the const, as here.
|
|
1012
1012
|
const DEPLOY_PAGE_RE = /^\/builders\/deploy(?:\.html)?\/?$/;
|
|
1013
|
-
//
|
|
1014
|
-
|
|
1013
|
+
// /money — the owner's one money page (task 1005047): the government floor; each
|
|
1014
|
+
// section's read keeps its own wall. NB as at PROJECT_SETTINGS_PAGE_RE.
|
|
1015
|
+
const MONEY_PAGE_RE = /^\/builders\/money(?:\.html)?\/?$/;
|
|
1015
1016
|
// /people and its legacy twin /scouting were the hall's cross-project builder
|
|
1016
1017
|
// directory. Task 1003440 deleted the /scouting door; task 1003444 deleted
|
|
1017
1018
|
// /people itself (owner call, 2026-09-25 — ADR 0337 D5): cross-project
|
|
@@ -1048,6 +1049,16 @@ function mountInternalSurfaces(app) {
|
|
|
1048
1049
|
return res.redirect(302, `${isBuildersHost(req) ? '' : '/builders'}/market-watch${qs}#settings`);
|
|
1049
1050
|
});
|
|
1050
1051
|
|
|
1052
|
+
// task 1005047: Fleet costs is /money's #hosting section now; 302 and no gate, as above.
|
|
1053
|
+
const RETIRED_FLEET_RE = /^\/builders\/fleet(?:\.html)?\/?$/;
|
|
1054
|
+
app.use((req, res, next) => {
|
|
1055
|
+
if (isModuleSurfaceHost(req)) return next();
|
|
1056
|
+
if (req.method !== 'GET' && req.method !== 'HEAD') return next();
|
|
1057
|
+
if (!RETIRED_FLEET_RE.test(path.posix.normalize(req.path))) return next();
|
|
1058
|
+
const qs = req.url.includes('?') ? req.url.slice(req.url.indexOf('?')) : '';
|
|
1059
|
+
return res.redirect(302, `${isBuildersHost(req) ? '' : '/builders'}/money${qs}#hosting`);
|
|
1060
|
+
});
|
|
1061
|
+
|
|
1051
1062
|
// task 1005046 (owner decision 2026-11-03, idea 1001311): ONE reading room. Ranks,
|
|
1052
1063
|
// Economy (/drachmae) and Diagrams explained what the Primer already explained, so
|
|
1053
1064
|
// they are Primer chapters now, each with its diagram, and each old URL lands on the
|
|
@@ -1094,7 +1105,8 @@ function mountInternalSurfaces(app) {
|
|
|
1094
1105
|
if (!req.path.startsWith('/builders')) return next();
|
|
1095
1106
|
const norm = path.posix.normalize(req.path);
|
|
1096
1107
|
if (WATCH_PAGE_RE.test(norm) || GATE_PAGE_RE.test(norm)
|
|
1097
|
-
|| SESSIONS_PAGE_RE.test(norm) || PROJECT_SETTINGS_PAGE_RE.test(norm)
|
|
1108
|
+
|| SESSIONS_PAGE_RE.test(norm) || PROJECT_SETTINGS_PAGE_RE.test(norm)
|
|
1109
|
+
|| MONEY_PAGE_RE.test(norm)) {
|
|
1098
1110
|
return gdsAuth.requireGovernmentPage(req, res, next);
|
|
1099
1111
|
}
|
|
1100
1112
|
// R16 (goal 1000069) widened the government shell from the manage atom
|
|
@@ -1125,9 +1137,6 @@ function mountInternalSurfaces(app) {
|
|
|
1125
1137
|
if (DEPLOY_PAGE_RE.test(norm)) {
|
|
1126
1138
|
return gdsAuth.requireCorePinPage(req, res, next);
|
|
1127
1139
|
}
|
|
1128
|
-
if (FLEET_PAGE_RE.test(norm)) {
|
|
1129
|
-
return gdsAuth.requireFleetPage(req, res, next);
|
|
1130
|
-
}
|
|
1131
1140
|
next();
|
|
1132
1141
|
});
|
|
1133
1142
|
|
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.37'; // 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');
|
|
@@ -97,18 +97,19 @@ test('AUDIT: every async middleware mounted directly on a router owns its reject
|
|
|
97
97
|
// requireBoardVotePage / BV1.R107 (and the ADR 0266 /board-room vote gate)
|
|
98
98
|
// requireCorePinPage / ADR 0293's /deploy door — the narrowest of them,
|
|
99
99
|
// on the archon-floor `core.pin.move` atom.
|
|
100
|
-
//
|
|
101
|
-
//
|
|
100
|
+
// Task 1005047 removed requireFleetPage with the /fleet page it fronted (its
|
|
101
|
+
// ledger is a section of /money now, behind the government page floor and the
|
|
102
|
+
// route's own atom). Task 1003450 removed two more — requireNonXenosPage and the R113
|
|
102
103
|
// requireGovernmentManagePage — which had both ended up dispatched from no
|
|
103
104
|
// route at all; tests/hall_page_gate_map.mjs now fails if that recurs. Task
|
|
104
105
|
// 1003444 removed requireProjectCuratePage with the /people page it fronted.
|
|
105
106
|
// Anything else async and router-mounted must be added with its own try/catch.
|
|
106
107
|
const src = fs.readFileSync(path.join(ROOT, 'src', 'bongos', 'auth.js'), 'utf8');
|
|
107
108
|
const asyncMw = [...src.matchAll(/^async function (require\w+|allow\w+)\s*\(req, res, next\)/gm)].map((m) => m[1]);
|
|
108
|
-
assert.deepEqual(asyncMw.sort(), ['requireBoardVotePage', 'requireBuilder', 'requireBuilderPage', 'requireCorePinPage', '
|
|
109
|
+
assert.deepEqual(asyncMw.sort(), ['requireBoardVotePage', 'requireBuilder', 'requireBuilderPage', 'requireCorePinPage', 'requireGovernmentPage'],
|
|
109
110
|
'a new async router middleware appeared — give it a try/catch and add it here');
|
|
110
111
|
// The page gates must actually delegate (that is WHY they are safe).
|
|
111
|
-
for (const name of ['requireBuilderPage', 'requireGovernmentPage', 'requireBoardVotePage', 'requireCorePinPage'
|
|
112
|
+
for (const name of ['requireBuilderPage', 'requireGovernmentPage', 'requireBoardVotePage', 'requireCorePinPage']) {
|
|
112
113
|
const fn = src.slice(src.indexOf(`async function ${name}`));
|
|
113
114
|
assert.match(sliceFn(fn), /runPageGate\(/, `${name} must delegate to the guarded runPageGate`);
|
|
114
115
|
}
|
|
@@ -103,24 +103,8 @@ test('no projects renders a sentence, not an empty table', () => {
|
|
|
103
103
|
assert.match(costs.ledgerHtml(null), /No projects are hosted here yet/);
|
|
104
104
|
});
|
|
105
105
|
|
|
106
|
-
//
|
|
107
|
-
|
|
108
|
-
const html = read(path.join(HALL, 'fleet.html'));
|
|
109
|
-
assert.ok(html.indexOf('fleet-costs.js') !== -1 && html.indexOf('fleet-costs.js') < html.indexOf('/fleet.js'), 'fleet-costs.js loads first');
|
|
110
|
-
const js = read(path.join(HALL, 'fleet.js'));
|
|
111
|
-
assert.match(js, /\/provisioning\/fleet\/cost-ledger/);
|
|
112
|
-
assert.match(js, /status === 403[\s\S]{0,200}fl-sealed/, 'a refusal shows the sealed state');
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
test('the page gate is the atom the ledger route checks, and the nav mirrors its floor', () => {
|
|
116
|
-
const route = read(path.join(ROOT, 'modules', 'provisioning', 'routes', 'provisioning.js'));
|
|
117
|
-
assert.match(route, /router\.get\('\/provisioning\/fleet\/cost-ledger', auth\.requireBuilder, auth\.requirePermission\('provisioning\.fleet\.manage'\)/);
|
|
118
|
-
assert.match(read(path.join(ROOT, 'src', 'bongos', 'auth.js')), /requireFleetPage: Object\.freeze\(\{ permission: 'provisioning\.fleet\.manage'/);
|
|
119
|
-
// The nav is cosmetic (the page gate is the wall); 'government' is the metic floor.
|
|
120
|
-
const { byKey } = require(path.join(ROOT, 'modules', 'government', 'catalog.js'));
|
|
121
|
-
assert.equal(byKey('provisioning.fleet.manage').floor, 'metic');
|
|
122
|
-
assert.match(read(path.join(HALL, 'shell.js')), /href: '\/fleet', gate: 'government', module: 'provisioning'/);
|
|
123
|
-
});
|
|
106
|
+
// The page's wiring and its gate moved to tests/hall_money_page.mjs with the page
|
|
107
|
+
// (task 1005047): the ledger is the money page's #hosting section, and /fleet redirects.
|
|
124
108
|
|
|
125
109
|
// ── the owner's line on their own project page ───────────────────────────────
|
|
126
110
|
const HUB = read(path.join(ROOT, 'modules', 'public-landing', 'public', 'projects.html'));
|
package/tests/hall_loading.mjs
CHANGED
|
@@ -83,7 +83,7 @@ test('the page loaders step aside by themselves, and never show without :has()',
|
|
|
83
83
|
assert.match(STYLE, /\.hall-loading--wait, \.hall-loading--zones \{ display: none; \}/);
|
|
84
84
|
assert.match(STYLE, /@supports selector\(:has\(a\)\) \{\s*\.hall-loading--wait:not\(:has\(~ :not\(\[hidden\], script, template, style\)\)\) \{ display: flex; \}\s*\.hall-loading--zones:not\(:has\(~ :not\(\[hidden\]\) > :not\(\[hidden\], script, template, style\)\)\) \{ display: flex; \}\s*\}/);
|
|
85
85
|
// A page whose sections all start [hidden] carries the --wait loader FIRST in its main.
|
|
86
|
-
for (const page of ['board-room', 'deploy', '
|
|
86
|
+
for (const page of ['board-room', 'deploy', 'gate', 'government', 'money', 'project-settings', 'sessions']) {
|
|
87
87
|
const html = read(`${page}.html`);
|
|
88
88
|
const main = html.slice(html.indexOf('<main id="hall-main">'));
|
|
89
89
|
const first = main.replace(/<main id="hall-main">\s*(<!--[\s\S]*?-->\s*)*/, '');
|