Skip to content

fix(secrets): keep startup alive when TTS SecretRefs are missing#101265

Merged
steipete merged 25 commits into
openclaw:mainfrom
snowzlmbot:fix/optional-tts-secret-startup
Jul 17, 2026
Merged

fix(secrets): keep startup alive when TTS SecretRefs are missing#101265
steipete merged 25 commits into
openclaw:mainfrom
snowzlmbot:fix/optional-tts-secret-startup

Conversation

@snowzlmbot

@snowzlmbot snowzlmbot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

First submitted: July 6, 2026, 10:00 PM (US Eastern Time) / 02:00 UTC.
Last body edit: July 17, 2026.
Latest head commit: July 17, 2026.

Closes #101204

What Problem This Solves

Fixes an issue where one missing SecretRef could abort the whole Gateway even when the credential belonged only to an optional capability or one model provider. A temporarily unavailable TTS key or unused model-provider key could therefore take unrelated chat, channels, tools, and plugins offline.

Why This Change Was Made

Secret assignments now carry explicit owner metadata: owner kind and id, whether Gateway ingress requires the value, and whether failure isolates the owner or fails closed. Cold startup isolates only known non-Gateway owners. The exact capability or provider becomes configured-unavailable, receives a typed redacted warning, and cannot silently fall back to environment or profile credentials.

Gateway ingress authentication remains required. Structurally invalid refs, unknown owners, and all unpartitioned surfaces still fail closed. Reload remains strict and preserves the last-known-good snapshot; expanding isolation to reload is intentionally deferred.

This bounded foundation partitions two current owner classes:

  • built-in TTS as capability:tts;
  • configured model providers as provider:<id>, covering API keys, headers, and request transport credentials.

The previous TTS-only optional-assignment machinery is removed. TTS uses the same generic owner registry and throws SecretSurfaceUnavailableError through direct SDK, injected runtime, tool, automatic TTS, and Gateway RPC paths. Model auth checks the cold-provider registry before any env/profile discovery.

Degraded owners are process-local and visible in status and doctor output. Persistence and the remaining channel/account/route partition work are follow-ups, not part of this PR. No config option, environment variable, protocol version, dependency, or persisted schema is added.

User Impact

On first Gateway startup, a missing TTS ref or unused configured model-provider ref no longer takes the whole Gateway down. The Gateway starts, logs a redacted owner-specific warning, and reports the owner in status/doctor. Calls into that owner fail with a typed unavailable error.

A missing gateway.auth token or password still refuses startup. Unknown ownership and malformed configuration still refuse startup. A failed explicit provider ref never activates an implicit environment or profile fallback.

Release-note context: Gateway startup now isolates missing SecretRefs to known optional TTS and model-provider owners while keeping ingress auth and unknown ownership fail-closed.

Evidence

  • node scripts/run-vitest.mjs src/secrets/runtime.test.ts src/secrets/resolve.test.ts src/secrets/runtime-config-collectors-tts.test.ts src/secrets/runtime-degraded-state.test.ts — 54 tests passed.
  • node scripts/run-vitest.mjs src/gateway/server-startup-secret-owner-isolation.test.ts src/gateway/server-startup-config.secrets.test.ts src/gateway/server-methods/tts.test.ts — 37 tests passed.
  • node scripts/run-vitest.mjs src/tts/tts.test.ts packages/speech-core/src/tts.test.ts src/commands/status.summary.test.ts src/commands/doctor-gateway-health.test.ts — 82 tests passed across three shards.
  • node scripts/run-vitest.mjs src/agents/model-auth.test.ts -t 'does not fall back|keeps the whole provider cold' — 4 tests passed; 152 unrelated tests skipped.
  • node --max-old-space-size=8192 --import tsx scripts/generate-plugin-sdk-api-baseline.ts --check — passed.
  • Hosted changed-surface gate — passed after 20m13s: format, SDK baseline, boundaries, core and core-test typechecks, all core lint shards, storage/import/security guards.
  • Real CLI Gateway proof — passed with node scripts/run-node.mjs gateway --port <free> --bind loopback: /readyz returned ready, capability:tts emitted SECRETS_OWNER_UNAVAILABLE, and a present implicit TTS environment credential was not used for the failed explicit ref.
  • Full branch autoreview against current main — clean, no accepted/actionable findings.

