Product documentation — installation, licensing, and integration guides.
SolvSRK-UQ
Examples

SolvSRK-UQ: Examples

Each example is a verified run of a guided tour script from the shipped python/examples/ bundle (see PROGRESSION.md for the full 01→06 sequence). Run the guided tour first: it narrates the scenario, explains each metric, and shows when to trust the result. Use the production one-liner when wiring the same API call into your pipeline.

Same package as SolvSRK: SolvSRK-UQ ships the solvsrk Python wheel. The guided tours below are the python/examples/journeys/ scripts bundled with that install — not a separate doc-site invention.

Release note: SolvSRK is a production (GA) release. Examples below match the shipped wheel and C library. Activate a trial or commercial license before running — see Install and Licensing.

Journeys

Example 1: Journey 01 — First contact

Version, license, and the smallest successful solve. Every support ticket starts with the package version. SolvSRK is gated by a machine-locked .lic file. In production you set SOLVSRK_LICENSE_FILE or run python -m solvsrk activate <file>.lic. From a git checkout, examples auto-issue a CI trial when tools/license_key.priv is present.

Walkthrough:

  1. What you are doing — Confirm the wheel and the native libsolvsrk load, see your license state, and run the smallest ODE that proves the solver is alive.

  2. Version — Every support ticket starts with the package version.

    • version: 2.4.0
  3. License — SolvSRK is gated by a machine-locked .lic file. In production you set SOLVSRK_LICENSE_FILE or run python -m solvsrk activate <file>.lic. From a git checkout, examples auto-issue a CI trial when tools/license_key.priv is present.

    • license_valid: True
    • days_remaining: 7
    • license_info: valid=1 licensee=ci seat_id=default expires=2026-08-29 duration_days=30 days_remaining=7
  4. Machine code — If activation fails, this is the fingerprint you paste into the Resonix portal to be issued a seat. It is safe to share.

    • machine_code: 53E9-2E74-D41B-2C82-9123-17AF-11C6-5411-B158-3C16-97AD-FD6C-0B5C-2D4C-52E7-BCA5
    • default_license_path: ~\AppData\Roaming\solvsrk\license.dat
  5. Simplest solve — Integrate exponential decay dy/dt = -y from t=0 to t=1 with y(0)=1. The exact answer is exp(-1). SolvSRK marshals your Python rhs(t, y) through ctypes to the C core - there is no second Python engine.

    • survived: True
    • failure_mode: ok
    • t_reached: 1
    • y_final: [0.367879]
    • total_rhs_evals: 220
    • front_phase: steps=200 rhs=220
    • stiff_phase: steps=0 rhs=0
    • t_handoff: 1
    • wall_s: 0.000329
    • expected: [0.367879]
    • max_abs_error: 2.266e-13

Guided tour output (from a verified run):

Version, license, and the smallest successful solve

-- Act 1 - What you are doing --
  -> Confirm the wheel and the native libsolvsrk load, see your license state, and run the smallest ODE that proves the solver is alive.

-- Act 2 - Version --
  -> Every support ticket starts with the package version.
  version: 2.4.0

-- Act 3 - License --
  -> SolvSRK is gated by a machine-locked .lic file. In production you set SOLVSRK_LICENSE_FILE or run `python -m solvsrk activate <file>.lic`. From a git checkout, examples auto-issue a CI trial when tools/license_key.priv is present.
  license_valid: True
  days_remaining: 7
  license_info: valid=1 licensee=ci seat_id=default expires=2026-08-29 duration_days=30 days_remaining=7

-- Act 4 - Machine code --
  -> If activation fails, this is the fingerprint you paste into the Resonix portal to be issued a seat. It is safe to share.
  machine_code: 53E9-2E74-D41B-2C82-9123-17AF-11C6-5411-B158-3C16-97AD-FD6C-0B5C-2D4C-52E7-BCA5
  default_license_path: ~\AppData\Roaming\solvsrk\license.dat

