Skip to content

chore(cli): define error actionability taxonomy#5829

Open
jgoux wants to merge 21 commits into
developfrom
julien/cli-1560-error-actionability-colocated
Open

chore(cli): define error actionability taxonomy#5829
jgoux wants to merge 21 commits into
developfrom
julien/cli-1560-error-actionability-colocated

Conversation

@jgoux

@jgoux jgoux commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

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

  • Taxonomy (apps/cli/src/shared/telemetry/error-actionability.ts): error_kind, error_category, suggestion_type enums, the sanitized CliErrorActionability contract, and the Q2 metric definitions (strict recovery, repeat error, internal/unknown bug rate).
  • Co-located declarations: every error class in apps/cli (391 classes) declares its own classification via a getter under the ErrorActionabilityId symbol, next to the message/suggestion it already carries. Instance-dependent cases branch on typed fields (statusCodeActionability(this.status, { upgradeSuggested })), never on message text.
  • Exhaustiveness tests: a coverage test enumerates every TaggedError in apps/cli/src and fails if one lacks a declaration (or isn't exported for verification), and checks that every error tag in packages/{stack,config,process-compose} has an external adapter. A production unknown classification now means "genuinely unforeseen failure", not registry drift.
  • Structured discriminants instead of string sniffing: StackBuildError.reason (invalid_config / asset_preparation), DockerPullError.daemonDown and LegacyDockerRunError.reason/daemonDown (detected at the docker boundary where the output is produced), and a typed upgradeSuggested prop threaded from legacySuggestUpgrade into the plan-gated sso/branches/vanity-subdomains errors — no Object.defineProperty side-channel, no sniffing user-facing English for "upgrade"/"billing"/"quota".
  • External adapter: a small structural adapter classifies the 27 error tags from workspace packages plus effect cli/http errors, kept exhaustive by test.

Why the different architecture vs #5775

The centralized actionabilityByTag map 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 to unknown — 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

  • No telemetry capture changes: cli_command_executed still emits only existing fields. Wiring classification into failure events (and command-name attribution for pre-handler failures) is CLI-1561.
  • No Go changes: the Go CLI is being removed; the KPI targets the TypeScript CLI.
  • Follow-up opportunity for CLI-1561: derive has_suggestion/suggestion_type from the code path that renders suggestions, so telemetry can never disagree with what the user saw.

🤖 Generated with Claude Code

…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>
@jgoux jgoux requested a review from a team as a code owner July 8, 2026 12:22
@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Supabase CLI preview

npx --yes https://pkg.pr.new/supabase/cli/supabase@db50a8e8218633dd3c5add78bbdb827ce17744ad

Preview package for commit db50a8e.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread apps/cli/src/shared/telemetry/error-actionability-coverage.unit.test.ts Outdated
Comment thread apps/cli/src/shared/telemetry/error-actionability.ts Outdated
Comment thread packages/stack/src/StackPreparation.ts Outdated
Comment thread apps/cli/src/shared/telemetry/error-actionability.ts Outdated
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>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread apps/cli/src/shared/functions/delete.errors.ts Outdated
Comment thread apps/cli/src/legacy/commands/db/query/query.errors.ts Outdated
Comment thread apps/cli/src/legacy/commands/link/link.errors.ts Outdated
Comment thread apps/cli/src/legacy/commands/link/link.errors.ts Outdated
- 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>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread apps/cli/src/legacy/shared/legacy-storage-credentials.errors.ts
Comment thread packages/stack/src/StackLifecycleCoordinator.ts
Comment thread apps/cli/src/shared/telemetry/error-actionability.ts
Comment thread apps/cli/src/shared/telemetry/error-actionability.ts
jgoux and others added 5 commits July 8, 2026 17:40
…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>
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>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread apps/cli/src/legacy/commands/login/login.errors.ts
Comment thread apps/cli/src/next/commands/login/login.errors.ts
Comment thread apps/cli/src/legacy/commands/bootstrap/bootstrap.errors.ts
Comment thread packages/stack/src/errors.ts Outdated
…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>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread apps/cli/src/legacy/commands/bootstrap/bootstrap.errors.ts Outdated
Comment thread apps/cli/src/shared/telemetry/error-actionability.ts
…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>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread apps/cli/src/next/auth/errors.ts Outdated
Comment thread apps/cli/src/shared/telemetry/error-actionability.ts
Comment thread apps/cli/src/legacy/commands/db/advisors/advisors.errors.ts Outdated
…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>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread apps/cli/src/shared/telemetry/error-actionability.ts Outdated
Comment thread apps/cli/src/legacy/commands/branches/branches.errors.ts Outdated
Comment thread apps/cli/src/legacy/commands/branches/branches.errors.ts
Comment thread apps/cli/src/next/auth/api.layer.ts Outdated
Comment thread apps/cli/src/legacy/auth/legacy-errors.ts Outdated
Comment thread apps/cli/src/legacy/shared/legacy-storage-gateway.errors.ts
…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>
@jgoux

jgoux commented Jul 9, 2026

Copy link
Copy Markdown
Contributor Author

Deferred classification refinements (for CLI-1561)

Recorded from the review rounds — all keep the correct error_kind, so none affect the headline KPI metrics (recovery / repeat / internal-unknown rate). Pick up during instrumentation if baseline data shows volume:

  1. UnixHttpClientError remediation by RPC path — daemon RPC failures all suggest stop-stack; a POST /start failure arguably wants a start/build bucket. Right fix is operation-specific tagged errors in RemoteStack, not path-string branching in the classifier.
  2. mapLegacyHttpError decode-vs-transport split — generated-client SchemaError/HttpBodyError from a malformed 200 lands in each command's *NetworkError (network) instead of api_response. Fix once in the mapper.
  3. fetchLoginSession decode failures — same split; barely surfaces because login polling wraps and retries into LoginFailedError.
  4. Invalid-token remediation by sourcesupabase login is the wrong suggestion when the bad token comes from SUPABASE_ACCESS_TOKEN; needs token-source threading through the auth layer to pick login vs set_env_var.
  5. has_suggestion render reconciliation — reconcile the declaration-level claim at capture time with whether the output layer actually rendered a suggestion (noted in error-actionability.ts docs).
  6. Login polling exhaustion discrimination — separating "user never completed the browser flow" from platform outage needs the login-session endpoint's pending semantics; check the baseline distribution of tag:LoginFailedError first.
  7. Watch error:Error fingerprints in production — any remaining plain-Error failure sites the coverage guard can't see will surface under this fingerprint in the baseline.

🤖 Generated with Claude Code

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread apps/cli/src/legacy/commands/branches/branches.errors.ts
Comment thread apps/cli/src/legacy/commands/snippets/snippets.errors.ts
Comment thread apps/cli/src/legacy/commands/snippets/snippets.errors.ts Outdated
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>
@jgoux

jgoux commented Jul 9, 2026

Copy link
Copy Markdown
Contributor Author

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 error:Error fingerprints in the baseline) remains the one genuinely data-phase task for CLI-1561, alongside capture-time has_suggestion reconciliation for message-conveyed remediations (the instance-level suggestion field is now reconciled at classify time).

