ExtendTyping:
    | { kind: "unresolved" }
    | {
        kind: "typed";
        signature: string;
        types: readonly CubeType[];
        upstream?: string;
    }
    | {
        column?: number;
        kind: "failed";
        message: string;
        signature: string;
        upstream?: string;
    }

What the engine said the columns' types are, for one input schema and one list of columns, told apart by their signature (getExtendSignature): nothing yet, a type per column, or why it couldn't type them, with the index of the column that failed when the engine named one.

upstream is what the host that typed it gave the engine for the input, digested: its relation and the model. Cube's schema can't tell everything the engine sees (an Extend's column is nullable to Cube, never empty to the engine after toOne()), so a host compares it and types again when it differs (PLAN §11.7). Cube never reads it, and doesn't save it: a loaded cube is typed again.