-- Act 5 - Simplest solve --
  -> Integrate exponential decay dy/dt = -y from t=0 to t=1 with y(0)=1. The exact answer is exp(-1). SolvSRK marshals your Python rhs(t, y) through ctypes to the C core - there is no second Python engine.
  survived: True
  failure_mode: ok
  t_reached: 1
  y_final: [0.367879]
  total_rhs_evals: 220
  front_phase: steps=200 rhs=220
  stiff_phase: steps=0 rhs=0
  t_handoff: 1
  wall_s: 0.000329
  expected: [0.367879]
  max_abs_error: 2.266e-13

-- Run complete --
  next_journey: 02_core_path.py
cd python
# Guided tour — narrated scenario walkthrough (recommended first run):
python examples/journeys/01_first_contact.py
 
# Production one-liner — same API call you ship:
python -c "import solvsrk as s; print(s.__version__, s.license_valid())"

Example 2: Journey 02 — Core path

A diagonal multi-rate system | ndim=3. solvsrk.run() takes a config, the dimension, the time span, y0, and your rhs(t, y). It returns a plain dict of native Python types - no ctypes objects leak into your code. survived tells you it reached t_end; phase counters in the result dict show where the work happened. SolvSRK is built for stiff dynamics under real-world noise — you supply the RHS; the library owns the integrator.

Walkthrough:

  1. The problem — dy_i/dt = -lambda_i * y_i for lambda = [1, 10, 100], y(0) = [1, 1, 1]. Each component decays at its own rate; the closed form is y_i(t) = exp(-lambda_i * t), so we can check the answer exactly.

  2. The call — solvsrk.run() takes a config, the dimension, the time span, y0, and your rhs(t, y). It returns a plain dict of native Python types - no ctypes objects leak into your code.

  3. Read the result — survived tells you it reached t_end; phase counters in the result dict show where the work happened. SolvSRK is built for stiff dynamics under real-world noise — you supply the RHS; the library owns the integrator.

    • survived: True
    • failure_mode: ok
    • t_reached: 0.5
    • y_final: [0.606531, 0.00673795, 1.92875e-22]
    • total_rhs_evals: 120
    • front_phase: steps=100 rhs=120
    • stiff_phase: steps=0 rhs=0
    • t_handoff: 0.5
    • wall_s: 0.0002828
    • expected: [0.606531, 0.00673795, 1.92875e-22]
    • max_abs_error: 2.300e-13

Guided tour output (from a verified run):

A diagonal multi-rate system | ndim=3

-- Act 1 - The problem --
  -> dy_i/dt = -lambda_i * y_i for lambda = [1, 10, 100], y(0) = [1, 1, 1]. Each component decays at its own rate; the closed form is y_i(t) = exp(-lambda_i * t), so we can check the answer exactly.

-- Act 2 - The call --
  -> solvsrk.run() takes a config, the dimension, the time span, y0, and your rhs(t, y). It returns a plain dict of native Python types - no ctypes objects leak into your code.

-- Act 3 - Read the result --
  -> survived tells you it reached t_end; phase counters in the result dict show where the work happened. SolvSRK is built for stiff dynamics under real-world noise — you supply the RHS; the library owns the integrator.
  survived: True
  failure_mode: ok
  t_reached: 0.5
  y_final: [0.606531, 0.00673795, 1.92875e-22]
  total_rhs_evals: 120
  front_phase: steps=100 rhs=120
  stiff_phase: steps=0 rhs=0
  t_handoff: 0.5
  wall_s: 0.0002828
  expected: [0.606531, 0.00673795, 1.92875e-22]
  max_abs_error: 2.300e-13

-- Run complete --
  next_journey: 03_configuration.py
cd python
# Guided tour — narrated scenario walkthrough (recommended first run):
python examples/journeys/02_core_path.py
 
# Production one-liner — same API call you ship:
python -c "import solvsrk,numpy as np; c=solvsrk.config_defaults(); print(solvsrk.run(c,3,0,0.5,(1,1,1),lambda t,y:-np.array([1,10,100.])*y)['y_final'])"

