@bongos/core 1.19.782 → 1.19.783
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 +17 -12
- package/docs/module-api-changelog.md +2 -0
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/scripts/gds/start.js +26 -3
- package/src/module-api.js +1 -1
- package/tests/start_inbox_count.mjs +112 -0
package/.bongos-core.json
CHANGED
|
@@ -2,22 +2,22 @@
|
|
|
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.783",
|
|
6
|
+
"core_contract": "1.19.783",
|
|
7
|
+
"source_commit": "6e5366479023ac5cbbd19fda61ebf8abc48a6113",
|
|
8
8
|
"source_ref": "HEAD",
|
|
9
|
-
"built_at": "2026-09-16T21:
|
|
9
|
+
"built_at": "2026-09-16T21:29:40.397Z",
|
|
10
10
|
"redaction": {
|
|
11
11
|
"model": "docs-redacted+functional-verbatim",
|
|
12
12
|
"docs_redacted": 482,
|
|
13
13
|
"agent_docs_stubbed": 25,
|
|
14
|
-
"functional_verbatim":
|
|
14
|
+
"functional_verbatim": 2154,
|
|
15
15
|
"rules": 3,
|
|
16
16
|
"gate_literals": 3,
|
|
17
17
|
"gate": "passed"
|
|
18
18
|
},
|
|
19
|
-
"file_count":
|
|
20
|
-
"tree_sha256": "
|
|
19
|
+
"file_count": 2661,
|
|
20
|
+
"tree_sha256": "76a7394b33c9a3c9d901bfc6016b4cc40c410b80f7958034ce571b72e952fdda",
|
|
21
21
|
"files": [
|
|
22
22
|
{
|
|
23
23
|
"path": ".claude/skills/ask-for-help/SKILL.md",
|
|
@@ -2507,7 +2507,7 @@
|
|
|
2507
2507
|
{
|
|
2508
2508
|
"path": "docs/module-api-changelog.md",
|
|
2509
2509
|
"mode": "0000644",
|
|
2510
|
-
"sha256": "
|
|
2510
|
+
"sha256": "a57c986ed1da32c1bd0bbb2724b8cf178e5df174970f1d1fac2b5a42d36d2279"
|
|
2511
2511
|
},
|
|
2512
2512
|
{
|
|
2513
2513
|
"path": "docs/modules-contract.md",
|
|
@@ -7612,12 +7612,12 @@
|
|
|
7612
7612
|
{
|
|
7613
7613
|
"path": "package-lock.json",
|
|
7614
7614
|
"mode": "0000644",
|
|
7615
|
-
"sha256": "
|
|
7615
|
+
"sha256": "e998a3dbacba277f1fce790f6b672738f339819dd866d3bef1896aee8a44d4a8"
|
|
7616
7616
|
},
|
|
7617
7617
|
{
|
|
7618
7618
|
"path": "package.json",
|
|
7619
7619
|
"mode": "0000644",
|
|
7620
|
-
"sha256": "
|
|
7620
|
+
"sha256": "914d6c6f028d4708afd08513c3e04f062098d14a4d08e2061c5051db928d026a"
|
|
7621
7621
|
},
|
|
7622
7622
|
{
|
|
7623
7623
|
"path": "public-docs/index.html",
|
|
@@ -8977,7 +8977,7 @@
|
|
|
8977
8977
|
{
|
|
8978
8978
|
"path": "scripts/gds/start.js",
|
|
8979
8979
|
"mode": "0000644",
|
|
8980
|
-
"sha256": "
|
|
8980
|
+
"sha256": "3b9cbebddc633952450ee38c933e42b465bd107edb28532ada58a113d6b5cbe5"
|
|
8981
8981
|
},
|
|
8982
8982
|
{
|
|
8983
8983
|
"path": "scripts/gds/status.js",
|
|
@@ -9477,7 +9477,7 @@
|
|
|
9477
9477
|
{
|
|
9478
9478
|
"path": "src/module-api.js",
|
|
9479
9479
|
"mode": "0000644",
|
|
9480
|
-
"sha256": "
|
|
9480
|
+
"sha256": "2b4da6b2263db105e394608f3043a0b7c1c46eb43b36928ccb2f761ccfb2ea6a"
|
|
9481
9481
|
},
|
|
9482
9482
|
{
|
|
9483
9483
|
"path": "src/module-loader/catalog.js",
|
|
@@ -12934,6 +12934,11 @@
|
|
|
12934
12934
|
"mode": "0000644",
|
|
12935
12935
|
"sha256": "dd7171dbc59e024de99a063763219237814cf4c943fb3d873cc324f3bfde7f25"
|
|
12936
12936
|
},
|
|
12937
|
+
{
|
|
12938
|
+
"path": "tests/start_inbox_count.mjs",
|
|
12939
|
+
"mode": "0000644",
|
|
12940
|
+
"sha256": "525f37837e39059c1b40c99b117764ba0547b803f01d709e80354744ad3438b7"
|
|
12941
|
+
},
|
|
12937
12942
|
{
|
|
12938
12943
|
"path": "tests/start_rebase_warning.mjs",
|
|
12939
12944
|
"mode": "0000644",
|
|
@@ -2038,5 +2038,7 @@ is load-bearing: the script throws rather than guess if it is missing, and
|
|
|
2038
2038
|
landed since 1.19.780 with no explicit bump. run 35150109281. (task 1002620)
|
|
2039
2039
|
1.19.782 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
2040
2040
|
landed since 1.19.781 with no explicit bump. run 35150844959. (task 1002620)
|
|
2041
|
+
1.19.783 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
2042
|
+
landed since 1.19.782 with no explicit bump. run 35152631705. (task 1002620)
|
|
2041
2043
|
---------------------------------------------------------------------------
|
|
2042
2044
|
```
|
package/package-lock.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bongos/core",
|
|
3
|
-
"version": "1.19.
|
|
3
|
+
"version": "1.19.783",
|
|
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.783",
|
|
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.783",
|
|
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/scripts/gds/start.js
CHANGED
|
@@ -112,6 +112,30 @@ function formatCostRow(cost) {
|
|
|
112
112
|
return `${fmtUsd(spent)} logged spend · ${credits}c reward shipped`;
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
+
// inboxOpenCount — how many ideas are OPEN in the inbox, from a GET /inbox response.
|
|
116
|
+
//
|
|
117
|
+
// WHY THIS IS NOT ideas.length (task 1003454). GET /inbox answers
|
|
118
|
+
// { ideas, open_count }, where `ideas` is a PAGE (default 50 rows) and
|
|
119
|
+
// `open_count` is the real total, counted server-side under the same rank gate
|
|
120
|
+
// as the rows. Reading the array length therefore reported the page size: the
|
|
121
|
+
// card said "50 ideas in inbox" while the payload said 99, and once the queue
|
|
122
|
+
// passed one page the figure pinned at exactly 50 forever — a number that looks
|
|
123
|
+
// plausible, never moves, and understates the backlog the card exists to make
|
|
124
|
+
// visible. capture.js already destructured open_count correctly, which is what
|
|
125
|
+
// made this an oversight rather than a convention.
|
|
126
|
+
//
|
|
127
|
+
// The page length stays as a FALLBACK so an older core that predates open_count
|
|
128
|
+
// still renders a figure rather than "N/A". Returns null when neither is
|
|
129
|
+
// readable, which the callers render as "ideas: N/A".
|
|
130
|
+
function inboxOpenCount(inboxRes) {
|
|
131
|
+
if (!inboxRes || !inboxRes.ok) return null;
|
|
132
|
+
const data = inboxRes.data;
|
|
133
|
+
if (data && typeof data.open_count === 'number') return data.open_count;
|
|
134
|
+
if (data && Array.isArray(data.ideas)) return data.ideas.length;
|
|
135
|
+
if (data && typeof data.count === 'number') return data.count;
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
|
|
115
139
|
function formatRecentRow({ recentShipped, inboxCount, blockerCount }) {
|
|
116
140
|
const bits = [];
|
|
117
141
|
// "1 ship in last 24h" — recent_shipped returns tasks shipped within
|
|
@@ -741,9 +765,7 @@ async function main() {
|
|
|
741
765
|
const progress = progressRes.ok && Array.isArray(progressRes.data?.progress) ? progressRes.data.progress : null;
|
|
742
766
|
const cost = costRes.ok ? costRes.data : null;
|
|
743
767
|
const recentShipped = recentRes.ok && Array.isArray(recentRes.data?.tasks) ? recentRes.data.tasks : null;
|
|
744
|
-
const inboxCount =
|
|
745
|
-
? inboxRes.data.ideas.length
|
|
746
|
-
: (inboxRes.ok && typeof inboxRes.data?.count === 'number' ? inboxRes.data.count : null);
|
|
768
|
+
const inboxCount = inboxOpenCount(inboxRes);
|
|
747
769
|
const blockerCount = blockersRes.ok && Array.isArray(blockersRes.data?.blockers)
|
|
748
770
|
? blockersRes.data.blockers.filter((b) => b.status === 'open' || !b.status).length
|
|
749
771
|
: null;
|
|
@@ -1023,6 +1045,7 @@ if (require.main === module) {
|
|
|
1023
1045
|
}
|
|
1024
1046
|
|
|
1025
1047
|
module.exports = {
|
|
1048
|
+
inboxOpenCount,
|
|
1026
1049
|
rankCrossDisciplineRecommendations,
|
|
1027
1050
|
rebaseWarningModel,
|
|
1028
1051
|
rebaseWarningMarkdown,
|
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.783'; // 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');
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
// tests/start_inbox_count.mjs
|
|
2
|
+
//
|
|
3
|
+
// task 1003454 — /builder-start's "N ideas in inbox" figure must be the inbox's
|
|
4
|
+
// OPEN COUNT, not the length of the page it happened to be served.
|
|
5
|
+
//
|
|
6
|
+
// GET /inbox answers { ideas, open_count }: `ideas` is a page (default 50 rows)
|
|
7
|
+
// and `open_count` is the real total, counted server-side under the same rank
|
|
8
|
+
// gate as the rows. start.js read `ideas.length`, so the card reported the page
|
|
9
|
+
// size — measured live at "50 ideas in inbox" against an open_count of 99, and
|
|
10
|
+
// pinned at exactly 50 for any queue larger than one page.
|
|
11
|
+
//
|
|
12
|
+
// Exercises the pure helper start.js exports, DB-free — no live server, mirroring
|
|
13
|
+
// start_rebase_warning.mjs. The invariants under test:
|
|
14
|
+
// - open_count wins whenever it is present, INCLUDING when it disagrees with
|
|
15
|
+
// the page length (the regression's exact shape)
|
|
16
|
+
// - a queue larger than one page reports honestly, not the page size
|
|
17
|
+
// - 0 is a real answer, not a missing one (the falsy trap)
|
|
18
|
+
// - the page length survives as a fallback for a core predating open_count
|
|
19
|
+
// - an unreadable/failed response is null, which renders as "ideas: N/A"
|
|
20
|
+
//
|
|
21
|
+
// Run: node tests/start_inbox_count.mjs
|
|
22
|
+
|
|
23
|
+
import { strict as assert } from 'node:assert';
|
|
24
|
+
import { createRequire } from 'node:module';
|
|
25
|
+
import fs from 'node:fs';
|
|
26
|
+
|
|
27
|
+
const require = createRequire(import.meta.url);
|
|
28
|
+
const START_PATH = require.resolve('../scripts/gds/start.js');
|
|
29
|
+
const { inboxOpenCount } = require(START_PATH);
|
|
30
|
+
|
|
31
|
+
let passed = 0;
|
|
32
|
+
let failed = 0;
|
|
33
|
+
function t(name, fn) {
|
|
34
|
+
try { fn(); passed++; console.log(` PASS ${name}`); }
|
|
35
|
+
catch (e) { failed++; console.log(` FAIL ${name}\n ${e.message}`); }
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
t('the helper is exported (the test cannot silently cover nothing)', () => {
|
|
39
|
+
assert.equal(typeof inboxOpenCount, 'function');
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
// --- the regression itself -------------------------------------------------
|
|
43
|
+
|
|
44
|
+
t('open_count wins over the page length — the measured 50-vs-99 case', () => {
|
|
45
|
+
const res = { ok: true, data: { ideas: new Array(50).fill({}), open_count: 99 } };
|
|
46
|
+
assert.equal(inboxOpenCount(res), 99, 'must report the real total, not the page');
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
t('a queue larger than one page does not pin at the page size', () => {
|
|
50
|
+
// The old code returned 50 for every one of these; the figure never moved.
|
|
51
|
+
for (const total of [51, 99, 250, 1000]) {
|
|
52
|
+
const res = { ok: true, data: { ideas: new Array(50).fill({}), open_count: total } };
|
|
53
|
+
assert.equal(inboxOpenCount(res), total, `expected ${total}`);
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
t('a queue smaller than a page still reads open_count (page length agrees)', () => {
|
|
58
|
+
const res = { ok: true, data: { ideas: new Array(7).fill({}), open_count: 7 } };
|
|
59
|
+
assert.equal(inboxOpenCount(res), 7);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
t('zero open ideas is a real answer, not a missing one', () => {
|
|
63
|
+
// The falsy trap: `open_count || ideas.length` would fall through to the page
|
|
64
|
+
// here, so an empty inbox and an unreadable one would render identically.
|
|
65
|
+
const res = { ok: true, data: { ideas: [], open_count: 0 } };
|
|
66
|
+
assert.equal(inboxOpenCount(res), 0);
|
|
67
|
+
assert.notEqual(inboxOpenCount(res), null, 'an empty inbox must not render as N/A');
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
// --- the fallbacks ---------------------------------------------------------
|
|
71
|
+
|
|
72
|
+
t('page length is the fallback when open_count is absent (older core)', () => {
|
|
73
|
+
const res = { ok: true, data: { ideas: new Array(12).fill({}) } };
|
|
74
|
+
assert.equal(inboxOpenCount(res), 12);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
t('a non-numeric open_count does not poison the figure', () => {
|
|
78
|
+
const res = { ok: true, data: { ideas: new Array(4).fill({}), open_count: '99' } };
|
|
79
|
+
assert.equal(inboxOpenCount(res), 4, 'a string count is not a count; fall back to the page');
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
t('the legacy `count` field is still honoured when there are no rows to count', () => {
|
|
83
|
+
const res = { ok: true, data: { count: 5 } };
|
|
84
|
+
assert.equal(inboxOpenCount(res), 5);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
// --- the null paths (rendered as "ideas: N/A") -----------------------------
|
|
88
|
+
|
|
89
|
+
t('a failed request is null, never 0', () => {
|
|
90
|
+
const res = { ok: false, data: { ideas: new Array(50).fill({}), open_count: 99 } };
|
|
91
|
+
assert.equal(inboxOpenCount(res), null, 'a failed read must not report a figure');
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
t('missing / malformed responses are null, and never throw', () => {
|
|
95
|
+
for (const res of [null, undefined, {}, { ok: true }, { ok: true, data: null },
|
|
96
|
+
{ ok: true, data: 'nope' }, { ok: true, data: { ideas: 'nope' } }]) {
|
|
97
|
+
assert.equal(inboxOpenCount(res), null, `expected null for ${JSON.stringify(res)}`);
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
// --- the guard: the bug must not be reintroduced in the caller -------------
|
|
102
|
+
|
|
103
|
+
t('the card derivation calls the helper — no inline ideas.length survives', () => {
|
|
104
|
+
const src = fs.readFileSync(START_PATH, 'utf8');
|
|
105
|
+
assert.match(src, /const inboxCount = inboxOpenCount\(inboxRes\);/,
|
|
106
|
+
'the header derivation must go through the helper');
|
|
107
|
+
assert.doesNotMatch(src, /inboxRes\.data\?\.ideas\.length/,
|
|
108
|
+
'no caller may read the page length directly again');
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
console.log(`\nstart_inbox_count: ${passed} passed, ${failed} failed`);
|
|
112
|
+
process.exit(failed ? 1 : 0);
|