Skip to content

fix: report standalone brain install in serve status - #2482

Merged
namastex888 merged 53 commits into
devfrom
fix/brain-standalone-status
May 23, 2026
Merged

namastex888 merged 53 commits into
devfrom
fix/brain-standalone-status

Conversation

@namastex888

Copy link
Copy Markdown
Contributor

Summary

  • fix genie serve status reporting brain: not installed when the standalone brain CLI is installed but no Brain server is running
  • preserve existing running/unhealthy/stopped Brain status behavior
  • add a regression test for standalone installed-but-not-running status

Verification

  • RED: focused regression failed before implementation because printStandaloneBrainStatus was not exported/implemented for this case
  • GENIE_TEST_SKIP_PGSERVE=1 bun test src/term-commands/serve.test.ts
  • bunx biome check src/term-commands/serve.ts src/term-commands/serve.test.ts
  • bun run build
  • source runtime proof: brain: installed standalone (1.64.0, server not running)

release-bot and others added 30 commits May 19, 2026 12:09
… + self-provision DB)

genie could not migrate onto autopg/pgserve v3. Three coupled defects,
all reproduced + fixed against a live autopg v3 host:

1. KEYSTONE — migrations absent from the compiled binary.
   db-migrations.ts loaded SQL via readdirSync(import.meta.dir
   /../db/migrations) + Bun.file(); `bun build --compile` does NOT bundle
   those runtime FS reads, so the shipped binary saw ZERO migrations →
   `genie db migrate` reported "Applied: 0" on an empty DB, schema never
   created. Fix: scripts/gen-migrations-manifest.ts →
   src/db/migrations.generated.ts (static `with { type: 'text' }` imports
   Bun embeds); loader prefers the embedded set, FS scan kept as a dev
   fallback; build-binary.sh regenerates pre-compile so it can't go
   stale; src/types/sql.d.ts ambient for the text import.

2. autopg v3 not detected as a direct postmaster.
   readPostmasterDiscovery() only read `<socketDir>/admin.json`; autopg
   v3 writes live discovery to `<socketDir>/runtime.json` (admin.json
   moved to ~/.autopg/). directPostmaster was always false → genie stayed
   on the legacy accept-hook/`postgres` path pgserve v3 deleted. Fix:
   read runtime.json (v3) then admin.json (v2), shared parse/validate.

3. No native DB provisioning. resolveDatabaseName() always returned
   `postgres`, relying on the deleted pgserve-v2 accept-hook to
   auto-create+route `app_<name>_<fp>`. Fix: on the direct-postmaster
   path target NATIVE_DB_NAME ('genie'; GENIE_DB_NAME override) and
   ensureDatabaseExists() creates it from the `postgres` maintenance DB
   (allowlisted ident; duplicate_database race tolerated). `database` is
   reassigned in-place so the bootstrap pool, role-cutover GRANTs and
   migrations agree on the target DB (an earlier split granted the scoped
   role in `postgres` while the pool ran in `genie` → "no schema has been
   selected to create in"). Legacy router path unchanged.

Proven on a live autopg v3 host, freshly compiled binary, zero env hacks
/ zero manual DB creation: genie db migrate → provisioned database
"genie" → role-cutover database=genie → 63 migrations → pg-seed 132
teams → genie db = 63 migrations / 52 tables → `genie ls` reads PG
cleanly. biome + tsc clean on changed files.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ple from role-cutover

CodeRabbit (Major) + Codex (P1) both correct:
- Native-DB provisioning was gated on `directPostmaster`, which is
  `cutoverEnabled && … && readPostmasterDiscovery()`. With
  GENIE_ROLE_CUTOVER=0 it was skipped → v3 fell back to `postgres` and
  re-broke (CodeRabbit).
- readPostmasterDiscovery() now also matches v2 `admin.json`, so
  `directPostmaster` was true on pgserve v2 too → my branch retargeted v2
  hosts from `postgres` to `genie`, booting them against a new empty DB
  (Codex P1 regression).

Fix: new `hasV3RuntimeDiscovery()` — true ONLY when `<socketDir>/
runtime.json` (the v3, router-less marker; v2 publishes only admin.json)
parses. Native-DB now keys off `v3NativeDb = transport.useSocket &&
hasV3RuntimeDiscovery()` — NOT cutoverEnabled, NOT v2 admin.json.
`directPostmaster` (role-cutover) is left exactly as-is, so v2 + v3
role-cutover behavior is unchanged.

Validated on a live v3 host, freshly compiled binary:
- default (cutover ON): 63 migrations → `genie` DB ✓
- GENIE_ROLE_CUTOVER=0: 63 migrations → `genie` DB ✓ (no postgres fallback)
- v2 (no runtime.json): v3NativeDb=false → stays on `postgres` (router path)
check:fast (typecheck/lint/dead-code/skills/wishes/emit) + biome green.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ration

fix(db): native genie → autopg/pgserve-v3 migration (embed migrations + self-provision DB)
chore: rolling promotion dev → main (native pgserve-v3 fix + recovery runbook)
release(stable): v4.260520.1 — agents survive VM reboot
release(stable): autopg-v3 install resolver — fresh-host genie install now works
Promote dev to stable: Genie observability resume-anchor fix
Promote dev to stable: PM2 Genie install recovery
release-bot and others added 23 commits May 22, 2026 16:19
Promote dev to stable: update diagnostics cleanup
Promote dev to stable: socket transport diagnostics
Promote v4.260522.17 stable: Brain control surface fix
Promote v4.260522.19 stable: doctor PATH fidelity
fix: reduce Genie DX false positives
@coderabbitai

coderabbitai Bot commented May 22, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 1280b6af-7678-4733-bba1-e351d00028ec

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/brain-standalone-status

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request updates version metadata and enhances the serve command to report the status of the standalone 'brain' binary even when the server is not running. The printStandaloneBrainStatus function was refactored to support dependency injection for testing, and a new test case was added. Feedback was provided to include timeouts for both the external process execution and the health check fetch to prevent potential hangs in the CLI.

function getStandaloneBrainVersion(): string | null {
try {
const resp = await fetch(`http://127.0.0.1:${config.port}/healthz`);
const result = spawnSync('brain', ['--version'], { encoding: 'utf-8' });

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

It's a good practice to include a timeout when spawning external processes to prevent the CLI from hanging indefinitely if the command (e.g., 'brain --version') fails to respond or hangs. Hardcoded limits are acceptable here to prevent performance issues.

Suggested change
const result = spawnSync('brain', ['--version'], { encoding: 'utf-8' });
const result = spawnSync('brain', ['--version'], { encoding: 'utf-8', timeout: 2000 });
References
  1. It is acceptable to use hardcoded numeric limits (magic numbers) in non-critical fallback logic, especially when they serve as intentional caps to prevent performance issues like excessive I/O.

}
try {
const fetchHealth = deps.fetchImpl ?? fetch;
const resp = await fetchHealth(`http://127.0.0.1:${config.port}/healthz`);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Adding a timeout to the health check fetch prevents the 'serve status' command from hanging if the network request to the local brain server takes too long. Hardcoded limits are acceptable here to prevent performance issues.

Suggested change
const resp = await fetchHealth(`http://127.0.0.1:${config.port}/healthz`);
const resp = await fetchHealth('http://127.0.0.1:' + config.port + '/healthz', { signal: AbortSignal.timeout(2000) });
References
  1. It is acceptable to use hardcoded numeric limits (magic numbers) in non-critical fallback logic, especially when they serve as intentional caps to prevent performance issues like excessive I/O.

@namastex888
namastex888 merged commit 8a8df1a into dev May 23, 2026
16 checks passed
@automagik-genie
automagik-genie deleted the fix/brain-standalone-status branch September 25, 2026 04:49
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.

3 participants