Skip to content

Fix 4 independent bugs#271

Open
SutubraResearch wants to merge 7 commits intoTemoaProject:unstablefrom
SutubraResearch:pr/bug-fixes
Open

Fix 4 independent bugs#271
SutubraResearch wants to merge 7 commits intoTemoaProject:unstablefrom
SutubraResearch:pr/bug-fixes

Conversation

@SutubraResearch
Copy link
Collaborator

@SutubraResearch SutubraResearch commented Mar 11, 2026

Summary

Four independent bug fixes found during large-scale national model testing:

  • output_curtailment FK: The foreign key on t_season referenced time_period instead of season_label, causing integrity errors when writing curtailment results
  • limit_capacity_constraint index: Missing check for (region, period, tech) in capacity sets caused KeyError when a technology appeared in MaxCapacity/MinCapacity but had no active vintages
  • loan_lifetime_process myopic KeyError: In myopic window 2+, the v >= min(vintage_optimize) filter excluded previously optimized vintages that were still in myopic_efficiency, causing KeyError during param construction
  • Season ramp for seasonal_timeslices: ramp_up/down_season_constraint_indices only skipped for consecutive_days mode. In seasonal_timeslices mode, seasons are not temporally adjacent so inter-season ramps are meaningless — added to the skip condition

Files changed

File Change
temoa/db_schema/temoa_schema_v4.sql FK target correction
temoa/components/limits.py Index existence check
temoa/components/costs.py Remove min_period filter
temoa/components/operations.py Add seasonal_timeslices to skip condition
tests/legacy_test_values.py Mediumville constraint count -8 (season ramp)

Test plan

  • All 190 tests pass
  • Each fix is independent and can be reviewed separately
  • Season ramp fix reduces mediumville constraints by 8 (4 up + 4 down) as expected

Summary by CodeRabbit

  • Bug Fixes

    • Include all efficiency vintages in lifetime loan processing.
    • Refine capacity constraints to ignore nonexistent vintages and skip empty constraints.
    • Disable seasonal ramp rules for seasonal timeslice sequencing.
  • Database

    • Fix foreign key for output curtailment season to reference season labels.
  • Tests

    • Update test datasets and expected constraint counts to align with behavior changes.

The output_curtailment table's foreign key on t_season incorrectly
referenced time_period instead of season_label. This caused an
integrity error when writing curtailment results for any scenario
with seasonal resolution.
The constraint index function did not verify that the (region, period,
tech) tuple existed in the relevant capacity sets before building
indices. This caused a KeyError when a technology appeared in
MaxCapacity or MinCapacity but had no active vintages in the current
optimization window.
In myopic window 2+, previously optimized vintages remain active in
myopic_efficiency but were excluded from loan_lifetime_process by the
v >= min(vintage_optimize) filter. This caused a KeyError during
Pyomo param construction when filtered data included those vintages.

Remove the min_period filter to match lifetime_process_indices, which
already accepts all efficiency vintages without restriction.
@coderabbitai
Copy link

coderabbitai bot commented Mar 11, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 174afc82-2b9d-44d9-8d0b-4a98a07ecb68

📥 Commits

Reviewing files that changed from the base of the PR and between c137019 and ba32996.

📒 Files selected for processing (3)
  • data_files/temoa_schema_v4.sql
  • temoa/components/limits.py
  • temoa/components/operations.py

Walkthrough

Adjusts vintage filtering and constraint guards in core components, disables season-ramp entries for seasonal time sequencing in tests, updates the curtailment season foreign key to reference seasons, and updates test datasets’ vintage/capacity mappings.

Changes

Cohort / File(s) Summary
Constraint & vintage logic
temoa/components/costs.py, temoa/components/limits.py
lifetime_loan_process_indices now accepts all efficiency vintages (no min-period filter). Capacity constraint sums now iterate only existing model.process_vintages triplets and return Constraint.Skip when expressions are empty/boolean.
Season ramp skipping
temoa/components/operations.py, tests/testing_data/mediumville_sets.json, tests/legacy_test_values.py
Ramp-up/down season constraint functions now skip when model.time_sequencing.first() is in ('consecutive_days','seasonal_timeslices'). Corresponding test data: mediumville season-ramp arrays emptied and CONSTR_COUNT reduced from 240→232.
Database schema
temoa/db_schema/temoa_schema_v4.sql, data_files/temoa_schema_v4.sql
output_curtailment.season foreign key changed from time_period (period) to season_label (season).
Test datasets — system & utopia
tests/testing_data/test_system_sets.json, tests/testing_data/utopia_sets.json
Large-scale data updates: many entries in loan_lifetime_process_rtv, new_capacity_var_rtv, capacity_available_var_rptv, and various limit blocks re-mapped with different technology codes and vintage years (extensive data-only changes).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested labels

