@rigour-labs/core 6.2.5 → 6.3.0

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.
Files changed (111) hide show
  1. package/README.md +2 -0
  2. package/dist/discovery-signals.d.ts +27 -0
  3. package/dist/discovery-signals.js +96 -0
  4. package/dist/discovery.d.ts +1 -2
  5. package/dist/discovery.js +36 -49
  6. package/dist/discovery.test.js +84 -71
  7. package/dist/gates/deep-analysis.d.ts +2 -0
  8. package/dist/gates/deep-analysis.js +5 -1
  9. package/dist/gates/deep-intent.d.ts +3 -0
  10. package/dist/gates/deep-intent.js +57 -0
  11. package/dist/gates/deep-intent.test.d.ts +1 -0
  12. package/dist/gates/deep-intent.test.js +51 -0
  13. package/dist/gates/deep-runner.js +1 -0
  14. package/dist/gates/deprecated-apis-ast.d.ts +8 -0
  15. package/dist/gates/deprecated-apis-ast.js +25 -0
  16. package/dist/gates/deprecated-apis-rules-node.js +2 -8
  17. package/dist/gates/deprecated-apis.js +5 -1
  18. package/dist/gates/deprecated-apis.test.js +30 -0
  19. package/dist/gates/frontend-secret-exposure.js +5 -1
  20. package/dist/gates/frontend-secret-exposure.test.js +20 -0
  21. package/dist/gates/hallucinated-imports/framework-modules.d.ts +14 -0
  22. package/dist/gates/hallucinated-imports/framework-modules.js +75 -0
  23. package/dist/gates/hallucinated-imports/index.js +14 -6
  24. package/dist/gates/hallucinated-imports/js-resolver.d.ts +16 -12
  25. package/dist/gates/hallucinated-imports/js-resolver.js +65 -153
  26. package/dist/gates/hallucinated-imports/ts-path-target.js +16 -0
  27. package/dist/gates/hallucinated-imports/tsconfig-paths.d.ts +16 -0
  28. package/dist/gates/hallucinated-imports/tsconfig-paths.js +120 -0
  29. package/dist/gates/hallucinated-imports-sveltekit.test.d.ts +1 -0
  30. package/dist/gates/hallucinated-imports-sveltekit.test.js +108 -0
  31. package/dist/gates/runner.js +5 -0
  32. package/dist/gates/semantic-bugs.d.ts +23 -0
  33. package/dist/gates/semantic-bugs.js +48 -0
  34. package/dist/gates/semantic-bugs.test.d.ts +1 -0
  35. package/dist/gates/semantic-bugs.test.js +70 -0
  36. package/dist/gates/side-effect-analysis/index.js +11 -1
  37. package/dist/gates/side-effect-analysis.test.d.ts +1 -0
  38. package/dist/gates/side-effect-analysis.test.js +162 -0
  39. package/dist/gates/side-effect-helpers/pattern-detection.js +35 -7
  40. package/dist/gates/side-effect-helpers/resource-tracking.js +17 -10
  41. package/dist/gates/side-effect-helpers/scope-analysis.d.ts +6 -0
  42. package/dist/gates/side-effect-helpers/scope-analysis.js +20 -0
  43. package/dist/index.d.ts +5 -1
  44. package/dist/index.js +4 -1
  45. package/dist/inference/sidecar-provider.js +12 -1
  46. package/dist/inference/types.d.ts +2 -0
  47. package/dist/semantic/ast.d.ts +29 -0
  48. package/dist/semantic/ast.js +122 -0
  49. package/dist/semantic/benchmark.d.ts +16 -0
  50. package/dist/semantic/benchmark.js +31 -0
  51. package/dist/semantic/benchmark.test.d.ts +1 -0
  52. package/dist/semantic/benchmark.test.js +18 -0
  53. package/dist/semantic/engine.d.ts +8 -0
  54. package/dist/semantic/engine.js +45 -0
  55. package/dist/semantic/intent/benchmark.d.ts +31 -0
  56. package/dist/semantic/intent/benchmark.js +74 -0
  57. package/dist/semantic/intent/intent-check.d.ts +43 -0
  58. package/dist/semantic/intent/intent-check.js +72 -0
  59. package/dist/semantic/intent/intent.test.d.ts +1 -0
  60. package/dist/semantic/intent/intent.test.js +46 -0
  61. package/dist/semantic/intent/parallel-reads.d.ts +23 -0
  62. package/dist/semantic/intent/parallel-reads.js +59 -0
  63. package/dist/semantic/learn/benchmark.d.ts +20 -0
  64. package/dist/semantic/learn/benchmark.js +71 -0
  65. package/dist/semantic/learn/compile.d.ts +4 -0
  66. package/dist/semantic/learn/compile.js +56 -0
  67. package/dist/semantic/learn/conditions.d.ts +22 -0
  68. package/dist/semantic/learn/conditions.js +93 -0
  69. package/dist/semantic/learn/extract.d.ts +30 -0
  70. package/dist/semantic/learn/extract.js +122 -0
  71. package/dist/semantic/learn/git-trees.d.ts +8 -0
  72. package/dist/semantic/learn/git-trees.js +32 -0
  73. package/dist/semantic/learn/identity.d.ts +18 -0
  74. package/dist/semantic/learn/identity.js +97 -0
  75. package/dist/semantic/learn/learn.d.ts +25 -0
  76. package/dist/semantic/learn/learn.js +109 -0
  77. package/dist/semantic/learn/learn.test.d.ts +1 -0
  78. package/dist/semantic/learn/learn.test.js +67 -0
  79. package/dist/semantic/learn/store.d.ts +4 -0
  80. package/dist/semantic/learn/store.js +39 -0
  81. package/dist/semantic/learn/types.d.ts +468 -0
  82. package/dist/semantic/learn/types.js +55 -0
  83. package/dist/semantic/origins.d.ts +42 -0
  84. package/dist/semantic/origins.js +149 -0
  85. package/dist/semantic/origins.test.d.ts +1 -0
  86. package/dist/semantic/origins.test.js +77 -0
  87. package/dist/semantic/program.d.ts +13 -0
  88. package/dist/semantic/program.js +62 -0
  89. package/dist/semantic/rules/credential-redirect.d.ts +2 -0
  90. package/dist/semantic/rules/credential-redirect.js +209 -0
  91. package/dist/semantic/rules/degraded-response-cached.d.ts +2 -0
  92. package/dist/semantic/rules/degraded-response-cached.js +271 -0
  93. package/dist/semantic/rules/in-memory-aggregation.d.ts +2 -0
  94. package/dist/semantic/rules/in-memory-aggregation.js +179 -0
  95. package/dist/semantic/summaries.d.ts +18 -0
  96. package/dist/semantic/summaries.js +33 -0
  97. package/dist/semantic/types.d.ts +32 -0
  98. package/dist/semantic/types.js +1 -0
  99. package/dist/storage/index.d.ts +1 -0
  100. package/dist/storage/index.js +1 -0
  101. package/dist/storage/team-diagnostics.d.ts +22 -0
  102. package/dist/storage/team-diagnostics.js +58 -0
  103. package/dist/storage/team-diagnostics.test.d.ts +1 -0
  104. package/dist/storage/team-diagnostics.test.js +51 -0
  105. package/dist/storage/team-schema.d.ts +6 -0
  106. package/dist/storage/team-schema.js +82 -0
  107. package/dist/storage/team-store.js +25 -72
  108. package/dist/templates/universal-config.js +4 -0
  109. package/dist/types/index.d.ts +56 -0
  110. package/dist/types/index.js +7 -0
  111. package/package.json +6 -6
