Skip to content

fix(model): thrust arcs wait their duration, bag deploy guarded, imaging pass length, disposal exits, far-field range guard - #41

Merged
HuiJun merged 30 commits into
developfrom
fix/review-modes-sequence
Oct 29, 2026
Merged

HuiJun merged 30 commits into
developfrom
fix/review-modes-sequence

Conversation

@devin-ai-integration

@devin-ai-integration devin-ai-integration Bot commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Closes the six confirmed WP-E review-triage defects (4-1, 4-2, 4-3, 4-5, 4-6, 4-7) in model/60-modes.sysml and model/61-sequence.sysml at their root on the pinned OpenSysML (5cd37f288), re-records only the runs the fixes move, and regenerates the software tables / conformance expectation that follow model 60. The maintainer decisions 4-4 (where stack recovery resumes) and 4-8 (SafeModeExit → deploying vs re-sent ArraysDeployed) are untouched; nothing of the closed #35 beyond the credited general fixes was taken (no arcDuration attribute form, no despin mode, no 2 h → 6 h array timeout).

Each finding was reproduced on the pinned tool before the fix (same probes as the triage: a /tmp probe package with farFieldFlight, shortPassFlight, breachCampaign, plus the committed runs) and re-run after it.

id before (probe) after fix
4-1 thrust arcs collapse the clock runs/sequence-nominal: lunarAssistAt = 11707200.0 [s] (135.5 d), 30 action steps lunarAssistAt = 129211200.0 [s] (1495.5 d), 36 steps; disposal still reached inside the committed -advance 190080000 ThrustArc is now timed: first start; then action burn accept after arcDuration; then done; with arcDuration kept as the in parameter (the pin evaluates parameterised accept after)
4-2 rejected capture deploys the bag runs/modes-tug-dense-target: retreat | standby | highGain | thrusters | deployed … | stowed stowed → deployed carries the capture-commit envelope guard (go.estimatedMass <= envelope.maximumBodyMass and go.estimatedDiameter <= envelope.maximumBodyDiameter) — as in the closed #35
4-3 depleted xenon reports clean disposal breachCampaign (returnArcPlan = 5): outcome = "disposed after 8 thrust arcs", xenonRemaining = -295.0 [kg], xenonReserve = 132.0 [kg] outcome = "xenon reserve breached; disposed after 8 thrust arcs" the final assign outcome prefixes the breach when xenonRemaining < xenonReserve — as in the closed #35
4-5 imaging ignores passDuration shortPassFlight (4 h request): still imaging at +5 h (-advance 108000), exit at +8 h imaging at +3 h, stationKeeping at +5 h InspectorModes gets attribute passDuration : DurationValue = 8.0 [h]; the InspectorImagingGo accept does assign passDuration := go.passDuration; imaging accept after passDuration — as in the closed #35
4-6 disposal thrusts forever runs/modes-tug-full-flight: done | thrusting | highGain | wheels | released done | off | highGain | wheels | released sepString gets state disposalBurn; standby accept DisposalGo … then disposalBurn; disposalBurn accept after disposalBurnDuration then off; disposalBurn accept SafeModeRequest then off — as in the closed #35
4-7 far-field range stops approach thrust farFieldFlight (RangeUpdate(range = 500.0 [km])): approach | standby | … approach | thrusting | … (the 20 km update still ends it) thrusting accept u : RangeUpdate via command if u.range <= rendezvousRange then standby — the flight region's own guard; as in the closed #35

Model 60 transitions/states added or changed (for the software tier)

  • TugModes::sepString: new state disposalBurn; standby --DisposalGo--> disposalBurn (was thrusting); new disposalBurn --after disposalBurnDuration--> off; new disposalBurn --SafeModeRequest--> off; thrusting --RangeUpdate--> standby now guarded u.range <= rendezvousRange.
  • TugModes::captureMechanism: stowed --CaptureGo--> deployed now guarded on the capture-commit envelope.
  • InspectorModes: new attribute passDuration = 8.0 [h]; stationKeeping --InspectorImagingGo--> imaging gains do assign passDuration := go.passDuration; imaging --after passDuration--> stationKeeping (was after 8.0 [h]).

Runs moved

  • sequence-nominal, sequence-small-target, sequence-large-target, sequence-dense-target, sequence-nominal-trace (4-1): lunarAssistAt 11707200 → 129211200 s (small target 107611200 s); arcs, xenon and outcomes unchanged (7 arcs / 955 kg, 6 / 2205 kg, dense target still capture refused); the trace additionally gains the software-tier packages develop lists.
  • modes-tug-dense-target (4-2): final … | stowed.
  • modes-tug-full-flight (4-6): final done | off | …, 27 events; modes-inspector-retired: 27 events (the shared scenario's extra disposal timer), state unchanged.
  • modes-tug-early-ops (4-5): two trace lines for the passDuration initial value.
  • house-rules (80537/703451 → 80552/703658 elements/checks, 0 violations), documents{,-html}/…ModeManagementDesignDescription (the sepString documentation row) and the two render logs' byte counts.
  • fdir-*, sw-*, modes-inspector-imaging (8 h request = default) unchanged.
  • Software: software/generated/{c,go,python} state tables and MANIFEST.sha256 regenerated (101 states / 163 transitions, pinned totals in software/flight/tests/test_system.c and docs/coverage/WP-SW-12.md updated); software/conformance/expected/trace/vc-final-targeting.txt records the one extra model trace event the evaluated RangeUpdate guard adds (host and model agree on all 12 machines).

Software side (model 65 + host), added on review

The flight software copies of the three behaviours had the same defects; fixed from the same sources, reproduced before/after both on the model (/tmp probe conductors on BehaviouralFlightSoftware) and on the host (argent_host stimulus files):

item before after fix
4-5 software side: InspectorHandler::relayingImagery relayed a literal 8 h 4 h request: model handler still relayingImagery at +5 h; host InspectorHandler still relaying at +4 h model released at +4 h; host released at +4 h the handler assigns passDuration := go.passDuration from the InspectorImagingGo it accepts and waits after passDuration (no default: relaying is only entered by a request); the host resolves passDuration from the item (INSPECTOR_HANDLER_E1), and on-board sequence 3 sends its InspectorImagingGo with the campaign's 8 h
review: far-field RangeUpdate stopped the real SEP controller model SepStringController standby after RangeUpdate(500 km); host standby, and host TugModes left approach (its guard compared km against 50000 m) model and host controller thrusting; TugModes approach | thrusting; the 20 km update still stops it the dispatcher's RangeUpdate transition is gated u.range <= modes.rendezvousRange (MODE_MANAGEMENT_DISPATCHER_G1); the host constants compare in km, the unit the uplinked item carries
review: the disposal burn never stopped the real SEP controller with ground contacts keeping the command-loss timer armed: model and host controller thrusting at 30 d+ disposalBurn until 30 d, then off, sim.sep_thrusting false the disposal dispatch sends SepDisposalBurn(duration = modes.disposalBurnDuration); SepStringController gets disposalBurn (after burnDuration → off, SepOff → off, ThrusterFlameout → restarting)

Model 65 states/transitions added: SepStringController::disposalBurn with standby --SepDisposalBurn--> disposalBurn, disposalBurn --after burnDuration--> off, disposalBurn --ThrusterFlameout--> restarting, disposalBurn --SepOff--> off; InspectorHandler::released --InspectorImagingGo--> relayingImagery gains the assign, relayingImagery --after passDuration--> released; dispatcher RangeUpdate guarded. Totals 102 states / 167 transitions / 21 guards / 39 effects (WP-SW-10, WP-SW-12, test_system.c). Three host system tests pin the three behaviours.

Declared: a flameout during the disposal burn restarts into the open-ended thrusting (the restart loses the burn timer, as the previous open-ended disposal thrust did); the host's dispatcher also echoes the sequence's InspectorCheckoutGo to the handler (pre-existing, unchanged).

Runs moved by this part: sw-* object-id shifts only (no Current state: change), sw-mode-manager-dispatch-sequence (SepThrust → SepDisposalBurn at disposal), sw-doc-sdd-flight-SepControl + the SepControl design description (new row), house-rules 80574/703914 (0 violations), *-satisfy id shifts. Conformance expectations unchanged (host/model still agree on all 12 machines).

Behaviour changes

  • No recorded verdict flips. Final states that moved: dense-target capture mechanism deployed → stowed; full-flight SEP string thrusting → off.
  • Software: the SEP controller now ends the disposal burn (disposalBurn → off after disposalBurnDuration), ignores far-field range updates, and the inspector handler relays for the requested pass.
  • Mission timeline now takes its real duration: lunar assist at ~1495 d instead of 135 d (schedule reference ~1480 d).
  • A reserve-breaching campaign now ends "xenon reserve breached; disposed after N thrust arcs".

Gates (pinned OpenSysML 5cd37f288, Java 21 for the pilot)

make validate no errors · make house-rules 80579 elements, 703966 checks, 0 violations (merged develop d49d64b) · make pilot-mission, make pilot-all exit 0 · make runs-check / make check clean · make software-check tables identical, 11 pytest passed · make software-flight-check 9313 checks, 0 failing · make software-conformance-check OK (12 machines agree) · make software-ground-check OK.

devin-ai-integration Bot and others added 14 commits October 23, 2026 23:54
…advances

ThrustArc now has a timed body (first start; then action burn accept after
arcDuration; then done), so each outbound and return arc takes its planned
duration and lunarAssistAt in sequence-nominal moves from 135.5 d to 1495.5 d,
in line with baselineSchedule.lunarGravityAssist (1480 d). The recorded
-advance 190080000 horizon still reaches disposal; sequence-* runs re-recorded.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
…mit envelope

The captureMechanism region accepted every CaptureGo, so a refused capture
(flight region to retreat) still left the bag deployed. The stowed->deployed
transition now carries the same envelope guard as the flight region's
proximityOperations->capture transition; modes-tug-dense-target re-recorded
(ends ... | stowed).

Co-Authored-By: jason.han <hanhuijun@gmail.com>
…racterised body

Despin takes the characterisation and the thrusters' arm and Isp as inputs and derives its angular momentum, duration and propellant through TethysCaptureSystem::DespinDuration and DespinPropellant, so the capture sequence carries 348 s and 5.91 kg for the nominal body instead of leaving both unbound. New run wpc-despin-step records the three values.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
…s rendezvousRange

The sepString region dropped to standby on any RangeUpdate, so a far-field
range report (500 km) stopped the approach thrust while the flight region
stayed in approach. The transition now carries the flight region's own guard
(u.range <= rendezvousRange), so only the rendezvous update ends the burn.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
…equence

Co-Authored-By: jason.han <hanhuijun@gmail.com>

# Conflicts:
#	runs/sequence-nominal-trace.txt
InspectorModes left imaging after a literal 8 h whatever InspectorImagingGo
asked for: a 4 h pass was still imaging at +5 h and ended at +8 h. The machine
now keeps a passDuration attribute (default 8 h), the accept of the command
assigns it from go.passDuration and the imaging exit waits that duration, as in
the closed #35. Re-recorded modes-tug-early-ops (the attribute's initial value
now shows in the trace).

Co-Authored-By: jason.han <hanhuijun@gmail.com>
…tion elapses

DisposalGo took sepString to thrusting with no exit, so the full-flight run
ended done | thrusting | ... with the string burning forever. The disposal arc
is now its own disposalBurn state that times out to off after
disposalBurnDuration (and goes off on SafeModeRequest like thrusting), as in
the closed #35. Full flight now ends done | off | highGain | wheels | released;
modes-inspector-retired moves by the one extra timer event.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
…isposal

The reserve-breach outcome set before the lunar assist was overwritten by the
unconditional "disposed after N thrust arcs" at the end of the campaign, so a
campaign that ran the reserve negative still reported a clean disposal. The
final outcome now carries the breach ("xenon reserve breached; disposed after
N thrust arcs"), as in the closed #35. The committed campaigns do not breach,
so no sequence run moves.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
…osal transitions

The generated C/Go/Python state-machine tables follow model 60: the sepString
RangeUpdate transition now carries TUG_MODES_G1, stowed -> deployed carries
TUG_MODES_G2, and sepString gains the disposalBurn state with its timed and
safe-mode exits (101 states / 163 transitions; the pinned totals in
test_system.c and WP-SW-12 move with them). The conformance expectation for
vc-final-targeting records the one extra model trace event the evaluated
RangeUpdate guard adds; host and model still agree on every machine.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
The trace now lists the software-tier packages develop added and the extra
literal evaluations develop's recording already shows; the mission itself is
unchanged (7 arcs, lunar assist at 129211200 s, disposed).

Co-Authored-By: jason.han <hanhuijun@gmail.com>
…the disposal quantities

TS-292's constraint now has a time term: passivationDelay (closeout
passivationCompleteTime - disposalBurnTime, 23 d) <= deadline (30 d).
SeparationDeltaV takes an ImpulseValue and a MassValue and returns a
SpeedValue, dividing the units out only inside the calc; TS-293 reads
TethysTarget::targetCases.{small,nominal,large}.mass and
amaranthFM.postCapture.mass instead of the stale 150/362/620/438.8 t
literals, and compares against 1.0e-3 m/s.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
Adds the wpc-despin-step and disposal-quantities runs and re-records
the four runs the model edits move (house-rules counts, one ID shift
in the three satisfy runs).