bugfix, database-schema

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 60.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'Fix 4 independent bugs' is vague and generic. It does not specify what bugs are being fixed or provide meaningful information about the changeset beyond indicating multiple fixes. Consider using a more specific title that indicates the primary bug or area affected, such as 'Fix capacity constraint KeyError and foreign key integrity issues' or breaking into separate PRs with specific titles for each fix.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
📝 Coding Plan
  • Generate coding plan for human review comments

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 and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
temoa/db_schema/temoa_schema_v4.sql (1)

703-711: ⚠️ Potential issue | 🟠 Major

Schema-only FK fix will not repair existing output_curtailment tables.

Because this file uses CREATE TABLE IF NOT EXISTS, any database that already has output_curtailment with the old FK will keep it. If users rerun against an existing SQLite file, the integrity error will persist until this table is migrated or recreated.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@temoa/db_schema/temoa_schema_v4.sql` around lines 703 - 711, The CREATE TABLE
IF NOT EXISTS for output_curtailment with updated foreign keys won't change
existing tables; add a migration that detects an existing output_curtailment and
rebuilds it with the corrected FK constraints (e.g., create a new temp table
with the desired schema referencing time_period(period) and
season_label(season), copy rows from output_curtailment, drop the old table,
rename the temp table, and re-create any indexes/constraints), or else
drop-and-recreate the table in a controlled migration step; target the
output_curtailment table and the FK references to time_period (period) and
season_label (season) when implementing this migration.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@temoa/components/limits.py`:
- Around line 1385-1391: The constraint rule currently lacks a guard for when
the sum in quicksum is empty, causing operator_expression to return a bool,
which Pyomo constraints cannot handle. In the constraint rule that uses capacity
and expr, add a guard after calling operator_expression: check if expr is a bool
with isinstance(expr, bool) and if so, return Constraint.Skip to avoid errors
during model construction. This matches the pattern used in other constraints in
this module like those around lines 365 and 406.

In `@tests/legacy_test_values.py`:
- Around line 67-68: The test currently updates ExpectedVals.CONSTR_COUNT but
lacks a targeted assertion for the specific bug; add a direct assertion that the
seasonal_timeslices output does not include season-ramp constraints by
inspecting the structure returned by seasonal_timeslices (e.g., call
seasonal_timeslices() or reference the fixture result and assert that no
constraint has a name or type containing "season_ramp" or equivalent
identifier), so instead of relying only on ExpectedVals.CONSTR_COUNT the test
explicitly checks the absence of season ramp constraints.

---

Outside diff comments:
In `@temoa/db_schema/temoa_schema_v4.sql`:
- Around line 703-711: The CREATE TABLE IF NOT EXISTS for output_curtailment
with updated foreign keys won't change existing tables; add a migration that
detects an existing output_curtailment and rebuilds it with the corrected FK
constraints (e.g., create a new temp table with the desired schema referencing
time_period(period) and season_label(season), copy rows from output_curtailment,
drop the old table, rename the temp table, and re-create any
indexes/constraints), or else drop-and-recreate the table in a controlled
migration step; target the output_curtailment table and the FK references to
time_period (period) and season_label (season) when implementing this migration.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 6d48d0a8-812f-4449-9f98-e47c63bac212

📥 Commits

Reviewing files that changed from the base of the PR and between 7f7ff86 and 374ffca.

📒 Files selected for processing (8)
  • temoa/components/costs.py
  • temoa/components/limits.py
  • temoa/components/operations.py
  • temoa/db_schema/temoa_schema_v4.sql
  • tests/legacy_test_values.py
  • tests/testing_data/mediumville_sets.json
  • tests/testing_data/test_system_sets.json
  • tests/testing_data/utopia_sets.json

Comment on lines +67 to +68
# reduced by 8 after disabling season ramp for seasonal_timeslices
ExpectedVals.CONSTR_COUNT: 232,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Prefer a targeted regression over another global count tweak.

