Skip to content

feat!: streaming-only — YAML is the product, linopy demoted to compat/oracle - #26

Merged
FBumann merged 4 commits into
mainfrom
feat/streaming-only
Jul 24, 2026
Merged

feat!: streaming-only — YAML is the product, linopy demoted to compat/oracle#26
FBumann merged 4 commits into
mainfrom
feat/streaming-only

Conversation

@FBumann

@FBumann FBumann commented Jul 24, 2026

Copy link
Copy Markdown
Owner

What

The repositioning decided in discussion: the streaming engine is the only runtime lane, and the interface is YAML — full stop. linopy leaves the runtime dependency graph and survives in exactly two roles: the opt-in compatibility layer and the differential-test oracle.

1. Native runner (api.py)

import linopy_yaml as ly

sol = ly.solve("model.yaml", sources={"p_max": "p_max.parquet", ...},
               coords={"snapshot": range(8760)}, memory_limit="2GB")
sol.objective
sol.primal("p")   # tidy DataFrame

Three verbs — build / solve / write_lp — that bind data sources (parquet paths, DataFrames, Series) to a YAML model and execute it. Not a modeling API: math is defined in YAML only; the relational IR is documented as internal (a stable IR-construction API may come later).

2. No fallback — strict language boundary

router.py is deleted. Constructs outside the streaming language are load errors naming the construct and its context (tests/test_language_boundary.py, formerly test_router.py). The elegant fallback machinery had become a product smell: two performance profiles and "which lane ran?" confusion.

3. Dependencies flipped

duckdb/pyarrow/highspy are core; linopy+xarray move to the [oracle] extra (included in dev). xarray imports are lazy in helpers, where_parser, and tidy_sources; parquet-path sources pass straight through to the executor.

The guarantee is tested: a subprocess test (test_api.py::test_runtime_is_linopy_free) imports the package, builds, and solves — asserting linopy and xarray never appear in sys.modules.

Breaking change

import linopy_yaml no longer patches linopy.Model. The legacy path is one line away:

import linopy_yaml.compat   # requires: pip install "linopy-yaml[oracle]"
m = Model.from_yaml("model.yaml", data={...})

ARCHITECTURE.md updated in-PR per its own convention (router removed from diagram, compat/oracle lane marked opt-in, new hard rules: linopy-never-runtime, YAML-only interface).

Suite: 135 passed. Follow-ups deferred to issues: streaming-subset completeness audit, solve-API maturation (duals, solver options, Gurobi direct sink).

🤖 Generated with Claude Code

FBumann and others added 3 commits July 24, 2026 18:21
Three-slide scrollytelling deck (problem / MVP / narrow-waist architecture)
built from SPEC §12 and issue #21, with the peak-RSS benchmark as an editable
SVG. Rendered .html/.pdf are gitignored; sources (.md + .svg) are tracked.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
macros/named expressions, piecewise-to-aux-var expansion, and the router have
all landed and read the same AST as the two backends — so built now spans 3 of
the 4 consumer families, not just backends. Add the macros transformer (was
missing) and reorder columns so the built families lead.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…/oracle

The streaming engine becomes the only runtime lane. linopy leaves the
runtime dependency graph and survives in exactly two places: the opt-in
compatibility layer (import linopy_yaml.compat patches Model.from_yaml /
.yaml — requires the new [oracle] extra) and the differential-test
oracle. A subprocess test proves import + build + solve never load
linopy or xarray.

- api.py: the runner — build/solve/write_lp bind data sources (parquet
  paths, DataFrames, Series) to a YAML model and execute it. Math is
  defined in YAML only; there is no Python modeling API, and the
  relational IR is documented as internal (a stable IR API may come
  later).
- router.py deleted: no fallback. Constructs outside the streaming
  language are load errors naming the construct and context
  (tests/test_language_boundary.py, formerly test_router.py).
- Dependencies flipped: duckdb/pyarrow/highspy are core; linopy+xarray
  move to [oracle] (and dev). xarray imports made lazy in helpers,
  where_parser, and tidy_sources; parquet-path sources pass through to
  the executor untouched.
- tidy_sources accepts parquet paths; convex-piecewise curvature checks
  run on in-memory inputs only (paths cannot be checked in process).
- ARCHITECTURE.md updated in-PR per its own rule: diagram drops the
  router, eager lane becomes the opt-in compat/oracle lane, hard rules
  3 and 6 state the linopy-never-runtime and YAML-only-interface
  positions.

BREAKING: importing linopy_yaml no longer patches linopy.Model — use
`import linopy_yaml.compat` (requires linopy-yaml[oracle]).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 24, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@FBumann, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 27 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: e9a9acba-4532-4ddd-a8d5-5618e8652b90

📥 Commits

Reviewing files that changed from the base of the PR and between 9238803 and 57c6e14.

📒 Files selected for processing (19)
  • .gitignore
  • ARCHITECTURE.md
  • docs/relational.md
  • linopy_yaml/__init__.py
  • linopy_yaml/api.py
  • linopy_yaml/compat.py
  • linopy_yaml/helpers.py
  • linopy_yaml/lowering.py
  • linopy_yaml/relational/__init__.py
  • linopy_yaml/relational/executor.py
  • linopy_yaml/router.py
  • linopy_yaml/where_parser.py
  • pyproject.toml
  • tests/conftest.py
  • tests/test_api.py
  • tests/test_language_boundary.py
  • tests/test_piecewise_block.py
  • tests/test_piecewise_convex.py
  • tests/test_schema.py
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/streaming-only

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant