Skip to content

All repair warnings treated as fatal convergence errors even when non-blocking #83889

@davinci282828

Description

@davinci282828

Severity: low / Confidence: medium / Category: api-contract
Triage: contract-mismatch
Detected against: openclaw v2026.5.18 (latest stable at time of scan, 2026-05-18)
Tooling: clawpatch 0.3.0 + acpx/claude-sonnet-4-5 via Brad Mills protocol

Evidence

  • src/cli/update-cli/post-core-plugin-convergence.ts:60-85 (runPostCorePluginConvergence)
const warnings: PostCoreConvergenceWarning[] = repair.warnings.map((message) => ({
    reason: message,
    message,
    guidance: [REPAIR_GUIDANCE],
  }));
  ...
  return {
    changes: repair.changes,
    warnings,
    errored: warnings.length > 0,
    smokeFailures: smoke.failures,
    installRecords: records,
  };

Reasoning

repairMissingConfiguredPluginInstalls can emit informational warnings (e.g. a plugin that was already up-to-date, a no-op repair). All such messages are appended to warnings before the smoke failures, and errored: warnings.length > 0 fires on ANY non-empty warning list. This means a purely informational repair observation blocks the gateway restart. The downstream convergenceWarningsToOutcomes propagates errored to set the plugin update status: 'error', which the outer caller uses for exit 1. The confidence is medium because the contract of repair.warnings from repairMissingConfiguredPluginInstalls cannot be fully verified from these files alone — if repair.warnings are always actionable, this is correct.

Reproduction

Trigger a repair run that emits a warning that is not a hard failure (e.g. a plugin repair that partially succeeds with a note). The update will refuse to restart.

Recommendation

Distinguish fatal convergence failures from soft repair observations. Either: (a) have repairMissingConfiguredPluginInstalls return a structured result with errors vs warnings, or (b) set errored: smoke.failures.length > 0 || repair.errors?.length > 0 rather than keying off total warning count. Document in PostCoreConvergenceResult whether errored is set only on hard failures.

Why existing tests miss this

No tests exist for runPostCorePluginConvergence.

Suggested regression test

it('errored is false when only soft repair warnings exist and smoke passes', async () => { /* mock repairMissingConfiguredPluginInstalls to return warnings:['note'] and runPluginPayloadSmokeCheck to return no failures */ const result = await runPostCorePluginConvergence(...); expect(result.errored).toBe(false); });

Minimum fix scope

Clarify the contract of repair.warnings and key errored only on genuine hard failures (smoke failures + repair errors), not soft warnings.


Standardized clawpatch finding. Persistent in v2026.5.18 (not resolved by upgrading from v2026.5.12). Finding ID: fnd_sig-feat-cli-command-0e1f16a0ce-_3cbd805bec.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Normal backlog priority with limited blast radius.clawsweeper:fix-shape-clearClawSweeper found a clear likely implementation shape for this issue.clawsweeper:queueable-fixClawSweeper marked this issue as an existing queue_fix_pr work candidate.clawsweeper:source-reproClawSweeper found a high-confidence source-level issue reproduction.impact:crash-loopCrash, hang, restart loop, or process-level availability failure.issue-rating: 🦞 diamond lobsterVery strong issue quality with high-confidence source-level or clear reproduction.

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions