feat: Band 4 — the answer holds up (live verification across transports and the converter pack) - #90
Open
tinix84 wants to merge 9 commits into
Open
Conversation
Live checks are selected by the `live_plecs` marker (deselected by default), probe the configured XML-RPC endpoint once and skip naming host:port, and run under temporary isolated configuration. The canonical buck is pinned as data (model, Operating Point `nominal`, Signal Map for the 13 probe outputs, five-period window, #61 tolerances, observed PLECS 4.7.7 facts). The oracle fails closed on missing signals, non-monotonic time, too few periods or non-convergence, checks analytic buck invariants, and compares time-weighted steady-state metrics against a recorded reference — never sample goldens. Each live run leaves an Evidence Bundle under tests/evidence. The Band 1 TAS smoke moves from PYPLECS_RUN_LIVE_TAS onto the same marker. Refs: #85, #86, #57, #60, #56 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…-api boots the live adapter `simulation_result_payload` next to normalization is now the single place that turns a Simulation Result into `time` + named `signals`; the REST result route gains those fields (keeping `timeseries_data` for v1.x), the sync route and the MCP `simulation_result` tool call the same function. The sync route honours the app's resolved PLECS endpoint and auto-launch setting instead of hard-coding port 1080. `pyplecs-api` startup builds its orchestrator with `LivePlecsAdapter`, so a REST submission reaches PLECS instead of failing with "no adapter" (#48). Live: Python, REST async, REST sync and a real MCP `ClientSession` over memory streams return the same normalized answer for the canonical buck on PLECS 4.7.7 — identical signal names, 1205 samples, max |Δsample| = 0 — and a second transport hits the Cache Record the first one wrote. Refs: #87, #48, #46, #80, #59 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…o SPICE ** The pack (`uv run pytest -m converter_acceptance`) reads LTspice ASCII raw exports from the evidence inbox (or runs LTspice when PYPLECS_LTSPICE is set), maps raw variables to the canonical Signal Map through explicit signed expressions, checks fail-closed preconditions, compares the last five periods' time-weighted metrics against PLECS under the #61 tolerances, records phase-aligned NRMSE as advisory only, and leaves an Evidence Bundle with a dependency-free overlay. Missing evidence fails naming the file; nothing skips. First run against PLECS 4.7.7 / LTspice 26.0.1 exposed two converter defects: - `.param Ro=Vo_ref^2/Po` was copied verbatim; `^` is XOR in SPICE, so the load was wrong and every current ~3x off. Fixed here: PLECS `^` becomes SPICE `**` in every emitted expression. With that, all 65 steady-state metrics agree (v_C 11.7827 vs 11.7811 V, i_L RMS 4.2783 vs 4.2786 A). - The `.asc` wires symbol origins rather than pin offsets (12 floating nodes) and carries no gate source, so LTspice cannot run it. Left as a strict xfail pointing at #20. Refs: #88, #61, #20, #56 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Record the Band 4 decision once: live checks are selected by marker, probe availability, run under isolated configuration, compare steady-state metrics against a recorded reference plus analytic invariants, leave an Evidence Bundle, and never gate a push. CONTEXT.md gains Evidence Bundle; README shows the two opt-in commands inside its 150-line cap; the Decision Log has its row. The sync-route tests pass a minimal request object now that the route reads the app's resolved PLECS endpoint. Refs: #89, #62, #56 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
`tests/test_basic.py` (PLECS GUI automation) and `tests/test_webgui.py` (a script against a running dashboard) broke collection of the whole tree whenever `pywinauto` or `aiohttp` was absent, so `uv run pytest` and `uv run pytest -m live_plecs` could only be run with hand-typed ignores. Both now `importorskip` their optional dependency; the GUI script carries the `live_plecs` marker because it drives PLECS. Refs: #85 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Python edits had rewritten CLAUDE.md, CONTEXT.md, README.md, the ADR index, .gitignore, pyproject.toml and simulation_sync.py as LF, turning one-line changes into whole-file diffs. Endings are restored line by line from the base blobs; content is unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Standards: the oracle speaks CONTEXT.md's language — it compares Design Quantities, not "metrics" (ADR-0013 renamed accordingly); the duplicated payload reducer in the oracle is gone in favour of `simulation_result_payload`; `to_spice_operators` says what it does and why the double swap is idempotent; pandas is imported at module level. Spec: the converter pack always takes PLECS live as its reference (no stale recorded-series fallback); the `.asc` check is a plain failure on missing evidence and an imperative xfail only when the known #20 defect is present; the `.asc` structural check now compares LTspice's netlisted node count with the Circuit Model's nets; cross-transport agreement applies the 0.1 % rule to every quantity with no absolute floors; the selection test covers both markers. Evidence and the recorded reference were regenerated once under the new schema (one recording, one comparison, transports, converter, asc). Refs: #84, #85, #86, #87, #88, #89 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…response proven against PLECS The first import adapter on the Circuit Model seam (ADR-0001, #43 track 1): `parse_ltspice` reads WIRE/FLAG/SYMBOL/SYMATTR/TEXT, places pins with the LTspice library's offsets under the rotate-then-mirror rule (verified against LTspice 26's netlister for all eight orientations), joins pins to wires at endpoints and interiors, names nets from labels with `FLAG 0` as ground, and turns values into PLECS expressions (unit suffixes to exponents, braces off, `**` to `^`); `.param`/`.tran` become the initialization variables the `.plecs` emitter expects. Only symbols with a PLECS counterpart are accepted; anything else fails naming the symbol. `ltspice_to_plecs` and `pyplecs-convert file.asc --format plecs --probe COMPONENT:SIGNAL` expose it. `tests/fixtures/rc_step.asc` is an RC low-pass with a 1 V step at t = 0 (DC source, capacitor initial voltage 0), authored in LTspice. Under the `converter_acceptance` marker it is run in LTspice, imported and run in the live PLECS, and the capacitor voltage compared point-wise on a common grid and against step*(1 - exp(-t/tau)): LTspice 26.0.1 vs PLECS 4.7.7 agree to 1.06e-7 of the step, both within 1.3e-7 of the analytic response. Refs: #91, #92, #93, #43 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #83 (Band 3), which is stacked on #74 (Band 2). Merge order: #74 → #83 → this.
Band 4 — "the answer holds up". Spec #84 (answers grilling #62 on map #56); tickets #85–#89; decision ADR-0013.
What this proves, live, on the PLECS installed here (4.7.7)
uv run pytest -m live_plecs— the canonical buck (data/simple_buck_prb.plecs, Operating Pointnominal) passes a metric-free-of-goldens oracle: strictly increasing time, ≥ 5 periods, required signals present, ≤ 1 % convergence, analytic buck invariants (D·Vi bound,v_C ≡ v_R,i_R = v_R/Ro,i_L ≈ i_R, ripple ≈ (Vi−Vo)·D/(fs·Lo)), and every steady-state Design Quantity within the Choose the semi-manual .cir and .asc acceptance matrix #61 tolerances of a tracked recorded reference.ClientSessionagainst the Simulation MCP Server return the same normalized answer — identical signal names, 1205 samples, max |Δsample| = 0 — and a second transport hits the Cache Record the first one wrote.PYPLECS_LTSPICE=… uv run pytest -m converter_acceptance— the emitted.cirreproduces PLECS in LTspice 26 on all 65 steady-state Design Quantities (v_C 11.7827 vs 11.7811 V; i_L RMS 4.2783 vs 4.2786 A). The.ascdoes not load (known emitter defect, reported on feat: PLECS-to-netlist converter (.cir + .asc) #20, imperative xfail with a written checklist). Missing evidence fails naming the file; nothing skips.Every run leaves an Evidence Bundle under
tests/evidence/…(tracked: manifest, versions, quantities, comparison, summary; untracked: raw series, overlays).Code changes outside tests
pyplecs/normalization.py:simulation_result_payload— the one place a Simulation Result becomestime+signals; REST result route (new fields,timeseries_datakept), sync route and the MCP tool use it (architecture 2/5: concentrate Raw PLECS Result normalization #46).pyplecs/api/__init__.py:pyplecs-apiboots its orchestrator withLivePlecsAdapter— a REST submission reaches PLECS instead of "no adapter" (architecture 4/5: concentrate the Simulation Task lifecycle #48).pyplecs/api/simulation_sync.py: honours the app's resolved PLECS endpoint / auto-launch instead of hard-coding port 1080.pyplecs/converter: PLECS^(power) → SPICE**in every emitted expression (^is XOR in SPICE; found by the pack).pyproject.toml:live_plecs/converter_acceptancemarkers, deselected by default. The pre-push gate is unchanged.Architecture epic
#46–#49 were implemented in Bands 1–3 and never closed; each carries an evidence comment mapping its acceptance list to tests. The only remaining gap (#48's
pyplecs-apibootstrap) is fixed here.Review
Two-axis review run; both axes' findings addressed in
ca7d61aand9be474a(line endings restored; Design-Quantity vocabulary; no stale-recording fallback; floor-free 0.1 % transport agreement;.ascnet-count check; imperative xfail).Added at the maintainer's request: LTspice → PLECS (#43 track 1; spec #91, tickets #92/#93)
parse_ltspice(.asc→ Circuit Model) — pin geometry from LTspice's own symbol library, rotate-then-mirror placement verified against LTspice 26's netlister in all eight orientations; fail-closed on unknown symbols.ltspice_to_plecsandpyplecs-convert x.asc --format plecs --probe C1:'Capacitor voltage'.tests/fixtures/rc_step.asc: RC low-pass with a 1 V step authored in LTspice. Under-m converter_acceptanceit runs in LTspice, is imported and run in PLECS, andv_C(t)is compared point-wise and against the analytic response: LTspice 26.0.1 vs PLECS 4.7.7 agree to 1.06e-7 of the step, both within 1.3e-7 of1 − e^(−t/τ)(evidence:tests/evidence/rc_step/step/*-ltspice-import/).Left open on purpose
ready-for-human..ascemitter defect → feat: PLECS-to-netlist converter (.cir + .asc) #20.Closes #85, #86, #87, #88, #89, #91, #92, #93, #46, #47, #48, #49, #29.
Refs: #84, #56, #57, #60, #20, #43.
🤖 Generated with Claude Code