Skip to main content

v0.38.0.0 Smoke Test Report

Editor’s Note (v0.39.3.0): This report was contributed verbatim from PR #1299 (thebuildceo-agents). Two findings were re-diagnosed during the v0.39.3.0 wave; see CHANGELOG.md for corrections:
  • BUG-2 location: the empty-body crash site is the else branch at src/commands/serve-http.ts:1594-1597 (Buffer.from(JSON.stringify(req.body), 'utf8') throws when req.body === undefined because JSON.stringify(undefined) === undefined), not line 1508 as originally reported. The empty-Buffer guard at :1600 correctly fires for empty Buffers but never reaches the undefined case.
  • WARN-5 root cause: modusbrain capture --help is minimal because capture is missing from the CLI_ONLY_SELF_HELP set at src/cli.ts:34-53. The detailed HELP constant at src/commands/capture.ts:90-113 is correct and comprehensive but unreachable; the dispatcher’s generic short-circuit at :95 fires printCliOnlyHelp(command) first. brainstorm and lsd are in the self-help set, which is why their help works.
All 2 bugs and 10 warnings are addressed in v0.39.3.0. The report below is preserved as the historical record of what production looked like on 2026-05-22.
Production smoke test of the v0.38.0.0 ingestion cathedral release on a live Postgres-backed server (Supabase, pgvector, PgBouncer transaction mode). Test date: 2026-05-22 Server: MCP HTTP server v0.38.0.0 on port 3131, Postgres engine Prior version: v0.37.9.0

Summary


🐛 Bugs (2)

BUG-1: capture --file doubles frontmatter on files with existing frontmatter

Severity: Medium Repro:
Observed: The page on disk gets TWO frontmatter blocks. The outer block has title: '---' (it parsed the inner --- delimiter as the title), and the original frontmatter is preserved verbatim inside the body:
Expected: buildContent should detect existing frontmatter (the commit message says it has a “looks like markdown” heuristic for first-line heading or frontmatter delimiter) and not double-wrap. The inner frontmatter fields should merge with capture’s fields. Location: src/commands/brainstorm.tsbuildContent function (shared with capture).

BUG-2: POST /ingest crashes with unhandled TypeError on empty body

Severity: Medium Repro:
Observed: Returns a 500 HTML error page with stack trace:
Expected: The route already has an empty_body check (documented in the code and tested in the E2E suite), but the body-parser middleware for /ingest uses express.raw() which returns undefined for an empty POST (no Content-Length, no body). The empty_body guard fires AFTER the computeContentHash(body) call, which crashes on undefined. Fix: Move the null/undefined/empty-buffer check before the content-hash computation, or add a guard at the top of the route handler:

⚠️ Warnings (10)

WARN-1: Dedup does not actually deduplicate identical captures

Observed: Capturing identical text twice produces the same slug but different content_hash values:
Root cause: The content hash includes the full serialized page with frontmatter, and captured_at changes between runs (it’s timestamped). The slug is deterministic (derived from content text), so it correctly maps to the same page — but the hash changes every time. Impact: The “24h content-hash LRU dedup” in the daemon layer won’t catch duplicate captures because the hash differs. The put_page upsert catches it at the slug level (overwrites), so no duplicate pages are created — but the content_hash-based dedup layer is effectively bypassed for CLI captures. Suggestion: Compute content_hash from the user’s input text before adding frontmatter, or exclude captured_at from the hash computation.

WARN-2: Same text with different --type flags overwrites the previous capture

Same slug is generated for identical text regardless of --type. The second capture with --type observation silently overwrites the first with --type idea. This is correct behavior (slug = content hash), but may surprise users who expect type changes to produce distinct pages.

WARN-3: --source flag crashes with raw FK violation

The error message exposes a raw Postgres FK violation. Users have no way to know what to do. The capture command should catch this error and print a human-friendly message:

WARN-4: facts:absorb connection error after every capture

