Skip to content

One reason string carries two incompatible meanings: a safety refusal and a provider contract violation #1204

Description

@drewstone

The problem

retained provider execution requires reconciliation before replacement is the settle reason for two situations that call for opposite operator responses:

  • We cannot safely determine whether this execution ran. Refusing to replace it is correct. The operator must reconcile before retrying, or risk paying twice for one turn.
  • The provider sent something malformed. Nothing needs reconciling. The execution's status is not in doubt; a contract was broken and the right response is to fix or report the provider.

An operator reading a journal cannot tell which one they have. Both produce the same string, and until recently both produced it with no cause at all.

Four exhibits, three days

# Cause carried in the chain When Record
1 ZodError … "path": ["prompt"] … maximum 16384 2026-09-11 ~11:00Z discovery@master:.agent/reflections/2026-09-11-190000.md
2 RetainedRunProviderContractError: <!DOCTYPE html> … tangle.tools | 502: Bad gateway 2026-09-11 ~23:40Z issue #1203, discovery-lab@master:pursuits/mech-interp-foundations-glm2-20260911e
3 Error: Tangle session event arrived without a stable id 2026-09-12 ~01:15Z mech-interp-foundations-astra-20260911f:s74, 1 death in 79 children
4 none — Sandbox.get(id) not-found for four ids while the same account listed 34 retained sandboxes 2026-09-09 discovery@master:research/r14-provider-reconciliation-20260909.md

Exhibit 4 is the control, and it is why this is one issue rather than three. There the execution genuinely could not be reconciled: four children journalled infra:true, zero iterations, zero tokens, no output reference, and the provider could not resolve their ids at all. R14 classifies that refusal as correct — "a safety refusal to retry an admitted-but-unobservable execution". Nothing about that should change.

Exhibits 1 through 3 are a different kind: a request-schema violation, a transport error body where JSON was expected, and a provider event violating its own identity contract. In none of them is reconciliation the issue. They wear the refusal's name because they arrive on the same path.

What I think the fix is

Discriminate where the cause is still known, so a contract violation never inherits the reconciliation refusal's reason. Concretely: when the failure is a schema, transport, or identity violation, settle it as that, with the provider and the violated contract named. Reserve the reconciliation reason for the case where the execution's status is genuinely unknown.

Fixing the three exhibits separately would leave the ambiguity intact for the fourth kind that arrives next.

A note on reading the history

All four are visible only because #1188 shipped the cause chain into the settle reason in 0.213.0 at 06:07Z on 2026-09-11. Before that these read as a bare wrapper with no cause. So the apparent absence of this pattern in older journals is an observability artifact, not a frequency claim, and anyone counting occurrences from historical records will undercount.

Scope

Not asking for the refusal behaviour to change. Exhibit 4 shows it doing its job. The ask is that the reason name which of the two things happened.

Exhibits 1, 2 and 4 were assembled by the session tracking the owner/operator handoff; exhibit 3 and the live journals are from the mech-interp lanes. Both citations verified against the files before filing.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions