@devrik-tools/claude-gates 0.1.2 → 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 (104) 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 -45
  25. package/plugins/gates/hooks/gates/bash-commands/bash-commands.edge.test.mjs +165 -0
  26. package/plugins/gates/hooks/gates/bash-commands/index.mjs +285 -268
  27. package/plugins/gates/hooks/gates/brief-before-delegate/brief-before-delegate.edge.test.mjs +151 -0
  28. package/plugins/gates/hooks/gates/brief-before-delegate/index.mjs +265 -177
  29. package/plugins/gates/hooks/gates/circuit-breaker/circuit-breaker.edge.test.mjs +207 -0
  30. package/plugins/gates/hooks/gates/circuit-breaker/index.mjs +501 -456
  31. package/plugins/gates/hooks/gates/circuit-breaker/test.mjs +161 -143
  32. package/plugins/gates/hooks/gates/dependency-skills/dependency-skills.edge.test.mjs +69 -0
  33. package/plugins/gates/hooks/gates/dependency-skills/index.mjs +126 -118
  34. package/plugins/gates/hooks/gates/diagnosis-before-patch/diagnosis-before-patch.edge.test.mjs +68 -0
  35. package/plugins/gates/hooks/gates/diagnosis-before-patch/index.mjs +43 -49
  36. package/plugins/gates/hooks/gates/feature-catalog/edge.edge.test.mjs +83 -0
  37. package/plugins/gates/hooks/gates/feature-catalog/index.mjs +83 -100
  38. package/plugins/gates/hooks/gates/force-parallel/index.mjs +119 -0
  39. package/plugins/gates/hooks/gates/force-parallel/test.mjs +88 -0
  40. package/plugins/gates/hooks/gates/forge-flow/forge-flow.edge.test.mjs +155 -0
  41. package/plugins/gates/hooks/gates/forge-flow/index.mjs +134 -112
  42. package/plugins/gates/hooks/gates/implementation-pipeline/edge.edge.test.mjs +66 -0
  43. package/plugins/gates/hooks/gates/implementation-pipeline/index.mjs +187 -186
  44. package/plugins/gates/hooks/gates/intent-flow/index.mjs +260 -238
  45. package/plugins/gates/hooks/gates/intent-flow/intent-flow.edge.test.mjs +96 -0
  46. package/plugins/gates/hooks/gates/intent-flow/test.mjs +165 -136
  47. package/plugins/gates/hooks/gates/lint-commit/index.mjs +149 -0
  48. package/plugins/gates/hooks/gates/lint-commit/test.mjs +85 -0
  49. package/plugins/gates/hooks/gates/mandatory-flow/edge.edge.test.mjs +100 -0
  50. package/plugins/gates/hooks/gates/mandatory-flow/index.mjs +180 -166
  51. package/plugins/gates/hooks/gates/neutral-spanish/index.mjs +79 -85
  52. package/plugins/gates/hooks/gates/neutral-spanish/neutral-spanish.edge.test.mjs +80 -0
  53. package/plugins/gates/hooks/gates/never-assume/index.mjs +58 -55
  54. package/plugins/gates/hooks/gates/never-assume/never-assume.edge.test.mjs +71 -0
  55. package/plugins/gates/hooks/gates/never-assume/test.mjs +95 -78
  56. package/plugins/gates/hooks/gates/no-blocking/index.mjs +148 -142
  57. package/plugins/gates/hooks/gates/no-blocking/no-blocking.edge.test.mjs +109 -0
  58. package/plugins/gates/hooks/gates/no-memory-dependency/index.mjs +123 -120
  59. package/plugins/gates/hooks/gates/no-memory-dependency/no-memory-dependency.edge.test.mjs +83 -0
  60. package/plugins/gates/hooks/gates/no-reconfirm/no-reconfirm.edge.test.mjs +91 -0
  61. package/plugins/gates/hooks/gates/protected-paths/index.mjs +144 -147
  62. package/plugins/gates/hooks/gates/protected-paths/protected-paths.edge.test.mjs +126 -0
  63. package/plugins/gates/hooks/gates/recurrence-lock/index.mjs +89 -64
  64. package/plugins/gates/hooks/gates/recurrence-lock/recurrence-lock.edge.test.mjs +102 -0
  65. package/plugins/gates/hooks/gates/reuse-before-build/edge.edge.test.mjs +94 -0
  66. package/plugins/gates/hooks/gates/reuse-before-build/index.mjs +159 -150
  67. package/plugins/gates/hooks/gates/risk-level/index.mjs +263 -203
  68. package/plugins/gates/hooks/gates/risk-level/risk-level.edge.test.mjs +116 -0
  69. package/plugins/gates/hooks/gates/risk-level/test.mjs +153 -125
  70. package/plugins/gates/hooks/gates/root-cause-first/index.mjs +56 -50
  71. package/plugins/gates/hooks/gates/root-cause-first/root-cause-first.edge.test.mjs +58 -0
  72. package/plugins/gates/hooks/gates/root-whitelist/index.mjs +116 -111
  73. package/plugins/gates/hooks/gates/root-whitelist/root-whitelist.edge.test.mjs +97 -0
  74. package/plugins/gates/hooks/gates/rule-skill-autodiscovery/index.mjs +184 -99
  75. package/plugins/gates/hooks/gates/rule-skill-autodiscovery/rule-skill-autodiscovery.edge.test.mjs +126 -0
  76. package/plugins/gates/hooks/gates/sdd-specs/edge.edge.test.mjs +130 -0
  77. package/plugins/gates/hooks/gates/sdd-specs/index.mjs +256 -251
  78. package/plugins/gates/hooks/gates/stop-pending/index.mjs +159 -0
  79. package/plugins/gates/hooks/gates/stop-pending/test.mjs +114 -0
  80. package/plugins/gates/hooks/gates/test-after-implementation/index.mjs +101 -101
  81. package/plugins/gates/hooks/gates/test-after-implementation/test-after-implementation.edge.test.mjs +72 -0
  82. package/plugins/gates/hooks/gates/test-matrix/edge.edge.test.mjs +63 -0
  83. package/plugins/gates/hooks/gates/test-matrix/index.mjs +187 -181
  84. package/plugins/gates/hooks/gates/test-matrix/test.mjs +114 -87
  85. package/plugins/gates/hooks/gates/tool-map/edge.edge.test.mjs +62 -0
  86. package/plugins/gates/hooks/gates/tool-map/index.mjs +143 -140
  87. package/plugins/gates/hooks/hooks.json +346 -286
  88. package/plugins/gates/hooks/lib/__tests__/config.test.mjs +173 -154
  89. package/plugins/gates/hooks/lib/__tests__/hook-io.test.mjs +210 -154
  90. package/plugins/gates/hooks/lib/__tests__/signals.test.mjs +114 -0
  91. package/plugins/gates/hooks/lib/config.mjs +172 -165
  92. package/plugins/gates/hooks/lib/hook-io-config.edge.test.mjs +189 -0
  93. package/plugins/gates/hooks/lib/hook-io.mjs +318 -208
  94. package/plugins/gates/hooks/lib/signals.mjs +127 -0
  95. package/plugins/gates/hooks/wiring-check.mjs +227 -0
  96. package/plugins/tasks/.claude-plugin/plugin.json +9 -0
  97. package/plugins/tasks/hooks/__tests__/register-requests.test.mjs +100 -0
  98. package/plugins/tasks/hooks/__tests__/session-tasks.test.mjs +95 -0
  99. package/plugins/tasks/hooks/hooks.json +26 -0
  100. package/plugins/tasks/hooks/lib/__tests__/task-store.test.mjs +180 -132
  101. package/plugins/tasks/hooks/lib/task-store.mjs +197 -159
  102. package/plugins/tasks/hooks/register-requests.mjs +141 -108
  103. package/plugins/tasks/hooks/session-tasks.mjs +108 -0
  104. package/registry.json +793 -686
@@ -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
+ });