{"slug": "show-hn-phaseprobe-find-simulation-transitions-and-turn-them-into-tests", "title": "Show HN: PhaseProbe – Find simulation transitions and turn them into tests", "summary": "PhaseProbe 0.1.0, a new open-source tool for finding qualitative transitions in simulations and converting them into pytest regression tests, was released on 2026-08-01. The tool, which requires Python 3.10+ and has no third-party runtime dependencies, performs bounded deterministic searches and generates executable tests without needing an API key, LLM, GPU, Docker, account, telemetry, or network connection. It includes built-in examples such as the logistic map, Lorenz system, predator-prey model, and genetic toggle switch, and provides stable exit codes for CI integration.", "body_md": "Find a simulation behavior boundary. Preserve it as a replay. Turn it into a test.\n\nMaintaining a simulation is risky when a tiny parameter or initial-condition change can cross a qualitative boundary while ordinary numeric assertions still look plausible. PhaseProbe runs a bounded, deterministic search, records exactly what it tested, and emits an offline report plus an executable pytest regression.\n\n``` bash\n$ python -m pip install .\n$ phaseprobe scan --example logistic\nQUALITATIVE TRANSITION FOUND\n\nModel: logistic-map\nSearch dimension: r\nBaseline regime: period-2\nChanged regime: period-4\nReplay: .phaseprobe/runs/<run-id>/replay.json\n\n$ phaseprobe generate-test .phaseprobe/runs/<run-id>/replay.json\n$ python -m pytest -q tests/generated\n1 passed\n```\n\nNo API key, LLM, GPU, Docker, account, telemetry, network connection, or hosted service is required at runtime. PhaseProbe 0.1.0 has no third-party runtime dependencies.\n\nRequires Python 3.10 or newer on Windows or Linux.\n\n```\npython -m pip install .\nphaseprobe scan --example logistic\nphaseprobe replay .phaseprobe/runs/<run-id>/replay.json\nphaseprobe generate-test .phaseprobe/runs/<run-id>/replay.json\npython -m pytest -q tests/generated\nphaseprobe report .phaseprobe/runs/<run-id>\n```\n\nReplace `<run-id>`\n\nwith the directory printed by `scan`\n\n. The scan returns `0`\n\nwhen it successfully finds a transition. Add `--fail-on-finding`\n\nonly when a finding should fail CI.\n\nThe quick-start evidence is empirical: the built-in classifier finds a finite-time period-2/period-4 bracket for the logistic map, performs bounded binary refinement, repeats both endpoints, saves trace hashes and a versioned fixture, and generates a fixed pytest template. It does not claim an exact bifurcation point.\n\n| command | job | normal success |\n|---|---|---|\n`scan` |\nBounded one-dimensional parameter scan, adjacent class-change detection, and stable bracket refinement | Finding or no finding, exit `0` |\n`perturb` |\nBaseline/perturbed twin runs over bounded initial-state changes | Finding or no finding, exit `0` |\n`check` |\nExecute a declared configuration policy for CI | Exit `1` only when policy fails |\n`replay` |\nValidate fixture integrity and re-execute model, parameters, seed, initial state, tolerances, and retention | Matching class and exact retained trace hashes |\n`generate-test` |\nValidate and copy a fixture into a non-extensible pytest template | Executable test under `tests/generated/` |\n`report` |\nRegenerate terminal, versioned JSON, and self-contained offline HTML evidence | Local report files |\n\nCommon options:\n\n```\nphaseprobe scan --config examples/configs/logistic-scan.json\nphaseprobe perturb --example lorenz --json\nphaseprobe check --example predator-prey\nphaseprobe scan --example logistic --fail-on-finding\n```\n\nExit codes are stable: `0`\n\ncompleted, `1`\n\ndeclared policy or explicit `--fail-on-finding`\n\n, `2`\n\ninvalid input/configuration, `3`\n\nnumerical failure, and `4`\n\ninternal PhaseProbe defect.\n\n| example | command | positive evidence | negative control | direct technical source |\n|---|---|---|---|---|\n| Logistic map | `phaseprobe scan --example logistic` |\nFinite-time period-2 to period-4 classification bracket | `--example logistic-negative` stays period-2 over its declared range |\n|\n\n`phaseprobe perturb --example lorenz`\n\n[Lorenz, 1963](https://journals.ametsoc.org/view/journals/atsc/20/2/1520-0469_1963_020_0130_dnf_2_0_co_2.xml)`phaseprobe check --example predator-prey`\n\n[Lotka, 1920](https://doi.org/10.1073/pnas.6.7.410)`phaseprobe perturb --example toggle`\n\n[Gardner, Cantor & Collins, 2000](https://www.nature.com/articles/35002131)Each configuration records the seed, fixed integration/iteration settings, tolerances, burn-in, observation window, classification rule, refinement rule, invalid-state policy, and trace cap. See [examples/README.md](/aliengineering-byte/phaseprobe/blob/main/examples/README.md) for equations and interpretation.\n\nOn 2026-08-01 with CPython 3.12.13 on Windows, the instrumented logistic quick-start scan completed in 10.114 seconds with a 34.81 MiB peak process-tree working set. All eight positive/negative example commands completed in 12.238 seconds. The final 38-test suite with branch coverage completed in 64.86 seconds at 87.92% coverage. These are observations from one local run, not cross-machine performance claims; the generated transcript is in [assets/demo-session.txt](/aliengineering-byte/phaseprobe/blob/main/assets/demo-session.txt).\n\nEvery execution is bounded under `.phaseprobe/runs/<run-id>/`\n\n:\n\n```\nrun.json       complete versioned evidence\nfindings.json  compact finding or negative result\nreplay.json    schema-versioned integrity-protected fixture\ntrace.jsonl    capped baseline/changed retained points\nreport.html    self-contained offline report\nmanifest.json  sizes and SHA-256 hashes\n```\n\nModel names used for generated test paths are sanitized. The generated source comes from a fixed template; configuration strings never become executable Python.\n\n| existing category | established strength | PhaseProbe’s narrower job |\n|---|---|---|\n| Solvers such as SciPy | Integrate differential equations with mature numerical methods | Consume an adapter’s trajectories and preserve a discovered qualitative boundary as test evidence |\n| Property-based testing such as Hypothesis | Generate and shrink broad input domains | Search declared simulation dimensions with model-specific observables and classes |\n| Bifurcation/attractor tools such as AUTO, PyDSTool, and Attractors.jl | Deep continuation, bifurcation, attractor, and basin analysis | Lightweight black-box numerical brackets plus replay and pytest materialization |\n| Sensitivity tools such as SALib | Quantify input contributions to output variation | Find a reproducible qualitative predicate change |\n| Simulation environments such as Mesa, NetLogo, cadCAD, and Golly | Build, run, and explore models | Test adapters without becoming another simulation environment |\n\nThe evidence-backed audit is in [PRIOR_ART.md](/aliengineering-byte/phaseprobe/blob/main/PRIOR_ART.md).\n\nAdapters implement a small typed protocol:\n\n```\nclass ModelAdapter(Protocol):\n    name: str\n    identity: str\n    dimensions: tuple[str, ...]\n\n    def initial_state(self, config, seed): ...\n    def step(self, state, parameters, dt): ...\n    def observe(self, state): ...\n    def classify(self, trace, tolerances): ...\n    def invariants(self, trace, parameters, tolerances): ...\n```\n\nThe explicit serializable state tuple makes bounded perturbation, invalid-value detection, trace hashing, and replay straightforward. See [ARCHITECTURE.md](/aliengineering-byte/phaseprobe/blob/main/ARCHITECTURE.md) for extension guidance.\n\nPhaseProbe uses these terms deliberately:\n\n- finite-time trajectory divergence: measured separation over the recorded window;\n- sensitive-dependence evidence: repeatable finite-time divergence under a declared small perturbation, not by itself a proof of chaos;\n- numerical instability: behavior attributable to the numerical method or step size;\n- invariant violation: a declared conservation or boundedness rule failed;\n- qualitative regime change: the adapter’s declared classifier changed;\n- bifurcation evidence: a numerical class-change bracket, not an exact bifurcation point;\n- invalid integration: NaN, infinity, overflow, state-shape mismatch, or hard bound breach;\n- solver failure: the step method could not advance a valid state.\n\nThe Lorenz example reports `finite-time divergence rate`\n\n; it does not compute or claim a Lyapunov exponent. “Smallest” always means smallest found within the declared bounded search. Read [SCIENTIFIC_METHODS.md](/aliengineering-byte/phaseprobe/blob/main/SCIENTIFIC_METHODS.md) and [LIMITATIONS.md](/aliengineering-byte/phaseprobe/blob/main/LIMITATIONS.md).\n\n```\npython -m pip install -e \".[dev]\"\npython -m ruff format --check .\npython -m ruff check .\npython -m mypy src tests\npython -m pytest --cov=phaseprobe\npython -m build\npython scripts/check_links.py\npython scripts/hygiene.py\n```\n\nSee [CONTRIBUTING.md](/aliengineering-byte/phaseprobe/blob/main/CONTRIBUTING.md) and the concrete good-first-issue templates in `.github/ISSUE_TEMPLATE/`\n\n.\n\nApache-2.0. Copyright 2026 Ali. Citation metadata is in [CITATION.cff](/aliengineering-byte/phaseprobe/blob/main/CITATION.cff).", "url": "https://wpnews.pro/news/show-hn-phaseprobe-find-simulation-transitions-and-turn-them-into-tests", "canonical_source": "https://github.com/aliengineering-byte/phaseprobe", "published_at": "2026-08-01 23:12:56+00:00", "updated_at": "2026-08-01 23:22:24.404098+00:00", "lang": "en", "topics": ["developer-tools", "ai-tools"], "entities": ["PhaseProbe", "pytest", "Python", "CPython", "Windows", "Linux"], "alternates": {"html": "https://wpnews.pro/news/show-hn-phaseprobe-find-simulation-transitions-and-turn-them-into-tests", "markdown": "https://wpnews.pro/news/show-hn-phaseprobe-find-simulation-transitions-and-turn-them-into-tests.md", "text": "https://wpnews.pro/news/show-hn-phaseprobe-find-simulation-transitions-and-turn-them-into-tests.txt", "jsonld": "https://wpnews.pro/news/show-hn-phaseprobe-find-simulation-transitions-and-turn-them-into-tests.jsonld"}}