Skip to content

Refactor: Move future and decommissioned assets out of AssetPool#1114

Open
alexdewar wants to merge 12 commits intomainfrom
separate-out-asset-pool
Open

Refactor: Move future and decommissioned assets out of AssetPool#1114
alexdewar wants to merge 12 commits intomainfrom
separate-out-asset-pool

Conversation

@alexdewar
Copy link
Collaborator

Description

I've been trying to refactor the asset code for #1100, but I realised that we don't have a particularly good separation of concerns for AssetPool.

Currently, it contains all active, as well as all future and all decommissioned assets. Bundling in the latter two with the active assets doesn't make sense, I think, and causes irritating lifetime issues, e.g. when trying to extract future assets and append them to the active pool (you can't have two mutable refs to self). We can work around the lifetime issues, but I think it's a sign that these data structures don't really belong together.

So I've refactored it so that there are now separate Vecs for future (user-defined) assets and decommissioned assets. I think this makes for a nicer API overall, actually: for example, we can now just return decommissioned assets as an iterator rather than making assumptions about what should be done with them.

I also moved the user-defined assets to be stored in Model along with the other input data, which I think make sense, so we now have to copy them at the start of the simulation to get a mutable Vec (though we only do this once).

Let me know what you think 😄.

Type of change

  • Bug fix (non-breaking change to fix an issue)
  • New feature (non-breaking change to add functionality)
  • Refactoring (non-breaking, non-functional change to improve maintainability)
  • Optimization (non-breaking change to speed up the code)
  • Breaking change (whatever its nature)
  • Documentation (improve or add documentation)

Key checklist

  • All tests pass: $ cargo test
  • The documentation builds and looks OK: $ cargo doc
  • Update release notes for the latest release if this PR adds a new feature or fixes a bug
    present in the previous release

Further checks

  • Code is commented, particularly in hard-to-understand areas
  • Tests added that prove fix is effective or that feature works

Copilot AI review requested due to automatic review settings February 3, 2026 12:25
@codecov
Copy link

codecov bot commented Feb 3, 2026

Codecov Report

❌ Patch coverage is 93.39623% with 7 lines in your changes missing coverage. Please review.
✅ Project coverage is 87.48%. Comparing base (b76c3ed) to head (ae12d93).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
src/simulation.rs 77.77% 0 Missing and 4 partials ⚠️
src/cli.rs 0.00% 0 Missing and 2 partials ⚠️
src/fixture.rs 50.00% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1114      +/-   ##
==========================================
- Coverage   87.52%   87.48%   -0.04%     
==========================================
  Files          55       55              
  Lines        7429     7415      -14     
  Branches     7429     7415      -14     
==========================================
- Hits         6502     6487      -15     
- Misses        630      631       +1     
  Partials      297      297              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR refactors the asset management code by separating concerns: instead of storing active, future, and decommissioned assets together in AssetPool, the code now stores user-defined assets in the Model struct and maintains separate collections for active and decommissioned assets during simulation. This improves the separation of concerns and eliminates lifetime issues that arose from needing multiple mutable references to the same structure.

Changes:

  • Refactored AssetPool to only contain active assets, removing the future and decommissioned fields
  • Moved user-defined assets to the Model struct as a new user_assets field
  • Changed load_model to return just Model (which now includes user_assets) instead of a tuple
  • Updated the simulation run function to manage user assets and decommissioned assets separately

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
src/simulation.rs Updated to clone user_assets from Model, manage active and decommissioned pools separately, and chain them when writing to file
src/model.rs Added user_assets field to store user-defined assets as part of the model input data
src/input/asset.rs Renamed read_assets to read_user_assets and changed return type from Vec<Asset> to Vec<AssetRef>
src/input.rs Modified load_model to return just Model (containing user_assets) instead of a tuple
src/fixture.rs Updated test fixtures to work with the new API (empty AssetPool creation, explicit commissioning)
src/cli.rs Updated to handle the new load_model return type and run function signature
src/asset.rs Refactored AssetPool structure, made commission_new and decommission_old/mothballed public, changed them to work with external user_assets and return iterators of decommissioned assets
src/output.rs Updated test method calls from iter_active() to iter() to match the new API

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings February 3, 2026 13:06
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 5 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

src/asset.rs Outdated
@@ -1425,10 +1375,10 @@ impl AssetPool {
}

// New assets may not have been sorted, but active needs to be sorted by ID
Copy link

Copilot AI Feb 3, 2026

Choose a reason for hiding this comment

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

The comment says "active needs to be sorted by ID" but the field is now called "assets". Update to "assets needs to be sorted by ID" or "the asset pool needs to be sorted by ID".

