Repository navigation
fix: show founders what they can fix and keep Tin's internals for operators - #403
Merged
Merged
Conversation
…rators Classify every run failure as needs you, temporary, Tin's own sentence or internal (failures.py). An activity interceptor attaches the kind; workflows pass it to their failure activities behind failure-reason-v1; runs store error_kind, error_action and an operator-only error_detail (migration 063). Billing refusals get per-code wording, and HTTP and MCP bodies stop relaying library, driver and provider text. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Oct 12, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What and why
We kept fixing the same bug one workflow at a time (#212, #270, #298, #387, #388, #393, #394), and it went both ways. Some failures hid the cause a founder could act on: X voice capture said "could not confirm completion" when X needed reconnecting, and a billing refusal became "the model result is unconfirmed". Others showed Tin's internals verbatim:
KeyError: 'rows', database constraint names, sandbox SDK text, pydantic dumps. Nothing in the code separated "safe to show" from "the founder can act on it".This PR adds that distinction once, in
failures.py. Every failure is one of:error_detail.1. Classification for every run
non_retryable_error_typesbehave as before.063_run_failure_kind.sqladdserror_kind,error_actionanderror_detailtoworkflow_runs.error_detailis never returned by the API or MCP.project_failurekeeps the first message of a run that already failed, so a later generic projection no longer overwrites a specific one.get_runandlist_project_runsreturnerror_kindanderror_fix.2. Billing wording
billing_refusalreplaces per-site handling. Onlyproject_limitandrun_limitread as spending limits.insufficient_fundsandschedule_not_fundedget their own wording, andusage_pendingreads as temporary. Tin's pricing and ledger states read as internal, and API diagnostics hide them.workflow.codemodel steps and paid reads, studio, content delivery, X delivery, keyword plan, organic audit, the Ads assessment, monitor and launch, payment recovery and the AI answers ledger.3. Failure activities that dropped the cause
failure_input, behind afailure-reason-v1patch. Older histories still pass a plain run ID and keep their old wording.4. HTTP and MCP responses
detail=str(exc)now goes throughpublic_error_text. Tin's own sentences pass, including typedApplicationErrors and anything raised outside the standard library and installed packages. Library, parser, driver and provider text does not.RuntimeErrors (provider, sandbox, Temporal) but keeps input errors, so an agent can still fix its call.run_servicestops rewrapping internal errors as input errors. GitHub install and account-choice errors keep their type, so the dashboard's install prompt fires again.AGENTS.md "Failing well" now states the rule.
Verification
tests/test_failures.pycovers the classifier, billing wording, the interceptor, the workflow side, receipts, and HTTP/MCP masking. Each changed failure activity has tests for an old plain-string history, a needs-you cause and an internal cause, and each billing fix checks that a retry makes no second paid call.Notes
usage_pendingbilling refusal is now non-retryable.failures.py, and the connection-collection sentences inconnection_collection_activities.py.🤖 Generated with Claude Code