@bongos/core 1.19.40 → 1.19.41
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 +13 -13
- package/modules/lifecycle/db.js +4 -1
- package/modules/lifecycle/done-when.js +4 -2
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/src/module-api.js +3 -1
- package/tests/criterion_progress.mjs +34 -0
- package/tests/goal_achievement.mjs +3 -1
- package/tests/goal_routes.mjs +11 -0
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.41",
|
|
6
|
+
"core_contract": "1.19.41",
|
|
7
|
+
"source_commit": "ef65ee2c6121ae010e5ad2c1ac67b349cf9b9161",
|
|
8
8
|
"source_ref": "HEAD",
|
|
9
|
-
"built_at": "2026-08-11T16:
|
|
9
|
+
"built_at": "2026-08-11T16:42:56.706Z",
|
|
10
10
|
"redaction": {
|
|
11
11
|
"model": "docs-redacted+functional-verbatim",
|
|
12
12
|
"docs_redacted": 289,
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"gate": "passed"
|
|
18
18
|
},
|
|
19
19
|
"file_count": 1523,
|
|
20
|
-
"tree_sha256": "
|
|
20
|
+
"tree_sha256": "8bdaf758774aaff55446f0ca5ac714795f728937d893a1085e21cf14db853915",
|
|
21
21
|
"files": [
|
|
22
22
|
{
|
|
23
23
|
"path": ".claude/skills/blocker-review/SKILL.md",
|
|
@@ -3377,12 +3377,12 @@
|
|
|
3377
3377
|
{
|
|
3378
3378
|
"path": "modules/lifecycle/db.js",
|
|
3379
3379
|
"mode": "0000644",
|
|
3380
|
-
"sha256": "
|
|
3380
|
+
"sha256": "57c88852ff0aa9f0b3673fa62b35f352d92cc9070e7872137003e395c42eb026"
|
|
3381
3381
|
},
|
|
3382
3382
|
{
|
|
3383
3383
|
"path": "modules/lifecycle/done-when.js",
|
|
3384
3384
|
"mode": "0000644",
|
|
3385
|
-
"sha256": "
|
|
3385
|
+
"sha256": "4e6f6af1cdaf026466155c1b0656a0e89872aa2bb264f36c50997ec4f069e808"
|
|
3386
3386
|
},
|
|
3387
3387
|
{
|
|
3388
3388
|
"path": "modules/lifecycle/github-push.js",
|
|
@@ -4027,12 +4027,12 @@
|
|
|
4027
4027
|
{
|
|
4028
4028
|
"path": "package-lock.json",
|
|
4029
4029
|
"mode": "0000644",
|
|
4030
|
-
"sha256": "
|
|
4030
|
+
"sha256": "3d5765b40ed913e05bea697ecb878e98fa799e667a5352d4d8f37236a0b671b4"
|
|
4031
4031
|
},
|
|
4032
4032
|
{
|
|
4033
4033
|
"path": "package.json",
|
|
4034
4034
|
"mode": "0000644",
|
|
4035
|
-
"sha256": "
|
|
4035
|
+
"sha256": "552a8ef2e0d6b1a69377cbf67bdc0b49574312a68b0ac4162bc606db5870afff"
|
|
4036
4036
|
},
|
|
4037
4037
|
{
|
|
4038
4038
|
"path": "public-docs/index.html",
|
|
@@ -5652,7 +5652,7 @@
|
|
|
5652
5652
|
{
|
|
5653
5653
|
"path": "src/module-api.js",
|
|
5654
5654
|
"mode": "0000644",
|
|
5655
|
-
"sha256": "
|
|
5655
|
+
"sha256": "f1c39c1f5862092c57f1c5f5232dfce0a9ac41376838899c92c286df3178936f"
|
|
5656
5656
|
},
|
|
5657
5657
|
{
|
|
5658
5658
|
"path": "src/module-loader/loader.js",
|
|
@@ -6172,7 +6172,7 @@
|
|
|
6172
6172
|
{
|
|
6173
6173
|
"path": "tests/criterion_progress.mjs",
|
|
6174
6174
|
"mode": "0000644",
|
|
6175
|
-
"sha256": "
|
|
6175
|
+
"sha256": "e5b5ccf87a34658b3b25e4289caf702fbc44d77bacfec5bd823d5f6666ff213b"
|
|
6176
6176
|
},
|
|
6177
6177
|
{
|
|
6178
6178
|
"path": "tests/criterion_proposal.mjs",
|
|
@@ -6442,7 +6442,7 @@
|
|
|
6442
6442
|
{
|
|
6443
6443
|
"path": "tests/goal_achievement.mjs",
|
|
6444
6444
|
"mode": "0000644",
|
|
6445
|
-
"sha256": "
|
|
6445
|
+
"sha256": "a6ddb674d4ce1f6da9eb7b653ef92b9f0fcc85387e70bdf5358aff84ef518824"
|
|
6446
6446
|
},
|
|
6447
6447
|
{
|
|
6448
6448
|
"path": "tests/goal_advisory.mjs",
|
|
@@ -6482,7 +6482,7 @@
|
|
|
6482
6482
|
{
|
|
6483
6483
|
"path": "tests/goal_routes.mjs",
|
|
6484
6484
|
"mode": "0000644",
|
|
6485
|
-
"sha256": "
|
|
6485
|
+
"sha256": "4fd3ec8ef855b0131e17931908e9aebf16238d45febdf0b8306e2908152e2655"
|
|
6486
6486
|
},
|
|
6487
6487
|
{
|
|
6488
6488
|
"path": "tests/goal_scope_check.mjs",
|
package/modules/lifecycle/db.js
CHANGED
|
@@ -893,7 +893,10 @@ async function listCriteriaForGoal(goalId, deps = {}) {
|
|
|
893
893
|
counts AS (
|
|
894
894
|
SELECT tc.criterion_id,
|
|
895
895
|
count(*)::int AS linked_tasks,
|
|
896
|
-
|
|
896
|
+
-- task 1002651 (migration 017's family): abandoned is a terminal
|
|
897
|
+
-- state (deliberately cut), not pending work — it must not hold a
|
|
898
|
+
-- criterion's "met — pending review" flip hostage forever.
|
|
899
|
+
count(*) FILTER (WHERE t.status NOT IN ('shipped', 'abandoned'))::int AS unshipped_tasks
|
|
897
900
|
FROM task_criteria tc
|
|
898
901
|
JOIN tasks t ON t.id = tc.task_id
|
|
899
902
|
WHERE tc.criterion_id IN (SELECT id FROM crit)
|
|
@@ -126,7 +126,7 @@ async function listPendingReviewCriteria({ versionId = null } = {}, deps = {}) {
|
|
|
126
126
|
JOIN tasks t ON t.id = tc.task_id
|
|
127
127
|
WHERE c.satisfied = false
|
|
128
128
|
GROUP BY c.id
|
|
129
|
-
HAVING count(*) FILTER (WHERE t.status
|
|
129
|
+
HAVING count(*) FILTER (WHERE t.status NOT IN ('shipped', 'abandoned')) = 0
|
|
130
130
|
),
|
|
131
131
|
goal_unsat AS (
|
|
132
132
|
SELECT goal_id, count(*)::int AS unsatisfied
|
|
@@ -269,7 +269,9 @@ function buildCriterionProgress(versionId, rows, unattributedCount = 0, goalRows
|
|
|
269
269
|
const counts = { total: c.tasks.length };
|
|
270
270
|
for (const t of c.tasks) counts[t.status] = (counts[t.status] || 0) + 1;
|
|
271
271
|
const shipped = counts.shipped || 0;
|
|
272
|
-
|
|
272
|
+
// task 1002651: abandoned is terminal (cut work, migration 017's family) —
|
|
273
|
+
// it is not "remaining" and must not block the pending-review flip.
|
|
274
|
+
const remaining = c.tasks.filter((t) => t.status !== 'shipped' && t.status !== 'abandoned');
|
|
273
275
|
// Auto-flag (ADR 0086 §6 / BV1.R63): a criterion is "met — pending review"
|
|
274
276
|
// when it has ≥1 linked task and every one has shipped, but it has NOT yet
|
|
275
277
|
// been confirmed (satisfied=false). Purely DERIVED — no stored column, no
|
package/package-lock.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bongos/core",
|
|
3
|
-
"version": "1.19.
|
|
3
|
+
"version": "1.19.41",
|
|
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.41",
|
|
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.41",
|
|
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
|
@@ -507,8 +507,10 @@ const { validateOrRespond, LIMITS, parseId, asyncHandler, corsPublicGet, parsePa
|
|
|
507
507
|
// landed since 1.19.38 with no explicit bump. run 31512284325. (task 1002620)
|
|
508
508
|
// 1.19.40 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
509
509
|
// landed since 1.19.39 with no explicit bump. run 31513136724. (task 1002620)
|
|
510
|
+
// 1.19.41 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
511
|
+
// landed since 1.19.40 with no explicit bump. run 31513793491. (task 1002620)
|
|
510
512
|
// ---------------------------------------------------------------------------
|
|
511
|
-
const CORE_VERSION = '1.19.
|
|
513
|
+
const CORE_VERSION = '1.19.41'; // CI auto-patch carrier (ADR 0161); see changelog above
|
|
512
514
|
|
|
513
515
|
// A namespaced logger so a module's log lines are attributable + consistent.
|
|
514
516
|
// Usage: const log = api.logger('dev-box'); log.info('mounted');
|
|
@@ -247,6 +247,40 @@ test('isPendingReview: agrees with the rollup it was extracted from', () => {
|
|
|
247
247
|
assert.equal(b.pending_review, false);
|
|
248
248
|
});
|
|
249
249
|
|
|
250
|
+
// --- task 1002651 (idea 1000635): abandoned tasks are terminal, not "remaining" ---
|
|
251
|
+
|
|
252
|
+
test('1002651 one shipped + one abandoned → remaining=0, criterion flips to pending review', () => {
|
|
253
|
+
const rows = [
|
|
254
|
+
row(1, 20, 'c-ab', false, 300, 'landed', 'shipped'),
|
|
255
|
+
row(1, 20, 'c-ab', false, 301, 'cut', 'abandoned'),
|
|
256
|
+
];
|
|
257
|
+
const c = buildCriterionProgress('V', rows, 0).criteria[0];
|
|
258
|
+
assert.equal(c.counts.remaining, 0, 'the abandoned task no longer counts as unshipped');
|
|
259
|
+
assert.deepEqual(c.remaining, [], 'the remaining list omits deliberately-cut work');
|
|
260
|
+
assert.equal(c.counts.abandoned, 1, 'the per-status bucket still reports it honestly');
|
|
261
|
+
assert.equal(c.pending_review, true, 'the criterion surfaces for human confirm instead of hanging forever');
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
test('1002651 abandoned does not hide genuinely unshipped work', () => {
|
|
265
|
+
const rows = [
|
|
266
|
+
row(1, 21, 'c-mix', false, 310, 'landed', 'shipped'),
|
|
267
|
+
row(1, 21, 'c-mix', false, 311, 'cut', 'abandoned'),
|
|
268
|
+
row(1, 21, 'c-mix', false, 312, 'in-flight', 'ready'),
|
|
269
|
+
];
|
|
270
|
+
const c = buildCriterionProgress('V', rows, 0).criteria[0];
|
|
271
|
+
assert.equal(c.counts.remaining, 1);
|
|
272
|
+
assert.deepEqual(c.remaining.map((t) => t.id), [312], 'only the live task remains');
|
|
273
|
+
assert.equal(c.pending_review, false, 'live work still blocks the flip');
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
test('1002651 an all-abandoned criterion surfaces for review rather than auto-satisfying silently', () => {
|
|
277
|
+
const rows = [row(1, 22, 'c-cut', false, 320, 'cut', 'abandoned')];
|
|
278
|
+
const c = buildCriterionProgress('V', rows, 0).criteria[0];
|
|
279
|
+
// linked>0 + unshipped=0 → pending review: a human confirms or rejects what
|
|
280
|
+
// "met" means for a criterion whose entire linked work was cut.
|
|
281
|
+
assert.equal(c.pending_review, true);
|
|
282
|
+
});
|
|
283
|
+
|
|
250
284
|
console.log('');
|
|
251
285
|
console.log(`criterionProgress aggregation tests: ${passed} passed, ${failed} failed`);
|
|
252
286
|
if (failed > 0) process.exit(1);
|
|
@@ -138,7 +138,9 @@ await test('listPendingReviewCriteria: SQL encodes the auto-flag (all shipped) +
|
|
|
138
138
|
const sql = String(find(pool.queries, /WITH pending AS/).sql).replace(/\s+/g, ' ');
|
|
139
139
|
// The derivation: satisfied=false AND every linked task shipped (zero non-shipped).
|
|
140
140
|
assert.match(sql, /c\.satisfied = false/, 'only unconfirmed criteria are pending');
|
|
141
|
-
|
|
141
|
+
// task 1002651: abandoned is terminal (cut work) — it must not hold the queue
|
|
142
|
+
// entry hostage, so the filter counts only live-and-unshipped tasks.
|
|
143
|
+
assert.match(sql, /HAVING count\(\*\) FILTER \(WHERE t\.status NOT IN \('shipped', 'abandoned'\)\) = 0/, 'all LIVE linked tasks must be shipped');
|
|
142
144
|
assert.match(sql, /is_last_in_goal/, 'surfaces whether confirming completes the goal');
|
|
143
145
|
});
|
|
144
146
|
|
package/tests/goal_routes.mjs
CHANGED
|
@@ -173,6 +173,17 @@ await test('listCriteriaForGoal: pending_review false once the criterion is conf
|
|
|
173
173
|
assert.equal(out.pending_review, false);
|
|
174
174
|
});
|
|
175
175
|
|
|
176
|
+
await test('listCriteriaForGoal: the unshipped filter excludes abandoned (task 1002651)', async () => {
|
|
177
|
+
const pool = critPool([critRow()]);
|
|
178
|
+
await listCriteriaForGoal(3, { pool });
|
|
179
|
+
const sel = find(pool.queries, CRIT_SQL_RE);
|
|
180
|
+
assert.match(
|
|
181
|
+
sel.sql,
|
|
182
|
+
/FILTER \(WHERE t\.status NOT IN \('shipped', 'abandoned'\)\)/,
|
|
183
|
+
'an abandoned linked task must not hold the pending-review flip hostage (migration 017 family)'
|
|
184
|
+
);
|
|
185
|
+
});
|
|
186
|
+
|
|
176
187
|
await test('listCriteriaForGoal: pending_review false with NO linked tasks (vacuous truth guard)', async () => {
|
|
177
188
|
const pool = critPool([critRow({ satisfied: false, linked_tasks: 0, unshipped_tasks: 0 })]);
|
|
178
189
|
const [out] = await listCriteriaForGoal(3, { pool });
|