feat: add workload-level library integration API (#453) - #458
Merged
zzylol merged 5 commits intoSep 29, 2026
Merged
Conversation
Collaborator
|
Although I still don't understand why PlanSpace is exposed, this actually looks good to me. |
Contributor
Author
|
@Selvomega please feel free to work based on this PR, or please guide whether I should merge this PR. Thanks! |
5 tasks
Lowering turns a PlanningWorkload into pre-ASAP IR, but the optimization stage still needs the workload's demand facts — recurrence, predictability, execution time, accuracy requirement — none of which live in the IR. Today a caller carries the two halves separately and links them with a hand-built `&[usize]` whose ordering contract is easy to get wrong and never checked. ParsedWorkload holds both behind a constructor that verifies one lowered expression per normalized entry, so positional correspondence is an invariant rather than a convention. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Optimization was the hard-coded two-phase pipeline: generate candidates, then select among them. The only extension points sat inside that paradigm, so an algorithm shaped differently — a greedy MQO loop with no candidate-generation phase at all — could only be added by disguising itself as a rule. OptimizationPass states the stage's end-to-end behaviour instead: pre-ASAP IR in, post-ASAP DAG out. It names none of this crate's two-phase vocabulary, so an implementation is not obliged to have phases. MajorPass is the shipped algorithm moved behind it unchanged, which also makes ReplacementStrategy a concept of that pass rather than of the interface. The `optimize` free function is the harness callers use: it validates the input once for every pass and checks the output contract downstream consumers rely on — that the requested variant came back, that every workload entry is accounted for, and that no plan is mislabelled. A defective pass therefore fails at the boundary rather than reaching a deployment. PassRegistry resolves a pass by name for callers driven by a CLI flag, a config file, or a sweep over every registered baseline. It is caller-owned rather than a link-time global so that two tests in one binary cannot see each other's registrations, and a duplicate name is an error rather than an overwrite so a comparison run cannot silently measure one pass twice. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Embedding ASAPPlanner meant assembling the pipeline by hand: lower per query with the right frontend, search, select, then assemble once per root, and make a second call with its own arguments for the deployment half. The only facade re-exporting more than one frontend was asap-devtools, a developer-tools crate. asap-planner is that facade. `e2e_plan` takes the prepared input and returns the selected DAG per query — and the maintenance decisions too, when lifecycle input is supplied. PlanSpace and GlobalSelection no longer appear in a user's code. It is async because the SQL frontend plans through DataFusion. Two details worth calling out: - The SQL and MetricsQL frontends are driven one normalized entry at a time rather than through `lower_sql_batch`, which walks `query_batch` alone and would silently drop every repeating query — exactly the entries whose recurrence the lifecycle stage reads. - `UserInput::validate` runs before lowering and rejects a frontend that cannot lower the workload's language, a non-positive horizon, and two disagreeing planning clocks. The last would otherwise build the DAG for one instant and price it for another, with neither stage able to notice. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…pass Covers what `e2e_plan` and `OptimizationPass` are, the three interfacing types a caller meets (`UserInput`, `OptimizationInput`, `PlanOutput`), how `MajorPass` fills the stage by default and how another pass replaces it, how the three workflows in input-output-workflow.md map onto this shape, and where the code lives. Written for the architecture audience: it states the interface and the reasons behind its shape, and leaves per-call argument detail to the library reference. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Selvomega
force-pushed
the
feat/issue-453-workflow-api
branch
from
September 23, 2026 02:44
7f38955 to
815c347
Compare
Selvomega
added a commit
that referenced
this pull request
Sep 29, 2026
Cherry-pick of the PR #458 merge commit (4dd64e5) onto main. PR #458 was merged into refactor/issue-456-interface-names after that branch had already reached main via #457 and #445, so its content never landed on main. Adds the asap-planner facade crate (#429), the pluggable optimization pass (#430), and the ParsedWorkload boundary type. Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Two requirements, split out of #423:
asap-devtools, a developer-tools crate.This PR also closes #453.
What
e2e_plangives library users one call from a prepared workload to the selected Post-ASAP DAG for every query.OptimizationPassgives developers a replaceable optimization stage — not an interface users call, but the slot the stage sits in, with the shipped algorithm as one implementation.Design doc:
docs/design_docs/architecture/updated_interface_with_pluggable_optimization.md.PlanSpace,cost_sorted, andglobal_selectionare unchanged.Before this PR
Planning one SQL workload with lifecycle decisions, from a
PlanningWorkloadand a catalog:Steps 1 and 3 carry two bindings — the
Idin the roots tuple and the&[usize]inWorkloadDemand— that both have to agree withentries()order, and nothing checks that they do.After this PR
And a different algorithm replaces the stage without touching the pipeline:
How
asap-typesParsedWorkload— the frontend/optimizer boundary; its constructor checks one lowered expression per normalized entry, so the binding above is an invariant rather than a conventionasap-aware-mappingOptimizationPass,OptimizationInput,PlanOutput,PlanningModels,LifecycleInput, theoptimizeharness,PassRegistry,MajorPassasap-planner(new)e2e_plan,UserInput,FrontendInput, lowering dispatchThree points worth a reviewer's attention:
MajorPassis a move, not a rewrite. The shipped pipeline runs unchanged behind the trait. One consequence:ReplacementStrategyis now a concept ofMajorPassrather than of the optimization stage.optimizefree function is the harness. A pass is third-party code, but downstream reads every pass's output against one contract, sooptimizevalidates the input and then checks that the variant matches the request, that there is one plan per workload entry, and thatplans[k].entry_index == k. Structural only.lower_sql_batch. It walksquery_batchalone and silently drops repeating entries — exactly the ones whoseRepeatedDemandthe lifecycle stage reads.asap-planneris a separate crate because it is the only one depending on every frontend; a pass depends onasap-aware-mappingandasap-typesonly, so writing one does not pull in DataFusion.Tests
12 new tests;
cargo test --workspaceis 1190 passing, 0 failing.pass: the contract check rejects a variant the input did not ask for and a plan count that drops a query; the registry refuses a duplicate name and lists names in order.asap-planner: every query planned in entry order; repeating SQL entries lowered; a caller-supplied pass runs instead of the shipped one; the harness catches a pass that mislabelsentry_index; a frontend that cannot lower the workload's language is rejected; disagreeing planning clocks are rejected; lifecycle input selects the lifecycle variant.Not in this PR
dag_export'sreplacements) stay outside the trait — they only exist for a two-phase algorithm. Tools that want them talk toMajorPassand the candidate-search API directly.dag_exportdoes not yet take a--passflag.OptimizationPass.