Skip to content

refactor: Stage 1 → Stage 2 boundary types in asap_types::stages (#1047 P5a) - #1086

Merged
zzylol merged 1 commit into
mainfrom
refactor/1047-p5a-stage-types
Oct 30, 2026
Merged

zzylol merged 1 commit into
mainfrom
refactor/1047-p5a-stage-types

Conversation

@zzylol

@zzylol zzylol commented Oct 30, 2026

Copy link
Copy Markdown
Contributor

Part of #1047 (step P5a) and #1054 (step 4: stage-boundary types live in asap_types::stages).

Why

P5 moves the Stage 2 catalog code from plan-selection into asap-physical-asap-optimization. That code reads Pass 2's output, but under #1054 the Stage 2 crate may not depend on the Stage 1 crate. The Stage 1 → Stage 2 boundary types therefore have to live in asap-types.

What

Move only. These items go from the logical crate to asap_types::stages:

Old path New path
asap_logical_asap_optimization::pass2::memo::{MemoGroupId, MemoGroup, CandidateGenerationTimeout, root_groups, queries_rooted_at} asap_types::stages::…
…::pass2::memo::candidates::{CandidateMemo, CandidateForMemoGroup, OriginOfCandidateForMemoGroup} (+ CandidateMemo::topological_order) asap_types::stages::…
…::pass2::logical_memo_candidates::LogicalASAPMemoCandidates asap_types::stages::LogicalASAPMemoCandidates

These stay in the logical crate because they are Stage 1 internals: DagOfLogicalMemoGroups, Pass2RoundState, the generators and rules, and PerComputationLogicalMemoCandidates.

There are no compatibility re-exports, and asap-types gains no dependency. No logic, plan or JSON changes.

How

The types move with their inherent impls; everything else is derives, which move with the types. Every user is updated (logical, plan-selection, devtools, integration-tests, docs).

MemoGroup.parents and .queries go from pub(crate) to pub, with a doc note that only Stage 1 maintains them. The logical crate builds and changes them in several places, and fields need less API than constructors and mutators would. Later stages read them through parent_groups() and reached_by_queries().

Key code interfaces added / modified

crates/types/src/stages/: every type here is the same as before, apart from its module path.

// asap_types::stages (was asap_logical_asap_optimization::pass2::{memo, memo::candidates, logical_memo_candidates})
pub struct MemoGroupId(pub u32);
pub struct MemoGroup {
    pub logical_node: Rc<OperatorNode>,   // unchanged
    pub child_groups: Vec<MemoGroupId>,   // unchanged
    pub parents: Vec<MemoGroupId>,        // was pub(crate): only Stage 1 maintains it
    pub queries: Vec<usize>,              // was pub(crate): only Stage 1 maintains it
}
pub struct CandidateMemo { /* unchanged */ }
pub struct CandidateForMemoGroup { /* unchanged */ }
pub enum OriginOfCandidateForMemoGroup { /* unchanged */ }
pub struct LogicalASAPMemoCandidates { pub memo: CandidateMemo }   // Stage 2 input
pub struct CandidateGenerationTimeout;

Usage: Pass 2 (logical crate) returns asap_types::stages::LogicalASAPMemoCandidates, and the Stage 2 catalog code reads it from asap-types. After P5, that catalog code lives in the physical crate and needs no dependency on the logical crate. Plans are unchanged.

Major algorithm changes

None.

Before / After

Before, the types passed from Stage 1 to Stage 2 were defined in the Stage 1 crate. After, they are shared types in asap-types.

Verification

At c2f146f20 (on main 41c515465):

  • fmt and clippy --workspace --all-targets -D warnings are clean.
  • cargo tree -p asap-types --edges normal --depth 1 is unchanged and contains no workspace crates.
  • Tests:
    • asap-types: 146 + 97 + 8 passed.
    • asap-logical-asap-optimization: 182 + 35 passed.
    • asap-plan-selection --lib: 344 passed.
    • asap-planner: passed.
    • asap-devtools, asap-integration-tests: passed; the known time-budget failures pass alone.
  • Corpus snapshots (release, --ignored): pass.
  • An independent review found:
    • moved bodies are identical, including topological_order;
    • no impls were dropped;
    • error chains and messages are unchanged;
    • no stale paths remain;
    • only the two documented fields are newly public.

🤖 Generated with Claude Code

… P5a)

Move the memo types that Pass 2 hands Stage 2 out of
asap-logical-asap-optimization into a new asap_types::stages module, so
the Stage 2 catalog code (P5) can read Pass 2's output without a
physical → logical crate edge (#1054 step 4).

Moved (move only, no logic change):
- pass2::memo: MemoGroupId, MemoGroup (+ parent_groups,
  reached_by_queries), CandidateGenerationTimeout, root_groups,
  queries_rooted_at
- pass2::memo::candidates: CandidateMemo (+ topological_order, formerly
  in pass2/memo/groups.rs), CandidateForMemoGroup,
  OriginOfCandidateForMemoGroup
- pass2::logical_memo_candidates: LogicalASAPMemoCandidates

MemoGroup.parents and .queries go from pub(crate) to pub: Stage 1
builds and extends the memo in many places, so this is the smallest
API; the fields' docs say later stages read them through the accessors.

Stays in the logical crate: DagOfLogicalMemoGroups, check_generation_deadline,
CandidatePopulationError, try_populate_pass1, Pass2RoundState and the
generators and rules. All users import from asap_types::stages; no
re-exports from the logical crate. asap-types gains no dependencies.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@zzylol
zzylol merged commit 7a778a6 into main Oct 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant