Skip to content

fix: fail closed when Grok CommHub MCP is unavailable - #822

Closed
vansin wants to merge 8 commits into
mainfrom
fix/813-grok-mcp-readiness-v2
Closed

fix: fail closed when Grok CommHub MCP is unavailable#822
vansin wants to merge 8 commits into
mainfrom
fix/813-grok-mcp-readiness-v2

Conversation

@vansin

@vansin vansin commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Closes #813.

Frozen coordinates

  • source: 91cf020609e519a1d580dcb7b5ee22026a5a182d
  • report-only: e0110e48a09e4af21d124ca9a8c33871b5660026
  • readiness image: sha256:981f63ab162a9a3db605ae02188ba3fdb4dc40795c83cd9226263cfdf9d67465
  • unit image: sha256:392c91572bce988835b6d7130632c8b39e5edb9ea2e59561bc02fd586c22180f

Change

  • Resolve and persist a canonical executable Bun path for Grok's runtime-owned CommHub MCP.
  • Run the real grok mcp doctor commhub --json preflight before every initial/recovery TUI spawn and require command/server/handshake/four-tool readiness.
  • Fail before Hub registration when Bun/MCP readiness is unavailable; do not silently start a TUI with an empty outbound tool surface.
  • Keep the Grok session unchanged on failed startup and preserve the same persisted session on recovery.

Exact-source evidence

The Docker readiness gate emitted:

  • PRODUCT_PATH_NEGATIVE_PASS registration=absent session=unchanged
  • PRODUCT_PATH_RECOVERY_PASS session=preserved
  • MUTATION_RED upload-tool-removed
  • MUTATION_RED stale-three-tool-doctor
  • MUTATION_RED bun-resolver-bypassed
  • RESULT: PASS source_commit=91cf020609e519a1d580dcb7b5ee22026a5a182d

The complete exact-source agent-node unit domain emitted:

  • 1283 pass / 0 fail / 4373 expect() / 91 files
  • built-in aggregate mutation red

Full report: docs/tests/report-test813-grok-mcp-readiness.txt.

Boundaries

  • Draft only: no package publish, merge, rollout, node restart, config or DB change is authorized by this PR.
  • The live 通信狗 remains on its current reviewed runtime and was not touched.
  • PR feat(grok): add strict repo-read co-presence profile #820 overlaps the Grok startup files and is not based on this source; it must be restacked after this readiness gate is reviewed/frozen.
  • Three other bare-Bun writers are tracked separately by [mcp-runtime] generated bare Bun commands fail under slim PATH #821. Current 12/12 sampled node processes inherit a PATH that resolves Bun, so that follow-up is latent-risk work rather than a blocker for this Grok-specific fix.

@vansin

vansin commented Aug 13, 2026

Copy link
Copy Markdown
Contributor Author

Live Grok TUI co-presence advisory (通信狗)

The pilot node 通信狗 completed a prompt-contained adversarial review through the same live Grok TUI + CommHub path (task 30a03669-81fe-4e83-9ba2-6626cc6cd111, replied 2026-08-13 04:56:39 UTC).

Its useful challenge is narrower than the existing Bun-path mutation:

  • the negative lane supports fail-closed behavior when the MCP command cannot resolve/execute;
  • the positive lane supports TUI readiness and session preservation with a valid BUN_BIN;
  • the highest-value independent mutation is to make doctor/readiness report healthy while returning zero/fewer CommHub tools (or bypass the doctor result), and require the product-path positive lane to fail before TUI readiness.

This is advisory evidence, not independent approval and not a substitute for the frozen-source review. No source/report coordinate changed.

@vansin

vansin commented Aug 13, 2026

Copy link
Copy Markdown
Contributor Author

Direct TUI outbound CommHub UAT — PASS

From the live tmux 通信狗, an operator entered a request directly into window 1:tui asking Grok to call commhub_send_message to 通信龙. The TUI discovered the CommHub tool, invoked it, returned Hub message id 948b5add-0f49-41e2-9e4b-3721866b2ec5, and returned to the interactive prompt in 6.3 seconds.

This did not use the agent-node task reply bridge as a substitute. It directly closes the observed user-facing state where inbound tasks worked but the TUI could not find CommHub tools. It is live-runtime UAT, not exact-source provenance for this PR and not independent approval.

Durable recovery record: PR #808, commit 7c7e9587.

@vansin

vansin commented Aug 13, 2026

Copy link
Copy Markdown
Contributor Author

GitHub CI completion

All checks on report head e0110e48a09e4af21d124ca9a8c33871b5660026 completed successfully:

  • agent-network unit (Docker, non-root): PASS
  • agent-node unit (Docker, non-root): PASS
  • L0 + L1 (report-only): PASS
  • E2E: PASS (both workflow invocations)
  • rename-ghost-gate: PASS (both workflow invocations)
  • no bare rm / no hardcoded from_session / no internal feedback slug: PASS

This closes the hosted-CI gate only. Independent source review remains pending; the PR stays Draft and unmerged.

@vansin

vansin commented Aug 13, 2026

Copy link
Copy Markdown
Contributor Author

DO-NOT-MERGE — product-path readiness assertion is source-literal vulnerable

A new exact-image reverse experiment changed only the fake Grok doctor check from 4 tools discovered to 3 tools discovered while keeping the report otherwise healthy, then ran the real built dist/cli product recovery path.

Observed:

  • runtime correctly threw before spawn: grok copresence pre-spawn audit failed: ... readiness failed: 4 tools discovered;
  • nevertheless the test did not fail at its first grep -Fq "[grok-copresence] TUI ready session=" assertion;
  • the failed minified dist/cli.js stack trace printed the entire source line, which itself contains the TUI ready session= literal;
  • the test only turned red at the later grok 0.2.93 assertion.

The decisive probe reported MUTATION_REACHED_TUI_READY and showed that the only match was inside file:///workspace/agent-node/dist/cli.js:..., not a timestamped runtime log line.

Therefore the current product gate can mistake a source literal in a stack trace for runtime readiness. The production implementation still failed closed in this experiment, but the evidence claim is too strong and the existing product assertion is not trustworthy. Frozen source 91cf0206 / report e0110e48 are superseded for merge purposes. I will create a new append-only source from 91cf0206 with anchored runtime-log assertions and a named product-path doctor mutation, rerun exact Docker evidence, and request fresh independent review. No production/node change.

@vansin

vansin commented Aug 13, 2026

Copy link
Copy Markdown
Contributor Author

独立窄审 · PR #822 (Draft) — test813 Grok MCP readiness gate

Verdict: CLEAN — no BLOCKER, no MAJOR, no MINOR. Two informational notes at ⑦.

Reviewer: 通信IM马 (independent, read-only). Extracted PR tree via git archive origin/pr-822 → temp dir; author worktree untouched. No merge, no deploy. Image not rebuilt on my host.

Scope framing: this PR adds a hard CommHub MCP readiness gate (Bun-resolver + doctor tool-count assertion) that fires before the Grok TUI can be considered ready — closing an inbound-only false-healthy failure mode. Product source touched: agent-node/src/cli.ts + new agent-node/src/runtime/grok-build-cli-home.ts symbols. Everything else is test infrastructure or docs.


Provenance

value check
HEAD (report-only) e0110e48a09e4af21d124ca9a8c33871b5660026 ✓ matches brief
source (last code+test commit) 91cf020609e519a1d580dcb7b5ee22026a5a182d ✓ matches brief
source tree 1add9f9d1096bc0c8dca9b6c09c5e5596c16b528 ✓ matches brief
base (merge-base) 034f00647d42d38d5086d7fc057eb7824a441791 ✓ matches brief
current main tip 034f0064... == base — no drift possible
files (base..HEAD) 11 matches diff
source→HEAD delta exactly docs/tests/report-test813-grok-mcp-readiness.txt ✓ report-only

Per-file drift base..main: 0 for every one of the 11 files. git merge-tree base main pr-822 = 0 conflict markers. Rebase-trivial.


Item-by-item

① Product path: build 后 dist/cli, 初始 + recovery 都在 TUI spawn 前 resolver+doctor — CONFIRMED

