# Bootstrap failures

> LFS pointer-sized archives, DMG checksum mismatch, missing app.asar files, GROK_BOT_018_APP version mismatch, and hydration checksum errors.

- Repository: sashimikun/grok-bot-0.18-reconstructed
- GitHub: https://github.com/sashimikun/grok-bot-0.18-reconstructed
- Human docs: https://grok-wiki.com/public/docs/sashimikun-grok-bot-0-18-reconstructed-c774cc9a5c15
- Complete Markdown: https://grok-wiki.com/public/docs/sashimikun-grok-bot-0-18-reconstructed-c774cc9a5c15/llms-full.txt

## Source Files

- `scripts/bootstrap-runtime.mjs`
- `scripts/lib/runtime.mjs`
- `scripts/lib/config.mjs`
- `tests/publication-bootstrap.test.mjs`
- `tests/research-archives.test.mjs`
- `research-archives/README.md`

---

---
title: "Bootstrap failures"
description: "LFS pointer-sized archives, DMG checksum mismatch, missing app.asar files, GROK_BOT_018_APP version mismatch, and hydration checksum errors."
---

`npm run bootstrap` (`scripts/bootstrap-runtime.mjs`) is fail-closed. It selects one 0.18.0 macOS runtime, copies it to `.cache/runtime/Grok Bot.app`, then hydrates gitignored `src/app/dist` from `Contents/Resources/app.asar` only when both the DMG (when used) and the ASAR match the pins in `scripts/lib/config.mjs`. A bad Git LFS pointer, a wrong `GROK_BOT_018_APP` bundle, or a drifted `app.asar` aborts; the script does not skip to the next source.

## Pinned identities

| Artifact | Path | Bytes | SHA-256 |
| --- | --- | ---: | --- |
| macOS DMG | `research-archives/original/0.18.0/macos-arm64/Grok_Bot_0.18.0.dmg` | `155793020` | `a253ccd8aab01e083f9812a0264354c5034d8ba7f0610bbb557e82ae77d203eb` |
| Cached DMG | `.cache/downloads/Grok_Bot_0.18.0.dmg` | same as pin | same as pin |
| Upstream `app.asar` | `Grok Bot.app/Contents/Resources/app.asar` | (hashed, not size-pinned) | `6665408168466f9cacc6087e917890c17f59d2e2e9c2404a5c4a59ad79c1de58` |

Public fallback URL (used only when the archived DMG is absent):

`https://downloads.cursor.com/grokbot/stable/darwin-arm64/0.18.0/Grok_Bot_0.18.0.dmg`

The preserved Windows `Grok_Bot_0.18.0_Setup.exe` is an evidence archive only. Bootstrap never mounts or hydrates it.

<ParamField body="GROK_BOT_018_APP" type="string">
Absolute path to an existing `Grok Bot.app`. When set and non-empty after trim, bootstrap copies that bundle with `/usr/bin/ditto` into `.cache/runtime/Grok Bot.app` and skips DMG attach. `CFBundleShortVersionString` must be exactly `0.18.0`.
</ParamField>

## Source selection

```mermaid
flowchart TD
  start["npm run bootstrap"] --> env{"GROK_BOT_018_APP set?"}
  env -->|yes| ditto["ditto into .cache/runtime/Grok Bot.app"]
  ditto --> validate["validateRuntimeApp"]
  env -->|no| cache{"cachedRuntimeApp exists?"}
  cache -->|yes| validate
  cache -->|no| dmg["downloadDmg"]
  dmg --> cachedDmg{".cache/downloads/Grok_Bot_0.18.0.dmg hash == dmgSha256?"}
  cachedDmg -->|yes| attach
  cachedDmg -->|no, file present| dropCache["rm cached DMG"]
  dropCache --> archive{"archived LFS DMG exists?"}
  cachedDmg -->|no file| archive
  archive -->|yes, hash mismatch| lfsFail["Archived DMG checksum mismatch — git lfs pull"]
  archive -->|yes, hash match| copyArchive["copyFile to cachedDmg"]
  archive -->|absent| fetch["fetch dmgUrl"]
  fetch -->|HTTP not ok or empty body| httpFail["Download failed: HTTP N"]
  fetch -->|hash mismatch| netHashFail["DMG checksum mismatch — delete .partial"]
  fetch -->|hash match| rename["rename .partial to cachedDmg"]
  copyArchive --> attach["hdiutil attach → Grok Bot.app"]
  rename --> attach
  attach --> validate
  validate -->|version != 0.18.0| verFail["Expected Grok Bot 0.18.0"]
  validate -->|missing executable or app.asar.unpacked| incomplete["Incomplete Grok Bot runtime"]
  validate -->|ok| hydrate["hydrateSourcePayloadFromAsar"]
  hydrate -->|asar hash mismatch| asarFail["Upstream app.asar checksum mismatch"]
  hydrate -->|missing required file| missingFail["Upstream app.asar is missing …"]
  hydrate -->|ok| ready["src/app/dist + Runtime ready"]
```

<Warning>
If `.cache/runtime/Grok Bot.app` already exists and `GROK_BOT_018_APP` is unset, bootstrap validates that cache and never opens the DMG. A stale or incomplete cache does not fall through to LFS or the public URL. Delete `.cache/runtime/Grok Bot.app` (and, if needed, `.cache/downloads/Grok_Bot_0.18.0.dmg`) before retrying.
</Warning>

`scripts/lib/build-asar.mjs` later calls `resolveRuntimeApp()`. Packaging without a successful bootstrap fails with `Missing 0.18.0 runtime. Run \`npm run bootstrap\` first.`

## Runtime gates

`validateRuntimeApp` requires all of:

| Check | Expected |
| --- | --- |
| `Contents/Info.plist` → `CFBundleShortVersionString` via `/usr/bin/plutil -extract … raw` | `0.18.0` (`upstreamVersion`) |
| `Contents/MacOS/Grok Bot` | regular file |
| `Contents/Resources/app.asar.unpacked` | directory |

DMG extract looks for `Grok Bot.app` at the `hdiutil` mountpoint (`-readonly -nobrowse`). Detach always runs in `finally`.

Hydration (`hydrateSourcePayloadFromAsar`) then:

1. SHA-256s the ASAR bytes against `upstreamAsarSha256` (overridable only by callers that pass `expectedSha256`; bootstrap does not override).
2. Extracts into a temp dir under `.cache/source-payloads/grok-bot-018-*`.
3. Requires these files inside the archive:

   - `dist/electron-main/main.cjs`
   - `dist/host/host-main.cjs`
   - `dist/renderer/index.html`

4. Replaces `src/app/dist` (`rm` then `cp` of the archive `dist/` tree only).
5. Deletes the temp extract in `finally`.

:::files
.cache/
  downloads/Grok_Bot_0.18.0.dmg
  downloads/Grok_Bot_0.18.0.dmg.partial   # network download; deleted on hash fail
  runtime/Grok Bot.app
  source-payloads/                        # temp extract; removed after hydrate
src/app/dist/                             # gitignored hydration output
  electron-main/main.cjs
  host/host-main.cjs
  renderer/index.html
research-archives/original/0.18.0/
  artifacts.json                          # schemaVersion 1 inventory
  SHA256SUMS
  macos-arm64/Grok_Bot_0.18.0.dmg         # Git LFS
:::

## Failure catalog

<AccordionGroup>
<Accordion title="LFS pointer instead of the 0.18.0 DMG">

Git tracks `research-archives/original/**/*.dmg` and `**/*.exe` with `filter=lfs`. A clone or source ZIP without `git lfs pull` leaves a small pointer file at the DMG path. `exists(archivedDmg)` is then true, so bootstrap **does not** fetch the public URL.

**Bootstrap error**

```text
Archived DMG checksum mismatch: expected a253ccd8aab01e083f9812a0264354c5034d8ba7f0610bbb557e82ae77d203eb, got <pointer-hash>. Run git lfs pull before bootstrapping.
```

**Test error** (`tests/research-archives.test.mjs`)

`metadata.size === artifact.bytes` fails with `<path> requires git lfs pull` when the file is not `155793020` bytes (macOS) or `125825552` bytes (Windows). Hosting ZIP/tarball downloads can also ship pointer files unless the host includes LFS objects.

**Fix**

```sh
git lfs install
git lfs pull
(cd research-archives/original/0.18.0 && shasum -a 256 -c SHA256SUMS)
npm run bootstrap
```

Confirm `git lfs ls-files` lists both installers and `ls -l research-archives/original/0.18.0/macos-arm64/Grok_Bot_0.18.0.dmg` is not pointer-sized.

</Accordion>

<Accordion title="DMG checksum mismatch (cache or download)">

A cached DMG whose digest is not `dmgSha256` is deleted, then the archived copy or network fetch runs. A network payload is written to `Grok_Bot_0.18.0.dmg.partial` with mode `0o600`; a bad digest deletes the partial and throws. `fetch` uses `redirect: "follow"`.

**Errors**

```text
DMG checksum mismatch: expected a253ccd8aab01e083f9812a0264354c5034d8ba7f0610bbb557e82ae77d203eb, got <digest>
Download failed: HTTP <status>
```

**Fix**

- Delete `.cache/downloads/Grok_Bot_0.18.0.dmg` and any `.partial`.
- Prefer a verified LFS archive over the network.
- Retry only after `shasum -a 256 -c SHA256SUMS` passes on the archived DMG.

There is no retry loop and no HTTP redirect-to-HTML tolerance: a non-ok response or null body fails immediately.

</Accordion>

<Accordion title="GROK_BOT_018_APP version or completeness mismatch">

`GROK_BOT_018_APP` must resolve to the upstream 0.18.0 app, not a reconstructed bundle under `dist/`. Version is read from Info.plist, not from `src/app/package.json`.

**Errors**

```text
Expected Grok Bot 0.18.0, got <version> at <appPath>
Incomplete Grok Bot runtime at <appPath>
/usr/bin/plutil exited with <code>: <stderr>
```

Incomplete means `Contents/MacOS/Grok Bot` is not a file or `Contents/Resources/app.asar.unpacked` is not a directory. A missing Info.plist surfaces as a `plutil` non-zero exit from `capture()`.

**Fix**

Point `GROK_BOT_018_APP` at a real 0.18.0 `Grok Bot.app` (from the pinned DMG), or unset it and bootstrap from LFS. Do not pass `dist/Grok Bot 0.18 Reconstructed.app`: that bundle can still report `0.18.0` and then fail the ASAR pin.

</Accordion>

<Accordion title="Missing or incomplete app.asar payload">

Hydration reads `Contents/Resources/app.asar`. After extract it requires the three `dist/` files above. `app.asar.unpacked` is a validate-time directory check, not an ASAR listing check.

**Errors**

```text
Upstream app.asar is missing dist/electron-main/main.cjs
Upstream app.asar is missing dist/host/host-main.cjs
Upstream app.asar is missing dist/renderer/index.html
```

A missing ASAR file itself fails at `readFile` (Node `ENOENT`), not a custom message. DMG attach that cannot find `Grok Bot.app` fails inside `cacheRuntimeFromApp` / `validateRuntimeApp`. `hdiutil` / `ditto` failures look like:

```text
/usr/bin/hdiutil exited with <code>
/usr/bin/ditto exited with <code>
```

**Fix**

Re-bootstrap from the pinned DMG. Do not hand-edit `src/app/dist`. Confirm the mounted app contains `Contents/Resources/app.asar` before retrying hydration.

</Accordion>

<Accordion title="Hydration checksum mismatch">

Every hydrate hashes the full ASAR. Bootstrap always expects `upstreamAsarSha256`. `tests/publication-bootstrap.test.mjs` asserts `hydrateSourcePayloadFromAsar` rejects `/checksum mismatch/` when `expectedSha256` is wrong.

**Error**

```text
Upstream app.asar checksum mismatch: expected 6665408168466f9cacc6087e917890c17f59d2e2e9c2404a5c4a59ad79c1de58, got <digest>
```

Typical causes: reconstructed or patched `app.asar` under `GROK_BOT_018_APP`, a non-0.18.0 build that still reports version `0.18.0`, or a truncated copy.

**Fix**

Use the DMG-extracted upstream app. Remove `.cache/runtime/Grok Bot.app` so the next run cannot reuse a bad cache. Successful hydrate prints the pinned digest.

</Accordion>
</AccordionGroup>

## Diagnose

<Steps>
<Step title="Confirm LFS objects, not pointers">

```sh
git lfs ls-files
ls -l research-archives/original/0.18.0/macos-arm64/Grok_Bot_0.18.0.dmg
(cd research-archives/original/0.18.0 && shasum -a 256 -c SHA256SUMS)
```

Expect `155793020` bytes and digest `a253ccd8…d203eb`. A ~100-byte text file is an LFS pointer.

</Step>
<Step title="Inspect env and cache">

```sh
printf '%s\n' "${GROK_BOT_018_APP-}"
ls -ld ".cache/runtime/Grok Bot.app" ".cache/downloads/Grok_Bot_0.18.0.dmg" 2>/dev/null || true
/usr/bin/plutil -extract CFBundleShortVersionString raw ".cache/runtime/Grok Bot.app/Contents/Info.plist"
```

Unset `GROK_BOT_018_APP` unless it is a verified 0.18.0 app. If the cached app exists, bootstrap will not re-read the DMG.

</Step>
<Step title="Clear the fail-closed cache and re-run">

```sh
rm -rf ".cache/runtime/Grok Bot.app" .cache/downloads/Grok_Bot_0.18.0.dmg .cache/downloads/Grok_Bot_0.18.0.dmg.partial
npm run bootstrap
```

</Step>
</Steps>

<Tabs>
<Tab title="LFS archive">

```sh
git lfs install
git lfs pull
npm run bootstrap
```

</Tab>
<Tab title="Existing app">

```sh
export GROK_BOT_018_APP="/path/to/Grok Bot.app"
npm run bootstrap
```

</Tab>
<Tab title="Public DMG">

Remove or rename the archived DMG only if you intend network fetch. Bootstrap copies a valid archive before `fetch`. After a failed download, delete `.partial` (the script already does this on hash mismatch).

</Tab>
</Tabs>

## Success signal

<ResponseExample>

```text
Runtime ready: <repo>/.cache/runtime/Grok Bot.app
Checksum-pinned source payload ready: <repo>/src/app/dist (6665408168466f9cacc6087e917890c17f59d2e2e9c2404a5c4a59ad79c1de58)
The checksum-pinned app supplies only the Electron shell, ABI-matched native dependencies, and explicitly documented build fallbacks.
```

</ResponseExample>

Also true after a good run:

- `src/app/dist/electron-main/main.cjs`, `src/app/dist/host/host-main.cjs`, and `src/app/dist/renderer/index.html` exist.
- `src/app/dist/` remains gitignored.
- `node --test tests/research-archives.test.mjs tests/publication-bootstrap.test.mjs` passes when LFS objects are present.

Do not weaken `dmgSha256`, `upstreamAsarSha256`, or the required ASAR file list to make bootstrap pass.

## Next

<CardGroup>
<Card title="Bootstrap the pinned runtime" href="/bootstrap-pinned-runtime">
Happy-path order: GROK_BOT_018_APP, cached app, LFS DMG, then the public URL.
</Card>
<Card title="Installation" href="/installation">
Git LFS, Node 26.5.x, and Xcode tools required before bootstrap.
</Card>
<Card title="Preserve original installers" href="/preserve-original-installers">
artifacts.json schemaVersion 1 and shasum -c SHA256SUMS.
</Card>
<Card title="Environment variables" href="/environment-variables">
GROK_BOT_018_APP and related overrides.
</Card>
<Card title="Packaging failures" href="/packaging-failures">
Errors after a successful hydrate, including Missing 0.18.0 runtime.
</Card>
<Card title="Evidence and provenance" href="/evidence-and-provenance">
Pinned 0.18.0 DMG and app.asar identities.
</Card>
</CardGroup>
