ExpressionCheck:
    | { kind: "unresolved" }
    | { kind: "checked"; signature: string; upstream?: string }
    | {
        kind: "failed";
        message: string;
        resultType?: string;
        signature: string;
        upstream?: string;
    }

What the engine said of a Filter by Expression's condition, for one input schema and one lambda, told apart by their signature (getExpressionFilterSignature): nothing yet; checked, one Boolean of a row; or why not, with the condition's type when it types but isn't one Boolean (resultType, as Integer[1]).

upstream is what the host that checked it gave the engine for the input, digested, as an Extend's typing records it (PLAN §11.7, §11.11): a host compares it and checks again when it differs. Cube never reads it, and doesn't save it: a loaded cube is checked again.