carnopy 0.1.0a1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. carnopy-0.1.0a1/.gitignore +34 -0
  2. carnopy-0.1.0a1/AGENTS.md +523 -0
  3. carnopy-0.1.0a1/LICENSE +21 -0
  4. carnopy-0.1.0a1/PKG-INFO +826 -0
  5. carnopy-0.1.0a1/README.md +795 -0
  6. carnopy-0.1.0a1/configs/cyclopentane_vapor_fraction_pressure.yaml +28 -0
  7. carnopy-0.1.0a1/configs/property_table_example.yaml +34 -0
  8. carnopy-0.1.0a1/configs/saturation_table_example.yaml +25 -0
  9. carnopy-0.1.0a1/configs/vapor_mass_fraction_table_example.yaml +31 -0
  10. carnopy-0.1.0a1/pyproject.toml +126 -0
  11. carnopy-0.1.0a1/scripts/__init__.py +1 -0
  12. carnopy-0.1.0a1/scripts/check_distribution.py +288 -0
  13. carnopy-0.1.0a1/scripts/hash_distributions.py +40 -0
  14. carnopy-0.1.0a1/scripts/preflight.py +62 -0
  15. carnopy-0.1.0a1/scripts/smoke_installed.py +198 -0
  16. carnopy-0.1.0a1/scripts/verify_index_release.py +189 -0
  17. carnopy-0.1.0a1/src/carnopy/__init__.py +59 -0
  18. carnopy-0.1.0a1/src/carnopy/__main__.py +9 -0
  19. carnopy-0.1.0a1/src/carnopy/_version.py +1 -0
  20. carnopy-0.1.0a1/src/carnopy/api.py +30 -0
  21. carnopy-0.1.0a1/src/carnopy/backends/__init__.py +29 -0
  22. carnopy-0.1.0a1/src/carnopy/backends/base.py +42 -0
  23. carnopy-0.1.0a1/src/carnopy/backends/coolprop.py +109 -0
  24. carnopy-0.1.0a1/src/carnopy/cli.py +517 -0
  25. carnopy-0.1.0a1/src/carnopy/config/__init__.py +18 -0
  26. carnopy-0.1.0a1/src/carnopy/config/io.py +37 -0
  27. carnopy-0.1.0a1/src/carnopy/config/models.py +99 -0
  28. carnopy-0.1.0a1/src/carnopy/config/normalize.py +115 -0
  29. carnopy-0.1.0a1/src/carnopy/config/outputs.py +28 -0
  30. carnopy-0.1.0a1/src/carnopy/config/visualization.py +81 -0
  31. carnopy-0.1.0a1/src/carnopy/domain/__init__.py +3 -0
  32. carnopy-0.1.0a1/src/carnopy/domain/failures.py +58 -0
  33. carnopy-0.1.0a1/src/carnopy/domain/phases.py +19 -0
  34. carnopy-0.1.0a1/src/carnopy/domain/properties.py +151 -0
  35. carnopy-0.1.0a1/src/carnopy/domain/units.py +75 -0
  36. carnopy-0.1.0a1/src/carnopy/generation/__init__.py +11 -0
  37. carnopy-0.1.0a1/src/carnopy/generation/common.py +219 -0
  38. carnopy-0.1.0a1/src/carnopy/generation/property_table.py +57 -0
  39. carnopy-0.1.0a1/src/carnopy/generation/saturation_table.py +127 -0
  40. carnopy-0.1.0a1/src/carnopy/generation/vapor_mass_fraction_table.py +99 -0
  41. carnopy-0.1.0a1/src/carnopy/outputs/__init__.py +27 -0
  42. carnopy-0.1.0a1/src/carnopy/outputs/layout.py +62 -0
  43. carnopy-0.1.0a1/src/carnopy/outputs/metadata.py +117 -0
  44. carnopy-0.1.0a1/src/carnopy/outputs/reports.py +68 -0
  45. carnopy-0.1.0a1/src/carnopy/outputs/schemas.py +56 -0
  46. carnopy-0.1.0a1/src/carnopy/outputs/writers.py +90 -0
  47. carnopy-0.1.0a1/src/carnopy/pipeline.py +234 -0
  48. carnopy-0.1.0a1/src/carnopy/provenance.py +93 -0
  49. carnopy-0.1.0a1/src/carnopy/py.typed +1 -0
  50. carnopy-0.1.0a1/src/carnopy/results.py +53 -0
  51. carnopy-0.1.0a1/src/carnopy/sampling/__init__.py +4 -0
  52. carnopy-0.1.0a1/src/carnopy/sampling/generate.py +57 -0
  53. carnopy-0.1.0a1/src/carnopy/sampling/models.py +98 -0
  54. carnopy-0.1.0a1/src/carnopy/templates/__init__.py +80 -0
  55. carnopy-0.1.0a1/src/carnopy/templates/property_table.yaml +34 -0
  56. carnopy-0.1.0a1/src/carnopy/templates/saturation_table.yaml +25 -0
  57. carnopy-0.1.0a1/src/carnopy/templates/vapor_mass_fraction_table.yaml +31 -0
  58. carnopy-0.1.0a1/src/carnopy/visualization/__init__.py +72 -0
  59. carnopy-0.1.0a1/src/carnopy/visualization/automation.py +272 -0
  60. carnopy-0.1.0a1/src/carnopy/visualization/config_io.py +29 -0
  61. carnopy-0.1.0a1/src/carnopy/visualization/configuration.py +326 -0
  62. carnopy-0.1.0a1/src/carnopy/visualization/curves.py +368 -0
  63. carnopy-0.1.0a1/src/carnopy/visualization/diagrams.py +157 -0
  64. carnopy-0.1.0a1/src/carnopy/visualization/export.py +307 -0
  65. carnopy-0.1.0a1/src/carnopy/visualization/fields.py +191 -0
  66. carnopy-0.1.0a1/src/carnopy/visualization/heatmaps.py +244 -0
  67. carnopy-0.1.0a1/src/carnopy/visualization/inspect.py +205 -0
  68. carnopy-0.1.0a1/src/carnopy/visualization/io.py +261 -0
  69. carnopy-0.1.0a1/src/carnopy/visualization/models.py +75 -0
  70. carnopy-0.1.0a1/src/carnopy/visualization/plots.py +652 -0
  71. carnopy-0.1.0a1/src/carnopy/visualization/render.py +108 -0
  72. carnopy-0.1.0a1/src/carnopy/visualization/requests.py +295 -0
  73. carnopy-0.1.0a1/src/carnopy/visualization/selection.py +288 -0
  74. carnopy-0.1.0a1/src/carnopy/visualization/series.py +331 -0
  75. carnopy-0.1.0a1/src/carnopy/visualization/xy.py +201 -0
  76. carnopy-0.1.0a1/tests/conftest.py +23 -0
  77. carnopy-0.1.0a1/tests/fixtures/property_table.yaml +16 -0
  78. carnopy-0.1.0a1/tests/fixtures/saturation_table.yaml +12 -0
  79. carnopy-0.1.0a1/tests/fixtures/vapor_mass_fraction_table.yaml +16 -0
  80. carnopy-0.1.0a1/tests/test_api.py +32 -0
  81. carnopy-0.1.0a1/tests/test_backend.py +31 -0
  82. carnopy-0.1.0a1/tests/test_cli.py +457 -0
  83. carnopy-0.1.0a1/tests/test_config.py +117 -0
  84. carnopy-0.1.0a1/tests/test_outputs.py +175 -0
  85. carnopy-0.1.0a1/tests/test_packaging_metadata.py +87 -0
  86. carnopy-0.1.0a1/tests/test_plot_inspect_batch.py +389 -0
  87. carnopy-0.1.0a1/tests/test_properties.py +33 -0
  88. carnopy-0.1.0a1/tests/test_property_table.py +41 -0
  89. carnopy-0.1.0a1/tests/test_provenance.py +64 -0
  90. carnopy-0.1.0a1/tests/test_release_tools.py +149 -0
  91. carnopy-0.1.0a1/tests/test_sampling.py +39 -0
  92. carnopy-0.1.0a1/tests/test_saturation_table.py +42 -0
  93. carnopy-0.1.0a1/tests/test_scientific_regressions.py +281 -0
  94. carnopy-0.1.0a1/tests/test_templates.py +63 -0
  95. carnopy-0.1.0a1/tests/test_units.py +19 -0
  96. carnopy-0.1.0a1/tests/test_vapor_mass_fraction_table.py +41 -0
  97. carnopy-0.1.0a1/tests/test_visualization_automation.py +353 -0
  98. carnopy-0.1.0a1/tests/test_visualization_diagrams.py +429 -0
  99. carnopy-0.1.0a1/tests/test_visualization_foundation.py +271 -0
  100. carnopy-0.1.0a1/tests/test_visualization_io.py +178 -0
  101. carnopy-0.1.0a1/tests/test_visualization_plots.py +637 -0
  102. carnopy-0.1.0a1/tests/test_workflows.py +47 -0
  103. carnopy-0.1.0a1/uv.lock +2341 -0
@@ -0,0 +1,34 @@
1
+ # Python bytecode/cache
2
+ __pycache__/
3
+ *.py[cod]
4
+
5
+ # Test/lint/type-check caches
6
+ .pytest_cache/
7
+ .ruff_cache/
8
+ .mypy_cache/
9
+
10
+ # Project virtual environments (uv uses .venv)
11
+ .venv/
12
+ venv/
13
+
14
+ # uv.lock is intentionally tracked.
15
+
16
+ # Build/package artifacts
17
+ build/
18
+ dist/
19
+ prerelease/
20
+ *.egg-info/
21
+
22
+ # Generated datasets
23
+ outputs/*
24
+ !outputs/.gitkeep
25
+
26
+ # Generated figures
27
+ figures/
28
+
29
+ # Local environment files
30
+ .env
31
+ .env.*
32
+
33
+ # Operator-specific coding-agent instructions
34
+ .agents/local.md
@@ -0,0 +1,523 @@
1
+ # Carnopy contributor and coding-agent guide
2
+
3
+ ## Authority and local instructions
4
+
5
+ This file applies to the repository root and all subdirectories unless a more
6
+ specific nested `AGENTS.md` exists.
7
+
8
+ Before inspecting, testing, or changing the repository, check this exact
9
+ repository-relative path:
10
+
11
+ ```text
12
+ <repository-root>/.agents/local.md
13
+ ```
14
+
15
+ If that file exists, read it in full before taking any other action. It is the
16
+ highest-priority repository instruction for local paths, environment selection,
17
+ allowed commands, Git authority, dependency operations, credentials, and
18
+ publication boundaries. Do not infer permission from this public file when the
19
+ local file is more restrictive.
20
+
21
+ The tracked `AGENTS.md` remains authoritative for public scientific behavior,
22
+ schemas, compatibility contracts, architecture, and contribution standards.
23
+ Local instructions may narrow operational authority but must not silently alter
24
+ those public contracts.
25
+
26
+ Canonical names:
27
+
28
+ ```text
29
+ Project: Carnopy
30
+ Repository: carnopy
31
+ Distribution: carnopy
32
+ Import package: carnopy
33
+ CLI: carnopy
34
+ ```
35
+
36
+ CoolProp is the first backend dependency, not the project identity.
37
+
38
+ Before starting an implementation stage, establish whether unrelated or
39
+ uncommitted work is present. If the tree is dirty, pause before editing,
40
+ describe the intended stage boundary, and suggest a Conventional Commit message
41
+ so separate stages are not mixed accidentally. Preserve unrelated changes.
42
+
43
+ Read-only Git commands are allowed when needed to inspect repository state or
44
+ review changes. Examples include:
45
+
46
+ ```text
47
+ git status --short
48
+ git diff
49
+ git diff --check
50
+ git log
51
+ git show
52
+ git ls-files
53
+ ```
54
+
55
+ Do not run Git commands that change repository state. Staging, committing,
56
+ amending, branching, tagging, rebasing, resetting, restoring, merging, pushing,
57
+ and changing remotes remain human-owned unless a local instruction explicitly
58
+ grants narrower authority.
59
+
60
+ Do not publish packages, create credentials, configure repository security, or
61
+ change dependency declarations without explicit maintainer authorization.
62
+
63
+ ## Purpose and scope
64
+
65
+ Carnopy generates reproducible, backend-derived synthetic thermophysical
66
+ datasets for machine-learning, surrogate-model, and engineering workflows.
67
+
68
+ Carnopy is not:
69
+
70
+ - a thermodynamic property model;
71
+ - experimental data or backend-independent ground truth;
72
+ - a process simulator;
73
+ - a machine-learning training framework.
74
+
75
+ The core workflow is:
76
+
77
+ ```text
78
+ sampling specification
79
+ → backend calls
80
+ → validation and stable diagnostics
81
+ → stable tabular schema
82
+ → CSV/Parquet
83
+ → metadata and report
84
+ → optional visualization of emitted columns
85
+ ```
86
+
87
+ Milestone 1 supports:
88
+
89
+ - CoolProp only;
90
+ - pure fluids only;
91
+ - YAML schema version 1;
92
+ - `property_table`;
93
+ - `saturation_table`;
94
+ - `vapor_mass_fraction_table`;
95
+ - deterministic sampling;
96
+ - selectable CSV and/or Parquet dataset output;
97
+ - metadata and report JSON;
98
+ - optional Matplotlib property curves, sampled heatmaps, x-y plots, and p-v/T-s
99
+ diagrams;
100
+ - configured post-generation visualization.
101
+
102
+ Out of scope:
103
+
104
+ - mixtures;
105
+ - ORC generation;
106
+ - additional property backends;
107
+ - random, Sobol, Latin-hypercube, adaptive, or active-learning sampling;
108
+ - ML training or inference;
109
+ - GUI, web/API services, or databases;
110
+ - ThermoML, OCR, RAG, or literature mining.
111
+
112
+ Do not broaden scope without maintainer approval.
113
+
114
+ ## Development workflow
115
+
116
+ Use the project-local environment and locked uv workflow described by local
117
+ instructions. `pyproject.toml` and `uv.lock` are authoritative; do not recreate
118
+ requirements files.
119
+
120
+ Normal synchronization:
121
+
122
+ ```bash
123
+ uv sync --locked --extra all --group dev
124
+ ```
125
+
126
+ Release tooling:
127
+
128
+ ```bash
129
+ uv sync --locked --extra all --group dev --group release
130
+ ```
131
+
132
+ Required quality gate:
133
+
134
+ ```bash
135
+ uv lock --check
136
+ uv run --locked ruff check .
137
+ uv run --locked ruff format --check .
138
+ uv run --locked mypy src/carnopy
139
+ uv run --locked pytest
140
+ uv run --locked python scripts/preflight.py
141
+ uv pip check --python .venv/bin/python
142
+ ```
143
+
144
+ If a required command or dependency is unavailable, preserve the exact failure
145
+ and ask before installing, upgrading, or substituting anything.
146
+
147
+ Use:
148
+
149
+ - `rg` for searches;
150
+ - `apply_patch` for repository file edits;
151
+ - temporary directories for generated test artifacts;
152
+ - focused tests for every behavior change.
153
+
154
+ Avoid:
155
+
156
+ - monolithic modules;
157
+ - speculative frameworks;
158
+ - heavy imports and side effects at module import time;
159
+ - brittle golden thermodynamic datasets;
160
+ - pixel-perfect figure tests.
161
+
162
+ Test count is not a target. Prefer a focused regression for each distinct
163
+ contract or failure mode, use parametrization where cases share behavior, and
164
+ remove redundant tests. The suite can still contain many tests because
165
+ configuration, scientific modes, provenance, visualization, CLI behavior,
166
+ packaging, and release tooling are separate public contracts.
167
+
168
+ Root and subcommand help must not import CoolProp, NumPy, pandas, PyArrow, or
169
+ Matplotlib.
170
+
171
+ ## Public interfaces
172
+
173
+ The public CLI is:
174
+
175
+ ```text
176
+ carnopy --version
177
+ carnopy init MODE OUTPUT [--create-parents]
178
+ carnopy properties
179
+ carnopy fluids
180
+ carnopy validate CONFIG.yaml
181
+ carnopy generate CONFIG.yaml [--out PATH] [--figures-out PATH]
182
+ carnopy inspect SOURCE
183
+ carnopy plot SOURCE ...
184
+ ```
185
+
186
+ The documented workflow is:
187
+
188
+ ```text
189
+ init → edit → optional validate → generate → inspect → optional plot
190
+ ```
191
+
192
+ Commands remain independently scriptable; do not add implicit chaining.
193
+
194
+ The supported Python API intentionally remains narrow:
195
+
196
+ - `load_config`;
197
+ - `validate_config`;
198
+ - `generate_dataset`;
199
+ - public configuration and result models;
200
+ - explicit visualization functions.
201
+
202
+ Keep CLI handlers thin and scientific logic outside `cli.py`.
203
+
204
+ ## Configuration and sampling contracts
205
+
206
+ Every configuration contains:
207
+
208
+ ```yaml
209
+ schema_version: 1
210
+ backend: coolprop
211
+ mode: property_table
212
+ fluids: [...]
213
+ grid: ...
214
+ properties: [...]
215
+ ```
216
+
217
+ Optional `outputs:` and `visualization:` sections are allowed. Dataset format
218
+ selection affects artifact-generation context but not scientific `spec_id`.
219
+ Visualization must not affect scientific or artifact-generation identity.
220
+
221
+ Dataset formats:
222
+
223
+ ```yaml
224
+ outputs:
225
+ dataset_formats: [csv, parquet]
226
+ ```
227
+
228
+ Omission defaults to both formats. At least one of `csv` or `parquet` is
229
+ required. Canonical format order is CSV then Parquet.
230
+
231
+ Public samplers:
232
+
233
+ ```text
234
+ explicit
235
+ linspace
236
+ stepspace
237
+ geomspace
238
+ logspace
239
+ ```
240
+
241
+ `stepspace` is inclusive and requires a reachable endpoint. Public `arange` is
242
+ not supported.
243
+
244
+ Supported input units:
245
+
246
+ ```text
247
+ temperature: K, degC
248
+ pressure: Pa, kPa, MPa, bar
249
+ vapor_mass_fraction: "1"
250
+ ```
251
+
252
+ All backend calls and generated numeric columns use SI. Preserve original
253
+ units and sampler declarations in metadata.
254
+
255
+ The row limit is 1,000,000 after sampler materialization, fluid
256
+ canonicalization, Cartesian expansion, and saturation endpoint expansion.
257
+
258
+ Mode contracts:
259
+
260
+ - `property_table` requires temperature and pressure;
261
+ - `saturation_table` requires exactly one of temperature or pressure and emits
262
+ separate liquid and vapor endpoint rows;
263
+ - `vapor_mass_fraction_table` requires vapor mass fraction plus exactly one of
264
+ temperature or pressure.
265
+
266
+ Public `vapor_mass_fraction` maps to CoolProp `Q` only inside the adapter.
267
+ Use \(x_{\mathrm{vap}}\) as its scientific symbol in figures and equations;
268
+ do not rename the public schema or dataset field.
269
+
270
+ ## Scientific behavior
271
+
272
+ Use the official CoolProp documentation as the backend authority:
273
+
274
+ - https://coolprop.org/coolprop/
275
+ - https://coolprop.org/coolprop/HighLevelAPI.html
276
+ - https://github.com/CoolProp/CoolProp
277
+
278
+ Reset every requested canonical fluid to CoolProp `DEF` once after validation
279
+ and before row evaluation. Do not change reference state during generation.
280
+
281
+ Specific enthalpy, entropy, and internal energy are reference-state dependent.
282
+ Absolute values are not directly comparable across different reference
283
+ conventions.
284
+
285
+ If actual CoolProp behavior contradicts an approved contract:
286
+
287
+ 1. Stop before implementing a workaround.
288
+ 2. Preserve fluid, normalized inputs, property, mode, CoolProp version,
289
+ exception type/message, and observed result.
290
+ 3. Explain the contradiction.
291
+ 4. Ask the maintainer to decide.
292
+
293
+ Do not silently change input pairs, phase rules, numerical methods, schemas, or
294
+ backend behavior.
295
+
296
+ ## Rows, validity, and failures
297
+
298
+ Every row includes:
299
+
300
+ ```text
301
+ run_id
302
+ case_id
303
+ mode
304
+ fluid
305
+ backend
306
+ backend_version
307
+ phase
308
+ backend_phase
309
+ valid
310
+ failure_layer
311
+ failure_code
312
+ failure_message
313
+ failure_property
314
+ backend_error_type
315
+ backend_error_message
316
+ ```
317
+
318
+ `case_id` is zero-based and assigned after deterministic final ordering.
319
+
320
+ Milestone 1 uses strict row validity. Any required coordinate, phase, or
321
+ requested-property failure invalidates the row. Successfully evaluated values
322
+ may remain populated; failed values remain null.
323
+
324
+ Do not infer stable failure categories by brittle parsing of backend messages.
325
+ Preserve raw backend diagnostics separately.
326
+
327
+ ## Provenance and immutable artifacts
328
+
329
+ Identity meanings:
330
+
331
+ - `spec_id`: canonical executable scientific specification;
332
+ - `generation_context_id`: artifact-generation context;
333
+ - `output_request_id`: canonical CSV/Parquet serialization request;
334
+ - `run_id`: one UUID4 generation attempt;
335
+ - artifact hashes: exact emitted bytes;
336
+ - `visualization_request_id`: normalized visualization request.
337
+
338
+ Generation writes immutable run directories containing:
339
+
340
+ ```text
341
+ dataset.csv
342
+ dataset.parquet
343
+ config.original.yaml
344
+ config.normalized.json
345
+ metadata.json
346
+ report.json
347
+ ```
348
+
349
+ Human-facing names use:
350
+
351
+ ```text
352
+ <UTC-second>_<mode-slug>_<eight-character-run-prefix>
353
+ ```
354
+
355
+ The directory name is a locator, not dataset identity.
356
+
357
+ Runs are staged and atomically renamed. Never overwrite an existing final or
358
+ staging directory. Do not add host source-config paths to metadata.
359
+
360
+ Tests use temporary directories. Do not commit generated datasets or figures.
361
+
362
+ ## Visualization contracts
363
+
364
+ Visualization is a reproducible view of emitted columns:
365
+
366
+ - never call a thermodynamic backend;
367
+ - never smooth, interpolate, extrapolate, or invent states;
368
+ - preserve invalid and missing gaps;
369
+ - derive only `specific_volume = 1 / mass_density`;
370
+ - use semantic scientific labels and units;
371
+ - keep visualization identity separate from dataset identity.
372
+
373
+ Supported kinds:
374
+
375
+ ```text
376
+ property_curves
377
+ property_heatmap
378
+ xy
379
+ pv
380
+ ts
381
+ ```
382
+
383
+ CLI spelling uses `property-curves` and `property-heatmap`.
384
+
385
+ Manual exports:
386
+
387
+ - prefer Parquet in run directories;
388
+ - fall back to CSV for CSV-only runs;
389
+ - verify recorded source hashes;
390
+ - write outside immutable source runs;
391
+ - write an image plus `.plot.json`;
392
+ - refuse existing image or sidecar paths;
393
+ - finalize using exclusive same-filesystem hard links;
394
+ - remain no-overwrite-safe but not fully two-file crash-atomic.
395
+
396
+ Configured visualization:
397
+
398
+ - validates before thermodynamic generation;
399
+ - executes after dataset finalization;
400
+ - writes under a separate figure root;
401
+ - records one `visualization-report.json`;
402
+ - preserves successful figures after another plot fails;
403
+ - never changes `config.normalized.json`, `spec_id`,
404
+ `generation_context_id`, or dataset artifact hashes.
405
+
406
+ `carnopy inspect SOURCE` reports emitted plotting capabilities without backend
407
+ calls. `carnopy plot RUN --config FILE.yaml` batch-renders a top-level
408
+ `visualization:` section against an existing immutable run. Batch rendering
409
+ must ignore scientific fields in a full generation config and validate only
410
+ against emitted run columns.
411
+
412
+ Dataset `run_status` remains solely about row validity.
413
+
414
+ ## Architecture
415
+
416
+ The high-level pipeline is:
417
+
418
+ ```text
419
+ YAML
420
+ → validated configuration
421
+ → canonical SI scientific specification
422
+ → thin backend adapter
423
+ → mode-specific rows
424
+ → stable DataFrame schema
425
+ → immutable CSV/Parquet + metadata/report
426
+ → optional emitted-column visualization
427
+ ```
428
+
429
+ The backend boundary contains only capabilities needed by current modes. It is
430
+ not a plugin framework. Add abstractions only when concrete additional backend
431
+ requirements exist.
432
+
433
+ Keep focused module boundaries:
434
+
435
+ - configuration parsing and normalization;
436
+ - semantic domain registries;
437
+ - backend adapter;
438
+ - mode generators;
439
+ - output/provenance writers;
440
+ - visualization requests, selection, rendering, and automation.
441
+
442
+ ## Packaging and release safeguards
443
+
444
+ Use the `src/` layout and Hatchling:
445
+
446
+ ```toml
447
+ [build-system]
448
+ requires = ["hatchling>=1.27.0"]
449
+ build-backend = "hatchling.build"
450
+ ```
451
+
452
+ Matplotlib remains optional through `viz`; `all` must remain synchronized with
453
+ all user-facing extras. PyArrow remains core.
454
+
455
+ The first intended public release is `0.1.0a1`. The release workflow builds one
456
+ wheel and sdist, verifies them, requires human approval, and publishes them to
457
+ production PyPI through GitHub OIDC Trusted Publishing.
458
+
459
+ Only a human maintainer may:
460
+
461
+ - make the repository public;
462
+ - configure GitHub environments or Trusted Publishers;
463
+ - create or push release tags;
464
+ - approve production deployment;
465
+ - publish to PyPI.
466
+
467
+ Never rebuild changed payloads under an uploaded version. Any changed payload
468
+ requires a new version. Never use `skip-existing` to repair a partial release.
469
+
470
+ Distribution checks:
471
+
472
+ ```bash
473
+ uv run --locked --group release python -m build
474
+ uv run --locked --group release python -m twine check dist/*
475
+ uv run --locked python scripts/check_distribution.py dist/*
476
+ ```
477
+
478
+ `python -m build` normally uses its default isolated build environment. That
479
+ environment installs the `[build-system]` requirements declared in
480
+ `pyproject.toml`. Do not modify the development environment solely to satisfy
481
+ the build backend. Use the ignored, repository-local `prerelease/` directory
482
+ for non-destructive rehearsal builds when an existing `dist/` must be
483
+ preserved. Final release artifacts belong in `dist/`. Do not write Carnopy
484
+ build artifacts outside the repository.
485
+
486
+ ## Commit messages
487
+
488
+ Use:
489
+
490
+ ```text
491
+ <type>(<scope>): <imperative summary>
492
+ ```
493
+
494
+ Rules:
495
+
496
+ - lowercase type and scope;
497
+ - imperative mood: `add`, `fix`, `validate`, `reject`, `document`;
498
+ - concise summary, ideally no more than 72 characters;
499
+ - no trailing period;
500
+ - body only when the reason or tradeoff matters.
501
+
502
+ Common types:
503
+
504
+ ```text
505
+ feat fix test docs refactor chore ci build perf style
506
+ ```
507
+
508
+ Recommended scopes:
509
+
510
+ ```text
511
+ dataset schema sampler coolprop cli validation metadata tests docs ci
512
+ packaging viz
513
+ ```
514
+
515
+ Examples:
516
+
517
+ ```text
518
+ feat(viz): add configured visualization outputs
519
+ fix(validation): reject duplicate canonical fluids
520
+ test(sampler): cover descending stepspace ranges
521
+ docs(project): consolidate public guidance
522
+ build(packaging): declare parquet runtime dependency
523
+ ```
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Göran Cem Alpay
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.