Co-Authored-By: jason.han <hanhuijun@gmail.com>
…cription

The new sepString state, attribute and transitions move the house-rules
element/check counts (80537/703451 -> 80552/703658, still 0 violations) and
the sepString documentation row of the ModeManagementDesignDescription
rendering (md and html, with their byte counts in the render logs).

Co-Authored-By: jason.han <hanhuijun@gmail.com>
@devin-ai-integration

Copy link
Copy Markdown
Contributor Author

I'll fix CI failures and address comments from users with write access. I'll skip comments containing "(aside)".

  • Disable automatic comment, CI, and merge conflict monitoring

devin-ai-integration Bot and others added 6 commits October 29, 2026 02:21
…critical count, document inventory queries

Review triage findings 3-2, 3-3, 3-4, 3-5, 5-2, 5-3, 5-5 and the integration-review documentation nits.

- 3-2 TethysRisk::riskRegister::noUnownedRedRisk quantifies over the new items : RiskItem[*] collection every register entry subsets, instead of naming earthImpactRisk; risk-constraints instantiates the register so the gate evaluates on it.
- 3-3 TH-001's returnTrajectoryInsideCorridor and lossOfThrustOnFinalArc causes are connected to earthImpact like the other hazards.
- 3-4 safetyCriticalSoftwareFunctions = 2 is replaced by the query TethysAllocationQueries::SafetyCriticalFunctions over @safetycritical.
- 3-5 Reliability durations are DurationValues in [d] and [h].
- 5-2 TugSubsystems reads TethysTug::Tug (10 rows, was 4).
- 5-3 Segments and Items exclude InterfaceUsage / InterfaceDefinition.
- 5-5 Risks scans TethysRisk and TethysSafety (6 rows, was 0).
- docs: IcdFlightSegment::inspectorDispenser, SE-049/SE-260/SE-278 rows say what the model shows, KerML citation §8.3.2.4.5.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
…rdering, capture function owner