Example 3: Journey 03 — Configuration

Tolerances, step caps, and the opaque profile path. Run the same problem at a loose tolerance then a tight one. Tighter tolerances cost more RHS evaluations but give more accurate digits. Watch total_rhs_evals grow as the tolerance shrinks. cvode_max_step bounds the largest internal step CVODE may take - useful when a forcing term or event must not be skipped over. 0.0 means 'no explicit cap' (the solver chooses).

Walkthrough:

  1. The config struct — config_defaults() returns a fully populated SolvsrkConfig. Never zero it yourself - override only the fields you care about. The knobs that move the needle most are cvode_rtol and cvode_atol (accuracy vs cost).

    • default_cvode_rtol: 1e-08
    • default_cvode_atol: 1e-08
    • default_ek_max_steps: 500
    • default_cvode_max_step: 1.0
  2. Loose vs tight tolerances — Run the same problem at a loose tolerance then a tight one. Tighter tolerances cost more RHS evaluations but give more accurate digits. Watch total_rhs_evals grow as the tolerance shrinks.

    • survived: True
    • failure_mode: ok
    • t_reached: 0.5
    • y_final: [0.606531, 0.00673795, 1.92875e-22]
    • total_rhs_evals: 120
    • front_phase: steps=100 rhs=120
    • stiff_phase: steps=0 rhs=0
    • t_handoff: 0.5
    • wall_s: 0.000325
    • expected: [0.606531, 0.00673795, 1.92875e-22]
    • max_abs_error: 2.300e-13
    • survived: True
    • failure_mode: ok
    • t_reached: 0.5
    • y_final: [0.606531, 0.00673795, 1.92875e-22]
    • total_rhs_evals: 120
    • front_phase: steps=100 rhs=120
    • stiff_phase: steps=0 rhs=0
    • t_handoff: 0.5
    • wall_s: 0.0002861
    • expected: [0.606531, 0.00673795, 1.92875e-22]
    • max_abs_error: 2.300e-13
  3. Step-size cap — cvode_max_step bounds the largest internal step CVODE may take - useful when a forcing term or event must not be skipped over. 0.0 means 'no explicit cap' (the solver chooses).

    • cvode_max_step: 0.01
    • cvode_steps: 0
  4. The profile path (run_profile) — For deployment, SolvTune can bake a tuned config into an opaque token so you ship a string, not a struct. run_profile(token, ...) decodes it in the library. Without a real token you get a clean profile_mode failure - that refusal is the point: no token, no silent wrong answer.

    • profile_survived: False
    • profile_failure_mode: bad_arg — In production the token comes from SolvScout/SolvTune, not a literal.

Guided tour output (from a verified run):

Tolerances, step caps, and the opaque profile path

-- Act 1 - The config struct --
  -> config_defaults() returns a fully populated SolvsrkConfig. Never zero it yourself - override only the fields you care about. The knobs that move the needle most are cvode_rtol and cvode_atol (accuracy vs cost).
  default_cvode_rtol: 1e-08
  default_cvode_atol: 1e-08
  default_ek_max_steps: 500
  default_cvode_max_step: 1.0

-- Act 2 - Loose vs tight tolerances --
  -> Run the same problem at a loose tolerance then a tight one. Tighter tolerances cost more RHS evaluations but give more accurate digits. Watch total_rhs_evals grow as the tolerance shrinks.
  survived: True
  failure_mode: ok
  t_reached: 0.5
  y_final: [0.606531, 0.00673795, 1.92875e-22]
  total_rhs_evals: 120
  front_phase: steps=100 rhs=120
  stiff_phase: steps=0 rhs=0
  t_handoff: 0.5
  wall_s: 0.000325
  expected: [0.606531, 0.00673795, 1.92875e-22]
  max_abs_error: 2.300e-13
  survived: True
  failure_mode: ok
  t_reached: 0.5
  y_final: [0.606531, 0.00673795, 1.92875e-22]
  total_rhs_evals: 120
  front_phase: steps=100 rhs=120
  stiff_phase: steps=0 rhs=0
  t_handoff: 0.5
  wall_s: 0.0002861
  expected: [0.606531, 0.00673795, 1.92875e-22]
  max_abs_error: 2.300e-13