@@ -0,0 +1,51 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { diagnoseMissingMembership, explainTeamConnectionError } from './team-diagnostics.js';
3
+ import { TEAM_SCHEMA } from './team-schema.js';
4
+ function pool(rows) {
5
+ return {
6
+ query: async () => {
7
+ if (rows instanceof Error)
8
+ throw rows;
9
+ return { rows, rowCount: rows.length };
10
+ },
11
+ };
12
+ }
13
+ describe('explainTeamConnectionError', () => {
14
+ it('explains an untrusted certificate chain with the CA fix', () => {
15
+ const message = explainTeamConnectionError(Object.assign(new Error('self-signed certificate in certificate chain'), { code: 'SELF_SIGNED_CERT_IN_CHAIN' }));
16
+ expect(message).toContain('NODE_EXTRA_CA_CERTS');
17
+ expect(message).toContain('sslmode=verify-full');
18
+ });
19
+ it('points a missing schema at init-schema', () => {
20
+ expect(explainTeamConnectionError({ code: '42P01', message: 'relation "rigour.memberships" does not exist' })).toContain('rigour team init-schema');
21
+ });
22
+ it('explains a rejected login and an unreachable host', () => {
23
+ expect(explainTeamConnectionError({ code: '28P01', message: 'password authentication failed' })).toContain('rejected the login');
24
+ expect(explainTeamConnectionError({ code: 'ECONNREFUSED', message: 'connect ECONNREFUSED' })).toContain('Cannot reach');
25
+ });
26
+ it('passes other errors through', () => {
27
+ expect(explainTeamConnectionError(new Error('something else'))).toBe('something else');
28
+ });
29
+ });
30
+ describe('diagnoseMissingMembership', () => {
31
+ it('names row-level security without a policy as the cause', async () => {
32
+ const message = await diagnoseMissingMembership(pool([{ table_name: 'memberships' }, { table_name: 'meta' }]));
33
+ expect(message).toContain('rigour.memberships and rigour.meta');
34
+ expect(message).toContain('init-schema');
35
+ });
36
+ it('reports a missing membership when nothing hides it', async () => {
37
+ expect(await diagnoseMissingMembership(pool([]))).toContain('no membership');
38
+ });
39
+ it('falls back to the membership message when the catalog cannot be read', async () => {
40
+ expect(await diagnoseMissingMembership(pool(new Error('permission denied')))).toContain('no membership');
41
+ });
42
+ });
43
+ describe('team schema', () => {
44
+ it('protects every team table with row-level security and a read policy', () => {
45
+ for (const table of ['lessons', 'memberships', 'meta']) {
46
+ expect(TEAM_SCHEMA).toContain(`ALTER TABLE rigour.${table} ENABLE ROW LEVEL SECURITY;`);
47
+ }
48
+ expect(TEAM_SCHEMA).toContain('CREATE POLICY memberships_read_own ON rigour.memberships FOR SELECT USING (db_role = current_user);');
49
+ expect(TEAM_SCHEMA).toContain('CREATE POLICY meta_read ON rigour.meta FOR SELECT USING (true);');
50
+ });
51
+ });
@@ -0,0 +1,6 @@
1
+ /**
2
+ * PostgreSQL team schema. Idempotent: re-running it on an existing database
3
+ * (`rigour team init-schema`) adds anything missing, including the RLS
4
+ * policies, without touching data.
5
+ */
6
+ export declare const TEAM_SCHEMA = "\nCREATE SCHEMA IF NOT EXISTS rigour;\nCREATE TABLE IF NOT EXISTS rigour.meta (\n key TEXT PRIMARY KEY,\n value TEXT NOT NULL\n);\nCREATE TABLE IF NOT EXISTS rigour.memberships (\n db_role NAME NOT NULL,\n organization_id TEXT NOT NULL,\n team_id TEXT NOT NULL,\n actor_id TEXT NOT NULL,\n role TEXT NOT NULL CHECK (role IN ('member', 'sme', 'owner')),\n PRIMARY KEY (db_role, team_id)\n);\nCREATE TABLE IF NOT EXISTS rigour.lessons (\n id TEXT PRIMARY KEY,\n organization_id TEXT NOT NULL,\n team_id TEXT NOT NULL,\n repository_id TEXT NOT NULL,\n actor_id TEXT NOT NULL,\n visibility TEXT NOT NULL CHECK (visibility IN ('personal', 'team')),\n state TEXT NOT NULL CHECK (state IN ('candidate', 'validated', 'promoted', 'rejected', 'superseded')),\n kind TEXT NOT NULL,\n subject TEXT NOT NULL,\n evidence_json JSONB NOT NULL,\n confidence DOUBLE PRECISION NOT NULL,\n source TEXT NOT NULL,\n supersedes_id TEXT,\n created_at BIGINT NOT NULL,\n updated_at BIGINT NOT NULL\n);\nALTER TABLE rigour.lessons ENABLE ROW LEVEL SECURITY;\nDROP POLICY IF EXISTS lessons_read ON rigour.lessons;\nCREATE POLICY lessons_read ON rigour.lessons FOR SELECT USING (\n EXISTS (\n SELECT 1 FROM rigour.memberships membership\n WHERE membership.db_role = current_user\n AND membership.organization_id = lessons.organization_id\n AND membership.team_id = lessons.team_id\n AND ((lessons.visibility = 'team' AND lessons.state = 'promoted')\n OR membership.actor_id = lessons.actor_id)\n )\n);\nDROP POLICY IF EXISTS lessons_write ON rigour.lessons;\nCREATE POLICY lessons_write ON rigour.lessons FOR ALL USING (\n EXISTS (\n SELECT 1 FROM rigour.memberships membership\n WHERE membership.db_role = current_user\n AND membership.organization_id = lessons.organization_id\n AND membership.team_id = lessons.team_id\n AND membership.actor_id = lessons.actor_id\n AND (lessons.visibility = 'personal' OR membership.role IN ('sme', 'owner'))\n )\n) WITH CHECK (\n EXISTS (\n SELECT 1 FROM rigour.memberships membership\n WHERE membership.db_role = current_user\n AND membership.organization_id = lessons.organization_id\n AND membership.team_id = lessons.team_id\n AND membership.actor_id = lessons.actor_id\n AND (lessons.visibility = 'personal' OR membership.role IN ('sme', 'owner'))\n )\n);\n-- Row-level security on every team table. A host (for example Supabase's\n-- security advisor) may enable RLS on its own; without a policy each member\n-- login would then see no rows at all. Members read only their own\n-- membership rows (the lessons policies read memberships the same way), and\n-- meta holds only the schema version.\nALTER TABLE rigour.memberships ENABLE ROW LEVEL SECURITY;\nDROP POLICY IF EXISTS memberships_read_own ON rigour.memberships;\nCREATE POLICY memberships_read_own ON rigour.memberships FOR SELECT USING (db_role = current_user);\nALTER TABLE rigour.meta ENABLE ROW LEVEL SECURITY;\nDROP POLICY IF EXISTS meta_read ON rigour.meta;\nCREATE POLICY meta_read ON rigour.meta FOR SELECT USING (true);\nINSERT INTO rigour.meta (key, value) VALUES ('schema_version', '1')\nON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value;\n";
@@ -0,0 +1,82 @@
1
+ /**
2
+ * PostgreSQL team schema. Idempotent: re-running it on an existing database
3
+ * (`rigour team init-schema`) adds anything missing, including the RLS
4
+ * policies, without touching data.
5
+ */
6
+ export const TEAM_SCHEMA = `
7
+ CREATE SCHEMA IF NOT EXISTS rigour;
8
+ CREATE TABLE IF NOT EXISTS rigour.meta (
9
+ key TEXT PRIMARY KEY,
10
+ value TEXT NOT NULL
11
+ );
12
+ CREATE TABLE IF NOT EXISTS rigour.memberships (
13
+ db_role NAME NOT NULL,
14
+ organization_id TEXT NOT NULL,
15
+ team_id TEXT NOT NULL,
16
+ actor_id TEXT NOT NULL,
17
+ role TEXT NOT NULL CHECK (role IN ('member', 'sme', 'owner')),
18
+ PRIMARY KEY (db_role, team_id)
19
+ );
20
+ CREATE TABLE IF NOT EXISTS rigour.lessons (
21
+ id TEXT PRIMARY KEY,
22
+ organization_id TEXT NOT NULL,
23
+ team_id TEXT NOT NULL,
24
+ repository_id TEXT NOT NULL,
25
+ actor_id TEXT NOT NULL,
26
+ visibility TEXT NOT NULL CHECK (visibility IN ('personal', 'team')),
27
+ state TEXT NOT NULL CHECK (state IN ('candidate', 'validated', 'promoted', 'rejected', 'superseded')),
28
+ kind TEXT NOT NULL,
29
+ subject TEXT NOT NULL,
30
+ evidence_json JSONB NOT NULL,
31
+ confidence DOUBLE PRECISION NOT NULL,
32
+ source TEXT NOT NULL,
33
+ supersedes_id TEXT,
34
+ created_at BIGINT NOT NULL,
35
+ updated_at BIGINT NOT NULL
36
+ );
37
+ ALTER TABLE rigour.lessons ENABLE ROW LEVEL SECURITY;
38
+ DROP POLICY IF EXISTS lessons_read ON rigour.lessons;
39
+ CREATE POLICY lessons_read ON rigour.lessons FOR SELECT USING (
40
+ EXISTS (
41
+ SELECT 1 FROM rigour.memberships membership
42
+ WHERE membership.db_role = current_user
43
+ AND membership.organization_id = lessons.organization_id
44
+ AND membership.team_id = lessons.team_id
45
+ AND ((lessons.visibility = 'team' AND lessons.state = 'promoted')
46
+ OR membership.actor_id = lessons.actor_id)
47
+ )
48
+ );
49
+ DROP POLICY IF EXISTS lessons_write ON rigour.lessons;
50
+ CREATE POLICY lessons_write ON rigour.lessons FOR ALL USING (
51
+ EXISTS (
52
+ SELECT 1 FROM rigour.memberships membership
53
+ WHERE membership.db_role = current_user
54
+ AND membership.organization_id = lessons.organization_id
55
+ AND membership.team_id = lessons.team_id
56
+ AND membership.actor_id = lessons.actor_id
57
+ AND (lessons.visibility = 'personal' OR membership.role IN ('sme', 'owner'))
58
+ )
59
+ ) WITH CHECK (
60
+ EXISTS (
61
+ SELECT 1 FROM rigour.memberships membership
62
+ WHERE membership.db_role = current_user
63
+ AND membership.organization_id = lessons.organization_id
64
+ AND membership.team_id = lessons.team_id
65
+ AND membership.actor_id = lessons.actor_id
66
+ AND (lessons.visibility = 'personal' OR membership.role IN ('sme', 'owner'))
67
+ )
68
+ );
69
+ -- Row-level security on every team table. A host (for example Supabase's
70
+ -- security advisor) may enable RLS on its own; without a policy each member
71
+ -- login would then see no rows at all. Members read only their own
72
+ -- membership rows (the lessons policies read memberships the same way), and
73
+ -- meta holds only the schema version.
74
+ ALTER TABLE rigour.memberships ENABLE ROW LEVEL SECURITY;
75
+ DROP POLICY IF EXISTS memberships_read_own ON rigour.memberships;
76
+ CREATE POLICY memberships_read_own ON rigour.memberships FOR SELECT USING (db_role = current_user);
77
+ ALTER TABLE rigour.meta ENABLE ROW LEVEL SECURITY;
78
+ DROP POLICY IF EXISTS meta_read ON rigour.meta;
79
+ CREATE POLICY meta_read ON rigour.meta FOR SELECT USING (true);
80
+ INSERT INTO rigour.meta (key, value) VALUES ('schema_version', '1')
81
+ ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value;
82
+ `;
@@ -3,6 +3,8 @@ import os from 'os';
3
3
  import path from 'path';