No visual surface changed, so screenshot evidence is not applicable.

Risk and rollback

The compatibility change is intentional: known non-required owners now fail locally instead of failing whole-Gateway cold startup. The strict boundaries are covered by regressions for Gateway auth, unknown owners, invalid refs, reload/config-write preflight, and implicit fallback prevention.

Rollback is a code revert only. No config or state migration is required.

Co-authored-by: @snowzlmbot

@snowzlmbot
snowzlmbot requested a review from a team as a code owner July 7, 2026 02:00
@openclaw-barnacle openclaw-barnacle Bot added docs Improvements or additions to documentation gateway Gateway runtime extensions: tts-local-cli plugin: azure-speech Azure Speech plugin size: M labels Jul 7, 2026
@snowzlmbot
snowzlmbot force-pushed the fix/optional-tts-secret-startup branch 2 times, most recently from 08066db to cd67c9c Compare July 7, 2026 02:07
@clawsweeper

clawsweeper Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge. Reviewed July 17, 2026, 12:01 AM ET / 04:01 UTC.

Summary
The PR adds owner-aware SecretRef resolution that isolates unavailable built-in TTS and configured model-provider owners during initial Gateway startup, exposes degraded owners through status and doctor, and blocks fallback credentials when those owners are used.

PR surface: Source +615, Tests +1263, Docs +16. Total +1894 across 45 files.

Reproducibility: yes. from source with high confidence: configure an enabled TTS provider with a missing environment SecretRef and start the Gateway; current main eagerly resolves the active ref and aborts startup. The linked issue includes the resulting SecretRefResolutionError, although this review did not execute the failing current-main setup locally.

Review metrics: 2 noteworthy metrics.

  • Cold-start isolation scope: 2 owner classes added. The behavior applies to the built-in TTS capability and configured model providers, while other and unknown surfaces remain strict.
  • New configuration surface: 0 options, 0 environment variables, 0 persisted schemas. The compatibility change is implemented through runtime ownership policy rather than an additional operator setting or migration.

Stored data model
Persistent data-model change detected: migration/backfill/repair: docs/cli/doctor.md, migration/backfill/repair: docs/tools/tts.md, migration/backfill/repair: src/commands/doctor-gateway-health.test.ts, serialized state: src/commands/status.summary.test.ts, serialized state: src/gateway/server-methods/config.shared-auth.test.ts. Confirm migration or upgrade compatibility proof before merge.

Root-cause cluster
Relationship: fixed_by_candidate
Canonical: #101204
Summary: This PR is the active candidate fix for the canonical optional-SecretRef startup issue; the similarly worded closed report is a duplicate, while the persona-level collection work concerns a distinct successful-resolution path.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

Merge readiness
Overall: 🦞 diamond lobster
Proof: 🦞 diamond lobster
Patch quality: 🦞 diamond lobster
Result: ready for maintainer review.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Risk before merge

  • [P1] Merging intentionally changes upgrade behavior: a missing mapped TTS or model-provider SecretRef no longer stops initial Gateway startup, so operators can see a healthy Gateway while that configured owner remains unavailable until its credential is restored.
  • [P2] The security boundary depends on complete request-entry guards and early provider-auth rejection; future owner mappings must not permit environment or profile fallback after an explicit SecretRef fails.
  • [P1] The PR is currently behind its base and some required checks remain in progress, so the final merge result and live proof should be refreshed against the rebased exact head.

Maintainer options:

  1. Rebase and re-prove the exact head (recommended)
    Update onto current main and merge only after the required gates and live startup/no-fallback proof pass on the final head.
  2. Accept owner-local startup degradation
    Merge the deliberate policy change knowing mapped TTS and model-provider owners can be unavailable while the rest of the Gateway remains operational.
  3. Narrow the isolation scope
    Pause and retain only TTS isolation if maintainers do not want configured model providers to share the new cold-start degradation policy.

Next step before merge

  • [P2] No autonomous repair is identified; maintainers should rebase the branch and let exact-head required checks and live proof gate the normal merge path.

Security
Cleared: The security-sensitive change is bounded to mapped cold-start owners, retains strict ingress and malformed/unknown-owner handling, prevents credential fallback, redacts diagnostics, and adds no dependency or workflow execution surface.

Review details

Best possible solution:

Rebase the owner-isolation design onto current main, rerun the exact-head live startup/no-fallback proof and required gates, then land it with Gateway ingress, unknown owners, malformed values, reload, and write preflight remaining fail-closed; add future owner classes only alongside complete request guards and diagnostic coverage.

Do we have a high-confidence way to reproduce the issue?

Yes from source with high confidence: configure an enabled TTS provider with a missing environment SecretRef and start the Gateway; current main eagerly resolves the active ref and aborts startup. The linked issue includes the resulting SecretRefResolutionError, although this review did not execute the failing current-main setup locally.

Is this the best way to solve the issue?

Yes. Owner-aware cold-start isolation is more maintainable than a TTS-only exception because it centralizes the fail-open decision, retains strict behavior for unmapped and Gateway-required surfaces, and prevents alternate credential fallback at the owner boundary.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against ff9b29167352.

Label changes

Label changes:

  • add rating: 🦞 diamond lobster: Overall readiness is 🦞 diamond lobster; proof is 🦞 diamond lobster and patch quality is 🦞 diamond lobster.
  • remove rating: 🐚 platinum hermit: Current PR rating is rating: 🦞 diamond lobster, so this older rating label is no longer current.

Label justifications:

  • P0: The existing behavior can block Gateway startup and first useful operation for a community user because an optional TTS or unused provider credential is unavailable.
  • merge-risk: 🚨 compatibility: Existing installations change from whole-Gateway startup failure to owner-local configured-unavailable behavior for mapped providers and TTS.
  • merge-risk: 🚨 security-boundary: The patch selectively relaxes fail-closed startup behavior and must preserve explicit-credential ownership, redaction, and no-fallback guarantees on every affected request path.
  • rating: 🦞 diamond lobster: Overall readiness is 🦞 diamond lobster; proof is 🦞 diamond lobster and patch quality is 🦞 diamond lobster.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (live_output): Current-head automation reports successful real CLI Gateway proof showing readiness, a redacted degraded-owner warning, and rejection of implicit environment fallback after an explicit TTS ref failed.
  • proof: sufficient: Contributor real behavior proof is sufficient. Current-head automation reports successful real CLI Gateway proof showing readiness, a redacted degraded-owner warning, and rejection of implicit environment fallback after an explicit TTS ref failed.
Evidence reviewed

PR surface:

Source +615, Tests +1263, Docs +16. Total +1894 across 45 files.

View PR surface stats
Area Files Added Removed Net
Source 24 773 158 +615
Tests 16 1300 37 +1263
Docs 5 17 1 +16
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 45 2090 196 +1894

What I checked:

  • Current main still needs the fix: Current main retains eager fail-fast activation for unresolved effectively active SecretRefs; the owner-isolation implementation exists only on this PR head, so the item remains necessary. Public docs: docs/gateway/secrets.md. (docs/gateway/secrets.md:24, ff9b29167352)
  • Cold-start boundary: The startup activator enables unavailable-owner handling only for the initial startup snapshot, while reload, restart-check, and config-write preflight remain strict in the adjacent implementation and regression coverage. (src/gateway/server-startup-config.ts:323, 287ab97c75fb)
  • Owner-scoped resolution: Assignments are grouped by explicit owner policy, with mapped isolatable owners degraded atomically and unknown, required, invalid, or fail-closed assignments rejected. (src/secrets/runtime-owner-assignments.ts:1, 287ab97c75fb)
  • Fallback prevention: Model authentication checks the active degraded-provider registry before profile or environment discovery, preventing a failed explicit SecretRef from silently selecting another credential. (src/agents/model-auth.ts:1212, 287ab97c75fb)
  • Request-path isolation: Speech entry points assert runtime availability, automatic TTS preserves the text payload when unavailable, and Gateway TTS RPC returns a typed unavailable response without invoking a provider. (packages/speech-core/src/tts.ts:1028, 287ab97c75fb)
  • Secret-safe diagnostics: Status publishes owner kind, id, paths, state, and reason but deliberately omits internal ref keys; regression coverage checks that identifiers are not exposed. (src/commands/status.summary.test.ts:276, 287ab97c75fb)

