diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 882438c..a5bb923 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -83,11 +83,12 @@ Run the current source-checkout desktop application with: uv run --locked carnopy-gui ``` -Version `0.1.0a3` contains the historical Linux-first Widgets GUI. The current -`0.1.0a4` source has completed tested QML parity, both public desktop -commands launch the same QML application, and the duplicate Widgets -presentation is removed. `carnopy-gui` is the canonical command; -`carnopy-app` remains a compatibility alias for `0.1.0a4`. +Version `0.1.0a3` contains the historical Linux-first Widgets GUI, and +`0.1.0a4` completed the migration to one tested QML application. Current +`0.1.0a5` source adds the structured Model Sweep and ML Preparation workflows, +the custom frame, and direct post-generation plotting. `carnopy-gui` is the +canonical command; `carnopy-app` remains the compatibility alias introduced +for `0.1.0a4`. Worker-backed inspection and preview changes must use stable table IDs rather than GUI-supplied artifact paths. Cover traversal, symlink, integrity-token, diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml index 2164a75..ed05948 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.yml +++ b/.github/ISSUE_TEMPLATE/bug-report.yml @@ -14,7 +14,7 @@ body: attributes: label: Carnopy and Python versions description: Include `carnopy --version` or `carnopy-app --version`, plus `python --version`. - placeholder: "carnopy 0.1.0a3 or carnopy-app 0.1.0a3; Python 3.12.12" + placeholder: "carnopy 0.1.0a5 or carnopy-gui 0.1.0a5; Python 3.12.12" validations: required: true - type: dropdown diff --git a/.github/ISSUE_TEMPLATE/scientific-discrepancy.yml b/.github/ISSUE_TEMPLATE/scientific-discrepancy.yml index 0bce082..a844bde 100644 --- a/.github/ISSUE_TEMPLATE/scientific-discrepancy.yml +++ b/.github/ISSUE_TEMPLATE/scientific-discrepancy.yml @@ -14,7 +14,7 @@ body: id: versions attributes: label: Carnopy and CoolProp versions - placeholder: "Carnopy 0.1.0a3; CoolProp 8.0.0" + placeholder: "Carnopy 0.1.0a5; CoolProp 8.0.0" validations: required: true - type: input diff --git a/AGENTS.md b/AGENTS.md index 87be6c8..61a1bba 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -68,9 +68,9 @@ reading. | Work being performed | Required guidance | | --- | --- | | Any implementation, test, documentation, or commit handoff | [Development and contribution workflow](docs/agent-guides/DEVELOPMENT.md) | -| Product identity, boundaries, future scope, or roadmap priority | Maintainer-local `PRODUCT_SCOPE.md` and `.agents/private/PRODUCT_STRATEGY.md` when present, plus the public [README Future Scope](README.md#future-scope) | +| Product identity, boundaries, future scope, or roadmap priority | Maintainer-local `PRODUCT_SCOPE.md` and `.agents/private/PRODUCT_STRATEGY.md` when present, plus the public [README Future Scope](README.md#future-scope), [thermophysical roadmap](THERMOPHYSICAL_ROADMAP.md), and [ML preparation roadmap](ML_PREPARATION_ROADMAP.md) | | Delegating work or changing project-agent definitions | [Codex delegation policy](docs/agent-guides/DELEGATION.md) and the applicable files under `.codex/agents/` | -| Scientific behavior, configuration, sampling, CLI/API, rows, provenance, preparation, visualization, or core architecture | [Public scientific and application contracts](docs/agent-guides/SCIENTIFIC_CONTRACTS.md) | +| Scientific behavior, configuration, sampling, CLI/API, rows, provenance, preparation, visualization, or core architecture | [Public scientific and application contracts](docs/agent-guides/SCIENTIFIC_CONTRACTS.md), plus the [thermophysical roadmap](THERMOPHYSICAL_ROADMAP.md) when planning future sources, mixtures, models, backends, cycles, or scientific visualization | | Desktop controllers, QML, Widgets, worker boundaries, packaging of desktop resources, native 3D, or frontend retirement | [Desktop architecture](DESKTOP_ARCHITECTURE.md) and, while GUI-2 is active, [GUI-2 plan](GUI2_PLAN.md) | | Preparation workflows, diagnostics, feature engineering, or research directions | [Public scientific and application contracts](docs/agent-guides/SCIENTIFIC_CONTRACTS.md) and [ML preparation roadmap](ML_PREPARATION_ROADMAP.md) | | Packaging metadata, dependency extras, distribution contents, CI publishing, tags, or releases | [Packaging and release safeguards](docs/agent-guides/RELEASE.md) and [Development and contribution workflow](docs/agent-guides/DEVELOPMENT.md) | @@ -85,10 +85,12 @@ blending them. Carnopy is an open and auditable thermophysical-data workbench. Current behavior and exclusions live in the tracked scientific contracts. The public -direction is summarized in the [README Future Scope](README.md#future-scope); -maintainer-local product files may order future work when present. Planned -directions are not implemented capabilities or authority to broaden a public -contract without maintainer approval. +direction is summarized in the [README Future Scope](README.md#future-scope), +[thermophysical roadmap](THERMOPHYSICAL_ROADMAP.md), and +[ML preparation roadmap](ML_PREPARATION_ROADMAP.md); maintainer-local product +files may order future work when present. Planned directions are not +implemented capabilities or authority to broaden a public contract without +maintainer approval. ## Always-on safeguards diff --git a/CITATION.cff b/CITATION.cff index 50e3bc5..74b98f0 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -2,9 +2,7 @@ cff-version: 1.2.0 message: "To cite Carnopy, use the metadata below." title: "Carnopy" type: software -version: "0.1.0a4" -doi: "10.5281/zenodo.21709965" -date-released: "2026-07-30" +version: "0.1.0a5" license: MIT authors: diff --git a/DESKTOP_ARCHITECTURE.md b/DESKTOP_ARCHITECTURE.md index 781bd6b..6d08c83 100644 --- a/DESKTOP_ARCHITECTURE.md +++ b/DESKTOP_ARCHITECTURE.md @@ -69,14 +69,13 @@ The source tree has one desktop presentation implementation: - the QML Activity page, guarded end-to-end cross-page/close parity, public launcher migration, and Widgets retirement are implemented. -The release version is `0.1.0a4`. Both public launchers select the -tested QML parity application; Carnopy does not ship two normal desktop -applications or a frontend selector. The resulting QML application is the -planned `0.1.0a4` alpha checkpoint. Later sweep, preparation, and native-3D -stages are not prerequisites for that release. Stage 3 implementation, remote -CI, the complete local gate, and native acceptance passed on 2026-07-30. Its -accepted screenshot and historical implementation index are tracked under -`docs/`, and this document records the accepted Stage 3 architecture. +The release-candidate version is `0.1.0a5`. Both public launchers select the +same QML application; Carnopy does not ship two normal desktop applications or +a frontend selector. This release includes the accepted structured Model Sweep +and ML Preparation workflows, the custom desktop frame, and direct +post-generation session-plot handoff. Native-3D Stages 6–8 remain outside its +scope. The historical `0.1.0a4` Stage 3 checkpoint and later Stage 4/5 +acceptance records remain indexed under `docs/`. ## Authority map @@ -90,6 +89,7 @@ Use the narrowest applicable authority: | `GUI2_PLAN.md` | Temporary GUI-2 scope, sequencing, decisions, and acceptance status | | `DESKTOP_ARCHITECTURE.md` | Durable implemented desktop structure and evolution | | `README.md` | Public product summary plus user-facing installation and workflow guidance | +| `THERMOPHYSICAL_ROADMAP.md` and `ML_PREPARATION_ROADMAP.md` | Public future scientific and interoperability candidates; not implementation authority | When these disagree, do not silently blend them. Repository source and tests establish current behavior, while `AGENTS.md`, its task-routed authoritative @@ -520,6 +520,16 @@ samples per fluid facet so their outlines cannot obscure the color mesh; invalid emitted states retain explicit cross markers and remain counted in the sidecar. +Future source, mixture, property-backend, and cycle adapters described in +`THERMOPHYSICAL_ROADMAP.md` remain worker-owned scientific integrations. QML may +present typed capability, result, and failure projections but must not call +those engines or infer their support. In particular, a cycle path requires a +new typed result containing ordered topology and process states; the current +emitted-state p-v and T-s series cannot be promoted into cycle paths by +presentation logic. A future imported ML-result workflow follows the same +boundary: Python validates exact Preparation, partition, row, target, unit, and +artifact identities before QML can visualize predictions or errors. + ### `WorkerClient` `WorkerClient` is transport, not workflow logic. It starts one `QProcess`, diff --git a/GUI2_PLAN.md b/GUI2_PLAN.md index d836c21..d1c7b47 100644 --- a/GUI2_PLAN.md +++ b/GUI2_PLAN.md @@ -12,16 +12,18 @@ finished application. ## Release and frontend baseline -- `0.1.0a4` is the published baseline and contains the accepted Stage 3 QML - parity application. +- `0.1.0a5` is the current release candidate. It contains the accepted Stage 5 + structured Model Sweep and ML Preparation workflows, the custom desktop + frame, and direct post-generation session plotting. +- `0.1.0a4` is the historical Stage 3 QML-parity release. - `0.1.0a3` is the historical GUI-1 release and contains the retired Widgets presentation. - `carnopy-gui` is canonical. `carnopy-app` launches the same QML application - as a compatibility alias for `0.1.0a4`. + as the compatibility alias introduced for `0.1.0a4`. - The obsolete Widgets presentation is deleted. Carnopy does not ship a frontend selector or two normal desktop applications. -- `0.1.0a4` is a bounded post-Stage-3 release. It does not wait for sweep and - preparation QML workflows or native 3D. +- `0.1.0a5` remains bounded before native 3D; Stages 6–8 are not part of this + release. - The `app` extra is the cross-platform QML application. A future optional `3d` extra may add the native VTK bridge to that application; it is not a second GUI. diff --git a/ML_PREPARATION_ROADMAP.md b/ML_PREPARATION_ROADMAP.md index b54d061..b123a14 100644 --- a/ML_PREPARATION_ROADMAP.md +++ b/ML_PREPARATION_ROADMAP.md @@ -109,7 +109,7 @@ discoverability remain a post-Stage-5 UX follow-up rather than preparation science or an unfinished data contract. The accepted implementation record is indexed in [`docs/archive/GUI2_STAGE5.md`](docs/archive/GUI2_STAGE5.md). -## Reviewed future direction — Optional PyTorch dataset export +## Reviewed future direction: Optional PyTorch dataset export The product sequence now prioritizes desktop workflow depth and then source breadth. This bounded PyTorch consumption format remains reviewed but planned @@ -137,6 +137,87 @@ supported Python and platform matrix before changing packaging or public templates. It must not narrow the supported base-install matrix merely to add this derived format. +## Framework interoperability boundary + +Carnopy should make prepared thermophysical data easy to consume without +becoming a training framework or accumulating unrelated runtime dependencies. +Future interoperability should use three explicit levels: + +1. framework-neutral files and manifests owned by Carnopy; +2. small, optional, version-qualified consumption adapters; and +3. external training and orchestration systems that remain outside Carnopy. + +The current and candidate technologies fall into these categories: + +| Technology | Roadmap classification | Rationale | +| --- | --- | --- | +| SafeTensors | Implemented derived export | Framework-neutral tensor storage with deterministic manifest evidence; Parquet remains canonical. | +| PyTorch | Reviewed optional adapter candidate | A plain `.pt` tensor dictionary, or a documented Dataset/DataLoader consumer adapter, may reduce integration effort without moving training into Carnopy. | +| DeepXDE | External physics-informed consumer | A candidate example integration for PINNs and scientific ML over prepared bundles, not a Carnopy dependency or execution engine. | +| NVIDIA PhysicsNeMo | External physics-informed consumer | A candidate consumer for PINNs and neural operators when exact coordinates, fields, constraints, and provenance can be mapped explicitly. | +| XGBoost | Optional external tabular benchmark | Useful for nonlinear regression baselines or downstream studies only when a concrete comparison need justifies an adapter. | +| LightGBM | Optional external tabular benchmark | Potentially useful for large prepared tables, but not added merely to increase estimator count. | +| CatBoost | Optional external tabular benchmark | Potentially useful when categorical fluid or model identities remain native categorical features; the current one-hot representation is not a drop-in CatBoost contract. | +| DeepSpeed | External distributed-training infrastructure | Training optimization, checkpointing, and distributed execution remain consumer responsibilities. | +| Ray | External orchestration and tuning infrastructure | A future adapter requires a concrete distributed or hyperparameter-search workflow; Ray is not part of preparation itself. | +| Helion | Out of scope for Carnopy core | A GPU kernel language sits below Carnopy's data and provenance abstraction. | +| vLLM | Out of scope for thermophysical ML Preparation | LLM inference and serving do not address Carnopy's tabular scientific-data contract. | + +These classifications prevent name-driven dependency growth. An adapter must +solve a demonstrated workflow, preserve the exact Preparation bundle identity, +and pass dependency, platform, serialization, security, and maintenance review. + +Flatten operations are tensor reshaping or neural-network layer choices, not +thermophysical feature transformations. Cross-entropy is a classification loss +and is relevant only to an explicit future classification target such as phase +or validity class. It is not an appropriate default for continuous property +regression. More relevant external regression measures include mean absolute +error, root mean squared error, Huber loss, carefully defined relative error, +maximum error, and physics-consistency residuals. Carnopy may define how +imported evaluation evidence is interpreted, but it does not own the training +loop or loss optimization. + +## Imported prediction results and ML visualization + +A useful ML workflow requires more than writing arrays. A future reviewed +result-import contract should let Carnopy inspect and compare outputs from an +external trainer without loading executable model objects. Every imported +result must bind to: + +- the exact Preparation bundle and manifest identity; +- scenario and partition identities; +- source dataset or sweep identity; +- feature, target, unit, row, and transformation definitions; +- external framework, model, training-run, and artifact identities; +- prediction and uncertainty column semantics; +- declared metrics and aggregation domains; and +- immutable imported bytes with hashes and provenance. + +Imported results must reject or clearly quarantine incompatible row identities, +partitions, targets, units, inverse transformations, and stale source bindings. +Carnopy should not deserialize arbitrary checkpoints, execute user models, or +infer missing training metadata. + +Candidate result views include: + +- predicted-versus-reference parity plots; +- residual distributions and quantile summaries; +- error by fluid, phase, backend model, temperature, pressure, composition, and + validity domain; +- train, validation, test, and holdout comparisons; +- learning and validation curves when supplied by the external trainer; +- uncertainty calibration and coverage plots; and +- side-by-side model comparisons over the exact same accepted rows. + +The result-import and visualization contract should work across PyTorch, +DeepXDE, PhysicsNeMo, scikit-learn, XGBoost, LightGBM, CatBoost, and other +external consumers without making any one framework the scientific authority. + +Framework-ready future exports should preserve coordinates, properties, units, +composition, domain masks, phase labels, available derivatives, physical +constraints, and complete provenance. They must not fabricate derivative or +constraint fields merely because a consumer framework can accept them. + ## Durable preparation rules - Split assignment precedes every fitted transformation. @@ -309,6 +390,25 @@ not part of the preparation roadmap. - scikit-learn, [Preprocessing reference](https://scikit-learn.org/stable/api/sklearn.preprocessing.html), for the semantics and tradeoffs of common transformations. +- scikit-learn, [Model evaluation](https://scikit-learn.org/stable/modules/model_evaluation.html) + and [learning curves](https://scikit-learn.org/stable/modules/learning_curve.html). +- PyTorch, [`torch.flatten`](https://docs.pytorch.org/docs/stable/generated/torch.flatten.html) + and [`CrossEntropyLoss`](https://docs.pytorch.org/docs/stable/generated/torch.nn.CrossEntropyLoss.html), + for their actual tensor and classification semantics. +- [DeepXDE](https://github.com/lululxvi/deepxde) and + [NVIDIA PhysicsNeMo](https://docs.nvidia.com/deeplearning/physicsnemo/physicsnemo-core/), + as candidate external physics-informed consumers. +- [XGBoost](https://xgboost.readthedocs.io/en/stable/index.html), + [LightGBM](https://lightgbm.readthedocs.io/en/stable/), and + [CatBoost](https://catboost.ai/docs/en/), as candidate external tabular + consumers. +- [DeepSpeed](https://deepspeed.readthedocs.io/en/stable/index.html), + [Ray Tune](https://docs.ray.io/en/latest/tune/tutorials/tune-lifecycle.html), + [Helion](https://pytorch.org/blog/helion/), and + [vLLM](https://docs.vllm.ai/en/stable/index.html), for the boundaries between + data preparation, external orchestration, kernel generation, and LLM serving. +- Hugging Face, [SafeTensors](https://huggingface.co/docs/safetensors/index), for + the implemented framework-neutral tensor format. - Brunton, Proctor, and Kutz, [Discovering governing equations from data by sparse identification of nonlinear dynamical systems](https://doi.org/10.1073/pnas.1517384113), *PNAS* 113 (2016), diff --git a/README.md b/README.md index 711af58..73b9254 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,6 @@ [![PyPI](https://img.shields.io/pypi/v/carnopy.svg)](https://pypi.org/project/carnopy/) [![Python](https://img.shields.io/pypi/pyversions/carnopy.svg)](https://pypi.org/project/carnopy/) [![Verify](https://github.com/gcalpay/carnopy/actions/workflows/ci.yml/badge.svg)](https://github.com/gcalpay/carnopy/actions/workflows/ci.yml) -[![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.21709965.svg)](https://doi.org/10.5281/zenodo.21709965) [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) Reproducible thermophysical data pipelines integrating property models, simulation backends and validated reference data, with inspection, visualization, provenance and leakage aware preparation for physics-informed machine learning workflows. @@ -13,19 +12,19 @@ explicit YAML sampling specification into immutable CSV and Parquet datasets, diagnostics, metadata, and optional figures, with an automation-friendly CLI, a Python library, and an optional QML desktop application. -![Carnopy QML Dataset workbench](https://raw.githubusercontent.com/gcalpay/carnopy/main/docs/assets/carnopy-dataset-workbench-dark.png) +![Carnopy QML Dataset workbench](docs/assets/carnopy-dataset-workbench-dark.png) > Carnopy is alpha software. Public interfaces and generated schemas may change > before the stable `0.1.0` release. -## Why Carnopy? +## Core capabilities - **Reproducible inputs:** explicit fluids, backend model, samplers, units, properties, and output formats. - **Traceable outputs:** normalized configuration, software and backend versions, reference-state context, artifact hashes, and stable identities. -- **Honest failures:** invalid thermodynamic states remain visible as row-level - diagnostics instead of silently disappearing. +- **Explicit failures:** invalid thermodynamic states remain visible as + row-level diagnostics instead of silently disappearing. - **One scientific core:** CLI, Python, and desktop workflows use the same validation, generation, inspection, and rendering contracts. - **Scientific visualization:** emitted states, gaps, phase changes, units, @@ -50,35 +49,22 @@ synthetic output from the selected backend and model. ## Installation -The commands below install the published `0.1.0a4` alpha from PyPI. Use an -isolated uv-managed environment for the desktop application or install the -CLI and Python library into the current environment with pip. +Carnopy requires Python 3.11 or later. Published packages, tagged source, and a +development checkout use separate installation paths. -### Isolated desktop application +### PyPI installation -Install the QML desktop workbench in its own uv-managed environment: - -```bash -uv tool install "carnopy[app]==0.1.0a4" -``` - -Then start the workbench: +Install the QML desktop workbench in an isolated uv-managed environment: ```bash +uv tool install "carnopy[app]==0.1.0a5" carnopy-gui ``` -### CLI and Python library - -Install the base package into your current Python environment: - -```bash -python -m pip install "carnopy==0.1.0a4" -``` - -Then inspect the available commands: +Install the CLI and Python library into an existing virtual environment: ```bash +python -m pip install "carnopy==0.1.0a5" carnopy --help ``` @@ -92,26 +78,42 @@ Optional capabilities use one extra on the same requirement: | `analysis` | Optional scikit-learn preparation diagnostics | | `all` | Exact union of all public extras | -For example, use `carnopy[viz]==0.1.0a4` instead of `carnopy==0.1.0a4` when a -CLI/library environment also needs plotting. PyArrow remains a core dependency -because Parquet is a first-class output format. +For example, use `carnopy[viz]==0.1.0a5` instead of `carnopy==0.1.0a5` when a +CLI or library environment also needs plotting. PyArrow remains a core +dependency because Parquet is a first-class output format. -`carnopy-gui` is the canonical desktop command. `carnopy-app` launches the same -QML application as a compatibility alias for the `0.1.0a4` release. +`carnopy-gui` is the canonical desktop command. `carnopy-app` is a +compatibility alias that launches the same QML application. -### Try the current source +### Installation from source + +Run the tagged release without installing contributor tooling: ```bash -git clone https://github.com/gcalpay/carnopy.git +git clone --branch v0.1.0a5 --depth 1 https://github.com/gcalpay/carnopy.git cd carnopy -uv sync --locked --extra app --group dev +uv sync --locked --extra app --no-dev uv run --locked carnopy-gui ``` -The desktop extra requires PySide6 Essentials 6.11.1 or later within the 6.11 release line. -The private native bridge remains qualified against exactly Qt 6.11.1. Qt is an -optional third-party dependency with its own licensing terms; Carnopy remains -MIT licensed and does not ship a standalone Qt installer. +### Development setup + +Clone the active repository and install the development environment: + +```bash +git clone https://github.com/gcalpay/carnopy.git +cd carnopy +uv sync --locked --extra all --group dev --group release +uv run --locked pytest +``` + +`pyproject.toml` and `uv.lock` are authoritative. Do not create parallel +requirements files. + +The desktop extra requires PySide6 Essentials 6.11.1 or later within the 6.11 +release line. The private native bridge remains qualified against exactly Qt +6.11.1. Qt is an optional third-party dependency with its own licensing terms; +Carnopy remains MIT licensed and does not ship a standalone Qt installer. ## Quick start @@ -131,7 +133,7 @@ carnopy plot outputs/ \ The normal command-line workflow is: ```text -init → edit → optional validate → generate/sweep → inspect → optional plot → optional prepare +init -> edit -> optional validate -> generate/sweep -> inspect -> optional plot -> optional prepare ``` `generate` always performs authoritative validation. The separate `validate` @@ -144,8 +146,10 @@ Use command-specific help for the complete current interface: carnopy --help carnopy init --help carnopy generate --help +carnopy sweep --help carnopy inspect --help carnopy plot --help +carnopy prepare --help ``` ## Desktop workflow @@ -156,48 +160,25 @@ Start the workbench with: carnopy-gui ``` -Its workflow is: +The primary desktop workflow is: ```text -Workspace → Dataset → Save → Run → Create plot / Inspect → Visualization - └→ optional YAML Preview - → Model Sweeps → Plan/Execute → Inspect - → ML Preparation → Plan/Execute → Inspect - → Activity and Recovery +Workspace -> Dataset -> Save -> Run -> Generate + |-> Create plot from this run -> Visualization -> Render plot + |-> Inspect data -> ML Preparation -> Plan -> Execute + |-> optional YAML Preview + +Workspace -> Model Sweeps -> Plan -> Execute -> Inspect ``` -- **Dataset** edits all three dataset modes and projects row counts without - importing the scientific stack into the GUI process. -- **Model Sweeps** edits the complete current sweep schema, including - comparison plots, and exposes worker-verified Plan, Execute, cancellation, - result status, and exact Inspect handoff. -- **ML Preparation** requires an explicitly bound eligible source from Inspect, - then edits the complete current Preparation schema and exposes the same - controlled Plan, Execute, cancellation, result, and Inspect lifecycle. -- **YAML Preview** shows the deterministic complete document. Save and Save As - validate those exact bytes in a worker before writing. -- **Run** validates and generates an exact clean saved snapshot, then can open - a compatible editable plot request for that exact finalized output. -- **Inspect** presents provenance, diagnostics, logical arrays, bounded - order-preserving table pages, and finalized Preparation audit evidence. -- **Visualization** separates automated plots for future Generate operations - from explicit session rendering over already generated, inspected columns. - A new session plot starts with compatible editable fields and never renders - until **Render plot** is pressed. -- **Activity and Recovery** projects private request records and removes only - explicitly selected, rescanned staging artifacts. - -The current source application keeps one active Dataset, Model Sweep, or -Preparation configuration with one Save, Reload, Close, dirty-state, and YAML -Preview lifecycle. Generic Open dispatches from the YAML `document_type`. -Preparation source profiling, explicit source binding, complete structured -drafts, planning, execution, and its packaged editor are implemented and -enabled in the normal shell. Inspect exposes the typed Preparation audit view -for accepted Preparation bundles. Lifecycle hardening, packaged QML -qualification, the complete local gate, remote verification, and native -functional acceptance have passed. The workflows remain scientifically dense; -broader onboarding and discoverability refinement are planned as focused UX -follow-up work. +Dataset supports property, saturation, and vapor-mass-fraction tables. Run +generates an exact clean saved configuration. A successful run can be inspected, +used for ML Preparation, or passed directly to Visualization as a compatible +editable plot request. Rendering, planning, and execution remain explicit user +actions. + +YAML Preview exposes the complete deterministic document. Activity and Recovery +provides request history and explicit recovery of selected staging artifacts. Scientific generation, inspection, and Matplotlib rendering run in short-lived workers. The QML process does not import CoolProp, NumPy, pandas, PyArrow, or @@ -255,13 +236,8 @@ properties: outputs: dataset_formats: [csv, parquet] -``` -Add an optional top-level `visualization` section to render configured figures -after the immutable dataset run is finalized. For example, this block adds a -non-interpolated density heatmap for the configuration above: - -```yaml +# Optional: render this figure during Generate. visualization: format: png fluids: [Propane] @@ -274,9 +250,9 @@ visualization: property: mass_density ``` -Configured visualization requires the `viz`, `app`, or `all` extra. Generated -figures are written outside the immutable dataset run with plot provenance and -a visualization report. +Remove the optional `visualization` section for a dataset-only run. Configured +figures require the `viz`, `app`, or `all` extra and are written outside the +immutable dataset run with plot provenance and a visualization report. Create a concise starter or the exhaustive commented reference: @@ -298,17 +274,10 @@ All backend calls and generated numeric columns use SI. Carnopy preserves the declared units and sampler definitions in provenance while normalizing the executable scientific specification deterministically. -### Backend models - -| Model | Meaning | Current limitation | -| --- | --- | --- | -| `heos` | Helmholtz-energy equations and associated models | Full current property registry, subject to fluid/state support | -| `pr` | Peng-Robinson cubic equation of state | No transport properties, surface tension, or usable triple point | -| `srk` | Soave-Redlich-Kwong cubic equation of state | No transport properties, surface tension, or usable triple point | - HEOS is the starter default, not experimental truth. PR and SRK are alternative -model assumptions, not accuracy rankings. Model selection changes scientific -identity and is recorded in rows, metadata, and reports. +model assumptions, not accuracy rankings, and do not provide transport +properties, surface tension, or a usable triple point. Model selection changes +scientific identity and is recorded in rows, metadata, and reports. ## Outputs and provenance @@ -327,14 +296,9 @@ outputs// ``` Runs are staged and then atomically renamed. Existing final or staging paths -are never overwritten. Important identities have distinct meanings: - -- `spec_id`: canonical executable scientific specification; -- `generation_context_id`: specification plus software and artifact context; -- `output_request_id`: canonical dataset serialization request; -- `run_id`: one execution attempt; -- artifact hashes: exact emitted bytes; -- `visualization_request_id`: normalized visualization request. +are never overwritten. The executable specification, generation context, +output request, execution attempt, visualization request, and exact artifact +bytes retain distinct identities. Metadata records software and backend versions, selected model, CoolProp `DEF` reference-state policy, canonical fluids and properties, sampling, failures, @@ -347,35 +311,26 @@ Visualization reads emitted columns only. It never calls a thermodynamic backend, smooths, interpolates, extrapolates, or invents states. Supported plot kinds are property curves, sampled property heatmaps, generic -X-Y plots, and emitted-state p-v and T-s diagrams. For example: - -```bash -carnopy plot outputs/ \ - --kind property-curves \ - --property specific_enthalpy \ - --x temperature \ - --series pressure=1bar \ - --series pressure=3bar \ - --display-unit temperature=degC \ - --display-unit specific_enthalpy=kJ/kg -``` +X-Y plots, and emitted-state p-v and T-s diagrams. Exact filters and series values never select a nearest neighbor. The p-v plot derives only `specific_volume = 1 / mass_density`; the T-s plot uses emitted temperature and specific entropy. Neither constructs a cycle, process path, phase envelope, saturation dome, or missing branch. -Configured visualization belongs in an optional top-level `visualization:` -section and runs only after the immutable dataset is finalized. Images are -written outside the dataset run with a `.plot.json` provenance sidecar and a -`visualization-report.json`. Supported formats are PNG, SVG, and PDF. +The optional YAML visualization section renders PNG, SVG, or PDF figures only +during a later Generate. It does not alter an existing run. In the desktop workbench, **Create plot from this run** inspects the exact -finalized output and opens an editable session-only request. This does not +finalized output and opens an editable session-only request. The request uses a +compatible plot kind, property, axes, and fluids, with PNG as the default. It +does not render until **Render plot** is pressed. Session plotting does not change the saved YAML or affect the generated dataset. Automated YAML plots remain available separately and render only during a later Generate. -## Model sweeps and ML preparation +## Model sweeps and ML Preparation + +### Model sweeps Model sweeps generate ordinary immutable child runs and compare their emitted values without extra thermodynamic evaluation during comparison: @@ -385,10 +340,13 @@ carnopy init model_sweep sweep.yaml carnopy sweep sweep.yaml ``` -In the current source desktop, create or open that YAML through Workspace and -use **Model Sweeps** for structured editing, planning, controlled execution, -cancellation, result review, and Inspect handoff. The published `0.1.0a4` -desktop predates this Stage 5 surface; its CLI behavior is unchanged. +In the desktop workbench, create or open that YAML through Workspace and use +**Model Sweeps** for structured editing, planning, controlled execution, +cancellation, result review, and Inspect handoff. + +### ML Preparation + +![Carnopy ML Preparation workbench](docs/assets/carnopy-mlprep-dark.png) Preparation reads an existing immutable run or sweep bundle and never calls a thermodynamic backend: @@ -398,6 +356,10 @@ carnopy init preparation preparation.yaml carnopy prepare outputs/ --config preparation.yaml --out prepared ``` +In the desktop workbench, bind an eligible source explicitly from Inspect, then +use **ML Preparation** for structured editing, planning, controlled execution, +cancellation, result review, and inspection of the finalized audit evidence. + Parquet remains the canonical prepared table. Optional NumPy and SafeTensors files are derived ML-consumption exports. Leakage-aware scenarios keep an exact thermodynamic-state hash in one partition, and transformations fit on training @@ -405,9 +367,7 @@ data only. Optional scikit-learn baselines are disposable diagnostics; Carnopy does not train, tune, register, or deploy production models. Implemented behavior and reviewed research directions are separated in the -[ML preparation roadmap](https://github.com/gcalpay/carnopy/blob/main/ML_PREPARATION_ROADMAP.md). -An optional manifest-backed PyTorch dataset export remains a reviewed future -direction; it is neither implemented nor the current product priority. +[ML preparation roadmap](ML_PREPARATION_ROADMAP.md). ## Python API @@ -429,11 +389,14 @@ Public helpers also cover model sweeps, preparation, and explicit visualization. CLI handlers and desktop controllers call the same core logic rather than maintaining separate scientific implementations. -## Scientific limitations +## Current alpha scope + +Carnopy `0.1.0a5` deliberately begins with a bounded, verified scientific +scope. The current alpha supports CoolProp pure fluids with HEOS, +Peng-Robinson, and Soave-Redlich-Kwong; three dataset modes; model sweeps; +emitted-column visualization; and leakage-aware ML Preparation. These are +current release boundaries, not the intended limit of the project. -- CoolProp is the only current backend; pure fluids only. -- Supported CoolProp models are HEOS, Peng-Robinson, and - Soave-Redlich-Kwong. - Generated data is backend output, not experimental evidence. - Specific enthalpy, entropy, and internal energy depend on reference state. - Carnopy resets every requested fluid to CoolProp `DEF` before generation and @@ -445,9 +408,9 @@ rather than maintaining separate scientific implementations. capability. - ML training, model hyperparameter sweeps, GPU orchestration, checkpoints, and deployment are outside Carnopy core. -- Mixtures, additional backends, ORC generation, web services, databases, - native 3D, and standalone desktop installers are not currently implemented; - the high-level public direction is summarized below. +- Mixtures, additional property backends, validated reference-data imports, + thermodynamic-cycle simulation, native 3D, web services, databases, and + standalone desktop installers are not implemented in this alpha. See the official [CoolProp documentation](https://coolprop.org/coolprop/) and [high-level API reference](https://coolprop.org/coolprop/HighLevelAPI.html) for @@ -455,44 +418,51 @@ backend behavior. ## Future Scope -Carnopy's current contracts remain intentionally narrower than its product +Carnopy's current contracts remain intentionally narrower than its planned direction: ```text thermophysical engines and data sources - → Carnopy configuration, generation/import, comparison, inspection, - visualization, preparation, export, and audit - → reproducible bundles and adapters - → external model-training frameworks and applications + -> Carnopy configuration, generation/import, comparison, inspection, + visualization, preparation, export, and audit + -> reproducible bundles and adapters + -> external model-training frameworks and applications ``` -The accepted direction is workflow depth now, source breadth next, and advanced -model breadth later. GUI-2 Stage 4 brought the existing model-sweep and -preparation workflows into the desktop's controlled nonvisual worker boundary. -Stage 5 completed the structured Model Sweep and Preparation editors, typed -Preparation audit inspection, lifecycle hardening, packaged QML qualification, -and native functional acceptance. Carnopy's next product-planning direction is -a validated import/source contract followed by one evidence-driven source -expansion. - -Detailed source and model candidates are maintainer planning rather than public -support promises. Optional PyTorch export, exact 3D, and automation remain -unimplemented directions that require separately reviewed plans before they can -change public behavior. - -## Development and contribution - -Carnopy uses a `src/` layout, Hatchling, standalone uv, Ruff, strict mypy, and -pytest. `pyproject.toml` and `uv.lock` are authoritative. - -```bash -uv sync --locked --extra all --group dev -uv lock --check -uv run --locked ruff check . -uv run --locked ruff format --check . -uv run --locked mypy src/carnopy -uv run --locked pytest -``` +The planned direction develops six connected capabilities: + +- **Validated sources and comparisons:** import reference and experimental data, + beginning with ThermoML-compatible records, while preserving citations, + methods, units, uncertainty, composition, and validity domains. +- **Mixtures and phase equilibria:** begin with binary mixtures through a data + contract that can extend to multicomponent compositions, flashes, phase + envelopes, and equilibrium data without changing scientific identity rules. +- **Additional models and backends:** evaluate established model families such + as NRTL, UNIQUAC, UNIFAC, PC-SAFT, CPA, Lee-Kesler, GERG, IAPWS, and Pitzer + through narrowly qualified backend adapters rather than reimplementing them. +- **Thermodynamic-cycle studies:** integrate simulation engines for Rankine and + organic Rankine cycles, refrigeration, heat pumps, and Brayton cycles while + retaining exact topology, assumptions, balances, solver evidence, and + provenance. +- **Expanded visualization:** add mixture, phase-equilibrium, model-comparison, + uncertainty, cycle, Preparation, and imported ML-result views backed only by + verified data contracts. +- **ML interoperability:** keep Parquet canonical while evaluating PyTorch and + selected external physics-informed and tabular-ML consumers, plus an + identity-bound result-import contract for prediction and error analysis. + +The [thermophysical and simulation roadmap](THERMOPHYSICAL_ROADMAP.md) records +the detailed source, model, backend, mixture, cycle, and visualization +candidates. The [ML preparation roadmap](ML_PREPARATION_ROADMAP.md) records +framework interoperability and result-evaluation directions. Roadmap entries +are research and planning candidates, not support promises; each requires a +separately reviewed scientific contract, implementation plan, and qualification +before it changes public behavior. + +## Contributing + +Carnopy uses a `src/` layout, Hatchling, uv, Ruff, strict mypy, and pytest. +`pyproject.toml` and `uv.lock` are authoritative. Read [CONTRIBUTING.md](https://github.com/gcalpay/carnopy/blob/main/.github/CONTRIBUTING.md) before proposing a public or scientific contract change. Use @@ -505,15 +475,15 @@ The implemented desktop ownership and worker boundary are documented in ## Release status -The latest published alpha is `0.1.0a4`, the bounded post-Stage-3 release of -the accepted QML parity application. Its complete local and remote release -gates, native acceptance, [PyPI publication](https://pypi.org/project/carnopy/0.1.0a4/), -[GitHub prerelease](https://github.com/gcalpay/carnopy/releases/tag/v0.1.0a4), -and [version-specific Zenodo archive](https://doi.org/10.5281/zenodo.21709965) -are complete. GUI-2 Stages 4 and 5 are implemented in current source without -changing the published `0.1.0a4` artifacts. Stage 5's structured Sweep and -Preparation desktop workflows therefore remain source-only until a later -release is separately planned and qualified. +The current alpha release is `0.1.0a5`. It includes the structured Model Sweep +and ML Preparation desktop workflows, direct post-generation plotting, the +custom desktop window frame, and the associated lifecycle and release +qualification work. See the +[v0.1.0a5 release notes](https://github.com/gcalpay/carnopy/blob/main/docs/releases/v0.1.0a5.md) +for a concise summary. + +The version-specific `0.1.0a5` DOI will be recorded after Zenodo archives the +final GitHub release. ## License diff --git a/THERMOPHYSICAL_ROADMAP.md b/THERMOPHYSICAL_ROADMAP.md new file mode 100644 index 0000000..ba7225d --- /dev/null +++ b/THERMOPHYSICAL_ROADMAP.md @@ -0,0 +1,299 @@ +# Carnopy thermophysical and simulation roadmap + +## Purpose and status + +This document records the public research direction beyond Carnopy's current +alpha contract. It separates potential sources, model families, backend +adapters, mixture capabilities, cycle workflows, and visualizations from +implemented behavior. + +Every item below is planned direction or a candidate for evaluation, not a +supported capability or a public API commitment. A candidate may enter Carnopy +only through a separately reviewed scientific contract and implementation +stage with licensing, platform, validation, provenance, and distribution +qualification. The current behavior remains defined by +[`docs/agent-guides/SCIENTIFIC_CONTRACTS.md`](docs/agent-guides/SCIENTIFIC_CONTRACTS.md). + +## Product direction + +Carnopy should not compete by reproducing every equation of state, activity +model, process solver, or training framework. Established scientific engines +already provide broad and specialized numerical implementations. Carnopy's +distinct role is to make work across those engines reproducible and auditable: + +- canonical source, component, composition, unit, model, and parameter + identities; +- explicit validity domains, reference states, uncertainty, and failure + evidence; +- immutable generation, import, comparison, cycle, and preparation outputs; +- aligned model-to-model and model-to-reference comparisons; +- inspection and visualization without inventing unsampled values; and +- exact handoffs to external simulation and machine-learning consumers. + +Backend count is not a success measure. A new adapter is useful only when its +results can be identified, validated, compared, reproduced, packaged, and +explained at least as rigorously as current CoolProp runs. + +## Recommended sequence + +1. Establish a validated source/import contract, beginning with ThermoML. +2. Add binary mixtures through a schema designed for later multicomponent use. +3. Add model-to-reference validation, uncertainty-aware residuals, and + parameter provenance. +4. Introduce TESPy-backed thermodynamic-cycle studies and cycle visualization. +5. Select one advanced property backend from measured workflow and scientific + needs instead of adding several shallow adapters. +6. Add a PyTorch consumption adapter and identity-bound imported prediction + evaluation as separately reviewed ML stages. +7. Consider electrolytes and specialized distributed-training integration only + after a concrete scientific use case requires them. + +This order is a planning guide, not a release schedule. Evidence may justify a +different sequence, but identity and validation contracts should precede broad +backend or model expansion. + +## Admission criteria for scientific expansions + +Every source, model, or simulator integration must define and test: + +- canonical names and versioned capability discovery; +- unit, basis, sign, composition, phase, and reference-state conventions; +- model parameters, interaction parameters, and their source or citation; +- supported properties, state variables, phases, and validity domains; +- behavior for unsupported, invalid, nonconverged, metastable, and ambiguous + states; +- uncertainty and method metadata when the source provides them; +- deterministic normalized configuration and stable scientific identities; +- complete software, database, backend, model, and artifact provenance; +- immutable outputs, no-overwrite finalization, and auditable diagnostics; +- license, redistribution, optional-dependency, platform, and maintenance + constraints; and +- independent checks against published or authoritative reference cases. + +Carnopy must not silently translate incompatible conventions, fill missing +scientific information, select an interaction parameter without provenance, +or present agreement between two models as experimental validation. + +## Validated reference and experimental data + +### ThermoML as the first import target + +ThermoML is the strongest first interchange target because it is an IUPAC +standard for representing thermodynamic property data and associated metadata. +A reviewed import stage should preserve, where supplied: + +- publication DOI and full citation; +- authors, laboratory, sample, and measurement method; +- reported variables, properties, units, constraints, and phases; +- component identities and composition basis; +- numeric values, uncertainty definitions, and coverage; +- data-quality notes, corrections, and source-record identity; and +- the exact imported bytes and normalized Carnopy representation. + +The importer must not treat every record as equally suitable for validation. +Method, uncertainty, phase, composition, and domain compatibility must remain +visible so users can decide what constitutes relevant evidence. + +### Comparison and validation products + +Model-to-reference comparison should align only scientifically compatible +states and should produce both row-level evidence and aggregate summaries: + +- signed and absolute residuals; +- relative residuals only where the denominator is scientifically meaningful; +- bias, mean absolute error, root mean squared error, maximum deviation, and + average absolute relative deviation where applicable; +- uncertainty-normalized residuals when uncertainty semantics are compatible; +- coverage maps over temperature, pressure, composition, property, and phase; +- model and parameter rankings scoped to an explicit domain; and +- traceable exclusions for unmatched or incompatible records. + +Parameter regression may be considered only after this comparison contract +exists. Fitted binary interaction or activity-model parameters must retain the +source records, objective, weighting, bounds, optimizer, convergence evidence, +software versions, covariance or uncertainty information when available, and +an immutable result identity. Fitted parameters must never silently replace a +backend default. + +## Mixtures and phase equilibria + +### Composition contract + +Binary mixtures are the practical first milestone, but the normalized schema +should not assume that exactly two components will always exist. It should +support: + +- ordered canonical component identities; +- mole and mass fractions, with volume fractions only when their reference + conditions and semantics are explicit; +- normalization tolerances and the original declared composition; +- mixture, component, and phase composition bases; +- interaction parameters with model, source, units, version, and applicability; +- phase identities, phase fractions, and per-phase compositions; and +- stable identities that change when composition, basis, model, parameters, or + reference context changes. + +### Equilibrium and flash capabilities + +Candidate mixture stages include: + +- bubble-point and dew-point calculations; +- temperature-pressure, pressure-enthalpy, pressure-entropy, and quality flashes + where the selected backend supports them; +- vapor-liquid and liquid-liquid equilibrium, followed later by + vapor-liquid-liquid equilibrium where justified; +- phase envelopes, critical points and lines, and azeotrope evidence; +- stability, initialization, iteration, and convergence diagnostics; and +- explicit distinction between equilibrium, metastable, and failed states. + +Backend capability discovery must decide which operations are available. QML, +CLI presentation, or generic list order must not guess scientific support. + +## Property and equilibrium model families + +The following families are evaluation candidates. Their names do not imply +that Carnopy will implement the mathematics itself. + +| Family | Candidate models or standards | Primary scientific role and required caution | +| --- | --- | --- | +| Multiparameter and reference formulations | HEOS extensions, REFPROP formulations, IAPWS-IF97, GERG-2008 | High-accuracy fluid, water/steam, and natural-gas work; database version, mixture rules, validity domain, and reference state must be explicit. | +| Cubic and corresponding-states models | PR and SRK extensions, PRSV variants, Lee-Kesler-Plocker | Engineering calculations and comparison baselines; mixing rules, alpha functions, volume translation, and binary parameters are part of identity. | +| Molecular and associating equations of state | PC-SAFT, Cubic-Plus-Association (CPA), SAFT-VR Mie | Associating, polar, chain, and complex-fluid systems; parameter sets and association schemes require strong provenance. | +| Activity-coefficient and excess-Gibbs models | NRTL, UNIQUAC, Wilson, UNIFAC, Modified UNIFAC | Liquid-phase nonideality and phase-equilibrium calculations; component groups, temperature dependence, parameter directionality, and regression source must be retained. | +| Electrolyte models | Pitzer, electrolyte NRTL, Specific Ion Interaction Theory (SIT) | A separate electrolyte milestone requiring ion and species identities, concentration scales, reactions, charge balance, and solvent conventions. | +| Predictive mixture methods | UNIFAC variants and, after careful evaluation, COSMO-based approaches | Useful when fitted binary parameters are unavailable, but method version, group assignment, parameter database, and expected accuracy domain remain essential. | + +NRTL, UNIQUAC, Wilson, and UNIFAC are not interchangeable equations of state. +They require an explicit phase-equilibrium framework and parameter contract. +CPA and PC-SAFT are especially relevant for associating and polar mixtures. +GERG-2008 is a natural-gas specialization, IAPWS-IF97 is a water and steam +industrial formulation, and Lee-Kesler is useful as an engineering benchmark. +Pitzer should not be folded into a generic fluid-mixture stage because aqueous +electrolytes add species, reaction, concentration, and electroneutrality +requirements. + +## Backend adapter candidates + +| Candidate | Potential value | Evaluation boundary | +| --- | --- | --- | +| CoolProp mixture and PC-SAFT capabilities | Lowest-friction extension of the current backend and worker boundary. | Qualify supported mixtures, models, flashes, parameters, and failure behavior per operation rather than assuming feature parity with pure-fluid HEOS. | +| NIST REFPROP | Authoritative high-accuracy pure-fluid and mixture formulations for many engineering uses. | Optional user-managed licensed installation only. Carnopy must not redistribute REFPROP and must record database version, fluid files, model, reference state, and capabilities. | +| ThermoPack | Broad multicomponent and multiphase engine with cubic, CPA, PC-SAFT, SAFT-VR Mie, Lee-Kesler, GERG, flash, envelope, and critical-point capabilities. Its Apache-2.0 license and current Windows, Linux, and macOS Python distribution make it a strong candidate. | Reverify license and platform artifacts at adoption, then evaluate ABI stability, thread/process behavior, numerical validation, and long-term adapter maintenance. | +| NIST teqp | Modern library for advanced Helmholtz-energy mixture models, CPA, PC-SAFT, SAFT-VR Mie, Lee-Kesler-Plocker, GERG, critical curves, phase equilibria, and fitting. | Define a narrow supported subset and stable parameter/model identities instead of exposing an unrestricted backend object model. | +| `thermo` | Python implementations of NRTL, UNIQUAC, UNIFAC and multiphase flash workflows. | Qualify model databases, parameter sources, flash algorithms, performance, dependency impact, and exact supported use cases. | + +Selection must follow a concrete user workflow and comparison corpus. License, +platform reach, scientific coverage, deterministic configuration, failure +evidence, and maintenance cost matter more than the length of the feature list. + +## Thermodynamic-cycle studies + +Cycle support is an explicit future direction. Carnopy should wrap qualified +simulation engines and own reproducible configuration, execution records, +comparison, inspection, visualization, provenance, and ML handoff. It should +not become an unbounded general-purpose process solver. + +### Candidate cycle families + +- Rankine, organic Rankine, and trilateral flash cycles; +- vapor-compression refrigeration cycles; +- heat-pump cycles; +- Brayton and recuperated Brayton cycles; +- combined and cascade cycles after the component and topology contracts are + proven; and +- reacting or propulsion cycles only through later specialized adapters. + +### Minimum cycle result contract + +A cycle run must retain: + +- ordered topology, streams, ports, component types, and connectivity; +- boundary conditions and design or off-design mode; +- working fluid, composition, property backend, model, parameters, and + reference state; +- compressor, turbine, pump, and other component efficiencies; +- heat-exchanger approaches, pressure losses, ambient assumptions, and other + declared component parameters; +- solver settings, initialization, convergence, residual, warning, and failure + evidence; +- state points with stable stream and component identities; +- mass, energy, entropy, and, where supported, exergy balances; +- heat duties, shaft powers, net power, efficiency, and coefficient of + performance with explicit sign and unit conventions; and +- exact engine, adapter, configuration, artifact, and software provenance. + +Current p-v and T-s plots connect emitted sampled states only within their +existing visualization contract. They cannot be relabeled as cycle diagrams. +Cycle visualization requires an ordered process topology and states accepted +through a new typed result contract. + +### Simulation-engine candidates + +- **TESPy** is the strongest first Python adapter candidate. Its MIT license and + Python workflow fit Carnopy's optional-adapter boundary, and it covers power + plants, heat pumps, refrigeration systems, Rankine and gas-turbine cycles, + exergy analysis, and property-diagram integration. +- **pyCycle** is a later candidate for jet-engine and propulsion cycle studies + through the OpenMDAO ecosystem. +- **Cantera** is a later candidate for reacting thermodynamics and reactor + networks rather than ordinary nonreacting property tables. +- **IDAES** is a later candidate for full process flowsheets and optimization + when a use case needs that broader process-modeling scope. + +Each adapter must remain optional and worker-owned. Carnopy configuration and +results should not expose mutable engine objects as public scientific state. + +## Visualization direction + +Future views should remain projections of verified imported or generated +artifacts. Candidate views include: + +- temperature-composition (T-x-y), pressure-composition (P-x-y), and + liquid-vapor composition (x-y) diagrams; +- binary and ternary composition views; +- bubble, dew, critical, and phase envelopes; +- model-to-reference parity, residual, and uncertainty plots; +- residual surfaces over temperature, pressure, composition, and phase; +- validity-domain and source-coverage maps; +- T-s, p-h, h-s, and p-v cycle diagrams based on ordered cycle results; +- component energy, entropy, and exergy views; +- sensitivity and working-fluid comparisons; +- Preparation partition, coverage, and leakage-diagnostic views; and +- imported ML prediction parity, residual, error-domain, learning-curve, and + uncertainty-calibration views. + +Visualization must preserve missing data, phase boundaries, uncertainty, +source identity, and failures. Interpolation, smoothing, derived envelopes, or +topological paths require an explicit scientific contract and must never be +introduced as presentation-only conveniences. + +## Relationship to ML Preparation + +Future source, mixture, and cycle outputs should expose machine-readable +coordinates, properties, units, compositions, phases, domain masks, +derivatives or constraints when genuinely available, and complete provenance. +Preparation can then consume those verified fields without calling the +originating scientific backend. Framework adapters, prediction-result imports, +metrics, and result visualization are detailed in +[`ML_PREPARATION_ROADMAP.md`](ML_PREPARATION_ROADMAP.md). + +## Primary references for candidate evaluation + +- IUPAC, [ThermoML](https://iupac.org/what-we-do/digital-standards/thermoml/). +- NIST Thermodynamics Research Center, + [ThermoML](https://www.nist.gov/mml/acmd/trc/thermoml) and the + [ThermoML Archive](https://www.nist.gov/mml/acmd/trc/thermoml/thermoml-archive). +- CoolProp, [Mixtures](https://coolprop.org/fluid_properties/Mixtures.html) and + [Backends](https://coolprop.org/develop/backends.html). +- NIST, [REFPROP](https://www.nist.gov/programs-projects/reference-fluid-thermodynamic-and-transport-properties-database-refprop). +- ThermoPack, [documentation](https://thermotools.github.io/thermopack/vcurrent/method_docs.html) + and [source repository](https://github.com/thermotools/thermopack). +- NIST, [teqp documentation](https://pages.nist.gov/teqp-docs/en/stable/index.html). +- `thermo`, [activity-coefficient models](https://thermo.readthedocs.io/activity_coefficients.html) + and [phase and flash workflows](https://thermo.readthedocs.io/tutorial_phases_and_flash.html). +- USGS PHREEQC, [Pitzer model documentation](https://water.usgs.gov/water-resources/software/PHREEQC/documentation/phreeqc3-html/phreeqc3-37.htm). +- TESPy, [documentation](https://tespy.readthedocs.io/en/main/documentation.html) + and [source repository](https://github.com/oemof/tespy). +- OpenMDAO, [pyCycle](https://github.com/openmdao/pycycle). +- Cantera, [reactor networks](https://cantera.org/stable/reference/reactors/index.html). +- IDAES, [process systems engineering framework](https://idaes.org/software/). diff --git a/docs/agent-guides/SCIENTIFIC_CONTRACTS.md b/docs/agent-guides/SCIENTIFIC_CONTRACTS.md index 6b0b818..94c33ff 100644 --- a/docs/agent-guides/SCIENTIFIC_CONTRACTS.md +++ b/docs/agent-guides/SCIENTIFIC_CONTRACTS.md @@ -53,10 +53,11 @@ Milestone 1 supports: - configured post-generation visualization; - model-sweep bundles comparing emitted values from multiple CoolProp models. -The `0.1.0a3` release line established a Linux-first PySide6 Widgets frontend -for the existing dataset workflow. Current `0.1.0a4` source has migrated -those accepted workflows into one QML application and removed the duplicate -Widgets presentation. The desktop application remains a presentation frontend, +The `0.1.0a3` release established a Linux-first PySide6 Widgets frontend, and +`0.1.0a4` migrated the accepted workflows into one QML application while +removing the duplicate Widgets presentation. Current `0.1.0a5` source also +exposes structured Model Sweep and ML Preparation workflows plus direct +post-generation session plotting. The desktop remains a presentation frontend, not a new scientific execution layer. Its permanent boundary includes the private worker protocol, workspace lifecycle, worker-validated configuration, saved-config execution, private activity and guarded staging recovery, @@ -82,9 +83,12 @@ Outside the current implemented contract: - web/API services or databases; - ThermoML, OCR, RAG, or literature mining. -The product-scope document distinguishes planned, research, and external work. -Do not interpret those classifications as implementation authority or broaden -this contract without maintainer approval. +[`THERMOPHYSICAL_ROADMAP.md`](../../THERMOPHYSICAL_ROADMAP.md) records public +source, mixture, model, backend, cycle, and visualization candidates. +[`ML_PREPARATION_ROADMAP.md`](../../ML_PREPARATION_ROADMAP.md) records current +Preparation behavior and future interoperability and evaluation directions. +Roadmap classifications are not implementation authority. Do not broaden this +contract without a separately approved stage and maintainer acceptance. ## Public interfaces diff --git a/docs/archive/GUI2_STAGE2.md b/docs/archive/GUI2_STAGE2.md index 9ba2b9c..5dc8222 100644 --- a/docs/archive/GUI2_STAGE2.md +++ b/docs/archive/GUI2_STAGE2.md @@ -27,10 +27,9 @@ regression: git show e3550b244d2ac05d0a33cb37875c98c0cb49c7c5:GUI2_PLAN.md ``` -The approved visual reference remains tracked at -[`docs/assets/gui2-stage2-dataset-dark.png`](../assets/gui2-stage2-dataset-dark.png) -with SHA-256 -`d6b0ed719218be659ad5d2b940f1f11eab61802d641b4896dee9b96084ad8d48`. +The historical Stage 2 capture was superseded after QML parity and is no longer +retained in the active screenshot inventory. The current accepted Dataset +capture is [`docs/assets/carnopy-dataset-workbench-dark.png`](../assets/carnopy-dataset-workbench-dark.png). This archive is deliberately not part of the mandatory startup-reading route. Completed-stage implementation detail must not consume every active Stage 3 diff --git a/docs/assets/carnopy-dataset-workbench-dark.png b/docs/assets/carnopy-dataset-workbench-dark.png index cfacedd..73ce00b 100644 Binary files a/docs/assets/carnopy-dataset-workbench-dark.png and b/docs/assets/carnopy-dataset-workbench-dark.png differ diff --git a/docs/assets/carnopy-mlprep-dark.png b/docs/assets/carnopy-mlprep-dark.png index c9c555d..04fdcd2 100644 Binary files a/docs/assets/carnopy-mlprep-dark.png and b/docs/assets/carnopy-mlprep-dark.png differ diff --git a/docs/assets/gui2-stage2-dataset-dark.png b/docs/assets/gui2-stage2-dataset-dark.png deleted file mode 100644 index 462a38b..0000000 Binary files a/docs/assets/gui2-stage2-dataset-dark.png and /dev/null differ diff --git a/docs/releases/v0.1.0a5.md b/docs/releases/v0.1.0a5.md new file mode 100644 index 0000000..cc46e76 --- /dev/null +++ b/docs/releases/v0.1.0a5.md @@ -0,0 +1,39 @@ +# Carnopy v0.1.0a5 + +Carnopy `0.1.0a5` expands the QML desktop from dataset parity into a complete +scientific workbench for generation, comparison, visualization, and +leakage-aware preparation. + +## Highlights + +- Added structured **Model Sweeps** and **ML Preparation** workflows with + worker-verified planning, controlled execution, cancellation, immutable + results, exact source binding, and preparation audit evidence. +- Made plotting a direct continuation of generation: **Create plot from this + run** inspects the exact finalized output and opens a compatible editable + request; rendering remains explicit. +- Added a custom cross-platform desktop frame with native move, resize, + minimize, maximize/restore, snapping where supported, persisted geometry, + and guarded close behavior. +- Improved WSLg/XCB startup and workflow lifecycle resilience, including stale + response rejection, shutdown sequencing, queued QML actions, and maximized + title-drag restoration. +- Refined Dataset and Preparation presentation, including sampler spacing and + deterministic Train → Validation → Test summaries. +- Clarified the bounded current-alpha scope and published separate + thermophysical, simulation, and ML interoperability roadmaps for future + scientific development. + +Carnopy remains alpha software. This release retains the existing public YAML, +CLI, Python, immutable-output, provenance, and scientific validation contracts. +CoolProp pure-fluid generation with HEOS, PR, and SRK remains the implemented +backend boundary; native 3D is not included. + +Install the desktop application with: + +```bash +uv tool install "carnopy[app]==0.1.0a5" +carnopy-gui +``` + +[Compare changes](https://github.com/gcalpay/carnopy/compare/v0.1.0a4...v0.1.0a5) diff --git a/native/carnopy-vtk-bridge/pyproject.toml b/native/carnopy-vtk-bridge/pyproject.toml index 9509bfa..8c46b5b 100644 --- a/native/carnopy-vtk-bridge/pyproject.toml +++ b/native/carnopy-vtk-bridge/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "scikit_build_core.build" [project] name = "carnopy-vtk-bridge" -version = "0.1.0a4" +version = "0.1.0a5" description = "Private native QML and VTK qualification bridge for Carnopy" readme = "README.md" requires-python = ">=3.12,<3.13" diff --git a/native/carnopy-vtk-bridge/src/carnopy_vtk_bridge/__init__.py b/native/carnopy-vtk-bridge/src/carnopy_vtk_bridge/__init__.py index 0316ca8..ea01838 100644 --- a/native/carnopy-vtk-bridge/src/carnopy_vtk_bridge/__init__.py +++ b/native/carnopy-vtk-bridge/src/carnopy_vtk_bridge/__init__.py @@ -20,7 +20,7 @@ del _module, _native, import_module -__version__ = "0.1.0a4" +__version__ = "0.1.0a5" __all__ = ( "__version__", "live_instances", diff --git a/native/carnopy-vtk-bridge/tests/qualification.py b/native/carnopy-vtk-bridge/tests/qualification.py index 4b8c207..e631142 100644 --- a/native/carnopy-vtk-bridge/tests/qualification.py +++ b/native/carnopy-vtk-bridge/tests/qualification.py @@ -15,7 +15,7 @@ from types import ModuleType NAME = "carnopy-vtk-bridge" -VERSION = "0.1.0a4" +VERSION = "0.1.0a5" PACKAGE = "carnopy_vtk_bridge" UNSET_ENVIRONMENT_VARIABLES = ( "CMAKE_ARGS", diff --git a/pyproject.toml b/pyproject.toml index 221b41d..0686d1c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -127,6 +127,7 @@ include = [ "/LICENSE", "/ML_PREPARATION_ROADMAP.md", "/README.md", + "/THERMOPHYSICAL_ROADMAP.md", "/configs", "/pyproject.toml", "/scripts", diff --git a/scripts/check_distribution.py b/scripts/check_distribution.py index c53962f..9717ba1 100644 --- a/scripts/check_distribution.py +++ b/scripts/check_distribution.py @@ -227,6 +227,7 @@ "LICENSE", "ML_PREPARATION_ROADMAP.md", "README.md", + "THERMOPHYSICAL_ROADMAP.md", "configs/model_sweep_example.yaml", "configs/property_table_example.yaml", "configs/saturation_table_example.yaml", @@ -340,6 +341,7 @@ "docs/agent-guides/SCIENTIFIC_CONTRACTS.md", "ML_PREPARATION_ROADMAP.md", "README.md", + "THERMOPHYSICAL_ROADMAP.md", } FORBIDDEN_ANYWHERE = { ".mypy_cache", diff --git a/src/carnopy/_version.py b/src/carnopy/_version.py index b0548b6..0a0820d 100644 --- a/src/carnopy/_version.py +++ b/src/carnopy/_version.py @@ -1 +1 @@ -__version__ = "0.1.0a4" +__version__ = "0.1.0a5" diff --git a/src/carnopy/app/preparation_draft.py b/src/carnopy/app/preparation_draft.py index 23dca1b..ed86789 100644 --- a/src/carnopy/app/preparation_draft.py +++ b/src/carnopy/app/preparation_draft.py @@ -20,7 +20,7 @@ PREPARATION_SOURCE_POLICY, PREPARATION_TARGETS, ) -from carnopy.app.scenario_draft import ScenarioDraft +from carnopy.app.scenario_draft import PARTITIONS, ScenarioDraft from carnopy.app.workflow_models import WorkflowListModel DERIVED_FEATURES = ( @@ -1436,8 +1436,14 @@ def _scenario_summary(value: Mapping[str, object]) -> str: if kind == "unsplit": details.append("All partition") elif isinstance(partitions, Mapping): + ordered_partitions = sorted( + partitions.items(), + key=lambda item: ( + PARTITIONS.index(str(item[0])) if str(item[0]) in PARTITIONS else len(PARTITIONS) + ), + ) details.extend( - f"{_display(str(name))} {_percentage(ratio)}" for name, ratio in partitions.items() + f"{_display(str(name))} {_percentage(ratio)}" for name, ratio in ordered_partitions ) holdouts = value.get("holdouts") if isinstance(holdouts, Mapping) and holdouts: diff --git a/src/carnopy/app/qml/Carnopy/components/SamplerEditor.qml b/src/carnopy/app/qml/Carnopy/components/SamplerEditor.qml index c535f09..3d8a60d 100644 --- a/src/carnopy/app/qml/Carnopy/components/SamplerEditor.qml +++ b/src/carnopy/app/qml/Carnopy/components/SamplerEditor.qml @@ -355,21 +355,16 @@ Card { } Label { - Accessible.name: root.draft.kind === "linspace" ? root.draft.axis + qsTr( - " derived spacing and interval count") : - root.draft.axis + qsTr( - " derived interval and point count") + Accessible.name: root.draft.axis + qsTr(" derived spacing and interval count") Layout.fillWidth: true color: Theme.success font.family: Theme.monoFamily font.pixelSize: 11 objectName: "samplerDerived-" + String(root.draft.axis) - text: root.draft.kind === "linspace" ? qsTr("Spacing %1 %2 · %3 intervals").arg( - root.draft.spacingText).arg(root.draft.unit).arg( - root.draft.intervalCount) : qsTr( - "%1 intervals · %2 sampled points").arg( - root.draft.intervalCount).arg( - root.draft.sampleCount) + text: qsTr("Spacing %1 %2 · %3 intervals").arg(root.draft.kind === "linspace" + ? root.draft.spacingText : + stepField.text).arg(root.draft.unit).arg( + root.draft.intervalCount) visible: root.draft.valid && (root.draft.kind === "linspace" || root.draft.kind === "stepspace") wrapMode: Text.Wrap diff --git a/src/carnopy/app/qml/Carnopy/pages/DatasetPage.qml b/src/carnopy/app/qml/Carnopy/pages/DatasetPage.qml index 0e9a6ee..b8939a6 100644 --- a/src/carnopy/app/qml/Carnopy/pages/DatasetPage.qml +++ b/src/carnopy/app/qml/Carnopy/pages/DatasetPage.qml @@ -182,28 +182,13 @@ Item { Layout.fillWidth: true spacing: Theme.spacingMedium - ColumnLayout { + Label { Layout.fillWidth: true - spacing: 3 - - Label { - Layout.fillWidth: true - color: Theme.text - font.family: Theme.sansFamily - font.pixelSize: 23 - font.weight: Font.DemiBold - text: qsTr("Dataset configuration") - } - - Label { - Layout.fillWidth: true - color: Theme.textMuted - font.family: Theme.sansFamily - font.pixelSize: 12 - text: qsTr( - "Define reproducible thermophysical sampling and emitted columns.") - wrapMode: Text.Wrap - } + color: Theme.text + font.family: Theme.sansFamily + font.pixelSize: 23 + font.weight: Font.DemiBold + text: qsTr("Dataset configuration") } StatusBadge { @@ -261,7 +246,7 @@ Item { valueRole: "value" ToolTip.text: qsTr( - "CoolProp is the only scientific backend supported in Carnopy 0.1.0a4.") + "CoolProp is the only scientific backend supported in Carnopy 0.1.0a5.") ToolTip.visible: hovered } diff --git a/src/carnopy/app/qml/Carnopy/pages/HelpPage.qml b/src/carnopy/app/qml/Carnopy/pages/HelpPage.qml index eb7b160..2407548 100644 --- a/src/carnopy/app/qml/Carnopy/pages/HelpPage.qml +++ b/src/carnopy/app/qml/Carnopy/pages/HelpPage.qml @@ -48,7 +48,7 @@ Item { color: Theme.textMuted font.family: Theme.sansFamily font.pixelSize: 13 - text: qsTr("Workflow boundaries, keyboard access, and validation authority.") + text: qsTr("Core workflows, validation authority, and keyboard access.") wrapMode: Text.Wrap } } @@ -60,43 +60,57 @@ Item { Card { Layout.fillWidth: true subtitle: qsTr( - "Use Ctrl+B to toggle the wide rail, Ctrl+I for the inspector, Ctrl+, for Settings, F1 for Help, and Escape to dismiss transient drawers.") - title: qsTr("Keyboard") + "Create or open a workspace, create a Dataset configuration, Save it, then use Run to Generate the exact saved snapshot.") + title: qsTr("Generate a dataset") } Card { Layout.fillWidth: true subtitle: qsTr( - "Local draft checks provide immediate guidance. Worker validation remains authoritative before any configuration is written.") - title: qsTr("Validation") + "After Generate succeeds, Create plot from this run inspects the exact output and opens a compatible editable request. Rendering starts only when Render plot is pressed.") + title: qsTr("Plot generated data") } Card { Layout.fillWidth: true subtitle: qsTr( - "CoolProp, generation, pandas, PyArrow, Matplotlib, and rendering remain outside the QML process and execute through the private worker boundary.") - title: qsTr("Scientific isolation") + "Automate future plots stores plot definitions in YAML. Changes apply only to a later Generate and never add figures to an existing run.") + title: qsTr("Automate future plots") } Card { Layout.fillWidth: true subtitle: qsTr( - "Carnopy operates on local workspaces. The QML shell does not add a web service, cloud database, or telemetry path.") - title: qsTr("Local data") + "Inspect an eligible finalized source, choose Use for ML Preparation, then continue to configure, Save, Plan, Execute, and inspect the immutable result.") + title: qsTr("Prepare data for ML") + } + + Card { + Layout.fillWidth: true + subtitle: qsTr( + "Local draft checks provide immediate guidance. Fresh worker validation remains authoritative before Save, Generate, Plan, Execute, inspection, or rendering at their established boundaries.") + title: qsTr("Validation") } Card { Layout.fillWidth: true subtitle: qsTr( - "Stage 2 provides bounded QML startup and interaction smoke coverage. Full Windows, macOS, Linux, packaging, and release qualification remains a Stage 8 gate.") - title: qsTr("Qualification status") + "CoolProp, generation, pandas, PyArrow, Matplotlib, and rendering remain outside the QML process and execute through the private worker boundary.") + title: qsTr("Scientific isolation") } Card { Layout.fillWidth: true subtitle: qsTr( - "Unavailable navigation entries name their planned stage and remain outside keyboard focus until their authoritative controllers are bound.") - title: qsTr("Migration status") + "Carnopy operates on local workspaces. The desktop adds no web service, cloud database, or telemetry path.") + title: qsTr("Local data") + } + + Card { + Layout.fillWidth: true + subtitle: qsTr( + "Use Ctrl+B to toggle the wide rail, Ctrl+I for the inspector, Ctrl+, for Settings, F1 for Help, and Escape to dismiss transient drawers.") + title: qsTr("Keyboard") } } } diff --git a/tests/test_app_preparation_draft.py b/tests/test_app_preparation_draft.py index 7a306b2..36687a7 100644 --- a/tests/test_app_preparation_draft.py +++ b/tests/test_app_preparation_draft.py @@ -282,7 +282,7 @@ def test_committed_scenarios_round_trip_with_concise_ordered_summaries() -> None "name": "random", "kind": "shuffle", "seed": 42, - "partitions": {"train": 0.8, "test": 0.2}, + "partitions": {"test": 0.15, "train": 0.7, "validation": 0.15}, }, { "name": "fluid-test", @@ -301,7 +301,7 @@ def test_committed_scenarios_round_trip_with_concise_ordered_summaries() -> None { "name": "random", "kind": "shuffle", - "summary": "Shuffle · Train 80% · Test 20% · Seed 42", + "summary": ("Shuffle · Train 70% · Validation 15% · Test 15% · Seed 42"), }, { "name": "fluid-test", diff --git a/tests/test_app_qml_dataset.py b/tests/test_app_qml_dataset.py index 5264c2d..46e9c9b 100644 --- a/tests/test_app_qml_dataset.py +++ b/tests/test_app_qml_dataset.py @@ -497,12 +497,24 @@ def test_sampler_qml_distinguishes_points_intervals_and_spacing( _process_events() temperature = runtime.controller.dataset_draft.sampler("temperature") + pressure = runtime.controller.dataset_draft.sampler("pressure") assert temperature is not None + assert pressure is not None derived = _visual_item(root, "samplerDerived-temperature") + pressure_derived = _visual_item(root, "samplerDerived-pressure") assert derived.property("visible") is True assert derived.property("text") == "Spacing 1 degC · 100 intervals" + pressure.set_kind("stepspace") + pressure.set_text("start", "100000") + pressure.set_text("stop", "500000") + pressure.set_text("step", "1000") + _process_events() + assert pressure.text("step") == "1000" + assert pressure.get_interval_count() == 400 + assert pressure_derived.property("text") == "Spacing 1000 Pa · 400 intervals" + temperature.set_text("num", "100") _process_events() assert derived.property("text") == ("Spacing 1.01010101010101 degC · 99 intervals") @@ -510,7 +522,7 @@ def test_sampler_qml_distinguishes_points_intervals_and_spacing( temperature.set_kind("stepspace") temperature.set_text("step", "1") _process_events() - assert derived.property("text") == "100 intervals · 101 sampled points" + assert derived.property("text") == "Spacing 1 degC · 100 intervals" assert runtime.warning_capture.runtime_warnings == () diff --git a/tests/test_packaging_metadata.py b/tests/test_packaging_metadata.py index 01da3a0..e6323f9 100644 --- a/tests/test_packaging_metadata.py +++ b/tests/test_packaging_metadata.py @@ -36,6 +36,7 @@ def test_desktop_extra_and_launcher_are_declared() -> None: root = Path(__file__).resolve().parents[1] pyproject: dict[str, Any] = tomllib.loads((root / "pyproject.toml").read_text(encoding="utf-8")) readme = (root / "README.md").read_text(encoding="utf-8") + normalized_readme = " ".join(readme.split()) assert pyproject["project"]["optional-dependencies"]["app"] == [ "PySide6-Essentials>=6.11.1,<6.12", @@ -47,8 +48,8 @@ def test_desktop_extra_and_launcher_are_declared() -> None: ) assert pyproject["project"]["scripts"]["carnopy-app"] == "carnopy.app.qml_launcher:main_app" assert pyproject["project"]["scripts"]["carnopy-gui"] == "carnopy.app.qml_launcher:main_gui" - assert "PySide6 Essentials 6.11.1 or later within the 6.11 release line" in readme - assert "native bridge remains qualified against exactly Qt 6.11.1" in readme + assert "PySide6 Essentials 6.11.1 or later within the 6.11 release line" in normalized_readme + assert "native bridge remains qualified against exactly Qt 6.11.1" in normalized_readme def test_qml_runtime_is_public_and_resources_live_in_the_app_package() -> None: @@ -215,7 +216,7 @@ def test_alpha_metadata_uses_modern_license_and_release_urls() -> None: assert "License :: OSI Approved :: MIT License" not in project["classifiers"] -def test_citation_metadata_matches_the_package_and_published_release() -> None: +def test_citation_metadata_matches_the_package_release_candidate() -> None: root = Path(__file__).resolve().parents[1] citation = yaml.safe_load((root / "CITATION.cff").read_text(encoding="utf-8")) pyproject = tomllib.loads((root / "pyproject.toml").read_text(encoding="utf-8")) @@ -225,8 +226,8 @@ def test_citation_metadata_matches_the_package_and_published_release() -> None: assert citation["license"] == "MIT" assert citation["repository-code"] == "https://github.com/gcalpay/carnopy" assert citation["abstract"] == pyproject["project"]["description"] - assert citation["doi"] == "10.5281/zenodo.21709965" - assert str(citation["date-released"]) == "2026-07-30" + assert "doi" not in citation + assert "date-released" not in citation assert "10.xxxx" not in json.dumps(citation) @@ -236,6 +237,7 @@ def test_public_and_community_markdown_have_intentional_distribution_boundaries( assert (root / "AGENTS.md").is_file() assert (root / "DESKTOP_ARCHITECTURE.md").is_file() assert (root / "ML_PREPARATION_ROADMAP.md").is_file() + assert (root / "THERMOPHYSICAL_ROADMAP.md").is_file() agent_guides = root / "docs" / "agent-guides" assert {path.name for path in agent_guides.glob("*.md")} == { "DELEGATION.md", @@ -255,6 +257,7 @@ def test_public_and_community_markdown_have_intentional_distribution_boundaries( assert "/CITATION.cff" in sdist_includes assert "/DESKTOP_ARCHITECTURE.md" in sdist_includes assert "/ML_PREPARATION_ROADMAP.md" in sdist_includes + assert "/THERMOPHYSICAL_ROADMAP.md" in sdist_includes assert "/PRODUCT_SCOPE.md" not in sdist_includes assert "/docs/agent-guides" in sdist_includes assert not any(path.startswith("/.github") for path in sdist_includes) @@ -268,11 +271,12 @@ def test_public_roadmap_separates_current_contracts_from_future_direction() -> N gui_plan = (root / "GUI2_PLAN.md").read_text(encoding="utf-8") desktop = (root / "DESKTOP_ARCHITECTURE.md").read_text(encoding="utf-8") - assert "workflow depth now, source breadth next, and advanced model breadth later" in ( + assert "These are current release boundaries, not the intended limit" in normalized_readme + assert "thermophysical and simulation roadmap" in normalized_readme + assert "six connected capabilities" in normalized_readme + assert "Roadmap entries are research and planning candidates, not support promises" in ( normalized_readme ) - assert "Detailed source and model candidates are maintainer planning" in normalized_readme - assert "it is neither implemented nor the current product priority" in normalized_readme assert "PRODUCT_SCOPE.md" not in readme assert "| 5 | Complete |" in gui_plan assert "| 4 | Add controlled sweep and preparation worker operations | Complete" in desktop @@ -285,25 +289,29 @@ def test_public_roadmap_separates_current_contracts_from_future_direction() -> N def test_readme_documents_published_and_source_release_boundaries() -> None: root = Path(__file__).resolve().parents[1] text = (root / "README.md").read_text(encoding="utf-8") - assert 'uv tool install "carnopy[app]==0.1.0a4"' in text - assert 'python -m pip install "carnopy==0.1.0a4"' in text - assert 'python -m pip install "carnopy[app]==0.1.0a4"' not in text + assert 'uv tool install "carnopy[app]==0.1.0a5"' in text + assert 'python -m pip install "carnopy==0.1.0a5"' in text + assert 'python -m pip install "carnopy[app]==0.1.0a5"' not in text for extra in ("app", "viz", "ml", "analysis", "all"): assert f"| `{extra}` |" in text assert "Exact union of all public extras" in text - assert "The latest published alpha is `0.1.0a4`" in text - assert "https://doi.org/10.5281/zenodo.21709965" in text + assert "The current alpha release is `0.1.0a5`" in text + assert "10.5281/zenodo.21709965" not in text + assert "docs/assets/carnopy-dataset-workbench-dark.png" in text + assert "docs/assets/carnopy-mlprep-dark.png" in text assert "kind: property_heatmap" in text assert "`carnopy-gui` is the canonical" in text - assert "`carnopy-app` launches the same\nQML application" in text + assert "`carnopy-app` is a\ncompatibility alias" in text assert "0.1.0a2" not in text assert "After `0.1.0a3` is published" not in text assert "not yet published" not in text assert "next-release" not in text - assert "uv sync --locked --extra app --group dev" in text + assert "uv sync --locked --extra app --no-dev" in text + assert "uv sync --locked --extra all --group dev --group release" in text assert "uv run --locked carnopy-gui" in text assert "0.1.0a3.dev0" not in text assert "0.1.0a4.dev0" not in text + assert "0.1.0a5.dev0" not in text assert "pending publisher" not in text.casefold() assert "Typing: typed" not in text @@ -329,8 +337,8 @@ def test_github_community_files_cover_public_reporting_paths() -> None: scientific = (issue_templates / "scientific-discrepancy.yml").read_text(encoding="utf-8") bug_report = (issue_templates / "bug-report.yml").read_text(encoding="utf-8") assert "0.1.0a3.dev0" not in bug_report - assert 'placeholder: "carnopy 0.1.0a3 or carnopy-app 0.1.0a3' in bug_report - assert 'placeholder: "Carnopy 0.1.0a3; CoolProp 8.0.0"' in scientific + assert 'placeholder: "carnopy 0.1.0a5 or carnopy-gui 0.1.0a5' in bug_report + assert 'placeholder: "Carnopy 0.1.0a5; CoolProp 8.0.0"' in scientific assert "private vulnerability" in security.casefold() assert "gc@carnopy.org" in security assert "Contributor Covenant, version 2.1" in conduct diff --git a/tests/test_release_tools.py b/tests/test_release_tools.py index 55721f5..24aa9a1 100644 --- a/tests/test_release_tools.py +++ b/tests/test_release_tools.py @@ -18,7 +18,7 @@ ROOT = Path(__file__).resolve().parents[1] BRIDGE_ROOT = ROOT / "native" / "carnopy-vtk-bridge" FIXTURE_VERSION = "1.2.3" -GUI2_RELEASE_VERSION = "0.1.0a4" +GUI2_RELEASE_VERSION = "0.1.0a5" def load_script(name: str) -> ModuleType: @@ -265,6 +265,7 @@ def test_distribution_checker_requires_model_sweep_artifacts() -> None: assert { "DESKTOP_ARCHITECTURE.md", "ML_PREPARATION_ROADMAP.md", + "THERMOPHYSICAL_ROADMAP.md", "configs/model_sweep_example.yaml", "scripts/check_qml.py", "src/carnopy/_execution.py",