Skip to content

Fix fallback safety, strict error diagnostics, and metadata command cache bypass#3

Merged
ggonzalez94 merged 3 commits intomainfrom
explore
Feb 22, 2026
Merged

Fix fallback safety, strict error diagnostics, and metadata command cache bypass#3
ggonzalez94 merged 3 commits intomainfrom
explore

Conversation

@ggonzalez94
Copy link
Owner

@ggonzalez94 ggonzalez94 commented Feb 22, 2026

Summary

This PR addresses the top three reliability issues identified in the DeFi CLI deep-dive review:

  • unsafe fallback behavior when assets are unresolved
  • metadata commands failing due to cache initialization
  • missing diagnostics in strict-mode partial-result errors

Changes

  • tightened fallback safety for unresolved assets
    • DefiLlama symbol matching no longer treats an empty expected symbol as a wildcard
    • lending fallback to DefiLlama is skipped when the asset symbol cannot be safely resolved
    • yield selection skips DefiLlama for unresolved-symbol assets and fails fast when no safe provider remains
  • decoupled metadata commands from cache initialization
    • version, schema, and providers list now bypass cache open
  • preserved diagnostics in strict partial failures
    • strict-mode (exit 15) error envelopes now include provider statuses, warnings, and meta.partial=true
  • added regression tests for all three behavior changes
  • updated docs and changelog
    • README.md, AGENTS.md, and CHANGELOG.md

Validation

  • go test ./...
  • go test -race ./...
  • go vet ./...
  • smoke
    • ./defi providers list --results-only
    • ./defi lend markets --protocol aave --chain 1 --asset USDC --results-only
    • ./defi yield opportunities --chain 1 --asset USDC --providers aave,morpho --limit 5 --results-only
  • behavior checks
    • metadata commands succeed with unopenable cache paths
    • unresolved-address lend fallback fails safely (no unsafe broad match)
    • strict partial error preserves warnings/providers/partial metadata

@ggonzalez94
Copy link
Owner Author

@codex please review

@ggonzalez94 ggonzalez94 self-assigned this Feb 22, 2026
@chatgpt-codex-connector
Copy link

Codex Review: Didn't find any major issues. Keep it up!

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@ggonzalez94
Copy link
Owner Author

@cursor please review

@cursor
Copy link

cursor bot commented Feb 22, 2026

Here’s my review:

  • Build and tests: go build/test (incl. -race) and go vet all pass. Smoke commands also succeed. I verified metadata commands bypass cache even with an unopenable cache path.
  • Fallback safety: DefiLlama no longer treats empty expected symbols as wildcards, and lending fallback is gated on a resolvable symbol. Yield selection skips DefiLlama when the symbol is unresolved and fails fast if no safe provider remains. See:
if !shouldFallback(err) {
  return nil, statuses, warnings, false, err
}
if !assetHasResolvedSymbol(asset) {
  warnings = append(warnings, "fallback skipped: asset symbol could not be resolved from input")
  return nil, statuses, warnings, false, err
}
if !assetHasResolvedSymbol(req.Asset) {
  filteredProviders := make([]string, 0, len(selectedProviders))
  skippedDefiLlama := false
  for _, providerName := range selectedProviders {
    if providerName == "defillama" {
      skippedDefiLlama = true
      continue
    }
    filteredProviders = append(filteredProviders, providerName)
  }
  if skippedDefiLlama {
    warnings = append(warnings, "provider defillama skipped: unresolved asset symbol cannot be matched safely")
  }
  selectedProviders = filteredProviders
  if len(selectedProviders) == 0 {
    return nil, nil, warnings, false, clierr.New(clierr.CodeUsage, "selected providers require a resolvable asset symbol")
  }
}
func matchesAssetSymbol(symbolRaw string, expected string) bool {
  if strings.TrimSpace(expected) == "" {
    return false
  }
  symbolRaw = strings.ToUpper(strings.TrimSpace(symbolRaw))
  expected = strings.ToUpper(strings.TrimSpace(expected))
  • Metadata cache bypass: Confirmed version, schema, and providers list skip cache initialization.
func shouldOpenCache(commandPath string) bool {
  switch normalizeCommandPath(commandPath) {
  case "", "version", "schema", "providers", "providers list":
    return false
  default:
    return true
  }
}
  • Strict-mode diagnostics: Partial results in strict mode return exit 15 while preserving warnings, provider statuses, and meta.partial=true. Tested at unit level; envelope fields are correctly populated:
env := model.Envelope{
  Version: model.EnvelopeVersion,
  Success: false,
  Data:    []any{},
  Error:   &model.ErrorBody{ Code: code, Type: typ, Message: message },
  Warnings: warnings,
  Meta: model.EnvelopeMeta{
    RequestID: newRequestID(),
    Timestamp: s.runner.now().UTC(),
    Command:   commandPath,
    Providers: providers,
    Cache:     cacheMetaBypass(),
    Partial:   partial,
  },
}

Suggestions (non-blocking):

  • Add a runner-level test that exercises yield’s unresolved-symbol path (ensuring DefiLlama is filtered and usage error is raised when no providers remain).
  • Minor docs nit: In AGENTS.md, “explicitely” → “explicitly”.
  • Consider a README example showing --strict behavior with a brief note that the error envelope still contains diagnostics even with --results-only.

Overall: Changes implement the stated goals, behavior is covered by tests (with the small gap noted), and docs/changelog are aligned. Approved.

Open in Web Open in Cursor 

@ggonzalez94 ggonzalez94 merged commit 61d2801 into main Feb 22, 2026
12 checks passed
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.

1 participant