Skip to content

fix(pdep): let the pdep parser read T3's own transitionState('TS2', 'qm/TS2.py') - #197

Merged
alongd merged 1 commit into
mainfrom
i016-ts-positional
Aug 24, 2026
Merged

fix(pdep): let the pdep parser read T3's own transitionState('TS2', 'qm/TS2.py')#197
alongd merged 1 commit into
mainfrom
i016-ts-positional

Conversation

@alongd

@alongd alongd commented Aug 23, 2026

Copy link
Copy Markdown
Member

What this fixes

T3's PES exploration loop crashed in round 1 on a hybrid network file T3 itself wrote in round 0, during the first run of the loop against real quantum chemistry:

ValueError: The pdep network file at '.../round_0/hybrid/network0_reduced.py' calls
'transitionState(...)' with 2 POSITIONAL argument(s); refusing to parse it because this module
reads keywords by name and would silently record the positional values as absent.

t3/pdep/hybrid.py emits transitionState('TS2', 'qm/TS2.py') when it vendors a QM-adopted transition state; t3/pdep/parser.py::_call_keywords refuses every positional argument. Producer and consumer are both inside T3 and they disagreed.

Why the fix is on the reader's side

The obvious fix — make the writer use keywords — does not work. arkane/input.py:241 is def transitionState(label, *args, **kwargs), and its load-a-statmech-file-from-a-path branch is guarded by if len(args) == 1 and len(kwargs) == 0. Arkane offers no keyword spelling for path-loading, and Arkane reads this same file, so transitionState(label=..., path=...) would silently stop loading the QM statmech file.

The guard's premise is what was wrong. Its comment justifies refusing positionals by surveying "zero of the 156 parseable files under RMG-Py's examples/ and arkane/data/". That survey is real and its conclusion does not hold here, because the corpus never contained T3's own writer's output.

The change

One narrow exception in _call_keywords, ahead of the unchanged refusal: when the call is transitionState with exactly two positional arguments and no keywords, map args[0] -> label, args[1] -> path. Every other positional shape — one or three-plus positionals, positionals mixed with keywords, and this same two-positional shape for species/reaction — still falls through to the refusal, which is deliberate: mapping positions to names generally would mean duplicating Arkane's signatures and keeping them in step forever.

Both _call_keywords call sites that can see a transitionState node (parse_pdep_network_text and parse_pdep_network_e0_text) pass call_name and are therefore covered.

Testing

The real crashed artifact is vendored at tests/data/pdep_hybrid/positional_ts/network0_reduced.py with a provenance README, since the run directory it came from is scratch.

  • It parses, and the parse recovers both the label and the path ({'label': 'TS2', 'path': 'qm/TS2.py'}) — not merely "no exception raised".
  • Mutation: removing the exception turns those tests red with the verbatim production error; restoring it returns them to green.
  • tests/test_pdep: 1902 passed.

Not covered, deliberately

arkane/input.py line ~130 gives species(label, *args, **kwargs) the identical path-loading shape, so the same trap is latent there. T3's writer never emits a positional species(...) — the hybrid writer's species channel is keyword-form — so covering it now would widen the guard to a spelling nothing writes, and would need a fabricated fixture. Until a writer path does emit it, the parser refuses loudly rather than mis-parsing silently, which is the safe failure direction.

@codecov-commenter

codecov-commenter commented Aug 23, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 82.71%. Comparing base (3992f60) to head (92f10be).

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #197      +/-   ##
==========================================
- Coverage   82.73%   82.71%   -0.02%     
==========================================
  Files          72       72              
  Lines       11720    11722       +2     
  Branches     2526     2527       +1     
==========================================
  Hits         9696     9696              
- Misses       1433     1434       +1     
- Partials      591      592       +1     
Flag Coverage Δ
unittests 82.71% <ø> (-0.02%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 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.

Copilot AI left a comment

Copy link
Copy Markdown

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 fixes a producer/consumer mismatch within T3’s pdep hybrid workflow by teaching the pdep parser to accept Arkane’s required two-positional transitionState(label, path) form that T3 itself writes into hybrid network files.

Changes:

  • Allow _call_keywords to map transitionState('TS2', 'qm/TS2.py') into {'label': ..., 'path': ...} while continuing to refuse other positional-argument shapes.
  • Add regression tests asserting the real hybrid artifact parses and that both label and path are recovered.
  • Vendor the real crashed hybrid network file plus provenance documentation under tests/data/.

Reviewed changes

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

File Description
t3/pdep/parser.py Adds a narrowly-scoped exception so transitionState(label, path) positional form is parsed into keywords.
tests/test_pdep/test_parser.py Adds regression tests covering the real crashed artifact and the narrowness of the exception.
tests/data/pdep_hybrid/positional_ts/README.md Documents provenance and the load-bearing line in the vendored artifact.
tests/data/pdep_hybrid/positional_ts/network0_reduced.py Adds the byte-for-byte hybrid network fixture that previously triggered the crash.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread t3/pdep/parser.py
Comment on lines +1336 to +1337
if call_name == 'transitionState' and len(call.args) == 2 and not call.keywords:
return {'label': call.args[0], 'path': call.args[1]}

def test_real_hybrid_file_parses(self):
"""Verifier 1: the real crashed artifact drives through the pdep parser and parses."""
network = parse_pdep_network_file(HYBRID_POSITIONAL_TS_FILE)
…qm/TS2.py')

The PES loop writes a hybrid network in round 0 and reads it back in round 1.
When a transition state is adopted from quantum chemistry, the writer
(t3/pdep/hybrid.py) rewrites it to transitionState('<label>', 'qm/<label>.py')
-- two positional arguments -- because that is the ONLY spelling Arkane accepts
to load a stat-mech file from a path (arkane/input.py:241, path-loading guarded
by `len(args) == 1 and len(kwargs) == 0`; the keyword spelling silently disables
it). The reader's _call_keywords refused every positional argument, so T3 crashed
on the very file it had written minutes earlier.

Widen the refusal by exactly one form: transitionState(label, path) with two
positionals and no keywords maps to {'label', 'path'}. Every other positional
shape, and this same shape for any other call name, still falls through to the
refusal -- the guard caught a real producer/consumer inconsistency and is not
relaxed generally. The writer is left untouched; it is correct for Arkane.

Vendored fixture is the byte-for-byte hybrid file from the r001_m1-cho2-pilot run
that actually crashed. A test drives it through parse_pdep_network_file and
asserts both TS2's label and its path are recovered -- not merely that no
exception is raised.
@alongd
alongd force-pushed the i016-ts-positional branch from 723c7ae to 92f10be Compare August 24, 2026 08:12
@alongd
alongd merged commit 8752bb3 into main Aug 24, 2026
4 checks passed
@alongd
alongd deleted the i016-ts-positional branch August 24, 2026 16:43
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.

3 participants