@mindrian_os/install 1.13.0-beta.19 → 1.13.0-beta.22

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.
@@ -0,0 +1,214 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ /*
5
+ * Phase 127-00 (Task 2 RED) -- mindrian-brain stdio shim static + spawn tests.
6
+ *
7
+ * Covers the static / shape / spawn tests for bin/mindrian-brain-mcp-client.cjs:
8
+ * Test 1: shim file exists and is executable
9
+ * Test 2: shim source registers exactly 6 tools
10
+ * Test 3: shim child process boots and writes startup line to stderr (<3s)
11
+ * Test 7: shim source contains zero fetch/http/brain.mindrian/https? matches
12
+ * Test 8: shim source contains zero sendPacket calls (no Phase 110 bypass)
13
+ * Test 9: shim starts with #!/usr/bin/env node shebang
14
+ *
15
+ * Tests 4/5/6 (live JSON-RPC handshake + Tier-0 protocol) land in
16
+ * tests/test-127-00-shim-handshake.sh (Task 3).
17
+ *
18
+ * Canon parts: 7 (reuse of brain-client; thin transport wrapper),
19
+ * 8 (delegation property: zero network surface in the shim itself).
20
+ *
21
+ * HARD RULE: no em-dashes.
22
+ */
23
+
24
+ const assert = require('node:assert/strict');
25
+ const fs = require('node:fs');
26
+ const path = require('node:path');
27
+ const cp = require('node:child_process');
28
+
29
+ const REPO_ROOT = path.resolve(__dirname, '..', '..');
30
+ const SHIM_PATH = path.join(REPO_ROOT, 'bin', 'mindrian-brain-mcp-client.cjs');
31
+
32
+ let passed = 0;
33
+ let failed = 0;
34
+
35
+ function ok(name) {
36
+ passed += 1;
37
+ process.stdout.write(' ok ' + name + '\n');
38
+ }
39
+
40
+ function fail(name, err) {
41
+ failed += 1;
42
+ process.stdout.write(' FAIL ' + name + '\n');
43
+ if (err) process.stdout.write(' ' + (err.message || String(err)) + '\n');
44
+ }
45
+
46
+ // ---------------------------------------------------------------------------
47
+ // Test 1: shim file exists and is executable.
48
+ // ---------------------------------------------------------------------------
49
+ (function test1_executable() {
50
+ const label = 'shim file exists and is executable (mode & 0o111)';
51
+ try {
52
+ assert.ok(fs.existsSync(SHIM_PATH), 'shim file must exist at ' + SHIM_PATH);
53
+ const st = fs.statSync(SHIM_PATH);
54
+ assert.ok((st.mode & 0o111) !== 0,
55
+ 'shim file must be executable; mode = 0' + (st.mode & 0o777).toString(8));
56
+ ok(label);
57
+ } catch (err) { fail(label, err); }
58
+ })();
59
+
60
+ // ---------------------------------------------------------------------------
61
+ // Test 2: exactly 6 tools registered (brain_ask/query/schema/search/stats/write).
62
+ // ---------------------------------------------------------------------------
63
+ (function test2_sixTools() {
64
+ const label = 'shim source registers exactly 6 tools (brain_ask|query|schema|search|stats|write)';
65
+ try {
66
+ const src = fs.readFileSync(SHIM_PATH, 'utf8');
67
+ const re = /server\.tool\(\s*['"]brain_(ask|query|schema|search|stats|write)['"]/g;
68
+ const matches = src.match(re) || [];
69
+ assert.equal(matches.length, 6,
70
+ 'expected exactly 6 server.tool() registrations; got ' + matches.length);
71
+ // Each of the 6 distinct names must appear exactly once. Use a per-name
72
+ // re-scan because the match string spans newlines under the canonical
73
+ // multi-line server.tool() formatting.
74
+ const expected = ['brain_ask', 'brain_query', 'brain_schema', 'brain_search', 'brain_stats', 'brain_write'];
75
+ for (const n of expected) {
76
+ const perName = new RegExp('server\\.tool\\(\\s*[\'"]' + n + '[\'"]', 'g');
77
+ const m = src.match(perName) || [];
78
+ assert.equal(m.length, 1,
79
+ 'tool name ' + n + ' must appear exactly once; got ' + m.length);
80
+ }
81
+ ok(label);
82
+ } catch (err) { fail(label, err); }
83
+ })();
84
+
85
+ // ---------------------------------------------------------------------------
86
+ // Test 3: child process boot writes startup line to stderr within 3s.
87
+ // ---------------------------------------------------------------------------
88
+ (function test3_bootStartupLine() {
89
+ const label = 'shim spawn writes "[mindrian-brain] MCP server v... started (stdio)" to stderr within 3s';
90
+ // Async test wrapped in IIFE; promise chain with timeout.
91
+ const done = new Promise((resolve) => {
92
+ const env = Object.assign({}, process.env);
93
+ delete env.MINDRIAN_BRAIN_KEY;
94
+ const proc = cp.spawn('node', [SHIM_PATH], { env: env, stdio: ['pipe', 'pipe', 'pipe'] });
95
+ let stderr = '';
96
+ let resolved = false;
97
+ proc.stderr.on('data', (chunk) => {
98
+ stderr += chunk.toString('utf8');
99
+ if (/\[mindrian-brain\] MCP server v[^ ]+ started \(stdio\)/.test(stderr)) {
100
+ if (!resolved) {
101
+ resolved = true;
102
+ proc.kill('SIGTERM');
103
+ resolve({ ok: true, stderr: stderr });
104
+ }
105
+ }
106
+ });
107
+ proc.on('error', (err) => {
108
+ if (!resolved) { resolved = true; resolve({ ok: false, error: err }); }
109
+ });
110
+ setTimeout(() => {
111
+ if (!resolved) {
112
+ resolved = true;
113
+ proc.kill('SIGKILL');
114
+ resolve({ ok: false, error: new Error('timeout 3s; stderr=' + stderr) });
115
+ }
116
+ }, 3000);
117
+ });
118
+ // Block on the promise via a synchronous loop is wrong; use an
119
+ // async test runner. Use top-level await via an immediately-invoked
120
+ // async function with a process exit deferral.
121
+ done.then((r) => {
122
+ try {
123
+ assert.ok(r.ok, r.error ? r.error.message : 'startup line not seen');
124
+ ok(label);
125
+ } catch (err) { fail(label, err); }
126
+ finalize();
127
+ });
128
+ })();
129
+
130
+ // ---------------------------------------------------------------------------
131
+ // Test 7: zero Brain network surface in shim source (Canon Part 8 delegation).
132
+ //
133
+ // Token set aligned with the orchestrator's load-bearing success criterion:
134
+ // grep -rE "fetch\(|http\.|brain\.mindrian|onrender" bin/mindrian-brain-mcp-client.cjs
135
+ // returns 0. Note: the plan's <behavior> Test 7 narrative also lists
136
+ // `https?://`, but the plan's <action> mandates the Tier-0 sentinel embed
137
+ // the upgrade-hint URL https://mindrianos.vercel.app/brain-access verbatim --
138
+ // a self-contradicting test specification (Rule 2 deviation). The intent of
139
+ // Canon Part 8 is to catch Brain-network egress in the shim, not user-facing
140
+ // upgrade-hint URLs in a sentinel string. We therefore enforce the
141
+ // orchestrator's load-bearing token set, which is the canon-faithful read.
142
+ // ---------------------------------------------------------------------------
143
+ (function test7_delegationProperty() {
144
+ const label = 'shim source contains zero Brain network surface (fetch / http. / brain.mindrian / onrender)';
145
+ try {
146
+ const src = fs.readFileSync(SHIM_PATH, 'utf8');
147
+ const forbidden = [
148
+ { re: /fetch\(/g, name: 'fetch(' },
149
+ { re: /\bhttp\./g, name: 'http.' },
150
+ { re: /brain\.mindrian/g, name: 'brain.mindrian' },
151
+ { re: /\bonrender\b/g, name: 'onrender' },
152
+ ];
153
+ // Active-code scan: strip block comments and line comments. The doc
154
+ // header explicitly names the forbidden tokens as PROHIBITED; the scan
155
+ // is against ACTIVE code, not documentation.
156
+ let code = src.replace(/\/\*[\s\S]*?\*\//g, '');
157
+ code = code.replace(/^[ \t]*\/\/.*$/gm, '');
158
+ for (const f of forbidden) {
159
+ const m = code.match(f.re) || [];
160
+ assert.equal(m.length, 0,
161
+ 'forbidden Brain network surface "' + f.name + '" found ' + m.length + ' time(s) in active code');
162
+ }
163
+ ok(label);
164
+ } catch (err) { fail(label, err); }
165
+ })();
166
+
167
+ // ---------------------------------------------------------------------------
168
+ // Test 8: zero sendPacket calls (no Phase 110 typed-packet bypass).
169
+ // ---------------------------------------------------------------------------
170
+ (function test8_noSendPacketBypass() {
171
+ const label = 'shim source contains zero sendPacket( / buildBrainPacket calls (Phase 110 contract)';
172
+ try {
173
+ const src = fs.readFileSync(SHIM_PATH, 'utf8');
174
+ let code = src.replace(/\/\*[\s\S]*?\*\//g, '');
175
+ code = code.replace(/^[ \t]*\/\/.*$/gm, '');
176
+ const sp = code.match(/\bsendPacket\(/g) || [];
177
+ const bp = code.match(/\bbuildBrainPacket\b/g) || [];
178
+ const pt = code.match(/\{\s*packet_type\s*:/g) || [];
179
+ assert.equal(sp.length, 0, 'sendPacket( bypass detected ' + sp.length + ' time(s)');
180
+ assert.equal(bp.length, 0, 'buildBrainPacket bypass detected ' + bp.length + ' time(s)');
181
+ assert.equal(pt.length, 0, 'inline { packet_type: } construction detected ' + pt.length + ' time(s)');
182
+ ok(label);
183
+ } catch (err) { fail(label, err); }
184
+ })();
185
+
186
+ // ---------------------------------------------------------------------------
187
+ // Test 9: shebang line.
188
+ // ---------------------------------------------------------------------------
189
+ (function test9_shebang() {
190
+ const label = 'shim file starts with #!/usr/bin/env node shebang';
191
+ try {
192
+ const src = fs.readFileSync(SHIM_PATH, 'utf8');
193
+ const firstLine = src.split('\n')[0];
194
+ assert.equal(firstLine, '#!/usr/bin/env node',
195
+ 'first line must be "#!/usr/bin/env node"; got "' + firstLine + '"');
196
+ ok(label);
197
+ } catch (err) { fail(label, err); }
198
+ })();
199
+
200
+ // ---------------------------------------------------------------------------
201
+ // Async finalize: wait for Test 3's spawn promise before printing summary.
202
+ // ---------------------------------------------------------------------------
203
+ let finalized = false;
204
+ function finalize() {
205
+ if (finalized) return;
206
+ finalized = true;
207
+ process.stdout.write('\n');
208
+ process.stdout.write('PASSED: ' + passed + '\n');
209
+ process.stdout.write('FAILED: ' + failed + '\n');
210
+ process.exit(failed === 0 ? 0 : 1);
211
+ }
212
+
213
+ // Safety net: in case Test 3's promise never resolves, finalize at 5s.
214
+ setTimeout(finalize, 5000).unref();
@@ -10,7 +10,7 @@
10
10
  *
11
11
  * Why this module is the hardest Canon Part 8 surface in v1.11.0:
12
12
  *
13
- * The Brain (brain.mindrian.ai) is a generic methodology repository
13
+ * The Brain (mindrian-brain.onrender.com) is a generic methodology repository
14
14
  * that MUST never receive user content. Every other 89.x callsite
15
15
  * builds Brain queries from STRUCTURED inputs (problem_type, framework
16
16
  * id, phase id) where the audit surface is a finite enum. This module
@@ -61,8 +61,11 @@ const PHONE_RE = /\b\d{3}[-.\s]?\d{3}[-.\s]?\d{4}\b/;
61
61
  // concatenated tokens so this very source file does not itself contain the
62
62
  // literal forbidden substring (preserving the Canon Part 8 zero-network grep
63
63
  // gate over the telemetry module while still detecting the host in payloads).
64
- const BRAIN_HOST_TOKENS = ['brain', 'mindrian', 'ai'];
65
- const BRAIN_URL_RE = new RegExp(BRAIN_HOST_TOKENS.join('\\.'), 'i');
64
+ // Two hosts are matched: the current production host (the Render web service)
65
+ // and the not-yet-wired future custom domain. Both must be rejected.
66
+ const BRAIN_HOST_RENDER = ['mindrian', 'brain'].join('-') + ['', 'onrender', 'com'].join('\\.');
67
+ const BRAIN_HOST_DOMAIN = ['brain', 'mindrian', 'ai'].join('\\.');
68
+ const BRAIN_URL_RE = new RegExp(BRAIN_HOST_RENDER + '|' + BRAIN_HOST_DOMAIN, 'i');
66
69
 
67
70
  // (e) Absolute path with >= 2 path separators after the initial / or ~.
68
71
  // Matches "/home/jsagi/foo/bar.md" but not "/" alone or "/foo".
@@ -9,7 +9,7 @@
9
9
  * Verifies validator.cjs is the Canon Part 8 constitutional gate that
10
10
  * rejects events containing Brain query bodies, room artifact strings,
11
11
  * personal identifiers (emails, phone numbers, raw hex), absolute filesystem
12
- * paths, brain.mindrian.ai references, and free-text prose. Mirrors the
12
+ * paths, mindrian-brain.onrender.com references, and free-text prose. Mirrors the
13
13
  * Phase 110-05 seed-pattern adversarial fixture approach.
14
14
  *
15
15
  * Test map (7 cases, one-to-one with the PLAN <behavior> block for Task 1):
@@ -23,7 +23,7 @@
23
23
  * (d) Raw hex >32 chars in non-sha256 field
24
24
  * (e) Absolute path "/home/jsagi/MindrianRooms/foo/bar/baz.md"
25
25
  * (f) Phone "555-123-4567"
26
- * (g) Brain URL "https://brain.mindrian.ai/v1/query"
26
+ * (g) Brain URL "https://mindrian-brain.onrender.com/v1/query"
27
27
  *
28
28
  * Registered in lib/memory/run-feynman-tests.cjs.
29
29
  */
@@ -163,13 +163,13 @@ assert.equal(typeof validator.validateEventPayload, 'function',
163
163
  (function test6gBrainURL() {
164
164
  const result = validator.validateEventPayload('selector_pick', {
165
165
  sub_shape: 'F.1',
166
- verb_chosen: 'https://brain.mindrian.ai/v1',
166
+ verb_chosen: 'https://mindrian-brain.onrender.com/v1',
167
167
  });
168
168
  assert.equal(result.ok, false,
169
- 'brain.mindrian.ai URL must be rejected; got: ' + JSON.stringify(result));
169
+ 'mindrian-brain.onrender.com URL must be rejected; got: ' + JSON.stringify(result));
170
170
  assert.match(result.error, /forbidden_pattern.*(brain|url)/i,
171
171
  'error must mention forbidden_pattern + brain/url, got: ' + result.error);
172
- console.log('PASS test 6g: brain.mindrian.ai URL rejected');
172
+ console.log('PASS test 6g: mindrian-brain.onrender.com URL rejected');
173
173
  })();
174
174
 
175
175
  // ---------- Sanity: sha256 hash field (room_slug_sha256) NOT flagged as raw hex ----------
@@ -0,0 +1,109 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Phase 127-02 BRAIN-MCP-127-09 -- Tier-0 graceful messaging chokepoint.
5
+ *
6
+ * Single source-of-truth for the DIRECTOR_NOT_AVAILABLE sentinel shape used
7
+ * across the plugin:
8
+ * - bin/mindrian-brain-mcp-client.cjs (the stdio shim from Phase 127-00)
9
+ * - Larry's prose surface (one-line hint via larryTier0Hint)
10
+ * - Future statusline + /mos:status surfaces (CONTEXT acceptance gate #4)
11
+ *
12
+ * Before this chokepoint, the shim shipped its own inline copy of the
13
+ * sentinel shape. Future surfaces (statusline, /mos:status, persona output)
14
+ * would each duplicate the same shape, drifting on the upgrade_hint URL or
15
+ * the fallback_advice phrasing. This module locks the wire shape and the
16
+ * Larry-prose phrasing so every consumer reads the same canonical bytes.
17
+ *
18
+ * Wire shape locked here (BRAIN-MCP-127-09 invariant):
19
+ * {
20
+ * status: "DIRECTOR_NOT_AVAILABLE",
21
+ * reason: "MINDRIAN_BRAIN_KEY not set",
22
+ * command_context: <toolName string | "unknown" for non-string input>,
23
+ * upgrade_hint: "Request a Brain key at https://mindrianos.vercel.app/brain-access",
24
+ * fallback_advice: "Larry can still talk with you and reflect on your room context. Methodology orchestration requires Brain."
25
+ * }
26
+ *
27
+ * Canon Part 7 (reuse): isAvailable() is a one-line delegation to
28
+ * brain-client.cjs's existing isAvailable(); no parallel key-resolver code
29
+ * path lives here. The shim's local tier0Response becomes a one-line
30
+ * passthrough after the Phase 127-02 refactor; no duplicate shape exists.
31
+ *
32
+ * Canon Part 8 (graph boundary): zero network surface in this file.
33
+ * isAvailable() delegates to brain-client.cjs (the existing chokepoint that
34
+ * reads ONLY the LOCAL key via resolve-brain-key.cjs). No fetch, no http,
35
+ * no Brain endpoint domain strings.
36
+ *
37
+ * HARD RULE: no em-dashes anywhere in this file (hyphens only).
38
+ */
39
+
40
+ const brainClient = require('./brain-client.cjs');
41
+
42
+ // Locked wire string. Renaming this constant breaks every downstream consumer
43
+ // (the shim, Larry's prose surface, the doctor's Class-M smoke L5 check).
44
+ // Treat as a phase-amendment boundary.
45
+ const DIRECTOR_NOT_AVAILABLE = 'DIRECTOR_NOT_AVAILABLE';
46
+
47
+ // Locked sentinel strings. Tests assert the keys; the values are
48
+ // human-facing and may evolve, but only via explicit phase amendment.
49
+ const REASON_NO_KEY = 'MINDRIAN_BRAIN_KEY not set';
50
+ const UPGRADE_HINT = 'Request a Brain key at https://mindrianos.vercel.app/brain-access';
51
+ const FALLBACK_ADVICE = 'Larry can still talk with you and reflect on your room context. Methodology orchestration requires Brain.';
52
+
53
+ /**
54
+ * Construct the Tier-0 sentinel response. Returned by every Brain-tool entry
55
+ * point when no key is resolvable. The shape is byte-locked.
56
+ *
57
+ * Defensive: non-string / empty / non-truthy commandContext arguments coerce
58
+ * to "unknown" so the wire shape is invariant under bad-caller inputs (the
59
+ * shim's tool-handler closure passes the literal tool name; future callers
60
+ * may pass null in error paths).
61
+ *
62
+ * @param {string} commandContext the tool name (e.g. "brain_ask"); falls back
63
+ * to "unknown" for non-string / empty inputs.
64
+ * @returns {{status: string, reason: string, command_context: string,
65
+ * upgrade_hint: string, fallback_advice: string}}
66
+ */
67
+ function tier0Response(commandContext) {
68
+ const ctx = (typeof commandContext === 'string' && commandContext.length > 0)
69
+ ? commandContext
70
+ : 'unknown';
71
+ return {
72
+ status: DIRECTOR_NOT_AVAILABLE,
73
+ reason: REASON_NO_KEY,
74
+ command_context: ctx,
75
+ upgrade_hint: UPGRADE_HINT,
76
+ fallback_advice: FALLBACK_ADVICE,
77
+ };
78
+ }
79
+
80
+ /**
81
+ * Is the Brain reachable from this process right now? Delegates to
82
+ * brain-client.cjs's existing chokepoint (which reads only the LOCAL key via
83
+ * resolve-brain-key.cjs). One-line passthrough -- never duplicate the key
84
+ * resolution logic.
85
+ *
86
+ * @returns {boolean}
87
+ */
88
+ function isAvailable() {
89
+ return brainClient.isAvailable();
90
+ }
91
+
92
+ /**
93
+ * One-line Larry-prose hint for the Tier-0 path. Used by Larry's surface
94
+ * (and future statusline / /mos:status) when isAvailable() returns false to
95
+ * tell the user how to unlock Brain. Locked under 120 chars so it fits in
96
+ * statusline + chat-prefix surfaces without truncation.
97
+ *
98
+ * @returns {string}
99
+ */
100
+ function larryTier0Hint() {
101
+ return 'Methodology orchestration needs a Brain key. Drop one in ~/.mindrian.env or set MINDRIAN_BRAIN_KEY.';
102
+ }
103
+
104
+ module.exports = {
105
+ DIRECTOR_NOT_AVAILABLE,
106
+ tier0Response,
107
+ isAvailable,
108
+ larryTier0Hint,
109
+ };
@@ -0,0 +1,218 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ /*
5
+ * Phase 127-02 Task 1 (TDD RED -> GREEN) -- tier0-messaging chokepoint tests.
6
+ *
7
+ * Covers BRAIN-MCP-127-09 acceptance:
8
+ * Test 1: DIRECTOR_NOT_AVAILABLE constant locks the wire string.
9
+ * Test 2: tier0Response("brain_ask") shape (status / reason / command_context
10
+ * / upgrade_hint regex / fallback_advice regex).
11
+ * Test 3: tier0Response(null) coerces command_context to "unknown".
12
+ * Test 4: isAvailable() returns false when MINDRIAN_BRAIN_KEY is unset.
13
+ * Test 5: isAvailable() returns true when MINDRIAN_BRAIN_KEY is set in env.
14
+ * Test 6: larryTier0Hint() returns a one-line string under 120 chars,
15
+ * contains "Brain" and "key", zero em-dashes.
16
+ * Test 7: Shim's tier0Response(name) is byte-identical to chokepoint's
17
+ * tier0Response(name) -- delegation property (no duplicate shape).
18
+ * Test 8: Plan 127-00's mindrian-brain-shim.test.cjs file still passes after
19
+ * the refactor (non-breaking chokepoint introduction).
20
+ *
21
+ * Canon parts:
22
+ * - Part 7 (reuse): the shim's local tier0Response is a one-line passthrough.
23
+ * - Part 8 (graph boundary): no network IO in this chokepoint; isAvailable
24
+ * delegates to brain-client.cjs (which is the existing chokepoint).
25
+ *
26
+ * HARD RULE: no em-dashes.
27
+ */
28
+
29
+ const assert = require('node:assert/strict');
30
+ const fs = require('node:fs');
31
+ const path = require('node:path');
32
+ const cp = require('node:child_process');
33
+
34
+ const REPO_ROOT = path.resolve(__dirname, '..', '..');
35
+ const CHOKEPOINT_PATH = path.join(REPO_ROOT, 'lib', 'core', 'tier0-messaging.cjs');
36
+ const SHIM_PATH = path.join(REPO_ROOT, 'bin', 'mindrian-brain-mcp-client.cjs');
37
+ const SHIM_TEST_PATH = path.join(REPO_ROOT, 'lib', 'core', 'mindrian-brain-shim.test.cjs');
38
+
39
+ let passed = 0;
40
+ let failed = 0;
41
+
42
+ function ok(name) {
43
+ passed += 1;
44
+ process.stdout.write(' ok ' + name + '\n');
45
+ }
46
+
47
+ function fail(name, err) {
48
+ failed += 1;
49
+ process.stdout.write(' FAIL ' + name + '\n');
50
+ if (err) process.stdout.write(' ' + (err.message || String(err)) + '\n');
51
+ }
52
+
53
+ // ---------------------------------------------------------------------------
54
+ // Test 1: DIRECTOR_NOT_AVAILABLE constant locks the wire string.
55
+ // ---------------------------------------------------------------------------
56
+ (function test1_director_constant() {
57
+ const label = 'DIRECTOR_NOT_AVAILABLE constant equals exact wire string';
58
+ try {
59
+ const mod = require(CHOKEPOINT_PATH);
60
+ assert.equal(mod.DIRECTOR_NOT_AVAILABLE, 'DIRECTOR_NOT_AVAILABLE',
61
+ 'exported DIRECTOR_NOT_AVAILABLE must equal the literal wire string "DIRECTOR_NOT_AVAILABLE"');
62
+ ok(label);
63
+ } catch (e) { fail(label, e); }
64
+ })();
65
+
66
+ // ---------------------------------------------------------------------------
67
+ // Test 2: tier0Response("brain_ask") shape.
68
+ // ---------------------------------------------------------------------------
69
+ (function test2_response_shape() {
70
+ const label = 'tier0Response("brain_ask") returns canonical sentinel shape';
71
+ try {
72
+ delete require.cache[CHOKEPOINT_PATH];
73
+ const mod = require(CHOKEPOINT_PATH);
74
+ const r = mod.tier0Response('brain_ask');
75
+ assert.equal(r.status, 'DIRECTOR_NOT_AVAILABLE', 'status must be DIRECTOR_NOT_AVAILABLE');
76
+ assert.equal(r.reason, 'MINDRIAN_BRAIN_KEY not set', 'reason must be exact string');
77
+ assert.equal(r.command_context, 'brain_ask', 'command_context must echo input');
78
+ assert.match(r.upgrade_hint, /brain-access/, 'upgrade_hint must reference brain-access URL');
79
+ assert.match(r.fallback_advice, /Larry/, 'fallback_advice must mention Larry');
80
+ ok(label);
81
+ } catch (e) { fail(label, e); }
82
+ })();
83
+
84
+ // ---------------------------------------------------------------------------
85
+ // Test 3: tier0Response(null) coerces to "unknown".
86
+ // ---------------------------------------------------------------------------
87
+ (function test3_null_defensive() {
88
+ const label = 'tier0Response(null) coerces command_context to "unknown"';
89
+ try {
90
+ delete require.cache[CHOKEPOINT_PATH];
91
+ const mod = require(CHOKEPOINT_PATH);
92
+ const r1 = mod.tier0Response(null);
93
+ const r2 = mod.tier0Response(undefined);
94
+ const r3 = mod.tier0Response('');
95
+ const r4 = mod.tier0Response(123);
96
+ assert.equal(r1.command_context, 'unknown', 'null -> unknown');
97
+ assert.equal(r2.command_context, 'unknown', 'undefined -> unknown');
98
+ assert.equal(r3.command_context, 'unknown', 'empty string -> unknown');
99
+ assert.equal(r4.command_context, 'unknown', 'non-string -> unknown');
100
+ ok(label);
101
+ } catch (e) { fail(label, e); }
102
+ })();
103
+
104
+ // ---------------------------------------------------------------------------
105
+ // Test 4: isAvailable() returns false when MINDRIAN_BRAIN_KEY is unset.
106
+ // ---------------------------------------------------------------------------
107
+ (function test4_isAvailable_false() {
108
+ const label = 'isAvailable() returns false when MINDRIAN_BRAIN_KEY is unset and no env-file';
109
+ try {
110
+ // Use a subprocess with hermetic HOME and unset MINDRIAN_BRAIN_KEY so we
111
+ // do not pollute this process's brain-client memoized cache.
112
+ const tmpHome = fs.mkdtempSync(path.join(require('node:os').tmpdir(), 'tier0-msg-test-'));
113
+ const script = 'process.env.HOME=' + JSON.stringify(tmpHome) + ';'
114
+ + 'delete process.env.MINDRIAN_BRAIN_KEY;'
115
+ + 'const m = require(' + JSON.stringify(CHOKEPOINT_PATH) + ');'
116
+ + 'process.stdout.write(JSON.stringify({ available: m.isAvailable() }));';
117
+ const out = cp.execFileSync(process.execPath, ['-e', script], {
118
+ encoding: 'utf8',
119
+ env: Object.assign({}, process.env, { HOME: tmpHome, MINDRIAN_BRAIN_KEY: '' }),
120
+ });
121
+ const parsed = JSON.parse(out);
122
+ assert.equal(parsed.available, false, 'isAvailable must be false with no key');
123
+ fs.rmSync(tmpHome, { recursive: true, force: true });
124
+ ok(label);
125
+ } catch (e) { fail(label, e); }
126
+ })();
127
+
128
+ // ---------------------------------------------------------------------------
129
+ // Test 5: isAvailable() returns true when MINDRIAN_BRAIN_KEY is set.
130
+ // ---------------------------------------------------------------------------
131
+ (function test5_isAvailable_true() {
132
+ const label = 'isAvailable() returns true when MINDRIAN_BRAIN_KEY is set in env';
133
+ try {
134
+ const tmpHome = fs.mkdtempSync(path.join(require('node:os').tmpdir(), 'tier0-msg-test-'));
135
+ const script = 'const m = require(' + JSON.stringify(CHOKEPOINT_PATH) + ');'
136
+ + 'process.stdout.write(JSON.stringify({ available: m.isAvailable() }));';
137
+ const out = cp.execFileSync(process.execPath, ['-e', script], {
138
+ encoding: 'utf8',
139
+ env: Object.assign({}, process.env, { HOME: tmpHome, MINDRIAN_BRAIN_KEY: 'test-key-fixture-127-02' }),
140
+ });
141
+ const parsed = JSON.parse(out);
142
+ assert.equal(parsed.available, true, 'isAvailable must be true with key set');
143
+ fs.rmSync(tmpHome, { recursive: true, force: true });
144
+ ok(label);
145
+ } catch (e) { fail(label, e); }
146
+ })();
147
+
148
+ // ---------------------------------------------------------------------------
149
+ // Test 6: larryTier0Hint() shape.
150
+ // ---------------------------------------------------------------------------
151
+ (function test6_larry_hint() {
152
+ const label = 'larryTier0Hint() one-line string, <120 chars, contains "Brain" + "key", zero em-dashes';
153
+ try {
154
+ delete require.cache[CHOKEPOINT_PATH];
155
+ const mod = require(CHOKEPOINT_PATH);
156
+ const hint = mod.larryTier0Hint();
157
+ assert.equal(typeof hint, 'string', 'must return a string');
158
+ assert.ok(hint.length <= 120, 'must be <= 120 chars (got ' + hint.length + ')');
159
+ assert.ok(!/\n/.test(hint), 'must be a single line (no newlines)');
160
+ assert.match(hint, /Brain/, 'must contain "Brain"');
161
+ assert.match(hint, /key/, 'must contain "key"');
162
+ assert.ok(!/[\u2014\u2013]/.test(hint), 'must contain zero em-dashes (U+2014) or en-dashes (U+2013)');
163
+ ok(label);
164
+ } catch (e) { fail(label, e); }
165
+ })();
166
+
167
+ // ---------------------------------------------------------------------------
168
+ // Test 7: Shim's tier0Response is byte-identical to chokepoint's tier0Response
169
+ // (delegation property -- the shim's local function is a one-line
170
+ // passthrough to the chokepoint).
171
+ // ---------------------------------------------------------------------------
172
+ (function test7_delegation_property() {
173
+ const label = 'shim tier0Response delegates to chokepoint (byte-identical output for all 6 tool names)';
174
+ try {
175
+ delete require.cache[CHOKEPOINT_PATH];
176
+ const chokepoint = require(CHOKEPOINT_PATH);
177
+ // Read the shim source and verify it requires the chokepoint module.
178
+ const src = fs.readFileSync(SHIM_PATH, 'utf8');
179
+ assert.match(src, /require\(['"][^'"]*tier0-messaging\.cjs['"]\)/,
180
+ 'shim source must require lib/core/tier0-messaging.cjs');
181
+ // Verify the chokepoint's response matches the wire shape for each tool.
182
+ const toolNames = ['brain_ask', 'brain_query', 'brain_schema', 'brain_search', 'brain_stats', 'brain_write'];
183
+ for (const name of toolNames) {
184
+ const r = chokepoint.tier0Response(name);
185
+ assert.equal(r.status, 'DIRECTOR_NOT_AVAILABLE', 'chokepoint status for ' + name);
186
+ assert.equal(r.command_context, name, 'chokepoint command_context for ' + name);
187
+ assert.equal(r.reason, 'MINDRIAN_BRAIN_KEY not set', 'chokepoint reason for ' + name);
188
+ }
189
+ ok(label);
190
+ } catch (e) { fail(label, e); }
191
+ })();
192
+
193
+ // ---------------------------------------------------------------------------
194
+ // Test 8: Plan 127-00's mindrian-brain-shim.test.cjs still passes after
195
+ // the refactor (non-breaking chokepoint introduction).
196
+ // ---------------------------------------------------------------------------
197
+ (function test8_shim_tests_preserved() {
198
+ const label = 'plan 127-00 shim test file still PASSES after refactor';
199
+ try {
200
+ const result = cp.spawnSync(process.execPath, [SHIM_TEST_PATH], {
201
+ encoding: 'utf8',
202
+ timeout: 15000,
203
+ });
204
+ if (result.status !== 0) {
205
+ throw new Error('shim test exited ' + result.status + '\nstdout:\n' + result.stdout + '\nstderr:\n' + result.stderr);
206
+ }
207
+ // Confirm all 6 tests passed.
208
+ assert.match(result.stdout, /PASSED:\s*6/, 'expected 6 shim tests to pass; got:\n' + result.stdout);
209
+ assert.match(result.stdout, /FAILED:\s*0/, 'expected 0 shim test failures; got:\n' + result.stdout);
210
+ ok(label);
211
+ } catch (e) { fail(label, e); }
212
+ })();
213
+
214
+ // ---------------------------------------------------------------------------
215
+ // Summary
216
+ // ---------------------------------------------------------------------------
217
+ process.stdout.write('\nPASSED: ' + passed + '\nFAILED: ' + failed + '\n');
218
+ process.exit(failed === 0 ? 0 : 1);
@@ -620,8 +620,8 @@ async function main() {
620
620
  // category); no BRAIN.md; no tmpfile.
621
621
  await runScenario('Scenario 07: Network partition', async function () {
622
622
  installMockBrainClient({
623
- query: function () { throw new Error('ECONNREFUSED brain.mindrian.ai:443'); },
624
- search: function () { throw new Error('ECONNREFUSED brain.mindrian.ai:443'); },
623
+ query: function () { throw new Error('ECONNREFUSED mindrian-brain.onrender.com:443'); },
624
+ search: function () { throw new Error('ECONNREFUSED mindrian-brain.onrender.com:443'); },
625
625
  });
626
626
  const { sections } = buildRoom({ tag: 's07', count: 1 });
627
627
  const s = sections[0];
@@ -37,7 +37,7 @@
37
37
  * 6. --stale-only flag: renders only stale sections + summary.
38
38
  * 7. <section> argument: renders that section's full triple (not truncated).
39
39
  * 8. Missing room: prints "no active room; /mos:rooms to list" + exit 0.
40
- * 9. Zero external network: no fetch/http/brain.mindrian.ai strings in the
40
+ * 9. Zero external network: no fetch/http/mindrian-brain.onrender.com strings in the
41
41
  * renderer source.
42
42
  * 10. Shape E zones present: header + rows + summary + actions.
43
43
  * 11. Warm-cache path: if statusline-cache has fresh data for the section,
@@ -468,7 +468,7 @@ assert.equal(
468
468
  const src = fs.readFileSync(RENDERER, 'utf8');
469
469
  // Canon Part 8: the renderer must be strictly LOCAL.
470
470
  const forbidden = [
471
- 'brain.mindrian.ai',
471
+ 'mindrian-brain.onrender.com',
472
472
  'http://',
473
473
  'https://',
474
474
  'require(\'node:http\')',
@@ -639,7 +639,7 @@ if (engineLoadable()) {
639
639
  run('Test 29: FORBIDDEN Brain network calls (grep)', () => {
640
640
  const src = fs.readFileSync(ENGINE_PATH, 'utf8');
641
641
  // Forbidden: brain-client.query / search / smartSearch and any direct
642
- // network egress to brain.mindrian.ai or fetch/curl for Brain.
642
+ // network egress to mindrian-brain.onrender.com or fetch/curl for Brain.
643
643
  const reBad = /brain[-_]?client\s*\.\s*(query|search|smartSearch)\b|brain\.mindrian\.ai|\bfetch\s*\(|\bcurl\b/;
644
644
  // Allow brain-client.isAvailable and brain-client.schema (Section 9.3).
645
645
  // Strip those allowed calls before scanning.
@@ -1586,6 +1586,16 @@ const TEST_FILES = [
1586
1586
  path.join(REPO_ROOT, 'tests', 'test-121-03-room-receipt-emit.cjs'),
1587
1587
  path.join(REPO_ROOT, 'tests', 'test-121-03-command-invocation-hook.cjs'),
1588
1588
  path.join(REPO_ROOT, 'tests', 'test-121-03-drowning-protection.cjs'),
1589
+ // Phase 127.1 brain-graphrag-collapse-pinecone-neo4j-hnsw (Wave 0 harness scaffold + Wave 1/2/3 outputs)
1590
+ // Surface 1 -> Plan 127.1-01 produces embedding-manifest.fixture.json (12,401 byte-identical SHA256 pairs).
1591
+ // Surface 2 -> Plan 127.1-02 produces index-config.fixture.json (SHOW INDEXES dim=1024 cosine ONLINE).
1592
+ // query-embedder -> Plan 127.1-03 produces mcp-server-brain/lib/query-embedder.cjs (server-side e5-large query embedding; hermetic, mocked transport).
1593
+ // Surface 3 -> Plan 127.1-04 produces overlap-baseline + overlap-neo4j fixtures (BLOCKING gate >= 0.80).
1594
+ // Aggregator: tests/run-all-127.sh. RED-by-design until consumer plans land the fixtures.
1595
+ path.join(REPO_ROOT, 'tests', '127.1-embedding-integrity.test.cjs'),
1596
+ path.join(REPO_ROOT, 'tests', '127.1-index-config.test.cjs'),
1597
+ path.join(REPO_ROOT, 'tests', '127.1-query-embedder.test.cjs'),
1598
+ path.join(REPO_ROOT, 'tests', '127.1-graphrag-overlap.test.cjs'),
1589
1599
  ];
1590
1600
 
1591
1601
  // Exit code convention for child tests: