@bongos/core 1.21.35 → 1.21.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 +100 -80
- package/clients/bongos-client/index.d.ts +3 -3
- package/docs/api/openapi.json +25 -35
- package/docs/api-reference.md +1 -1
- package/docs/copy-inventory.md +8 -8
- package/docs/copy-registry.json +8 -8
- package/docs/module-api-changelog.md +4 -0
- package/docs/page-inventory.json +4 -1
- package/docs/page-readings.json +569 -523
- package/modules/autonomy/matter-acts.js +41 -0
- package/modules/autonomy/routes/autonomy.js +2 -0
- package/modules/government/board.js +4 -0
- package/modules/government/db.js +14 -0
- package/modules/government/decision-board.js +90 -11
- package/modules/government/docket-vocab.js +5 -0
- package/modules/government/docket.js +11 -0
- package/modules/government/routes/government.js +2 -1
- package/modules/hall-ui/public/atlas.html +3 -3
- package/modules/hall-ui/public/blockers.html +3 -3
- package/modules/hall-ui/public/board-room.html +3 -3
- package/modules/hall-ui/public/city.html +3 -3
- package/modules/hall-ui/public/collab.html +3 -3
- package/modules/hall-ui/public/commands.html +3 -3
- package/modules/hall-ui/public/copy-desk.html +3 -3
- package/modules/hall-ui/public/craft-mode.js +44 -6
- package/modules/hall-ui/public/deploy.html +3 -3
- package/modules/hall-ui/public/diagrams.html +3 -3
- package/modules/hall-ui/public/drachmae.html +3 -3
- package/modules/hall-ui/public/fleet.html +3 -3
- package/modules/hall-ui/public/gate.html +3 -3
- package/modules/hall-ui/public/goal-map.html +3 -3
- package/modules/hall-ui/public/goals.html +3 -3
- package/modules/hall-ui/public/government.html +3 -3
- package/modules/hall-ui/public/idea.html +3 -3
- package/modules/hall-ui/public/ideas.html +3 -3
- package/modules/hall-ui/public/index.html +3 -3
- package/modules/hall-ui/public/modules.html +3 -3
- package/modules/hall-ui/public/primer.html +3 -3
- package/modules/hall-ui/public/profile.html +3 -3
- package/modules/hall-ui/public/project-settings.html +3 -3
- package/modules/hall-ui/public/ranks.html +3 -3
- package/modules/hall-ui/public/roadmap.html +3 -3
- package/modules/hall-ui/public/roster.html +3 -3
- package/modules/hall-ui/public/sessions.html +3 -3
- package/modules/hall-ui/public/settings.html +3 -3
- package/modules/hall-ui/public/street-card.js +62 -2
- package/modules/hall-ui/public/street-desk.js +101 -8
- package/modules/hall-ui/public/street-inside.js +6 -3
- package/modules/hall-ui/public/street.css +15 -0
- package/modules/hall-ui/public/street.html +3 -3
- package/modules/hall-ui/public/street.js +73 -4
- package/modules/hall-ui/public/street.states.json +124 -0
- package/modules/hall-ui/public/studio.html +3 -3
- package/modules/hall-ui/public/style.css +121 -2
- package/modules/hall-ui/public/task.html +3 -3
- package/modules/hall-ui/public/thinking.html +3 -3
- package/modules/hall-ui/public/tweak-editor.html +3 -3
- package/modules/hall-ui/public/watch.html +3 -3
- package/modules/hall-ui/public/work.html +3 -3
- package/modules/hall-ui/records/craft-mode.md +8 -0
- package/modules/ideas/governor-docket.js +91 -0
- package/modules/lifecycle/governor-docket.js +69 -0
- package/modules/lifecycle/matter-acts.js +63 -0
- package/modules/lifecycle/routes/done-when.js +26 -12
- package/modules/lifecycle/routes/gate-approvals.js +74 -59
- package/modules/lifecycle/routes/lifecycle.js +2 -0
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/release-notes.json +16 -0
- package/src/bongos/route-rank-check.js +2 -0
- package/src/bongos/routes/builders.js +56 -1
- package/src/module-api.js +1 -1
- package/tests/craft_mode_looks.mjs +170 -0
- package/tests/craft_mode_nav.mjs +7 -5
- package/tests/governor_matter_acts.mjs +241 -0
- package/tests/hall_street_desk.mjs +244 -4
- package/tests/hall_street_inside.mjs +3 -3
- package/tests/hall_tweak_editor.mjs +1 -1
|
@@ -225,9 +225,9 @@
|
|
|
225
225
|
|
|
226
226
|
<div id="toast" class="toast" role="status" aria-live="polite" data-visible="0"></div>
|
|
227
227
|
|
|
228
|
-
<script src="/builders/shell-trail.js?v=2026-10-03-
|
|
229
|
-
<script src="/builders/craft-mode.js?v=2026-10-03-
|
|
230
|
-
<script src="/builders/shell.js?v=2026-10-03-
|
|
228
|
+
<script src="/builders/shell-trail.js?v=2026-10-03-looks"></script>
|
|
229
|
+
<script src="/builders/craft-mode.js?v=2026-10-03-looks"></script>
|
|
230
|
+
<script src="/builders/shell.js?v=2026-10-03-looks"></script>
|
|
231
231
|
<script src="/builders/palette.js" defer></script>
|
|
232
232
|
<script src="/builders/dom-utils.js?v=2026-06-23-contrib"></script>
|
|
233
233
|
<!-- task 1003069 (R08) — the quick-filing form's routed result links a task
|
|
@@ -106,9 +106,9 @@
|
|
|
106
106
|
<script src="/builders/brand-apply.js?v=2026-06-27-r75" defer></script>
|
|
107
107
|
<!-- The app shell (sidebar + top bar + view router). Dependency-free; loaded
|
|
108
108
|
BEFORE builders.js so the chrome ids exist when events are wired. -->
|
|
109
|
-
<script src="/builders/shell-trail.js?v=2026-10-03-
|
|
110
|
-
<script src="/builders/craft-mode.js?v=2026-10-03-
|
|
111
|
-
<script src="/builders/shell.js?v=2026-10-03-
|
|
109
|
+
<script src="/builders/shell-trail.js?v=2026-10-03-looks" defer></script>
|
|
110
|
+
<script src="/builders/craft-mode.js?v=2026-10-03-looks" defer></script>
|
|
111
|
+
<script src="/builders/shell.js?v=2026-10-03-looks" defer></script>
|
|
112
112
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
113
113
|
<script src="/builders/palette.js" defer></script>
|
|
114
114
|
<!-- task 2166: the shared component kit (window.OTBKit) — pager/ledger/rail.
|
|
@@ -101,9 +101,9 @@
|
|
|
101
101
|
|
|
102
102
|
<div id="toast" class="toast" role="status" aria-live="polite" data-visible="0"></div>
|
|
103
103
|
|
|
104
|
-
<script src="/builders/shell-trail.js?v=2026-10-03-
|
|
105
|
-
<script src="/builders/craft-mode.js?v=2026-10-03-
|
|
106
|
-
<script src="/builders/shell.js?v=2026-10-03-
|
|
104
|
+
<script src="/builders/shell-trail.js?v=2026-10-03-looks"></script>
|
|
105
|
+
<script src="/builders/craft-mode.js?v=2026-10-03-looks"></script>
|
|
106
|
+
<script src="/builders/shell.js?v=2026-10-03-looks"></script>
|
|
107
107
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
108
108
|
<script src="/builders/palette.js" defer></script>
|
|
109
109
|
<script src="/builders/dom-utils.js?v=2026-06-23-contrib"></script>
|
|
@@ -115,9 +115,9 @@
|
|
|
115
115
|
|
|
116
116
|
<div id="toast" class="toast" role="status" aria-live="polite" data-visible="0"></div>
|
|
117
117
|
|
|
118
|
-
<script src="/builders/shell-trail.js?v=2026-10-03-
|
|
119
|
-
<script src="/builders/craft-mode.js?v=2026-10-03-
|
|
120
|
-
<script src="/builders/shell.js?v=2026-10-03-
|
|
118
|
+
<script src="/builders/shell-trail.js?v=2026-10-03-looks"></script>
|
|
119
|
+
<script src="/builders/craft-mode.js?v=2026-10-03-looks"></script>
|
|
120
|
+
<script src="/builders/shell.js?v=2026-10-03-looks"></script>
|
|
121
121
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
122
122
|
<script src="/builders/palette.js" defer></script>
|
|
123
123
|
<!-- the shared markdown reader (window.OTBMdReader) — primer.js renders through
|
|
@@ -206,9 +206,9 @@
|
|
|
206
206
|
|
|
207
207
|
<!-- The app shell (sidebar + top bar). Dependency-free; loaded FIRST so the
|
|
208
208
|
chrome exists before the page script runs. -->
|
|
209
|
-
<script src="/builders/shell-trail.js?v=2026-10-03-
|
|
210
|
-
<script src="/builders/craft-mode.js?v=2026-10-03-
|
|
211
|
-
<script src="/builders/shell.js?v=2026-10-03-
|
|
209
|
+
<script src="/builders/shell-trail.js?v=2026-10-03-looks"></script>
|
|
210
|
+
<script src="/builders/craft-mode.js?v=2026-10-03-looks"></script>
|
|
211
|
+
<script src="/builders/shell.js?v=2026-10-03-looks"></script>
|
|
212
212
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
213
213
|
<script src="/builders/palette.js" defer></script>
|
|
214
214
|
<!-- shared frontend toolkit (window.OTB) — loaded before profile.js, which pulls from it. -->
|
|
@@ -58,9 +58,9 @@
|
|
|
58
58
|
|
|
59
59
|
<div id="toast" class="toast" role="status" aria-live="polite" data-visible="0"></div>
|
|
60
60
|
|
|
61
|
-
<script src="/builders/shell-trail.js?v=2026-10-03-
|
|
62
|
-
<script src="/builders/craft-mode.js?v=2026-10-03-
|
|
63
|
-
<script src="/builders/shell.js?v=2026-10-03-
|
|
61
|
+
<script src="/builders/shell-trail.js?v=2026-10-03-looks"></script>
|
|
62
|
+
<script src="/builders/craft-mode.js?v=2026-10-03-looks"></script>
|
|
63
|
+
<script src="/builders/shell.js?v=2026-10-03-looks"></script>
|
|
64
64
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
65
65
|
<script src="/builders/palette.js" defer></script>
|
|
66
66
|
<script src="/builders/dom-utils.js?v=2026-06-16-gate"></script>
|
|
@@ -77,9 +77,9 @@
|
|
|
77
77
|
|
|
78
78
|
<!-- The app shell (sidebar + top bar). Dependency-free; loaded FIRST so the
|
|
79
79
|
chrome exists before the page script runs. -->
|
|
80
|
-
<script src="/builders/shell-trail.js?v=2026-10-03-
|
|
81
|
-
<script src="/builders/craft-mode.js?v=2026-10-03-
|
|
82
|
-
<script src="/builders/shell.js?v=2026-10-03-
|
|
80
|
+
<script src="/builders/shell-trail.js?v=2026-10-03-looks"></script>
|
|
81
|
+
<script src="/builders/craft-mode.js?v=2026-10-03-looks"></script>
|
|
82
|
+
<script src="/builders/shell.js?v=2026-10-03-looks"></script>
|
|
83
83
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
84
84
|
<script src="/builders/palette.js" defer></script>
|
|
85
85
|
<!-- shared frontend toolkit (window.OTB) — loaded before ranks.js, which pulls from it. -->
|
|
@@ -41,9 +41,9 @@
|
|
|
41
41
|
|
|
42
42
|
<div id="toast" class="toast" role="status" aria-live="polite" data-visible="0"></div>
|
|
43
43
|
|
|
44
|
-
<script src="/builders/shell-trail.js?v=2026-10-03-
|
|
45
|
-
<script src="/builders/craft-mode.js?v=2026-10-03-
|
|
46
|
-
<script src="/builders/shell.js?v=2026-10-03-
|
|
44
|
+
<script src="/builders/shell-trail.js?v=2026-10-03-looks"></script>
|
|
45
|
+
<script src="/builders/craft-mode.js?v=2026-10-03-looks"></script>
|
|
46
|
+
<script src="/builders/shell.js?v=2026-10-03-looks"></script>
|
|
47
47
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
48
48
|
<script src="/builders/palette.js" defer></script>
|
|
49
49
|
<script src="/builders/dom-utils.js?v=2026-06-14-domutils"></script>
|
|
@@ -53,9 +53,9 @@
|
|
|
53
53
|
|
|
54
54
|
<!-- The app shell (sidebar + top bar). Dependency-free; loaded FIRST so the
|
|
55
55
|
chrome exists before the page script runs. -->
|
|
56
|
-
<script src="/builders/shell-trail.js?v=2026-10-03-
|
|
57
|
-
<script src="/builders/craft-mode.js?v=2026-10-03-
|
|
58
|
-
<script src="/builders/shell.js?v=2026-10-03-
|
|
56
|
+
<script src="/builders/shell-trail.js?v=2026-10-03-looks"></script>
|
|
57
|
+
<script src="/builders/craft-mode.js?v=2026-10-03-looks"></script>
|
|
58
|
+
<script src="/builders/shell.js?v=2026-10-03-looks"></script>
|
|
59
59
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
60
60
|
<script src="/builders/palette.js" defer></script>
|
|
61
61
|
<!-- shared frontend toolkit (window.OTB — rank labels, number formats) + the
|
|
@@ -111,9 +111,9 @@
|
|
|
111
111
|
|
|
112
112
|
<!-- The app shell (sidebar + top bar). Dependency-free; loaded FIRST so the
|
|
113
113
|
chrome exists before the page script runs. -->
|
|
114
|
-
<script src="/builders/shell-trail.js?v=2026-10-03-
|
|
115
|
-
<script src="/builders/craft-mode.js?v=2026-10-03-
|
|
116
|
-
<script src="/builders/shell.js?v=2026-10-03-
|
|
114
|
+
<script src="/builders/shell-trail.js?v=2026-10-03-looks"></script>
|
|
115
|
+
<script src="/builders/craft-mode.js?v=2026-10-03-looks"></script>
|
|
116
|
+
<script src="/builders/shell.js?v=2026-10-03-looks"></script>
|
|
117
117
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
118
118
|
<script src="/builders/palette.js" defer></script>
|
|
119
119
|
<!-- shared frontend toolkit (window.OTB) — loaded BEFORE sessions.js so it can pull from it. -->
|
|
@@ -435,9 +435,9 @@
|
|
|
435
435
|
|
|
436
436
|
<!-- The app shell (sidebar + top bar). Dependency-free; loaded FIRST so the
|
|
437
437
|
chrome exists before the page scripts run. -->
|
|
438
|
-
<script src="/builders/shell-trail.js?v=2026-10-03-
|
|
439
|
-
<script src="/builders/craft-mode.js?v=2026-10-03-
|
|
440
|
-
<script src="/builders/shell.js?v=2026-10-03-
|
|
438
|
+
<script src="/builders/shell-trail.js?v=2026-10-03-looks"></script>
|
|
439
|
+
<script src="/builders/craft-mode.js?v=2026-10-03-looks"></script>
|
|
440
|
+
<script src="/builders/shell.js?v=2026-10-03-looks"></script>
|
|
441
441
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
442
442
|
<script src="/builders/palette.js" defer></script>
|
|
443
443
|
<!-- shared frontend toolkit (window.OTB) — loaded before consuming IIFEs. -->
|
|
@@ -512,6 +512,60 @@
|
|
|
512
512
|
ACT_ROUTES.backup = { backup: function () { return post('/backup/trigger', {}); } };
|
|
513
513
|
ACT_ROUTES.invite = { invite: function (id, inp) { return str(inp.option).trim() ? post('/access-requests/invite', { github_login: str(inp.option).trim() }) : null; } };
|
|
514
514
|
ACT_ROUTES.autonomy_fence = ACT_ROUTES.autobongos_fence;
|
|
515
|
+
// The Planning desks (task 1004560). A blocker is decided by one of its chips,
|
|
516
|
+
// whose words are the resolution note; a criterion proposal ratifies in one
|
|
517
|
+
// tap; a Full Idea the board carried becomes a goal in the version its chip names.
|
|
518
|
+
ACT_ROUTES.blockers = {
|
|
519
|
+
decide: function (id, inp) { return str(inp.option).trim() ? post('/blockers/' + id + '/resolve', { resolution_note: 'Decided on the floor desk: ' + str(inp.option).trim() + '.' }) : null; },
|
|
520
|
+
};
|
|
521
|
+
// task 1004561: a builder's monthly limit (PATCH /builders/:id/budget; the
|
|
522
|
+
// 'none' chip clears it), and a sign-off undone (POST /done-when/:id/unsatisfy,
|
|
523
|
+
// the chip's words as the reason it logs).
|
|
524
|
+
ACT_ROUTES.builder_budget = {
|
|
525
|
+
budget: function (id, inp) { return inp.option ? call('PATCH', '/builders/' + id + '/budget', { monthly_budget_usd: inp.option === 'none' ? null : Number(inp.option) }) : null; },
|
|
526
|
+
};
|
|
527
|
+
ACT_ROUTES.signed_criterion = { unsign: function (id, inp) { return post('/done-when/' + id + '/unsatisfy', { reason: str(inp.label) || 'undone on the floor desk' }); } };
|
|
528
|
+
// The same acts at a building a sitting decides (task 1004561): filed as the
|
|
529
|
+
// building's matter, which carries the act out once it passes. Each returns
|
|
530
|
+
// { title, action } for POST /government/board/matters.
|
|
531
|
+
var COUNCIL_ACTS = {
|
|
532
|
+
autobongos_fence: {
|
|
533
|
+
switch_on: function () { return { title: 'Switch unattended building on', action: { type: 'switch_on' } }; },
|
|
534
|
+
switch_off: function () { return { title: 'Switch unattended building off', action: { type: 'switch_off' } }; },
|
|
535
|
+
allow: function (id, inp) { return inp.option ? { title: 'Allow ' + str(inp.label || 'goal ' + inp.option) + ' to build unattended', action: { type: 'allow_goal', goal_id: Number(inp.option) } } : null; },
|
|
536
|
+
},
|
|
537
|
+
criteria_uat: { force: function (id, inp, who) { return { title: 'Sign off: ' + who, action: { type: 'satisfy_criterion', criterion_id: Number(id) } }; } },
|
|
538
|
+
override_requests: { release: function (id, inp, who) { return { title: 'Release past its check: ' + who, action: { type: 'approve_override', request_id: Number(id) } }; } },
|
|
539
|
+
gate_approvals: { release: function (id, inp, who) { return { title: 'Release from the gate: ' + who, action: { type: 'approve_gate', pr: Number(id) } }; } },
|
|
540
|
+
builder_budget: {
|
|
541
|
+
budget: function (id, inp, who) { return inp.option ? { title: who + ': ' + str(inp.label || inp.option), action: { type: 'set_budget', builder_id: Number(id), monthly_usd: inp.option === 'none' ? null : Number(inp.option) } } : null; },
|
|
542
|
+
},
|
|
543
|
+
};
|
|
544
|
+
COUNCIL_ACTS.autonomy_fence = COUNCIL_ACTS.autobongos_fence;
|
|
545
|
+
COUNCIL_ACTS.autonomy_goal = { allow: COUNCIL_ACTS.autobongos_fence.allow };
|
|
546
|
+
function councilRequest(s, key, inp) {
|
|
547
|
+
var make = COUNCIL_ACTS[s.kind] && COUNCIL_ACTS[s.kind][key];
|
|
548
|
+
var m = make ? make(decoded(s.id), inp, str(s.who) || 'a matter') : null;
|
|
549
|
+
return m ? post('/government/board/matters', { area: s.council, title: str(m.title).slice(0, 200), action: m.action }) : null;
|
|
550
|
+
}
|
|
551
|
+
ACT_ROUTES.criterion_proposal = { ratify: function (id) { return post('/inbox/' + id + '/ratify', { notes_md: 'Ratified on the floor desk.' }); } };
|
|
552
|
+
ACT_ROUTES.full_idea = {
|
|
553
|
+
ratify_goal: function (id, inp) { return inp.option ? post('/inbox/' + id + '/ratify-goal', { target_version: str(inp.option), notes_md: 'Ratified on the floor desk.' }) : null; },
|
|
554
|
+
};
|
|
555
|
+
// The Priorities desk's save (task 1004560): the new order goes to
|
|
556
|
+
// POST /goals/reorder, or, where the decision table puts Planning to a sitting,
|
|
557
|
+
// it is filed as a Planning matter for the sitting to decide. save is the desk
|
|
558
|
+
// model's { set, ids, names, council }.
|
|
559
|
+
function orderRequest(save) {
|
|
560
|
+
var s = save || {};
|
|
561
|
+
var ids = (s.ids || []).map(Number).filter(function (n) { return n > 0 && Math.floor(n) === n; });
|
|
562
|
+
if (!ids.length) return null;
|
|
563
|
+
if (s.council) {
|
|
564
|
+
var lines = (s.names || []).map(function (n, i) { return (i + 1) + '. ' + str(n); });
|
|
565
|
+
return post('/government/board/matters', { area: 'planning', title: 'A new order for the goals', detail_md: 'Proposed on the floor desk, for version ' + str(s.set) + ':\n\n' + lines.join('\n') });
|
|
566
|
+
}
|
|
567
|
+
return post('/goals/reorder', { version_id: str(s.set), ordered_ids: ids });
|
|
568
|
+
}
|
|
515
569
|
function decoded(encoded) { return decodeURIComponent(encoded); }
|
|
516
570
|
// input: { reason, section } for object; { text } for revise.
|
|
517
571
|
function request(cv, key, input) {
|
|
@@ -541,6 +595,7 @@
|
|
|
541
595
|
if (key === 'fine') return post('/goals/' + enc(s.goalId) + '/requests/' + enc(s.id) + '/respond', { action: 'approve' });
|
|
542
596
|
if (key === 'refuse') return post('/goals/' + enc(s.goalId) + '/requests/' + enc(s.id) + '/respond', { action: 'deny' });
|
|
543
597
|
}
|
|
598
|
+
if (s.council && COUNCIL_ACTS[s.kind] && COUNCIL_ACTS[s.kind][key]) return councilRequest(s, key, inp);
|
|
544
599
|
if (ACT_ROUTES[s.kind] && ACT_ROUTES[s.kind][key]) return ACT_ROUTES[s.kind][key](enc(s.id), inp);
|
|
545
600
|
if (s.kind === 'override_requests' && key === 'release') return post('/override-requests/' + enc(s.id) + '/decide', { decision: 'approve' });
|
|
546
601
|
if (s.kind === 'gate_approvals' && key === 'release') return post('/gate-approvals/' + enc(s.id) + '/approve', {});
|
|
@@ -565,6 +620,9 @@
|
|
|
565
620
|
var r = res || {};
|
|
566
621
|
var who = cv && cv.subject && cv.subject.who ? cv.subject.who : 'They';
|
|
567
622
|
var b = cv ? cv.building : null;
|
|
623
|
+
if (cv && cv.subject && cv.subject.council && COUNCIL_ACTS[cv.subject.kind] && COUNCIL_ACTS[cv.subject.kind][key]) {
|
|
624
|
+
return { toast: 'Sent to the council. It is carried out when they pass it.', building: b, kind: 'light', close: false };
|
|
625
|
+
}
|
|
568
626
|
if (key === 'for') {
|
|
569
627
|
if (r.item_closed && r.outcome === 'passed') return { toast: 'Passed. It is in force from today.', building: b, kind: 'rise', close: false };
|
|
570
628
|
if (r.item_closed) return { toast: 'The sitting closed: it went back to its author.', building: b, kind: 'settle', close: false };
|
|
@@ -594,8 +652,10 @@
|
|
|
594
652
|
tier: '{who} has a new tier.', deactivate: '{who} is deactivated.', give: 'Rank given.', take: 'Rank taken back.',
|
|
595
653
|
check: 'Checking it. The answer lands on this floor in a couple of minutes; nothing moves.', take_core: 'Taking it. The core moves on the runner\'s next tick.',
|
|
596
654
|
rot: 'Rot timer set.', module_on: 'Turned on.', module_off: 'Turned off.', backup: 'Backing up now.', invite: '{who} is invited.',
|
|
655
|
+
decide: 'Decided. The work it held moves again.', ratify: 'Ratified. The promise is on its version.', ratify_goal: 'Ratified. It is a goal now.',
|
|
656
|
+
budget: '{who} has a new monthly limit.', unsign: 'Undone. The promise is open again.',
|
|
597
657
|
};
|
|
598
|
-
var ACT_KINDS = { check: 'light', rot: 'light', module_on: 'rise', module_off: 'settle', backup: 'light', confirm: 'settle', dispute: 'settle', fix: 'rise', remove: 'settle', keep: 'settle', signoff: 'rise', force: 'rise', switch_on: 'rise', switch_off: 'settle', allow: 'rise', disallow: 'settle', first: 'light', pause: 'settle', resume: 'rise', tier: 'light', deactivate: 'settle', give: 'light', take: 'settle' };
|
|
658
|
+
var ACT_KINDS = { budget: 'light', unsign: 'settle', decide: 'rise', ratify: 'rise', ratify_goal: 'rise', check: 'light', rot: 'light', module_on: 'rise', module_off: 'settle', backup: 'light', confirm: 'settle', dispute: 'settle', fix: 'rise', remove: 'settle', keep: 'settle', signoff: 'rise', force: 'rise', switch_on: 'rise', switch_off: 'settle', allow: 'rise', disallow: 'settle', first: 'light', pause: 'settle', resume: 'rise', tier: 'light', deactivate: 'settle', give: 'light', take: 'settle' };
|
|
599
659
|
|
|
600
660
|
// A refused act, in words. The server's own message wins when it has one.
|
|
601
661
|
var REFUSALS = {
|
|
@@ -786,7 +846,7 @@
|
|
|
786
846
|
|
|
787
847
|
var api = {
|
|
788
848
|
API: API, SECTIONS: SECTIONS, needsRoom: needsRoom, itemIdOf: itemIdOf, subjectKind: subjectKind,
|
|
789
|
-
model: model, actsCard: actsCard, request: request, check: check, answer: answer, refusal: refusal, render: render,
|
|
849
|
+
model: model, actsCard: actsCard, request: request, orderRequest: orderRequest, check: check, answer: answer, refusal: refusal, render: render,
|
|
790
850
|
memberWords: memberWords, windowWords: windowWords,
|
|
791
851
|
// the wording change, for a drafted amendment's struck and inserted text (task 1004530)
|
|
792
852
|
change: changeOf,
|
|
@@ -38,10 +38,20 @@
|
|
|
38
38
|
// GovDesk.fit(s, n, words) the line formatter
|
|
39
39
|
// GovDesk.breaks(desk) [] when the desk keeps the line rule
|
|
40
40
|
// GovDesk.todayPips(n) the street header's meter
|
|
41
|
+
// GovDesk.moved(order, key, by) a desk order with one row moved
|
|
41
42
|
// GovDesk.LIMITS, ACT_WORDS, CHIPS, NOUNS, CLEAR
|
|
42
43
|
// A desk row is { key, matter, ini, name, fact, facts[], actions[{ key, label,
|
|
43
44
|
// tone, go, ask }], chips { for, ask, options[{ key, label, input }] } | null,
|
|
44
45
|
// wait, needs, card }: `card` is the GovMatterCard model the act is sent with.
|
|
46
|
+
//
|
|
47
|
+
// THE PLANNING DESKS (task 1004560). A row may carry `pips` [{ key, on }]: a
|
|
48
|
+
// goal's promises kept of total, or a vote's seats (filled = a yes). A row of an
|
|
49
|
+
// ordered set (the Priorities desk: `order` is its version) is moved with its
|
|
50
|
+
// two arrows; input.order is the order the viewer has made, and a changed order
|
|
51
|
+
// gives the desk a `save` { line, label, set, ids, names, council }: the
|
|
52
|
+
// council when the decision table puts Planning to a sitting that cannot act
|
|
53
|
+
// alone, so the save files a Planning matter instead of setting the order. A
|
|
54
|
+
// blocker's chips stand open (`show`): deciding it IS picking one.
|
|
45
55
|
|
|
46
56
|
(function (root) {
|
|
47
57
|
'use strict';
|
|
@@ -54,7 +64,7 @@
|
|
|
54
64
|
nameWords: 3, name: 20, fact: 26, facts: 3, factLen: 24, actions: 2,
|
|
55
65
|
tiles: 3, tileValue: 8, tileWords: 2, tileLabel: 14,
|
|
56
66
|
status: 44, clearLine: 30, clearSub: 40, record: 4, recordLen: 30,
|
|
57
|
-
chips: 5, chip: 16, todayTarget: 10,
|
|
67
|
+
chips: 5, chip: 16, todayTarget: 10, pips: 12, saveLine: 48,
|
|
58
68
|
});
|
|
59
69
|
|
|
60
70
|
// One line, never more: the house rule for every row, tile and status. A cap
|
|
@@ -105,15 +115,29 @@
|
|
|
105
115
|
switch_on: 'switch on', switch_off: 'switch off', allow: 'allow', disallow: 'disallow', first: 'first',
|
|
106
116
|
pause: 'pause', resume: 'resume', tier: 'tier', deactivate: 'deactivate', give: 'give', take: 'take back',
|
|
107
117
|
check: 'check', take_core: 'take it', rot: 'set', module_on: 'turn on', module_off: 'turn off', backup: 'back up', invite: 'invite', open: 'open',
|
|
118
|
+
// the Planning desks (task 1004560)
|
|
119
|
+
decide: 'decide', ratify: 'ratify', ratify_goal: 'make goal', up: 'move up', down: 'move down',
|
|
120
|
+
// task 1004561: a builder's monthly limit, and a sign-off undone
|
|
121
|
+
budget: 'set limit', unsign: 'undo',
|
|
108
122
|
});
|
|
109
123
|
// What a row's chips ask, per act (a reason or an option is one tap, never text).
|
|
110
|
-
const ASKS = Object.freeze({ check: 'check', take_core: 'move to', rot: 'stale after', module_off: 'sure', invite: 'their GitHub name', object: 'why', force: 'why', switch_off: 'why', pause: 'why', deactivate: 'why', signoff: 'confirm', allow: 'which goal', tier: 'which tier', give: 'to whom', take: 'from whom' });
|
|
124
|
+
const ASKS = Object.freeze({ budget: 'monthly limit', unsign: 'why', decide: 'pick one', ratify_goal: 'which version', check: 'check', take_core: 'move to', rot: 'stale after', module_off: 'sure', invite: 'their GitHub name', object: 'why', force: 'why', switch_off: 'why', pause: 'why', deactivate: 'why', signoff: 'confirm', allow: 'which goal', tier: 'which tier', give: 'to whom', take: 'from whom' });
|
|
111
125
|
// How a floor counts rows nobody is waiting on (desk rows), by its desk.
|
|
112
126
|
const DESK_NOUNS = Object.freeze({
|
|
113
127
|
'people.builders': 'builders', 'people.ranks': 'ranks', 'disputes.confirmed': 'to fix',
|
|
114
128
|
'automation.switch': 'switch', 'automation.goals': 'allowed', 'automation.runners': 'runners',
|
|
115
129
|
'people.invite': 'invites', 'release.core': 'update', 'rules.settings': 'settings', 'rules.modules': 'modules', 'treasury.backup': 'backups',
|
|
130
|
+
'planning.order': 'goals in order', 'planning.ratify': 'to ratify',
|
|
131
|
+
'treasury.budgets': 'builders', 'review.signed': 'signed off',
|
|
116
132
|
});
|
|
133
|
+
// Is this building decided by a sitting that cannot act alone (task 1004561)?
|
|
134
|
+
// The decision table's row, as the docket's buildings carry it: then a desk act
|
|
135
|
+
// is filed as the building's matter, and carried out once the sitting passes it.
|
|
136
|
+
function councilOf(docket, key) {
|
|
137
|
+
const b = docket && Array.isArray(docket.buildings) ? docket.buildings.find((x) => x && x.key === key) : null;
|
|
138
|
+
const d = b && b.decision ? b.decision : null;
|
|
139
|
+
return !!(d && d.sitting && ['decide', 'first'].indexOf(d.rule) < 0);
|
|
140
|
+
}
|
|
117
141
|
// An objection's reason as one tap: the five sections the server accepts
|
|
118
142
|
// (street-card.js SECTIONS), each in at most 16 characters.
|
|
119
143
|
const CHIPS = Object.freeze({ scope: 'what it changes', purpose: 'its purpose', why_matters: 'why it matters', fit: 'how it fits', success: 'how to measure' });
|
|
@@ -185,6 +209,8 @@
|
|
|
185
209
|
});
|
|
186
210
|
}
|
|
187
211
|
const cv = C && C.model ? C.model({ docket: ctx.docket, key: m.id, room: ctx.room, constitution: ctx.constitution, now: now, viewerId: ctx.viewerId }) : null;
|
|
212
|
+
// a release held for a sitting goes to it as a matter (task 1004561)
|
|
213
|
+
if (cv && cv.subject && cv.subject.itemId == null) cv.subject.council = councilOf(ctx.docket, cv.building) ? cv.building : null;
|
|
188
214
|
const actions = [];
|
|
189
215
|
let chips = null;
|
|
190
216
|
if (cv && !cv.readOnly && !cv.loading) {
|
|
@@ -200,6 +226,8 @@
|
|
|
200
226
|
return {
|
|
201
227
|
key: str(m.id), matter: str(m.id), ini: initials(name), name: name, fact: fact, facts: facts,
|
|
202
228
|
actions: actions, chips: chips, choices: chips ? { [chips.for]: chips } : {}, wait: wait, needs: stateOf(m) === 'needs', source: m.source, opened: m.opened_at || null, card: cv,
|
|
229
|
+
// a vote shows its seats: one pip each, filled for a yes
|
|
230
|
+
pips: cv && Array.isArray(cv.seats) && cv.seats.length ? cv.seats.slice(0, LIMITS.pips).map((s, i) => ({ key: 's' + i, on: s.pos === 'for' })) : null,
|
|
203
231
|
};
|
|
204
232
|
}
|
|
205
233
|
|
|
@@ -210,6 +238,8 @@
|
|
|
210
238
|
// goes to the matter's own page (a sign-off that needs a recording).
|
|
211
239
|
function actedRow(acts, card, ctx) {
|
|
212
240
|
const titles = new Map((ctx.goals || []).map((g) => [str(g.id), str(g.title || 'goal ' + g.id)]));
|
|
241
|
+
// an act at a building a sitting decides is filed as its matter (task 1004561)
|
|
242
|
+
if (card && card.subject) card.subject.council = councilOf(ctx.docket, card.building) ? card.building : null;
|
|
213
243
|
const actions = [];
|
|
214
244
|
const choices = {};
|
|
215
245
|
acts.forEach((a) => {
|
|
@@ -232,7 +262,9 @@
|
|
|
232
262
|
actions.push({ key: a.key, label: ACT_WORDS[word], tone: actions.length ? 'quiet' : 'primary', go: goes ? card.href : null, ask: ask });
|
|
233
263
|
});
|
|
234
264
|
const first = actions.find((a) => a.ask);
|
|
235
|
-
|
|
265
|
+
// deciding a blocker is picking one of its options: its chips stand open
|
|
266
|
+
const show = first && first.key === 'decide' && choices.decide ? 'decide' : null;
|
|
267
|
+
return { actions: actions, chips: first ? choices[first.key] : null, choices: choices, show: show, wait: actions.length ? '' : 'not from here', card: card };
|
|
236
268
|
}
|
|
237
269
|
|
|
238
270
|
// A desk row (task 1004559): something on this floor the viewer may act on that
|
|
@@ -253,6 +285,8 @@
|
|
|
253
285
|
return Object.assign(actedRow(d.acts || [], card || { href: null }, ctx), {
|
|
254
286
|
key: str(d.id), matter: str(d.id), ini: initials(name), name: name, fact: fit(d.fact, LIMITS.fact), facts: facts,
|
|
255
287
|
needs: d.needs === true, source: d.desk, opened: d.opened_at || null, desk: true, tool: d.tool === true, over: d.over || null,
|
|
288
|
+
order: d.set || null, goalId: d.set && ref.id != null ? str(ref.id) : null, full: full,
|
|
289
|
+
pips: d.pips ? Array.from({ length: Math.min(d.pips.of, LIMITS.pips) }, (_, i) => ({ key: 'p' + i, on: i < d.pips.on })) : null,
|
|
256
290
|
});
|
|
257
291
|
}
|
|
258
292
|
// The desk rows of one floor: those of the desk its PLAN entry names.
|
|
@@ -292,13 +326,27 @@
|
|
|
292
326
|
const spec = plan.floors[floor];
|
|
293
327
|
const fl = I.floorFor(spec, { key: o.key, docket: docket, goals: o.goals || [], now: o.now || 0 });
|
|
294
328
|
const ctx = { room: o.room, constitution: o.constitution, now: o.now || 0, viewerId: o.viewerId, done: o.done, goals: o.goals || [] };
|
|
295
|
-
|
|
329
|
+
let rows = docket ? rowsFor(o.key, floor, docket, ctx) : [];
|
|
330
|
+
// the Priorities desk: the ordered rows in the order the viewer has made
|
|
331
|
+
const ordered = rows.filter((r) => r.order);
|
|
332
|
+
let save = null;
|
|
333
|
+
if (ordered.length > 1) {
|
|
334
|
+
const base = ordered.map((r) => r.key);
|
|
335
|
+
const want = Array.isArray(o.order) ? o.order.map(str) : null;
|
|
336
|
+
const mine = want && want.length === base.length && base.every((k) => want.indexOf(k) >= 0) ? want : base;
|
|
337
|
+
const sorted = mine.map((k) => ordered.find((r) => r.key === k));
|
|
338
|
+
sorted.forEach((r, i) => { r.pos = i + 1; r.top = i === 0; r.bottom = i === sorted.length - 1; });
|
|
339
|
+
rows = rows.filter((r) => !r.order).concat(sorted);
|
|
340
|
+
if (mine.join('|') !== base.join('|')) save = saveOf(docket, o.key, sorted);
|
|
341
|
+
}
|
|
296
342
|
const bind = spec[2] || {};
|
|
297
343
|
const src = bind.source ? bind.source : bind.floor === 'planning.ideas' ? 'idea' : floor === 0 ? 'board' : null;
|
|
298
344
|
const needs = rows.filter((r) => r.needs);
|
|
299
345
|
const noun = NOUNS[src] || 'open';
|
|
300
346
|
// rows nobody waits on: 'moving' for matters, the desk's own noun for desk rows
|
|
301
|
-
|
|
347
|
+
// (rows waiting on no one, when all of them are desk rows, count in their desk's noun: 'to ratify')
|
|
348
|
+
const rest = rows.filter((r) => !r.needs && !r.tool);
|
|
349
|
+
const moving = rest.length && rest.every((r) => r.desk) ? (DESK_NOUNS[rest[0].source] || 'here') : 'moving';
|
|
302
350
|
const counted = rows.filter((r) => !r.tool);
|
|
303
351
|
const oldestOf = (list) => list.reduce((a, r) => (r.opened && (!a || Date.parse(r.opened) < Date.parse(a)) ? r.opened : a), null);
|
|
304
352
|
const cleared = !!o.cleared && rows.length === 0;
|
|
@@ -320,7 +368,13 @@
|
|
|
320
368
|
const words = str(l).replace(/\s+/g, ' ').trim().split(' ').slice(0, LIMITS.tileWords).join(' ').replace(/[,.;:·-]+$/, '');
|
|
321
369
|
tiles.push({ key: 't' + tiles.length, v: fit(val, LIMITS.tileValue), l: fit(words, LIMITS.tileLabel) });
|
|
322
370
|
};
|
|
323
|
-
if (
|
|
371
|
+
if (ordered.length > 1) {
|
|
372
|
+
// the order's one number: the share of its goals' promises kept
|
|
373
|
+
const on = ordered.reduce((a, r) => a + (r.pips || []).filter((p) => p.on).length, 0);
|
|
374
|
+
const of = ordered.reduce((a, r) => a + (r.pips || []).length, 0);
|
|
375
|
+
tile(needs.length, noun);
|
|
376
|
+
if (of) tile(Math.round((100 * on) / of) + '%', 'promises kept');
|
|
377
|
+
} else if (rows.length) { tile(needs.length, noun); tile(counted.length - needs.length, moving); }
|
|
324
378
|
else if (fl.count) tile(fl.count, str(fl.line).replace(/^[$]?[0-9][0-9,.%]*\s*/, '') || 'on this floor');
|
|
325
379
|
tile(history.length, 'on record');
|
|
326
380
|
const record = (o.mine || []).map((t, i) => ({ key: 'm' + i, text: fit(t + ' · now', LIMITS.recordLen), mine: true }))
|
|
@@ -330,13 +384,50 @@
|
|
|
330
384
|
key: o.key + ':' + floor, building: o.key, floor: floor, name: spec[0], sym: o.sym || { d: '', f: '' },
|
|
331
385
|
status: fit(status, LIMITS.status), hot: hot,
|
|
332
386
|
tiles: tiles.slice(0, LIMITS.tiles), rows: rows,
|
|
333
|
-
quiet: quiet, cleared: cleared,
|
|
387
|
+
quiet: quiet, cleared: cleared, save: save,
|
|
334
388
|
clearLine: fit(cleared ? (CLEAR[src] || 'Floor clear') : 'Nothing needs you here', LIMITS.clearLine),
|
|
335
389
|
clearSub: fit(cleared ? 'lit up · ' + (o.today || 0) + ' decided today' : fl.line, LIMITS.clearSub),
|
|
336
390
|
record: record,
|
|
337
391
|
};
|
|
338
392
|
}
|
|
339
393
|
|
|
394
|
+
// ---------- the Priorities desk's save ----------
|
|
395
|
+
// Who decides the order: the decision table's Planning row, as the docket's
|
|
396
|
+
// buildings carry it. A sitting whose rule cannot act alone means the save
|
|
397
|
+
// files a matter for it; the yes it needs is read from its seats.
|
|
398
|
+
function yesNeeded(rule, n) {
|
|
399
|
+
if (!(n > 0)) return null;
|
|
400
|
+
if (rule === 'majority') return Math.floor(n / 2) + 1;
|
|
401
|
+
if (rule === 'unanimous') return n;
|
|
402
|
+
if (rule === 'signoff') return 1;
|
|
403
|
+
return null;
|
|
404
|
+
}
|
|
405
|
+
function saveOf(docket, key, sorted) {
|
|
406
|
+
const b = docket && Array.isArray(docket.buildings) ? docket.buildings.find((x) => x && x.key === key) : null;
|
|
407
|
+
const d = b && b.decision ? b.decision : null;
|
|
408
|
+
const council = councilOf(docket, key);
|
|
409
|
+
const yes = council ? yesNeeded(d.rule, Number(b.holder_count)) : null;
|
|
410
|
+
const line = !council ? 'new order · saved for everyone'
|
|
411
|
+
: d.rule === 'consent' ? 'new order · to the council · unless one objects'
|
|
412
|
+
: 'new order · goes to the council' + (yes ? ' · ' + yes + ' yes needed' : '');
|
|
413
|
+
// what the toast says once it is sent: whole sentences, never the line cut up
|
|
414
|
+
const said = !council ? 'Saved. Goals are worked in this order now.'
|
|
415
|
+
: d.rule === 'consent' ? 'The new order is with the council. It passes unless someone objects.'
|
|
416
|
+
: 'The new order is with the council.' + (yes ? ' It needs ' + yes + ' yes.' : '');
|
|
417
|
+
return {
|
|
418
|
+
line: fit(line, LIMITS.saveLine), label: council ? 'send to council' : 'save order', council: council, said: said,
|
|
419
|
+
set: sorted[0].order, ids: sorted.map((r) => r.goalId), names: sorted.map((r) => r.full || r.name),
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
// An order with one row moved one place (by -1 up, +1 down); the ends hold.
|
|
423
|
+
function moved(order, key, by) {
|
|
424
|
+
const o = (order || []).slice();
|
|
425
|
+
const i = o.indexOf(key), j = i + by;
|
|
426
|
+
if (i < 0 || j < 0 || j >= o.length) return o;
|
|
427
|
+
o[i] = o[j]; o[j] = key;
|
|
428
|
+
return o;
|
|
429
|
+
}
|
|
430
|
+
|
|
340
431
|
// ---------- the rule as a checker ----------
|
|
341
432
|
function breaks(desk) {
|
|
342
433
|
const out = [];
|
|
@@ -364,7 +455,9 @@
|
|
|
364
455
|
if ((!c.field && !c.options.length) || c.options.length > LIMITS.chips || c.options.some((x) => !x.label || x.label.length > LIMITS.chip)) bad('chips', c.options.map((x) => x.label));
|
|
365
456
|
});
|
|
366
457
|
if (r.actions.some((a) => a.ask && !(r.choices || {})[a.key])) bad('an ask without its own chips', r.name);
|
|
458
|
+
if (r.pips && r.pips.length > LIMITS.pips) bad('more than twelve pips', r.pips.length);
|
|
367
459
|
});
|
|
460
|
+
if (desk.save && (!oneLine(desk.save.line) || desk.save.line.length > LIMITS.saveLine)) bad('save line', desk.save.line);
|
|
368
461
|
if (desk.record.length > LIMITS.record || desk.record.some((x) => !oneLine(x.text) || x.text.length > LIMITS.recordLen)) bad('record line', desk.record.map((x) => x.text));
|
|
369
462
|
return out;
|
|
370
463
|
}
|
|
@@ -379,7 +472,7 @@
|
|
|
379
472
|
|
|
380
473
|
const api = {
|
|
381
474
|
LIMITS: LIMITS, ACT_WORDS: ACT_WORDS, ASKS: ASKS, DESK_NOUNS: DESK_NOUNS, CHIPS: CHIPS, NOUNS: NOUNS, CLEAR: CLEAR,
|
|
382
|
-
fit: fit, ageWord: ageWord, floorMatters: floorMatters, firstNeeds: firstNeeds, rowsFor: rowsFor, deskModel: deskModel, breaks: breaks, todayPips: todayPips,
|
|
475
|
+
fit: fit, ageWord: ageWord, floorMatters: floorMatters, firstNeeds: firstNeeds, rowsFor: rowsFor, deskModel: deskModel, breaks: breaks, todayPips: todayPips, moved: moved,
|
|
383
476
|
};
|
|
384
477
|
root.GovDesk = api;
|
|
385
478
|
if (typeof module !== 'undefined' && module.exports) module.exports = api;
|
|
@@ -112,6 +112,8 @@
|
|
|
112
112
|
const PLAN_SYMBOLS = {
|
|
113
113
|
'Rules in force': 'gavel', 'New rules': 'wrench', 'Security reports': 'shield', 'Removals': 'removal', 'Grade appeals': 'scales',
|
|
114
114
|
'Goals': 'flag', 'Promises': 'seal', 'Spending matters': 'coins',
|
|
115
|
+
// the Desks board's name for the blockers floor (task 1004560)
|
|
116
|
+
'Waiting on you': 'hourglass',
|
|
115
117
|
};
|
|
116
118
|
function floorSymbol(name) {
|
|
117
119
|
return PROTO_SYMBOLS[name] || PLAN_SYMBOLS[name] || 'crate';
|
|
@@ -346,7 +348,8 @@
|
|
|
346
348
|
planning: {
|
|
347
349
|
holds: 'Goals, and the promises that say when each one is done. Kept promises are what the project owes its users.', rule: 'majority', cap: 9,
|
|
348
350
|
growth: 'When it fills, the next new goal opens a second planning office.', annex: 'room for a second planning office',
|
|
349
|
-
|
|
351
|
+
// the three desks first, as on the Desks board (task 1004560)
|
|
352
|
+
floors: [['Priorities', 'the order goals are worked in', { floor: 'planning.priorities', desk: 'planning.order' }], ['Ideas to ratify', 'ideas waiting to be ratified', { floor: 'planning.ideas', desk: 'planning.ratify' }], ['Waiting on you', 'blockers holding work', { source: 'blockers' }], ['Goals', 'the open goals', { floor: 'planning.goals', goals: true }], ['Promises', 'what the goals say they deliver', { reading: 'promises' }], ['Versions', 'what each version holds', { floor: 'planning.versions' }]],
|
|
350
353
|
},
|
|
351
354
|
automation: {
|
|
352
355
|
holds: 'AI builders working on their own. You choose which goals they may build and how much they may spend, and you can stop them at any time.', rule: 'decide', cap: 6,
|
|
@@ -356,7 +359,7 @@
|
|
|
356
359
|
review: {
|
|
357
360
|
holds: 'Testing finished work and signing it off. Work does not count until someone who did not build it says it works.', rule: 'signoff', cap: 5,
|
|
358
361
|
growth: 'When one queue of testers is not enough, an annex can take design reviews.', vacantGrowth: 'Nothing is built here until the charter says who holds the seat.', annex: 'room for an annex, such as design review',
|
|
359
|
-
floors: [['Testers', 'who signs off finished work', { floor: 'review.testers' }], ['Waiting outside', 'finished work waiting for a tester', { source: 'criteria_uat', held: 'Being tested' }], ['Signed off', 'work a tester has signed off', { floor: 'review.signed_off' }]],
|
|
362
|
+
floors: [['Testers', 'who signs off finished work', { floor: 'review.testers' }], ['Waiting outside', 'finished work waiting for a tester', { source: 'criteria_uat', held: 'Being tested' }], ['Signed off', 'work a tester has signed off', { floor: 'review.signed_off', desk: 'review.signed' }]],
|
|
360
363
|
},
|
|
361
364
|
release: {
|
|
362
365
|
holds: 'Putting finished work live, and taking updates to Bongos itself.', rule: 'decide', cap: 7,
|
|
@@ -366,7 +369,7 @@
|
|
|
366
369
|
treasury: {
|
|
367
370
|
holds: 'The budget, and who gets paid for what.', rule: 'majority', cap: 7,
|
|
368
371
|
growth: 'Each new spending line takes a floor.', annex: 'room for an annex of spending lines',
|
|
369
|
-
floors: [['Builder rewards', 'paid for shipped work', { floor: 'treasury.rewards' }], ['AI grading', 'the reviewer that grades every ship', { floor: 'treasury.grading' }], ['Hosting', 'servers and storage', { floor: 'treasury.hosting', desk: 'treasury.backup' }], ['Reserve', 'what is left this month', { reading: 'money' }], ['Spending matters', 'spending put to a vote', { source: 'treasury_spending' }]],
|
|
372
|
+
floors: [['Builder rewards', 'paid for shipped work', { floor: 'treasury.rewards' }], ['AI grading', 'the reviewer that grades every ship', { floor: 'treasury.grading' }], ['Hosting', 'servers and storage', { floor: 'treasury.hosting', desk: 'treasury.backup' }], ['Reserve', 'what is left this month', { reading: 'money', desk: 'treasury.budgets' }], ['Spending matters', 'spending put to a vote', { source: 'treasury_spending' }]],
|
|
370
373
|
},
|
|
371
374
|
});
|
|
372
375
|
const MONTHS = ['jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 'aug', 'sep', 'oct', 'nov', 'dec'];
|
|
@@ -314,6 +314,18 @@ html[data-fullscreen="on"] .street-top { padding-right: 184px; }
|
|
|
314
314
|
.desk-chip:hover { filter: brightness(1.08); }
|
|
315
315
|
.desk-chip[disabled] { opacity: 0.55; cursor: progress; }
|
|
316
316
|
.desk-wait { font-size: 13px; color: var(--ink-faint); border: 1px dashed var(--street-rule-strong); border-radius: 999px; padding: 6px 12px; white-space: nowrap; }
|
|
317
|
+
/* the Planning desks (task 1004560): a goal's place in the order, its promise
|
|
318
|
+
pips (or a vote's seats), the two arrows, and the save bar under a moved order */
|
|
319
|
+
.desk-pos { width: 22px; flex: none; font-size: 13px; color: var(--ink-faint); font-variant-numeric: tabular-nums; }
|
|
320
|
+
.desk-pips { display: flex; gap: 4px; flex: none; }
|
|
321
|
+
.desk-pip { width: 12px; height: 12px; border-radius: 3px; box-sizing: border-box; border: 1px solid var(--street-rule-strong); }
|
|
322
|
+
.desk-pip--on { background: var(--ink); border-color: var(--ink); }
|
|
323
|
+
.desk-arrow { width: 34px; height: 34px; flex: none; border-radius: 999px; border: 1px solid var(--street-rule-strong); background: none; color: var(--ink); cursor: pointer; display: inline-flex; align-items: center; justify-content: center; padding: 0; }
|
|
324
|
+
.desk-arrow svg { fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
|
|
325
|
+
.desk-arrow[disabled] { opacity: 0.55; cursor: progress; }
|
|
326
|
+
.desk-arrow:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
|
|
327
|
+
.desk-save { display: flex; align-items: center; flex-wrap: wrap; gap: 10px 14px; padding: 16px 0 0; animation: street-enter 300ms cubic-bezier(.16,1,.3,1) both; }
|
|
328
|
+
.desk-save__line { font-size: 13.5px; color: var(--ink-soft); margin-right: auto; }
|
|
317
329
|
.desk-facts, .desk-choices { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; padding: 10px 0 2px 52px; animation: street-enter 300ms cubic-bezier(.16,1,.3,1) both; }
|
|
318
330
|
.desk-fact { font-size: 13px; color: var(--ink-soft); background: var(--street-wash); border-radius: 6px; padding: 6px 10px; white-space: nowrap; }
|
|
319
331
|
.desk-choices__ask { font-size: 12.5px; color: var(--ink-faint); margin-right: 4px; }
|
|
@@ -373,6 +385,9 @@ html[data-fullscreen="on"] .street-top { padding-right: 184px; }
|
|
|
373
385
|
.inside-gov__row { flex-wrap: wrap; row-gap: 4px; }
|
|
374
386
|
.desk-row__main { flex-wrap: wrap; row-gap: 8px; }
|
|
375
387
|
.desk-name { flex-basis: calc(100% - 52px); }
|
|
388
|
+
.desk-pos ~ .desk-name { flex-basis: calc(100% - 88px); }
|
|
389
|
+
.desk-pos ~ .desk-pips { margin-left: 88px; }
|
|
390
|
+
.desk-pips ~ .desk-acts { margin-left: auto; }
|
|
376
391
|
.desk-acts { margin-left: 52px; }
|
|
377
392
|
.desk-facts, .desk-choices { padding-left: 0; }
|
|
378
393
|
.desk-tile { min-width: 0; padding: 10px 14px; }
|
|
@@ -208,9 +208,9 @@
|
|
|
208
208
|
</div>
|
|
209
209
|
</div>
|
|
210
210
|
|
|
211
|
-
<script src="/builders/shell-trail.js?v=2026-10-03-
|
|
212
|
-
<script src="/builders/craft-mode.js?v=2026-10-03-
|
|
213
|
-
<script src="/builders/shell.js?v=2026-10-03-
|
|
211
|
+
<script src="/builders/shell-trail.js?v=2026-10-03-looks"></script>
|
|
212
|
+
<script src="/builders/craft-mode.js?v=2026-10-03-looks"></script>
|
|
213
|
+
<script src="/builders/shell.js?v=2026-10-03-looks"></script>
|
|
214
214
|
<script src="/builders/palette.js" defer></script>
|
|
215
215
|
<script src="/builders/city-draw.js?v=2026-10-02-street1"></script>
|
|
216
216
|
<script src="/builders/street-draw.js?v=2026-10-02-street1"></script>
|