NatLabRockies / NatLabRockies/r2x-cli
fix(cli): pass durable System to context-based class exporters
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 4
- Forks
- 2
- Avg merge
- 1d 4h
- Merged PRs (30d)
- 12
Description
Summary
r2x run <exporter> -i <system.json> rejects a context-based class exporter even after the bridge has loaded the System into PluginContext.system.
This blocks the public durable-boundary contract for r2x-plexos.plexos-exporter.
Environment
r2x-cli 0.1.8(0d384a15cb96c360afb1ff8cc126263f6021d02f)r2x-plexos 0.3.0(51a93284ddeffa3a0964c780cd3c5565b9bd6e8f)r2x synccompleted successfully and does not change the result.
Reproducer
After creating a valid durable translated System with the public CLI:
r2x run r2x-plexos.plexos-exporter \
-i /tmp/geothermal-r2x-018-short-smoke/translated-system.json \
--output-path /tmp/geothermal-exporter-repro \
--model-name Geothermal_A1 \
--horizon-year 2050 \
--weather-year 2012 \
--template PLEXOS10.0
Verbose output shows the contradictory dispatch:
DEBUG: Invoking plugin with target: r2x_plexos:PLEXOSExporter.export
DEBUG: Parsing target: r2x_plexos:PLEXOSExporter.export
DEBUG: Using method 'run' for plugin 'PLEXOSExporter'
Error: Run command failed: Python bridge error: Plugin stream error: plugin method 'PLEXOSExporter.run' does not accept a System or JSON input
The command then aborts with the known GIL finalization failure.
Why this is incorrect
PLEXOSExporter is a context-based r2x_core.Plugin:
- It implements
on_export(self)and obtains the model throughself.system. self.systemreadsPluginContext.system.- It inherits
Plugin.run(self, *, ctx=None); it intentionally accepts no positionalSystemargument.
The bridge already deserializes the -i artifact and passes it into PluginContext.system for the exporter role. It then chooses inherited run() and applies the generic positional-System signature check, rejecting the input before run() can execute on_export().
Additionally, the role-derived PLEXOSExporter.export call target is synthetic: this exporter defines no concrete export() method.
Expected behavior
For a context-based exporter:
- Deserialize
-iintoPluginContext.system. - Construct the plugin from that context.
- Invoke its lifecycle
run()with no positional payload. - Treat the exporter as a terminal sink.
Suggested fix
In the class-plugin bridge, exempt context-based exporter lifecycle invocation from the generic System/JSON positional-argument validation. Once the bridge has populated PluginContext.system, call run() with no positional argument.
Avoid treating a role-derived Class.export string as a concrete class method unless the plugin defines that method. An adapter convention is also viable, but it should preserve the documented r2x run <exporter> -i <system.json> contract.
Regression coverage
Add an integration fixture that:
- defines a class exporter inheriting
Plugin, withon_export()readingself.systemand no concreteexport()orrun()override; - invokes it through direct short-form
r2x run <plugin-ref> -i <durable-system.json>; - verifies the exporter receives the System and writes its configured terminal artifact;
- verifies no JSON is emitted to stdout.
This should cover real r2x-plexos exporter lifecycle semantics without requiring PLEXOS in the CLI test suite.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start at the class-plugin bridge used by the direct short-form r2x run <plugin-ref> -i <durable-system.json> entry point, then reproduce the exporter failure described above. Add the integration fixture with a Plugin exporter whose on_export() reads self.system and has no concrete export() or run() override. Done means the System reaches the exporter, its terminal artifact is written, and no JSON is emitted to stdout.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python, rust
- Domain
- backend, cli
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 55/100