Skip to content

Packaged Brain Console omits model-catalog.json, falsely reporting OpenAI/Gemini keys as absent #86

Description

@sparkling

Summary

The Brain Console's provider checklist gives false negatives in the published/persistent runtime: OpenAI and Google/Gemini are shown as unavailable even when their environment variables are present and Brain's own subscription detector sees them.

This is a release-boundary regression in the implementation delivered for #24 / PR #26, not a credential-configuration problem.

Reproduction

With the published 4.0.2 runtime and synthetic or real OPENAI_API_KEY plus GOOGLE_API_KEY:

  1. Start the Brain Console.
  2. Request GET /api/state.
  3. Compare sections.savings.routerEngine.keys with sections.savings.routerEngine.subscriptions.

Observed on a live packaged runtime:

{
  "keys": { "openrouter": true },
  "subscriptions": {
    "openai": { "apiKey": true },
    "google": { "apiKey": true }
  }
}

No credential values are exposed. The contradiction is enough to demonstrate the defect.

Root cause

Current main and the published package have a broken asset boundary:

  • scripts/model-catalog.mjs loads ../data/model-catalog.json.
  • package.json#files includes scripts/ but does not publish data/model-catalog.json.
  • beginConsoleRuntimeTransaction() copies the Console and scripts into the persistent runtime, but not the catalog data.
  • gatherRouterEngine() performs catalog loading and provider-key detection in one try.
  • When loadCatalog() throws, the catch supplies only the fallback house provider; providerKeys remains empty.
  • The API then returns only the separately detected OpenRouter entry, although detectSubscriptions() correctly sees OpenAI and Google/Gemini.

The same missing asset was reproduced in clean installed/npx 4.0.2 package roots and in the persistent .console-runtime.

Why the previous fix is incomplete

#24 and PR #26 added the correct detect_env-driven provider checks. Those checks work from a developer checkout containing data/model-catalog.json, but the released npm artifact and staged Console runtime omit the required catalog. The feature therefore fails at the package/runtime boundary.

Expected behavior

A clean published install and the persistent Console runtime must both contain every required provider-catalog asset. The Console must report the same provider availability that Brain's native detectors observe.

If a required catalog cannot be loaded, the runtime must expose an explicit degraded/error state or fail staging. It must not silently convert an internal asset failure into apparently valid “key absent” results.

Proposed upstream implementation

  1. Add the exact required data/model-catalog.json asset to the npm files allow-list.
  2. Add the catalog to beginConsoleRuntimeTransaction()'s required asset set.
  3. Before activating a staged persistent runtime, load and validate the catalog from the staged location.
  4. Separate catalog-load health from credential detection:
    • preserve the catalog-driven provider matrix when available;
    • use the existing detectSubscriptions() result as the known-provider fallback if catalog loading fails;
    • expose that the catalog-dependent view is degraded rather than presenting false negatives.
  5. Keep all credential handling boolean-only; never return key values.

Required regression coverage

  • Pack the release artifact and assert data/model-catalog.json is present.
  • Build the persistent Console runtime from that packed artifact and assert the catalog is copied and loadable there.
  • Launch the packed/staged runtime with dummy OPENAI_API_KEY and GOOGLE_API_KEY; assert /api/state reports both as available.
  • Cover GEMINI_API_KEY as the Google-provider alias.
  • Include unset-key negative controls.
  • Remove/withhold the catalog and assert staging fails explicitly, or the API reports a degraded catalog state while retaining correct native subscription detections.
  • Run these checks in release CI so a package cannot be published when source-checkout behavior and packed-runtime behavior diverge.

Verified against

  • ruvnet-brain 4.0.2
  • current upstream main at 924d29a8a5d7b5c09effdd21d75250ea15140c60
  • macOS persistent Console runtime

Related: #24, PR #26.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions