[GH-ISSUE #6207] [Bug] Grok Build setup drops comments beside the existing REA table #3779

Closed
opened 2026-10-31 00:43:58 +00:00 by bsakaguchi · 0 comments
Owner

Originally created by @coygeek on GitHub (Oct 22, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/6207

Originally assigned to: @kaoru0822-kitauji on GitHub.

Before submitting

  • I searched the open and closed issues for a related report.
  • I removed credentials, tokens, private paths, and sensitive target data.

Area

Setup, packaging, or upgrade

Observed behavior

setup --client grok_build --skill=false --yes --json removes a comment immediately before an existing [mcp_servers.rea] table and a trailing file note after it, despite reporting ready. I reproduced this in two fresh isolated homes through the registered production source CLI. The root comment and model setting survived, the stale REA command was replaced, and both original backups were byte-identical to their inputs. A Codex control with the same input retained all three comments.

Reproduction

Run from the baseline checkout with its locked dependencies already installed. Save this test as tests/process-global/repro-grok-comment-loss.test.ts. It invokes the registered production source CLI with real setup/filesystem behavior and isolated selected environments; it does not require a runtime build or native Grok client.

import { mkdir, readFile, writeFile } from "node:fs/promises";
import { join } from "node:path";
import { expect, it } from "vitest";
import { createCli, closeCliJavaScriptResources } from "../../src/cli.js";

it("records comment preservation through the registered setup CLI", async () => {
  const root = process.env.REA_VERIFY_ROOT!;
  const original = '# root explanation\nmodel = "x"\n\n# about rea\n[mcp_servers.rea]\ncommand = "old"\n\n# trailing note about the file\n';
  const receipts: unknown[] = [];
  const initialExitCode = process.exitCode;
  try {
    for (const [index, client] of ["grok_build", "grok_build", "codex"].entries()) {
      const home = join(root, `trial-${index}`);
      const configRoot = join(home, client === "codex" ? ".codex" : ".grok");
      await mkdir(configRoot, { recursive: true });
      const config = join(configRoot, "config.toml");
      await writeFile(config, original);
      const environment = {
        HOME: home,
        USERPROFILE: home,
        DSH_HOME: join(home, ".dsh"),
        GROK_HOME: join(home, ".grok"),
        CODEX_HOME: join(home, ".codex"),
        XDG_CONFIG_HOME: join(home, ".config"),
        TMPDIR: join(root, "temp"),
        REA_LOG_LEVEL: "silent",
      };
      let stdout = "";
      let exitCode = 0;
      await createCli(environment).serve(
        ["setup", "--client", client, "--skill=false", "--yes", "--json"],
        { env: {}, stdout: text => { stdout += text; }, exit: code => { exitCode = code; } },
      );
      const result = JSON.parse(stdout);
      const after = await readFile(config, "utf8");
      const backup = await readFile(`${config}.rea.backup`, "utf8");
      receipts.push({ client, exitCode, result, original, after, backupMatches: backup === original });
      await writeFile(join(root, "receipts.json"), JSON.stringify(receipts, null, 2));
      expect(exitCode, stdout).toBe(0);
      expect(result.status, stdout).toBe("ready");
      expect(backup).toBe(original);
      expect(after).toContain('# root explanation\nmodel = "x"');
      expect(after).toContain("[mcp_servers.rea]");
      expect(after).not.toContain('command = "old"');
      for (const comment of ["# about rea", "# trailing note about the file"]) {
        expect(after.includes(comment)).toBe(client === "codex");
      }
    }
  } finally {
    await closeCliJavaScriptResources();
    process.exitCode = initialExitCode;
  }
}, 60_000);

Run:

PROOF_ROOT="$(mktemp -d)"
mkdir -p "$PROOF_ROOT/home" "$PROOF_ROOT/dsh" "$PROOF_ROOT/temp"
HOME="$PROOF_ROOT/home" DSH_HOME="$PROOF_ROOT/dsh" REA_VERIFY_ROOT="$PROOF_ROOT" node node_modules/vitest/vitest.mjs run tests/process-global/repro-grok-comment-loss.test.ts --maxWorkers=1

The temporary test filename above is neutralized for reporting. The same test content and invocation reproduced the comment loss in 2/2 fresh Grok homes, with a preserving Codex control in 1/1 home. Its assertions deliberately confirm the current wrong behavior; a passing test is reproduction evidence. Delete the temporary test after running it. The JSON receipt retains the before/after text and CLI result.

Expected behavior

Refreshing the REA registration should retain unrelated comment text, including the trailing file note. The configuration-write contract promises preservation of unrelated entries and comments, and the Grok Build setup scope identifies the REA server/environment tables and disabled-server membership as the edited configuration.

Impact and scope

Observed in 2/2 Grok source CLI invocations on this fixture. Only comments were lost; parsed settings survived and no downstream runtime change was established. Impact assessment: P3. The exact original backup was observed in both runs, so the comment text can be restored manually. Other platforms, installed-package dispatch, and native Grok execution were not tested.

REA version

Source commit c465ff5a81 (main)

Runtime and platform

Node v26.12.0; macOS 27.0.1; arm64. The repository pins Node 24.18.0. Preinstalled locked dependencies and Vitest 5.0.3; no runtime build or dependency installation was run.

Target and artifact context

Existing Grok Build TOML configuration with a stale local REA entry and adjacent comment lines. No target program or model service was executed.

Interface

CLI

Earliest failure stage

Setup or provider admission

Relevant output or evidence

The focused test passed (one test), confirming the current wrong behavior across two fresh Grok homes plus a Codex control. The Grok result contained:

{"status":"ready","appliedActions":["configured_grok_build"],"clients":{"grok_build":{"status":"configured"}}}

This is a relevant-field projection; the full receipt is written by the test. Both Grok outputs kept # root explanation and model = "x", contained a refreshed [mcp_servers.rea], and omitted # about rea and # trailing note about the file. Both backups exactly matched the original. The source CLI ran under Vitest: its selected launcher was the test worker, so this proves setup text editing and readback, not an installed-dispatcher subprocess or a usable native-client registration.

Typed outcome or recovery expected

Keep ready, the updated REA registration, and the original backup while retaining both currently lost comments. The root comment and setting must also remain unchanged.

Analysis or suspected cause

Source-derived explanation: the shared TOML editor discards queued comments before the REA header. Its comment branch preserves comments immediately only for the Codex toml dialect; Grok queues them, and end-of-file handling leaves them unflushed while skipping the REA table. This matches the two observed losses; no patch was tested.

Additional context

Related but distinct: #1163 and merged #1178 concerned Codex's earlier whole-document serializer; the current Codex control preserves the comments. #1732 concerns retained semantic entry fields and excludes comment preservation. #4856 concerns large-document capacity, rather than comment loss. Searches covered open/closed issues and PRs with Grok/comment, setup/comment-loss, and ClientConfigurationDocument keyword sets. Fetched upstream main at 87c8086fc1 has no intervening changes to the relevant serializer, client mapping, setup producer, CLI registration, or documentation. NOT_ENOUGH_INFO for a last-known-good Grok version; no regression boundary was established.

Originally created by @coygeek on GitHub (Oct 22, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/6207 Originally assigned to: @kaoru0822-kitauji on GitHub. ### Before submitting - [x] I searched the open and closed issues for a related report. - [x] I removed credentials, tokens, private paths, and sensitive target data. ### Area Setup, packaging, or upgrade ### Observed behavior `setup --client grok_build --skill=false --yes --json` removes a comment immediately before an existing `[mcp_servers.rea]` table and a trailing file note after it, despite reporting `ready`. I reproduced this in two fresh isolated homes through the registered production source CLI. The root comment and `model` setting survived, the stale REA command was replaced, and both original backups were byte-identical to their inputs. A Codex control with the same input retained all three comments. ### Reproduction Run from the baseline checkout with its locked dependencies already installed. Save this test as `tests/process-global/repro-grok-comment-loss.test.ts`. It invokes the registered production source CLI with real setup/filesystem behavior and isolated selected environments; it does not require a runtime build or native Grok client. ```ts import { mkdir, readFile, writeFile } from "node:fs/promises"; import { join } from "node:path"; import { expect, it } from "vitest"; import { createCli, closeCliJavaScriptResources } from "../../src/cli.js"; it("records comment preservation through the registered setup CLI", async () => { const root = process.env.REA_VERIFY_ROOT!; const original = '# root explanation\nmodel = "x"\n\n# about rea\n[mcp_servers.rea]\ncommand = "old"\n\n# trailing note about the file\n'; const receipts: unknown[] = []; const initialExitCode = process.exitCode; try { for (const [index, client] of ["grok_build", "grok_build", "codex"].entries()) { const home = join(root, `trial-${index}`); const configRoot = join(home, client === "codex" ? ".codex" : ".grok"); await mkdir(configRoot, { recursive: true }); const config = join(configRoot, "config.toml"); await writeFile(config, original); const environment = { HOME: home, USERPROFILE: home, DSH_HOME: join(home, ".dsh"), GROK_HOME: join(home, ".grok"), CODEX_HOME: join(home, ".codex"), XDG_CONFIG_HOME: join(home, ".config"), TMPDIR: join(root, "temp"), REA_LOG_LEVEL: "silent", }; let stdout = ""; let exitCode = 0; await createCli(environment).serve( ["setup", "--client", client, "--skill=false", "--yes", "--json"], { env: {}, stdout: text => { stdout += text; }, exit: code => { exitCode = code; } }, ); const result = JSON.parse(stdout); const after = await readFile(config, "utf8"); const backup = await readFile(`${config}.rea.backup`, "utf8"); receipts.push({ client, exitCode, result, original, after, backupMatches: backup === original }); await writeFile(join(root, "receipts.json"), JSON.stringify(receipts, null, 2)); expect(exitCode, stdout).toBe(0); expect(result.status, stdout).toBe("ready"); expect(backup).toBe(original); expect(after).toContain('# root explanation\nmodel = "x"'); expect(after).toContain("[mcp_servers.rea]"); expect(after).not.toContain('command = "old"'); for (const comment of ["# about rea", "# trailing note about the file"]) { expect(after.includes(comment)).toBe(client === "codex"); } } } finally { await closeCliJavaScriptResources(); process.exitCode = initialExitCode; } }, 60_000); ``` Run: ```sh PROOF_ROOT="$(mktemp -d)" mkdir -p "$PROOF_ROOT/home" "$PROOF_ROOT/dsh" "$PROOF_ROOT/temp" HOME="$PROOF_ROOT/home" DSH_HOME="$PROOF_ROOT/dsh" REA_VERIFY_ROOT="$PROOF_ROOT" node node_modules/vitest/vitest.mjs run tests/process-global/repro-grok-comment-loss.test.ts --maxWorkers=1 ``` The temporary test filename above is neutralized for reporting. The same test content and invocation reproduced the comment loss in 2/2 fresh Grok homes, with a preserving Codex control in 1/1 home. Its assertions deliberately confirm the current wrong behavior; a passing test is reproduction evidence. Delete the temporary test after running it. The JSON receipt retains the before/after text and CLI result. ### Expected behavior Refreshing the REA registration should retain unrelated comment text, including the trailing file note. The [configuration-write contract](https://github.com/morluto/rea/blob/c465ff5a814b8e1a386fc547cbcd94df5c35f086/docs/installation.md#L63) promises preservation of unrelated entries and comments, and the [Grok Build setup scope](https://github.com/morluto/rea/blob/c465ff5a814b8e1a386fc547cbcd94df5c35f086/docs/client-configuration.md#L426) identifies the REA server/environment tables and disabled-server membership as the edited configuration. ### Impact and scope Observed in 2/2 Grok source CLI invocations on this fixture. Only comments were lost; parsed settings survived and no downstream runtime change was established. Impact assessment: P3. The exact original backup was observed in both runs, so the comment text can be restored manually. Other platforms, installed-package dispatch, and native Grok execution were not tested. ### REA version Source commit c465ff5a814b8e1a386fc547cbcd94df5c35f086 (main) ### Runtime and platform Node v26.12.0; macOS 27.0.1; arm64. The repository pins Node 24.18.0. Preinstalled locked dependencies and Vitest 5.0.3; no runtime build or dependency installation was run. ### Target and artifact context Existing Grok Build TOML configuration with a stale local REA entry and adjacent comment lines. No target program or model service was executed. ### Interface CLI ### Earliest failure stage Setup or provider admission ### Relevant output or evidence The focused test passed (one test), confirming the current wrong behavior across two fresh Grok homes plus a Codex control. The Grok result contained: ```json {"status":"ready","appliedActions":["configured_grok_build"],"clients":{"grok_build":{"status":"configured"}}} ``` This is a relevant-field projection; the full receipt is written by the test. Both Grok outputs kept `# root explanation` and `model = "x"`, contained a refreshed `[mcp_servers.rea]`, and omitted `# about rea` and `# trailing note about the file`. Both backups exactly matched the original. The source CLI ran under Vitest: its selected launcher was the test worker, so this proves setup text editing and readback, not an installed-dispatcher subprocess or a usable native-client registration. ### Typed outcome or recovery expected Keep `ready`, the updated REA registration, and the original backup while retaining both currently lost comments. The root comment and setting must also remain unchanged. ### Analysis or suspected cause Source-derived explanation: the [shared TOML editor](https://github.com/morluto/rea/blob/c465ff5a814b8e1a386fc547cbcd94df5c35f086/src/application/ClientConfigurationDocument.ts#L1038) discards queued comments before the REA header. Its [comment branch](https://github.com/morluto/rea/blob/c465ff5a814b8e1a386fc547cbcd94df5c35f086/src/application/ClientConfigurationDocument.ts#L1130) preserves comments immediately only for the Codex `toml` dialect; Grok queues them, and [end-of-file handling](https://github.com/morluto/rea/blob/c465ff5a814b8e1a386fc547cbcd94df5c35f086/src/application/ClientConfigurationDocument.ts#L1152) leaves them unflushed while skipping the REA table. This matches the two observed losses; no patch was tested. ### Additional context Related but distinct: #1163 and merged #1178 concerned Codex's earlier whole-document serializer; the current Codex control preserves the comments. #1732 concerns retained semantic entry fields and excludes comment preservation. #4856 concerns large-document capacity, rather than comment loss. Searches covered open/closed issues and PRs with Grok/comment, setup/comment-loss, and ClientConfigurationDocument keyword sets. Fetched upstream main at 87c8086fc1c9783de1ef4011dfdf597957064813 has no intervening changes to the relevant serializer, client mapping, setup producer, CLI registration, or documentation. NOT_ENOUGH_INFO for a last-known-good Grok version; no regression boundary was established.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#3779
No description provided.