Skip to content

ExclusionReason asserts "the job finished without producing a usable file" while holding the server's own blockedReason #375

Description

@ZacxDev

Found by the systematic sweep for "the CLI disclaiming knowledge it is already holding" (the class behind #343, #346 and #367).

The claim

ExclusionReason (internal/genapi/status.go) checks !Available first:

switch {
case !o.Available:
    return "not available (the job finished without producing a usable file)"
case hasBlockedReason(o):
    return "blocked by moderation: " + strings.TrimSpace(*o.BlockedReason)
case o.Hidden:
    return "hidden (you deleted this result on the website)"
}

So for a blob carrying both available:false and blockedReason:"…", the CLI prints a specific causal claim — "the job finished without producing a usable file" — and discards the server's own moderation string, which is in the struct it already parsed (Blob.BlockedReason *string).

That sentence is not a hedge. It asserts a cause (the job ran and produced nothing) that a present blockedReason contradicts (moderation withheld it).

Why the combination is plausible — and what is NOT claimed

The platform's own predicate, vendored verbatim in Deliverable, ANDs the two independently:

output.filter((x) => x.available && !x.blockedReason && !x.hidden)

An independent AND only earns its keep if the operands vary independently. BlockedReason is modelled as a pointer specifically to keep "moderation said something" distinct from "it didn't".

🔴 No payload in this repo carries both, and I am not claiming the combination is common or even that it occurs — that would be exactly the per-key rule manufactured from one observation that item 13 and the #343 retraction forbid. The point is narrower and does not depend on frequency: the CLI should not assert a cause while holding a different one.

Note the interaction with #372 (open)

#372 rewrites this same function for #367, making the !Available branch prefer the step-level output.errors:

case !o.Available:
    if r := joinReasons(o.StepErrors); r != "" {
        return "not available (the server reported: " + r + ")"
    }
    return "not available (the job finished without producing a usable file)"

Its comment addresses the other two branches deliberately — "a moderation block and a user deletion already carry their own specific cause, and a step-level failure reason does not explain either of them" — but that reasoning is about step errors vs. the other branches. It does not cover the case here: available:false plus a per-blob blockedReason and no step errors still falls through to the fabricated generic sentence.

So this is a distinct question from #367, on the same function. It should be resolved on top of #372, not in a competing PR — which is why it is filed rather than fixed.

What would settle it

  1. Capture one real orchestrator.getWorkflow payload for a moderation-blocked output and record whether available is false or true alongside blockedReason. That is the missing evidence, and it costs no Buzz (getWorkflow is a read).
  2. Whatever it shows, the safe change is to stop discarding: when both are present, report both rather than picking one. That is correct whether or not the combination is common, and it requires no decision about which cause is "closest".

Secondary, same function, same shape

Blob.Available is a plain bool, not a pointer. An absent available key therefore decodes to false and produces the same confident sentence about a field the server never sent. Worth deciding deliberately (pointer + fail-closed, as BlockedReason already does) rather than by zero-value accident.

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