@bongos/core 1.20.80 → 1.20.82

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/.bongos-core.json +98 -53
  2. package/clients/bongos-client/README.md +1 -1
  3. package/clients/bongos-client/bongos-client.global.js +8 -0
  4. package/clients/bongos-client/index.cjs +8 -0
  5. package/clients/bongos-client/index.d.ts +12 -0
  6. package/clients/bongos-client/index.mjs +8 -0
  7. package/docs/api/openapi.json +245 -4
  8. package/docs/api-reference.md +7 -3
  9. package/docs/copy-inventory.md +84 -71
  10. package/docs/copy-registry.json +271 -145
  11. package/docs/module-api-changelog.md +4 -0
  12. package/docs/page-inventory.json +2 -1
  13. package/docs/page-readings.json +139 -119
  14. package/modules/autonomy/cadence.js +3 -0
  15. package/modules/autonomy/db.js +136 -0
  16. package/modules/autonomy/fence.js +88 -3
  17. package/modules/autonomy/migrations/autonomy_005_builder_scope.sql +55 -0
  18. package/modules/autonomy/routes/autonomy.js +123 -3
  19. package/modules/economy/earnings.js +117 -0
  20. package/modules/economy/module.json +1 -1
  21. package/modules/economy/routes/earnings.js +47 -0
  22. package/modules/government/catalog.js +9 -1
  23. package/modules/government/migrations/government_022_autonomy_run.sql +38 -0
  24. package/modules/hall-ui/public/gate.css +49 -0
  25. package/modules/hall-ui/public/gate.html +8 -7
  26. package/modules/hall-ui/public/gate.js +272 -115
  27. package/modules/hall-ui/public/profile-charts.js +206 -104
  28. package/modules/hall-ui/public/profile.css +23 -0
  29. package/modules/hall-ui/public/profile.js +3 -3
  30. package/modules/hall-ui/public/profile.states.json +8 -4
  31. package/modules/hall-ui/public/settings-autobongos.js +156 -0
  32. package/modules/hall-ui/public/settings.html +19 -0
  33. package/modules/hall-ui/public/settings.js +1 -0
  34. package/modules/hall-ui/records/profile-roles.md +21 -0
  35. package/modules/lifecycle/db-goals.js +6 -0
  36. package/modules/lifecycle/db-versions.js +3 -0
  37. package/modules/lifecycle/done-when.js +4 -0
  38. package/modules/lifecycle/goal-close-sweep.js +34 -0
  39. package/modules/provisioning/app-status.js +17 -4
  40. package/modules/public-landing/public/projects.html +7 -0
  41. package/package-lock.json +2 -2
  42. package/package.json +1 -1
  43. package/release-notes.json +28 -0
  44. package/scripts/hall-preview/server.js +4 -0
  45. package/src/module-api.js +1 -1
  46. package/tests/auto_satisfy_criteria.mjs +8 -6
  47. package/tests/autonomy_builder_scope.mjs +474 -0
  48. package/tests/autonomy_fence_priority.mjs +7 -3
  49. package/tests/autonomy_runner_identity.mjs +1 -1
  50. package/tests/criterion_goal_attach.mjs +5 -1
  51. package/tests/goal_close_cancels_requests.mjs +82 -0
  52. package/tests/goal_closure_invariants.mjs +5 -2
  53. package/tests/hall_profile_world.mjs +57 -58
  54. package/tests/profile_earnings.mjs +237 -0
  55. package/tests/projects_hub_app_status.mjs +17 -0
  56. package/tests/provisioning_app_status.mjs +25 -1
@@ -0,0 +1,47 @@
1
+ // modules/economy/routes/earnings.js — GET /builders/:builderId/earnings: what a
2
+ // builder earned, per day and per kind of credit (task 1004436 / WA6.RP06).
3
+ //
4
+ // → { builder_id, days: [{ day, kind, credits }], totals: { <kind>: credits }, total }
5
+ //
6
+ // The profile's earnings chart reads it for EVERY builder, whatever their craft:
7
+ // an ideator or an artist who never shipped a task is paid all the same, and the
8
+ // chart used to draw only for someone who had. `../earnings.js` owns the read and
9
+ // the kinds; this file is only the doorway, and must never grow SQL.
10
+ //
11
+ // SIGNED IN. The owner's decision (a), 2026-09-30: "no one should be able to open
12
+ // up the hood of data without being signed in." Sums only — the itemised ledger
13
+ // (/builders/:builderId/credits) stays behind builder.roster.read.
14
+ //
15
+ // MODULE BOUNDARY: reaches core only through the published doorway
16
+ // `../../../src/module-api`; `../earnings` is an intra-module sibling.
17
+
18
+ 'use strict';
19
+
20
+ const express = require('express');
21
+ const api = require('../../../src/module-api');
22
+ const { readEarnings } = require('../earnings');
23
+
24
+ module.exports = function buildEarningsRouter() {
25
+ const router = express.Router();
26
+
27
+ // rank: builder — any signed-in builder may read any builder's earnings by
28
+ // kind, as the profile's other signed-in sections are; a stranger gets the
29
+ // sign-in line. The param names the builder (`:builderId`), the credits
30
+ // route's convention, because this route deliberately reads someone else.
31
+ router.get('/builders/:builderId/earnings', api.requireBuilder, async (req, res) => {
32
+ const targetId = api.parseId(req, res, { param: 'builderId', code: 'bad_builder_id', positiveInt: true });
33
+ if (targetId === null) return;
34
+ try {
35
+ const b = await api.getBuilderById(targetId);
36
+ if (!b) return res.fail('builder_not_found', 404);
37
+ const out = await readEarnings(targetId);
38
+ res.set('Cache-Control', 'no-store');
39
+ res.json({ builder_id: targetId, ...out });
40
+ } catch (err) {
41
+ console.error('[gds] GET /builders/:builderId/earnings', err);
42
+ if (!res.headersSent) res.fail('earnings_read_failed', { status: 500, message: 'internal error' });
43
+ }
44
+ });
45
+
46
+ return router;
47
+ };
@@ -119,7 +119,15 @@ const PERMISSIONS = [
119
119
  // suggestion. Deliberately NOT paired with a read permission: seeing whether the
120
120
  // runner is on is harmless, and GET /autonomy/fence is any-builder so the runner
121
121
  // itself does not need an elevated session merely to learn it must stop.
122
- { key: 'autonomy.fence.manage', system: true, floor: 'archon', guards: 'POST /autonomy/fence (the kill switch), POST|DELETE /autonomy/fence/goals (the allowlist) — the Autobongos fence (ADR 0307 §6)' },
122
+ { key: 'autonomy.fence.manage', system: true, floor: 'archon', guards: 'POST /autonomy/fence (the kill switch), POST|DELETE /autonomy/fence/goals (the allowlist), POST /autonomy/builders/:id/pause (one builder\'s runner), GET /autonomy/runners/all — the Autobongos fence (ADR 0307 §6)' },
123
+ // autonomy.run (task 1004501) — WHO MAY RUN A RUNNER AT ALL. Held, a builder may
124
+ // pick which allowlisted goals their own runner works, and GET /autonomy/fence
125
+ // hands their runner those goals; not held, the fence they read is off. NOT
126
+ // system: it is operational, and an owner who wants a custom rank of
127
+ // "runner operators" should be able to compose one. It can never widen the fence
128
+ // — the project allowlist and the kill switch stay behind autonomy.fence.manage —
129
+ // so delegating it delegates only "whose machine may work the allowed goals".
130
+ { key: 'autonomy.run', system: false, floor: 'metic', guards: 'PUT /autonomy/me/goals (a builder\'s own runner scope); also decides whether GET /autonomy/fence answers enabled for the caller' },
123
131
  // BV1.R21 (task 1003608, goal 1000086). ADR 0250 §6 amends ADR 0157 for exactly
124
132
  // this key: `version.create` returns to the Archon floor.
125
133
  //
@@ -0,0 +1,38 @@
1
+ -- government_022_autonomy_run.sql — grant the new `autonomy.run` atom to Metic and
2
+ -- Archon (task 1004501).
3
+ --
4
+ -- WHAT IT IS. Whether a builder may run an Autobongos runner at all: pick the
5
+ -- allowlisted goals their own runner works, and be answered `enabled` when their
6
+ -- runner reads GET /autonomy/fence. Without it, a builder's runner reads a fence
7
+ -- that is off for them, whatever the project switch says.
8
+ --
9
+ -- METIC FLOOR. A runner spawns sessions with blanket bypassPermissions on the
10
+ -- builder's own machine, and sub-Metic builders stay out of the build pipeline
11
+ -- (ADR 0043). NOT system: an owner may add it to a custom rank. That delegates
12
+ -- only whose machine may work the allowed goals — the allowlist and the kill
13
+ -- switch stay behind the archon-only `autonomy.fence.manage`.
14
+ --
15
+ -- WHY THIS FILE EXISTS AT ALL. RANK_SEED is derived from the catalog's floors and
16
+ -- tests/government_seed.mjs compares it against the run-once seed plus every later
17
+ -- grant migration, per rank. A catalog row without this migration leaves the key
18
+ -- held on paper and not in the database.
19
+ --
20
+ -- Additive only; idempotent (ON CONFLICT DO NOTHING); forward-safe (INSERT only).
21
+ -- The `SELECT '<rank>', unnest(ARRAY[…])` shape is load-bearing: the drift guard
22
+ -- scans for it literally.
23
+
24
+ BEGIN;
25
+
26
+ INSERT INTO government_rank_permissions (rank_key, permission_key)
27
+ SELECT 'metic', unnest(ARRAY[
28
+ 'autonomy.run'
29
+ ])
30
+ ON CONFLICT (rank_key, permission_key) DO NOTHING;
31
+
32
+ INSERT INTO government_rank_permissions (rank_key, permission_key)
33
+ SELECT 'archon', unnest(ARRAY[
34
+ 'autonomy.run'
35
+ ])
36
+ ON CONFLICT (rank_key, permission_key) DO NOTHING;
37
+
38
+ COMMIT;
@@ -23,3 +23,52 @@
23
23
  .gate-reason > span:nth-of-type(2) { flex: 1 1 100%; order: 3; }
24
24
  .gate-reason__floor { margin-left: auto; }
25
25
  }