- TethysTrades::PowerAvailableToSep takes the propulsion system's maximum power and returns the lesser of the aphelion-scaled array power and that limit; the array trade reads it from argent.sep.maximumPower, so the 48 kW and 70 kW options both thrust at 40 kW and the cost sweep keeps array48kW at every penalty.
- TethysPhysics::XenonTransfer flows tank.remaining to thruster.xenonIn, the target its general Feeds declares, not thruster.inputPower.
- TethysNotation windowIsOrdered requires opens < closes AND not marginal, as its documentation says.
- argentDesign performs functions.captureBody on captureSystem (ArgentCapture, which declares CaptureBody's inputs), not on structure.
- CONVENTIONS.md states the 81-physics.kerml Real/SI-base-unit contract as the one declared exception to the units rule.

Runs re-recorded: trades, trades-sweep, house-rules (element count) and the traces/ids that move with the capture perform's owner.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
…Ordered literals

WP-G LANG-223/225 quote the flow as it now reads (to thruster.xenonIn); LANG-347/348 cite only ReturnWindow::marginal = false, since windowIsOrdered no longer carries a boolean literal.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
…ring documentation

Co-Authored-By: jason.han <hanhuijun@gmail.com>
The inventory of @safetycritical functions showed documentation = (none) for all three rows; the reason for each classification lives in SafetyCritical::rationale, so the query projects that instead. Re-recorded allocations-queries.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
A passivation recorded before the disposal burn gave a negative
passivationDelay that satisfied the 30 d upper bound alone; the
constraint now requires 0 d <= passivationDelay <= deadline.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
@devin-ai-integration
devin-ai-integration Bot marked this pull request as ready for review October 29, 2026 03:42
devin-ai-integration[bot]

This comment was marked as resolved.

devin-ai-integration Bot and others added 5 commits October 29, 2026 04:22
…dates and ends the disposal burn

Model 65's InspectorHandler relayed every imaging pass for a literal 8 h; it now
assigns the passDuration the InspectorImagingGo carries and waits for it, as the
inspector's own modes do. The mode manager's dispatcher sent SepStandby for every
RangeUpdate; it now gates on the mode machine's rendezvousRange like the SEP
region. The disposal dispatch sent an open-ended SepThrust; it now sends a
SepDisposalBurn carrying the mode machine's disposalBurnDuration and the
SepStringController burns in a disposalBurn state that times out to off (or
leaves on SepOff / restarts on a flameout).

Regenerated state tables (102 states, 167 transitions, 21 guards, 39 effects);
re-recorded the runs the new elements move (ids, house-rules counts, the
SepControl design description, the dispatch sequence's SepDisposalBurn).

Co-Authored-By: jason.han <hanhuijun@gmail.com>
…ge gate

The duration resolver answers burnDuration / passDuration from the value the
SepDisposalBurn / InspectorImagingGo item carried (effects SEP_STRING_CONTROLLER_E1,
INSPECTOR_HANDLER_E1); the dispatcher guard MODE_MANAGEMENT_DISPATCHER_G1 and
TugModes' range guard compare in km, the unit the uplinked RangeUpdate carries;
the disposal burn drives the thrust simulation like an arc; on-board sequence 3
sends InspectorImagingGo with the campaign's 8 h pass. Three system tests pin the
far-field update, the 30 d burn and the 4 h pass.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
…osure rule

SpecificImpulseTrade computed its own required xenon (argent.wetMass, one return arc, no inspector release, no missed-thrust margin) and penalised only xenon above the raw load, so no option was ever infeasible and the trade selected isp2000 against its Rationale and argent.sep.specificImpulse. TethysBudgets::XenonForMission now takes the Isp as an input (the propellant budget passes argentDesign.sep.specificImpulse; its recorded values are unchanged), the trade calls it for the nominal case at each option's Isp, and the feasibility penalty is TethysMarginPolicy::ClosesWithMargin against propellantBudget.usable with the active policy, as the budget asserts. The Rationale text carries the recomputed numbers. Re-recorded runs/trades.txt and the house-rules element count.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
…inventory

The calc inventory in argent_conformance/calcs.py listed XenonForMission with only its body parameter after the Isp input was added; the entry stays skipped (body is a SmallBody part) but now carries the current signature, and its recorded expectation header follows.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
…equence

Co-Authored-By: jason.han <hanhuijun@gmail.com>

# Conflicts:
#	runs/house-rules.txt
devin-ai-integration Bot and others added 5 commits October 29, 2026 14:47
…documents

Co-Authored-By: jason.han <hanhuijun@gmail.com>

# Conflicts:
#	runs/house-rules.txt
Co-Authored-By: jason.han <hanhuijun@gmail.com>
…sposal

Co-Authored-By: jason.han <hanhuijun@gmail.com>
…tructure

Co-Authored-By: jason.han <hanhuijun@gmail.com>
…quence

Co-Authored-By: jason.han <hanhuijun@gmail.com>

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Devin Review found 2 new potential issues.

1 flag not posted on this PR by your GitHub settings — view it in Devin Review. (Configure)

Devin Review

Comment thread model/86-risk.sysml
doc /* The project risk register at the start of Phase B. Identifiers TK-nnn. */
doc /* The project risk register at the start of Phase B. Identifiers TK-nnn. Every
* entry subsets `items`, the collection the register-wide gates quantify over. */
part items : RiskItem[*];

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

🟡 Risk register displays a phantom entry

Every rendering of riskRegisterView includes items as a seventh risk. The view exposes all register parts, including this collection, which has no risk details.

Learn more

The risk register view exposes every member of riskRegister through riskRegisterView. The new collection is a part usage of RiskItem, so the grid includes it alongside the six named risks. The checked-in rendering confirms an extra row with no risk identity or values.

Example: With TK-001 through TK-006 defined, the grid begins with an items row and then lists those six risks; a reader sees seven apparent risk entries instead of six.

Recommended fix: Filter riskRegisterView to expose only the six concrete risk entries, or make the collection a non-part feature excluded by the grid while preserving its use by noUnownedRedRisk. Regenerate the pinned renderings.

Devin Review


Was this helpful? React with 👍 or 👎 to provide feedback.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Confirmed: riskRegisterView exposes riskRegister::* with the GridView filter @SysML::PartUsage, and part items : RiskItem[*] (the quantification set noUnownedRedRisk iterates) is a part usage, so the pinned rendering carries an items row before TK-001…TK-006. The code comes from 3123ac4 (fix/review-safety-documents, #44), stacked under this branch by the maintainer; the fix (exclude the collection from the grid — e.g. a non-composite ref part items with the view filtering on composite parts, or exposing the identified risks only — and re-render) is held until the maintainer says on which branch of the stack it lands.

Comment thread model/71-trades.sysml
in housekeepingW : Real;
return sepPowerW : Real =
powerAtOneAuW * SolarFlux(amaranth.orbit.aphelionAu) / SolarFlux(1.0) - housekeepingW;
in maximumSepPowerW : Real;

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

🟡 SEP power limit loses its unit type

maximumSepPowerW represents electrical power but uses bare Real outside the KerML exception. The units convention requires an ISQ quantity type for every SysML physical quantity.

Learn more

The repository's units convention requires ISQ types and SI literals for physical quantities in SysML packages; only the KerML physics library accepts and returns untyped SI-base-unit Real values. This new parameter is a power quantity in a SysML trade calculation. Changing the declaration alone would not work because its expression and caller currently divide quantities into numeric watts.

Example: A caller supplies a numerical maximum SEP power to PowerAvailableToSep; the signature gives no unit type that distinguishes watts from kilowatts.

Recommended fix: Type the power inputs and return as PowerValue, perform the calculation using quantity values and unit literals, and update the ArrayPowerTrade call accordingly.

Devin Review


Was this helpful? React with 👍 or 👎 to provide feedback.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Confirmed against CONVENTIONS.md: maximumSepPowerW : Real is a power quantity declared as bare Real in a SysML package. It follows the calc def's pre-existing shape (powerAtOneAuW, housekeepingW were already bare Real, the caller dividing by 1 [W]), so the finding is conformance debt the new parameter widened by one input rather than a wrong number. The code comes from 45fd390 (fix/review-analyses-structure, #42), stacked under this branch by the maintainer; typing the three inputs and the return as PowerValue (the solar-flux ratio is dimensionless, so the expression stays valid; the min needs its quantity form) and updating the ArrayPowerTrade call is held until the maintainer says on which branch of the stack it lands.

@HuiJun
HuiJun merged commit 62ae379 into develop Oct 29, 2026
5 checks passed
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.

1 participant