@bongos/core 1.20.54 → 1.20.55

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 CHANGED
@@ -2,11 +2,11 @@
2
2
  "artifact": "bongos-core",
3
3
  "manifest_schema": 1,
4
4
  "generator": "scripts/gds/package-core.js",
5
- "core_version": "1.20.54",
6
- "core_contract": "1.20.54",
7
- "source_commit": "0fb32cfd989215446812f0ee1f953d35325b8606",
5
+ "core_version": "1.20.55",
6
+ "core_contract": "1.20.55",
7
+ "source_commit": "0fb1d496d093ffd8b5166b91733a65060da69014",
8
8
  "source_ref": "HEAD",
9
- "built_at": "2026-10-01T05:26:34.110Z",
9
+ "built_at": "2026-10-01T05:41:11.828Z",
10
10
  "redaction": {
11
11
  "model": "docs-redacted+functional-verbatim",
12
12
  "docs_redacted": 569,
@@ -17,7 +17,7 @@
17
17
  "gate": "passed"
18
18
  },
19
19
  "file_count": 3334,
20
- "tree_sha256": "18a0716b2420187019ac58ed948d1c70ab971cc342734b0d628faf68167191ea",
20
+ "tree_sha256": "9359eda1fabf15c48b2fc4d7c303de23772ed6b0ca09824edf83d8acb6bc78f2",
21
21
  "files": [
22
22
  {
23
23
  "path": ".claude/skills/ask-for-help/SKILL.md",
@@ -2287,12 +2287,12 @@
2287
2287
  {
2288
2288
  "path": "docs/copy-inventory.md",
2289
2289
  "mode": "0000644",
2290
- "sha256": "432295beaf30da14491132723fe17f9334b21cf323243c4dae889b87065068b9"
2290
+ "sha256": "676131a6c53ccc299f025f6ca641909126234bd9482846e33536e1fabf3fed2e"
2291
2291
  },
2292
2292
  {
2293
2293
  "path": "docs/copy-registry.json",
2294
2294
  "mode": "0000644",
2295
- "sha256": "36b5e5a089e407b68cbb30eaa3f27955abb90de934c44b3f466529b752e99c2a"
2295
+ "sha256": "576c91e194b6f846f0594493a2b0c26d0b8b2ee1d68e8c4b6ec6fb13fd79623b"
2296
2296
  },
2297
2297
  {
2298
2298
  "path": "docs/design/apex-pass-2-direction.md",
@@ -2797,7 +2797,7 @@
2797
2797
  {
2798
2798
  "path": "docs/module-api-changelog.md",
2799
2799
  "mode": "0000644",
2800
- "sha256": "a7fa1446d5105ab6ed15cd26c615671b427efc4d55aae6eb9bf47bfe574f390d"
2800
+ "sha256": "a5144c331936e77ad1842a5a105861816b55a9b3afc0b8864bebd2ed7c097291"
2801
2801
  },
2802
2802
  {
2803
2803
  "path": "docs/modules-contract.md",
@@ -2887,7 +2887,7 @@
2887
2887
  {
2888
2888
  "path": "docs/page-readings.json",
2889
2889
  "mode": "0000644",
2890
- "sha256": "ecc0b9355b0d07faaf9911d22b44db5d9b7652f5e01a45910a5bf2c2cb08eb4f"
2890
+ "sha256": "89370aecc37c029b715409173cabebd147cb63f266c1cd5d083d4b66b90ac75a"
2891
2891
  },
2892
2892
  {
2893
2893
  "path": "docs/project-context.template.md",
@@ -4922,7 +4922,7 @@
4922
4922
  {
4923
4923
  "path": "modules/government/recommendations.js",
4924
4924
  "mode": "0000644",
4925
- "sha256": "2ae0e7f49aacbf966d466ca75a8dac4ab526496107fa491563890f310a8e24d4"
4925
+ "sha256": "d831ebafe52bf1f3d61e3702a648c418a854e54cb96c4ba6b43ecd20ff5cd5ee"
4926
4926
  },
4927
4927
  {
4928
4928
  "path": "modules/government/resolver.js",
@@ -4932,7 +4932,7 @@
4932
4932
  {
4933
4933
  "path": "modules/government/routes/government.js",
4934
4934
  "mode": "0000644",
4935
- "sha256": "2e901a13f0d5624c246add50c66ed95e345a1979440d62c027c51d24cab6b16d"
4935
+ "sha256": "8290486f1b25e9bb080911a5f6ed231bd8d1473bca87f8adafcbe01b9d98e962"
4936
4936
  },
4937
4937
  {
4938
4938
  "path": "modules/government/routes/rank-sync.js",
@@ -5487,7 +5487,7 @@
5487
5487
  {
5488
5488
  "path": "modules/hall-ui/public/government.js",
5489
5489
  "mode": "0000644",
5490
- "sha256": "1d74433b5971c17bfe84c7fd80ff7888ea6fdbea60413e7ad5fc0eca7f36ecc8"
5490
+ "sha256": "fab666dad26e7b9b92d50ba3fb4027da0b9d166bf09291775ddf9c42619ddf38"
5491
5491
  },
5492
5492
  {
5493
5493
  "path": "modules/hall-ui/public/government.states.json",
@@ -9242,12 +9242,12 @@
9242
9242
  {
9243
9243
  "path": "package-lock.json",
9244
9244
  "mode": "0000644",
9245
- "sha256": "7f75af0db1642a139e780c4668c28ef7d4dd94d23606688cc932de869c92eb77"
9245
+ "sha256": "402e96b388e6d955089715bb4ec23ffbf406723559a3cd0189d736344932c6d7"
9246
9246
  },
9247
9247
  {
9248
9248
  "path": "package.json",
9249
9249
  "mode": "0000644",
9250
- "sha256": "21aa86d2d5532b61965e866c80e9ccb6bb081f680b2c0ec6ec1c301029924750"
9250
+ "sha256": "5e2b7d9fef83b43a5ed9e63c92e8abac5f19be08bc7efb9c0d304916a9ce59b6"
9251
9251
  },
9252
9252
  {
9253
9253
  "path": "public-docs/index.html",
@@ -9267,7 +9267,7 @@
9267
9267
  {
9268
9268
  "path": "release-notes.json",
9269
9269
  "mode": "0000644",
9270
- "sha256": "ebfd2ffffb89ec082dc9d5ebda46442a68adc7afab70f78b015f95ed2ba8eb84"
9270
+ "sha256": "8ee955d907ac5a5443f58e71a05f624e61e80880dfecf8e2cc91cab1b760ec27"
9271
9271
  },
9272
9272
  {
9273
9273
  "path": "scripts/bongos-mcp.js",
@@ -11432,7 +11432,7 @@
11432
11432
  {
11433
11433
  "path": "src/module-api.js",
11434
11434
  "mode": "0000644",
11435
- "sha256": "e894e0d14143f77b8d933b1a192250dc098db1883b839306ac2a40e39719a514"
11435
+ "sha256": "b2916718459f0ffb6b4b6793ff8cc7ea10b56563556cdeb1a9c9db2926e3ab54"
11436
11436
  },
11437
11437
  {
11438
11438
  "path": "src/module-loader/catalog.js",
@@ -13347,7 +13347,7 @@
13347
13347
  {
13348
13348
  "path": "tests/government_recommendations.mjs",
13349
13349
  "mode": "0000644",
13350
- "sha256": "b915086865be9029ccc605a468937434f5916561a51f45a03b34cffeacf4249f"
13350
+ "sha256": "b4d9b0ba70bb40332aff9cb981d4f3571e460191865ae5a7d2895636b8358703"
13351
13351
  },
13352
13352
  {
13353
13353
  "path": "tests/government_require_permission.mjs",
@@ -13362,7 +13362,7 @@
13362
13362
  {
13363
13363
  "path": "tests/government_routes.mjs",
13364
13364
  "mode": "0000644",
13365
- "sha256": "c04df68f34c55f13c908d4565d6d38116341738e611c14dba6577724725e9e85"
13365
+ "sha256": "caec7484f283e0674b37a46ad24ba47668f58b10a19a07a03709a986e7e2f762"
13366
13366
  },
13367
13367
  {
13368
13368
  "path": "tests/government_seed.mjs",
@@ -246,6 +246,7 @@ Identical copy within one surface. Sometimes right (a repeated button), sometime
246
246
  | `6d6d626fc518` | certain | Bulk release | `modules/hall-ui/public/work.html:165` |
247
247
  | `181cfa50b127` | certain | By the numbers | `modules/hall-ui/public/profile.html:60` |
248
248
  | `a015a43bfc7f` | certain | CLI access | `modules/hall-ui/public/settings.html:133` |
249
+ | `09e863eb90af` | certain | Can: {…} | `modules/hall-ui/public/government.js:870` |
249
250
  | `084eb64bce72` | certain | Capabilities held by a machine identity, never by a person or a rank. Shown for completeness; nothing here can | `modules/hall-ui/public/government.html:123` |
250
251
  | `bdca1f219e6f` | certain | Cast objection | `modules/hall-ui/public/board-room.js:368` |
251
252
  | `a974494e44f3` | certain | Catalog at a glance | `modules/hall-ui/public/modules.html:53` |
@@ -1552,7 +1553,6 @@ Identical copy within one surface. Sometimes right (a repeated button), sometime
1552
1553
  | `b6ceacaad5e5` | certain | pick another | `modules/hall-ui/public/studio.js:682` |
1553
1554
  | `b6ceacaad5e5` | certain | pick another | `modules/hall-ui/public/tweak-editor.html:105` |
1554
1555
  | `3b22c5af029b` | certain | rank or above, or that it is your own. | `modules/hall-ui/public/copy-desk.html:47` |
1555
- | `a86aeceacc7e` | certain | rank {…} · may: {…} | `modules/hall-ui/public/government.js:870` |
1556
1556
  | `80ddf28baee7` | certain | rank-key (kebab-case) | `modules/hall-ui/public/government.html:82` |
1557
1557
  | `41a4b66c21e5` | certain | reads the control plane's own observation · ADR 0293 · every move is recorded with who asked | `modules/hall-ui/public/deploy.js:704` |
1558
1558
  | `8d810f134b7b` | certain | reconnect GitHub with repository access | `modules/hall-ui/public/deploy.js:416` |
@@ -3812,6 +3812,15 @@
3812
3812
  "origin": "html-text",
3813
3813
  "confidence": "certain"
3814
3814
  },
3815
+ {
3816
+ "id": "09e863eb90af",
3817
+ "surface": "builders-hall",
3818
+ "text": "Can: {…}",
3819
+ "file": "modules/hall-ui/public/government.js",
3820
+ "line": 870,
3821
+ "origin": "js-markup",
3822
+ "confidence": "certain"
3823
+ },
3815
3824
  {
3816
3825
  "id": "084eb64bce72",
3817
3826
  "surface": "builders-hall",
@@ -15566,15 +15575,6 @@
15566
15575
  "origin": "html-text",
15567
15576
  "confidence": "certain"
15568
15577
  },
15569
- {
15570
- "id": "a86aeceacc7e",
15571
- "surface": "builders-hall",
15572
- "text": "rank {…} · may: {…}",
15573
- "file": "modules/hall-ui/public/government.js",
15574
- "line": 870,
15575
- "origin": "js-markup",
15576
- "confidence": "certain"
15577
- },
15578
15578
  {
15579
15579
  "id": "80ddf28baee7",
15580
15580
  "surface": "builders-hall",
@@ -2765,5 +2765,7 @@ is load-bearing: the script throws rather than guess if it is missing, and
2765
2765
  landed since 1.20.52 with no explicit bump. run 36818406554. (task 1002620)
2766
2766
  1.20.54 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
2767
2767
  landed since 1.20.53 with no explicit bump. run 36819731905. (task 1002620)
2768
+ 1.20.55 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
2769
+ landed since 1.20.54 with no explicit bump. run 36820911043. (task 1002620)
2768
2770
  ---------------------------------------------------------------------------
2769
2771
  ```
@@ -1269,8 +1269,8 @@
1269
1269
  "surface": "builders",
1270
1270
  "title": "Government",
1271
1271
  "states_read": ["constitution","out","permissions","board","constitution-tab"],
1272
- "files_hash": "bbf04524bee9d2db",
1273
- "reading_hash": "f79ecbcfaec9cd68",
1272
+ "files_hash": "f0884c4c6f7f0dd1",
1273
+ "reading_hash": "7a4c380c5c88d659",
1274
1274
  "counts": {"lines":83,"placed":34,"shared":5,"unplaced":44},
1275
1275
  "omitted": {"data":28},
1276
1276
  "notes": ["board: an action failed (page.click: Timeout 6000ms exceeded.); read as it stood"],
@@ -1330,7 +1330,7 @@
1330
1330
  {"key":"L0053","section":"Recommended for your project","text":"{…} of {…}","placement":"placed","file":"modules/hall-ui/public/sky-panel.js","line":120,"string_id":"73c1372b43d9"},
1331
1331
  {"key":"L0054","section":"Recommended for your project","text":"{…} project{…}","placement":"placed","file":"modules/hall-ui/public/fleet.js","line":39,"string_id":"771bef3d31b5"},
1332
1332
  {"key":"L0055","section":"Recommended for your project","text":"{…} and {…}","placement":"placed","file":"modules/hall-ui/public/profile-nudge.js","line":77,"string_id":"56b00d773232","occurrences":2},
1333
- {"key":"L0056","section":"Recommended for your project","text":"rank {…} · may: {…}","placement":"placed","file":"modules/hall-ui/public/government.js","line":870,"string_id":"a86aeceacc7e","occurrences":2},
1333
+ {"key":"L0056","section":"Recommended for your project","text":"Can: {…}","placement":"placed","file":"modules/hall-ui/public/government.js","line":870,"string_id":"09e863eb90af","occurrences":2},
1334
1334
  {"key":"L0057","section":"Charter library","text":"Charter library","placement":"placed","file":"modules/hall-ui/public/government.js","line":809,"string_id":"e6982a9ff948"},
1335
1335
  {"key":"L0058","section":"Charter library","text":"The seven government structures, for getting a team up to speed before deciding when to flip a switch.","placement":"placed","file":"modules/hall-ui/public/government.js","line":809,"string_id":"af664a644b13"},
1336
1336
  {"key":"L0059","section":"Charter library","text":"Selectable today","placement":"placed","file":"modules/hall-ui/public/government.js","line":809,"string_id":"ae43a132699b"},
@@ -83,6 +83,16 @@ const JOB_GRANTS = freeze({
83
83
  'goal.create', 'priority.run']),
84
84
  });
85
85
 
86
+ // What each job can do, in the words a person would use (task 1004478). The
87
+ // keys above are what the apply route grants; this is what the page shows, so
88
+ // a reader never has to decode a permission key to judge a recommendation.
89
+ // When a job's grants change, change its sentence in the same edit.
90
+ const JOB_CAN = freeze({
91
+ reviewer: 'Check finished work against what "done" means, vote on tasks, and sort incoming ideas.',
92
+ lead: 'Write, edit and order tasks, move them into the queue, look after their own goals, sort ideas and check finished work.',
93
+ council: 'Put proposals to the board, ratify ideas, decide when a goal is met (or reopen it), create goals and set priorities.',
94
+ });
95
+
86
96
  // What each type calls those jobs. The rank key is what gets created, so it is
87
97
  // a kebab-case slug the rank API accepts.
88
98
  const JOB_NAMES = freeze({
@@ -184,6 +194,7 @@ function recommendedRankSet(type, headcount) {
184
194
  label: JOB_NAMES[t][job].label,
185
195
  description: JOB_NAMES[t][job].description,
186
196
  permissions: JOB_GRANTS[job],
197
+ can: JOB_CAN[job],
187
198
  }));
188
199
  const why = ranks.length
189
200
  ? `At this size ${projectPhrase(t)} hands out ${ranks.length === 1 ? 'one job' : `${ranks.length} jobs`} beyond the four standard ranks. Each is added as a custom rank you can edit or delete.`
@@ -210,6 +221,7 @@ module.exports = {
210
221
  SIZE_BANDS,
211
222
  JOB_GRANTS,
212
223
  JOB_NAMES,
224
+ JOB_CAN,
213
225
  normalizeType,
214
226
  sizeBandFor,
215
227
  recommendedCharter,
@@ -320,12 +320,12 @@ module.exports = function buildGovernmentRouter() {
320
320
  const skipped = [];
321
321
  try {
322
322
  for (const r of set.ranks) {
323
- if (await db.getRankByKey(r.rank_key)) { skipped.push(r.rank_key); continue; }
323
+ if (await db.getRankByKey(r.rank_key)) { skipped.push({ rank_key: r.rank_key, label: r.label }); continue; }
324
324
  let rank;
325
325
  try {
326
326
  rank = await db.createRank({ rankKey: r.rank_key, label: r.label, description: r.description, createdBy: req.builder.id });
327
327
  } catch (err) {
328
- if (err && err.code === '23505') { skipped.push(r.rank_key); continue; }
328
+ if (err && err.code === '23505') { skipped.push({ rank_key: r.rank_key, label: r.label }); continue; }
329
329
  throw err;
330
330
  }
331
331
  const granted = [];
@@ -870,7 +870,7 @@
870
870
  return `<li class="ov-row"><div class="ov-row__main">
871
871
  <span class="ov-row__title">${escapeHtml(r.label)}</span>
872
872
  <p class="ov-row__sub">${escapeHtml(r.description)}</p>
873
- <p class="gov-charter__how">rank ${escapeHtml(r.rank_key)} · may: ${escapeHtml(r.permissions.join(', '))}</p>
873
+ <p class="ov-row__sub">Can: ${escapeHtml(r.can)}</p>
874
874
  </div></li>`;
875
875
  }
876
876
 
@@ -926,7 +926,7 @@
926
926
  try {
927
927
  const r = await sendJson('POST', '/government/rank-sets/apply', { type: reco.type, headcount: reco.headcount });
928
928
  const made = (r.created || []).map((c) => c.label);
929
- const kept = r.skipped || [];
929
+ const kept = (r.skipped || []).map((s) => s.label);
930
930
  toast(made.length
931
931
  ? `Added ${made.join(', ')}.${kept.length ? ` Already here, left as they were: ${kept.join(', ')}.` : ''}`
932
932
  : 'Those ranks are already here — nothing changed.');
package/package-lock.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@bongos/core",
3
- "version": "1.20.54",
3
+ "version": "1.20.55",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@bongos/core",
9
- "version": "1.20.54",
9
+ "version": "1.20.55",
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.20.54",
3
+ "version": "1.20.55",
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",
@@ -8441,5 +8441,11 @@
8441
8441
  "id": "1004400",
8442
8442
  "text": "The Government page now recommends a starting government and a starting set of ranks for your kind of project (game, research, business, non-profit) and its size. It only ever recommends a form you can adopt today. A team of a"
8443
8443
  }
8444
+ ],
8445
+ "1.20.55": [
8446
+ {
8447
+ "id": "1004478",
8448
+ "text": "The recommended ranks on the Government page now say in plain words what each one can do, for example \"Check finished work, vote on tasks, and sort incoming ideas\", instead of listing system codes. The confirmation after addin"
8449
+ }
8444
8450
  ]
8445
8451
  }
package/src/module-api.js CHANGED
@@ -75,7 +75,7 @@ const { responsibilityFor, ROLE_RESPONSIBILITIES } = require('./role-responsibil
75
75
  // MAJOR (see allowBoxScope below): passes the request through untouched.
76
76
  function deprecatedNoopMiddleware(_req, _res, next) { next(); }
77
77
 
78
- const CORE_VERSION = '1.20.54'; // CI auto-patch carrier (ADR 0161); changelog: docs/module-api-changelog.md
78
+ const CORE_VERSION = '1.20.55'; // CI auto-patch carrier (ADR 0161); changelog: docs/module-api-changelog.md
79
79
 
80
80
  // A namespaced logger so a module's log lines are attributable + consistent.
81
81
  // Usage: const log = api.logger('discord'); log.info('mounted');
@@ -117,3 +117,16 @@ test('recommendationsFor carries both answers and the vocabulary to ask about an
117
117
  assert.equal(r.project_types.length, TYPES.length);
118
118
  for (const b of r.size_bands) assert.equal(reco.sizeBandFor(b.example).key, b.key, 'each size option lands in its own band');
119
119
  });
120
+
121
+ test('the panel says what a recommended rank can do in words, never in permission keys (task 1004478)', () => {
122
+ for (const job of Object.keys(reco.JOB_GRANTS)) {
123
+ const can = reco.JOB_CAN[job];
124
+ assert.ok(typeof can === 'string' && can.length > 20, `job ${job} needs a plain sentence`);
125
+ assert.ok(!/[a-z]+\.[a-z_]+/.test(can), `job ${job}'s sentence must not spell a permission key`);
126
+ }
127
+ for (const r of reco.recommendedRankSet('game', 200).ranks) assert.equal(r.can, reco.JOB_CAN[r.job]);
128
+ const client = fs.readFileSync(path.join(ROOT, 'modules', 'hall-ui', 'public', 'government.js'), 'utf8');
129
+ const row = client.slice(client.indexOf('function recoRankRow'), client.indexOf('function recommendationHtml'));
130
+ assert.match(row, /r\.can/, 'the rank row renders the sentence');
131
+ assert.doesNotMatch(row, /permissions/, 'the rank row does not render the raw keys');
132
+ });
@@ -254,7 +254,7 @@ test('POST /government/rank-sets/apply creates the missing ranks with their gran
254
254
  try {
255
255
  const r = await call('POST', '/government/rank-sets/apply', { type: 'game', headcount: 20 });
256
256
  assert.equal(r.status, 200);
257
- assert.deepEqual(r.json.skipped, ['design-lead']);
257
+ assert.deepEqual(r.json.skipped, [{ rank_key: 'design-lead', label: 'Design lead' }], 'a kept rank is named by its label, not its key (task 1004478)');
258
258
  assert.deepEqual(r.json.created.map((c) => c.rank_key), ['playtester']);
259
259
  const creates = calls.filter(([k]) => k === 'createRank');
260
260
  assert.equal(creates.length, 1);