-- Act 3 - Step-size cap --
  -> cvode_max_step bounds the largest internal step CVODE may take - useful when a forcing term or event must not be skipped over. 0.0 means 'no explicit cap' (the solver chooses).
  cvode_max_step: 0.01
  cvode_steps: 0

-- Act 4 - The profile path (run_profile) --
  -> For deployment, SolvTune can bake a tuned config into an opaque token so you ship a string, not a struct. run_profile(token, ...) decodes it in the library. Without a real token you get a clean profile_mode failure - that refusal is the point: no token, no silent wrong answer.
  profile_survived: False
  profile_failure_mode: bad_arg
  -> In production the token comes from SolvScout/SolvTune, not a literal.

-- Run complete --
  next_journey: 04_diagnostics.py
cd python
# Guided tour — narrated scenario walkthrough (recommended first run):
python examples/journeys/03_configuration.py
 
# Production one-liner — same API call you ship:
python -c "import solvsrk as s; c=s.config_defaults(); c.cvode_rtol=1e-10; c.cvode_atol=1e-12; print(c.cvode_rtol)"

Example 4: Journey 04 — Diagnostics

Every field in the result dict, plus UQ. survived + failure_mode + t_reached are the go/no-go trio. SolvSRK reports front-phase and stiff-tail cost counters in the result dict, plus the handoff time between them. Use those fields for timing and support — not as a recipe to reimplement the solver.

Walkthrough:

  1. Why diagnostics matter — In production you do not watch a solver run - you read its receipt. SolvSRK returns a dict you can log, assert on, and alert against.

  2. Did it finish? — survived + failure_mode + t_reached are the go/no-go trio.

    • survived: True
    • failure_mode: ok
    • failure_msg: (none)
    • t_reached: 1
    • rc: 0 — failure_mode is a string: ok, max_steps, blowup, timeout, bad_arg, license, ...
  3. Where did the work go? — SolvSRK reports front-phase and stiff-tail cost counters in the result dict, plus the handoff time between them. Use those fields for timing and support — not as a recipe to reimplement the solver.

    • ek_steps: 200
    • ek_n_rhs: 230
    • ek_wall_s: 0.0005476
    • ek_noise_detected: True
    • cvode_steps: 0
    • cvode_n_rhs: 0
    • cvode_n_jac: 0
    • cvode_wall_s: 0
    • t_handoff: 1
    • confidence: 0.005001
    • total_wall_s: 0.0005507
  4. Full successful-step telemetry (emit_history) — Trajectory storage is off by default. Enable it when you need SciPy-style t/y arrays, phase labels, or live-monitoring samples.

    • t_shape: (0,)
    • y_shape: (2, 0)
    • n_history: 0
    • nfev: 0
    • njev: 0
    • nsteps: 0
    • truncated: False
  5. Uncertainty (emit_uq) — SolvSRK-UQ — Trials include UQ (features: uq). After purchase, emit_uq needs a SolvSRK-UQ add-on or Edge seat — purchased base SolvSRK refuses it with failure_mode=license. Check solvsrk.license_has_uq() first.

    • license_has_uq: False — Skipping UQ acts — activate a trial .lic (includes UQ) or a purchased SolvSRK-UQ / Edge seat with features: uq.

Guided tour output (from a verified run):

Every field in the result dict, plus UQ

-- Act 1 - Why diagnostics matter --
  -> In production you do not watch a solver run - you read its receipt. SolvSRK returns a dict you can log, assert on, and alert against.

-- Act 2 - Did it finish? --
  -> survived + failure_mode + t_reached are the go/no-go trio.
  survived: True
  failure_mode: ok
  failure_msg: (none)
  t_reached: 1
  rc: 0
  -> failure_mode is a string: ok, max_steps, blowup, timeout, bad_arg, license, ...

-- Act 3 - Where did the work go? --
  -> SolvSRK reports front-phase and stiff-tail cost counters in the result dict, plus the handoff time between them. Use those fields for timing and support — not as a recipe to reimplement the solver.
  ek_steps: 200
  ek_n_rhs: 230
  ek_wall_s: 0.0005476
  ek_noise_detected: True
  cvode_steps: 0
  cvode_n_rhs: 0
  cvode_n_jac: 0
  cvode_wall_s: 0
  t_handoff: 1
  confidence: 0.005001
  total_wall_s: 0.0005507

-- Act 4 - Full successful-step telemetry (emit_history) --
  -> Trajectory storage is off by default. Enable it when you need SciPy-style t/y arrays, phase labels, or live-monitoring samples.
  t_shape: (0,)
  y_shape: (2, 0)
  n_history: 0
  nfev: 0
  njev: 0
  nsteps: 0
  truncated: False

-- Act 5 - Uncertainty (emit_uq) — SolvSRK-UQ --
  -> Trials include UQ (features: uq). After purchase, emit_uq needs a SolvSRK-UQ add-on or Edge seat — purchased base SolvSRK refuses it with failure_mode=license. Check solvsrk.license_has_uq() first.
  license_has_uq: False
  -> Skipping UQ acts — activate a trial .lic (includes UQ) or a purchased SolvSRK-UQ / Edge seat with features: uq.

-- Run complete --
  next_journey: 05_stiff_chemistry.py
cd python
# Guided tour — narrated scenario walkthrough (recommended first run):
python examples/journeys/04_diagnostics.py
 
# Production one-liner — same API call you ship:
python -c "import solvsrk,numpy as np; c=solvsrk.config_defaults(); r=solvsrk.run(c,1,0,1,(1.,),lambda t,y:-y); print(r['survived'], r['failure_mode'], r['t_reached'])"

Example 5: Journey 05 — Stiff chemistry (Robertson)

Robertson kinetics | rates span 1e9 | ndim=3. Concentrations cannot go negative and the three species must sum to 1 (mass is conserved). SolvSRK can enforce both at the internal handoff and inside the stiff integrator, so numerical noise never produces an unphysical state. For stiff problems an analytic Jacobian pays for itself — the stiff integrator uses it directly instead of finite-differencing. Pass jac_fn and SolvSRK marshals it row-major to the C core.

Walkthrough:

  1. The system — Three chemical species. y1 leaks slowly to y2; y2 is consumed almost instantly by a fast quadratic reaction into y3. The mix of a very fast and a very slow mode is what 'stiff' means - and what defeats a plain explicit stepper.

  2. Physical constraints as config — Concentrations cannot go negative and the three species must sum to 1 (mass is conserved). SolvSRK can enforce both at the internal handoff and inside the stiff integrator, so numerical noise never produces an unphysical state.

    • handoff_nonneg: 1
    • handoff_conservation_sum: 1.0
    • cvode_enforce_nonneg: 1
  3. Solve with an analytic Jacobian — For stiff problems an analytic Jacobian pays for itself — the stiff integrator uses it directly instead of finite-differencing. Pass jac_fn and SolvSRK marshals it row-major to the C core.

    • survived: True
    • failure_mode: ok
    • t_reached: 40
    • y_final: [0.715827, 9.18554e-06, 0.284164]
    • total_rhs_evals: 1037
    • front_phase: steps=500 rhs=600
    • stiff_phase: steps=297 rhs=437
    • t_handoff: 0.05
    • wall_s: 0.003992
  4. Sanity check — When the integration succeeds, the three concentrations should still sum to ~1 — the conservation wrapper keeps mass balanced across the stiff tail. Check sum(y) and that every component stayed non-negative.

    • y1: 0.715827
    • y2: 9.18554e-06
    • y3: 0.284164
    • sum: 1.0000000000
    • conservation_error: 6.661e-16

Guided tour output (from a verified run):

Robertson kinetics | rates span 1e9 | ndim=3

-- Act 1 - The system --
  -> Three chemical species. y1 leaks slowly to y2; y2 is consumed almost instantly by a fast quadratic reaction into y3. The mix of a very fast and a very slow mode is what 'stiff' means - and what defeats a plain explicit stepper.

-- Act 2 - Physical constraints as config --
  -> Concentrations cannot go negative and the three species must sum to 1 (mass is conserved). SolvSRK can enforce both at the internal handoff and inside the stiff integrator, so numerical noise never produces an unphysical state.
  handoff_nonneg: 1
  handoff_conservation_sum: 1.0
  cvode_enforce_nonneg: 1

-- Act 3 - Solve with an analytic Jacobian --
  -> For stiff problems an analytic Jacobian pays for itself — the stiff integrator uses it directly instead of finite-differencing. Pass jac_fn and SolvSRK marshals it row-major to the C core.
  survived: True
  failure_mode: ok
  t_reached: 40
  y_final: [0.715827, 9.18554e-06, 0.284164]
  total_rhs_evals: 1037
  front_phase: steps=500 rhs=600
  stiff_phase: steps=297 rhs=437
  t_handoff: 0.05
  wall_s: 0.003992

-- Act 4 - Sanity check --
  -> When the integration succeeds, the three concentrations should still sum to ~1 — the conservation wrapper keeps mass balanced across the stiff tail. Check sum(y) and that every component stayed non-negative.
  y1: 0.715827
  y2: 9.18554e-06
  y3: 0.284164
  sum: 1.0000000000
  conservation_error: 6.661e-16

-- Run complete --
  next_journey: 06_limits.py
cd python
# Guided tour — narrated scenario walkthrough (recommended first run):
python examples/journeys/05_stiff_chemistry.py
 
# Production one-liner — same API call you ship:
python examples/journeys/05_stiff_chemistry.py

Example 6: Journey 06 — Limits

What SolvSRK is for - and what it is not. SolvSRK will happily integrate a linear system y' = A y, but if A is constant and linear, SolvLRDE computes y(T) directly by Talbot contour integration - no time stepping, cost independent of T, immune to stiffness. Below, SolvSRK steps through a linear decay; for this shape of problem LRDE is the sharper tool. SolvSRK integrates ONE problem per call. If you need to run the same model across hundreds of parameter sets and shortlist the best, that is an orchestration problem - SolvJump wraps SolvSRK to run the sweep, cache a fast path, and write receipts. Do not hand-roll a for-loop over run() when you want a study.

Walkthrough:

  1. What SolvSRK is for — One stiff, possibly nonlinear, initial-value ODE integrated forward in time to a final state - reactors, kinetics, thermal transients, control plants. You give it rhs(t, y); it gives you y(t_end) with a receipt.

  2. Limit 1 - a linear system is a job for SolvLRDE — SolvSRK will happily integrate a linear system y' = A y, but if A is constant and linear, SolvLRDE computes y(T) directly by Talbot contour integration - no time stepping, cost independent of T, immune to stiffness. Below, SolvSRK steps through a linear decay; for this shape of problem LRDE is the sharper tool.

    • survived: True
    • failure_mode: ok
    • t_reached: 1
    • y_final: [0, 0.368248]
    • total_rhs_evals: 230
    • front_phase: steps=200 rhs=230
    • stiff_phase: steps=0 rhs=0
    • t_handoff: 1
    • wall_s: 0.0004799 — Linear + constant A -> prefer solvlrde.solve(A, y0, T).
  3. Limit 2 - a parameter sweep is a job for SolvJump — SolvSRK integrates ONE problem per call. If you need to run the same model across hundreds of parameter sets and shortlist the best, that is an orchestration problem - SolvJump wraps SolvSRK to run the sweep, cache a fast path, and write receipts. Do not hand-roll a for-loop over run() when you want a study.

  4. Limit 3 - it will refuse rather than lie — Ask for something impossible - here, integrate a system that blows up - and SolvSRK returns survived=False with a failure_mode string instead of a plausible-looking wrong number. A refusal you can branch on beats a silent bad answer every time.

    • survived: False
    • failure_mode: blowup
    • t_reached: 1.03
    • failure_msg: ek blowup
  5. The stack — SolvJump (studies) -> SolvSRK (one stiff nonlinear solve) and SolvLRDE (one linear solve). Pick the layer that matches your problem.

Guided tour output (from a verified run):

What SolvSRK is for - and what it is not

-- Act 1 - What SolvSRK is for --
  -> One stiff, possibly nonlinear, initial-value ODE integrated forward in time to a final state - reactors, kinetics, thermal transients, control plants. You give it rhs(t, y); it gives you y(t_end) with a receipt.

-- Act 2 - Limit 1 - a linear system is a job for SolvLRDE --
  -> SolvSRK will happily integrate a linear system y' = A y, but if A is constant and linear, SolvLRDE computes y(T) *directly* by Talbot contour integration - no time stepping, cost independent of T, immune to stiffness. Below, SolvSRK steps through a linear decay; for this shape of problem LRDE is the sharper tool.
  survived: True
  failure_mode: ok
  t_reached: 1
  y_final: [0, 0.368248]
  total_rhs_evals: 230
  front_phase: steps=200 rhs=230
  stiff_phase: steps=0 rhs=0
  t_handoff: 1
  wall_s: 0.0004799
  -> Linear + constant A -> prefer solvlrde.solve(A, y0, T).

-- Act 3 - Limit 2 - a parameter sweep is a job for SolvJump --
  -> SolvSRK integrates ONE problem per call. If you need to run the same model across hundreds of parameter sets and shortlist the best, that is an orchestration problem - SolvJump wraps SolvSRK to run the sweep, cache a fast path, and write receipts. Do not hand-roll a for-loop over run() when you want a study.

-- Act 4 - Limit 3 - it will refuse rather than lie --
  -> Ask for something impossible - here, integrate a system that blows up - and SolvSRK returns survived=False with a failure_mode string instead of a plausible-looking wrong number. A refusal you can branch on beats a silent bad answer every time.
  survived: False
  failure_mode: blowup
  t_reached: 1.03
  failure_msg: ek blowup

-- Act 5 - The stack --
  -> SolvJump (studies) -> SolvSRK (one stiff nonlinear solve) and SolvLRDE (one linear solve). Pick the layer that matches your problem.

-- Run complete --
  suite: complete
  see: examples/PROGRESSION.md
cd python
# Guided tour — narrated scenario walkthrough (recommended first run):
python examples/journeys/06_limits.py
 
# Production one-liner — same API call you ship:
python examples/journeys/06_limits.py

Example bundle

Every journey is a domain scenario with narrated acts — run the guided tour first to see what each number means, then copy the production one-liner into your pipeline.

ResourcePurpose
PROGRESSION.mdOrdered runbook — journeys 01→06 with dual commands
COVERAGE.mdCapability matrix — which APIs each journey exercises
APPLICATIONS.mdWhere the product applies in real programs
run_examples.pyInteractive menu to launch any journey

Guided journeys

#ScriptScenario
0101_first_contact.pyVersion, license, and the smallest successful solve
0202_core_path.pyA diagonal multi-rate system
0303_configuration.pyTolerances, step caps, and the opaque profile path
0404_diagnostics.pyEvery field in the result dict, plus UQ
0505_stiff_chemistry.pyRobertson kinetics
0606_limits.pyWhat SolvSRK is for - and what it is not

Run from the python/ directory after install and license activation. Set SOLVSRK_QUIET=1 only when you want silent CLI runs (no narration).