Skip to content

engine: replace base_from with from_salsa constructor#379

Merged
bpowers merged 4 commits intomainfrom
engine/from-salsa-constructor
Mar 8, 2026
Merged

engine: replace base_from with from_salsa constructor#379
bpowers merged 4 commits intomainfrom
engine/from-salsa-constructor

Conversation

@bpowers
Copy link
Owner

@bpowers bpowers commented Mar 8, 2026

Summary

  • Replace the monolithic Project::base_from with from_salsa which builds a Project from a pre-synced salsa database
  • All variable parsing comes from salsa-cached results instead of duplicating parsing/DB-setup logic
  • New constructor takes a salsa DB and SourceProject (already synced by the caller), eliminating local DB creation
  • Convenience wrapper from_datamodel handles the common case of creating a local DB and syncing
  • For stdlib (implicit) models, pass all variable names as extra module idents so PREVIOUS expansion uses module expansion instead of LoadPrev

Fixes #376

Test plan

  • Existing engine tests pass
  • Simulation integration tests produce correct results

Replace the monolithic `Project::base_from` with `from_salsa` which
builds a Project from a pre-synced salsa database. All variable
parsing comes from salsa-cached results instead of duplicating
the parsing/DB-setup logic.

The new constructor takes a salsa DB and SourceProject (already
synced by the caller), eliminating the local DB creation and
`cached_sources` parameter that `base_from` needed. A convenience
wrapper `from_datamodel` handles the common case of creating a
local DB and syncing.

For stdlib (implicit) models, all variable names are passed as
extra module idents so PREVIOUS expansion uses module expansion
instead of LoadPrev. This matches the behavior of the old
`ModelStage0::new()` for implicit models, where module inputs
lack persistent slots in prev_values.
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e9cfa24f5a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

models,
model_order: ordered_models,
errors: project_errors,
errors: vec![],

Choose a reason for hiding this comment

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

P2 Badge Preserve project-level unit definition errors

from_salsa now hardcodes errors: vec![], which drops the UnitDefinitionErrors that Project::base_from previously surfaced when Context::new_with_builtins failed. In the test/testing construction path (Project::from/from_datamodel), this means malformed project unit declarations are silently accepted because project_units_context only accumulates diagnostics in salsa and nothing copies them onto Project.errors; callers like TestProject::compile and build_sim check compiled.errors to reject invalid projects, so they can now incorrectly proceed with a default unit context.

Useful? React with 👍 / 👎.

@claude
Copy link

claude bot commented Mar 8, 2026

Code Review: engine: replace base_from with from_salsa constructor

Summary

This PR replaces the monolithic Project::base_from with from_salsa (building from a pre-synced salsa database) and from_datamodel (convenience wrapper). The change correctly replicates the prior behavior:

  • Stdlib model detection via "stdlib\u{205A}" prefix matches the old is_stdlib_override logic
  • Extra module idents for stdlib models (ALL variable names) correctly prevents LoadPrev for module inputs
  • sync_from_datamodel already handles stdlib override deduplication, so no explicit check is needed in from_salsa
  • Variable parsing through parse_source_variable_with_module_context uses the same module ident context as the old new_cached path
  • Implicit variable (SMOOTH/DELAY expansion) parsing with parse_var matches the old new_cached approach

Findings

No bugs found.

Minor observations (non-blocking)

  1. Dropped assertion on recursive implicit vars (src/simlin-engine/src/project.rs:154-159): The old ModelStage0::new and new_cached both had assert_eq!(0, dummy_implicit_vars.len()) after parsing implicit vars, validating that implicit vars never recursively generate more implicit vars. The new code uses a dummy vec that is silently discarded. Not a bug (the assertion always passed), but worth noting the lost invariant check.

  2. Project.errors always empty (src/simlin-engine/src/project.rs:240): Intentional and well-documented in the field comment. The old path accumulated UnitDefinitionErrors here; the new path routes them through the salsa accumulator. Callers in test_common.rs that check compiled.errors.is_empty() will always see an empty vec — this is fine since the from_salsa path is test-only and unit definition errors are still reported through the salsa diagnostic system.

Verdict

Correct. The patch is a clean refactor that consolidates variable parsing through salsa-cached results. Existing code and tests should not break.

@codecov
Copy link

codecov bot commented Mar 8, 2026

Codecov Report

❌ Patch coverage is 83.78378% with 12 lines in your changes missing coverage. Please review.
✅ Project coverage is 76.81%. Comparing base (fd36f50) to head (2f2a546).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
src/simlin-engine/src/project.rs 83.33% 12 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #379      +/-   ##
==========================================
+ Coverage   76.79%   76.81%   +0.01%     
==========================================
  Files         143      143              
  Lines       36171    36171              
==========================================
+ Hits        27777    27784       +7     
+ Misses       8394     8387       -7     

☔ 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.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

After calling project_units_context, collect accumulated
CompilationDiagnostics for unit definition errors and convert them
to Error instances stored in Project.errors. Without this, the
from_salsa constructor always produced an empty errors vec, so
callers inspecting compiled.errors (e.g. test_common helpers)
would silently miss malformed unit definitions.

Also restore the implicit-var recursion guard assertion that was
present in ModelStage0::new but dropped in the from_salsa path,
and rename the opaque "dummy" variable to "nested_implicit".
@claude
Copy link

claude bot commented Mar 8, 2026

Code Review

Reviewed the replacement of Project::base_from with from_salsa / from_datamodel constructors.

Analysis

Changes reviewed:

  • src/simlin-engine/src/project.rs — New from_salsa constructor building Project from pre-synced salsa DB; from_datamodel convenience wrapper; From<datamodel::Project> now delegates to from_datamodel
  • src/simlin-engine/src/units_infer.rs — Test callsites updated to use explicit DB + sync + from_salsa
  • src/simlin-engine/src/model.rs#[allow(dead_code)] on test-only ModelStage0::new
  • src/simlin-engine/CLAUDE.md — Doc updated to reflect new API

