Skip to content

feat(study): reject parameter dependency extension at load time, with actionable errors - #276

Open
aoustry wants to merge 7 commits into
mainfrom
claude/issue-258-plan-mvm163
Open

feat(study): reject parameter dependency extension at load time, with actionable errors#276
aoustry wants to merge 7 commits into
mainfrom
claude/issue-258-plan-mvm163

Conversation

@aoustry

@aoustry aoustry commented Aug 14, 2026

Copy link
Copy Markdown
Collaborator

Process ID

Process: GP-02 (refs #258 — see Scope vs #258 below; this PR does not close it)

Description

A component parameter's time/scenario dependency must be the one its model declares, axis by axis: a component may narrow what the model declares (truefalse) but never extend it.

Narrowing already worked, end to end — this PR adds the missing test coverage for it, it does not fix it. Extension already failed too; what was wrong is when and how. It surfaced only inside build_problem() as Data inconsistency for component: G, parameter: cost. Requirement not met., which named neither the flags, nor the model, nor the file — so load_study() succeeded and nothing failed until you tried to solve.

  • The check moves into resolve_system(), so load_study() and the CLI fail immediately with an error naming the component, the parameter, and both declarations.
  • Study.check_consistency() stays as the safety net for programmatically built studies, now reporting the data's and the model's axes.
  • Data-shape errors name the offending component/parameter, report the shape read, and point at the flag to change. Strict shapes are unchanged (T×1, 1×S, T×S, inline float).
  • check_requirement() is now derived from a new indexing_structure() per data container instead of being reimplemented four times; accept/reject behaviour is identical, and four dead isinstance(self, X) guards (tautologically true inside X.check_requirement) are gone.

So the user-visible delta is error timing and wording only — no study that used to work stops working, and no study that used to fail starts working.

Scope vs #258

#258 reports three things. This PR addresses one and takes a position on a second; the third is untouched. It therefore refs the issue rather than closing it.

#258 asks This PR
Narrowing (truefalse from the system file) should work Already worked before this PR — covered by tests here, no behaviour change
The system file should be able to extend the model's declared dependency Rejected by design, earlier and more clearly — the opposite of the request
A single-axis parameter shouldn't be capped at one column/row of data Not addressed; only the error message is reworded

Rationale for rejecting extension: _build_param_arrays_for_model builds one array per model, shaped from param.structure (the model's declaration). A component varying along an axis its model does not declare has nowhere to live without per-component dims, which would ripple into the indexing-structure analysis used for constraint shapes. Making it a clear, early error is the cheap and coherent option.

Impact Analysis

Affected modules: study/ only (resolve_components.py, data.py, study.py). No changes to expression/, simulation/, or optim_config/.

Solver output values are not expected to change. Parameter arrays keep the dimensions the model declares, and narrower data is broadcast over the remaining axes exactly as before; the check_requirement truth table is unchanged for all four data containers. test_narrowing_does_not_change_the_problem_shape asserts narrowing leaves array dimensions, variables, and constraints untouched, and the 8 parametrized end-to-end cases pin the objective values. Backward compatible; the only wording change to an existing message is scenario-series "exactly one row" instead of "exactly one line".

One caveat worth a reviewer's eye: moving the check into resolve_system() means a study whose system file extends a model declaration now fails at load, not at solve. That is the intent, but it is a behaviour change for gems_craft-only consumers that load without solving. gems_craft_hybrid is unaffected (it parses and writes, it never calls resolve_system).

AbstractDataStructure gains a new abstract indexing_structure(), so any out-of-tree subclass must implement it.

Checklist

  • Unit tests pass (pytest) — 632 passed, 6 skipped, 2 xfailed
  • Type checking passes (mypy) — 68 source files
  • Formatting passes (black, isort)
  • pyproject.toml version bumped if applicable — not bumped: this repo bumps in dedicated release: commits, so the entry went under [Unreleased] in docs/CHANGELOG.md
  • AGENTS.md reviewed for impact and updated if needed — reviewed, no change needed (the rule is user-facing and documented in docs/user-guide/inputs.md)

claude and others added 7 commits August 14, 2026 16:42
…he system

A component parameter's time/scenario dependency must be less than or equal
to the one its model declares, axis by axis: the component may narrow what
the model declares (true -> false) but never extend it.

Narrowing already worked correctly at solve time — parameter arrays keep the
dimensions the model declares and narrower data is broadcast over the
remaining axes — but nothing tested it, and extending was caught only later,
inside build_problem(), by a "Data inconsistency ... Requirement not met"
message that named neither the flags nor the file.

Move the check into resolve_system(), so load_study() and the CLI fail
immediately with an error naming the component, the parameter, and both
declarations. Keep Study.check_consistency() as the safety net for studies
built programmatically, and report the data's and the model's axes there
too. Data-shape errors now name the offending component and parameter,
report the shape read, and point at the flag to change.

check_requirement() is now derived from a new structure() on each data
container rather than reimplemented per subclass; the accept/reject
behaviour is unchanged.

Solver output is unchanged: an end-to-end test covers every allowed
model/component combination and asserts the data is constant along each axis
the component declared independent, and that narrowing leaves the problem's
variables, constraints, and array dimensions untouched.

Closes #258

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013uUKXBbXCvH9ZECvbx4nC6
Removed section on parameter time and scenario dependency from the user guide.
Updated CHANGELOG to reflect fixed issues and clearer error messages.
Clarified error handling for parameter time/scenario dependency validation and improved data-shape error messages.
Removed unnecessary lines from the inputs documentation.
…_structure()

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013uUKXBbXCvH9ZECvbx4nC6
@aoustry aoustry changed the title feat(study): validate parameter dependency narrowing when resolving the system feat(study): reject parameter dependency extension at load time, with actionable errors Aug 14, 2026
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.

2 participants