@bongos/core 1.19.655 → 1.19.656
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.19.
|
|
6
|
-
"core_contract": "1.19.
|
|
7
|
-
"source_commit": "
|
|
5
|
+
"core_version": "1.19.656",
|
|
6
|
+
"core_contract": "1.19.656",
|
|
7
|
+
"source_commit": "c0c5d7b3e5b4f9be24da806b898180fc4bf0df47",
|
|
8
8
|
"source_ref": "HEAD",
|
|
9
|
-
"built_at": "2026-09-11T00:
|
|
9
|
+
"built_at": "2026-09-11T00:27:13.017Z",
|
|
10
10
|
"redaction": {
|
|
11
11
|
"model": "docs-redacted+functional-verbatim",
|
|
12
12
|
"docs_redacted": 472,
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"gate": "passed"
|
|
18
18
|
},
|
|
19
19
|
"file_count": 2607,
|
|
20
|
-
"tree_sha256": "
|
|
20
|
+
"tree_sha256": "90e88ec865416bea870aef7c0ea90db47124defc012e894bc04037bea59f12a6",
|
|
21
21
|
"files": [
|
|
22
22
|
{
|
|
23
23
|
"path": ".claude/skills/backlog-review/SKILL.md",
|
|
@@ -2782,7 +2782,7 @@
|
|
|
2782
2782
|
{
|
|
2783
2783
|
"path": "docs/module-api-changelog.md",
|
|
2784
2784
|
"mode": "0000644",
|
|
2785
|
-
"sha256": "
|
|
2785
|
+
"sha256": "448e81f5dfb15330d406be135e4ada5c3cfcf0751fca4457a7c91ab58d836d10"
|
|
2786
2786
|
},
|
|
2787
2787
|
{
|
|
2788
2788
|
"path": "docs/modules-contract.md",
|
|
@@ -5662,7 +5662,7 @@
|
|
|
5662
5662
|
{
|
|
5663
5663
|
"path": "modules/lifecycle/db-rank-authz.js",
|
|
5664
5664
|
"mode": "0000644",
|
|
5665
|
-
"sha256": "
|
|
5665
|
+
"sha256": "e5feff1eb42ad631b6c0165c23224d8ac56ef7f40e5d238afb09013501e9db7c"
|
|
5666
5666
|
},
|
|
5667
5667
|
{
|
|
5668
5668
|
"path": "modules/lifecycle/db-shared.js",
|
|
@@ -7742,12 +7742,12 @@
|
|
|
7742
7742
|
{
|
|
7743
7743
|
"path": "package-lock.json",
|
|
7744
7744
|
"mode": "0000644",
|
|
7745
|
-
"sha256": "
|
|
7745
|
+
"sha256": "667fc77f1bfd67239fa405a73b70b64ec77419d97da57bc8350c96ba3c68197b"
|
|
7746
7746
|
},
|
|
7747
7747
|
{
|
|
7748
7748
|
"path": "package.json",
|
|
7749
7749
|
"mode": "0000644",
|
|
7750
|
-
"sha256": "
|
|
7750
|
+
"sha256": "9bee6edf68d9dc8177a24349a4c444c1829ff77619a511be70c8a49329726ac8"
|
|
7751
7751
|
},
|
|
7752
7752
|
{
|
|
7753
7753
|
"path": "public-docs/index.html",
|
|
@@ -9502,7 +9502,7 @@
|
|
|
9502
9502
|
{
|
|
9503
9503
|
"path": "src/module-api.js",
|
|
9504
9504
|
"mode": "0000644",
|
|
9505
|
-
"sha256": "
|
|
9505
|
+
"sha256": "3077ef167f846985e33e1d8316b78cefa5e7ff4825b9a0a7e1b71187a49e4636"
|
|
9506
9506
|
},
|
|
9507
9507
|
{
|
|
9508
9508
|
"path": "src/module-loader/catalog.js",
|
|
@@ -10847,7 +10847,7 @@
|
|
|
10847
10847
|
{
|
|
10848
10848
|
"path": "tests/government_claim_eligibility.mjs",
|
|
10849
10849
|
"mode": "0000644",
|
|
10850
|
-
"sha256": "
|
|
10850
|
+
"sha256": "1989a7e5e39a6bb177dfd86e610c0806c96fdc97f9149800de431af816f2c31a"
|
|
10851
10851
|
},
|
|
10852
10852
|
{
|
|
10853
10853
|
"path": "tests/government_config.mjs",
|
|
@@ -1759,5 +1759,7 @@ is load-bearing: the script throws rather than guess if it is missing, and
|
|
|
1759
1759
|
landed since 1.19.653 with no explicit bump. run 34544345437. (task 1002620)
|
|
1760
1760
|
1.19.655 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
1761
1761
|
landed since 1.19.654 with no explicit bump. run 34545744588. (task 1002620)
|
|
1762
|
+
1.19.656 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
1763
|
+
landed since 1.19.655 with no explicit bump. run 34546461767. (task 1002620)
|
|
1762
1764
|
---------------------------------------------------------------------------
|
|
1763
1765
|
```
|
|
@@ -80,15 +80,33 @@ function xenosClaimAllowed(rank, newcomerFriendly) {
|
|
|
80
80
|
|
|
81
81
|
// claimPermissionsFor — the builder's effective permission set for the claim
|
|
82
82
|
// decision, read through the `governance` kernel PORT (never by importing the
|
|
83
|
-
// module — the one-way rule, ADR 0083).
|
|
84
|
-
//
|
|
85
|
-
//
|
|
86
|
-
//
|
|
87
|
-
// • the
|
|
88
|
-
//
|
|
89
|
-
//
|
|
90
|
-
//
|
|
91
|
-
//
|
|
83
|
+
// module — the one-way rule, ADR 0083).
|
|
84
|
+
//
|
|
85
|
+
// NULL means authority could not be ESTABLISHED, which claimEligibilityAllows
|
|
86
|
+
// reads as "fall back to the incumbent rank rule". Exactly two things mean that:
|
|
87
|
+
// • the governance module is not mounted (no port), so there is no authority
|
|
88
|
+
// system to ask;
|
|
89
|
+
// • the resolver threw, so the answer is unknown rather than empty.
|
|
90
|
+
//
|
|
91
|
+
// AN EMPTY SET IS AN ANSWER, NOT A FAILURE (task 1003816). It used to be folded
|
|
92
|
+
// into the null above, on the stated grounds that governance_002's backfill was
|
|
93
|
+
// run-once and nothing re-assigned a rank-role afterwards — so a builder holding
|
|
94
|
+
// no role row was a live gap rather than a real verdict. That is no longer true,
|
|
95
|
+
// and the three writes that closed it are all shipped:
|
|
96
|
+
// • BV1.R95b rotates the role inside the rank-change transaction, and syncs it
|
|
97
|
+
// on every sign-in (src/bongos/auth-admission.js safeSyncRankRole);
|
|
98
|
+
// • task 1003193 rotates it in-tx on offboard AND reactivation;
|
|
99
|
+
// • governance_005 repaired the rows already written.
|
|
100
|
+
// governance_005 states the intended reading in as many words — a builder with no
|
|
101
|
+
// role row "resolves to the empty set (denied everywhere)" — and
|
|
102
|
+
// syncGovernanceRankRole calls that same outcome "the fail-closed answer". Folding
|
|
103
|
+
// it back into the rank rule is what stopped those three from being true at the
|
|
104
|
+
// claim gate, so the empty set now flows through as a real deny.
|
|
105
|
+
//
|
|
106
|
+
// The residual way to hold no role row is the sign-in sync failing transiently
|
|
107
|
+
// (it is deliberately best-effort so a governance hiccup cannot block a sign-in).
|
|
108
|
+
// Denying the claim is the correct read of that state, and it self-repairs on the
|
|
109
|
+
// next successful sign-in.
|
|
92
110
|
//
|
|
93
111
|
// Called BEFORE the claim transaction opens: authority is a per-request read (ADR
|
|
94
112
|
// 0016 — resolved server-side, uncached), and taking a second pool connection while
|
|
@@ -98,7 +116,9 @@ async function claimPermissionsFor(builderId) {
|
|
|
98
116
|
if (!governance || typeof governance.resolveBuilderPermissions !== 'function') return null;
|
|
99
117
|
try {
|
|
100
118
|
const keys = await governance.resolveBuilderPermissions(builderId);
|
|
101
|
-
|
|
119
|
+
// A non-array is a broken port contract, not a verdict — resolveBuilderPermissions
|
|
120
|
+
// always returns an array. Treat it as "could not establish", never as "denied".
|
|
121
|
+
if (!Array.isArray(keys)) return null;
|
|
102
122
|
return new Set(keys);
|
|
103
123
|
} catch (err) {
|
|
104
124
|
console.error('[gds] claim eligibility: permission resolve failed, falling back to the rank rule', err);
|
package/package-lock.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bongos/core",
|
|
3
|
-
"version": "1.19.
|
|
3
|
+
"version": "1.19.656",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@bongos/core",
|
|
9
|
-
"version": "1.19.
|
|
9
|
+
"version": "1.19.656",
|
|
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.19.
|
|
3
|
+
"version": "1.19.656",
|
|
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/src/module-api.js
CHANGED
|
@@ -71,7 +71,7 @@ const { responsibilityFor, ROLE_RESPONSIBILITIES } = require('./role-responsibil
|
|
|
71
71
|
// there. scripts/gds/bump-version.js still rewrites the literal below; it appends
|
|
72
72
|
// the entry to that file. Look for a version's history there, not here.
|
|
73
73
|
// ---------------------------------------------------------------------------
|
|
74
|
-
const CORE_VERSION = '1.19.
|
|
74
|
+
const CORE_VERSION = '1.19.656'; // CI auto-patch carrier (ADR 0161); changelog: docs/module-api-changelog.md
|
|
75
75
|
|
|
76
76
|
// A namespaced logger so a module's log lines are attributable + consistent.
|
|
77
77
|
// Usage: const log = api.logger('dev-box'); log.info('mounted');
|
|
@@ -37,6 +37,13 @@ const LIFECYCLE = path.join(ROOT, 'modules', 'lifecycle');
|
|
|
37
37
|
const eligibility = require(path.join(LIFECYCLE, 'claim-eligibility.js'));
|
|
38
38
|
const db = require(path.join(LIFECYCLE, 'db.js'));
|
|
39
39
|
const catalog = require(path.join(ROOT, 'modules', 'government', 'catalog.js'));
|
|
40
|
+
// The doorway, so section D can stand a stub `government` port up in front of the
|
|
41
|
+
// REAL claimPermissionsFor instead of re-implementing its branches in the test.
|
|
42
|
+
const moduleApi = require(path.join(ROOT, 'src', 'module-api.js'));
|
|
43
|
+
// claimPermissionsFor is NOT on the db.js facade — db-claims.js imports it from
|
|
44
|
+
// the authz module directly, so the test reads it from the same place the real
|
|
45
|
+
// caller does rather than from a re-export that does not exist.
|
|
46
|
+
const rankAuthz = require(path.join(LIFECYCLE, 'db-rank-authz.js'));
|
|
40
47
|
import { lifecycleDbSource } from './helpers.mjs';
|
|
41
48
|
|
|
42
49
|
const { CLAIM_ANY, CLAIM_NEWCOMER, permissionAllowsClaim, claimEligibilityAllows } = eligibility;
|
|
@@ -262,3 +269,78 @@ test('the abuse case stays blocked: a xenos cannot reach the general queue by an
|
|
|
262
269
|
assert.equal(permissionAllowsClaim(held, false), false);
|
|
263
270
|
assert.equal(permissionAllowsClaim(held, true), true);
|
|
264
271
|
});
|
|
272
|
+
|
|
273
|
+
// --- D. claimPermissionsFor's three-way answer (task 1003816) ---------------
|
|
274
|
+
//
|
|
275
|
+
// The function this section covers had NO test of its own: every case above
|
|
276
|
+
// drives the pure consumer (claimEligibilityAllows) with a hand-made
|
|
277
|
+
// heldPermissions value, so nothing proved which value the REAL reader produces.
|
|
278
|
+
// That is exactly where the bug lived — an empty permission set was folded in
|
|
279
|
+
// with "could not establish authority" and silently became a rank-rule fallback.
|
|
280
|
+
//
|
|
281
|
+
// The distinction is the whole point, so it is asserted as a distinction: null
|
|
282
|
+
// (fall back) for the two unestablished cases, a Set (a real verdict, denied when
|
|
283
|
+
// empty) whenever the resolver actually answered.
|
|
284
|
+
const realResolveOptional = moduleApi.resolveOptional;
|
|
285
|
+
async function withGovernance(stub, fn) {
|
|
286
|
+
moduleApi.resolveOptional = (name) => (name === 'government' ? stub : realResolveOptional.call(moduleApi, name));
|
|
287
|
+
try { return await fn(); } finally { moduleApi.resolveOptional = realResolveOptional; }
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
test('no governance port — authority cannot be established, so the rank rule decides', async () => {
|
|
291
|
+
await withGovernance(undefined, async () => {
|
|
292
|
+
assert.equal(await rankAuthz.claimPermissionsFor('42'), null);
|
|
293
|
+
});
|
|
294
|
+
// A port object that does not implement the resolver is the same situation.
|
|
295
|
+
await withGovernance({}, async () => {
|
|
296
|
+
assert.equal(await rankAuthz.claimPermissionsFor('42'), null);
|
|
297
|
+
});
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
test('the resolver throwing is UNKNOWN, not empty — still the rank rule', async () => {
|
|
301
|
+
await withGovernance({ resolveBuilderPermissions: async () => { throw new Error('synthetic resolver outage'); } }, async () => {
|
|
302
|
+
assert.equal(await rankAuthz.claimPermissionsFor('42'), null);
|
|
303
|
+
});
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
test('a broken port contract (non-array) is unknown, never a deny', async () => {
|
|
307
|
+
for (const bad of [null, undefined, 'task.claim.any', 42, {}]) {
|
|
308
|
+
await withGovernance({ resolveBuilderPermissions: async () => bad }, async () => {
|
|
309
|
+
assert.equal(await rankAuthz.claimPermissionsFor('42'), null, `a ${typeof bad} return must not read as "denied"`);
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
test('ZERO permissions is a real verdict now, not a fallback (the 1003816 fix)', async () => {
|
|
315
|
+
await withGovernance({ resolveBuilderPermissions: async () => [] }, async () => {
|
|
316
|
+
const held = await rankAuthz.claimPermissionsFor('42');
|
|
317
|
+
assert.ok(held instanceof Set, 'an answered resolve returns a Set, so the rank rule is NOT consulted');
|
|
318
|
+
assert.equal(held.size, 0);
|
|
319
|
+
// And the consumer turns that into a deny for every queue, however permissive
|
|
320
|
+
// the incumbent rank rule would have been.
|
|
321
|
+
for (const nf of NF_VALUES) {
|
|
322
|
+
assert.equal(
|
|
323
|
+
claimEligibilityAllows({ heldPermissions: held, newcomerFriendly: nf, rankRuleAllows: true }),
|
|
324
|
+
false,
|
|
325
|
+
'a builder with no role row is denied even where the rank rule would allow',
|
|
326
|
+
);
|
|
327
|
+
}
|
|
328
|
+
});
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
test('a real permission set is passed through as the verdict', async () => {
|
|
332
|
+
await withGovernance({ resolveBuilderPermissions: async () => [CLAIM_ANY] }, async () => {
|
|
333
|
+
const held = await rankAuthz.claimPermissionsFor('42');
|
|
334
|
+
assert.ok(held instanceof Set);
|
|
335
|
+
assert.equal(held.has(CLAIM_ANY), true);
|
|
336
|
+
assert.equal(claimEligibilityAllows({ heldPermissions: held, newcomerFriendly: false, rankRuleAllows: false }), true);
|
|
337
|
+
});
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
test('the doc comment no longer argues for the fallback it describes retiring', () => {
|
|
341
|
+
const src = fs.readFileSync(path.join(LIFECYCLE, 'db-rank-authz.js'), 'utf8');
|
|
342
|
+
assert.ok(
|
|
343
|
+
!/nothing yet re-assigns a rank-role/.test(src),
|
|
344
|
+
'the stale "nothing yet re-assigns a rank-role" claim is false since BV1.R95b + task 1003193 — it must not survive the fix',
|
|
345
|
+
);
|
|
346
|
+
});
|