Skip to content

Add a first-class validated input schema for ARC (pydantic, mirroring T3) - #926

Open
alongd wants to merge 3 commits into
mainfrom
input_schema
Open

alongd wants to merge 3 commits into
mainfrom
input_schema

Conversation

@alongd

@alongd alongd commented Jul 26, 2026 •

Copy link
Copy Markdown
Member

Summary

input.yml / restart.yml
        │
        ▼
validate_input_dict() ── ARCInput (Pydantic v2, strict)
        │ normalized supplied keys
        ▼
     ARC(**validated)
        │
        ▼
restart.yml + schema_version + arc_version

Adds a validated ARC input schema at the CLI load seam. It covers the top-level ARC options, species and reaction fields, job types, and registered TS adapters. extra="forbid" catches misspelled fields that ARCSpecies previously swallowed; runtime restart blobs that ARC itself serializes remain pass-through values.

as_input_dict() preserves only keys the user supplied, including explicit nulls. Existing example and ARC restart inputs are covered, and restart files now record schema and ARC versions. Also fixes scalar T_max normalization in draw_kinetics_plots, which this PR makes reachable from plain input.

Evidence

  • Before: the CLI passed raw YAML directly to ARC(**input_dict). Malformed values could fail deep in construction, and unknown species keys could be silently ignored.
  • After: validate_input_dict() validates and normalizes at the load seam. Tests cover schema fields against ARC construction/serialization, example and restart inputs, explicit nulls, strict types, and equivalence between validated and direct construction on supported inputs.
  • The previous head had all GitHub checks green. CI is running again on the rebased head.

Merge Danger

Door: Two-way

Blast Radius: Input

Strict validation can reject malformed or unmodelled restart fields that previously passed through. Some T3-generated restart.yml files are known to be rejected by this strict ARC schema; T3 is unchanged, and that compatibility gap remains.

Brief: D-002 arc-review-request-batch

Comment thread arc/schema.py Fixed
Comment thread arc/job/factory_test.py Fixed
Comment thread arc/schema.py Fixed
@codecov

codecov Bot commented Jul 26, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 67.36%. Comparing base (6da9d99) to head (6271f03).

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main     #926      +/-   ##
==========================================
+ Coverage   67.15%   67.36%   +0.20%     
==========================================
  Files         123      124       +1     
  Lines       43675    43964     +289     
  Branches    11153    11174      +21     