🤖 Generated with Claude Code

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread apps/cli/src/next/commands/login/login.handler.ts
Comment thread apps/cli/src/legacy/shared/legacy-login-api.layer.ts Outdated
Comment thread apps/cli/src/legacy/commands/branches/branches.errors.ts
Comment thread apps/cli/src/legacy/commands/login/login.errors.ts Outdated
Comment thread apps/cli/src/legacy/commands/functions/list/list.errors.ts
Comment thread apps/cli/src/legacy/commands/link/link.errors.ts Outdated
Comment thread apps/cli/src/legacy/commands/sso/sso.errors.ts Outdated
Comment thread apps/cli/src/shared/functions/download.ts
…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>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread apps/cli/src/legacy/commands/functions/list/list.errors.ts
Comment thread apps/cli/src/legacy/commands/db/query/query.errors.ts
Comment thread apps/cli/src/legacy/shared/legacy-storage-gateway.errors.ts
Comment thread apps/cli/src/shared/telemetry/error-actionability.ts
- 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>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread apps/cli/src/legacy/commands/link/link.errors.ts
Comment thread apps/cli/src/shared/functions/deploy.ts
Comment thread apps/cli/src/shared/telemetry/error-actionability.ts
Comment thread apps/cli/src/legacy/shared/legacy-storage-credentials.errors.ts
Comment thread apps/cli/src/shared/telemetry/error-actionability.ts
@chatgpt-codex-connector

Copy link
Copy Markdown

💡 Codex Review

return statusCodeActionability(this.status);

P2 Badge Classify link api-key 404s as input

When supabase link --project-ref is mistyped or points at a non-existent ref, classifyProjectError in link.handler.ts treats the initial getProject 404 as a possible branch and then proceeds to getProjectApiKeys; a 404 from that api-keys request is wrapped as LegacyLinkAuthTokenError and this generic status mapping records it as external_service/api_status. In that scenario the actionable problem is the supplied ref not being found, so special-case 404 here as invalid input/not found before falling through to the generic status policy.


new FunctionsApiStatusError({

P2 Badge Preserve deploy response decode status

In the source deploy path, uploadFunctionSource yields response.body from raw.json before reaching this status wrapper; if the Management API returns a 201 with malformed JSON, or a non-201 HTML/plain-text error body, the JSON decode fails through mapTransportError and this new FunctionsApiStatusError is never constructed. Those response-shape/status failures are then recorded as network transport errors, so check the HTTP status before parsing JSON or carry a decode/status signal for raw.json failures.


export function classifyCliCauseActionability(cause: Cause.Cause<unknown>): CliErrorActionability {

P1 Badge Emit actionability on failed command events

For any failing TS or legacy command, this classifier is never called outside unit tests (rg classifyCliCauseActionability only finds tests and this export), while both command instrumentation wrappers still capture cli_command_executed with only exit/duration/output-format data. The new taxonomy therefore never reaches telemetry, so the recovery/repeat/error-kind KPIs see no error_kind or error_fingerprint; enrich failed captures from exit.cause before re-failing.


return statusCodeActionability(this.status);

P2 Badge Classify storage api-key 404s as input

When remote Storage or seed buckets --linked resolves credentials without SUPABASE_AUTH_SERVICE_ROLE_KEY, legacyResolveStorageCredentials calls getProjectApiKeys with the user-provided or stale linked project ref; a 404 from that endpoint means that ref was not found. This mapping sends the status through the generic Management API policy as external_service/api_status, so common bad refs pollute the API-status bucket instead of invalid-input/not-found.


HttpBodyError: () => ({ ...actionability.apiStatus, fingerprint_suffix: "api_response" }),
SchemaError: () => ({ ...actionability.apiStatus, fingerprint_suffix: "api_response" }),

P2 Badge Keep daemon decode failures in stack bucket

These adapters are global, but RemoteStack also runs HttpClientResponse.schemaBodyJson(...) against the local Unix-socket daemon after the status wrapper; if a detached daemon returns a 200 with malformed or version-skewed JSON for /status, logs, or service state, the resulting SchemaError/HttpBodyError is classified as a Management-API response problem. Wrap daemon body-decode failures in a daemon/stack tagged error before they reach this generic generated-client adapter so local daemon corruption does not inflate the external API-response bucket.

ℹ️ 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".

- 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>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

new Error(
`failed to read functions list: ${error instanceof Error ? error.message : String(error)}`,

P2 Badge Tag deploy list decode failures

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".

Comment thread apps/cli/src/legacy/commands/projects/projects.errors.ts
Comment thread apps/cli/src/legacy/commands/projects/projects.errors.ts
Comment thread apps/cli/src/legacy/commands/backups/backups.errors.ts
Comment thread apps/cli/src/legacy/commands/secrets/secrets.errors.ts
Comment thread apps/cli/src/legacy/commands/snippets/snippets.errors.ts
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>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread apps/cli/src/shared/telemetry/error-actionability.ts
Comment thread apps/cli/src/shared/telemetry/error-actionability.ts
Comment thread apps/cli/src/shared/functions/download.errors.ts Outdated
Comment thread apps/cli/src/legacy/commands/postgres-config/postgres-config.errors.ts Outdated
Comment thread apps/cli/src/legacy/shared/legacy-storage-credentials.errors.ts Outdated
Comment thread apps/cli/src/legacy/commands/db/advisors/advisors.errors.ts Outdated
Comment thread apps/cli/src/legacy/shared/legacy-edge-runtime-script.errors.ts
Comment thread apps/cli/src/legacy/shared/legacy-storage-gateway.errors.ts Outdated
- 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>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread apps/cli/src/next/config/project-link-remote.layer.ts Outdated
Comment thread apps/cli/src/shared/functions/download.errors.ts
Comment thread apps/cli/src/legacy/commands/branches/branches.errors.ts Outdated
Comment thread apps/cli/src/legacy/shared/legacy-db-config.errors.ts Outdated
…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>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread apps/cli/src/shared/telemetry/error-actionability.ts
Comment thread apps/cli/src/shared/telemetry/error-actionability.ts
Comment thread apps/cli/src/next/commands/branches/errors.ts
Comment thread apps/cli/src/legacy/shared/legacy-docker-lifecycle.ts
Comment thread apps/cli/src/legacy/commands/db/shared/legacy-migra.errors.ts
Comment thread apps/cli/src/shared/functions/functions-api.errors.ts
Comment thread apps/cli/src/legacy/commands/branches/branches.errors.ts
Comment thread apps/cli/src/legacy/commands/db/pull/pull.errors.ts
…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>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread apps/cli/src/shared/functions/functions-api.errors.ts
Comment thread apps/cli/src/legacy/commands/login/login.errors.ts
Comment thread apps/cli/src/shared/functions/deploy.ts
Comment thread apps/cli/src/legacy/commands/bootstrap/bootstrap.handler.ts Outdated
- 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>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment on lines +717 to +719
export function classifyCliCauseActionability(cause: Cause.Cause<unknown>): CliErrorActionability {
const error = Option.getOrElse(Cause.findErrorOption(cause), () => Cause.squash(cause));
return classifyCliErrorActionability(error);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge 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 👍 / 👎.

Comment on lines 102 to 104
return yield* Effect.fail(
new opts.networkError({ message: opts.networkMessage(String(cause)) }),
new opts.networkError({ message: opts.networkMessage(String(cause)), decode: true }),
);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge 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 👍 / 👎.

Comment on lines +497 to +498
if (reasonTag === "StatusCodeError" || isErrorRecord(response)) {
return { ...actionability.apiStatus, fingerprint_suffix: "api_status" };

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge 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 👍 / 👎.

Comment on lines +28 to +30
get [ErrorActionabilityId](): CliErrorActionabilityDeclaration {
return actionability.externalNetwork;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge 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 👍 / 👎.

Comment on lines +21 to +23
get [ErrorActionabilityId](): CliErrorActionabilityDeclaration {
return actionability.dbFinding;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge 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 👍 / 👎.

Comment on lines +37 to +39
get [ErrorActionabilityId](): CliErrorActionabilityDeclaration {
return actionability.startStack;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge 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 👍 / 👎.

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