pub fn find_shape<R: Shapeable>(
        &self,
        record: &R,
    ) -> Result<Shape<RiscvAirId>, CoreShapeError> {
        match record.kind() {
            // If this is a packed "core" record where the cpu events are alongisde the memory init
            // and finalize events, try to fix the shape using the tiny shapes.
            ShardKind::PackedCore => {
                // Get the heights of the core airs in the record.
                let mut heights = record.core_heights();
                heights.extend(record.memory_heights());

                let (cluster_index, shape, _) = self
                    .minimal_cluster_shape(self.partial_small_shapes.iter().enumerate(), &heights)
                    .ok_or_else(|| {
                        // No shape found, so return an error.
                        CoreShapeError::ShapeError(
                            heights
                                .iter()
                                .map(|(air, height)| (air.to_string(), log2_ceil_usize(*height)))
                                .collect(),
                        )
                    })?;

                let shard = record.shard();
                tracing::debug!("Shard Lifted: Index={}, Cluster={}", shard, cluster_index);
                for (air, height) in heights.iter() {
                    if shape.contains(air) {
                        tracing::debug!(
                            "Chip {:<20}: {:<3} -> {:<3}",
                            air,
                            log2_ceil_usize(*height),
                            shape.log2_height(air).unwrap(),
                        );
                    }
                }
                Ok(shape)
            }
            ShardKind::Core => {
                // If this is a normal "core" record, try to fix the shape as such.

                // Get the heights of the core airs in the record.
                let heights = record.core_heights();

                // Try to find the smallest shape fitting within at least one of the candidate
                // shapes.
                let log2_shard_size = record.log2_shard_size();

                let (cluster_index, shape, _) = self
                    .minimal_cluster_shape(
                        self.partial_core_shapes
                            .range(log2_shard_size..)
                            .flat_map(|(_, clusters)| clusters.iter().enumerate()),
                        &heights,
                    )
                    // No shape found, so return an error.
                    .ok_or_else(|| CoreShapeError::ShapeError(record.debug_stats()))?;

                let shard = record.shard();
                tracing::debug!("Shard Lifted: Index={}, Cluster={}", shard, cluster_index);

                for (air, height) in heights.iter() {
                    if shape.contains(air) {
                        tracing::debug!(
                            "Chip {:<20}: {:<3} -> {:<3}",
                            air,
                            log2_ceil_usize(*height),
                            shape.log2_height(air).unwrap(),
                        );
                    }
                }
                Ok(shape)
            }
            ShardKind::GlobalMemory => {
                // If the record is a does not have the CPU chip and is a global memory
                // init/finalize record, try to fix the shape as such.
                let heights = record.memory_heights();
                let shape = self
                    .partial_memory_shapes
                    .find_shape(&heights)
                    .ok_or(CoreShapeError::ShapeError(record.debug_stats()))?;
                Ok(shape)
            }
            ShardKind::Precompile => {
                // Try to fix the shape as a precompile record.
                for (&air, (memory_events_per_row, allowed_log2_heights)) in
                    self.partial_precompile_shapes.iter()
                {
                    // Filter to check that the shard and shape air match.
                    let Some((height, num_memory_local_events, num_global_events)) =
                        record.precompile_heights().find_map(|x| (x.0 == air).then_some(x.1))
                    else {
                        continue;
                    };
                    for allowed_log2_height in allowed_log2_heights {
                        let allowed_height = 1 << allowed_log2_height;
                        if height <= allowed_height {
                            for shape in self.get_precompile_shapes(
                                air,
                                *memory_events_per_row,
                                *allowed_log2_height,
                            ) {
                                let mem_events_height = shape[2].1;
                                let global_events_height = shape[3].1;
                                if num_memory_local_events
                                    .div_ceil(NUM_LOCAL_MEMORY_ENTRIES_PER_ROW) <=
                                    (1 << mem_events_height) &&
                                    num_global_events <= (1 << global_events_height)
                                {
                                    let mut actual_shape: Shape<RiscvAirId> = Shape::default();
                                    actual_shape.extend(
                                        shape
                                            .iter()
                                            .map(|x| (RiscvAirId::from_str(&x.0).unwrap(), x.1)),
                                    );
                                    return Ok(actual_shape);
                                }
                            }
                        }
                    }
                    tracing::error!(
                        "Cannot find shape for precompile {:?}, height {:?}, and mem events {:?}",
                        air,
                        height,
                        num_memory_local_events
                    );
                    return Err(CoreShapeError::ShapeError(record.debug_stats()));
                }
                Err(CoreShapeError::PrecompileNotIncluded(record.debug_stats()))
            }
        }
    }
TODO move this into the executor crate
crates/core/machine/src/shape/mod.rs