Every capture logs:
Non-fatal (exit 0), but noisy. The facts subsystem tries to open a separate connection that the CLI capture path doesn’t initialize.

WARN-5: capture --help is minimal — doesn’t show flags

Compare with brainstorm --help which has a full Options section, examples, and cost info. The capture help should document --type, --file, --source, --json, --stdin, --slug, etc.

WARN-6: capture, brainstorm, lsd missing from modusbrain --help

None of these three commands appear in the main help text. They work when invoked directly, but users can’t discover them from the help output. modusbrain --help lists every other command (get, put, search, etc.) but the v0.37/v0.38 commands are absent.

WARN-7: Binary file capture succeeds silently

This succeeds, creating a page with binary garbage as content. Should either reject non-text files or at minimum warn.

WARN-8: Provenance columns not populated by capture

The capture CLI reports "source_kind": "capture-cli" in its JSON output, but the actual database row has:
The provenance fields from capture’s output don’t round-trip into the put_page call that persists the page.

WARN-9: Admin register-client ignores scope parameter

Registering a client via /admin/api/register-client with "scope": "read write" creates a client with scope "read" only. The admin endpoint appears to ignore or default the scope field. Required manual DB update to get write scope for webhook testing.

WARN-10: brainstorm / lsd may hang or timeout on PgBouncer

In transaction-mode PgBouncer environments, brainstorm consistently times out after the cost estimate with canceling statement due to statement timeout. The hybrid search + domain-bank phase appears to hit PgBouncer’s statement timeout. This may be environmental, but the command should handle the timeout gracefully and report what failed rather than silently producing no output.

✅ What Works Well

  • modusbrain capture "text" — works perfectly for the simple case. Frontmatter stamps, JSON output, disk write, immediate searchability.
  • modusbrain capture --file — works for plain text and simple markdown (frontmatter doubling bug only affects files with existing frontmatter).
  • modusbrain capture "" and no-args — clean error messages: "provide content positionally, --file PATH, or --stdin".
  • modusbrain capture --file /nonexistent — clean ENOENT error.
  • Unicode/emojimodusbrain capture "测试 🧠🔥 émojis" works perfectly.
  • Long text — 2500+ character capture works, correctly produces 2 chunks.
  • POST /ingest auth gate — properly rejects missing auth (401), invalid tokens (401), and insufficient scope (403).
  • POST /ingest content-type validation — properly rejects image/png and application/pdf with a helpful error pointing to skillpack processors.
  • POST /ingest accepted types — text/plain, text/markdown, text/html, application/json all accepted and queued.
  • X-Modusbrain-Source-Id header — custom source ID flows through correctly.
  • MCP health endpoint — returns clean JSON with version and engine.
  • OAuth client_credentials flow — works correctly once the client has proper scope.
  • Content-hash dedup on webhook — verified via response content_hash.
  • Migration v81 — provenance columns added cleanly, nullable, no disruption to existing pages. 290K+ existing pages unaffected.
  • brainstorm --help / lsd --help — excellent help text with examples, cost estimates, and cross-references.
  • Soft delete + recovery — cleanup via modusbrain delete works with 72h recovery window.
  • --type flagnote, idea, observation all work correctly.

💡 Suggestions

  1. capture --help parity — give it the same quality help text as brainstorm --help. Document every flag.
  2. Main help completeness — add capture, brainstorm, and lsd to the modusbrain --help command listing. These are user-facing features that can’t be discovered.
  3. Content-hash stability — consider computing the dedup hash from user input text only (before frontmatter injection) so identical captures are properly deduped at the daemon layer.
  4. Provenance write-throughcapture already knows it’s source_kind: "capture-cli". Pass this through to put_page so the DB columns are populated.
  5. Binary file guard — reject or warn on non-text input in capture --file. Check file content or extension before proceeding.
  6. --source error UX — catch the FK violation and print a human-friendly hint about registering sources.