Key areas verified:

  1. Unit error recovery — The salsa accumulator path (project_units_context::accumulated) correctly captures DiagnosticError::Unit variants and maps them to ErrorCode::UnitDefinitionErrors, matching the old inline behavior. The new test test_unit_definition_errors_surface_in_project_errors confirms this.
  2. Module ident handling for stdlib — Passing all variable names as extra_module_idents for stdlib models is equivalent to the old ModelStage0::new logic (which collected all variable idents when implicit=true). The model_module_ident_context function combines these with collect_module_idents() results and deduplicates.
  3. Implicit variable parsing — SMOOTH/DELAY expansion variables are correctly parsed outside salsa caching (since they're generated artifacts), with the debug_assert! guarding against unexpected nested expansion.
  4. Dimension contextproject_datamodel_dims(db, source_project) produces equivalent data to &project_datamodel.dimensions, consistent with how other salsa paths (e.g., db_ltm.rs) construct DimensionsContext.
  5. ModelStage0 field initializationerrors: None and display_name assignment match the existing ModelStage0::new and new_cached constructors.

Findings

No bugs found. The refactoring correctly eliminates redundant parsing by leveraging salsa-cached results, simplifies the constructor API (removing the cached_sources Option triple), and maintains semantic equivalence with the old base_from path.

Verdict

Correct — The patch is free of bugs and blocking issues. Existing code and tests will not break.

Use the canonical HashMap key (always lowercase) for the
starts_with("stdlib⁚") check instead of the raw model name,
so non-canonical spellings like Stdlib⁚Delay1 are handled
correctly. Also bind model_name once to reduce repeated
src_model.name(db) calls.
@claude
Copy link

claude bot commented Mar 8, 2026

Code Review

This PR replaces the monolithic Project::base_from with two cleaner constructors: from_salsa (builds from a pre-synced salsa database) and from_datamodel (convenience wrapper). The refactoring eliminates duplicated parsing/DB-setup logic by reading all variable parsing results from salsa-cached tracked functions.

Architecture: The split into from_salsa + from_datamodel is clean. from_salsa takes an already-synced DB and SourceProject, while from_datamodel handles the common create-and-sync pattern. This removes the awkward Option parameter from the old base_from.

Stdlib module ident handling: Passing all variable names as extra_module_idents for stdlib models is well-motivated -- module inputs in submodules lack persistent slots in prev_values, so LoadPrev would be incorrect. Non-stdlib models correctly rely on model_module_ident_context to collect module idents from the model own variables.

Error recovery from salsa accumulator: The pattern of recovering CompilationDiagnostic from project_units_context::accumulated and filtering for DiagnosticError::Unit is correct. Error detail formatting differs slightly from the old path (old code included unit_name in the message while the salsa accumulator drops it), but this is a pre-existing characteristic of the salsa path, not introduced by this PR.

Implicit var parsing: The direct parse_var call for SMOOTH/DELAY expansion implicit vars with the debug_assert guard for nested implicit vars is consistent with the old behavior.

Test coverage: The new test validates the error accumulation path. All unit inference tests are updated to the new API.

No bugs found. The refactoring is mechanical and correct -- the behavioral semantics are preserved while eliminating code duplication.

Verdict: Correct -- existing code and tests will not break. The patch is a clean refactoring with no bugs or blocking issues.

Include the failing unit name in UnitDefinitionErrors details so
callers can identify which unit definition is broken. The salsa
accumulator in project_units_context now stores the unit name in
the Diagnostic.variable field; from_salsa recovers it and formats
errors as "{name}: {err}" matching the old base_from behavior.

Also tighten stdlib model detection to check against the known
crate::stdlib::MODEL_NAMES list instead of just the "stdlib⁚"
prefix, so user models with that prefix are not incorrectly
classified as implicit.
@claude
Copy link

claude bot commented Mar 8, 2026

Code Review

Reviewed the replacement of the monolithic base_from with the from_salsa / from_datamodel constructors.

Analysis

The refactoring is well-structured:

  • from_datamodel cleanly replaces the old base_from(dm, None, cb) path (local DB creation + sync).
  • from_salsa properly iterates source_project.models(db) (which includes stdlib models), uses salsa-cached parsing via parse_source_variable_with_module_context, and correctly identifies stdlib models via strip_prefix + MODEL_NAMES.contains.
  • The extra_module_idents handling for stdlib models (passing all variable names to prevent incorrect LoadPrev for module inputs) is correctly motivated and matches the equivalent logic in ModelStage0::new (lines 900-908).
  • Implicit variable parsing (SMOOTH/DELAY expansion) matches the old behavior: parse_var without module context, with the same assertion that nested implicit vars don't produce further implicit vars.
  • Unit error recovery from the salsa accumulator correctly maps CompilationDiagnostic entries back to Project.errors, and the db.rs change to populate variable: Some(unit_name.clone()) ensures the unit name surfaces in error details.
  • The test test_unit_definition_errors_surface_in_project_errors validates the error propagation path end-to-end.
  • All callers in units_infer.rs are mechanically updated to the new API (create DB, sync, pass to from_salsa).

Verdict

Correct. No bugs found. The patch maintains behavioral equivalence with the old code while eliminating redundant parsing through salsa caching. Existing tests and the new test adequately cover the changes.

@bpowers
Copy link
Owner Author

bpowers commented Mar 8, 2026

Review Summary

Three review iterations addressed feedback from both automated reviewers:

Iteration 1 fixed a P2 behavioral regression where Project.errors was always empty after the from_salsa refactor. Unit definition errors from the salsa accumulator are now recovered and stored in Project.errors, with a new test verifying the behavior. Also restored a dropped implicit-var recursion guard assertion.

Iteration 2 tightened stdlib model detection to use the canonical HashMap key instead of the raw model name, ensuring non-canonical spellings are handled correctly.

Iteration 3 further improved the stdlib check to validate against the known crate::stdlib::MODEL_NAMES list (not just the prefix), and preserved the failing unit name in error details so callers can identify which unit definition is broken. The unit name is now stored in the salsa diagnostic's variable field, improving diagnostic quality for both the test path and production.

Both reviewers passed with no actionable issues in the final iteration.

@bpowers bpowers merged commit a8ea19e into main Mar 8, 2026
12 checks passed
@bpowers bpowers deleted the engine/from-salsa-constructor branch March 8, 2026 03:32
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.

get_stdlib_composite_ports blocks removal of monolithic Project::base_from path

1 participant