@bongos/core 1.19.258 → 1.19.259

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.258",
6
- "core_contract": "1.19.258",
7
- "source_commit": "66f71503310987ea2c91b4e930f3d5c81b3fb018",
5
+ "core_version": "1.19.259",
6
+ "core_contract": "1.19.259",
7
+ "source_commit": "c8780bb9be3f75bfac1c6c697c5d8e1d081d8dae",
8
8
  "source_ref": "HEAD",
9
- "built_at": "2026-08-19T18:01:56.705Z",
9
+ "built_at": "2026-08-19T18:22:02.664Z",
10
10
  "redaction": {
11
11
  "model": "docs-redacted+functional-verbatim",
12
12
  "docs_redacted": 317,
13
13
  "agent_docs_stubbed": 22,
14
- "functional_verbatim": 1358,
14
+ "functional_verbatim": 1360,
15
15
  "rules": 3,
16
16
  "gate_literals": 3,
17
17
  "gate": "passed"
18
18
  },
19
- "file_count": 1697,
20
- "tree_sha256": "66ae54f6968edbafb532b3e566ec10fad20a45ca1c48af7951a8bc3fe1a06cd7",
19
+ "file_count": 1699,
20
+ "tree_sha256": "3cbb76304d7e5e19aa97c2b90a211e4b35bf3e08d882a9684184df0720855449",
21
21
  "files": [
22
22
  {
23
23
  "path": ".claude/skills/blocker-review/SKILL.md",
@@ -1402,7 +1402,7 @@
1402
1402
  {
1403
1403
  "path": "docs/architecture.md",
1404
1404
  "mode": "0000644",
1405
- "sha256": "497b1fbf18ec1cf6d7e0f3620669cfba9008bc6a40e1f70e4b5f53d3406bc12e"
1405
+ "sha256": "193c04262908677d4cdee4c9ba20031ed19220c3886cce8f25f54ea3e615079f"
1406
1406
  },
1407
1407
  {
1408
1408
  "path": "docs/branding-contract.md",
@@ -2414,6 +2414,11 @@
2414
2414
  "mode": "0000644",
2415
2415
  "sha256": "51d7fc76fdc59a5ab145839aa4943fe7753324022f82e4b4a76c2fe3cab9b98d"
2416
2416
  },
2417
+ {
2418
+ "path": "migrations/core_222_idea_inbox_suggested_goal.sql",
2419
+ "mode": "0000644",
2420
+ "sha256": "9939ee2c641caa8ae4f5055c60e3208a6ed4e379b1bfd1aaa67247a8ed4a4fd8"
2421
+ },
2417
2422
  {
2418
2423
  "path": "modules/autonomy/CLAUDE.md",
2419
2424
  "mode": "0000644",
@@ -3674,6 +3679,11 @@
3674
3679
  "mode": "0000644",
3675
3680
  "sha256": "3c30ba66b8426d6f304c8135764108f25c4c9aeb8a571347dd7c22ff7a68fad2"
3676
3681
  },
3682
+ {
3683
+ "path": "modules/ideas/migrations/ideas_003_lineage_origin_route.sql",
3684
+ "mode": "0000644",
3685
+ "sha256": "8edeeb0bbf5bac57111008357fc287f8dc14e6907d7bc218264c40633778b9c3"
3686
+ },
3677
3687
  {
3678
3688
  "path": "modules/ideas/module.json",
3679
3689
  "mode": "0000644",
@@ -4447,12 +4457,12 @@
4447
4457
  {
4448
4458
  "path": "package-lock.json",
4449
4459
  "mode": "0000644",
4450
- "sha256": "815b7d1a58cdf1a0d9c7e30a97f70faa146ee6f826501f0c42f1b38529851575"
4460
+ "sha256": "df6bf392719f8ba6a0aa64db49a0c29fc65dbc623f6efe0cf0b33e984469803b"
4451
4461
  },
4452
4462
  {
4453
4463
  "path": "package.json",
4454
4464
  "mode": "0000644",
4455
- "sha256": "dcc8774d55d45595b6e3f3229a278b4bf5e263438bb730a8bdd620edf9c47bbd"
4465
+ "sha256": "8afa3a02911351bbae1709a66e204a73ff07c65132c50fad0536246708143aac"
4456
4466
  },
4457
4467
  {
4458
4468
  "path": "public-docs/index.html",
@@ -6097,7 +6107,7 @@
6097
6107
  {
6098
6108
  "path": "src/module-api.js",
6099
6109
  "mode": "0000644",
6100
- "sha256": "a34bf521314a258ef3c444962bac548fa9aa2e0853dc45531f79586ef52bdeec"
6110
+ "sha256": "c00527049537e4f63e7c3d70446ebb20ba7e760fa77bb200aa26f3e2de6b22f2"
6101
6111
  },
6102
6112
  {
6103
6113
  "path": "src/module-loader/catalog.js",
@@ -154,7 +154,13 @@ learnings(id, title, body_md, tags text[], related_files text[], captured_by, so
154
154
  source_ref, task_id?, created_at)
155
155
  indexes: GIN(tags), GIN(related_files), UNIQUE(source, source_ref) WHERE non-null
156
156
  idea_inbox(id, title, body_md, kind, suggested_version, suggested_priority, captured_at,
157
- captured_by, status 'open'|'promoted'|'discarded'|'merged', promoted_to_task_id, reviewed_at)
157
+ captured_by, status 'open'|'promoted'|'discarded'|'merged', promoted_to_task_id, reviewed_at,
158
+ merged_into_idea_id? FK idea_inbox, triage_note?, -- mig core_195 (task 1002447): what a
159
+ -- triage VERDICT decided -- which idea a merge folded into, and why a discard happened.
160
+ -- CHECK (merged_into_idea_id IS NULL OR status = 'merged') -- no merge chains.
161
+ suggested_goal_id? FK goals ON DELETE SET NULL) -- mig core_222 (task 1003060, goal 1000071):
162
+ -- an ADVISORY routing hint for rows that did NOT convert (homeless/soft-landed/Discord).
163
+ -- The binding home for routed work is tasks.goal_id; nothing may gate on this column.
158
164
  done_when_criteria(id, version_id, criterion_id, criterion_md, satisfied bool, satisfied_by_task_id,
159
165
  checked_at, sort_order, UNIQUE(version_id, criterion_id)) -- 13 seeded (V1 + PMS-V2)
160
166
  task_criteria(task_id FK tasks, criterion_id FK done_when_criteria, source 'backfill'|'manual'|'planning',
@@ -0,0 +1,57 @@
1
+ -- core_222_idea_inbox_suggested_goal.sql — a routing HINT on an inbox row
2
+ -- (task 1003060, BV1.R02, goal 1000071 "Idea routing").
3
+ --
4
+ -- WHAT THIS IS NOT. This is not where a routed idea's goal lives. When routing
5
+ -- fires, the idea is converted in the same transaction (R01): the idea row goes
6
+ -- status='promoted' with promoted_to_task_id set, and the TASK carries the real
7
+ -- goal_id. The binding home for "which goal does this work belong to" is
8
+ -- tasks.goal_id — always. This column is strictly the ADVISORY leftover for rows
9
+ -- that did NOT convert:
10
+ -- * soft-landed / homeless ideas that stayed in the inbox (no goal at filing),
11
+ -- * Discord #ideas inbound carrying a classifier's guess (R12),
12
+ -- * Full Ideas and criterion-proposals, which never auto-route by design,
13
+ -- so /idea-triage can show "this probably belongs to goal N" instead of making
14
+ -- every triage pass re-derive it. A hint is nullable, overwritable, and load-
15
+ -- bearing for NOTHING — no rank check, no scope wall, and no payout may read it.
16
+ --
17
+ -- WHY CORE, NOT modules/ideas/migrations/. `idea_inbox` is a CORE table. A module
18
+ -- migration may only touch its own <key>_-prefixed objects — fitness.js
19
+ -- checkModuleMigrationsAdditive hard-fails an `ALTER TABLE idea_inbox` from a
20
+ -- module (ADR 0083 §Decision #5). Same reasoning core_195 recorded when it added
21
+ -- merged_into_idea_id: the ideas module owns every QUERY against this table and
22
+ -- none of its schema. The lineage half of R02 — which touches an ideas-OWNED
23
+ -- table — is correctly a module migration (ideas_003).
24
+ --
25
+ -- WHY ON DELETE SET NULL. A hint must never keep a goal alive nor block its
26
+ -- deletion, and a dangling hint is worse than no hint: an archived-then-deleted
27
+ -- goal would otherwise leave triage pointing at a tombstone. RESTRICT would let
28
+ -- an advisory column veto a goal deletion, which inverts the whole point.
29
+ --
30
+ -- Additive, nullable, idempotent (safe to re-run). Forward-safe by construction:
31
+ -- every existing reader SELECTs an explicit column list, so old code on the new
32
+ -- schema neither sees nor needs this (tests/migrations_forward_safe.mjs).
33
+
34
+ BEGIN;
35
+
36
+ ALTER TABLE idea_inbox
37
+ ADD COLUMN IF NOT EXISTS suggested_goal_id bigint REFERENCES goals(id) ON DELETE SET NULL;
38
+
39
+ -- Triage's homeless-only walk (R13) filters "open ideas that have a hint" and
40
+ -- the reverse "what is pointed at this goal". Partial: the overwhelming majority
41
+ -- of rows are NULL (no hint), so a partial index stays small and still serves
42
+ -- both directions.
43
+ --
44
+ -- NOT CONCURRENTLY, and it cannot be: CREATE INDEX CONCURRENTLY is forbidden
45
+ -- inside a transaction block, and this migration is wrapped BEGIN/COMMIT so the
46
+ -- column and its index land atomically (a half-applied migration is the worse
47
+ -- failure). The plain form takes a brief ACCESS EXCLUSIVE lock on idea_inbox for
48
+ -- the duration of the build. That is acceptable HERE specifically because
49
+ -- idea_inbox is a low-volume human-filing queue — ideas arrive at human pace, not
50
+ -- per-request — so the build is milliseconds against a small table and no write
51
+ -- path of consequence blocks. This reasoning does NOT generalise: a future index
52
+ -- on a write-hot table wants CONCURRENTLY in its OWN transaction-less migration.
53
+ CREATE INDEX IF NOT EXISTS idx_idea_inbox_suggested_goal
54
+ ON idea_inbox (suggested_goal_id)
55
+ WHERE suggested_goal_id IS NOT NULL;
56
+
57
+ COMMIT;
@@ -0,0 +1,62 @@
1
+ -- ideas_003_lineage_origin_route.sql — 'route' becomes a legal lineage origin
2
+ -- (task 1003060, BV1.R02, goal 1000071 "Idea routing").
3
+ --
4
+ -- WHY. ideas_002 created ideas_task_lineage with origin IN ('promote','develop')
5
+ -- — the two ways a task could descend from an idea when it was written. Routing
6
+ -- adds a THIRD: capture-time promotion, where the idea row and its task are
7
+ -- written in one transaction at filing time (R01) rather than by a later triage
8
+ -- promote. That is genuinely a different provenance and must be distinguishable
9
+ -- in the ledger: 'promote' means a human triaged it, 'route' means the filer
10
+ -- named a goal and the system converted it on the spot. Collapsing the two would
11
+ -- destroy the only signal that tells us how much triage routing actually saved
12
+ -- (C6 triage-shrinks-to-judgment) — and IC4 may want to weigh them differently.
13
+ --
14
+ -- WHY THE WHOLE POINT IS ATTRIBUTION. Discord #bugs is the cautionary tale this
15
+ -- goal exists to fix: it creates tasks DIRECTLY, skipping idea_inbox, so there is
16
+ -- no captured_by and no lineage row — the ideator-credit lane (goal 1000067) has
17
+ -- nothing to ever pay against. Routing must never become a second such bypass, so
18
+ -- every routed task gets a lineage row like any other. This CHECK is what lets it.
19
+ --
20
+ -- WHY THIS IS ADDITIVE DESPITE THE `DROP CONSTRAINT`. Postgres has no "extend a
21
+ -- CHECK" verb; widening an enum-style CHECK is necessarily drop-then-re-add of
22
+ -- the SAME-named constraint. That is additive in EFFECT — the new predicate
23
+ -- permits a strict superset of the old one, so no existing row can be
24
+ -- invalidated and no data is touched. fitness.js recognises exactly this shape
25
+ -- (isConstraintWidening, task 1978): a DROP whose constraint name is re-ADDed in
26
+ -- the same file is exempt from the destructive-DDL rule. The name must therefore
27
+ -- match Postgres's auto-generated name from the ideas_002 inline column CHECK —
28
+ -- ideas_task_lineage_origin_check — or the exemption does not apply and the
29
+ -- constraint silently does not come back. provisioning_003 is the precedent.
30
+ --
31
+ -- Module migrations are ADDITIVE and NAMESPACED: every object here is
32
+ -- ideas_-prefixed, no down-migration, idempotent (safe to re-run).
33
+
34
+ BEGIN;
35
+
36
+ ALTER TABLE ideas_task_lineage DROP CONSTRAINT IF EXISTS ideas_task_lineage_origin_check;
37
+ ALTER TABLE ideas_task_lineage ADD CONSTRAINT ideas_task_lineage_origin_check
38
+ CHECK (origin IN ('promote', 'develop', 'route'));
39
+
40
+ -- SAFETY NET — did the widening actually take? If ideas_002's inline CHECK ever
41
+ -- carried a name other than Postgres's auto-generated ideas_task_lineage_origin_check,
42
+ -- the DROP above silently no-ops and the ADD installs a SECOND constraint while the
43
+ -- original keeps rejecting 'route' — routing would then fail at runtime, in the one
44
+ -- transaction whose whole job is preserving attribution, with nothing pointing here.
45
+ -- A migration that cannot prove its own effect must not report success. Read-only,
46
+ -- no DDL: it asserts that no surviving CHECK on this table still excludes 'route'.
47
+ DO $$
48
+ DECLARE stale text;
49
+ BEGIN
50
+ SELECT string_agg(conname, ', ') INTO stale
51
+ FROM pg_constraint
52
+ WHERE conrelid = 'ideas_task_lineage'::regclass
53
+ AND contype = 'c'
54
+ AND pg_get_constraintdef(oid) ILIKE '%origin%'
55
+ AND pg_get_constraintdef(oid) NOT ILIKE '%route%';
56
+ IF stale IS NOT NULL THEN
57
+ RAISE EXCEPTION
58
+ 'ideas_003: CHECK constraint(s) % still reject origin=''route'' — the widening did not take (name mismatch with ideas_002). Rename the DROP target to match and re-run.', stale;
59
+ END IF;
60
+ END $$;
61
+
62
+ COMMIT;
package/package-lock.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@bongos/core",
3
- "version": "1.19.258",
3
+ "version": "1.19.259",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@bongos/core",
9
- "version": "1.19.258",
9
+ "version": "1.19.259",
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.258",
3
+ "version": "1.19.259",
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
@@ -943,8 +943,10 @@ const { validateOrRespond, LIMITS, parseId, asyncHandler, corsPublicGet, parsePa
943
943
  // landed since 1.19.256 with no explicit bump. run 32209295358. (task 1002620)
944
944
  // 1.19.258 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
945
945
  // landed since 1.19.257 with no explicit bump. run 32284962866. (task 1002620)
946
+ // 1.19.259 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
947
+ // landed since 1.19.258 with no explicit bump. run 32286866098. (task 1002620)
946
948
  // ---------------------------------------------------------------------------
947
- const CORE_VERSION = '1.19.258'; // CI auto-patch carrier (ADR 0161); see changelog above
949
+ const CORE_VERSION = '1.19.259'; // CI auto-patch carrier (ADR 0161); see changelog above
948
950
 
949
951
  // A namespaced logger so a module's log lines are attributable + consistent.
950
952
  // Usage: const log = api.logger('dev-box'); log.info('mounted');