@bongos/core 1.19.239 → 1.19.240

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.239",
6
- "core_contract": "1.19.239",
7
- "source_commit": "92f85bc3527c85038cc818e47b4d503a340c8abb",
5
+ "core_version": "1.19.240",
6
+ "core_contract": "1.19.240",
7
+ "source_commit": "fd0201e6b50f0e354cea9a97c215730c16357ee3",
8
8
  "source_ref": "HEAD",
9
- "built_at": "2026-08-18T19:09:51.272Z",
9
+ "built_at": "2026-08-18T20:26:47.249Z",
10
10
  "redaction": {
11
11
  "model": "docs-redacted+functional-verbatim",
12
12
  "docs_redacted": 312,
13
13
  "agent_docs_stubbed": 21,
14
- "functional_verbatim": 1324,
14
+ "functional_verbatim": 1325,
15
15
  "rules": 3,
16
16
  "gate_literals": 3,
17
17
  "gate": "passed"
18
18
  },
19
- "file_count": 1657,
20
- "tree_sha256": "ba99d83f49d20d229d51e1ca9cbb5232f744888d91ab1dbf43d5c092eade4cf9",
19
+ "file_count": 1658,
20
+ "tree_sha256": "a6ef1676edb20a115c4942ab09c2689af96309917e65340533f47d7cd18c6e7c",
21
21
  "files": [
22
22
  {
23
23
  "path": ".claude/skills/blocker-review/SKILL.md",
@@ -4342,12 +4342,12 @@
4342
4342
  {
4343
4343
  "path": "package-lock.json",
4344
4344
  "mode": "0000644",
4345
- "sha256": "16010eb616ec78eb915efe81ecf81ad7b20339180ec495e40eb50b71bbac8b93"
4345
+ "sha256": "5016dfd9f9b3ee1b5141dc1d0a24a478637b449e39b8e82fa42dc8f5084356f5"
4346
4346
  },
4347
4347
  {
4348
4348
  "path": "package.json",
4349
4349
  "mode": "0000644",
4350
- "sha256": "8cf3937acd1926b71f0e9ee112fce2b1d23adfd5b58cb2a2e36926f90b2e714f"
4350
+ "sha256": "9e996de99c2422683685f66dc08b2b8a8663d4e5da4e71f00059c332acfa9b37"
4351
4351
  },
4352
4352
  {
4353
4353
  "path": "public-docs/index.html",
@@ -5332,7 +5332,7 @@
5332
5332
  {
5333
5333
  "path": "scripts/gds/run-unit-tests.js",
5334
5334
  "mode": "0000644",
5335
- "sha256": "21bcaeaa9d8b2048b9c3f9ff9b251a9203a9259c991a536636c0ec3c8745bbd5"
5335
+ "sha256": "192350d9d65934a1af724d0f285cc74a89a842e75d0fdec37037d34ded5db546"
5336
5336
  },
5337
5337
  {
5338
5338
  "path": "scripts/gds/sandbox-stage.js",
@@ -5962,7 +5962,7 @@
5962
5962
  {
5963
5963
  "path": "src/module-api.js",
5964
5964
  "mode": "0000644",
5965
- "sha256": "3995623cfa7376dbf8cbcf14b238c1fa1c919ad9d8da5af781b0f78dcb0bb8cc"
5965
+ "sha256": "4c133ea04355ccf4ac6b4f1530d612421ca5e5a99393a4ee102cee4949377611"
5966
5966
  },
5967
5967
  {
5968
5968
  "path": "src/module-loader/catalog.js",
@@ -6967,7 +6967,12 @@
6967
6967
  {
6968
6968
  "path": "tests/government_live_proof.mjs",
6969
6969
  "mode": "0000644",
6970
- "sha256": "af6423ac87819ff344c8a7804c0eda903a3e8c7633d1e4182e7d4f446d30cec0"
6970
+ "sha256": "6d829af6ef71bfa744a4ff457a4766b5cce021f317661579b06ecfc14298a523"
6971
+ },
6972
+ {
6973
+ "path": "tests/government_live_proof_shape.mjs",
6974
+ "mode": "0000644",
6975
+ "sha256": "75160048aba7b8c2264478c29aa2fc19636c67f66cd63842a83851574b722469"
6971
6976
  },
6972
6977
  {
6973
6978
  "path": "tests/government_ownership_scope.mjs",
package/package-lock.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@bongos/core",
3
- "version": "1.19.239",
3
+ "version": "1.19.240",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@bongos/core",
9
- "version": "1.19.239",
9
+ "version": "1.19.240",
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.239",
3
+ "version": "1.19.240",
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",
@@ -74,7 +74,13 @@ const INTEGRATION = new Set([
74
74
  // .github/workflows/consumer-layout-boot.yml, not this DB-free gate (task 2142).
75
75
  'consumer_layout_boot',
76
76
  'claim_gate_open_blocker', 'claim_gate_rebase', 'clawback_confirmed_backlog', 'discord_autojoin', 'discord_oauth',
77
- 'governance_fold_bench', 'governance_live_proof', 'linkify_refs', 'memory_isolation',
77
+ // RENAMED by ADR 0174 (goal 1000068) — these entries said governance_* until task
78
+ // 1003091. A curated set keyed by a stem that no longer exists silently stops
79
+ // covering its file: both of these dropped OUT of the integration set and INTO the
80
+ // DB-free lane, where they only "passed" because they self-skip. The pairing guard
81
+ // is in tests/government_live_proof_shape.mjs — every curated entry must name a
82
+ // real test file.
83
+ 'government_fold_bench', 'government_live_proof', 'linkify_refs', 'memory_isolation',
78
84
  'memory_pull', 'needs_rebase', 'parallel-load', 'profile_rollup_consent', 'reward_mode_cost_plus_only',
79
85
  'scouting_rollup_fanout', 'session_records', 'setup_smoke',
80
86
  'status-probe',
package/src/module-api.js CHANGED
@@ -905,8 +905,10 @@ const { validateOrRespond, LIMITS, parseId, asyncHandler, corsPublicGet, parsePa
905
905
  // landed since 1.19.237 with no explicit bump. run 32172843539. (task 1002620)
906
906
  // 1.19.239 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
907
907
  // landed since 1.19.238 with no explicit bump. run 32174983930. (task 1002620)
908
+ // 1.19.240 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
909
+ // landed since 1.19.239 with no explicit bump. run 32182178305. (task 1002620)
908
910
  // ---------------------------------------------------------------------------
909
- const CORE_VERSION = '1.19.239'; // CI auto-patch carrier (ADR 0161); see changelog above
911
+ const CORE_VERSION = '1.19.240'; // CI auto-patch carrier (ADR 0161); see changelog above
910
912
 
911
913
  // A namespaced logger so a module's log lines are attributable + consistent.
912
914
  // Usage: const log = api.logger('dev-box'); log.info('mounted');
@@ -13,6 +13,11 @@
13
13
  // resolver behind the real `governance` kernel port, no stubs, no monkeypatches.
14
14
  // The captured sandbox transcript lives in docs/governance/bongos-v1-c6-live-proof.md.
15
15
  //
16
+ // REPAIRED 2026-08-18 (task 1003091): between ADR 0174's rename and that task this
17
+ // file was SILENTLY DEAD — see the readiness guard below for what happened and why
18
+ // the guard's shape, not just its table name, was the bug. tests/
19
+ // government_live_proof_shape.mjs now pins both from the DB-free lane.
20
+ //
16
21
  // Real-DB integration test (the needs_rebase.mjs class): SELF-SKIPS (exit 0)
17
22
  // when DATABASE_URL is unset/unreachable or the governance tables are missing,
18
23
  // and is listed in run-unit-tests.js's INTEGRATION set so the DB-free lane
@@ -38,18 +43,65 @@ if (!process.env.DATABASE_URL) {
38
43
 
39
44
  const { Pool } = require('pg');
40
45
  const pool = new Pool({ connectionString: process.env.DATABASE_URL });
46
+
47
+ // ── THE READINESS GUARD, AND WHY ITS SHAPE MATTERS (task 1003091) ────────────
48
+ //
49
+ // This guard used to be one `SELECT 1 FROM governance_roles LIMIT 1` inside a
50
+ // catch-all that skipped on ANY error. When ADR 0174's rename landed
51
+ // (government_001), that table became `government_ranks` — so on a HEALTHY,
52
+ // fully migrated database the probe raised 42P01 (undefined_table), the catch
53
+ // read it as "no migrated Postgres", and the proof exited 0 having asserted
54
+ // NOTHING. It stayed that way silently, because a fail-OPEN guard cannot fail
55
+ // and this file lives in run-unit-tests' INTEGRATION set, where nobody reads the
56
+ // skip line.
57
+ //
58
+ // So the two cases are now separated, and only one of them is a skip:
59
+ // • the server is unreachable (no DATABASE_URL, refused, no such DB) → SKIP.
60
+ // That is the "this lane has no Postgres" case the skip exists for.
61
+ // • the server IS reachable but an expected table is MISSING → FAIL, naming
62
+ // the tables. A schema this file cannot recognise is exactly the condition
63
+ // it must shout about: either the proof is stale (as it was) or the database
64
+ // is not what it claims to be.
65
+ const REQUIRED_TABLES = [
66
+ 'builders', 'builder_sessions', 'idea_inbox',
67
+ 'government_ranks', 'government_builder_ranks', 'government_rank_permissions',
68
+ ];
41
69
  try {
42
- await pool.query('SELECT 1 FROM governance_roles LIMIT 1');
70
+ await pool.query('SELECT 1');
43
71
  } catch (e) {
44
- console.log(`government_live_proof.mjs SKIPPED — no migrated Postgres (${e.code || e.message}).`);
72
+ console.log(`government_live_proof.mjs SKIPPED — Postgres unreachable (${e.code || e.message}).`);
45
73
  await pool.end().catch(() => {});
46
74
  process.exit(0);
47
75
  }
76
+ {
77
+ const { rows } = await pool.query(
78
+ `SELECT table_name FROM information_schema.tables
79
+ WHERE table_schema = 'public' AND table_name = ANY($1::text[])`,
80
+ [REQUIRED_TABLES],
81
+ );
82
+ const present = new Set(rows.map((r) => r.table_name));
83
+ const missing = REQUIRED_TABLES.filter((t) => !present.has(t));
84
+ if (missing.length === REQUIRED_TABLES.length) {
85
+ // Nothing at all: an empty database, not a stale proof. Still a legitimate
86
+ // skip — this is the "reachable server, no instance schema" case.
87
+ console.log('government_live_proof.mjs SKIPPED — reachable Postgres with no instance schema (run scripts/migrate.sh).');
88
+ await pool.end().catch(() => {});
89
+ process.exit(0);
90
+ }
91
+ if (missing.length) {
92
+ await pool.end().catch(() => {});
93
+ throw new Error(
94
+ `government_live_proof.mjs CANNOT RUN: this database is migrated but is missing ${missing.join(', ')}. `
95
+ + 'Either the schema was renamed under this proof (the task-1003091 failure — fix the names HERE, do not widen the guard) '
96
+ + 'or the target is not a Cloud Bongos instance database.'
97
+ );
98
+ }
99
+ }
48
100
 
49
101
  // ── fixtures (high-ID range; cleaned before AND after so reruns are safe) ────
50
102
  const ARCHON = 90000701;
51
103
  const THETES = 90000702;
52
- const ROLE_KEY = 'glp-demo-triager';
104
+ const RANK_KEY = 'glp-demo-triager';
53
105
  const OPERATIONAL_KEY = 'idea.triage'; // system:false, floor metic — above thetes
54
106
  const SYSTEM_KEY = 'deploy.push_main'; // system:true — substrate-enforced
55
107
  const tok = () => 'glp' + crypto.randomBytes(24).toString('hex');
@@ -59,8 +111,8 @@ const THETES_TOKEN = tok();
59
111
  const q = (sql, params) => pool.query(sql, params).then((r) => r.rows);
60
112
 
61
113
  async function cleanup() {
62
- await q(`DELETE FROM governance_roles WHERE role_key=$1`, [ROLE_KEY]); // grants+assignments cascade
63
- await q(`DELETE FROM governance_builder_roles WHERE builder_id IN ($1,$2)`, [ARCHON, THETES]);
114
+ await q(`DELETE FROM government_ranks WHERE rank_key=$1`, [RANK_KEY]); // grants+assignments cascade
115
+ await q(`DELETE FROM government_builder_ranks WHERE builder_id IN ($1,$2)`, [ARCHON, THETES]);
64
116
  await q(`DELETE FROM builder_sessions WHERE builder_id IN ($1,$2)`, [ARCHON, THETES]);
65
117
  await q(`DELETE FROM idea_inbox WHERE captured_by IN ($1,$2)`, [ARCHON, THETES]);
66
118
  // The audit middleware records the demo's own writes; those rows FK the
@@ -80,7 +132,7 @@ async function seed() {
80
132
  // builder mirrors its effect here (one seeded rank-role each, fail-closed
81
133
  // otherwise — the archon would resolve ZERO permissions and deny itself).
82
134
  await q(
83
- `INSERT INTO governance_builder_roles (builder_id, role_key)
135
+ `INSERT INTO government_builder_ranks (builder_id, rank_key)
84
136
  VALUES ($1,'archon'), ($2,'thetes')`,
85
137
  [ARCHON, THETES]
86
138
  );
@@ -143,35 +195,35 @@ try {
143
195
 
144
196
  // Act 2 — an Archon creates a custom role and grants the operational permission.
145
197
  r = await call(ARCHON_TOKEN, 'POST', '/government/ranks',
146
- { role_key: ROLE_KEY, label: 'GLP demo triage role' });
147
- ok(r.status === 201, 'the Archon creates a custom role (201)');
148
- r = await call(ARCHON_TOKEN, 'PUT', `/governance/roles/${ROLE_KEY}/permissions/${OPERATIONAL_KEY}`);
198
+ { rank_key: RANK_KEY, label: 'GLP demo triage rank' });
199
+ ok(r.status === 201, 'the Archon creates a custom rank (201)');
200
+ r = await call(ARCHON_TOKEN, 'PUT', `/government/ranks/${RANK_KEY}/permissions/${OPERATIONAL_KEY}`);
149
201
  ok(r.status === 200 && r.body.ok === true,
150
- `the Archon grants operational '${OPERATIONAL_KEY}' to the custom role (200)`);
202
+ `the Archon grants operational '${OPERATIONAL_KEY}' to the custom rank (200)`);
151
203
 
152
204
  // Act 3 — the locked wall: a system permission is refused through the same API.
153
- r = await call(ARCHON_TOKEN, 'PUT', `/governance/roles/${ROLE_KEY}/permissions/${SYSTEM_KEY}`);
205
+ r = await call(ARCHON_TOKEN, 'PUT', `/government/ranks/${RANK_KEY}/permissions/${SYSTEM_KEY}`);
154
206
  ok(r.status === 400 && r.body.error.code === 'permission_not_grantable',
155
207
  `system '${SYSTEM_KEY}' is NOT grantable, even by the Archon (400 permission_not_grantable)`);
156
- r = await call(ARCHON_TOKEN, 'PUT', `/governance/roles/${ROLE_KEY}/permissions/government.manage`);
208
+ r = await call(ARCHON_TOKEN, 'PUT', `/government/ranks/${RANK_KEY}/permissions/government.manage`);
157
209
  ok(r.status === 400 && r.body.error.code === 'permission_not_grantable',
158
210
  'the meta-escalation (government.manage) is refused the same way');
159
211
 
160
212
  // Act 4 — assign, then the same builder performs the action: no re-login, no
161
213
  // restart — the per-request, uncached resolve (ADR 0016) picks the role up.
162
214
  r = await call(ARCHON_TOKEN, 'POST', '/government/assignments',
163
- { builder_id: THETES, role_key: ROLE_KEY });
164
- ok(r.status === 201, 'the Archon assigns the custom role to the thetes builder (201)');
215
+ { builder_id: THETES, rank_key: RANK_KEY });
216
+ ok(r.status === 201, 'the Archon assigns the custom rank to the thetes builder (201)');
165
217
  r = await call(THETES_TOKEN, 'PATCH', `/inbox/${ideaId}`, { status: 'discarded' });
166
- ok(r.status === 200, 'AFTER: the same builder, same session, can now triage (200) — the custom role works');
218
+ ok(r.status === 200, 'AFTER: the same builder, same session, can now triage (200) — the custom rank works');
167
219
 
168
220
  // Act 5 — the wall behind the wall: force the grant row no API path can create,
169
- // so the role now "has" a system permission in the DB…
221
+ // so the rank now "has" a system permission in the DB…
170
222
  await q(
171
- `INSERT INTO governance_role_permissions (role_key, permission_key) VALUES ($1,$2)`,
172
- [ROLE_KEY, SYSTEM_KEY]
223
+ `INSERT INTO government_rank_permissions (rank_key, permission_key) VALUES ($1,$2)`,
224
+ [RANK_KEY, SYSTEM_KEY]
173
225
  );
174
- console.log(` (forced INTO the DB: grant ${ROLE_KEY} ← ${SYSTEM_KEY} — no API path can write this row)`);
226
+ console.log(` (forced INTO the DB: grant ${RANK_KEY} ← ${SYSTEM_KEY} — no API path can write this row)`);
175
227
 
176
228
  // …the resolver reports it honestly (it is a defined catalog key; matrix V10
177
229
  // proves no route consumes it via requirePermission, so it admits nothing
@@ -193,7 +245,7 @@ try {
193
245
  ok(sub.hardFail === true && sub.findings.length === 2,
194
246
  'the substrate checker still BLOCKS the protected-path attempt (deploy/migration machinery), forced grant and all');
195
247
 
196
- console.log(`\ngovernance_live_proof: ${pass} assertions passed`);
248
+ console.log(`\ngovernment_live_proof: ${pass} assertions passed`);
197
249
  } finally {
198
250
  await cleanup().catch((e) => console.error('cleanup failed', e.message));
199
251
  if (server) await new Promise((resolve) => server.close(resolve));
@@ -0,0 +1,124 @@
1
+ // tests/government_live_proof_shape.mjs — the DB-free guard on the C6 live proof
2
+ // (task 1003091). ADR 0151's C6 proof (tests/government_live_proof.mjs) is a
3
+ // REAL-DB integration test, so the DB-free lane never runs it — which is how it
4
+ // came to be silently dead for days.
5
+ //
6
+ // WHAT HAPPENED: its readiness probe was `SELECT 1 FROM governance_roles LIMIT 1`
7
+ // inside a catch-all that skipped on ANY error. ADR 0174's rename
8
+ // (government_001) turned that table into `government_ranks`, so on a healthy,
9
+ // fully migrated database the probe raised 42P01 and the catch reported "no
10
+ // migrated Postgres". The proof exited 0 having asserted nothing, and no signal
11
+ // anywhere said so — a fail-OPEN guard cannot fail.
12
+ //
13
+ // So this file pins the two properties that make that irrecoverable-by-silence
14
+ // state impossible, from the lane that DOES run every PR:
15
+ // 1. the proof names the CURRENT schema + routes, not the pre-rename ones;
16
+ // 2. its guard SEPARATES "unreachable" (skip) from "reachable but missing an
17
+ // expected table" (throw) — and no OTHER integration test reintroduces the
18
+ // old shape by probing a specific table inside its skip guard.
19
+ //
20
+ // Run: node --test tests/government_live_proof_shape.mjs
21
+ import assert from 'node:assert/strict';
22
+ import { test } from 'node:test';
23
+ import fs from 'node:fs';
24
+ import path from 'node:path';
25
+ import { fileURLToPath } from 'node:url';
26
+
27
+ const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
28
+ const PROOF_REL = 'tests/government_live_proof.mjs';
29
+ const proof = fs.readFileSync(path.join(ROOT, PROOF_REL), 'utf8');
30
+
31
+ // A line that CITES the incident has to be able to name the old spellings —
32
+ // otherwise the file cannot explain its own history. Same principle as
33
+ // fitness.js's VOCAB_HISTORICAL_REF.
34
+ const CITATION = /task[- ]?1003091|used to be|pre-rename|ADR 0174/i;
35
+ const PRE_RENAME = [
36
+ 'governance_roles',
37
+ 'governance_builder_roles',
38
+ 'governance_role_permissions',
39
+ '/governance/roles',
40
+ ];
41
+
42
+ test('the C6 proof names the CURRENT government schema and routes', () => {
43
+ const offenders = [];
44
+ proof.split('\n').forEach((line, i) => {
45
+ if (CITATION.test(line)) return;
46
+ for (const old of PRE_RENAME) {
47
+ if (line.includes(old)) offenders.push(`${PROOF_REL}:${i + 1}: ${old} → ${line.trim().slice(0, 80)}`);
48
+ }
49
+ });
50
+ assert.deepEqual(offenders, [],
51
+ 'the proof still names pre-rename objects; ADR 0174 renamed them (government_001) and task 1003084 removed the /governance/* alias');
52
+ for (const t of ['government_ranks', 'government_builder_ranks', 'government_rank_permissions']) {
53
+ assert.ok(proof.includes(t), `the proof must exercise ${t}`);
54
+ }
55
+ assert.match(proof, /\/government\/ranks\/\$\{RANK_KEY\}\/permissions\//,
56
+ 'the grant route is /government/ranks/:rankKey/permissions/:permissionKey');
57
+ });
58
+
59
+ test('the readiness guard skips on UNREACHABLE and THROWS on a migrated-but-missing schema', () => {
60
+ // Connectivity is probed with a table-free query: a `SELECT 1 FROM <table>`
61
+ // here is precisely the bug — it conflates "no database" with "schema I do not
62
+ // recognise", and the second one must never be silent.
63
+ const guard = proof.slice(proof.indexOf('const REQUIRED_TABLES'), proof.indexOf('// ── fixtures'));
64
+ assert.ok(guard.includes("pool.query('SELECT 1')"),
65
+ 'connectivity must be probed WITHOUT naming a table');
66
+ assert.ok(!/pool\.query\('SELECT 1 FROM/.test(guard),
67
+ 'no table-named readiness probe may return: that is the task-1003091 failure mode');
68
+ assert.match(guard, /information_schema\.tables/, 'the expected tables are checked explicitly');
69
+ assert.match(guard, /throw new Error\(/, 'a migrated database missing an expected table must THROW');
70
+ assert.match(guard, /CANNOT RUN/, 'and say so loudly enough to read in CI output');
71
+ // The skip branches stay, but only for the two honest cases.
72
+ const skips = guard.match(/SKIPPED/g) || [];
73
+ assert.equal(skips.length, 2,
74
+ 'exactly two skip cases: unreachable server, and a reachable server with NO instance schema');
75
+ });
76
+
77
+ test('no other integration test probes a specific table inside its skip guard', () => {
78
+ // The sibling real-DB tests (needs_rebase, handle_machinery, …) already probe
79
+ // `SELECT 1`. This asserts the whole class, so the old shape cannot reappear
80
+ // in a NEW file and rot there unseen.
81
+ const offenders = [];
82
+ const SELF = path.basename(fileURLToPath(import.meta.url)); // the rule is not one of its own subjects
83
+ for (const name of fs.readdirSync(path.join(ROOT, 'tests')).filter((n) => n.endsWith('.mjs') && n !== SELF)) {
84
+ const src = fs.readFileSync(path.join(ROOT, 'tests', name), 'utf8');
85
+ if (!src.includes('SKIPPED')) continue;
86
+ src.split('\n').forEach((line, i) => {
87
+ if (CITATION.test(line)) return;
88
+ // A readiness probe is a LIVE query: `await pool.query('SELECT 1 FROM x')`.
89
+ // Assertions ABOUT sql strings (fakePool matchers, /SELECT 1 FROM …/ regexes)
90
+ // are not queries and are left alone.
91
+ if (/(await\s+)?pool\.query\(\s*['"`]SELECT 1 FROM /.test(line)) {
92
+ offenders.push(`tests/${name}:${i + 1}: ${line.trim().slice(0, 80)}`);
93
+ }
94
+ });
95
+ }
96
+ assert.deepEqual(offenders, [],
97
+ 'a skip guard that probes a named table skips silently the day that table is renamed (task 1003091)');
98
+ });
99
+
100
+ test('every curated INTEGRATION / KNOWN_FAILING entry names a real test file', () => {
101
+ // The SAME rename miss, one layer out: run-unit-tests.js's curated sets are keyed
102
+ // by filename STEM, and the INTEGRATION set still said `governance_live_proof`
103
+ // after ADR 0174 renamed the file. A stem that matches nothing does not error —
104
+ // the entry just stops applying, so the file quietly moved into the DB-free lane
105
+ // (where it "passed" by self-skipping). Curated lists must point at real files.
106
+ const runner = fs.readFileSync(path.join(ROOT, 'scripts', 'gds', 'run-unit-tests.js'), 'utf8');
107
+ const setEntries = (name) => {
108
+ const start = runner.indexOf(`const ${name} = new Set([`);
109
+ assert.ok(start > -1, `${name} must exist in run-unit-tests.js`);
110
+ const block = runner.slice(start, runner.indexOf(']);', start));
111
+ return [...block.matchAll(/'([a-z0-9_.-]+)'/gi)].map((m) => m[1]).filter((k) => k !== name);
112
+ };
113
+ const stems = new Set(
114
+ fs.readdirSync(path.join(ROOT, 'tests')).filter((n) => n.endsWith('.mjs')).map((n) => n.replace(/\.mjs$/, ''))
115
+ );
116
+ const missing = [];
117
+ for (const setName of ['INTEGRATION', 'KNOWN_FAILING']) {
118
+ for (const stem of setEntries(setName)) {
119
+ if (!stems.has(stem)) missing.push(`${setName}: '${stem}' matches no tests/*.mjs`);
120
+ }
121
+ }
122
+ assert.deepEqual(missing, [],
123
+ 'a curated entry whose file was renamed silently stops applying (task 1003091)');
124
+ });