AC OPF solver decision
Status: accepted for feasibility work. Recorded 24 September 2026. On 29 October 2026 the release owner approved EPL-2.0 distribution of the WASI asset, and the website serves it as an experimental, base-case-only calculation. Release gates 2 to 5 below remain open.
Backend update — 4 November 2026
The native and dedicated WASI paths now pin the published, checksummed
pounce-nl = pounce-rs = 0.15.0 release, with FERAL 0.22.0. The release and
source-manifest guard checks all 16 POUNCE crates. The two new transitive
crates, pounce-convex and pounce-sens-core, have explicit EPL-2.0 exceptions
alongside the existing POUNCE crates in deny.toml.
POUNCE 0.15.0 adds complementarity support, which Tellegen does not use. Four upstream changes can move Tellegen’s solves:
perturb_slack_max_rows(new in 0.15.0, default 1000) caps the inertia correction’s slack-block perturbation. A model with at most 1000 inequality rows solves exactly as before; above that, solves that hit inertia correction can take a different path.- Restoration’s release test now uses the outer filter’s own quantities (0.14.0). A failed base solve can end with a different status, which changes which second-opinion rungs follow.
- The second-opinion ladder gained a saddle-escape rung after an infeasibility verdict (0.14.0).
- A stop requested from the intermediate callback is now honoured during
POUNCE’s automatic re-solves (0.15.0). The ladder itself still runs its
remaining rungs after
UserRequestedStop, so Tellegen keeps refusing their initialization once cancelled.
The SQP handover added in 0.14.0 is off by default and stays off. Tellegen
continues to construct its existing polar AC OPF model through
NlProblemParts and apply its independent physical validator, with unchanged
POUNCE_OPTIONS. The dependency update does not add a complementarity
formulation or change the public API. The validation results below for 0.13.0
remain historical evidence for that release.
Local validation used Rust 1.96.0 on macOS arm64: all 428 enabled engine tests
and the WASI adapter test passed, along with strict all-target AC OPF Clippy,
the HS071 probe, release/source-manifest checks, and the EPL isolation guard.
The release wasm32-wasip1 build also solved the existing three-bus planning
fixture using the production WASI host under Node: objective
631.5334170921521, 12 iterations, and active/reactive balance residuals below
5e-12 MW/MVAr. This was a reactor smoke test; the browser UI was not rerun.
The engine tests solve only three- and four-bus cases, below the 1000-row
threshold, so the native acopf_benchmark example compared 0.13.0 and 0.15.0
on 14 PGLib v23.07 cases (case14_ieee to case4661_sdet). Both versions
solve the same 13 cases, and every objective agrees within 1e-12 relative.
Nine solve identically: same status, iterations and objective. The rest:
| Case | 0.13.0 | 0.15.0 | Cause |
|---|---|---|---|
case793_goc | succeeded, 210 it, 1.8 s | acceptable, 137 it, 1.3 s | slack cap |
case1354_pegase | 192 it, 3 restorations | 190 it, 2 restorations | restoration test |
case1888_rte | 605 it, 10.2 s | 788 it, 14.1 s | slack cap |
case3012wp_k | base step error, rescued by mu_strategy=adaptive | base restoration failure, same rescue | restoration test |
case4661_sdet | fails after 1 rung, 615 it, 123 s | fails after 3 rungs, 1824 it, 244 s | restoration test |
Times are single serial runs. A third build, 0.15.0 with
perturb_slack_max_rows 0, reproduced 0.13.0 exactly on case793_goc and
case1888_rte, and matched 0.15.0’s restoration behaviour on the other three.
On case4661_sdet it was slower still: 2076 iterations in 360 s. Tellegen
therefore keeps the upstream default. case4661_sdet fails in both versions
with a small constraint violation and a KKT error of 1.35e4. Under 0.15.0
its base solve ends in Restoration_Failed rather than
Error_In_Step_Computation, so the ladder tries three rungs instead of one
and failure takes about twice as long. Every attempt keeps the per-attempt
max_iter 1000.
Two generator-free variants (case14_ieee and case300_ieee with every
generator’s real-power limits set to zero) fail identically under both
versions: InfeasibleProblemDetected after the same three rungs and 114 and
194 total iterations, in 0.1 s and 0.9 s. The saddle-escape rung did not fire.
Released backend integration — 22 October 2026
The native and dedicated WASI paths were updated to the published, checksummed
pounce-nl = pounce-rs = 0.13.0 release (FERAL 0.21.0). Both exact dependency
pins and every transitive POUNCE lockfile entry are checked by
scripts/acopf-release.py, also invoked by the build and EPL isolation gate.
The former Git-source exception has been removed.
Tellegen installs POUNCE’s multi-pass restoration factory and invokes the
released second-opinion ladder on the same cancellable TNLP. Failed retries
cannot overwrite the selected point. Every emitted result still passes the
independent physical validator; a retry does not weaken acceptance or turn a
local infeasibility report into a proof. Cancellation is checked before rescue
attempts, by callbacks during them, and after the ladder regardless of the
selected status. POUNCE 0.13.0 may still visit later retry rungs after
UserRequestedStop; the TNLP refuses their initialization once cancelled,
before they can rebuild or evaluate the model. Browser cancellation terminates
the entire worker.
Responses retain the selected solve’s iteration count and residuals, and add
base_solver_status, total_nlp_iterations, base_restoration_calls, restoration_calls,
recovery_attempts, and recovered_by. The restoration count belongs to the
selected solve; the total iteration count includes rejected attempts. The solve
card uses that total and marks recovered solves. Older responses remain
readable. The engine’s TypeScript contract now includes the NLP diagnostic
variant, which previously existed only in the Rust and Study schemas. Each
attempt uses the configured POUNCE iteration limit; the total across retries
can exceed that per-attempt limit.
A canonical full-pi regression forces entry into restoration, requires
restoration_calls > 0, and checks electrical feasibility and objective
agreement. A genuinely unserviceable instance exercises the retry ladder and
must still return an error. Small exact-expression regressions additionally
prove that a failed base solve can be rescued, rejected retries retain the
base point and verdict, total work includes every attempt, and cancellation
during the ladder returns a cancellation error. Existing finite-difference,
corrupt-result, portable-emission, cancellation and worker-lifecycle checks
remain in place.
The opt-in build now places POUNCE-EPL-2.0.txt, POUNCE-NOTICE.txt and
POUNCE-SOURCE.json beside the WASM asset. The manifest records its SHA-256,
size, lockfile hash, Tellegen revision/dirty state, and all 14 POUNCE source
archive URLs and checksums. Website builds copy these files with the solver. These
materials prepare review; they do not approve public distribution. Python
3.11+ is required for the release guard (PYTHON can select an interpreter).
Local validation at commit c721344 used Rust 1.96.0 on macOS arm64 and Chromium
with the release WASI artifact SHA-256
e6bf0775a90dec4fc8658c0559fadfed97545870adaae41152afb8ba8c12f5de
(10,463,176 bytes). The four browser UI/import/disposal checks and the four
external PGLib corpus checks all passed. Each corpus test hashes the served
artifact and input, requires independently checked primal violation below
1e-6, compares the objective to the checksum-keyed oracle, and verifies that
the worker terminates. These are single-run correctness checks, not a
performance or peak-memory characterization.
The external corpus was PGLib-OPF revision
dc6be4b2f85ca0e776952ec22cbd4c22396ea5a3. Its published TYP baseline uses
PowerModels.jl 0.19.9 and Ipopt.jl 1.4.1 / Ipopt 3.14.4. The rounded baseline
values below are compared with relative tolerance 1e-4; they are not
full-precision solution or expression-graph oracles. The same cases passed
the native benchmark:
| PGLib case | Published objective | Native objective | Native iterations | Native restoration entries | Browser oracle check |
|---|---|---|---|---|---|
| 14_ieee | 2,178.1 | 2,178.0804107 | 14 | 0 | passed |
| 30_ieee | 8,208.5 | 8,208.5154410 | 21 | 0 | passed |
| 300_ieee | 565,220 | 565,219.9746588 | 113 | 0 | passed |
| 6468_rte | 2,069,700 | 2,069,730.1566176 | 678 | 14 | passed |
Case6468 returned Solved_To_Acceptable_Level; its independently checked
maximum physical violation was below 1e-8. No case needed a second-opinion
promotion. The small forced-restoration and impossible-generation regressions
separately exercise the restoration and retry-driver paths.
The dated sections below retain the earlier feasibility evidence; their Git pin and old release observations describe those historical runs.
Main integration check — 5 October 2026
The feasibility branch includes main at 0d08c55, including compact
multiconductor PF session responses, the generated feeder regression and the
additional center-tap reference cases. The just ci aggregate retains both
acopf-probe and mc-pf-regression, matching the Rust workflow. The existing
multiconductor PF sessions remain independent of this opt-in NLP boundary.
The POUNCE revision and release/restoration/distribution gates are unchanged. The latest tagged release checked for this refresh is v0.12.0; the pinned revision is 35 commits ahead of that tag. Native AC OPF compilation/solve and the unpublished multiconductor IVR work remain separate layers of the stack.
Local validation for this refresh passed the HS071 probe (17.014017274,
maximum source-equation violation 2.484e-8), PowerIO source check, EPL feature
isolation and formatting. Workspace tests excluding the Python extension passed
374 tests (2 existing ignores), the independent mc-pf suite passed 160
(1 ignore), the conic engine suite passed 312 (2 ignores), and the conic WASM
adapter passed 40. Strict Clippy passed for the shipping Rust adapters plus the
opt-in probe and separately for Python with extension-module. The generated
feeder-10k --check regression passed all deterministic checks; timings are not
acceptance thresholds. Cross-platform, JavaScript and distribution checks remain
in the GitHub workflows.
Decision
Tellegen will use POUNCE as its first nonlinear solver for canonical balanced transmission AC OPF. The choice favors an end-to-end Rust implementation and a responsive upstream over building two solver adapters in the first cycle. The public problem and solution boundary must remain backend-neutral.
The decision follows POUNCE’s WASM-frontend restoration fix and the AC OPF follow-up experiments. Those results are feasibility and implementation evidence, not general solver performance guarantees.
This decision does not relabel the existing SOCWR relaxation as AC OPF. The
native opt-in feature now makes Problem::Acopf available after adding the
exact PowerIO-prepared polar model, independent primal validation, truthful
status mapping, and portable AcOpfSolution emission. Product distribution
still requires the browser worker boundary and release approval below.
POUNCE 0.13.0 replaces the original PR #961 Git pin. The upstream WASM fix
does not retrofit callers of a bare IpoptApplication; Tellegen now explicitly
installs the restoration factory and calls the released recovery driver.
Feasibility boundary
The non-default tellegen/acopf feature enables pounce-nl and pounce-rs.
No shipping adapter forwards it; the unpublished development WASI adapter does.
The native acopf_hs071_probe example constructs
HS071 with NlProblem::from_expressions, builds NlTnlp, verifies the sparse
Jacobian and Lagrangian-Hessian structures, solves with exact derivatives, and
checks the result independently.
Run it with:
cargo run -p tellegen --example acopf_hs071_probe --features acopf --locked
The probe pins the FERAL backend, exact Hessians, identity NLP/linear-system
scaling, and 1e-9 solver/constraint tolerances. The acceptance check requires
the known HS071 objective within 1e-5, source-equation violation below
1e-7, eight Jacobian nonzeros, and ten lower-triangle Hessian nonzeros.
PowerIO 0.11.3 provides the released preparation boundary used here. The model
compiler consumes its AcOpfInstance, build_ac_opf_preparation, and
AcOpfSolution APIs rather than reinterpreting MATPOWER data or reusing
Tellegen’s modified CATS power-flow physics.
Canonical model boundary
The opt-in feature now also contains a private, POUNCE-specific polar model
compiler. It consumes AcOpfInstance only through
build_ac_opf_preparation, preserves PowerIO’s generator and branch columns
and source maps, and emits an in-memory POUNCE expression DAG with exact sparse
derivatives. Native module dispatch and capabilities are feature-gated; no
shipping adapter or browser package enables them.
The recorded assembly policy is per-unit values, no zero-impedance skipping, no synthesized thermal ratings, and PowerIO’s angle-interval correction enabled. The preparation, including those choices, and the formulation version are hashed into the model fingerprint. Changing any policy is therefore a model change rather than a solver tuning option.
The variable map carries bus Va/Vm, generator-level Pg/Qg, and one
epigraph column for each active convex piecewise generator cost. Constraint
maps retain P/Q balance rows, zero reference angles, selected angle bounds,
both terminal thermal margins, and exact piecewise segments. Balance rows use
generation minus branch withdrawals, shunt consumption, and demand equal to
zero. Thermal and epigraph rows use nonnegative remaining margin. No dual is
published until these signs and unit conversions are independently validated.
The tests evaluate the full pi model at a non-flat point with taps, phase shifts, charging and bus shunts, compare both-end flows and nodal balances to a separate numerical calculation, and compare the sparse Jacobian and Lagrangian Hessian to finite differences. Unsupported active storage, voltage-dependent loads, and remote voltage regulation fail with the source element’s identity.
An ignored, path-driven external_model_build_ladder test makes the standard
MATPOWER 14/30/300-bus construction check reproducible without vendoring a
second copy of those fixtures. On 24 September 2026, a local arm64 debug build
after compilation produced:
| case | variables / rows | nnz Jacobian / Hessian | expression compile | derivative tape | max absolute directional J / H error |
|---|---|---|---|---|---|
| 14 | 38 / 49 | 267 / 127 | 1.849 ms | 3.841 ms | 4.545e-9 / 1.557e-7 |
| 30 | 72 / 184 | 871 / 260 | 1.016 ms | 12.803 ms | 7.186e-9 / 3.412e-8 |
| 300 | 738 / 1,012 | 5,433 / 2,605 | 8.380 ms | 70.444 ms | 2.723e-7 / 3.601e-7 |
These are correctness/prototype measurements, not solver performance claims.
Run the ladder with TELLEGEN_ACOPF_FIXTURES pointing to a directory containing
case14.m, case30.m, and case300.m. Peak RSS was not available inside the
sandbox used for this run, and frozen-NL parity remains a separate acceptance
measurement. The regression test now reports both absolute error and error
scaled by the analytic and finite-difference magnitudes with a floor of one.
The latest scaled J/H errors were 3.478e-9 / 2.418e-9, 1.791e-9 /
2.239e-10, and 9.095e-7 / 2.966e-9 for cases 14, 30, and 300
respectively.
Typed native solve boundary
The opt-in native API now exposes solve_ac_opf_instance and
solve_ac_opf_instance_to_solution plus cancellable counterparts. The
cancellable paths poll an atomic flag before model construction and at every
iteration of the base solve and recovery attempts. They run POUNCE with FERAL,
exact Hessians, identity NLP and linear-system scaling, a 1e-8
solver/constraint tolerance, 1e-7 acceptable tolerance, and a 1,000-iteration
ceiling. The returned AcOpfSolution is scattered through PowerIO’s source
row/winding maps in MW/MVAr and degrees, retains inactive source rows as
unavailable values, and round-trips through PioModule.
Only SolveSucceeded and SolvedToAcceptableLevel are candidates for
emission, and both must pass a separate calculation from the prepared arrays:
P/Q balance, voltage/generator boxes, references, angle and both-end thermal
limits, exact piecewise epigraphs, finite outputs, and source-cost objective.
The portable residuals report the independently calculated MW/MVAr balance
mismatch. A local NLP infeasibility report remains a diagnostic error rather
than PowerIO’s proof-strength Infeasible. No LMP or limit multiplier is
emitted yet; the POUNCE dual arrays stay private pending sign and source-unit
perturbation tests.
Native solve_module_json promotes a balanced network or consumes a stored
AcOpfInstance when the request selects acopf, and the capability advertises
only vm, va, injections, flows, and dispatch. Request edits currently
fail with an instruction to amend the canonical instance, rather than being
silently dropped, and every sensitivity request fails until the NLP KKT
contract exists. A successful nonlinear solve is reported as feasible, not
globally optimal, and its response includes the POUNCE status, iteration
count, solver constraint/KKT residuals, independently checked primal residual,
and model fingerprint. Failure and cancellation errors include the available
iteration and residual diagnostics.
Native API example
With tellegen built with features = ["acopf"], a stored canonical instance
can be solved for either the compact API response or the portable solution:
#![allow(unused)]
fn main() {
use std::sync::Arc;
use tellegen::{Problem, SolveRequest};
fn example(module_json: &str) -> Result<(), String> {
let module = tellegen::ir::deserialize_module(module_json)?;
let powerio::PioValue::AcOpfInstance(instance) = module.into_value() else {
return Err("expected an ac_opf_instance".into());
};
let request = SolveRequest { formulation: Problem::Acopf, ..Default::default() };
let response = tellegen::solve_ac_opf_instance(&instance, &request)?;
// Compact response: powers in MW/MVAr, voltage angles in radians.
assert!(response.lmp.is_none());
let solution = tellegen::solve_ac_opf_instance_to_solution(Arc::new(instance), "my-app")?;
// Portable solution: source table order, powers in MW/MVAr, angles in degrees.
let stored = powerio::PioModule::new(powerio::PioValue::AcOpfSolution(solution));
let json = tellegen::ir::serialize_module(&stored)?;
Ok(())
}
}
These are alternative entry points; calling both performs two solves. Inactive
source rows, including three-winding transformer terminals, remain unavailable
(NaN in Rust, the PowerIO unavailable representation in serialized modules).
Reproducible external comparisons
The committed acopf_benchmark example accepts MATPOWER files and emits one
JSONL record per case, including input and executable SHA-256, elapsed time,
objective, model fingerprint, residuals, solver status, and failures. It exits
nonzero if any case fails, while continuing through the remaining cases.
cargo run -p tellegen --release --example acopf_benchmark --features acopf --locked -- \
- /path/to/case14.m /path/to/case30.m /path/to/case300.m > results.jsonl
For an independent objective comparison, replace - with a JSON file containing
provenance (corpus revision, reference solver version/options, and result source)
and objectives (a map from exact input SHA-256 to its reference objective).
Missing checksums fail rather than comparing different case revisions. The
comparison tolerance is 1e-4 * max(1, abs(reference objective)). Keep that
reference file and the corpus provenance alongside the resulting JSONL. This
runner does not supply or regenerate an independent oracle. The published
PGLib baseline comparison above does not replace frozen expression parity or
validation on the final release artifact.
Experimental browser ABI
POUNCE’s proven browser target is a separate wasm32-wasip1 module with its
WASI clock/random/output shim. A direct wasm32-unknown-unknown/wasm-bindgen
probe compiles and loads but traps when the solver first calls
std::time::Instant::now(). Therefore tellegen-wasm does not forward
acopf, and a browser AC OPF solve must use a dedicated, terminable worker with
a small typed message boundary and one POUNCE memory. There must be no
synchronous main-thread fallback.
The development integration now implements that boundary as the unpublished
tellegen-acopf-wasi crate. Its raw ABI accepts one PowerIO module and one
solve request, then returns a length-prefixed SolveResponse. The JavaScript
host instantiates it with a minimal WASI Preview 1 clock/random/output shim in a
fresh worker for every solve. Cancelling or superseding a solve terminates that
worker; there is deliberately no synchronous or main-thread fallback.
The hosted UI defaults PUBLIC_TELLEGEN_ACOPF_WASM_URL to the bundled
/experimental-acopf/tellegen_acopf_wasi.wasm asset. It probes that URL through
the worker before enabling the AC OPF selector. Website builds now include the
EPL-bearing asset and its notices; the Docker build compiles the reactor, while
local builds and CI prepare it with npm run wasm:acopf. CI runs the three-bus
browser solve against the ordinary website build. This integration prepares
website enablement; it does not waive the release gates below.
The current UI path is intentionally base-case only because the
canonical AC OPF API rejects request edits and sensitivities rather than
silently dropping them.
For a local development preview from the repository root:
npm ci
rustup target add wasm32-unknown-unknown wasm32-wasip1
npm run wasm
npm run wasm:acopf
npm run build:engine
npm run build:web
npm --workspace tellegen-frontend run preview
The app copies the asset and notices during every website build. The Vite
development server also serves them after npm run wasm:acopf.
These commands are for local development and do not authorize distribution.
| Browser operation | Experimental AC OPF support |
|---|---|
| Balanced network / MATPOWER input | Promoted to a canonical instance for the base solve |
Stored AcOpfInstance | Imported without replacing its objective or constraints; requires the worker to solve |
| Geographic sidecars / layout | Supported while retaining the instance |
| Demand or rating edits | Rejected; reset edits before selecting AC OPF |
| LMPs / sensitivities | Unavailable |
| Save case / Export as | Disabled; the one-shot path has no retained Study |
| Save exact AC OPF solution in the UI | Unavailable; portable solution emission is currently a native API |
| Server fallback / WebMCP calculations | Unavailable for AC OPF |
tellegen-acopf-wasi requires its own explicit acopf feature. Default
workspace builds leave it inert, so selecting the workspace cannot silently
enable POUNCE in the CLI or other adapters. The build script enables this
feature only for the experimental reactor. Do not combine an explicitly
enabled AC OPF build with a shipping-adapter build in one Cargo invocation:
Cargo unifies their engine features. The EPL guard checks the default
workspace graph as well as individual adapters.
A single wasm-bindgen module can be reconsidered after POUNCE has a portable clock. That reconsideration must measure artifact size, memory growth, and hard worker cancellation in real browsers.
Experimental native multiconductor IVR OPF
The separate mc-opf feature adds native unbalanced current–voltage rectangular
OPF with explicit terminals and neutrals. The entry points are
solve_mc_ac_opf_instance, solve_mc_ac_opf_instance_cancellable, and
solve_mc_ac_opf_module_json; the JSON entry point requires an explicitly
declared McAcOpfInstance. This feature is not enabled by shipping adapters or
forwarded by the balanced browser worker described above.
PowerIO owns the canonical electrical semantics and solver-independent IVR
preparation. Tellegen constructs the expressions and independently checks the
accepted solution’s physical equations, limits and objective. Polynomial rows
use POUNCE’s existing exact sparse quadratic evaluator; general load laws and
smooth inverter controls use its existing sparse AD. No new differentiation
package is introduced. McOpfResult includes terminal voltages and physical
branch/device/winding/shunt ledgers with explicit terminal and coil identities.
Canonical JSON exports retain the full report in a versioned PowerIO module
extension; the MC APIs expose typed McOpfError diagnostics.
Explicit canonical initial points and the mc_opf_initial_point_from_pf helper
seed numerical variables without changing the declared physical problem; see
initial points for supported fields
and projection rules.
McOpfOptions.collect_profile enables optional
stage and KKT diagnostics. Native McOpfSession retains a compiled model and
accepted primal for repeated solves and atomic edits.
McOpfOptions.collect_duals separately enables original-scale multipliers, KKT
residuals, and conditional local marginal values
for supported load and limit parameters. Raw IVR KCL multipliers are not nodal
prices. McOpfResult::sensitivities() and McOpfSession::sensitivities() provide
conditional local forward and adjoint derivatives
from a verified current dual point, reusing one sparse active-KKT factorization.
Nominal load P/Q mappings include constant-current, constant-impedance, ZIP and
exponential laws, including coefficients hidden by zero nominal powers. Their
voltage-law coefficients and nominal voltages remain fixed. Inverter mappings
cover per-coil availability, P/Q bounds, apparent-power and conductor-current
ratings, including neutral returns and their effects on existing volt-var and
volt-watt references. Transformer mappings cover effective port ratings and
physical continuous tap bounds; outputs include winding/port flows and optimized
tap ratios, including inverse regulator conventions. Shared control-profile
mappings cover volt-var/volt-watt breakpoints and fractions and interior signed
power factors, including all assigned coils and smoothing-width derivatives.
Control modes, references and electrical coefficients remain fixed. Sparse rank
qualification uses explicit fill/work budgets, with reusable KKT structure and
per-query residual diagnostics exposed by sensitivity views. Version 7 reports
retain these claims; version 2–6 reports are verified with their original maps
and dense rank audit before upgrade.
The feature builds against published POUNCE 0.13.0 and PowerIO 0.11.8. Build and test the native feature from the repository root:
cargo build -p tellegen --no-default-features --features mc-opf --locked
cargo test -p tellegen --no-default-features --features mc-opf --locked
bash scripts/check-mc-opf.sh tests a temporary archive of committed source with
all features, MC OPF alone, and strict all-target Clippy using the locked
dependencies. Its optional PowerIO checkout argument is for companion development:
it patches all eight PowerIO crates only in the temporary archive and does not
rewrite either checkout’s lockfile. A companion checkout is not required.
See Formulations for the electrical profile and derivative strategy, Validation for acceptance and regression coverage, and Methodology for optional external studies. Ordinary frozen-reference tests need neither Julia nor the large ENWL dataset. The existing solver release and distribution gates below also apply to MC OPF.
License and release gate
POUNCE is EPL-2.0 while Tellegen is MIT. deny.toml admits EPL-2.0 only for the
named POUNCE crates, and scripts/epl-guard.sh proves POUNCE is absent from the
default engine and all shipping adapters while present in the opt-in probe.
That mechanical boundary is not legal approval. Before distributing a native
binary or WASI asset containing POUNCE, the release owner must approve the
EPL-2.0 obligations, include its license/notices, and provide a reasonable
corresponding-source location. Problem::Acopf remains unavailable in the
default native engine and shipping adapters; the website uses the separate
worker reactor.
On 29 October 2026 Samuel Talkington, the release owner, approved EPL-2.0 distribution of POUNCE in the website’s WASI asset. The website build meets the obligations as follows:
- POUNCE is used without modification.
POUNCE-EPL-2.0.txt(the license) andPOUNCE-NOTICE.txt(the notice) are served beside the asset under/experimental-acopf/. POUNCE-SOURCE.json, beside the asset, gives the corresponding source: the crates.io archive URL and SHA-256 of each of the 14 POUNCE crates, the upstream tag, the Tellegen commit the deployed image was built from, and the asset’s own SHA-256 and size. The deployed asset’s manifest records"development_only": false; local builds still recordtrue.- The
/creditspage links all three files.
Remaining release gates
The released dependency and restoration-driver gates are implemented. Gate 1 is complete. The release owner enabled the experimental calculation on the public website with gates 2 to 5 still open; they are not complete:
- Release-owner approval of EPL-2.0 distribution obligations. Approved on 29 October 2026; see the section above.
- Resolve the inherited PowerIO → ZIP advisory failures using a reviewed, patched PowerIO release; no advisory exception is added here.
- Repeat the independent corpus check on the final Tellegen release artifact and intended browser/platform matrix. The draft’s local validation is not a certificate for a different artifact.
- Complete repeated performance and peak-memory measurements, including stressed starts, beyond the correctness and lifecycle checks recorded here.
- Compare the 14/30/300 expressions against independently frozen benchmark values in addition to the physical validator and finite-difference checks.
The optional browser corpus regression uses the production importer and worker, checks the served WASM hash against its manifest, and requires checksum-keyed independent objectives. For example, after an opt-in build:
TELLEGEN_ACOPF_CORPUS=/path/to/pglib-opf \
TELLEGEN_ACOPF_REFERENCE=/path/to/reference.json \
TELLEGEN_ACOPF_CASES=pglib_opf_case14_ieee,pglib_opf_case30_ieee,pglib_opf_case300_ieee,pglib_opf_case6468_rte \
PLAYWRIGHT_JSON_OUTPUT_NAME=/path/to/browser-results.json \
npm --workspace tellegen-frontend exec -- playwright test ac-opf-experimental.spec.ts --workers=1 --reporter=list,json
The reference JSON has the same provenance and SHA-256-keyed objectives
format as acopf_benchmark. Each test attaches the full response, input hash,
artifact manifest and elapsed time. External corpus tests skip explicitly when
these paths are absent; the four ordinary UI/lifecycle tests still run in CI.
A failure of expression-DAG scaling changes the private solver adapter, not the PowerIO problem or solution contract.
Input preparation safeguards
PowerIO 0.11.5 filters inactive loads and shunts during preparation; Tellegen uses that preparation directly and retains a regression covering source rows, selected constraints, objective and explicit warm-start voltages. Networks claiming to be normalized while retaining inactive injections are rejected. Selected voltage, generator, thermal and angle bounds are checked before model construction. Zero thermal ratings remain unlimited. Small full-pi directional derivative checks run in ordinary CI, with a complex-current branch-flow oracle independent of the polar coefficient transcription.
Review diagnostics and benchmark timing
Compact AC OPF primal_residual is the maximum independent P/Q balance mismatch
in MW/MVAr. The optional residuals object separates voltage and generation
bounds, reference/branch angles, thermal limits, epigraph gaps and objective
agreement, with explicit units. Acceptance still checks every residual family;
objective agreement is not presented as a power mismatch. Compact flow output
includes three-winding transformer legs using the same synthetic IDs as SOCWR.
Portable solutions retain the caller’s producer and append POUNCE’s exact final
status, including Solved_To_Acceptable_Level.
The benchmark emits compact objective/status/iteration records, input and
artifact hashes, parse_ms, solve_ms, and total_elapsed_ms. Solve timing
includes model construction and independent validation but excludes parsing,
file hashing and JSON serialization. Earlier elapsed_ms records measured the
full input/JSON/solve path and must not be compared directly with solve_ms.
The base restoration count survives retry promotion; restoration_calls remains
the selected attempt’s count. Neither field claims to total all retries.
Portable producer metadata appends the base verdict, promotion label and both
counts when recovery succeeds. Tests separately cover cancellation before retry
initialization and cancellation from an in-flight retry’s iteration callback.
The EPL dependency-leak guard does not need Python. The separate release-pin
verification remains mandatory in Rust CI and the WASI build, requires Python
3.11+, and reports that requirement explicitly on older interpreters. Set
PYTHON for the WASI build when the system python3 is older.