Likely related people:

  • steipete: They carried the generic owner-isolation refactor, strict-boundary repairs, resolver batching and error normalization, exact-head proof, and the latest branch updates. (role: recent area contributor and branch integrator; confidence: high; commits: 81688aee485b, 5ee1e003e22a, 1297d970b94e; files: src/secrets/runtime-owner-assignments.ts, src/secrets/resolve.ts, src/gateway/server-startup-config.ts)
  • joshavant: Repository history attributes foundational external-secret management and later SecretRef coverage expansion to their work, making them relevant for the underlying runtime contract. (role: original SecretRef feature contributor; confidence: medium; commits: 806803b7e, 4e7a833a24; files: src/secrets/runtime.ts, src/config/types.secrets.ts, docs/gateway/secrets.md)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.
Review history (17 earlier review cycles; latest 8 shown)
  • reviewed 2026-07-07T08:59:28.145Z sha 19f3aa3 :: needs maintainer review before merge. :: none
  • reviewed 2026-07-07T09:07:16.159Z sha 19f3aa3 :: needs maintainer review before merge. :: none
  • reviewed 2026-07-13T13:57:21.709Z sha 62e6444 :: needs maintainer review before merge. :: none
  • reviewed 2026-07-13T19:43:43.356Z sha b895821 :: found issues before merge. :: [P1] Limit fail-open handling to the intended activation path
  • reviewed 2026-07-13T21:37:40.757Z sha 7fa0e6b :: needs real behavior proof before merge. :: [P1] Limit fail-open handling to the activating startup path
  • reviewed 2026-07-16T02:51:54.148Z sha 9a4986f :: needs maintainer review before merge. :: none
  • reviewed 2026-07-16T21:51:46.564Z sha b96708f :: needs maintainer review before merge. :: none
  • reviewed 2026-07-16T23:49:51.962Z sha b96708f :: needs real behavior proof before merge. :: none

@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P0 Emergency: data loss, security bypass, crash loop, or unusable core runtime. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. merge-risk: 🚨 security-boundary 🚨 May affect sandboxing, authorization, credentials, or sensitive data. labels Jul 7, 2026
@snowzlmbot
snowzlmbot force-pushed the fix/optional-tts-secret-startup branch 4 times, most recently from d94a892 to 2cb6b39 Compare July 7, 2026 02:38
@clawsweeper clawsweeper Bot removed rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. merge-risk: 🚨 security-boundary 🚨 May affect sandboxing, authorization, credentials, or sensitive data. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels Jul 7, 2026
@snowzlmbot
snowzlmbot force-pushed the fix/optional-tts-secret-startup branch from 2cb6b39 to 5f3452a Compare July 7, 2026 02:44
@openclaw-barnacle openclaw-barnacle Bot added the app: web-ui App: web-ui label Jul 7, 2026
@snowzlmbot
snowzlmbot force-pushed the fix/optional-tts-secret-startup branch from 5f3452a to 606539e Compare July 7, 2026 02:56
@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. merge-risk: 🚨 security-boundary 🚨 May affect sandboxing, authorization, credentials, or sensitive data. labels Jul 7, 2026
@snowzlmbot
snowzlmbot force-pushed the fix/optional-tts-secret-startup branch from 606539e to 4572dae Compare July 7, 2026 03:13
@steipete

Copy link
Copy Markdown
Contributor

Merged via squash.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling channel: googlechat Channel integration: googlechat commands Command implementations docs Improvements or additions to documentation extensions: tts-local-cli gateway Gateway runtime merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. merge-risk: 🚨 security-boundary 🚨 May affect sandboxing, authorization, credentials, or sensitive data. P0 Emergency: data loss, security bypass, crash loop, or unusable core runtime. plugin: azure-speech Azure Speech plugin proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. size: XL status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Gateway should not fail to start when optional ElevenLabs/TTS API key is missing

2 participants