@devrik-tools/claude-gates 0.1.1 → 0.1.3

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 (105) hide show
  1. package/.claude-plugin/marketplace.json +23 -17
  2. package/cli/__tests__/config.test.mjs +113 -101
  3. package/cli/__tests__/install.test.mjs +102 -0
  4. package/cli/__tests__/materialize.test.mjs +95 -0
  5. package/cli/__tests__/registry-gates-consistency.test.mjs +52 -44
  6. package/cli/__tests__/task.test.mjs +124 -0
  7. package/cli/config.mjs +124 -113
  8. package/cli/index.mjs +100 -97
  9. package/cli/init.mjs +259 -256
  10. package/cli/install.mjs +150 -80
  11. package/cli/materialize.mjs +102 -51
  12. package/cli/registry.mjs +136 -127
  13. package/cli/task.mjs +140 -0
  14. package/package.json +74 -73
  15. package/plugins/gates/hooks/__tests__/ask-adoption.test.mjs +83 -0
  16. package/plugins/gates/hooks/__tests__/doctor.test.mjs +85 -0
  17. package/plugins/gates/hooks/__tests__/wiring-check.test.mjs +65 -0
  18. package/plugins/gates/hooks/ask-adoption.mjs +147 -0
  19. package/plugins/gates/hooks/doctor.mjs +207 -0
  20. package/plugins/gates/hooks/gates/audit-before-build/audit-before-build.edge.test.mjs +83 -0
  21. package/plugins/gates/hooks/gates/audit-before-build/index.mjs +88 -88
  22. package/plugins/gates/hooks/gates/audit-before-build/test.mjs +117 -92
  23. package/plugins/gates/hooks/gates/autonomous-mode/autonomous.edge.test.mjs +104 -0
  24. package/plugins/gates/hooks/gates/autonomous-mode/index.mjs +48 -0
  25. package/plugins/gates/hooks/gates/autonomous-mode/test.mjs +58 -0
  26. package/plugins/gates/hooks/gates/bash-commands/bash-commands.edge.test.mjs +165 -0
  27. package/plugins/gates/hooks/gates/bash-commands/index.mjs +285 -268
  28. package/plugins/gates/hooks/gates/brief-before-delegate/brief-before-delegate.edge.test.mjs +151 -0
  29. package/plugins/gates/hooks/gates/brief-before-delegate/index.mjs +265 -177
  30. package/plugins/gates/hooks/gates/circuit-breaker/circuit-breaker.edge.test.mjs +207 -0
  31. package/plugins/gates/hooks/gates/circuit-breaker/index.mjs +501 -456
  32. package/plugins/gates/hooks/gates/circuit-breaker/test.mjs +161 -143
  33. package/plugins/gates/hooks/gates/dependency-skills/dependency-skills.edge.test.mjs +69 -0
  34. package/plugins/gates/hooks/gates/dependency-skills/index.mjs +126 -118
  35. package/plugins/gates/hooks/gates/diagnosis-before-patch/diagnosis-before-patch.edge.test.mjs +68 -0
  36. package/plugins/gates/hooks/gates/diagnosis-before-patch/index.mjs +43 -49
  37. package/plugins/gates/hooks/gates/feature-catalog/edge.edge.test.mjs +83 -0
  38. package/plugins/gates/hooks/gates/feature-catalog/index.mjs +83 -100
  39. package/plugins/gates/hooks/gates/force-parallel/index.mjs +119 -0
  40. package/plugins/gates/hooks/gates/force-parallel/test.mjs +88 -0
  41. package/plugins/gates/hooks/gates/forge-flow/forge-flow.edge.test.mjs +155 -0
  42. package/plugins/gates/hooks/gates/forge-flow/index.mjs +134 -112
  43. package/plugins/gates/hooks/gates/implementation-pipeline/edge.edge.test.mjs +66 -0
  44. package/plugins/gates/hooks/gates/implementation-pipeline/index.mjs +187 -186
  45. package/plugins/gates/hooks/gates/intent-flow/index.mjs +260 -238
  46. package/plugins/gates/hooks/gates/intent-flow/intent-flow.edge.test.mjs +96 -0
  47. package/plugins/gates/hooks/gates/intent-flow/test.mjs +165 -136
  48. package/plugins/gates/hooks/gates/lint-commit/index.mjs +149 -0
  49. package/plugins/gates/hooks/gates/lint-commit/test.mjs +85 -0
  50. package/plugins/gates/hooks/gates/mandatory-flow/edge.edge.test.mjs +100 -0
  51. package/plugins/gates/hooks/gates/mandatory-flow/index.mjs +180 -166
  52. package/plugins/gates/hooks/gates/neutral-spanish/index.mjs +79 -85
  53. package/plugins/gates/hooks/gates/neutral-spanish/neutral-spanish.edge.test.mjs +80 -0
  54. package/plugins/gates/hooks/gates/never-assume/index.mjs +58 -55
  55. package/plugins/gates/hooks/gates/never-assume/never-assume.edge.test.mjs +71 -0
  56. package/plugins/gates/hooks/gates/never-assume/test.mjs +95 -78
  57. package/plugins/gates/hooks/gates/no-blocking/index.mjs +148 -142
  58. package/plugins/gates/hooks/gates/no-blocking/no-blocking.edge.test.mjs +109 -0
  59. package/plugins/gates/hooks/gates/no-memory-dependency/index.mjs +123 -120
  60. package/plugins/gates/hooks/gates/no-memory-dependency/no-memory-dependency.edge.test.mjs +83 -0
  61. package/plugins/gates/hooks/gates/no-reconfirm/no-reconfirm.edge.test.mjs +91 -0
  62. package/plugins/gates/hooks/gates/protected-paths/index.mjs +144 -147
  63. package/plugins/gates/hooks/gates/protected-paths/protected-paths.edge.test.mjs +126 -0
  64. package/plugins/gates/hooks/gates/recurrence-lock/index.mjs +89 -64
  65. package/plugins/gates/hooks/gates/recurrence-lock/recurrence-lock.edge.test.mjs +102 -0
  66. package/plugins/gates/hooks/gates/reuse-before-build/edge.edge.test.mjs +94 -0
  67. package/plugins/gates/hooks/gates/reuse-before-build/index.mjs +159 -150
  68. package/plugins/gates/hooks/gates/risk-level/index.mjs +263 -203
  69. package/plugins/gates/hooks/gates/risk-level/risk-level.edge.test.mjs +116 -0
  70. package/plugins/gates/hooks/gates/risk-level/test.mjs +153 -125
  71. package/plugins/gates/hooks/gates/root-cause-first/index.mjs +56 -50
  72. package/plugins/gates/hooks/gates/root-cause-first/root-cause-first.edge.test.mjs +58 -0
  73. package/plugins/gates/hooks/gates/root-whitelist/index.mjs +116 -111
  74. package/plugins/gates/hooks/gates/root-whitelist/root-whitelist.edge.test.mjs +97 -0
  75. package/plugins/gates/hooks/gates/rule-skill-autodiscovery/index.mjs +184 -99
  76. package/plugins/gates/hooks/gates/rule-skill-autodiscovery/rule-skill-autodiscovery.edge.test.mjs +126 -0
  77. package/plugins/gates/hooks/gates/sdd-specs/edge.edge.test.mjs +130 -0
  78. package/plugins/gates/hooks/gates/sdd-specs/index.mjs +256 -251
  79. package/plugins/gates/hooks/gates/stop-pending/index.mjs +159 -0
  80. package/plugins/gates/hooks/gates/stop-pending/test.mjs +114 -0
  81. package/plugins/gates/hooks/gates/test-after-implementation/index.mjs +101 -101
  82. package/plugins/gates/hooks/gates/test-after-implementation/test-after-implementation.edge.test.mjs +72 -0
  83. package/plugins/gates/hooks/gates/test-matrix/edge.edge.test.mjs +63 -0
  84. package/plugins/gates/hooks/gates/test-matrix/index.mjs +187 -181
  85. package/plugins/gates/hooks/gates/test-matrix/test.mjs +114 -87
  86. package/plugins/gates/hooks/gates/tool-map/edge.edge.test.mjs +62 -0
  87. package/plugins/gates/hooks/gates/tool-map/index.mjs +143 -140
  88. package/plugins/gates/hooks/hooks.json +346 -266
  89. package/plugins/gates/hooks/lib/__tests__/config.test.mjs +173 -154
  90. package/plugins/gates/hooks/lib/__tests__/hook-io.test.mjs +210 -154
  91. package/plugins/gates/hooks/lib/__tests__/signals.test.mjs +114 -0
  92. package/plugins/gates/hooks/lib/config.mjs +172 -165
  93. package/plugins/gates/hooks/lib/hook-io-config.edge.test.mjs +189 -0
  94. package/plugins/gates/hooks/lib/hook-io.mjs +318 -208
  95. package/plugins/gates/hooks/lib/signals.mjs +127 -0
  96. package/plugins/gates/hooks/wiring-check.mjs +227 -0
  97. package/plugins/tasks/.claude-plugin/plugin.json +9 -0
  98. package/plugins/tasks/hooks/__tests__/register-requests.test.mjs +100 -0
  99. package/plugins/tasks/hooks/__tests__/session-tasks.test.mjs +95 -0
  100. package/plugins/tasks/hooks/hooks.json +26 -0
  101. package/plugins/tasks/hooks/lib/__tests__/task-store.test.mjs +180 -132
  102. package/plugins/tasks/hooks/lib/task-store.mjs +197 -159
  103. package/plugins/tasks/hooks/register-requests.mjs +141 -108
  104. package/plugins/tasks/hooks/session-tasks.mjs +108 -0
  105. package/registry.json +793 -668
@@ -1,55 +1,58 @@
1
- import { runGate, warn, TOOL_GROUPS } from '../../lib/hook-io.mjs';
2
-
3
- const GATE_ID = 'never-assume';
4
- const CONFIG_KEY = 'requireVerificationBeforeAssuming';
5
-
6
- const DEFAULT_CONJECTURE_PATTERNS = [
7
- 'i assume',
8
- 'assuming that',
9
- 'probably',
10
- 'i guess',
11
- 'should be',
12
- "i'll default to",
13
- ];
14
-
15
- function extractContent(toolName, toolInput) {
16
- if (TOOL_GROUPS.delegation.includes(toolName)) return toolInput?.prompt;
17
- return toolInput?.content ?? toolInput?.new_string;
18
- }
19
-
20
- runGate(
21
- {
22
- id: GATE_ID,
23
- configKey: CONFIG_KEY,
24
- enabledByDefault: false,
25
- defaultParams: {
26
- conjecturePatterns: DEFAULT_CONJECTURE_PATTERNS,
27
- },
28
- },
29
- ({ toolName, toolInput, parameters }) => {
30
- const isWrite = TOOL_GROUPS.write.includes(toolName);
31
- const isDelegation = TOOL_GROUPS.delegation.includes(toolName);
32
- if (!isWrite && !isDelegation) return;
33
-
34
- const content = extractContent(toolName, toolInput);
35
- if (typeof content !== 'string') return;
36
-
37
- const patterns = parameters.conjecturePatterns.map(
38
- (source) => new RegExp(source, 'i'),
39
- );
40
- const hits = [];
41
- for (const pattern of patterns) {
42
- const match = content.match(pattern);
43
- if (match) hits.push(match[0]);
44
- }
45
- if (hits.length === 0) return;
46
-
47
- warn(
48
- GATE_ID,
49
- `Content contains conjecture phrasing without stated verification: ${hits.join(', ')}. Verify before asserting instead of assuming.`,
50
- );
51
- },
52
- );
53
-
54
- // The source guard (guard-never-assume.mjs) is explicit: this never denies,
55
- // only warns — conjecture language is a prompt to verify, not a blocker.
1
+ import {
2
+ runGate,
3
+ warn,
4
+ toolInGroups,
5
+ writtenContentOf,
6
+ delegationPromptOf,
7
+ } from '../../lib/hook-io.mjs';
8
+ import { CONJECTURE_SOURCES } from '../../lib/signals.mjs';
9
+
10
+ const GATE_ID = 'never-assume';
11
+ const CONFIG_KEY = 'requireVerificationBeforeAssuming';
12
+
13
+ // Bilingual (ES+EN) conjecture phrasing, centralized in lib/signals.mjs so every gate
14
+ // that needs to recognize unverified-assumption prose shares the same coverage. See
15
+ // signals.mjs header for the ES/EN-only limitation.
16
+ const DEFAULT_CONJECTURE_PATTERNS = CONJECTURE_SOURCES;
17
+
18
+ function extractContent(toolName, toolInput) {
19
+ if (toolInGroups(toolName, ['delegation'])) return delegationPromptOf(toolInput);
20
+ return writtenContentOf(toolInput);
21
+ }
22
+
23
+ runGate(
24
+ {
25
+ id: GATE_ID,
26
+ configKey: CONFIG_KEY,
27
+ enabledByDefault: false,
28
+ defaultParams: {
29
+ conjecturePatterns: DEFAULT_CONJECTURE_PATTERNS,
30
+ },
31
+ },
32
+ ({ toolName, toolInput, parameters }) => {
33
+ const isWrite = toolInGroups(toolName, ['write']);
34
+ const isDelegation = toolInGroups(toolName, ['delegation']);
35
+ if (!isWrite && !isDelegation) return;
36
+
37
+ const content = extractContent(toolName, toolInput);
38
+ if (!content) return;
39
+
40
+ const patterns = parameters.conjecturePatterns.map(
41
+ (source) => new RegExp(source, 'i'),
42
+ );
43
+ const hits = [];
44
+ for (const pattern of patterns) {
45
+ const match = content.match(pattern);
46
+ if (match) hits.push(match[0]);
47
+ }
48
+ if (hits.length === 0) return;
49
+
50
+ warn(
51
+ GATE_ID,
52
+ `Content contains conjecture phrasing without stated verification: ${hits.join(', ')}. Verify before asserting instead of assuming.`,
53
+ );
54
+ },
55
+ );
56
+
57
+ // The source guard (guard-never-assume.mjs) is explicit: this never denies,
58
+ // only warns — conjecture language is a prompt to verify, not a blocker.
@@ -0,0 +1,71 @@
1
+ import assert from 'node:assert/strict';
2
+ import { execFileSync } from 'node:child_process';
3
+ import { mkdtempSync, mkdirSync, writeFileSync } from 'node:fs';
4
+ import { tmpdir } from 'node:os';
5
+ import { dirname, join } from 'node:path';
6
+ import { test } from 'node:test';
7
+ import { fileURLToPath } from 'node:url';
8
+
9
+ const GATE = join(dirname(fileURLToPath(import.meta.url)), 'index.mjs');
10
+
11
+ function runGate(payload, { config } = {}) {
12
+ const project = mkdtempSync(join(tmpdir(), 'never-assume-edge-'));
13
+ mkdirSync(join(project, '.git'));
14
+ if (config) {
15
+ mkdirSync(join(project, '.ai'));
16
+ writeFileSync(join(project, '.ai', 'config.json'), JSON.stringify(config));
17
+ }
18
+ const out = execFileSync(process.execPath, [GATE], {
19
+ input: JSON.stringify(payload),
20
+ encoding: 'utf8',
21
+ cwd: project,
22
+ env: { ...process.env, HOME: project, USERPROFILE: project },
23
+ });
24
+ return out.trim() ? JSON.parse(out.trim()) : null;
25
+ }
26
+
27
+ function isWarn(result) {
28
+ return result?.hookSpecificOutput?.additionalContext !== undefined;
29
+ }
30
+
31
+ const ENABLE = { config: { gates: { requireVerificationBeforeAssuming: true } } };
32
+
33
+ // FIXED: extractContent() now reads through writtenContentOf() (lib/hook-io.mjs), which
34
+ // covers NotebookEdit's new_source field, closing the tool-coverage gap this test used to
35
+ // document as a bug.
36
+ test('FIXED: conjecture phrasing written via NotebookEdit is detected', () => {
37
+ const payload = {
38
+ tool_name: 'NotebookEdit',
39
+ tool_input: {
40
+ notebook_path: '/repo/nb.ipynb',
41
+ cell_id: 'x',
42
+ new_source: '# i assume the timezone is UTC',
43
+ cell_type: 'code',
44
+ },
45
+ };
46
+ assert.ok(isWarn(runGate(payload, ENABLE)), 'gate now detects conjecture phrasing via NotebookEdit');
47
+ });
48
+
49
+ // EDGE CASE (BUG): 'invoke_subagent' is a declared delegation tool name (TOOL_GROUPS.delegation
50
+ // in lib/hook-io.mjs) and is matched in hooks.json, but extractContent() branches on
51
+ // TOOL_GROUPS.delegation.includes(toolName) which DOES include invoke_subagent — so this one
52
+ // should actually work. Verify it does (a real behavioral check, not a bug) to make sure the
53
+ // delegation branch itself is sound before concluding the write-side gap is the only issue.
54
+ test('OK: conjecture phrasing in an invoke_subagent prompt is detected (delegation branch is sound)', () => {
55
+ const payload = {
56
+ tool_name: 'invoke_subagent',
57
+ tool_input: { prompt: 'i assume the config is already loaded, proceed' },
58
+ };
59
+ assert.ok(isWarn(runGate(payload, ENABLE)));
60
+ });
61
+
62
+ // EDGE CASE: false-positive check — "should be" is a very broad conjecture pattern that can
63
+ // match ordinary correct engineering prose describing an invariant, not an unverified guess,
64
+ // e.g. "the response should be a 200 for valid input" (spec language, not conjecture).
65
+ test('OK/expected-noise: "should be" fires even on spec-style invariant language (broad pattern, not a bug but a known false-positive source)', () => {
66
+ const result = runGate(
67
+ { tool_name: 'Write', tool_input: { file_path: '/repo/x.js', content: '// per the spec, the response should be a 200 for valid input' } },
68
+ ENABLE,
69
+ );
70
+ assert.ok(isWarn(result), 'documents that "should be" over-fires on legitimate spec prose, not just conjecture');
71
+ });
@@ -1,78 +1,95 @@
1
- import assert from 'node:assert/strict';
2
- import { execFileSync } from 'node:child_process';
3
- import { mkdtempSync, mkdirSync, writeFileSync } from 'node:fs';
4
- import { tmpdir } from 'node:os';
5
- import { dirname, join } from 'node:path';
6
- import { test } from 'node:test';
7
- import { fileURLToPath } from 'node:url';
8
-
9
- const GATE = join(dirname(fileURLToPath(import.meta.url)), 'index.mjs');
10
-
11
- function runGate(payload, { config } = {}) {
12
- const project = mkdtempSync(join(tmpdir(), 'never-assume-'));
13
- mkdirSync(join(project, '.git'));
14
- if (config) {
15
- mkdirSync(join(project, '.ai'));
16
- writeFileSync(join(project, '.ai', 'config.json'), JSON.stringify(config));
17
- }
18
- const out = execFileSync(process.execPath, [GATE], {
19
- input: JSON.stringify(payload),
20
- encoding: 'utf8',
21
- cwd: project,
22
- // Isolate from the user's real global config: point homedir() at the temp
23
- // project so the global-config fallback finds nothing (registry default).
24
- env: { ...process.env, HOME: project, USERPROFILE: project },
25
- });
26
- return out.trim() ? JSON.parse(out.trim()) : null;
27
- }
28
-
29
- function write(content) {
30
- return {
31
- tool_name: 'Write',
32
- tool_input: { file_path: '/repo/src/x.js', content },
33
- };
34
- }
35
- function isWarn(result) {
36
- return result?.hookSpecificOutput?.additionalContext !== undefined;
37
- }
38
- function isDeny(result) {
39
- return result?.hookSpecificOutput?.permissionDecision === 'deny';
40
- }
41
-
42
- const ENABLE = {
43
- config: { gates: { requireVerificationBeforeAssuming: true } },
44
- };
45
-
46
- test('warns on conjecture phrasing', () => {
47
- assert.ok(isWarn(runGate(write('// i assume the timezone is UTC'), ENABLE)));
48
- assert.ok(isWarn(runGate(write('// probably fine to skip this'), ENABLE)));
49
- });
50
-
51
- test('never denies, only warns', () => {
52
- const result = runGate(write('// i assume this works'), ENABLE);
53
- assert.ok(isWarn(result));
54
- assert.ok(!isDeny(result));
55
- });
56
-
57
- test('allows content without conjecture phrasing', () => {
58
- assert.equal(runGate(write('const x = 1;'), ENABLE), null);
59
- });
60
-
61
- test('disabled by default (registry default is false)', () => {
62
- assert.equal(runGate(write('// i assume this works')), null);
63
- });
64
-
65
- test('project conjecturePatterns override replaces the built-in list', () => {
66
- const config = {
67
- gates: {
68
- requireVerificationBeforeAssuming: {
69
- enabled: true,
70
- conjecturePatterns: ['totally made up'],
71
- },
72
- },
73
- };
74
- assert.equal(runGate(write('// i assume this works'), { config }), null);
75
- assert.ok(
76
- isWarn(runGate(write('// totally made up value here'), { config })),
77
- );
78
- });
1
+ import assert from 'node:assert/strict';
2
+ import { execFileSync } from 'node:child_process';
3
+ import { mkdtempSync, mkdirSync, writeFileSync } from 'node:fs';
4
+ import { tmpdir } from 'node:os';
5
+ import { dirname, join } from 'node:path';
6
+ import { test } from 'node:test';
7
+ import { fileURLToPath } from 'node:url';
8
+
9
+ const GATE = join(dirname(fileURLToPath(import.meta.url)), 'index.mjs');
10
+
11
+ function runGate(payload, { config } = {}) {
12
+ const project = mkdtempSync(join(tmpdir(), 'never-assume-'));
13
+ mkdirSync(join(project, '.git'));
14
+ if (config) {
15
+ mkdirSync(join(project, '.ai'));
16
+ writeFileSync(join(project, '.ai', 'config.json'), JSON.stringify(config));
17
+ }
18
+ const out = execFileSync(process.execPath, [GATE], {
19
+ input: JSON.stringify(payload),
20
+ encoding: 'utf8',
21
+ cwd: project,
22
+ // Isolate from the user's real global config: point homedir() at the temp
23
+ // project so the global-config fallback finds nothing (registry default).
24
+ env: { ...process.env, HOME: project, USERPROFILE: project },
25
+ });
26
+ return out.trim() ? JSON.parse(out.trim()) : null;
27
+ }
28
+
29
+ function write(content) {
30
+ return {
31
+ tool_name: 'Write',
32
+ tool_input: { file_path: '/repo/src/x.js', content },
33
+ };
34
+ }
35
+ function isWarn(result) {
36
+ return result?.hookSpecificOutput?.additionalContext !== undefined;
37
+ }
38
+ function isDeny(result) {
39
+ return result?.hookSpecificOutput?.permissionDecision === 'deny';
40
+ }
41
+
42
+ const ENABLE = {
43
+ config: { gates: { requireVerificationBeforeAssuming: true } },
44
+ };
45
+
46
+ test('warns on conjecture phrasing', () => {
47
+ assert.ok(isWarn(runGate(write('// i assume the timezone is UTC'), ENABLE)));
48
+ assert.ok(isWarn(runGate(write('// probably fine to skip this'), ENABLE)));
49
+ });
50
+
51
+ test('never denies, only warns', () => {
52
+ const result = runGate(write('// i assume this works'), ENABLE);
53
+ assert.ok(isWarn(result));
54
+ assert.ok(!isDeny(result));
55
+ });
56
+
57
+ test('allows content without conjecture phrasing', () => {
58
+ assert.equal(runGate(write('const x = 1;'), ENABLE), null);
59
+ });
60
+
61
+ test('disabled by default (registry default is false)', () => {
62
+ assert.equal(runGate(write('// i assume this works')), null);
63
+ });
64
+
65
+ test('warns on conjecture phrasing in Spanish', () => {
66
+ assert.ok(isWarn(runGate(write('// supongo que la zona horaria es UTC'), ENABLE)));
67
+ assert.ok(isWarn(runGate(write('// probablemente sea correcto omitir esto'), ENABLE)));
68
+ assert.ok(isWarn(runGate(write('// deberia ser suficiente con este chequeo'), ENABLE)));
69
+ });
70
+
71
+ test('bilingual control: ES and EN equivalent conjecture briefs both warn', () => {
72
+ const es = write('// creo que el usuario ya esta autenticado, no lo verifique');
73
+ const en = write('// i assume the user is already authenticated, did not verify it');
74
+ assert.ok(isWarn(runGate(es, ENABLE)));
75
+ assert.ok(isWarn(runGate(en, ENABLE)));
76
+ });
77
+
78
+ test('allows neutral Spanish content without conjecture phrasing', () => {
79
+ assert.equal(runGate(write('const contrasena = "verificada";'), ENABLE), null);
80
+ });
81
+
82
+ test('project conjecturePatterns override replaces the built-in list', () => {
83
+ const config = {
84
+ gates: {
85
+ requireVerificationBeforeAssuming: {
86
+ enabled: true,
87
+ conjecturePatterns: ['totally made up'],
88
+ },
89
+ },
90
+ };
91
+ assert.equal(runGate(write('// i assume this works'), { config }), null);
92
+ assert.ok(
93
+ isWarn(runGate(write('// totally made up value here'), { config })),
94
+ );
95
+ });