==========================================
+ Hits        29332    29618     +286     
+ Misses      11203    11202       -1     
- Partials     3140     3144       +4     
Flag Coverage Δ
functionaltests 67.36% <ø> (+0.20%) ⬆️
unittests 67.36% <ø> (+0.20%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.
see 12 files with indirect coverage changes

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

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 introduces a first-class, Pydantic v2–based input/restart schema for ARC to validate and normalize YAML input at load time (mirroring T3’s approach), improving early error reporting and preventing silent misconfiguration.

Changes:

  • Added arc/schema.py with an ARCInput model (plus nested Species, Reaction, JobTypes, and enums) and a public validate_input_dict() helper for validate-then-construct.
  • Wired the CLI entry point (ARC.py) to validate inputs and exit cleanly with formatted validation errors on invalid YAML content.
  • Added schema drift-guard tests and restart/versioning support (schema_version, arc_version), plus a small plotter regression fix for scalar T_max.

Reviewed changes

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

Show a summary per file
File Description
environment.yml Declares pydantic>=2 for the conda environment.
arc/schema.py Adds the Pydantic input/restart schema and validate_input_dict() API.
arc/schema_test.py Adds comprehensive schema validation + drift-guard + seam equivalence tests.
arc/plotter.py Fixes scalar T_max normalization bug in kinetics plotting.
arc/plotter_test.py Adds regression coverage for scalar T_max in draw_kinetics_plots().
arc/main.py Adds restart version keys to as_dict(), ignores them in __init__, and uses public adapter-registry getter.
arc/main_test.py Updates as_dict() expectations and adds CLI validation seam test.
arc/job/factory.py Exposes get_registered_job_adapters() for public registry access.
arc/job/factory_test.py Adds a unit test asserting the registry accessor returns the live adapter registry.
arc/common.py Introduces ARC_INPUT_SCHEMA_VERSION constant for restart schema versioning.
ARC.py Validates input dict via schema before constructing ARC; prints validation errors and exits with code 1.

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

Comment thread arc/schema.py Resolved
@alongd
alongd force-pushed the input_schema branch 2 times, most recently from a30b7dd to 9841340 Compare July 28, 2026 04:01
@alongd
alongd force-pushed the input_schema branch 2 times, most recently from 1774d1c to 15e963f Compare August 6, 2026 19:40
@alongd alongd closed this Aug 6, 2026
@alongd alongd reopened this Aug 6, 2026
@alongd
alongd force-pushed the input_schema branch 3 times, most recently from 57f5f9a to cfc4d76 Compare August 14, 2026 02:20
@alongd
alongd force-pushed the input_schema branch 2 times, most recently from ef25de0 to 528772e Compare October 11, 2026 07:14
@alongd
alongd requested a balanced review from Copilot October 11, 2026 08:00

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Comment thread ARC.py Resolved
Comment thread arc/schema.py Resolved
Comment thread arc/schema.py Resolved
Comment thread arc/schema.py Resolved
Comment thread arc/schema.py Resolved
Comment thread arc/schema.py Resolved
Comment thread arc/schema_test.py Resolved

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Comment thread arc/schema.py Resolved
Comment thread arc/schema.py Resolved
Comment thread arc/schema.py Resolved
Comment thread arc/schema.py Resolved
Introduce arc/schema.py: a pydantic v2 ARCInput model (mirroring T3's
t3/schema.py) that validates and normalizes the ARC input/restart dict
before an ARC object is constructed. Wire it into ARC.py's main() as a
validate-then-construct gate; ARC.__init__ is otherwise unchanged.

- Top-level ARCInput mirrors the ARC.__init__ kwargs and as_dict() keys
- Full Species and Reaction sub-models, a JobTypes sub-model, BACTypeEnum,
  TemperatureUnitEnum, the reused StatmechEnum, and ts_adapters validation
- extra="forbid" at every level: an unknown top-level key already raised a
  TypeError in ARC.__init__, but an unknown species key was silently
  swallowed by ARCSpecies (a "mutliplicity" typo yielded multiplicity 3).
  Guard tests assert the schema fields stay a superset of what
  ARC.__init__ accepts and of what as_dict() emits, so the strictness
  cannot drift out of sync.
- Strict bools and ints: a quoted "False" is truthy to raw ARC and would
  have silently inverted compute_thermo; ARCSpecies rejects a non-int
  multiplicity, so the schema must not launder "3" into 3. Integral floats
  (14.0) are still accepted for job_memory, n_confs and T_count, which raw
  ARC accepts.
- T_min/T_max accept either a bare scalar or a (value, unit) pair, are
  serialized as plain lists (yaml.dump writes !!python/tuple for a tuple,
  corrupting restart.yml) and are restricted to Kelvin, since the unit
  string is never read downstream and [300, 'C'] was silently computed as
  300 K.
- as_input_dict() uses exclude_unset rather than exclude_none: an explicit
  bac_type: None disables BAC, while an absent bac_type defaults to 'p'.
- Public validate_input_dict() so Python-API and T3 callers can opt into
  the same validation without touching ARC.__init__.
- as_dict() now records schema_version and arc_version in restart files;
  ARC.__init__ accepts and ignores them so a raw ARC(**restart_dict) keeps
  working. A newer schema version is an error, an older one warns.

arc/schema_test.py mirrors t3/tests/test_schema.py and adds an end-to-end
check that ARC(**raw).as_dict() equals ARC(**validated).as_dict() over the
real example and restart fixtures.

Declare pydantic in environment.yml, and add a public
get_registered_job_adapters() to arc/job/factory.py so neither arc/main.py
nor arc/schema.py imports the private registry.
draw_kinetics_plots() normalizes a bare scalar T_max to a (value, 'K')
tuple, but used T_min as the value, so a scalar T_max was silently
replaced by T_min. Pre-existing and unrelated to the input schema, but
the schema newly blesses a bare scalar temperature as a valid input
form, which makes this path reachable from a plain input file.
initialize_job_types() aliased the module-level default_job_types dict when
job_types was None and then deleted 'fine_grid' from it (and added 'fine'/
'onedmin'), corrupting ARC's defaults for every subsequent reader in the
process. Copy the dict before mutating it. Surfaced by the input-schema work,
whose JobTypes model reads default_job_types at class-body time and would
KeyError on 'fine_grid' once the global had been corrupted.

This branch has not been deployed

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants