Skip to content

Guide the fix for a provider failure where it shows up - #2128

Merged
ppXD merged 1 commit into
mainfrom
fix/guide-the-fix-for-a-provider-failure
Oct 18, 2026
Merged

ppXD merged 1 commit into
mainfrom
fix/guide-the-fix-for-a-provider-failure

Conversation

@ppXD

@ppXD ppXD commented Oct 18, 2026

Copy link
Copy Markdown
Owner

Summary

  • A run that fails on a provider connection (credential disconnected or refused, GitLab rejecting a token, an address that redirects, a push the remote refused, a sign-in that could not be renewed) now records a machine-readable failure beside its sentence, and the run detail answers with a remedy computed for the caller: what is wrong in plain language, the credential and repository it names, and which fixes this person may press (Re-link, Reconnect, Replace token, Edit provider address, Open Providers, Re-run) or whom to ask. The page renders it as a remediation card in the warm theme; a refused webhook delivery gets the same card on the repository's delivery history.
  • The remedy only offers what the endpoint behind it accepts: reconnecting a sign-in needs credentials.manage (as starting an OAuth connect does), replacing a pasted token needs the credential's own person or credentials.manage, an address edit is offered only when UpdateProviderInstanceCommand would take it (nothing connected through the provider, or an http to https upgrade of the same host), otherwise the sentence says what works.
  • The failure is the one the node that ended the run recorded (or that node's agent run); a failure the run handled, or met before it was abandoned, does not speak for it. The git write nodes that word a provider 401 themselves keep the exception beside their sentence, so the 401 is recorded without changing what they say or how they retry.
  • A renewal or a standing lookup the provider did not answer blames nobody and sends nobody to repair a credential nobody refused; the refusal row keeps which lookup failed in its existing request metadata column.
  • The Providers dialog lists every credential with its health and bound repositories, a repository row says when its credential is not healthy whatever its status, and Re-link offers only the caller's own and the team's credentials. No migration; older rows and older clients render as before.

Test plan

  • Unit (full suite, 14707 passed): per-code, per-role action matrix; redirect repair agrees with the update endpoint's own rule; copy per code and per lookup cause; capture of the OAuth error code; wire strings pinned
  • Integration (high fidelity, real engine and Postgres, GitLab stub or loopback only): dead OAuth grant, revoked token, disconnected credential, renewal GitLab did not answer, six git write nodes on a 401, redirect repaired through the real update and disconnect commands, handled failure then another failure, abandoned run, agent-run correlation, per-role remedies, masked base URL, standing refusals per cause
  • HTTP E2E (high fidelity, real pipeline): the run detail's Reconnect state matches what the OAuth init endpoint answers the credential's own Member; remedy wire shape for an Owner, a Member and a Viewer; old rows unchanged
  • Frontend: vitest 2682 passed (card per code and role, repository row Reconnect vs Replace token, no-fault and unrepairable-redirect cards), pnpm lint 0 errors, tsc --noEmit -p tsconfig.app.json, pnpm build
  • Staging: reconnect a dead OAuth grant from the run card as an Admin and re-run; confirm a Member owner sees Reconnect under "Not yours to do"

A run that failed on a provider connection (a credential disconnected or
refused, GitLab rejecting a token, an address that redirects, a push the
remote refused) said so in a sentence nobody could act on: the run page
printed it, the room sent people to their MODEL credentials because the
sentence contains the word "credential", the Providers dialog hid every
credential that was not Active, Re-link existed only for a repository
already in Error, and a refused webhook delivery read as an unrecognised
reason. The fix existed (reconnect in place, replace a token, re-link,
correct the address); nothing connected the failure to it.

A failure that a person can repair outside the run is now written down
as what it is. The node's node.failed record, a bootstrap run.failed
record and an agent run's stored result carry an additive failure
object: its code and the identifiers it names, taken from the
exception's own IFailure details and the repository the node declares it
acts on. The git write nodes that word a provider 401 themselves keep
the exception beside their sentence, so the failure is recorded without
changing what they say or how they retry. Nothing is stored that the API
response for the same failure did not already carry. No migration; an
older reader ignores the key and an older row simply has none.

The run's failure is the one the node that ENDED it recorded, or that
node's agent run: a provider failure the run handled with an error edge,
or one met before a run the reconciler abandoned, says nothing about why
it ended.

Read at request time, a remedy says what is wrong in plain language,
names the credential and the repository, and lists what the asking
person may do about it under the endpoints' own rules (re-link and a
provider's address need repos.manage, replacing a pasted token needs the
credential's own person or credentials.manage, reconnecting a sign-in
needs credentials.manage because starting an OAuth connect does), with
the Owners and Admins to ask when it is not theirs. It offers only a
repair the server will accept: an address edit is offered when the
update would be (nothing connected through the provider, or an http to
https upgrade of the same host), else the sentence says what works. A
renewal or a standing lookup the provider did not answer blames nobody;
the refusal row keeps which lookup failed so the two are told apart. It
reads "resolved" once the credential works again, so the page leads with
Re-run. It is never cached with the room's turn, which carries only the
failure's code. The run detail carries it, a lean read serves the room,
and a repository's refused deliveries carry one for the two refusals
that blame its credential.

The run page shows a remediation card in the room's attention palette:
only what the caller may press is a button, the rest is a line saying
whose it is. The Providers dialog lists every credential with its health
and how many repositories hang on it, a repository row on the team,
project and repository pages says when its credential is not healthy
whatever its status, and Re-link offers only the caller's own and the
team's credentials, as Add Repository does.
@ppXD
ppXD merged commit 46d4ea5 into main Oct 18, 2026
8 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