Resolver call site (cli.ts:3628, inside ensureGrokCopresenceRuntime):

const commhubMcpCommand = resolveGrokCommhubMcpCommand(
  process.env.BUN_BIN || "bun",
  process.env.PATH || "",
);

Runs at the top of the async closure, before any prepareRuntime() call. Resolved to an absolute canonical executable via realpathSync + X_OK check (grok-build-cli-home.ts:53-70).

Doctor call site (cli.ts:3737-3750, inside auditAndPrepareRuntime closure):

doctor = execFileSync(grokBinary, ["mcp", "doctor", "commhub", "--json"], {
  encoding: "utf-8",
  stdio: ["ignore", "pipe", "pipe"],
  timeout: 10_000,
  ...
  env: auditRuntime.env,
});
...
assertGrokCommhubMcpDoctor(doctor);

assertGrokCommhubMcpDoctor throws if any of healthy_count === 1, failing_count === 0, server.healthy === true, or the four required check labels ["command found", "server started", "handshake OK", "4 tools discovered"] (each passed=true) are missing.

Initial + recovery both covered:

  • auditAndPrepareRuntime is passed as beforeSpawn: () => auditAndPrepareRuntime().env (cli.ts:3814)
  • runtime.ts:982 spawnTui(resume) is the SINGLE spawn function
  • runtime.ts:984 const refreshedEnv = await this.opts.beforeSpawn?.({ resume }); — invoked before every pty.spawn
  • recoverFromExit at runtime.ts:1076-1153 uses the same spawn path, so recovery also goes through beforeSpawn
  • cli.ts:3697 comment (author's own words): "Reuse this exact gate before the initial PTY and every recovery spawn."

Product path is built (bun run build produces agent-node/dist/cli.js — verified used by product-path.sh:38) and invoked via real /usr/local/bin/node /workspace/agent-node/dist/cli.js — so the gate is on the same code path production ships.

② Bun resolver bypass + tool-list + doctor mutations 非 vacuous, 红在命名理由 — CONFIRMED

All three mutations pass through a probe() bun-runner + expect_red helper that:

  • Snapshots the original file bytes before mutating
  • Reverts after evaluation regardless of pass/fail
  • Asserts mutation dies with the specific named string

Mutation 1: upload-tool-removed (run.sh:43-44)

  • sed -i '/^[[:space:]]*"commhub_upload_file",[[:space:]]*$/d' agent-network/src/node-server.ts — removes the tool literal
  • Expected red: TOOL_SET_MISMATCH
  • Independent verification: probe.ts:72-79 compares actual tools list (via real MCP tools/list) against ["commhub_get_all_status","commhub_send_message","commhub_send_task","commhub_upload_file"] and throws exactly TOOL_SET_MISMATCH expected=... actual=... — string match load-bearing ✓

Mutation 2: stale-three-tool-doctor (run.sh:46-47)

  • sed -i 's/"4 tools discovered"/"3 tools discovered"/' agent-node/src/runtime/grok-build-cli-home.ts — mutates the required-check literal in production source
  • Expected red: readiness failed: 3 tools discovered
  • Independent verification: after mutation, requiredChecks[3] = "3 tools discovered". Real doctor produces label "4 tools discovered". assertGrokCommhubMcpDoctor searches for a check with label "3 tools discovered" (mutated required) that passed=true — none exists → missing = ["3 tools discovered"] → throws readiness failed: 3 tools discovered
  • The probe first runs the healthy path (asserts pass), THEN a stale path (asserts throw contains "4 tools discovered"). Under mutation, healthy path throws first with the "3 tools discovered" text.

Mutation 3: bun-resolver-bypassed (run.sh:53-73)

  • Target cardinality check: [ "$(grep -Fc "$target" agent-node/src/cli.ts)" -eq 1 ] — hard fail if not exactly one occurrence of process.env.BUN_BIN || "bun",
  • sed -i 's/process\.env\.BUN_BIN || "bun",/"\/usr\/local\/bin\/bun",/' agent-node/src/cli.ts — hardcodes the path, bypassing env-driven resolver logic
  • Explicit byte-change guard: grep -Fq '"/usr/local/bin/bun",' agent-node/src/cli.ts (asserts source was actually written)
  • Expected red: NEGATIVE_RUNTIME_GATE_NOT_REACHED
  • product-path.sh negative test runs with BUN_BIN=/definitely/missing/bun — unmutated code catches this (throws "grok copresence CommHub MCP command could not be resolved or executed") and the test grep-finds that string. Mutated code IGNORES the env var, resolves to real /usr/local/bin/bun → gate doesn't fire → grep misses → NEGATIVE_RUNTIME_GATE_NOT_REACHED emitted → run.sh captures it as named-red ✓

Baseline is proven green FIRST — run.sh runs probe (unmodified source) at line 41 before any mutation. The mutation helper always snapshots and restores. Byte-change/target-cardinality guards prevent no-op mutations from silently "passing".

Not fooled by fixture self-consistency: probe.ts spawns REAL production bun agent-network/src/node-server.ts and does actual MCP JSON-RPC handshake — the tool set is derived from the running server, not from a test fixture. The doctor JSON validation uses the SAME assertGrokCommhubMcpDoctor exported from production source — mutations to the production symbol propagate into the probe (which is what the mutation test wants).

③ Highest risk — fake doctor healthy=true but 0/3 tools, or bypass assert, does product chain red BEFORE TUI ready? — CONFIRMED red BEFORE TUI ready

Scenario reasoning:

  • Suppose doctor returns healthy: true, healthy_count: 1, failing_count: 0 but the "N tools discovered" label is "0 tools discovered" or "3 tools discovered" (below expected 4).
  • assertGrokCommhubMcpDoctor looks for a check with label === "4 tools discovered" AND passed === true. If the label doesn't match, no such check exists → missing = ["4 tools discovered"] → throws.
  • The check is done AFTER all the healthy_count / failing_count / server.healthy checks — but ANY of them failing also throws immediately.
  • The throw propagates out of auditAndPrepareRuntime, out of the beforeSpawn callback in runtime.ts:984, causing spawnTui to throw before nodePty.spawn.
  • Therefore the TUI is never spawned; product path reds at the exact pre-TUI-spawn boundary.

Independent verification (unit test at grok-build-cli-home.test.ts:83-99):

const missingTools = JSON.parse(healthy);
missingTools.servers[0].checks.pop();
expect(() => assertGrokCommhubMcpDoctor(JSON.stringify(missingTools)))
  .toThrow("4 tools discovered");

Direct assertion that popping the tool-count check throws with the exact named-red text.

Coupling strength (product path ↔ probe): The probe (probe.ts:5) imports assertGrokCommhubMcpDoctor DIRECTLY from ../../agent-node/src/runtime/grok-build-cli-home — the exact production symbol. There is no fixture shim, no re-implementation. A mutation to the production symbol's behavior propagates to both the probe and the product path. This is strong coupling (matches feedback_mutation_on_mocks_proves_selfconsistency_not_reality — real production symbol used, not mock).

④ fake Grok placeholder + Leader cleanup — 不掩盖真实恢复缺陷 — CONFIRMED (with note ⑦b)

Fake-grok placeholder invariants asserted (product-path.sh:113-123):

for name in .grok .claude .cursor .mcp.json .envrc; do
    placeholder="$work/$name"
    [ -f "$placeholder" ] && [ ! -L "$placeholder" ] \
      && [ ! -s "$placeholder" ] && [ "$(stat -c %a "$placeholder")" = 444 ]
    ...
done

Four hard invariants per placeholder: is regular file, not symlink, empty content, mode 0444. If native Grok's placeholder shape drifts (permission widened, symlink introduced, non-empty), this reds.

Fake-grok Leader cleanup: stop_fake_leaders at product-path.sh:57-77 explicitly walks /proc/*/cmdline, matches on $root/grok agent leader, SIGTERMs, polls up to 1s for exit, hard-fails if the fake Leader survives. Sockets removed via find $home/.anet-grok -type s ... -delete.

Not masking real defects:

  • Product source cleanup logic (cleanupGrokCliPostStopState, GROK_POST_STOP_CLEANUP_POLICY) has its own unit tests in agent-node/src/runtime/grok-build-cli-home.test.ts (imports cleanupGrokCliPostStopState + cleanupGrokCliStoppedTuiGeneration + GROK_POST_STOP_CLEANUP_POLICY explicitly — 1512-line test file).
  • product-path.sh manually cleans placeholders because the test terminates the product mid-flight at the (deliberately unreachable) Hub-registration boundary — the launcher's own stop-time cleanup path isn't reached. Author's comment (product-path.sh:110-112) is honest about this: "A real launcher stop removes them; this probe deliberately terminates at the unreachable Hub registration boundary, so verify their exact harmless tuple before performing that launcher-owned cleanup."
  • Recovery test verifies session preservation (sid1 == sid2 at product-path.sh:141) and TUI ready marker reached again on second run.

The fake-grok abstraction and manual cleanup are testing accommodations for terminating mid-flight, not defect-masks — the placeholder-shape and cleanup-policy invariants are guarded by BOTH the integration test (shape check) AND the unit tests (product policy shape + cleanup behavior).

⑤ exact provenance / secret sweep / merge-tree — CONFIRMED clean

  • Provenance: coordinates match brief exactly (base/source/source-tree/HEAD). source→HEAD is exactly the report file (docs/tests/report-test813-...txt), so the source-commit tree fully carries the code and test changes. No source-vs-report topology dependence.
  • git merge-tree base main pr-822 = 0 conflict markers.
  • Per-file drift base..main = 0 for every one of the 11 changed files.
  • Secret sweep across all 11 files with patterns ntok_/utok_/atok_/BEGIN PRIVATE KEY/AKIA/AIza/ghp_/gho_/xoxb-/sk-live:
    • agent-node/src/cli.ts: 9 hits — all in secret-scrubbing regex patterns and comments describing what secrets look like (production sanitizer code)
    • agent-node/src/runtime/grok-build-cli-home.test.ts: 7 hits — all fixture strings ntok_test, ntok_secret, ntok_private, utok_private (obvious _test/_secret/_private suffixes, no real credential material)
    • tests/test225-grok-preview-package-live/run.sh: 7 hits — all TEST225_NTOK_CANARY_4af821 / TEST225_UTOK_CANARY_a1dd60 (explicit test-canary markers used by the leak-scanner probe)
    • Other 8 files: 0 hits each
    • 0 real credential material in any file
  • Dockerfile hygiene (test813-grok-mcp-readiness/Dockerfile):
    • Base image digest-pinned: node:22-bookworm-slim@sha256:d649c27dae7ba0137b3cef5dd75baa422c08dc3d9e3fc0c23dfb172dc3cc6436
    • Bun 1.3.14 pinned via SHA256 951ee2aee855f08595aeec6225226a298d3fea83a3dcd6465c09cbccdf7e848f + fail-closed test "$(bun --version)" = "$BUN_VERSION" — the same canonical from PR fix(ci): pin Bun across the L1 contract suite #762
    • USER node non-root, --chown=node:node COPY-time ownership
    • install -d -o node -g node -m 0700 "/run/user/$(id -u node)" for XDG_RUNTIME_DIR
    • ARG SOURCE_COMMIT + ENV TEST813_SOURCE_COMMIT=$SOURCE_COMMIT for provenance; run.sh hard-requires ^[0-9a-f]{40}$ regex match

Informational (not blocking)

⑦a Test comment "all three tools" vs required "4 tools discovered"

grok-build-cli-home.test.ts:66it("requires a real CommHub MCP doctor handshake and all three tools", ...). The label mentions "three tools" but the actual required-check assertion is 4 tools discovered (production has 4 tools: commhub_get_all_status, commhub_send_message, commhub_send_task, commhub_upload_file). Cosmetic docstring drift, not a functional issue — probably legacy from when there were 3 tools before commhub_upload_file was added. Worth a one-word fix in a follow-up.

⑦b product-path.sh does not exercise product's own cleanupGrokCliPostStopState path

The integration test cleans placeholders manually because the product path terminates before the launcher's stop-time cleanup runs (see ④). The unit tests in grok-build-cli-home.test.ts cover cleanupGrokCliPostStopState and GROK_POST_STOP_CLEANUP_POLICY directly. A future addition would be end-to-end coverage that lets the product reach its own cleanup path, but that is a scope expansion (would need a real Hub or mock Hub reachable) — appropriately deferred from this PR.


Reviewer discipline (self)

Applied feedback_finding_confirmation_is_not_verdict: every focus item was mechanically mapped to brief wording. Nothing lands on BLOCKER/MAJOR/MINOR gate wording. Verdict: CLEAN.

Applied feedback_single_commit_topology_does_not_guarantee_report_source_commit: read the report's own source_commit line. Report header at L2 declares source_commit=91cf020609e519a1d580dcb7b5ee22026a5a182d which matches the brief's source SHA exactly. Report anchor is honest (source-tree ships the code, HEAD adds only the report).

Independent verifications performed on this host:

  1. git rev-parse origin/pr-822 = e0110e48...
  2. git merge-base origin/pr-822 origin/main = 034f0064...
  3. git rev-parse 91cf0206^{tree} = 1add9f9d...
  4. git diff --name-only source..HEAD = report txt only ✓
  5. Traced product path: cli.ts:3628 (resolveGrokCommhubMcpCommand) → cli.ts:3750 (assertGrokCommhubMcpDoctor) → cli.ts:3814 (beforeSpawn callback) → runtime.ts:984 (beforeSpawn invocation in spawnTui) → runtime.ts:1076-1153 (recoverFromExit uses same spawn path)
  6. Verified assertGrokCommhubMcpDoctor semantics via unit tests in grok-build-cli-home.test.ts (rejects missing tool check with named-red "4 tools discovered")
  7. Verified probe.ts imports the exact production symbol (../../agent-node/src/runtime/grok-build-cli-home), not a mock
  8. Read all three mutation blocks in run.sh — each has target cardinality guard, byte-change guard, and named-red assertion
  9. git log --oneline base..main -- <11 files> = 0 for each — no drift
  10. git merge-tree base main pr-822 | grep -cE '^<<<<<<< |^======= |^>>>>>>> ' = 0
  11. Secret sweep across 11 files: 0 real credentials (all matches are sanitizer regex / fixture strings / canary markers)
  12. Dockerfile: digest-pinned base + Bun SHA256 + fail-closed version + non-root

No approve, no merge, no deploy.

@vansin

vansin commented Aug 13, 2026

Copy link
Copy Markdown
Contributor Author

独立对抗审(通信龙)— 四个攻击点逐条结果

审的是冻结坐标 source=91cf0206 / report-only=e0110e48全程只读 exact source,没有跑镜像(冻结期,也不想再占这台机器的负载)。
以下内容此前只在 commhub 里说过 —— 证据不落在制品上就等于不存在,所以补成 durable 记录。

④ provenance —— 打不动

head~1 == source;source→report 只改 docs/tests/report-test813-grok-mcp-readiness.txt;
报告全文 source_commit 只有 1 个值,等于 source。
(这是我自己栽过两次的地方:一次 ref 传成 origin/main,一次在 git commit 之前取 SHA。这条上无可攻。)

① product-path 是不是 fixture 自洽 —— 打不动

product-path.sh(cd agent-node && bun run build),再用
/usr/local/bin/node /workspace/agent-node/dist/cli.js 拉起;node-server.js 也是从
agent-network/src/node-server.ts 真 build。跑的是构建出来的生产件,不是 fixture。

② resolver-bypass mutation 会不会空转 / 错因红 —— 打不动

三道防守都在:

  1. 变异前查基数:[ "$(grep -Fc "$target" agent-node/src/cli.ts)" -eq 1 ],否则
    FAIL: product-path mutation target cardinality changed —— 堵死 sed 空转;
  2. 变异后验字节:grep -Fq '"/usr/local/bin/bun",';
  3. 错因红防守:要求红落在 NEGATIVE_RUNTIME_GATE_NOT_REACHED

我按「宽容断言」追第 3 条:该标记只在 product-path.sh:79 一处产生,且只在
grep -Fq 'grok copresence CommHub MCP command could not be resolved or executed' || { … }
失败分支里 —— 不是通过时也会命中的那种。

顺带:negative 场景还断言未出现「已注册到 CommHub」持久化 config 的 sha256 不变。是行为级断言。

③ Leader/socket cleanup 是否遮住真实恢复缺陷 —— 有一条 NOT COVERED,但范围比我最初说的窄得多

结论(第四版,最终):attach.tsunlinkOwnedSocket() 的两个调用点
(:179start() 失败的 catch 里、:243 在停止路径)都不在 listen() 之前,
所以残留的 attach socket 会让首次 listen 失败(→ catch → unlink → rethrow;不是静默 hang,也不是自动复用)。
product-path.sh:72 每个场景之间 find … -name 'leader.sock' -o -name 'attach.sock' -delete,
把这条分支系统性地绕开了

leader 侧不在此列 —— 它有专门覆盖:leader-lifecycle.test.ts:79 的测试名就是
"terminates one exact generation and removes only its stale socket",:112 还有身份守卫
(代次对不上会 reject identity changed);runtime.test.ts:388-394 是同型第二处。

建议:若要补,只补一条 —— 保留 attach.sock 再走一次产品路径启动,
断言以可诊断的错误失败、且 unlink 后重试可成。leader 侧不必动。

这一条我改了四版,把演变留下(免得有人按早期版本排期)

版本 说法 问题
「生产里最常见的形态是 socket 残留」 无证据,是我编的
实测本机 8 个 socket、ss -lx 比对 → 有监听者 8 / stale 0 撤回上句,降为「前提未验证」
换个可回答的问题:不问频率,问代码怎么处理 → 读 attach.ts 拿到源码依据,升回「值得补」
补验 leader 侧 → 发现它有专门覆盖 范围收窄到 attach 侧

每一版都比上一版窄。 按第一版排期会写一个我当时没证实其存在的场景;按第四版补的是一条确实存在、确实没测、范围明确的分支。

关于「doctor 工具面与 TUI-ready 解耦」这条怀疑 —— 我能指出它在哪

工具面 mutation 是有的,而且第一条很硬(upload-tool-removednode-server.ts 真删掉一个工具,要求红在 TOOL_SET_MISMATCH)。
但它们验的是 probe,不是产品路径:

expect_red() { …; if probe >"$log" 2>&1; then FAIL: mutation survived; fi; … }
probe()      { bun tests/test813-grok-mcp-readiness/probe.ts; }

而产品路径自己只断言 TUI ready session=、版本横幅 grok 0.2.93、session 持久化;
我 grep doctor|tools discovered|TOOL_SET|commhub_send|4 tools —— 产品路径没有任何一条校验工具面
(唯一命中的 "doctor" 是一句 FAIL 文案里的词)。

所以「doctor 被伪造成 healthy/4 tools 而 TUI 仍 ready」这个不对称态,在产品路径上没有 mutation 证明它会红。
定性同样是 NOT COVERED 而非假绿(两层的断言各自都是真的)。

补它时注意两点(都是我自己栽过的):红必须先于 TUI ready 出现,否则证明不了解耦被堵住;断言要锚在失败行上,别用通过时也会出现的串。

我没做的

只读了 attach.tsleader-lifecycle.test.tsrun.shproduct-path.sh;没跑任何镜像;
没验 proprietary Grok 的真实行为。若需要我在容器里真造一次 attach socket 残留来验证上面那段推断,可以说一声。

@vansin

vansin commented Aug 13, 2026

Copy link
Copy Markdown
Contributor Author

Superseded by #825. Reverse testing proved the old product-path readiness grep could accept a minified source line from a failure stack as a runtime event. Durable DO-NOT-MERGE evidence is in the earlier review comment; #825 has a fresh branch, exact-source rerun, anchored timestamped events, and a named product-boundary mutation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[grok-copresence] recovery can leave inbound Hub healthy while TUI CommHub MCP is dead

1 participant