@bongos/core 1.20.8 → 1.20.9

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.20.8",
6
- "core_contract": "1.20.8",
7
- "source_commit": "fb1af293583380a02ab4fa8df4a06e31a89c73cc",
5
+ "core_version": "1.20.9",
6
+ "core_contract": "1.20.9",
7
+ "source_commit": "2b36b101931a77f890370e4ca5bfe3c52380aa86",
8
8
  "source_ref": "HEAD",
9
- "built_at": "2026-09-30T04:32:44.486Z",
9
+ "built_at": "2026-09-30T04:43:40.633Z",
10
10
  "redaction": {
11
11
  "model": "docs-redacted+functional-verbatim",
12
12
  "docs_redacted": 556,
13
13
  "agent_docs_stubbed": 25,
14
- "functional_verbatim": 2623,
14
+ "functional_verbatim": 2624,
15
15
  "rules": 3,
16
16
  "gate_literals": 3,
17
17
  "gate": "passed"
18
18
  },
19
- "file_count": 3205,
20
- "tree_sha256": "4b5867abb42ec4c580d94333e13d9f029d81da62bf68a26c753511d54082f26c",
19
+ "file_count": 3206,
20
+ "tree_sha256": "da9805685f777ab35786f149befb6dbcacca93c0a0e53c2ffee30b11544aa62d",
21
21
  "files": [
22
22
  {
23
23
  "path": ".claude/skills/ask-for-help/SKILL.md",
@@ -2772,7 +2772,7 @@
2772
2772
  {
2773
2773
  "path": "docs/module-api-changelog.md",
2774
2774
  "mode": "0000644",
2775
- "sha256": "4bcc9fffeff37ae0b087af39c16e3cf8f381a066b2e70019fe8b1f30f49bce3c"
2775
+ "sha256": "030b3fb4cd9862ccb5e1d96644271f79485912b6b6abba869dafde16715c4d84"
2776
2776
  },
2777
2777
  {
2778
2778
  "path": "docs/modules-contract.md",
@@ -3939,6 +3939,11 @@
3939
3939
  "mode": "0000644",
3940
3940
  "sha256": "b80e47e3a9d27909521d8a9adca0376381705fc6618435b91c9f5ee585135afa"
3941
3941
  },
3942
+ {
3943
+ "path": "migrations/core_263_closeness_history_indexes.sql",
3944
+ "mode": "0000644",
3945
+ "sha256": "6f502903c02f48a65370d2ca167b42a5ea514bed38bb9862d34465ea627191f2"
3946
+ },
3942
3947
  {
3943
3948
  "path": "modules/agents/CLAUDE.md",
3944
3949
  "mode": "0000644",
@@ -6042,7 +6047,7 @@
6042
6047
  {
6043
6048
  "path": "modules/lifecycle/closeness.js",
6044
6049
  "mode": "0000644",
6045
- "sha256": "4ea4fe1c93ffe6d6f42af31d96dfe402d7dbccb4a5825b71c571024548a87c25"
6050
+ "sha256": "d464e808e8854e68f4796cd92be96a326104375bb7b82c570291939910e48c39"
6046
6051
  },
6047
6052
  {
6048
6053
  "path": "modules/lifecycle/collab-settle.js",
@@ -8852,12 +8857,12 @@
8852
8857
  {
8853
8858
  "path": "package-lock.json",
8854
8859
  "mode": "0000644",
8855
- "sha256": "3a10ecd6f93e42f1792e7edb0a406edaefb3377506afb359cde35e3fdd901296"
8860
+ "sha256": "51e46a6ba6eb82e2c829d8c5a220cdc835fe959e0b73f12dcffa69b61de3325c"
8856
8861
  },
8857
8862
  {
8858
8863
  "path": "package.json",
8859
8864
  "mode": "0000644",
8860
- "sha256": "065257986765387a5b632092aab054e6a9d8299b9c27473a9b0e306dec3d73cc"
8865
+ "sha256": "131c787425281094366c5871f082c5b8340e593eaa7c5d9aaf779ceb906da786"
8861
8866
  },
8862
8867
  {
8863
8868
  "path": "public-docs/index.html",
@@ -8877,7 +8882,7 @@
8877
8882
  {
8878
8883
  "path": "release-notes.json",
8879
8884
  "mode": "0000644",
8880
- "sha256": "3c69418a8c305f1aa08dd13193ee4489ac818f9723147c218e8f5745dfae1e8b"
8885
+ "sha256": "7c9e016bd4bcc8e7f702fb3dc2aa9112cf6b7c27f27ed638b2d357a906f30088"
8881
8886
  },
8882
8887
  {
8883
8888
  "path": "scripts/bongos-mcp.js",
@@ -10992,7 +10997,7 @@
10992
10997
  {
10993
10998
  "path": "src/module-api.js",
10994
10999
  "mode": "0000644",
10995
- "sha256": "fdb2e5eb052bbdc4698fdb5cde2da471036c90c52f7f105cd8b057ae330ee8c1"
11000
+ "sha256": "154bd9ea1d7f6ea701c30fcfc8b2c4f26133710f2c2b30f0a1942894fb07c357"
10996
11001
  },
10997
11002
  {
10998
11003
  "path": "src/module-loader/catalog.js",
@@ -11767,7 +11772,7 @@
11767
11772
  {
11768
11773
  "path": "tests/closeness.mjs",
11769
11774
  "mode": "0000644",
11770
- "sha256": "be10e63b6a424914ba71537dbfa653dcb247b28b3e6a9a8caf4696268e4500cf"
11775
+ "sha256": "a1d1e2a77e0ad6b1a00c187775859dfcd646389959062b8b78173fc27c2c02ed"
11771
11776
  },
11772
11777
  {
11773
11778
  "path": "tests/cloud_bongos_pack.mjs",
@@ -2673,5 +2673,7 @@ is load-bearing: the script throws rather than guess if it is missing, and
2673
2673
  landed since 1.20.6 with no explicit bump. run 36668328505. (task 1002620)
2674
2674
  1.20.8 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
2675
2675
  landed since 1.20.7 with no explicit bump. run 36669272909. (task 1002620)
2676
+ 1.20.9 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
2677
+ landed since 1.20.8 with no explicit bump. run 36669791458. (task 1002620)
2676
2678
  ---------------------------------------------------------------------------
2677
2679
  ```
@@ -0,0 +1,56 @@
1
+ -- core_263 — index the history the closeness signals join on (task 1003268)
2
+ --
3
+ -- modules/lifecycle/closeness.js builds a builder's "who have I worked near" graph
4
+ -- from three self-joins (task 1003174): overlapping CLAIMS in a shared goal,
5
+ -- SESSION LOGS on a shared goal's tasks, and SHIPS in a shared goal. The grader of
6
+ -- 1003174 flagged that the join keys might be unindexed, which would make each
7
+ -- query scale with the whole table instead of with one builder's goals. Checked
8
+ -- against the tree, key by key:
9
+ --
10
+ -- tasks.goal_id — ALREADY COVERED. The task was filed before core_228 added
11
+ -- idx_tasks_goal ON tasks (goal_id). A second index on the
12
+ -- same column would only cost writes, so none is added.
13
+ -- claims.builder_id — only idx_claims_builder_active (003), partial on
14
+ -- released_at IS NULL. Closeness reads SETTLED claims
15
+ -- (`mine.builder_id = $1 AND mine.claimed_at > now() - …`),
16
+ -- which a partial-on-active index cannot serve. Added below,
17
+ -- with claimed_at second so the time window is a range scan.
18
+ -- claims.task_id — only the partial UNIQUE on active claims (003). The join
19
+ -- `other.task_id = t_other.id` walks every claim, settled
20
+ -- ones included. Added below.
21
+ -- tasks.shipped_by — idx_tasks_needs_rebase (core_193) is partial on
22
+ -- needs_rebase, and idx_tasks_shipped_by_shipped_at
23
+ -- (core_228) is partial on status = 'shipped'. The ship
24
+ -- signal filters `shipped_by = $1 AND goal_id IS NOT NULL`
25
+ -- with no status predicate, so the planner can use neither.
26
+ -- Added below, partial on exactly that query's predicates.
27
+ -- session_logs — covered by idx_session_logs_task / _builder (003).
28
+ --
29
+ -- Not urgent at today's size (a few thousand tasks, fifteen builders); this closes
30
+ -- the gap before it grows rather than after it hurts.
31
+ --
32
+ -- Additive and idempotent: indexes only, no column, no constraint, no data. Safe
33
+ -- to run forward against a live database, and an older release running against it
34
+ -- just has unused indexes. Rollback is DROP INDEX.
35
+ --
36
+ -- NOT a lifecycle_* module migration: `tasks` and `claims` are CORE tables, and a
37
+ -- module migration may only touch its own namespaced tables (fitness.js
38
+ -- checkModuleMigrationsAdditive, ADR 0083 Decision #5). That boundary is why this
39
+ -- was split out of task 1003174 in the first place.
40
+
41
+ CREATE INDEX IF NOT EXISTS idx_claims_builder_history
42
+ ON claims (builder_id, claimed_at);
43
+
44
+ CREATE INDEX IF NOT EXISTS idx_claims_task_all
45
+ ON claims (task_id);
46
+
47
+ CREATE INDEX IF NOT EXISTS idx_tasks_shipped_by_goal
48
+ ON tasks (shipped_by, goal_id)
49
+ WHERE shipped_by IS NOT NULL AND goal_id IS NOT NULL;
50
+
51
+ COMMENT ON INDEX idx_claims_builder_history IS
52
+ 'Closeness (modules/lifecycle/closeness.js): a builder''s settled claims in a time window. idx_claims_builder_active is partial on active claims and cannot serve history.';
53
+ COMMENT ON INDEX idx_claims_task_all IS
54
+ 'Closeness: joins every claim (settled too) on task_id. The 003 unique index covers active claims only.';
55
+ COMMENT ON INDEX idx_tasks_shipped_by_goal IS
56
+ 'Closeness ship signal: shipped_by = $1 AND goal_id IS NOT NULL, no status predicate, so core_228''s status-partial index does not apply.';
@@ -37,13 +37,13 @@
37
37
  // The gate FAILS CLOSED: a consent read that throws or returns null yields the
38
38
  // empty set, and so the empty graph.
39
39
  //
40
- // A KNOWN PERFORMANCE GAP, measured rather than assumed. The signal joins key on
41
- // tasks.goal_id (NO index), claims.builder_id and claims.task_id (indexed only
42
- // partially, on ACTIVE claims — closeness reads history) and tasks.shipped_by
43
- // (partial too). At today's size that is fine; it scales with total table size
44
- // rather than goal size. The indexes belong in a core_ migration, not here — a
45
- // module migration may only touch its own lifecycle_ tables (ADR 0083 §5), and
46
- // the fitness check enforces it. Filed with the SQL as task 1003268.
40
+ // INDEXES. The signal joins key on tasks.goal_id (idx_tasks_goal, core_228),
41
+ // claims.builder_id + claimed_at and claims.task_id over HISTORY, not just active
42
+ // claims, and tasks.shipped_by + goal_id with no status predicate. The last three
43
+ // were unindexed for this shape and are added by migrations/core_263 (from
44
+ // task 1003268). They live in a core_ migration, not here — a module migration may only
45
+ // touch its own lifecycle_ tables (ADR 0083 §5), and the fitness check enforces it.
46
+ // Change a join key or predicate here and re-check that migration still serves it.
47
47
  //
48
48
  // Reaches core only through the doorway (ADR 0083). The core tables it reads
49
49
  // (claims, tasks, session_logs, builders) are read-only here.
package/package-lock.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@bongos/core",
3
- "version": "1.20.8",
3
+ "version": "1.20.9",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@bongos/core",
9
- "version": "1.20.8",
9
+ "version": "1.20.9",
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.8",
3
+ "version": "1.20.9",
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",
@@ -8100,5 +8100,11 @@
8100
8100
  "id": "1002992",
8101
8101
  "text": "When you claim a task, your assistant is now told on its own which playbook to work from: engineer, artist, ideator or UI. Before, the instructions only reached it if someone read the claim output. Each workspace gets only its"
8102
8102
  }
8103
+ ],
8104
+ "1.20.9": [
8105
+ {
8106
+ "id": "1003268",
8107
+ "text": "Added three database lookups so the 'who have I worked near' view stays fast as the project grows. Nothing changes on screen today."
8108
+ }
8103
8109
  ]
8104
8110
  }
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.8'; // CI auto-patch carrier (ADR 0161); changelog: docs/module-api-changelog.md
78
+ const CORE_VERSION = '1.20.9'; // 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');
@@ -434,10 +434,25 @@ test('the index gap the grader raised is ANSWERED, not left open', () => {
434
434
  // and these are core tables. That makes it a core_ migration, which needs a
435
435
  // reserved number and human eyes. Filed as task 1003268 with the SQL.
436
436
  //
437
- // This test pins the REFERENCE so the finding cannot be quietly dropped: if
438
- // someone lands the indexes and deletes the note, they should delete this too.
437
+ // Task 1003268 then landed them as migrations/core_263 — minus a goal_id index,
438
+ // because core_228 had already added idx_tasks_goal. This test now pins that the
439
+ // source still points at the migration and that the migration carries every
440
+ // index the three signals need, so a later edit cannot drop one quietly.
439
441
  assert.match(SRC, /task 1003268/,
440
- 'the closeness source cites the follow-up that carries the indexes');
442
+ 'the closeness source cites the task that carries the indexes');
443
+ assert.match(SRC, /core_263/, 'and names the migration that serves its joins');
444
+ const core = fs.readFileSync(path.join(ROOT, 'migrations', 'core_263_closeness_history_indexes.sql'), 'utf8');
445
+ for (const [name, shape] of [
446
+ ['idx_claims_builder_history', /ON claims \(builder_id, claimed_at\)/],
447
+ ['idx_claims_task_all', /ON claims \(task_id\)/],
448
+ ['idx_tasks_shipped_by_goal', /ON tasks \(shipped_by, goal_id\)/],
449
+ ]) {
450
+ assert.match(core, new RegExp(`CREATE INDEX IF NOT EXISTS ${name}\\b`), `${name} is created`);
451
+ assert.match(core, shape, `${name} has the shape the closeness join needs`);
452
+ }
453
+ const goalIdx = fs.readFileSync(path.join(ROOT, 'migrations', 'core_228_idea_inbox_captured_by_idx.sql'), 'utf8');
454
+ assert.match(goalIdx, /CREATE INDEX IF NOT EXISTS idx_tasks_goal ON tasks \(goal_id\)/,
455
+ 'tasks.goal_id is served by core_228, which is why core_263 does not repeat it');
441
456
  const files = fs.readdirSync(path.join(ROOT, 'modules', 'lifecycle', 'migrations'));
442
457
  assert.ok(!files.some((f) => /closeness/i.test(f)),
443
458
  'and no module migration tries to index a core table again');