Suggested change
// New assets may not have been sorted, but active needs to be sorted by ID
// New assets may not have been sorted, but assets need to be sorted by ID

Copilot uses AI. Check for mistakes.
src/asset.rs Outdated
pub fn commission_new(&mut self, year: u32, user_assets: &mut Vec<AssetRef>) {
let to_commission = user_assets.extract_if(.., |asset| asset.commission_year <= year);

// Move assets from future to active
Copy link

Copilot AI Feb 3, 2026

Choose a reason for hiding this comment

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

The comment "Move assets from future to active" is outdated. With the refactored design, user assets are no longer called "future" assets, and they're now stored externally. Consider updating this comment to something like "Commission assets from user_assets that are due this year" to better reflect the new architecture.

Suggested change
// Move assets from future to active
// Commission assets from user_assets that are due on or before this year into the active pool

Copilot uses AI. Check for mistakes.
src/asset.rs Outdated
@@ -1348,36 +1329,25 @@ impl AssetPool {
pub fn get(&self, id: AssetID) -> Option<&AssetRef> {
// The assets in `active` are in order of ID
Copy link

Copilot AI Feb 3, 2026

Choose a reason for hiding this comment

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

The comment references "active" but the field is now called "assets". Update the comment to say "The assets in assets are in order of ID" or simply "Assets are stored in order of ID".

Suggested change
// The assets in `active` are in order of ID
// The assets in `assets` are in order of ID

Copilot uses AI. Check for mistakes.
@alexdewar alexdewar requested review from Aurashk February 3, 2026 15:58
@alexdewar alexdewar added this to MUSE Feb 3, 2026
@alexdewar alexdewar moved this to 👀 In review in MUSE Feb 3, 2026
@alexdewar
Copy link
Collaborator Author

Actually @Aurashk I've realised this needs more work, so maybe hold off on review for now

1 similar comment
@alexdewar
Copy link
Collaborator Author

Actually @Aurashk I've realised this needs more work, so maybe hold off on review for now

@alexdewar alexdewar marked this pull request as draft February 5, 2026 10:20
Returning an iterator has a subtle gotcha: because iterators are evaluated lazily, if the caller does not comsume the whole thing, only some of the assets that should be decommissioned will be.
@alexdewar
Copy link
Collaborator Author

@aurash I've tweaked this now.

My original implementation returned decommissioned assets as iterators, but this has a subtle
gotcha: because iterators are evaluated lazily, if the caller does not comsume the whole thing, only
some of the assets that should be decommissioned will be.

Anyway, I think this is ready for review now.

@alexdewar alexdewar marked this pull request as ready for review February 5, 2026 11:22
Copilot AI review requested due to automatic review settings February 5, 2026 11:22
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.


// Write assets to file
writer.write_assets(assets.iter_all())?;
writer.write_assets(asset_pool.iter())?;
Copy link

Copilot AI Feb 5, 2026

Choose a reason for hiding this comment

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

In the base year, only active assets are written to the output file, but decommissioned assets should also be included for consistency. If any user-defined assets have already reached their max_decommission_year by the base year, they would be skipped during commissioning (with a warning) but never written to the output file. This creates an inconsistency with subsequent years (line 133) where both decommissioned and active assets are written. Consider changing this line to: writer.write_assets(decommissioned.iter().chain(asset_pool.iter()))?; to match the pattern used in subsequent years.

Copilot uses AI. Check for mistakes.
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This isn't right... assets that are "decommissioned" before the time horizon are simply discarded, so they never end up in the decommissioned Vec. So there are no decommissioned assets to be written to file here.

Copilot AI review requested due to automatic review settings February 5, 2026 11:31
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

let mut writer = DataWriter::create(output_path, &model.model_path, debug_model)?;
let mut user_assets = model.user_assets.clone();
let mut asset_pool = AssetPool::new(); // active assets
let mut decommissioned = Vec::new();
Copy link

Copilot AI Feb 5, 2026

Choose a reason for hiding this comment

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

The decommissioned Vec is never cleared between milestone years, causing decommissioned assets to accumulate across all years. When assets are written at line 133, all previously decommissioned assets from earlier years will be written again, creating duplicate entries in the output. The Vec should be cleared after writing assets to file (after line 133) to ensure each year only writes the assets that were decommissioned in that specific year.

Copilot uses AI. Check for mistakes.
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yes, but that's by design! We write all decommissioned assets to file.

Unsure why `cargo fmt` didn't fix this...

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@alexdewar alexdewar force-pushed the separate-out-asset-pool branch from 9a1deeb to ae12d93 Compare February 5, 2026 11:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: 👀 In review

Development

Successfully merging this pull request may close these issues.

1 participant