4
4
  import { openDatabase } from './db.js';
5
5
  import { decryptLocalPayload, encryptLocalPayload } from './local-encryption.js';
6
+ import { TEAM_SCHEMA } from './team-schema.js';
7
+ import { diagnoseMissingMembership, explainTeamConnectionError } from './team-diagnostics.js';
6
8
  import { TEAM_VECTOR_SCHEMA, backfillConfiguredTeamEmbeddings, getTeamSemanticHealth, searchConfiguredTeamKnowledge, upsertTeamLessonEmbedding, } from './team-vector-store.js';
7
9
  const DEFAULT_SEMANTIC = {
8
10
  provider: 'pgvector',
@@ -84,72 +86,6 @@ async function queuedChanges() {
84
86
  await db.close();
85
87
  }
86
88
  }
87
- const TEAM_SCHEMA = `
88
- CREATE SCHEMA IF NOT EXISTS rigour;
89
- CREATE TABLE IF NOT EXISTS rigour.meta (
90
- key TEXT PRIMARY KEY,
91
- value TEXT NOT NULL
92
- );
93
- CREATE TABLE IF NOT EXISTS rigour.memberships (
94
- db_role NAME NOT NULL,
95
- organization_id TEXT NOT NULL,
96
- team_id TEXT NOT NULL,
97
- actor_id TEXT NOT NULL,
98
- role TEXT NOT NULL CHECK (role IN ('member', 'sme', 'owner')),
99
- PRIMARY KEY (db_role, team_id)
100
- );
101
- CREATE TABLE IF NOT EXISTS rigour.lessons (
102
- id TEXT PRIMARY KEY,
103
- organization_id TEXT NOT NULL,
104
- team_id TEXT NOT NULL,
105
- repository_id TEXT NOT NULL,
106
- actor_id TEXT NOT NULL,
107
- visibility TEXT NOT NULL CHECK (visibility IN ('personal', 'team')),
108
- state TEXT NOT NULL CHECK (state IN ('candidate', 'validated', 'promoted', 'rejected', 'superseded')),
109
- kind TEXT NOT NULL,
110
- subject TEXT NOT NULL,
111
- evidence_json JSONB NOT NULL,
112
- confidence DOUBLE PRECISION NOT NULL,
113
- source TEXT NOT NULL,
114
- supersedes_id TEXT,
115
- created_at BIGINT NOT NULL,
116
- updated_at BIGINT NOT NULL
117
- );
118
- ALTER TABLE rigour.lessons ENABLE ROW LEVEL SECURITY;
119
- DROP POLICY IF EXISTS lessons_read ON rigour.lessons;
120
- CREATE POLICY lessons_read ON rigour.lessons FOR SELECT USING (
121
- EXISTS (
122
- SELECT 1 FROM rigour.memberships membership
123
- WHERE membership.db_role = current_user
124
- AND membership.organization_id = lessons.organization_id
125
- AND membership.team_id = lessons.team_id
126
- AND ((lessons.visibility = 'team' AND lessons.state = 'promoted')
127
- OR membership.actor_id = lessons.actor_id)
128
- )
129
- );
130
- DROP POLICY IF EXISTS lessons_write ON rigour.lessons;
131
- CREATE POLICY lessons_write ON rigour.lessons FOR ALL USING (
132
- EXISTS (
133
- SELECT 1 FROM rigour.memberships membership
134
- WHERE membership.db_role = current_user
135
- AND membership.organization_id = lessons.organization_id
136
- AND membership.team_id = lessons.team_id
137
- AND membership.actor_id = lessons.actor_id
138
- AND (lessons.visibility = 'personal' OR membership.role IN ('sme', 'owner'))
139
- )
140
- ) WITH CHECK (
141
- EXISTS (
142
- SELECT 1 FROM rigour.memberships membership
143
- WHERE membership.db_role = current_user
144
- AND membership.organization_id = lessons.organization_id
145
- AND membership.team_id = lessons.team_id
146
- AND membership.actor_id = lessons.actor_id
147
- AND (lessons.visibility = 'personal' OR membership.role IN ('sme', 'owner'))
148
- )
149
- );
150
- INSERT INTO rigour.meta (key, value) VALUES ('schema_version', '1')
151
- ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value;
152
- `;
153
89
  export async function initializeTeamSchema(databaseUrl, options = {}) {
154
90
  validateTeamDatabaseUrl(databaseUrl);
155
91
  const { Pool } = await loadPg();
@@ -171,7 +107,7 @@ export async function getTeamModeStatus() {
171
107
  }
172
108
  try {
173
109
  const result = await doctorTeamConnection(config);
174
- return result;
110
+ return result.connectivity === 'offline' ? { ...result, message: `Offline — changes queued. ${result.message}` } : result;
175
111
  }
176
112
  catch (error) {
177
113
  return {
@@ -190,7 +126,21 @@ export async function doctorTeamConnection(config) {
190
126
  if (!resolved?.databaseUrl) {
191
127
  return { mode: 'local', connectivity: 'local', queuedChanges: await queuedChanges(), message: 'Team mode is not configured.' };
192
128
  }
193
- validateTeamDatabaseUrl(resolved.databaseUrl);
129
+ const offline = async (message) => ({
130
+ mode: 'team',
131
+ connectivity: 'offline',
132
+ organizationId: resolved.organizationId,
133
+ teamId: resolved.teamId,
134
+ actorId: resolved.actorId,
135
+ queuedChanges: await queuedChanges(),
136
+ message,
137
+ });
138
+ try {
139
+ validateTeamDatabaseUrl(resolved.databaseUrl);
140
+ }
141
+ catch (error) {
142
+ return offline(explainTeamConnectionError(error));
143
+ }
194
144
  const { Pool } = await loadPg();
195
145
  const pool = new Pool({ connectionString: resolved.databaseUrl });
196
146
  try {
@@ -200,10 +150,10 @@ export async function doctorTeamConnection(config) {
200
150
  FROM rigour.memberships
201
151
  WHERE db_role = current_user AND team_id = $1 AND actor_id = $2 AND organization_id = $3`, [resolved.teamId, resolved.actorId, resolved.organizationId]);
202
152
  if (result.rowCount !== 1)
203
- throw new Error('Database role is not provisioned for this team.');
153
+ return offline(await diagnoseMissingMembership(pool));
204
154
  const schemaVersion = Number(result.rows[0].schema_version);
205
155
  if (schemaVersion !== 1)
206
- throw new Error(`Incompatible team schema version ${schemaVersion}; expected 1.`);
156
+ return offline(`Incompatible team schema version ${schemaVersion}; expected 1.`);
207
157
  const semantic = resolved.semantic ? await getTeamSemanticHealth(pool, resolved) : undefined;
208
158
  return {
209
159
  mode: 'team',
@@ -219,8 +169,11 @@ export async function doctorTeamConnection(config) {
219
169
  message: 'PostgreSQL team mode is healthy.',
220
170
  };
221
171
  }
172
+ catch (error) {
173
+ return offline(explainTeamConnectionError(error));
174
+ }
222
175
  finally {
223
- await pool.end();
176
+ await pool.end().catch(() => undefined);
224
177
  }
225
178
  }
226
179
  export async function syncTeamOutbox(options = {}) {
@@ -243,7 +196,7 @@ export async function syncTeamOutbox(options = {}) {
243
196
  WHERE db_role = current_user AND team_id = $1
244
197
  AND actor_id = $2 AND organization_id = $3`, [config.teamId, config.actorId, config.organizationId]);
245
198
  if (membership.rowCount !== 1)
246
- throw new Error('Database role is not provisioned for this team.');
199
+ throw new Error(await diagnoseMissingMembership(pool));
247
200
  for (const item of pending) {
248
201
  const lesson = await decryptLocalPayload(item.payload_json);
249
202
  try {
@@ -234,6 +234,9 @@ export const UNIVERSAL_CONFIG = {
234
234
  track_branches: true,
235
235
  track_returns: true,
236
236
  },
237
+ semantic_bugs: {
238
+ enabled: false,
239
+ },
237
240
  side_effect_analysis: {
238
241
  enabled: true,
239
242
  check_unbounded_timers: true,
@@ -252,6 +255,7 @@ export const UNIVERSAL_CONFIG = {
252
255
  provider: 'local',
253
256
  threads: 4,
254
257
  temperature: 0.1,
258
+ intent_checks: false,
255
259
  checks: {
256
260
  solid: true,
257
261
  dry: true,
@@ -495,6 +495,16 @@ export declare const GatesSchema: z.ZodObject<{
495
495
  custom_patterns?: string[] | undefined;
496
496
  audit_log?: boolean | undefined;
497
497
  }>>>;
498
+ semantic_bugs: z.ZodDefault<z.ZodOptional<z.ZodObject<{
499
+ enabled: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
500
+ rules: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
501
+ }, "strip", z.ZodTypeAny, {
502
+ enabled: boolean;
503
+ rules?: string[] | undefined;
504
+ }, {
505
+ enabled?: boolean | undefined;
506
+ rules?: string[] | undefined;
507
+ }>>>;
498
508
  side_effect_analysis: z.ZodDefault<z.ZodOptional<z.ZodObject<{
499
509
  enabled: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
500
510
  check_unbounded_timers: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
@@ -576,6 +586,7 @@ export declare const GatesSchema: z.ZodObject<{
576
586
  max_tokens: z.ZodOptional<z.ZodNumber>;
577
587
  temperature: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
578
588
  timeout_ms: z.ZodOptional<z.ZodNumber>;
589
+ intent_checks: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
579
590
  checks: z.ZodDefault<z.ZodOptional<z.ZodObject<{
580
591
  solid: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
581
592
  dry: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
@@ -610,6 +621,7 @@ export declare const GatesSchema: z.ZodObject<{
610
621
  provider: string;
611
622
  threads: number;
612
623
  temperature: number;
624
+ intent_checks: boolean;
613
625
  checks: {
614
626
  architecture: boolean;
615
627
  test_quality: boolean;
@@ -638,6 +650,7 @@ export declare const GatesSchema: z.ZodObject<{
638
650
  max_tokens?: number | undefined;
639
651
  temperature?: number | undefined;
640
652
  timeout_ms?: number | undefined;
653
+ intent_checks?: boolean | undefined;
641
654
  checks?: {
642
655
  architecture?: boolean | undefined;
643
656
  test_quality?: boolean | undefined;
@@ -656,6 +669,7 @@ export declare const GatesSchema: z.ZodObject<{
656
669
  provider: string;
657
670
  threads: number;
658
671
  temperature: number;
672
+ intent_checks: boolean;
659
673
  checks: {
660
674
  architecture: boolean;
661
675
  test_quality: boolean;
@@ -852,6 +866,10 @@ export declare const GatesSchema: z.ZodObject<{
852
866
  custom_patterns: string[];
853
867
  audit_log: boolean;
854
868
  };
869
+ semantic_bugs: {
870
+ enabled: boolean;
871
+ rules?: string[] | undefined;
872
+ };
855
873
  side_effect_analysis: {
856
874
  enabled: boolean;
857
875
  ignore_patterns: string[];
@@ -890,6 +908,7 @@ export declare const GatesSchema: z.ZodObject<{
890
908
  max_tokens?: number | undefined;
891
909
  temperature?: number | undefined;
892
910
  timeout_ms?: number | undefined;
911
+ intent_checks?: boolean | undefined;
893
912
  checks?: {
894
913
  architecture?: boolean | undefined;
895
914
  test_quality?: boolean | undefined;
@@ -1080,6 +1099,10 @@ export declare const GatesSchema: z.ZodObject<{
1080
1099
  custom_patterns?: string[] | undefined;
1081
1100
  audit_log?: boolean | undefined;
1082
1101
  } | undefined;
1102
+ semantic_bugs?: {
1103
+ enabled?: boolean | undefined;
1104
+ rules?: string[] | undefined;
1105
+ } | undefined;
1083
1106
  side_effect_analysis?: {
1084
1107
  enabled?: boolean | undefined;
1085
1108
  ignore_patterns?: string[] | undefined;
@@ -1661,6 +1684,16 @@ export declare const ConfigSchema: z.ZodObject<{
1661
1684
  custom_patterns?: string[] | undefined;
1662
1685
  audit_log?: boolean | undefined;
1663
1686
  }>>>;
1687
+ semantic_bugs: z.ZodDefault<z.ZodOptional<z.ZodObject<{
1688
+ enabled: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
1689
+ rules: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
1690
+ }, "strip", z.ZodTypeAny, {
1691
+ enabled: boolean;
1692
+ rules?: string[] | undefined;
1693
+ }, {
1694
+ enabled?: boolean | undefined;
1695
+ rules?: string[] | undefined;
1696
+ }>>>;
1664
1697
  side_effect_analysis: z.ZodDefault<z.ZodOptional<z.ZodObject<{
1665
1698
  enabled: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
1666
1699
  check_unbounded_timers: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
@@ -1742,6 +1775,7 @@ export declare const ConfigSchema: z.ZodObject<{
1742
1775
  max_tokens: z.ZodOptional<z.ZodNumber>;
1743
1776
  temperature: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
1744
1777
  timeout_ms: z.ZodOptional<z.ZodNumber>;
1778
+ intent_checks: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
1745
1779
  checks: z.ZodDefault<z.ZodOptional<z.ZodObject<{
1746
1780
  solid: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
1747
1781
  dry: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
@@ -1776,6 +1810,7 @@ export declare const ConfigSchema: z.ZodObject<{
1776
1810
  provider: string;
1777
1811
  threads: number;
1778
1812
  temperature: number;
1813
+ intent_checks: boolean;
1779
1814
  checks: {
1780
1815
  architecture: boolean;
1781
1816
  test_quality: boolean;
@@ -1804,6 +1839,7 @@ export declare const ConfigSchema: z.ZodObject<{
1804
1839
  max_tokens?: number | undefined;
1805
1840
  temperature?: number | undefined;
1806
1841
  timeout_ms?: number | undefined;
1842
+ intent_checks?: boolean | undefined;
1807
1843
  checks?: {
1808
1844
  architecture?: boolean | undefined;
1809
1845
  test_quality?: boolean | undefined;
@@ -1822,6 +1858,7 @@ export declare const ConfigSchema: z.ZodObject<{
1822
1858
  provider: string;
1823
1859
  threads: number;
1824
1860
  temperature: number;
1861
+ intent_checks: boolean;
1825
1862
  checks: {
1826
1863
  architecture: boolean;
1827
1864
  test_quality: boolean;
@@ -2018,6 +2055,10 @@ export declare const ConfigSchema: z.ZodObject<{
2018
2055
  custom_patterns: string[];
2019
2056
  audit_log: boolean;
2020
2057
  };
2058
+ semantic_bugs: {
2059
+ enabled: boolean;
2060
+ rules?: string[] | undefined;
2061
+ };
2021
2062
  side_effect_analysis: {
2022
2063
  enabled: boolean;
2023
2064
  ignore_patterns: string[];
@@ -2056,6 +2097,7 @@ export declare const ConfigSchema: z.ZodObject<{
2056
2097
  max_tokens?: number | undefined;
2057
2098
  temperature?: number | undefined;
2058
2099
  timeout_ms?: number | undefined;
2100
+ intent_checks?: boolean | undefined;
2059
2101
  checks?: {
2060
2102
  architecture?: boolean | undefined;
2061
2103
  test_quality?: boolean | undefined;
@@ -2246,6 +2288,10 @@ export declare const ConfigSchema: z.ZodObject<{
2246
2288
  custom_patterns?: string[] | undefined;
2247
2289
  audit_log?: boolean | undefined;
2248
2290
  } | undefined;
2291
+ semantic_bugs?: {
2292
+ enabled?: boolean | undefined;
2293
+ rules?: string[] | undefined;
2294
+ } | undefined;
2249
2295
  side_effect_analysis?: {
2250
2296
  enabled?: boolean | undefined;
2251
2297
  ignore_patterns?: string[] | undefined;
@@ -2320,6 +2366,7 @@ export declare const ConfigSchema: z.ZodObject<{
2320
2366
  provider: string;
2321
2367
  threads: number;
2322
2368
  temperature: number;
2369
+ intent_checks: boolean;
2323
2370
  checks: {
2324
2371
  architecture: boolean;
2325
2372
  test_quality: boolean;
@@ -2516,6 +2563,10 @@ export declare const ConfigSchema: z.ZodObject<{
2516
2563
  custom_patterns: string[];
2517
2564
  audit_log: boolean;
2518
2565
  };
2566
+ semantic_bugs: {
2567
+ enabled: boolean;
2568
+ rules?: string[] | undefined;
2569
+ };
2519
2570
  side_effect_analysis: {
2520
2571
  enabled: boolean;
2521
2572
  ignore_patterns: string[];
@@ -2580,6 +2631,7 @@ export declare const ConfigSchema: z.ZodObject<{
2580
2631
  max_tokens?: number | undefined;
2581
2632
  temperature?: number | undefined;
2582
2633
  timeout_ms?: number | undefined;
2634
+ intent_checks?: boolean | undefined;
2583
2635
  checks?: {
2584
2636
  architecture?: boolean | undefined;
2585
2637
  test_quality?: boolean | undefined;
@@ -2770,6 +2822,10 @@ export declare const ConfigSchema: z.ZodObject<{
2770
2822
  custom_patterns?: string[] | undefined;
2771
2823
  audit_log?: boolean | undefined;
2772
2824
  } | undefined;
2825
+ semantic_bugs?: {
2826
+ enabled?: boolean | undefined;
2827
+ rules?: string[] | undefined;
2828
+ } | undefined;
2773
2829
  side_effect_analysis?: {
2774
2830
  enabled?: boolean | undefined;
2775
2831
  ignore_patterns?: string[] | undefined;
@@ -266,6 +266,10 @@ export const GatesSchema = z.object({
266
266
  audit_log: z.boolean().optional().default(true),
267
267
  }).optional().default({}),
268
268
  // v4.3+ Side-Effect Safety Analysis
269
+ semantic_bugs: z.object({
270
+ enabled: z.boolean().optional().default(false),
271
+ rules: z.array(z.string()).optional(),
272
+ }).optional().default({}),
269
273
  side_effect_analysis: z.object({
270
274
  enabled: z.boolean().optional().default(true),
271
275
  check_unbounded_timers: z.boolean().optional().default(true),
@@ -306,6 +310,9 @@ export const GatesSchema = z.object({
306
310
  max_tokens: z.number().optional(), // default per provider: local 1024, cloud 4096
307
311
  temperature: z.number().optional().default(0.1),
308
312
  timeout_ms: z.number().optional(), // per inference call; default per provider: local 60s, cloud 120s
313
+ // Intent questions at engine-proven sites (optional-read-no-fallback) in scoped reviews.
314
+ // Off: the stock local models failed the zero-false-finding bar (docs/DEEP_ANALYSIS.md).
315
+ intent_checks: z.boolean().optional().default(false),
309
316
  checks: z.object({
310
317
  solid: z.boolean().optional().default(true),
311
318
  dry: z.boolean().optional().default(true),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rigour-labs/core",
3
- "version": "6.2.5",
3
+ "version": "6.3.0",
4
4
  "description": "AI-native quality gate engine with local Bayesian learning. AST analysis, drift detection, Fix Packet generation, and agent self-healing across TypeScript, JavaScript, Python, Go, Ruby, and C#.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://rigour.run",
@@ -67,11 +67,11 @@
67
67
  "pg": "^8.16.3",
68
68
  "sqlite3": "^5.1.7",
69
69
  "openai": "^4.104.0",
70
- "@rigour-labs/brain-darwin-arm64": "6.2.5",
71
- "@rigour-labs/brain-darwin-x64": "6.2.5",
72
- "@rigour-labs/brain-linux-arm64": "6.2.5",
73
- "@rigour-labs/brain-win-x64": "6.2.5",
74
- "@rigour-labs/brain-linux-x64": "6.2.5"
70
+ "@rigour-labs/brain-darwin-arm64": "6.3.0",
71
+ "@rigour-labs/brain-darwin-x64": "6.3.0",
72
+ "@rigour-labs/brain-linux-arm64": "6.3.0",
73
+ "@rigour-labs/brain-win-x64": "6.3.0",
74
+ "@rigour-labs/brain-linux-x64": "6.3.0"
75
75
  },
76
76
  "devDependencies": {
77
77
  "@types/fs-extra": "^11.0.4",