26
+
27
+ /* The Autobongos runner panel (task 1004509): a status line with the switch,
28
+ a checklist only while something is missing, goals as chips, and the
29
+ machine facts folded under Details. */
30
+ .rn-head { display: flex; align-items: center; gap: 12px; }
31
+ .rn-head__text { flex: 1; min-width: 0; }
32
+ .rn-title { margin: 0; font-size: 17px; color: var(--ink); }
33
+ .rn-meta { margin: 2px 0 0; font-size: 12.5px; color: var(--ink-faint); }
34
+ .rn-dot { width: 12px; height: 12px; border-radius: 50%; flex: none; background: var(--info); }
35
+ .rn-dot--ok { background: var(--ok); }
36
+ .rn-dot--warn { background: var(--warn); }
37
+ .rn-dot--danger { background: var(--danger); }
38
+
39
+ .rn-switch { display: inline-flex; align-items: center; gap: 8px; background: none; border: 0; padding: 4px; cursor: pointer; color: var(--ink-soft); font: inherit; font-size: 13px; }
40
+ .rn-switch__track { position: relative; width: 40px; height: 22px; border-radius: var(--radius-pill); background: var(--rule); transition: background .15s; }
41
+ .rn-switch__track::after { content: ""; position: absolute; top: 3px; left: 3px; width: 16px; height: 16px; border-radius: 50%; background: var(--bg-card); transition: transform .15s; }
42
+ .rn-switch[aria-checked="true"] .rn-switch__track { background: var(--ok); }
43
+ .rn-switch[aria-checked="true"] .rn-switch__track::after { transform: translateX(18px); }
44
+ .rn-switch:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; border-radius: var(--radius-sm); }
45
+
46
+ .rn-check { list-style: none; margin: 16px 0 0; padding: 0; display: grid; gap: 10px; }
47
+ .rn-check__item { display: flex; align-items: flex-start; gap: 10px; font-size: 14px; color: var(--ink); }
48
+ .rn-check__icon { width: 20px; height: 20px; border-radius: 50%; flex: none; display: inline-flex; align-items: center; justify-content: center; font-size: 12px; }
49
+ .rn-check__item--ok .rn-check__icon { background: var(--ok-weak); color: var(--ok); }
50
+ .rn-check__item--todo .rn-check__icon { background: var(--warn-weak); color: var(--warn); }
51
+ .rn-check__item--wait { color: var(--ink-faint); }
52
+ .rn-check__item--wait .rn-check__icon { border: var(--line) solid var(--rule); color: var(--ink-faint); }
53
+ .rn-check__text { flex: 1; min-width: 0; }
54
+ .rn-check__hint { display: block; font-size: 12.5px; color: var(--ink-faint); }
55
+ .rn-check .rn-meta { display: inline; }
56
+
57
+ .rn-sub { margin: 20px 0 8px; font-size: 13px; font-weight: 500; color: var(--ink-soft); }
58
+ .rn-chips { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
59
+ .rn-chip { display: inline-flex; align-items: center; gap: 4px; padding: 3px 6px; border: var(--line) solid var(--rule); border-radius: var(--radius-pill); font-size: 13px; background: none; color: var(--ink); }
60
+ .rn-chip a { color: inherit; text-decoration: none; padding: 0 2px; }
61
+ .rn-chip a:hover { text-decoration: underline; }
62
+ .rn-chip--pri { border-color: var(--accent); }
63
+ .rn-chip__star, .rn-chip__x { background: none; border: 0; padding: 0 4px; cursor: pointer; color: var(--ink-faint); font: inherit; font-size: 14px; line-height: 1; }
64
+ .rn-chip--pri .rn-chip__star { color: var(--accent); }
65
+ .rn-chip__star:hover, .rn-chip__x:hover { color: var(--ink); }
66
+ .rn-chip--add { border-style: dashed; color: var(--ink-soft); padding: 3px 12px; cursor: pointer; font: inherit; font-size: 13px; }
67
+ .rn-add { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
68
+ .rn-add input[type="number"] { width: 140px; }
69
+
70
+ .rn-details { margin: 18px 0 0; font-size: 12.5px; color: var(--ink-faint); }
71
+ .rn-details summary { cursor: pointer; width: fit-content; }
72
+ .rn-details p, .rn-details ul { margin: 8px 0 0; max-width: var(--measure); }
73
+ .rn-details ul { padding-left: 18px; display: grid; gap: 4px; }
74
+ .rn-dot--sm { display: inline-block; width: 8px; height: 8px; vertical-align: 1px; }
@@ -51,12 +51,13 @@
51
51
  behind it are system:true/archon server-side regardless. -->
52
52
  <section class="scroll" id="fence-panel" aria-labelledby="fence-h" hidden>
53
53
  <h2 class="scroll__h" id="fence-h">Autobongos runner</h2>
54
- <p class="scroll__lede">The unattended runner works only the goals listed here, and only while it is on. This is the switch — it lives on the server, so the machine can read it and cannot change it.</p>
55
- <!-- Liveness first (task 1003905): "is it running at all" is the
56
- question before "is it allowed to run". -->
57
- <div id="fence-runner"><span class="kit-skel"></span></div>
58
- <div id="fence-state"><span class="kit-skel"></span></div>
59
- <div id="fence-goals"></div>
54
+ <!-- One panel (task 1004509): a checklist while anything the runner
55
+ needs is missing, one status line with the switch once it is all
56
+ ticked. Drawn from /autonomy/runners + /autonomy/fence together. -->
57
+ <div id="fence-body"><span class="kit-skel"></span></div>
58
+ <!-- Every builder's runner (task 1004501): what each one picked to
59
+ work, whether you paused it, and whether it is checking in. -->
60
+ <div id="fence-builders"></div>
60
61
  </section>
61
62
 
62
63
  <section class="scroll" aria-labelledby="gate-list-h">
@@ -81,6 +82,6 @@
81
82
  <script src="/builders/palette.js" defer></script>
82
83
  <script src="/builders/dom-utils.js?v=2026-06-16-gate"></script>
83
84
  <script src="/builders/hall-kit.js"></script>
84
- <script src="/builders/gate.js?v=2026-09-19-runner"></script>
85
+ <script src="/builders/gate.js?v=2026-10-01-runner-checklist"></script>
85
86
  </body>
86
87
  </html>