@bongos/core 1.19.708 → 1.19.709
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,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.709",
|
|
6
|
+
"core_contract": "1.19.709",
|
|
7
|
+
"source_commit": "e931b6db287584c48e0e0fbb4f302198e7ad7ae1",
|
|
8
8
|
"source_ref": "HEAD",
|
|
9
|
-
"built_at": "2026-09-13T06:
|
|
9
|
+
"built_at": "2026-09-13T06:55:41.726Z",
|
|
10
10
|
"redaction": {
|
|
11
11
|
"model": "docs-redacted+functional-verbatim",
|
|
12
12
|
"docs_redacted": 477,
|
|
13
13
|
"agent_docs_stubbed": 24,
|
|
14
|
-
"functional_verbatim":
|
|
14
|
+
"functional_verbatim": 2140,
|
|
15
15
|
"rules": 3,
|
|
16
16
|
"gate_literals": 3,
|
|
17
17
|
"gate": "passed"
|
|
18
18
|
},
|
|
19
|
-
"file_count":
|
|
20
|
-
"tree_sha256": "
|
|
19
|
+
"file_count": 2641,
|
|
20
|
+
"tree_sha256": "38d60d3f6875f0ae881aeb4942d3a09b3aa7f9d0df66d7ec712d0ead28d6b3dd",
|
|
21
21
|
"files": [
|
|
22
22
|
{
|
|
23
23
|
"path": ".claude/skills/ask-for-help/SKILL.md",
|
|
@@ -2802,7 +2802,7 @@
|
|
|
2802
2802
|
{
|
|
2803
2803
|
"path": "docs/module-api-changelog.md",
|
|
2804
2804
|
"mode": "0000644",
|
|
2805
|
-
"sha256": "
|
|
2805
|
+
"sha256": "ebca814eb4d786c2958e44b166b23986ef624b9145bc9c5a6b5a0068ef05a411"
|
|
2806
2806
|
},
|
|
2807
2807
|
{
|
|
2808
2808
|
"path": "docs/modules-contract.md",
|
|
@@ -3859,6 +3859,11 @@
|
|
|
3859
3859
|
"mode": "0000644",
|
|
3860
3860
|
"sha256": "03df9104a0309011df1b6e96627c62cc6612f34b654134306d13fd5c89b8f038"
|
|
3861
3861
|
},
|
|
3862
|
+
{
|
|
3863
|
+
"path": "migrations/core_239_claimable_respects_blocker_status.sql",
|
|
3864
|
+
"mode": "0000644",
|
|
3865
|
+
"sha256": "75a3d09bce8a40b51015054b4f4c77706ce76e7f8cb3fc4a54048c9bd33814b8"
|
|
3866
|
+
},
|
|
3862
3867
|
{
|
|
3863
3868
|
"path": "modules/agents/lib/validate.js",
|
|
3864
3869
|
"mode": "0000644",
|
|
@@ -7782,12 +7787,12 @@
|
|
|
7782
7787
|
{
|
|
7783
7788
|
"path": "package-lock.json",
|
|
7784
7789
|
"mode": "0000644",
|
|
7785
|
-
"sha256": "
|
|
7790
|
+
"sha256": "9e9bbca8f0efb3bed421d30ad97be1b18edf775e80cbc07590a583b2452ea609"
|
|
7786
7791
|
},
|
|
7787
7792
|
{
|
|
7788
7793
|
"path": "package.json",
|
|
7789
7794
|
"mode": "0000644",
|
|
7790
|
-
"sha256": "
|
|
7795
|
+
"sha256": "eb6d8897c8a65579eaee354a12435b412606029b3f182f192cf5628941580075"
|
|
7791
7796
|
},
|
|
7792
7797
|
{
|
|
7793
7798
|
"path": "public-docs/index.html",
|
|
@@ -9567,7 +9572,7 @@
|
|
|
9567
9572
|
{
|
|
9568
9573
|
"path": "src/module-api.js",
|
|
9569
9574
|
"mode": "0000644",
|
|
9570
|
-
"sha256": "
|
|
9575
|
+
"sha256": "5359ee8368381b16bb0d6e18a13e390dd9366b3a3cdc3965e749cb5746f5cc4f"
|
|
9571
9576
|
},
|
|
9572
9577
|
{
|
|
9573
9578
|
"path": "src/module-loader/catalog.js",
|
|
@@ -10159,6 +10164,11 @@
|
|
|
10159
10164
|
"mode": "0000644",
|
|
10160
10165
|
"sha256": "6e5ff3acb835fd6219136ee2a5e144841076a82733915cc7111688f707464442"
|
|
10161
10166
|
},
|
|
10167
|
+
{
|
|
10168
|
+
"path": "tests/claimable_blocker_status.mjs",
|
|
10169
|
+
"mode": "0000644",
|
|
10170
|
+
"sha256": "6bb10ab7ee346bbe673055e46e9fc53865540157c48c203e57c11ad51ba44336"
|
|
10171
|
+
},
|
|
10162
10172
|
{
|
|
10163
10173
|
"path": "tests/claims_bind_session.mjs",
|
|
10164
10174
|
"mode": "0000644",
|
|
@@ -1875,5 +1875,7 @@ is load-bearing: the script throws rather than guess if it is missing, and
|
|
|
1875
1875
|
landed since 1.19.706 with no explicit bump. run 34741980536. (task 1002620)
|
|
1876
1876
|
1.19.708 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
1877
1877
|
landed since 1.19.707 with no explicit bump. run 34742245823. (task 1002620)
|
|
1878
|
+
1.19.709 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
1879
|
+
landed since 1.19.708 with no explicit bump. run 34743928060. (task 1002620)
|
|
1878
1880
|
---------------------------------------------------------------------------
|
|
1879
1881
|
```
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
-- core_239 — claimable_tasks must filter on the blocker being OPEN, not on the
|
|
2
|
+
-- link row existing (task 1003863).
|
|
3
|
+
--
|
|
4
|
+
-- THE DEFECT. core_231's claimable_tasks excludes a task if ANY task_blockers row
|
|
5
|
+
-- exists for it, with no check on the blocker's status:
|
|
6
|
+
--
|
|
7
|
+
-- AND NOT EXISTS (SELECT 1 FROM task_blockers tb WHERE tb.task_id = t.id)
|
|
8
|
+
--
|
|
9
|
+
-- Nothing ever deletes that link: there is no `DELETE FROM task_blockers` in
|
|
10
|
+
-- migrations/ or modules/. So when core_223's trg_promote_tasks_on_blocker_resolve
|
|
11
|
+
-- flips a task 'blocked' -> 'ready' on its last blocker resolving, the link row
|
|
12
|
+
-- survives and this view keeps hiding the task. A task that has ever been blocked
|
|
13
|
+
-- is promoted to ready and then never appears in /builder-start again.
|
|
14
|
+
--
|
|
15
|
+
-- It stays claimable BY ID — modules/lifecycle/db-claims.js checks b.status='open'
|
|
16
|
+
-- correctly (task 1002650) — so the row is workable but unfindable. Same family as
|
|
17
|
+
-- bug 1003553, inverted: there the feed advertises what the claim path refuses;
|
|
18
|
+
-- here the claim path accepts what the feed hides.
|
|
19
|
+
--
|
|
20
|
+
-- LATENT, NOT HARMLESS. Every blocker on the instance was status='open' when this
|
|
21
|
+
-- was written, so the bad branch had never executed. Eleven tasks were linked to
|
|
22
|
+
-- open blockers at that moment, and each would have vanished from the queue the
|
|
23
|
+
-- moment its blocker resolved — including task 1001440 behind blocker 1000144.
|
|
24
|
+
--
|
|
25
|
+
-- THE LEFT JOIN IS LOAD-BEARING. Legacy markdown-anchor links carry
|
|
26
|
+
-- task_blockers.blocker_ref with NO blockers row (core_223's header, same scope as
|
|
27
|
+
-- 176). An inner join would drop those rows from the NOT EXISTS and thereby
|
|
28
|
+
-- UNHIDE their tasks — a silent widening of the feed. `LEFT JOIN` plus
|
|
29
|
+
-- `b.id IS NULL OR b.status = 'open'` keeps an unresolvable legacy link blocking,
|
|
30
|
+
-- which is exactly today's behaviour. Fail closed on anything we cannot resolve.
|
|
31
|
+
--
|
|
32
|
+
-- Scope: this view only. The OTHER gap in the same view — it never filters
|
|
33
|
+
-- unshipped dependencies either (finding #60 of task 1000379) — is a separate
|
|
34
|
+
-- clause with a separate fix and is deliberately NOT bundled here.
|
|
35
|
+
--
|
|
36
|
+
-- Idempotent: DROP VIEW IF EXISTS + CREATE, the same shape core_231 used. The
|
|
37
|
+
-- column list is `t.*` plus the calibrated-minutes column, byte-identical to
|
|
38
|
+
-- core_231 so the wildcard re-expands to every current column (core_227's header
|
|
39
|
+
-- records six columns that silently never reached the feed by diverging here).
|
|
40
|
+
|
|
41
|
+
BEGIN;
|
|
42
|
+
|
|
43
|
+
DROP VIEW IF EXISTS claimable_tasks;
|
|
44
|
+
CREATE VIEW claimable_tasks AS
|
|
45
|
+
SELECT t.*,
|
|
46
|
+
pms_calibrated_minutes(t.est_minutes, t.kind) AS est_minutes_calibrated
|
|
47
|
+
FROM tasks t
|
|
48
|
+
WHERE t.status = 'ready'
|
|
49
|
+
AND t.title NOT LIKE '\_\_smoke\_\_%' ESCAPE '\'
|
|
50
|
+
AND NOT EXISTS (
|
|
51
|
+
SELECT 1
|
|
52
|
+
FROM task_blockers tb
|
|
53
|
+
LEFT JOIN blockers b ON b.id = tb.blocker_id
|
|
54
|
+
WHERE tb.task_id = t.id
|
|
55
|
+
AND (b.id IS NULL OR b.status = 'open')
|
|
56
|
+
)
|
|
57
|
+
AND NOT EXISTS (
|
|
58
|
+
SELECT 1 FROM claims c
|
|
59
|
+
JOIN tasks t2 ON t2.id = c.task_id
|
|
60
|
+
WHERE c.released_at IS NULL
|
|
61
|
+
AND t2.touches && t.touches
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
COMMIT;
|
|
65
|
+
|
|
66
|
+
INSERT INTO schema_migrations (version) VALUES ('core_239_claimable_respects_blocker_status')
|
|
67
|
+
ON CONFLICT (version) DO NOTHING;
|
package/package-lock.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bongos/core",
|
|
3
|
-
"version": "1.19.
|
|
3
|
+
"version": "1.19.709",
|
|
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.709",
|
|
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.709",
|
|
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.709'; // 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,98 @@
|
|
|
1
|
+
// tests/claimable_blocker_status.mjs
|
|
2
|
+
//
|
|
3
|
+
// Task 1003863 — claimable_tasks must hide a task only while a blocker on it is
|
|
4
|
+
// still OPEN, not forever because a link row exists. Static shape guard for
|
|
5
|
+
// core_239, in the style of blocker_resolve_guard.mjs: no live DB, assert the SQL
|
|
6
|
+
// TEXT so a future edit cannot silently drop the fix or "simplify" the LEFT JOIN
|
|
7
|
+
// back into the bug. Runtime behaviour is proven against real Postgres at deploy.
|
|
8
|
+
//
|
|
9
|
+
// THE BUG THIS PINS. core_231's view excluded a task if ANY task_blockers row
|
|
10
|
+
// existed, and nothing ever deletes that row. core_223's trigger flips the task
|
|
11
|
+
// 'blocked' -> 'ready' when its last blocker resolves, so the task became ready
|
|
12
|
+
// and permanently invisible to /builder-start — workable by id, unfindable in the
|
|
13
|
+
// feed. Latent when found (every blocker was open), but eleven tasks were one
|
|
14
|
+
// resolve away from vanishing.
|
|
15
|
+
//
|
|
16
|
+
// Run: node tests/claimable_blocker_status.mjs
|
|
17
|
+
|
|
18
|
+
import { strict as assert } from 'node:assert';
|
|
19
|
+
import { readFileSync, readdirSync } from 'node:fs';
|
|
20
|
+
import { fileURLToPath } from 'node:url';
|
|
21
|
+
import { dirname, join } from 'node:path';
|
|
22
|
+
import { makeRunner } from './helpers.mjs';
|
|
23
|
+
|
|
24
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
25
|
+
const repoRoot = join(__dirname, '..');
|
|
26
|
+
const read = (...p) => readFileSync(join(repoRoot, ...p), 'utf8');
|
|
27
|
+
|
|
28
|
+
const MIG = 'core_239_claimable_respects_blocker_status.sql';
|
|
29
|
+
const mig = read('migrations', MIG);
|
|
30
|
+
// Comments carry the rationale; strip them when asserting on the executable body
|
|
31
|
+
// so a claim in prose can never stand in for the real SQL.
|
|
32
|
+
const body = mig.replace(/^\s*--.*$/gm, '').replace(/\s+/g, ' ');
|
|
33
|
+
|
|
34
|
+
const { test, summary } = makeRunner();
|
|
35
|
+
|
|
36
|
+
await test('239 replaces claimable_tasks, in core_231-s drop-and-create shape', () => {
|
|
37
|
+
assert.match(body, /DROP VIEW IF EXISTS claimable_tasks;/);
|
|
38
|
+
assert.match(body, /CREATE VIEW claimable_tasks AS/);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
await test('the blocker clause filters on the blocker being OPEN, not on the link existing', () => {
|
|
42
|
+
assert.match(body, /FROM task_blockers tb/, 'it still looks at the link table');
|
|
43
|
+
assert.match(body, /blockers b ON b\.id = tb\.blocker_id/, 'and resolves the blocker itself');
|
|
44
|
+
assert.match(body, /b\.status = 'open'/, 'so a RESOLVED blocker stops hiding the task');
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
await test('the join is a LEFT JOIN with the fail-closed arm — an inner join would UNHIDE legacy links', () => {
|
|
48
|
+
// Legacy markdown-anchor links carry task_blockers.blocker_ref with no blockers
|
|
49
|
+
// row (core_223 header, same scope as 176). An inner join drops them from the
|
|
50
|
+
// NOT EXISTS and silently widens the feed. This is the one line most likely to
|
|
51
|
+
// be "tidied" later, so it is asserted from both directions.
|
|
52
|
+
assert.match(body, /LEFT JOIN blockers b/, 'LEFT, so an unresolvable link survives the join');
|
|
53
|
+
assert.match(body, /b\.id IS NULL OR b\.status = 'open'/, 'and an unresolvable link still blocks');
|
|
54
|
+
assert.doesNotMatch(
|
|
55
|
+
body,
|
|
56
|
+
/(?<!LEFT )JOIN blockers b ON b\.id = tb\.blocker_id/,
|
|
57
|
+
'a bare inner JOIN onto blockers would unhide every legacy link'
|
|
58
|
+
);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
await test('the view-s OTHER guards survive the rewrite', () => {
|
|
62
|
+
// A view rewrite replaces the whole definition, so dropping a sibling clause is
|
|
63
|
+
// a silent regression with no error anywhere. Each of these was its own fix.
|
|
64
|
+
assert.match(body, /t\.status = 'ready'/, 'only ready tasks are claimable');
|
|
65
|
+
assert.match(body, /NOT LIKE '\\_\\_smoke\\_\\_%'/, 'smoke rows stay out of the feed');
|
|
66
|
+
assert.match(body, /c\.released_at IS NULL/, 'and the touches-overlap parallel-safety guard holds');
|
|
67
|
+
assert.match(body, /t2\.touches && t\.touches/, 'against other live claims');
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
await test('the column list stays the t.* wildcard (core_227-s silent-column lesson)', () => {
|
|
71
|
+
// core_227's header records six columns that never reached the feed because a
|
|
72
|
+
// rewrite spelled the list out instead of re-expanding it.
|
|
73
|
+
assert.match(body, /SELECT t\.\*,/, 'the wildcard re-expands to every current column');
|
|
74
|
+
assert.match(body, /pms_calibrated_minutes\(t\.est_minutes, t\.kind\) AS est_minutes_calibrated/);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
await test('239 is the LAST definition of claimable_tasks in migrations/', () => {
|
|
78
|
+
// If a later migration redefines the view, it inherits whatever that one says —
|
|
79
|
+
// which is exactly how 177 silently dropped migration 176's blocker clause from
|
|
80
|
+
// task_is_fully_unblocked. Catch the next one at the source.
|
|
81
|
+
const defs = readdirSync(join(repoRoot, 'migrations'))
|
|
82
|
+
.filter((f) => f.endsWith('.sql'))
|
|
83
|
+
.filter((f) => /CREATE VIEW claimable_tasks/.test(read('migrations', f)))
|
|
84
|
+
.sort();
|
|
85
|
+
assert.ok(defs.includes(MIG), 'this migration defines the view');
|
|
86
|
+
assert.equal(defs[defs.length - 1], MIG,
|
|
87
|
+
`a later migration redefines claimable_tasks and must carry the blocker-status clause: ${defs.join(', ')}`);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
await test('the feed and the claim path enforce the SAME rule', () => {
|
|
91
|
+
// The whole bug class is the two gates disagreeing. db-claims.js got this right
|
|
92
|
+
// for the by-id path in task 1002650; this pins that they still match.
|
|
93
|
+
const claims = read('modules', 'lifecycle', 'db-claims.js');
|
|
94
|
+
assert.match(claims, /b\.status = 'open'/,
|
|
95
|
+
'the by-id claim path checks blocker STATUS, and the view must not be laxer or stricter');
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
summary();
|