chore(cli): define error actionability taxonomy#5829
Conversation
…rations Defines the CLI error actionability taxonomy for KPI reporting (CLI-1560): error kinds, categories, suggestion types, and the Q2 strict-recovery / repeat-error / internal-unknown-rate metric definitions. Classification is declared where each error is defined: every error class in apps/cli exposes a CliErrorActionabilityDeclaration under the ErrorActionabilityId symbol, enforced by an exhaustiveness test that fails when any error class lacks a declaration. Errors from workspace packages (stack, config, process-compose) and effect cli/http are classified by a small structural adapter, exhaustiveness-checked against those packages' sources. Broad wrapper errors gain structured discriminants instead of message sniffing: StackBuildError.reason, DockerPullError.daemonDown, LegacyDockerRunError.reason/daemonDown, and a typed upgradeSuggested prop threaded from legacySuggestUpgrade through the plan-gated sso, branches, and vanity-subdomains errors. No telemetry capture changes: cli_command_executed still emits only existing fields until CLI-1561 wires classification into failure events. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Supabase CLI previewnpx --yes https://pkg.pr.new/supabase/cli/supabase@db50a8e8218633dd3c5add78bbdb827ce17744adPreview package for commit |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: afd73d0c8f
ℹ️ 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".
Coverage: the drift guard now also enforces declarations on plain `extends Error` classes, and the external adapters cover the full effect cli parser error set (MissingArgument, DuplicateOption, InvalidValue), UserError unwrapping, and PlatformError/BadArgument with reason-based classification. Classification fixes from a construction-site audit of all ~420 classes: local filesystem failures mislabeled as config/input errors now classify as permission; CLI-internal declarative script failures move to internal_bug; transport failures conflated with user errors in LegacyDbQueryExecError, LegacyDeclarativeApplyError, and LegacyDomainsCnameError are split via typed discriminants; paused projects get the new open_dashboard suggestion type; and LegacyDbConfigIpv6Error's suggestion now matches the link command the CLI actually prints. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 68442e6671
ℹ️ 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".
- Coverage scan now recognizes any local `*Error("Tag")` factory (e.g. the
next login shell's LoginError), closing the drift-guard gap for NoTtyError
and LoginFailedError, which now declare auth classifications.
- classifyCliErrorActionability recurses into a StackError's preserved
tagged cause before falling back, and uses own-property adapter lookups so
sanitized tags like "constructor" cannot hit Object.prototype.
- DockerPullError.daemonDown now also covers docker spawn failures (binary
missing), not just daemon-down output.
- DeleteFunctionUnexpectedStatusError, LegacyDbQueryUnexpectedStatusError,
and LegacyLinkAuthTokenError thread the response status and classify via
statusCodeActionability, so 401s land in auth and 5xx in api_status.
- Paused projects get a dedicated project_paused category instead of
polluting plan_limit.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 11232cb803
ℹ️ 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".
…ures - classifyCliErrorActionability recurses into the classifiable preserved cause of stack wrapper errors (asset-preparation StackBuildError, DownloadError, StackError), so a daemon-down DockerPullError or a local filesystem PlatformError is no longer reported as a registry/network failure. Recursion is guarded: an unclassifiable cause keeps the wrapper's own bucket. - statusCodeActionability and the HttpClientError adapter classify 403 as user-actionable account permission (after the entitlement-gate branch, so confirmed plan gates stay plan_limit). - packages/api joins the adapter coverage scan; SupabaseApiConfigError classifies as auth/set_env_var. - LegacyStorageAuthTokenError branches on its stored status like its link twin, so api-keys 5xx responses stop counting as user login problems. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ror-actionability-colocated
The coverage guard correctly failed on the develop merge: the stop/status port and config-validation refactor introduced new error classes. Each now declares its actionability from its construction sites (workdir flags → provide_flags, config.toml content → invalid_config, docker CLI wrapper failures → docker_not_running, missing/unhealthy containers → start-stack remediation), LegacyContainerRuntimeNotFoundError is exported for guard verification, and packages/config's InvalidRemoteProjectIdError joins the external adapters as invalid_config. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
From a final multi-angle review pass: - Cause-chain recursion (ShowHelp, UserError, stack wrapper causes) is capped at depth 8, so a cyclic cause chain can never stack-overflow the failure-telemetry path; regression tests cover mutual and self cycles. - Reason-less StackBuildErrors now classify their preserved cause, so a user's ProjectConfigParseError inside "Failed to configure Edge Functions" reports invalid_config instead of an internal bug; explicit invalid_config wrappers are never overridden. The cleanup-metadata persistence site drops its invalid_config reason (it is a filesystem failure, classified from its cause). - toStackError's ServiceNotFoundError case preserves `cause` like every sibling case, so wrapped stack failures classify uniformly. - DockerPullError's spawnFailed flag resets once a later attempt spawns successfully, so a transient spawn hiccup no longer reports a genuine registry failure as docker-not-running. - The docker daemon-down matcher lives once in @supabase/stack and is imported by the legacy docker-run layer; the plan-limit-gated declaration is shared (planLimitGatedActionability) instead of triplicated. - LegacyDbQueryExecError's non-transport branch classifies as dbFinding, matching every sibling "user's own SQL failed" error. - The cname failure discriminant is null-safe. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…k gate The last commit left an unformatted line in packages/stack, which failed CI's Check code quality job (it runs the check targets across all projects) while the focused apps/cli checks were green. Fix the formatting and record the rule in AGENTS.md: multi-workspace changes must pass `npx nx run-many -t types:check lint:check fmt:check knip:check` from the repo root before the task is done, judged by the Nx Failed tasks list rather than filtered output. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: dcc2a916fe
ℹ️ 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".
…cker socket denials - Plain new Error(...) failures at the functions deploy/download Management-API status checks become FunctionsApiStatusError with statusCodeActionability, so common deploy/download failures stop reporting as unknown; messages are byte-identical. - LegacyBootstrapHealthError threads the health-poll status and classifies through the shared status helper (service-unhealthy stays api_status). - The shared docker daemon-down matcher recognizes socket permission-denied output, so a Linux user missing docker group membership classifies as a local runtime problem instead of a registry failure. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c30bd0f977
ℹ️ 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".
…se recursion - LegacyBootstrapHealthError carries a transport flag for polls that failed without an HTTP response (DNS/TLS/timeout), classifying them as network instead of api_status; service-unhealthy responses keep api_status. - DownloadError cause recursion is restricted to local filesystem PlatformError causes. HTTP causes stay on the wrapper: the HttpClientError adapter's 401/403 auth/permission policy is Management-API-specific and must not label GitHub/CDN asset-download failures as login problems. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a6d69ca20f
ℹ️ 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".
…isely - mapTransportError in functions deploy/download returns FunctionsApiTransportError (network bucket) instead of plain Error, so Management API outages during --use-api flows stop counting as unknown. - ApiError and the advisors NetworkError classes carry a decode flag set only by the response-decode catch sites, classifying 200-with-bad-body as api_status/api_response instead of network. - RemoteStack maps non-OK daemon responses into UnixHttpClientError before Effect.orDie, so a local daemon 500 classifies as a stack problem instead of a Management API status. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0309ab2c38
ℹ️ 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".
…external - LegacyBranchesFindUnexpectedStatusError treats 404 as invalid_input (not_found): a user-supplied branch name that matches nothing is a user error and belongs in the recovery funnel, not the external bucket. - LegacyStorageGatewayStatusError stops routing 401/403 through the Management-API auth policy: a tenant Storage gateway auth failure means stale local service keys, which supabase login cannot fix. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Deferred classification refinements (for CLI-1561)Recorded from the review rounds — all keep the correct
🤖 Generated with Claude Code |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: cc03e8146e
ℹ️ 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".
Un-defers the remaining review items and covers the latest round: - mapLegacyHttpError sets decode on generated-client response-decode failures, and all 59 mapper-backed *NetworkError classes (plus the snippets and config-push direct decode sites) classify decode as api_status/api_response instead of network. - Branch detail and snippets download 404s classify as invalid_input (not_found) — user-supplied identifiers, back in the recovery funnel. - UnixHttpClientError branches on the daemon RPC path: /start failures suggest starting the stack, others keep the stop remediation. - has_suggestion is reconciled at classify time with the instance's rendered suggestion field (false flips to true, never the reverse). - Invalid access tokens carry their source: env/flag-provided tokens suggest fixing the token (set_env_var) instead of supabase login, in both shells. - fetchLoginSession decode failures get the api_response fingerprint, matching fetchProfile. - Login polling exhaustion threads the last poll failure into the terminal error in both shells: 5xx classifies api_status, transport or timeout classifies network, pending 4xx keeps the auth bucket (verified against Go's uniform non-200 retry in login.go:139-157). Messages and retry behavior are byte-identical. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Update on the deferred-refinements list above: all code-actionable items (1–6) are now implemented in 47664b6 — the list stands only as review history. Item 7 (watching 🤖 Generated with Claude Code |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 47664b6e42
ℹ️ 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".
…glers - Login polling in both shells threads a decode discriminant through the retry loop: a persistent 200-with-malformed-JSON classifies as api_response instead of auth (next) or network (legacy). - Branch operation 404s (pause/unpause/delete, and update/create when not plan-gated) classify as invalid_input/not_found — ref-shaped inputs bypass the lookup, so the operation endpoint sees user-supplied refs. - LegacyLoginSaveTokenError classifies authToken: its only construction path is a provided token (--token/env/stdin), which supabase login cannot fix. - Direct decode catch sites in functions list and link pass decode (link discriminates transport from generated-client decode causes). - LegacySsoMetadataUrlNetworkError classifies provideFlags: all five sites preflight the user-supplied --metadata-url, a third-party URL whose failures do not belong in the Supabase external-service bucket. - FunctionsApiStatusError treats 404 as invalid_input/not_found — every construction site is keyed by user-supplied slugs or refs. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4e888b324d
ℹ️ 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".
- functions list 404 classifies as invalid_input/not_found: the ref came from the user or a stale link, consistent with the other functions paths. - db query --linked 400 classifies as the user's own SQL (dbFinding), the remote twin of the local exec error. - Storage gateway 404 classifies as invalid_input/not_found by status — the friendly bucket-not-found bodies are intercepted upstream, and classification stays free of body-text matching. - A native JS exception preserved as the cause of a code-UNKNOWN StackError classifies as internal_bug/panic instead of unknown, matching the top-level native-exception rule. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8da950419a
ℹ️ 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".
💡 Codex ReviewWhen cli/apps/cli/src/shared/functions/deploy.ts Line 1577 in 8da9504 In the source deploy path, For any failing TS or legacy command, this classifier is never called outside unit tests ( When remote Storage or cli/apps/cli/src/shared/telemetry/error-actionability.ts Lines 483 to 484 in 8da9504 These adapters are global, but ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
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". |
- Link and storage api-key 404s classify as invalid_input/not_found: the ref came from the user or a stale link. - functions deploy reads response text defensively and checks the status before parsing, so non-201 HTML bodies and malformed success bodies classify by status instead of as network transport; JSON-body messages are byte-identical. - RemoteStack wraps daemon body-decode failures in UnixHttpClientError (sibling of the status helper), so daemon JSON corruption classifies as a stack problem instead of a Management API response. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
cli/apps/cli/src/shared/functions/deploy.ts
Lines 1464 to 1465 in 8f9ae5b
When functions deploy --use-api preloads remote functions and the Management API returns a 200 with malformed JSON or an unexpected list shape, this branch fails with a plain Error. The classifier has no declaration for Error, so this response-shape regression is reported as unknown instead of the functions API response/status bucket; wrap this path in FunctionsApiStatusError or another tagged decode error.
ℹ️ 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".
Management API paths are keyed by user-supplied or linked identifiers, so an ungated 404 means the user-named resource was not found. statusCodeActionability now classifies it invalid_input/not_found after the entitlement-gate branch, covering projects api-keys, backups list, secrets list, snippets list, and every future status error uniformly; the twelve per-class 404 branches that duplicated this policy are removed. projects list additionally marks its malformed-200 constructions with decode so they fingerprint api_response. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 510042ce76
ℹ️ 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".
- 200-with-undecodable-body errors fingerprint api_response across functions download, postgres-config unmarshal, storage credentials missing-key, and the storage gateway parse path. - The advisors invalid-token wrapper copies the token source, so a malformed SUPABASE_ACCESS_TOKEN keeps the set_env_var remediation through the re-wrap (query/not-logged-in siblings verified unaffected). - LegacyEdgeRuntimeScriptError threads the docker discriminant from its runCapture wrap site: daemon failures classify docker_not_running, registry pulls classify network, and only genuine script/SQL failures stay dbFinding. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8b4d757d66
ℹ️ 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".
…lers - NoProjectApiKeyError and LegacyBranchesPrimaryNotFoundError fingerprint api_response: both fire on successful responses with missing expected content, matching their storage/decode siblings. - UnsafeFunctionDownloadPathError discriminates unsafe remote response paths (api_response) from local temp-file write failures (permission). - LegacyDbConfigParseUrlError classifies provideFlags: its only site is a user-supplied --db-url failing to parse, matching the other invalid database URL errors. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 18e62e84e0
ℹ️ 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".
…pper follow-ups - packages/api raises SupabaseApiInputError when the generated client's input schema rejects user-provided values before any request, and the adapter classifies it invalid_input/request_input; response decode keeps api_response. - The raw HttpClientError adapter gains the 404 -> not_found branch for parity with the shared status policy. - NoBranchNameError's declined-prompt path classifies user_cancelled; legacy branches create 409 classifies invalid_input/conflict when not plan-gated, matching the next shell's BranchAlreadyExistsError. - Docker discriminants: LegacyDockerLifecycleInspectError detects daemon-down output (status/stop), LegacyMigraDiffError threads the docker reason through the migra fallback like the edge-runtime twin. - FunctionsApiStatusError marks successful-status decode failures as api_response; LegacyDbPullDumpError splits local file-open failures (permission) from pg_dump runs (db_connection). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 055ebcbdca
ℹ️ 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".
- mapTransportError in functions deploy/download passes SupabaseApiInputError through unchanged, so a generated-client input rejection of a user flag keeps its invalid_input/request_input classification instead of network. - listRemoteFunctions' 200-decode failure constructs FunctionsApiStatusError with decode, closing the last plain-Error unknown leak on the deploy path. - Bootstrap's health mapper distinguishes generated-client body-decode causes (api_response) from genuine transport failures (network). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: db50a8e821
ℹ️ 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".
| export function classifyCliCauseActionability(cause: Cause.Cause<unknown>): CliErrorActionability { | ||
| const error = Option.getOrElse(Cause.findErrorOption(cause), () => Cause.squash(cause)); | ||
| return classifyCliErrorActionability(error); |
There was a problem hiding this comment.
Emit actionability on failed command captures
This classifier is only exercised by tests; I checked both apps/cli/src/shared/telemetry/command-instrumentation.ts and apps/cli/src/legacy/telemetry/legacy-command-instrumentation.ts, and the cli_command_executed capture still sends only exit code, duration, and output format before rethrowing failures. Since no production path calls classifyCliCauseActionability for failed exits, none of the new error_kind/error_category/error_fingerprint fields ever reach PostHog, so the KPI taxonomy remains inert for every command failure.
Useful? React with 👍 / 👎.
| return yield* Effect.fail( | ||
| new opts.networkError({ message: opts.networkMessage(String(cause)) }), | ||
| new opts.networkError({ message: opts.networkMessage(String(cause)), decode: true }), | ||
| ); |
There was a problem hiding this comment.
Preserve generated input errors in legacy HTTP mapper
When a generated client rejects request input before sending a request, this shared legacy mapper still treats the non-HttpClientError cause as a response decode failure and wraps it in the command's *NetworkError with decode: true. For example, legacy callers using mapLegacyHttpError can pass user flags into generated schemas (e.g. branches update --notify-url not-a-url fails the uri input schema), but this line reports that flag error as api_response instead of the SupabaseApiInputError invalid-input bucket; pass that error through or map it separately before the decode fallback.
Useful? React with 👍 / 👎.
| if (reasonTag === "StatusCodeError" || isErrorRecord(response)) { | ||
| return { ...actionability.apiStatus, fingerprint_suffix: "api_status" }; |
There was a problem hiding this comment.
Route HTTP body decode reasons to api_response
This branch treats any HttpClientError that carries a response as api_status, but Effect body readers can surface malformed/empty bodies as HttpClientError reasons such as DecodeError/EmptyBodyError with the response attached (the login API mapper in this PR has to special-case those same reason tags). If such a raw error escapes to the taxonomy, a 200 response with an undecodable body is fingerprinted as a status failure instead of api_response; check decode reason tags before the generic response/status branch.
Useful? React with 👍 / 👎.
| get [ErrorActionabilityId](): CliErrorActionabilityDeclaration { | ||
| return actionability.externalNetwork; | ||
| } |
There was a problem hiding this comment.
Pass through function-delete input errors
Fresh evidence after the deploy/download fix: deleteFunction still has its own mapper in shared/functions/delete.ts that wraps every non-HttpClientError in DeleteFunctionNetworkError. In the next shell, an explicit malformed --project-ref is returned without local validation, so v1DeleteAFunction can fail its generated input schema before any request; this getter then records a user flag error as external network. Pass through SupabaseApiInputError (as deploy/download now do) before using this network bucket.
Useful? React with 👍 / 👎.
| get [ErrorActionabilityId](): CliErrorActionabilityDeclaration { | ||
| return actionability.dbFinding; | ||
| } |
There was a problem hiding this comment.
Preserve pg-delta edge-runtime Docker failures
Fresh evidence after the edge-runtime-script fix: legacy-pgdelta.ts still maps LegacyEdgeRuntimeScriptError into LegacyDeclarativeEdgeRuntimeError by copying only message, dropping the newly added docker discriminator. When db diff/db pull/declarative export hit a daemon-down or registry-pull failure through this pg-delta wrapper, this unconditional dbFinding classification reports it as user SQL/schema instead of Docker/network; carry the discriminator through this wrapper too.
Useful? React with 👍 / 👎.
| get [ErrorActionabilityId](): CliErrorActionabilityDeclaration { | ||
| return actionability.startStack; | ||
| } |
There was a problem hiding this comment.
Preserve shadow DB Docker-daemon failures
Fresh evidence after the Docker inspect fix: the declarative shadow-DB seam bypasses legacyInspectContainerState and wraps docker container inspect failures directly in LegacyDeclarativeShadowDbError; if the Docker daemon is stopped, the stderr is not distinguished from a missing local stack. This unconditional startStack bucket points users at supabase start even though the required remediation is starting Docker, so thread a daemon-down discriminator (or reuse the shared inspect helper) before classifying this error.
Useful? React with 👍 / 👎.
Defines the CLI error actionability taxonomy for KPI reporting (CLI-1560). Replaces #5775 with an architecture where classification lives on the error types themselves instead of a centralized tag registry.
What
apps/cli/src/shared/telemetry/error-actionability.ts):error_kind,error_category,suggestion_typeenums, the sanitizedCliErrorActionabilitycontract, and the Q2 metric definitions (strict recovery, repeat error, internal/unknown bug rate).apps/cli(391 classes) declares its own classification via a getter under theErrorActionabilityIdsymbol, next to the message/suggestion it already carries. Instance-dependent cases branch on typed fields (statusCodeActionability(this.status, { upgradeSuggested })), never on message text.TaggedErrorinapps/cli/srcand fails if one lacks a declaration (or isn't exported for verification), and checks that every error tag inpackages/{stack,config,process-compose}has an external adapter. A productionunknownclassification now means "genuinely unforeseen failure", not registry drift.StackBuildError.reason(invalid_config/asset_preparation),DockerPullError.daemonDownandLegacyDockerRunError.reason/daemonDown(detected at the docker boundary where the output is produced), and a typedupgradeSuggestedprop threaded fromlegacySuggestUpgradeinto the plan-gated sso/branches/vanity-subdomains errors — noObject.definePropertyside-channel, no sniffing user-facing English for "upgrade"/"billing"/"quota".Why the different architecture vs #5775
The centralized
actionabilityByTagmap re-stated, far from each definition, facts each error already knows about itself. It covered 229 of 407 tags after 169 review-comment rounds, and any new error silently fell through tounknown— inflating the exact KPI numerator this project is meant to measure. With co-location the classification is reviewed in the same diff that introduces an error, and the coverage test turns "we forgot to classify" into a CI failure instead of a data-quality bug.Scope notes
cli_command_executedstill emits only existing fields. Wiring classification into failure events (and command-name attribution for pre-handler failures) is CLI-1561.has_suggestion/suggestion_typefrom the code path that renders suggestions, so telemetry can never disagree with what the user saw.🤖 Generated with Claude Code