Updating CONSTR_COUNT keeps this fixture aligned, but it still only checks the bug indirectly. Please add an assertion that seasonal_timeslices does not build the season ramp constraints, so unrelated constraint churn does not mask a regression here.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/legacy_test_values.py` around lines 67 - 68, The test currently updates
ExpectedVals.CONSTR_COUNT but lacks a targeted assertion for the specific bug;
add a direct assertion that the seasonal_timeslices output does not include
season-ramp constraints by inspecting the structure returned by
seasonal_timeslices (e.g., call seasonal_timeslices() or reference the fixture
result and assert that no constraint has a name or type containing "season_ramp"
or equivalent identifier), so instead of relying only on
ExpectedVals.CONSTR_COUNT the test explicitly checks the absence of season ramp
constraints.

In seasonal_timeslices mode, seasons are not temporally adjacent so
inter-season ramp constraints are not meaningful. Previously only
consecutive_days mode skipped these constraints. Add
seasonal_timeslices to the skip condition in both ramp_up and
ramp_down season constraint index functions.

Update test expectations: mediumville constraint count drops by 8
(4 ramp_up + 4 ramp_down). Regenerate set cache files to reflect
expanded loan_lifetime_process_rtv from the earlier fix.
@SutubraResearch SutubraResearch force-pushed the pr/bug-fixes branch 2 times, most recently from b9908b8 to c481781 Compare March 12, 2026 16:08
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (1)
temoa/components/limits.py (1)

1385-1392: ⚠️ Potential issue | 🔴 Critical

Skip the constraint when the filtered sum is empty.

This fixes the missing (region, period, tech) lookup, but the empty-match case still falls through. If every candidate is filtered out, quicksum(...) becomes 0, operator_expression(...) becomes a plain bool, and Pyomo constraint rules cannot return that.

Suggested fix
 def limit_capacity_constraint(
     model: TemoaModel, r: Region, p: Period, t: Technology, op: str
 ) -> ExprLike:
     regions = geography.gather_group_regions(model, r)
     techs = technology.gather_group_techs(model, t)
     cap_lim = value(model.limit_capacity[r, p, t, op])
     capacity = quicksum(
         model.v_capacity_available_by_period_and_tech[_r, p, _t]
         for _t in techs
         for _r in regions
         if (_r, p, _t) in model.process_vintages
     )
     expr = operator_expression(capacity, Operator(op), cap_lim)
+    if isinstance(expr, bool):
+        return Constraint.Skip
     return expr

Read-only verification:

#!/bin/bash
set -euo pipefail

sed -n '1367,1394p' temoa/components/limits.py
echo
rg -n -C2 'if isinstance\(expr, bool\)' temoa/components/limits.py

Expected result: this rule should have the same bool-guard pattern already used by nearby constraint rules in this module.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@temoa/components/limits.py` around lines 1385 - 1392, The constraint rule
builds capacity with quicksum over techs/regions filtered by
model.process_vintages but doesn't handle the case where the filter yields no
terms; detect whether any ( _r, p, _t ) pairs survive the filter (e.g., by
evaluating the generator into a short-circuit any(...) or by collecting terms
into a list) and when empty return pyomo.environ.Constraint.Skip (or follow the
module's existing bool-guard pattern) instead of proceeding to
operator_expression; update the rule around capacity, operator_expression,
Operator and cap_lim so it returns Constraint.Skip when there are no matching
(region, period, tech) candidates.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@temoa/components/operations.py`:
- Around line 77-78: Update the ramp docs/comments to reflect that both
'consecutive_days' and 'seasonal_timeslices' disable the seasonal ramp
constraint: locate the comment/docstring near the check if
model.time_sequencing.first() in ('consecutive_days', 'seasonal_timeslices')
(and the second occurrence around lines with the same condition) and amend the
text in the ramp_up_day_constraint / related comment to mention
'seasonal_timeslices' alongside 'consecutive_days' so documentation matches the
code.

In `@temoa/db_schema/temoa_schema_v4.sql`:
- Around line 710-711: The distribution copy of the schema still uses the old
foreign key reference time_period(period) instead of the corrected
season_label(season); update the distribution schema copy to change the FK to
"season TEXT REFERENCES season_label(season)" (the same fix applied in
temoa_schema_v4.sql), and then either increment DB_MINOR to 1 (update DB_MINOR
from 0 to 1) so new installs pick up the change automatically or add a clear
migration step in the release notes explaining that existing v4 databases must
be altered manually to change the FK from time_period(period) to
season_label(season); ensure you update the file that ships with the package
(the data_files copy) and the DB_MINOR constant (DB_MAJOR/DB_MINOR) accordingly
if you choose the version bump option.

---

Duplicate comments:
In `@temoa/components/limits.py`:
- Around line 1385-1392: The constraint rule builds capacity with quicksum over
techs/regions filtered by model.process_vintages but doesn't handle the case
where the filter yields no terms; detect whether any ( _r, p, _t ) pairs survive
the filter (e.g., by evaluating the generator into a short-circuit any(...) or
by collecting terms into a list) and when empty return
pyomo.environ.Constraint.Skip (or follow the module's existing bool-guard
pattern) instead of proceeding to operator_expression; update the rule around
capacity, operator_expression, Operator and cap_lim so it returns
Constraint.Skip when there are no matching (region, period, tech) candidates.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 751c584b-2aeb-4b55-8882-1ae6b1b5f24d

📥 Commits

Reviewing files that changed from the base of the PR and between b9908b8 and c481781.

📒 Files selected for processing (12)
  • temoa/components/costs.py
  • temoa/components/limits.py
  • temoa/components/operations.py
  • temoa/db_schema/temoa_schema_v4.sql
  • tests/legacy_test_values.py
  • tests/testing_data/mediumville_sets.json
  • tests/testing_data/test_system_sets.json
  • tests/testing_data/utopia_sets.json
  • tests/utilities/capture_set_values_for_cache.py
  • tests/utilities/config_mediumville.toml
  • tests/utilities/config_test_system.toml
  • tests/utilities/config_utopia.toml

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (2)
temoa/components/operations.py (1)

77-78: ⚠️ Potential issue | 🟡 Minor

Update the ramp docs/comments to match the new guard.

The code now disables seasonal ramp constraints for seasonal_timeslices too, but the nearby ramp_up_day_constraint / ramp_down_day_constraint docs still say only consecutive_days skips the seasonal ramp.

Also applies to: 97-98

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@temoa/components/operations.py` around lines 77 - 78, Update the
docstrings/comments for ramp_up_day_constraint and ramp_down_day_constraint to
reflect the new guard: they now skip seasonal ramp constraints when
model.time_sequencing.first() is either 'consecutive_days' or
'seasonal_timeslices' (not just 'consecutive_days'); locate the conditional in
operations.py where the check if model.time_sequencing.first() in
('consecutive_days', 'seasonal_timeslices'): return set() appears and change any
nearby comment or docstring text that still mentions only 'consecutive_days' to
explicitly list both 'consecutive_days' and 'seasonal_timeslices' so the docs
match the code (apply the same edit for the similar block at the other
occurrence around lines 97-98).
temoa/components/limits.py (1)

1385-1392: ⚠️ Potential issue | 🔴 Critical

Skip the constraint when the filtered capacity sum is empty.

If this filter removes every term, quicksum(...) becomes 0 and operator_expression(...) can return a plain Python bool. Pyomo constraint rules still need the usual Constraint.Skip guard here.

Suggested fix
     expr = operator_expression(capacity, Operator(op), cap_lim)
+    if isinstance(expr, bool):
+        return Constraint.Skip
     return expr
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@temoa/components/limits.py` around lines 1385 - 1392, The constraint must
skip when the filtered sum has no terms: build the term list used in quicksum
(e.g., terms = [model.v_capacity_available_by_period_and_tech[_r, p, _t] for _t
in techs for _r in regions if (_r, p, _t) in model.process_vintages]) and if not
terms return pyomo.environ.Constraint.Skip (or Constraint.Skip) before calling
quicksum/operator_expression; otherwise compute capacity = quicksum(terms) and
return expr as before using Operator(op) and cap_lim.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@temoa/components/limits.py`:
- Around line 1385-1392: The constraint must skip when the filtered sum has no
terms: build the term list used in quicksum (e.g., terms =
[model.v_capacity_available_by_period_and_tech[_r, p, _t] for _t in techs for _r
in regions if (_r, p, _t) in model.process_vintages]) and if not terms return
pyomo.environ.Constraint.Skip (or Constraint.Skip) before calling
quicksum/operator_expression; otherwise compute capacity = quicksum(terms) and
return expr as before using Operator(op) and cap_lim.

In `@temoa/components/operations.py`:
- Around line 77-78: Update the docstrings/comments for ramp_up_day_constraint
and ramp_down_day_constraint to reflect the new guard: they now skip seasonal
ramp constraints when model.time_sequencing.first() is either 'consecutive_days'
or 'seasonal_timeslices' (not just 'consecutive_days'); locate the conditional
in operations.py where the check if model.time_sequencing.first() in
('consecutive_days', 'seasonal_timeslices'): return set() appears and change any
nearby comment or docstring text that still mentions only 'consecutive_days' to
explicitly list both 'consecutive_days' and 'seasonal_timeslices' so the docs
match the code (apply the same edit for the similar block at the other
occurrence around lines 97-98).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: f2db9007-df45-422a-8923-00c7bf8c913e

📥 Commits

Reviewing files that changed from the base of the PR and between c481781 and c137019.

📒 Files selected for processing (8)
  • temoa/components/costs.py
  • temoa/components/limits.py
  • temoa/components/operations.py
  • temoa/db_schema/temoa_schema_v4.sql
  • tests/legacy_test_values.py
  • tests/testing_data/mediumville_sets.json
  • tests/testing_data/test_system_sets.json
  • tests/testing_data/utopia_sets.json

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