equiframe 0.12.4__py3-none-any.whl

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 (170) hide show
  1. equiframe/__init__.py +832 -0
  2. equiframe/__main__.py +3 -0
  3. equiframe/_base.py +84 -0
  4. equiframe/_cli_support.py +125 -0
  5. equiframe/_comparison_io.py +161 -0
  6. equiframe/_dataset_provenance.py +146 -0
  7. equiframe/_decimal.py +22 -0
  8. equiframe/_diff_capture.py +433 -0
  9. equiframe/_doctor.py +123 -0
  10. equiframe/_document_io.py +61 -0
  11. equiframe/_documents.py +79 -0
  12. equiframe/_duckdb_transport.py +149 -0
  13. equiframe/_error_reporting.py +52 -0
  14. equiframe/_first_use.py +102 -0
  15. equiframe/_path_compat.py +26 -0
  16. equiframe/_physical.py +133 -0
  17. equiframe/_r_review.R +308 -0
  18. equiframe/_regular_io.py +167 -0
  19. equiframe/_report_format_v1.py +298 -0
  20. equiframe/_report_io.py +591 -0
  21. equiframe/_stability_inventory.py +1421 -0
  22. equiframe/_timezones.py +257 -0
  23. equiframe/_vendor/cyclonedx/LICENSE +201 -0
  24. equiframe/_vendor/cyclonedx/PROVENANCE.md +18 -0
  25. equiframe/_vendor/cyclonedx/bom-1.6.schema.json +5673 -0
  26. equiframe/_vendor/cyclonedx/jsf-0.82.schema.json +240 -0
  27. equiframe/_vendor/cyclonedx/spdx.schema.json +712 -0
  28. equiframe/adapters.py +454 -0
  29. equiframe/assertion_types.py +122 -0
  30. equiframe/assertions.py +271 -0
  31. equiframe/benchmark.py +101 -0
  32. equiframe/bundle.py +240 -0
  33. equiframe/cli.py +693 -0
  34. equiframe/comparison.py +937 -0
  35. equiframe/comparison_report.py +660 -0
  36. equiframe/comparison_types.py +257 -0
  37. equiframe/compatibility.py +546 -0
  38. equiframe/contracts.py +879 -0
  39. equiframe/datasets.py +1301 -0
  40. equiframe/decision.py +34 -0
  41. equiframe/destinations.py +295 -0
  42. equiframe/detector_types.py +431 -0
  43. equiframe/detectors.py +389 -0
  44. equiframe/diff.py +192 -0
  45. equiframe/diff_contracts.py +523 -0
  46. equiframe/docs/adoption.md +329 -0
  47. equiframe/docs/api.md +534 -0
  48. equiframe/docs/arquitecto.md +143 -0
  49. equiframe/docs/choosing-api.md +84 -0
  50. equiframe/docs/cientifico.md +180 -0
  51. equiframe/docs/compatibility.md +254 -0
  52. equiframe/docs/contributing.md +171 -0
  53. equiframe/docs/dependencies.md +237 -0
  54. equiframe/docs/eda.md +166 -0
  55. equiframe/docs/extending.md +158 -0
  56. equiframe/docs/fast-ci.md +52 -0
  57. equiframe/docs/first-use.md +78 -0
  58. equiframe/docs/index.md +142 -0
  59. equiframe/docs/ingestion.md +145 -0
  60. equiframe/docs/inicio.md +129 -0
  61. equiframe/docs/installed-private.md +97 -0
  62. equiframe/docs/journeys.md +362 -0
  63. equiframe/docs/lectura-conversion.md +211 -0
  64. equiframe/docs/licensing.md +17 -0
  65. equiframe/docs/maintenance.md +233 -0
  66. equiframe/docs/migration-ir.md +333 -0
  67. equiframe/docs/option-audit.md +45 -0
  68. equiframe/docs/outcome-gates.md +134 -0
  69. equiframe/docs/performance.md +263 -0
  70. equiframe/docs/piloto-simulado.md +56 -0
  71. equiframe/docs/quickstart.md +156 -0
  72. equiframe/docs/r_review.md +212 -0
  73. equiframe/docs/recipes.md +248 -0
  74. equiframe/docs/releasing.md +183 -0
  75. equiframe/docs/security.md +218 -0
  76. equiframe/docs/semantics.md +274 -0
  77. equiframe/docs/sqlite-snapshots.md +262 -0
  78. equiframe/docs/universal-sources.md +49 -0
  79. equiframe/docs/universalidad-cinco-pasos.md +107 -0
  80. equiframe/docs/upgrading.md +538 -0
  81. equiframe/duckdb_capture.py +410 -0
  82. equiframe/eda/__init__.py +36 -0
  83. equiframe/eda/__main__.py +3 -0
  84. equiframe/eda/_backend.py +612 -0
  85. equiframe/eda/_inventory.py +49 -0
  86. equiframe/eda/_paths.py +49 -0
  87. equiframe/eda/_report.py +291 -0
  88. equiframe/eda/api.py +535 -0
  89. equiframe/eda/cli.py +102 -0
  90. equiframe/eda/models.py +239 -0
  91. equiframe/errors.py +83 -0
  92. equiframe/evidence.py +375 -0
  93. equiframe/examples/integrations/eda_generic.py +60 -0
  94. equiframe/examples/integrations/outcome_gates.py +94 -0
  95. equiframe/examples/integrations/sqlite_snapshot.py +246 -0
  96. equiframe/examples/integrations/sqlite_snapshot_demo.py +226 -0
  97. equiframe/examples/integrations/universal_first_use.py +296 -0
  98. equiframe/examples/journeys/README.md +31 -0
  99. equiframe/examples/journeys/__init__.py +1 -0
  100. equiframe/examples/journeys/a_pandas_refactor.py +88 -0
  101. equiframe/examples/journeys/b_native_migration.py +181 -0
  102. equiframe/examples/journeys/c_retail_etl.py +460 -0
  103. equiframe/examples/journeys/common.py +136 -0
  104. equiframe/examples/journeys/d_financial_reconciliation.py +96 -0
  105. equiframe/examples/journeys/e_telemetry.py +135 -0
  106. equiframe/examples/journeys/f_data_science_preparation.py +84 -0
  107. equiframe/examples/journeys/g_external_snapshots.py +197 -0
  108. equiframe/examples/journeys/h_portable_ci.py +129 -0
  109. equiframe/examples/journeys/requirements.lock +249 -0
  110. equiframe/examples/journeys/verify_journeys.py +117 -0
  111. equiframe/examples/load_convert_compare.py +85 -0
  112. equiframe/execution.py +355 -0
  113. equiframe/execution_types.py +177 -0
  114. equiframe/ingestion.py +744 -0
  115. equiframe/local.py +126 -0
  116. equiframe/migration/__init__.py +94 -0
  117. equiframe/migration/_physical.py +8 -0
  118. equiframe/migration/backends/_timestamp_transport.py +109 -0
  119. equiframe/migration/backends/duckdb.py +651 -0
  120. equiframe/migration/backends/duckdb_decimal.py +125 -0
  121. equiframe/migration/backends/duckdb_time.py +87 -0
  122. equiframe/migration/backends/pandas.py +544 -0
  123. equiframe/migration/backends/polars.py +915 -0
  124. equiframe/migration/backends/polars_decimal.py +231 -0
  125. equiframe/migration/io.py +198 -0
  126. equiframe/migration/ports.py +96 -0
  127. equiframe/migration/runner.py +545 -0
  128. equiframe/migration/runner_types.py +405 -0
  129. equiframe/migration/types.py +354 -0
  130. equiframe/migration/validation.py +619 -0
  131. equiframe/normalization.py +358 -0
  132. equiframe/pipeline.py +274 -0
  133. equiframe/pipeline_types.py +247 -0
  134. equiframe/ports.py +39 -0
  135. equiframe/preprocessing.py +110 -0
  136. equiframe/profile_types.py +343 -0
  137. equiframe/profiles.py +447 -0
  138. equiframe/py.typed +0 -0
  139. equiframe/r_review.py +706 -0
  140. equiframe/reduction.py +518 -0
  141. equiframe/registry.py +121 -0
  142. equiframe/report_rendering.py +366 -0
  143. equiframe/report_types.py +294 -0
  144. equiframe/reporting.py +26 -0
  145. equiframe/rule_types.py +178 -0
  146. equiframe/rules.py +819 -0
  147. equiframe/schemas/r-execution-binding-1.0.schema.json +46 -0
  148. equiframe/schemas/r-review-binding-1.0.schema.json +28 -0
  149. equiframe/schemas/r-review-options-1.0.schema.json +38 -0
  150. equiframe/schemas/r-review-result-1.0.schema.json +207 -0
  151. equiframe/schemas/reviewed-decision-1.0.schema.json +3394 -0
  152. equiframe/serialization.py +152 -0
  153. equiframe/snapshot.py +296 -0
  154. equiframe/sources.py +283 -0
  155. equiframe/tables.py +459 -0
  156. equiframe/types.py +71 -0
  157. equiframe/values.py +252 -0
  158. equiframe/verification_request.py +35 -0
  159. equiframe/verify.py +799 -0
  160. equiframe/verify_types.py +255 -0
  161. equiframe/workflow.py +510 -0
  162. equiframe/workflow_request.py +38 -0
  163. equiframe-0.12.4.dist-info/METADATA +268 -0
  164. equiframe-0.12.4.dist-info/RECORD +170 -0
  165. equiframe-0.12.4.dist-info/WHEEL +4 -0
  166. equiframe-0.12.4.dist-info/entry_points.txt +3 -0
  167. equiframe-0.12.4.dist-info/licenses/LICENSE +21 -0
  168. equiframe-0.12.4.dist-info/licenses/THIRD_PARTY_NOTICES.md +42 -0
  169. equiframe-0.12.4.dist-info/licenses/tools/cyclonedx/LICENSE +201 -0
  170. equiframe-0.12.4.dist-info/licenses/tools/cyclonedx/PROVENANCE.md +18 -0
@@ -0,0 +1,129 @@
1
+ # Empieza con EquiFrame
2
+
3
+ Para cargar archivos con pocas opciones y elegir Pandas, Polars o DuckDB,
4
+ consulta [lectura y conversión](lectura-conversion.md). La
5
+ [revisión opcional con el lenguaje R](r_review.md) permite una segunda
6
+ comparación después de reglas e Isolation Forest, conservando sus decisiones.
7
+
8
+ [Arquitecto](arquitecto.md) · [Científico](cientifico.md) · [Manual](index.md) · [Elegir API](choosing-api.md) · [Ocho recorridos](journeys.md) ·
9
+ [Semántica de referencia](semantics.md) · [Compatibilidad](compatibility.md)
10
+
11
+ EquiFrame compara resultados tabulares completos y deja evidencia para explicar
12
+ las diferencias. Puedes usarlo desde tu Python, notebook, pytest u orquestador
13
+ actual. No necesitas adoptar el benchmark ni desplegar un servicio.
14
+
15
+ Para intercambiar CSV, SQL y otras entradas conservando un contrato, usa el
16
+ [recorrido de universalidad en cinco pasos](universalidad-cinco-pasos.md).
17
+
18
+ El alcance estable objetivo es **0.12.4**. Identifica los bytes de cada artefacto
19
+ por su revisión y SHA-256. El código propio usa MIT y el propietario autorizó
20
+ preparar y publicar manualmente en TestPyPI/PyPI sujeto a los
21
+ [gates de release](releasing.md); autorización no significa publicación terminada.
22
+ La adopción humana y la aceptación científica/DW real siguen separadas y pendientes.
23
+
24
+ ## 1. Instala una copia identificada
25
+
26
+ Si prefieres ejecutar un ejemplo sin copiar código, usa
27
+ [primer uso por perfil](first-use.md): comprueba el entorno con `doctor` y ejecuta
28
+ `demo` para arquitectura SQL o preparación científica. Las guías largas siguen
29
+ disponibles para integrar tus propias tablas, contratos y tests.
30
+
31
+ Necesitas Python 3.10–3.13 y un artefacto identificado con dependencias revisadas.
32
+ Los [comandos de instalación](quickstart.md#1-install-the-artifact-you-were-given)
33
+ crean un entorno fuera del checkout y verifican que el import apunta a esa
34
+ instalación. El [kit reproducible](recipes.md) fija dependencias para
35
+ el minor seleccionado; no demuestra automáticamente compatibilidad con otro entorno.
36
+
37
+ Para este primer ejemplo basta el extra `arrow`. Para DataFrames pandas usa
38
+ `pandas`; para las ocho rutas usa `engines`. No hace falta `ml` para determinar
39
+ si una preparación de datos conservó sus filas y valores. `import equiframe`
40
+ no carga motores opcionales. La matriz [de compatibilidad](compatibility.md)
41
+ separa versiones admitidas de combinaciones realmente ejecutadas.
42
+
43
+ ## 2. Detecta una regresión sin aprender la arquitectura
44
+
45
+ Después de la instalación, guarda este script en una carpeta privada. Todos sus
46
+ datos son sintéticos. Puede repetirse: cada ejecución crea un directorio nuevo.
47
+
48
+ ```python
49
+ from pathlib import Path
50
+ from uuid import uuid4
51
+
52
+ import equiframe as ef
53
+ import pyarrow as pa
54
+
55
+ root = Path.cwd() / ("revision-" + uuid4().hex)
56
+ expected = pa.table({"id": ["A", "B"], "quantity": [10, 20]})
57
+ candidate = pa.table({"id": ["B", "A"], "quantity": [21, 10]})
58
+ result = ef.diff(candidate, expected, keys=["id"], work_dir=root / "evidence")
59
+ report = ef.write_comparison_report(result, root / "report")
60
+ print(result.state, result.complete) # different True
61
+ print(report.to_text())
62
+ print("Evidencia privada:", root)
63
+
64
+ try:
65
+ ef.assert_equivalent(result)
66
+ except ef.EquivalenceDifferentError:
67
+ print("Regresión rechazada: B tiene 21 en vez de 20")
68
+ else:
69
+ raise AssertionError("La discrepancia sintética no debe aprobarse")
70
+
71
+ corrected = ef.diff(expected, expected, keys=["id"], work_dir=root / "evidence")
72
+ ef.assert_equivalent(corrected)
73
+ print(corrected.state, corrected.complete) # equivalent True
74
+ ```
75
+
76
+ El ejemplo captura la excepción deliberada para mostrar ambas rutas. En un test
77
+ real deja que `ef.assert_equivalent(result)` falle: no captures el fallo para
78
+ continuar publicando datos. El reporte minimiza valores/nombres/rutas por defecto;
79
+ la evidencia original sigue conteniendo datos y necesita tu política de acceso.
80
+ La minimización del reporte no borra ni anonimiza las capturas originales.
81
+
82
+ ## 3. Usa cinco operaciones habituales
83
+
84
+ 1. `diff(candidate, expected)`: compara DataFrames eager/Arrow ya calculados
85
+ 2. `read_diff_contract(result)`: inspecciona la política inferida o declarada
86
+ 3. `comparison_report(result)`: explica el resultado sin escribir archivos
87
+ 4. `write_comparison_report(result, directory)`: conserva un reporte nuevo
88
+ 5. `assert_equivalent(result)`: rechaza diferencias y falta de evaluación
89
+
90
+ El esquema de referencia está a la derecha. Las claves declaradas se comprueban;
91
+ no se deduplican filas para hacerlas coincidir. Dinero usa Decimal exacto y unidad
92
+ explícita cuando el dominio la necesita. Un contrato inferido no inventa moneda,
93
+ reglas de negocio ni independencia del esperado. Consulta
94
+ [la elección de API](choosing-api.md) antes de ampliar el flujo.
95
+
96
+ ## 4. Interpreta el resultado antes de actuar
97
+
98
+ - `equivalent`: la comparación completa satisface el contrato evaluado; aún debe
99
+ satisfacer la garantía/evidencia que exige tu consumidor
100
+ - `different`: se encontraron diferencias o incumplimientos
101
+ - `not_evaluable`: no pudo establecerse el juicio requerido; también rechaza la
102
+ aceptación, incluso si una inspección terminó con `complete=True`
103
+
104
+ `bool(result)` y `assert result` se rechazan. Una ejecución `completed`, dos
105
+ motores de acuerdo, un HTML generado o un lector de integridad con salida cero
106
+ no prueban corrección de negocio. Comparar con un esperado revisado es una
107
+ comprobación adicional; los hashes acreditan bytes contra una referencia, no
108
+ la identidad del autor ni la validez humana de ese esperado.
109
+
110
+ ## 5. Continúa según tu problema
111
+
112
+ - Desarrollador: [A, regresión pandas](journeys.md), claves/duplicados y pytest
113
+ - Ingeniero: [B/C/H](journeys.md), migración nativa, ETL local y revisión portable
114
+ - Arquitecto: [G](journeys.md), [puertos](extending.md) y
115
+ [snapshot SQLite](sqlite-snapshots.md), sin dependencia del servicio real
116
+ - Científico de datos: [D/E/F](journeys.md), exactitud monetaria, telemetría y
117
+ preservación de variables; equivalencia y anomalías son preguntas distintas
118
+
119
+ Los ocho recorridos incluyen caso correcto, discrepancia y fallo/no evaluación,
120
+ con datos sintéticos, esperados literales, dependencias identificadas y aceptación
121
+ automatizada. Publicar Parquet en una carpeta local no publica el paquete ni
122
+ despliega servicios. Las [capacidades](compatibility.md) separan captura,
123
+ comparación, ejecución y migración: no extrapoles una etapa a otra.
124
+
125
+ La referencia técnica única de firmas/políticas es [API](api.md) y
126
+ [semántica](semantics.md). Este inicio es una ruta de lectura; no crea otra API ni
127
+ redefine formatos históricos. El objetivo de diagnóstico en cinco minutos y la
128
+ [adopción real](adoption.md) necesitan participantes con consentimiento y evidencia:
129
+ las ejecuciones automáticas no cuentan como pilotos humanos.
@@ -0,0 +1,97 @@
1
+ # Install identified 0.12.4 artifacts offline
2
+
3
+ [Quick start](quickstart.md) · [Compatibility](compatibility.md) · [Release policy](releasing.md)
4
+
5
+ The release target is `0.12.4` for both `equiframe` and
6
+ `equiframe-benchmark`; publication remains a separately verified step in the
7
+ [release process](releasing.md). This guide is the optional offline/local-artifact
8
+ route, not a claim that a private kit or public registry file is already available.
9
+ Historical A7 introduced the minimum-Polars expression-composition correction;
10
+ earlier alpha revisions remain in the changelog. Identify both current artifacts
11
+ by their separate wheel hashes.
12
+ The earlier 0.11.1 artifacts retain their historical identity. Match the commit and SHA-256 in the supplied receipt as well as
13
+ the version. Project-owned code is MIT; third-party notices retain their terms.
14
+ Registry ownership, upload and clean installation have their own gates; consult
15
+ the verified release status rather than installing an unrelated homonym.
16
+
17
+ ## Normal pip resolution from a private wheelhouse
18
+
19
+ Obtain the identified wheelhouse for your Python/platform and verify its closed
20
+ SHA-256 inventory through a trusted channel. A Linux wheelhouse is not a Windows
21
+ wheelhouse. A provided command does not mean that platform was executed.
22
+ Create the environment outside the source checkout. Set `WHEELHOUSE` to its real
23
+ absolute path; never use `pip install -e`, `PYTHONPATH` or source-path fallbacks.
24
+
25
+ Linux (the commands illustrate Python 3.12; select any supported 3.10–3.13
26
+ minor only with its matching wheelhouse and identified validation):
27
+
28
+ ```bash
29
+ mkdir equiframe-consumer
30
+ cd equiframe-consumer
31
+ python3.12 -m venv .venv
32
+ WHEELHOUSE=/absolute/path/reviewed-wheelhouse
33
+ .venv/bin/python -I -m pip install --no-index --find-links="$WHEELHOUSE" \
34
+ 'equiframe[engines,ml]==0.12.4' --report install-report.json
35
+ .venv/bin/python -I -m pip check
36
+ .venv/bin/python -I -c 'import equiframe, importlib.metadata, sys; print(sys.executable); print(equiframe.__file__); print(importlib.metadata.version("equiframe"))'
37
+ ```
38
+
39
+ PowerShell (requires a wheelhouse resolved for Windows x64 and that interpreter):
40
+
41
+ ```powershell
42
+ New-Item -ItemType Directory equiframe-consumer
43
+ Set-Location equiframe-consumer
44
+ py -3.12 -m venv .venv
45
+ $Wheelhouse = 'C:\authorized\wheelhouse'
46
+ .\.venv\Scripts\python.exe -I -m pip install --no-index --find-links="$Wheelhouse" 'equiframe[engines,ml]==0.12.4' --report install-report.json
47
+ .\.venv\Scripts\python.exe -I -m pip check
48
+ .\.venv\Scripts\python.exe -I -c 'import equiframe, importlib.metadata, sys; print(sys.executable); print(equiframe.__file__); print(importlib.metadata.version("equiframe"))'
49
+ ```
50
+
51
+ The imported file must be under this environment's `site-packages`. The primary
52
+ trial deliberately lets pip resolve dependencies from wheel metadata. No
53
+ `--no-deps` is used to conceal missing requirements. Base and individual extras
54
+ must be tested in separate fresh environments; base must contain no Arrow,
55
+ engines, NumPy or scikit-learn. Benchmark base intentionally includes core Arrow;
56
+ its separate extras are `engines`, `ml` and `resources`.
57
+
58
+ For the benchmark, the wheelhouse must contain its exact matching core wheel:
59
+
60
+ ```bash
61
+ .venv/bin/python -I -m pip install --no-index --find-links="$WHEELHOUSE" \
62
+ 'equiframe-benchmark[engines,ml,resources]==0.12.4' --report benchmark-install.json
63
+ .venv/bin/python -I -m pip check
64
+ ```
65
+
66
+ ## Independent reproducibility trial
67
+
68
+ Use a second fresh environment and the supplied platform-specific lock containing
69
+ exact versions and SHA-256 hashes for the candidate and every resolved runtime
70
+ dependency. Do not substitute a development lock or another Python's lock.
71
+
72
+ ```bash
73
+ python3.12 -m venv .venv-hashed
74
+ .venv-hashed/bin/python -I -m pip install --no-index --find-links="$WHEELHOUSE" \
75
+ --require-hashes -r runtime-with-candidate.lock --report hashed-install.json
76
+ .venv-hashed/bin/python -I -m pip check
77
+ ```
78
+
79
+ Hash integrity does not authenticate a publisher or establish semantic correctness.
80
+ Minimum-direct and latest-permitted resolutions have separate real locks and
81
+ receipts. They do not prove every cross-product allowed by dependency ranges.
82
+ The stable `0.12.4` pin does not require prerelease resolution. Historical alpha
83
+ artifacts retain their separate exact pins and hashes. Never change global pip
84
+ configuration or describe an offline installation as a public PyPI installation.
85
+
86
+ ## A useful comparison
87
+
88
+ Continue with the [complete quick-start comparison](quickstart.md#2-compare-two-complete-outputs):
89
+ `diff` → `write_comparison_report` → `assert_equivalent`. A finished execution,
90
+ integrity-check success or a caught expected rejection is not data acceptance.
91
+ Run the acceptance step with Python `-O` too; use `assert_equivalent`, not a Python
92
+ `assert` statement, for the gate that must survive optimization.
93
+
94
+ The independent consumer-lab application and permitted frozen real datasets are
95
+ separate artifacts. Its provenance, exact CLI, application return codes and
96
+ mutation outcomes belong to its own delivery receipt. The historical A–H
97
+ examples remain synthetic regression checks, not real-data adoption evidence.
@@ -0,0 +1,362 @@
1
+ # Eight reproducible user journeys
2
+
3
+ [Handbook](index.md) · [Quick start](quickstart.md) · [API](api.md) ·
4
+ [Semantics](semantics.md) · [External SQLite source](sqlite-snapshots.md)
5
+
6
+ **Entrada en español:** estos ocho recorridos contienen datos pequeños totalmente
7
+ sintéticos, un esperado literal independiente y casos correcto, discrepante y
8
+ fallido/no evaluable. Los comandos y criterios de aceptación están aquí como
9
+ fuente única. Un resultado `completed`, un reporte o acuerdo entre motores no
10
+ aprueba los datos. Los casos negativos deben rechazarse; ninguna prueba sustituye
11
+ revisión científica, aceptación del DW real ni un piloto con usuarios.
12
+
13
+ Each journey is a complete script using the existing APIs. They are examples,
14
+ not a second core API, framework, connector service or anomaly benchmark.
15
+ `common.py` shares only example contract construction, reports, CLI and runtime
16
+ receipts. No callbacks, models or hidden datasets are downloaded.
17
+
18
+ ## Installation outside the checkout
19
+
20
+ The commands below use an identified **0.12.4 offline wheelhouse**, with a
21
+ matching identity for the actual CPython 3.10–3.13 minor and platform. Follow
22
+ [installed-private.md](installed-private.md) for normal resolution, `pip check`,
23
+ import verification and the separate complete hash-lock trial. Use `[engines]`
24
+ for the current common journey environment; ML and benchmark are unnecessary.
25
+ Run from a fresh consumer directory outside the checkout:
26
+
27
+ ```bash
28
+ python3.12 -m venv .venv
29
+ WHEELHOUSE=/absolute/path/reviewed-wheelhouse
30
+ .venv/bin/python -I -m pip install --no-index --find-links "$WHEELHOUSE" \
31
+ 'equiframe[engines]==0.12.4' --report install-report.json
32
+ .venv/bin/python -I -m pip check
33
+ .venv/bin/python -I -c 'import equiframe, sys; print(sys.executable); print(equiframe.__file__); print(equiframe.__version__)'
34
+ .venv/bin/python -I -m equiframe.examples.journeys.verify_journeys --output acceptance
35
+ ```
36
+
37
+ Replace the placeholder with the reviewed wheelhouse, containing exactly the
38
+ chosen core artifact and compatible dependencies. Verify its separately supplied
39
+ hash inventory first. The import must be in this environment's site-packages.
40
+ Do not use editable installs, PYTHONPATH, `--no-deps`, or an unreviewed public
41
+ homonym. A new repetition uses a new output directory.
42
+
43
+ Historical recipe: the retained `examples/journeys/requirements.lock` is a
44
+ byte-for-byte copy of the **0.11.1 / Python 3.12** first-use kit dependency lock.
45
+ Its pins (including Typer 0.27.2 and tzdata 2026.4) and old receipts are retained
46
+ for that exact historical kit, described in [recipes.md](recipes.md). It is not
47
+ the current A7 platform lock. Current independent hash-locked installation uses
48
+ `runtime-with-candidate.lock` supplied with the selected artifact/environment,
49
+ including the candidate hash; never mix old and new wheels with one filename.
50
+
51
+ Dependencies may need to be downloaded in a separately reviewed preparation
52
+ step. The A7 private kit has a pinned public-dependency reconstruction procedure;
53
+ only after that preparation is installation completely offline. None of these
54
+ synthetic examples needs network data. The examples alone do not establish a
55
+ platform run; see [measured compatibility](compatibility.md) for executed scope.
56
+
57
+ The **candidate wheel includes these scripts** and the guide. Alternatively,
58
+ copy the entire `examples/journeys` directory from the sdist or approved handoff:
59
+ `python journeys/a_pandas_refactor.py ...` works from another directory without
60
+ checkout imports or `PYTHONPATH`. Use ordinary Python for copied direct scripts;
61
+ `-I` removes the script directory and is intended here for the installed `-m`
62
+ route. On Windows use your environment's `Scripts/python.exe`; the commands are
63
+ not a claim of a newly executed Windows matrix.
64
+
65
+ A/F use pandas+Arrow; B/C use pandas+DuckDB+Arrow; D/E use Arrow; G/H use
66
+ DuckDB+Arrow. All also need core base dependencies. The single lock deliberately
67
+ covers the entire suite and pytest. Importing a journey module does not load any
68
+ optional engine. A missing direct Python import exits 2 with an installation
69
+ hint rather than a traceback; native engine failures retain their separate
70
+ core stage diagnostics and cannot approve data. Polars, ML, benchmark, SQLite services, cloud
71
+ accounts and SERCOP are not needed for these eight journeys. The existing native
72
+ migration tests separately cover all six pandas/Polars/DuckDB directions.
73
+
74
+ Every completed script writes `environment.json` with the actual interpreter,
75
+ platform, installed dependency versions and SHA-256 of the example scripts. The
76
+ candidate's commit and wheel hash belong in the accompanying build receipt;
77
+ a version string alone is insufficient to identify code. Historical results do not prove
78
+ a new wheel passed.
79
+
80
+ ## Commands and exits
81
+
82
+ All modules are under `equiframe.examples.journeys`. Replace `a_pandas_refactor`
83
+ in this command with the module below; choose a fresh output directory:
84
+
85
+ ```bash
86
+ python -I -m equiframe.examples.journeys.a_pandas_refactor --case good --output evidence-a
87
+ ```
88
+
89
+ | Journey/module | Correct | Discrepancy | Error/unavailable | Additional regression |
90
+ |---|---|---|---|---|
91
+ | A `a_pandas_refactor` | `good` → 0 | `different` → 1 | `not_evaluable` → 3 | `duplicate` → 1 |
92
+ | B `b_native_migration` | `good` → 0 | `different` → 1 | `not_evaluable` → 3 | Shared error despite peer agreement |
93
+ | C `c_retail_etl` | `good` → 0 | `different` → 1 | `error` → 2 | Both CSV and JSON exercised |
94
+ | D `d_financial_reconciliation` | `good` → 0 | `different` → 1 | `not_evaluable` → 3 | Equal totals with two wrong records |
95
+ | E `e_telemetry` | `good` → 0 | `different` → 1 | `not_evaluable` → 3 | `null_nan`, `duplicate_loss` → 1 |
96
+ | F `f_data_science_preparation` | `good` → 0 | `different` → 1 | `not_evaluable` → 3 | `dropped_row`, `changed_id` → 1 |
97
+ | G `g_external_snapshots` | `good` → 0 | `different` → 1 | `error` → 2 | `schema_error` → 2 |
98
+ | H `h_portable_ci` | `good` → 0 | `different` → 1 | `not_evaluable` → 3 | `error` → 2 |
99
+
100
+ For individual journeys, 0 means the requested acceptance checks passed; 1 is a
101
+ real discrepancy; 2 is invalid input/integrity/setup failure; 3 is unavailable
102
+ required judgment. A one-row comparison budget creates real non-evaluability in
103
+ the relevant branches; the script never fabricates a result state. Setup errors
104
+ fail closed. Existing output directories are refused, without overwriting them.
105
+
106
+ `verify_journeys` is different: it is a **test harness**, deliberately expecting
107
+ negative exits. Its 0 means all 31 named scenarios matched their specified
108
+ outcomes. `production_data_approval` is always false. Do not replace your CI
109
+ acceptance gate with a harness that expects a discrepancy.
110
+
111
+ ## A. Pandas refactor regression
112
+
113
+ **User/problem:** a Python developer replaces row-wise multiplication with a
114
+ vectorized calculation and needs meaningful pytest diagnostics. Three order
115
+ lines use composite identity `(order_id, line)`, preserving leading zeroes and
116
+ repeated order IDs. Money is exact signed int64 **USD cents**, not float.
117
+
118
+ The independent expected literal is `(001,1,250)`, `(001,2,50)`, `(002,1,300)`.
119
+ The old implementation is separately checked against it; the candidate is then
120
+ compared after harmless row permutation. `different` adds one cent to the third
121
+ line. The diagnostic must identify key `("002", 1)`, column `total_cents`, 301
122
+ versus 300. `duplicate` inserts another occurrence with an already-used composite
123
+ key; it is not silently deduplicated. A budget failure remains non-evaluable.
124
+
125
+ **Acceptance:** `diff` plus `assert_equivalent`, complete/final counts and the
126
+ actual difference records. The repository pytest recipe includes a direct
127
+ `pytest.raises(EquivalenceDifferentError)` test and rejects an invalid duplicate
128
+ expected table with `EquivalenceNotEvaluableError`. In your own pytest test:
129
+
130
+ ```python
131
+ from equiframe.examples.journeys.a_pandas_refactor import declaration, materialize
132
+ import equiframe as ef
133
+
134
+
135
+ def test_optimized_totals(tmp_path):
136
+ candidate, expected = materialize("good")
137
+ ef.assert_equivalent(ef.diff(candidate, expected, contract=declaration(), work_dir=tmp_path))
138
+ ```
139
+
140
+ **Artifacts/limits:** private full captures and differences; minimized
141
+ `reports/refactor/report.html`; runtime receipt and summary. Integer cents are a
142
+ USD-specific declaration in this example; do not infer arbitrary currencies or
143
+ rounding policies. A pandas index is not automatically the business key.
144
+
145
+ ## B. Native migration with an independent expected
146
+
147
+ **User/problem:** an engineer migrates a currency aggregate from pandas to
148
+ DuckDB. Both native compilers receive the same admitted IR and captured inputs;
149
+ neither engine's output feeds the other. `check_migration` runs before capture,
150
+ and the counted source resolves exactly once. Native execution identities and
151
+ identical input SHA-256 are recorded.
152
+
153
+ Four source rows contain USD 1.10 and 2.20 and two EUR NULLs. The expected is a
154
+ separate literal: USD 3.30, EUR NULL, with Decimal(20,2). `different` changes the
155
+ IR's NULL-only sum policy to zero. Both engines successfully execute and agree,
156
+ yet both fail against the unchanged literal. `not_evaluable` leaves native
157
+ execution completed but required comparisons unavailable.
158
+
159
+ **Acceptance:** preflight supported; one source capture; two distinct native
160
+ execution records; materialized expected independent of those outputs; all
161
+ three comparisons and the migration exit gate accepted. `read_migration`
162
+ checks persisted evidence after DuckDB closes. Reports cover peers and each
163
+ engine-versus-expected comparison separately.
164
+
165
+ **Limits:** bounded declarative compilation, not arbitrary code translation. The
166
+ same declarative plan is compiled independently; that does not prove independent
167
+ human design. The expected has no claim of external scientific review. This
168
+ journey demonstrates one direction; the separate matrix checks six directions.
169
+
170
+ ## C. Retail CSV/JSON ETL and local Parquet
171
+
172
+ **User/problem:** an ETL engineer needs explicit input schemas, a visible
173
+ invalid-record decision, native transformations, Verify and gated local output.
174
+ CSV and nested JSON independently encode the same four synthetic sales; they
175
+ are alternate representations, **not batches to concatenate**.
176
+
177
+ The schema preserves text SKU zeroes and exact Decimal money. Each source has
178
+ three valid rows and one invalid decimal. `good` deliberately quarantines the
179
+ known fourth record and writes a precise disposition: only record 3 with
180
+ `invalid_decimal` is excluded. It does not declare the entire input valid or
181
+ authorize similar exclusions on real data. `error` uses reject-whole-input and
182
+ never hands partial data to a workflow.
183
+
184
+ Native pandas/DuckDB checkpoints compute net then totals, once per source
185
+ format. Independent expected net literals are SKU 0007 USD 12.00, 0008 USD 2.00,
186
+ 0009 EUR 9.00. Totals are USD 14.00/2 rows and EUR 9.00/1 row. NULL discount is
187
+ explicitly zero in the transformation, not silently repaired by comparison.
188
+ The one-cent CSV discrepancy fails its net checkpoint and skips its dependent
189
+ totals; unrelated JSON checkpoints still run. Nothing is published after any
190
+ required checkpoint fails.
191
+
192
+ **Acceptance:** explicit subset disposition, all four checkpoints, required
193
+ expected/rule checks, Verify coverage and current-publication readback. Four
194
+ Parquet tables are written only for `good`; automated checks inspect their
195
+ literal values. `raw/quarantine-disposition.json` explains exclusions;
196
+ `raw/` includes sources, ingestion receipts, original invalid rows, workflows
197
+ and verification evidence. `public_reports/` contains minimized comparison
198
+ reports. `published/current.json` points to the verified local Parquet version.
199
+
200
+ **Limits/privacy:** raw files, receipt and publication metadata may disclose
201
+ values and local paths. Publish only the explicitly reviewed report view to
202
+ other people. Local Parquet publication is file creation; it does not publish
203
+ the Python package, deploy infrastructure, write a production DW, implement a
204
+ remote transaction, or accept Jhair's domain policy.
205
+
206
+ ## D. Exact financial reconciliation
207
+
208
+ **User/problem:** a financial-data engineer must find compensating errors that
209
+ an aggregate reconciliation misses. Identity is `(account, currency)` and money
210
+ is Decimal(20,2). USD and EUR remain separate; there is no inferred FX conversion.
211
+
212
+ The literal ledger is A/USD 1000000000000000.01, B/USD 0.09 and A/EUR 12.50.
213
+ `different` moves one cent from B/USD to A/USD. Both **per-currency totals stay
214
+ identical**, yet two keyed amount differences must remain. No intermediate
215
+ float, tolerance, quantization or deduplication hides them.
216
+
217
+ **Acceptance/artifacts:** complete exact keyed `diff`, assertion and two
218
+ per-record differences for the deliberate fault; minimized `reports/ledger/`,
219
+ private captures and the explicit `per_currency_totals_match` field. The error
220
+ branch uses a real comparison budget. This is a precision example, not accounting
221
+ advice, balancing rules or support for all financial instrument semantics.
222
+
223
+ ## E. Telemetry, zones, missingness, duplicates and order
224
+
225
+ **User/problem:** an engineer must distinguish transport changes from changed
226
+ measurements. Four records include a repeated observation, a separate NaN, a
227
+ NULL measurement and a NULL timestamp. The two non-NULL instants have literal
228
+ integer nanoseconds ending in 1 and 2; those sub-microsecond digits are retained.
229
+ Expected timestamps use UTC; the candidate uses America/Guayaquil at the same
230
+ instants. An explicitly lossless/instant policy admits that zone difference.
231
+
232
+ The expected sequence retains both repeated observations. `different` reorders
233
+ it; `duplicate_loss` removes one occurrence; `null_nan` swaps distinct missing
234
+ representations. All must fail. `good` preserves order and multiplicity.
235
+
236
+ **Acceptance:** Arrow `diff` with significant order, NULL last, ties preserved,
237
+ NaN distinct, exact readings and a declared instant policy. The script also
238
+ runs real `check_migration` calls: this Scan-only plan is refused because its
239
+ significant-order contract has no matching final Sort. This is not evidence that
240
+ all timestamp IR is unsupported. A successful direct comparison never implies
241
+ admission of a particular migration plan.
242
+
243
+ **API limits:** direct eager capture/comparison can retain nanoseconds. This
244
+ migration IR admits a bounded timestamp subset, documented in
245
+ [migration-ir.md](migration-ir.md). Native DuckDB zoned transport has its
246
+ separate microsecond limit; no silent conversion to it is demonstrated here.
247
+ NaN distinctions already collapsed by NumPy cannot be recovered. Original
248
+ per-row timestamp text/offset is not retained by Arrow; store it separately if
249
+ required. Timezone-provider versions may differ across engines. Artifacts are
250
+ private captures and minimized `reports/telemetry/`.
251
+
252
+ ## F. Data-science preparation without anomaly claims
253
+
254
+ **User/problem:** a data scientist optimizes feature preparation and must preserve
255
+ sample identity, row coverage, feature values and ordering of feature columns.
256
+ Four synthetic samples have zero-prefixed IDs. A predetermined milliseconds-to-
257
+ seconds conversion has independent literal seconds `[1.0, 2.5, 0.0, 1000.0]` and
258
+ event counts `[2, 3, 0, 99]`. No labels, training output or other engine determine
259
+ the expected table or scale.
260
+
261
+ `different` clips the large fourth feature to 100.0, `dropped_row` removes that
262
+ record, and `changed_id` erases identifier zeroes. Each fails exact keyed
263
+ comparison. The large value must survive `good`, whatever a future model might
264
+ think of it. A budget interruption is unavailable judgment.
265
+
266
+ **Acceptance/artifacts:** IDs, all rows and all features pass the declared
267
+ contract and assertion. `reports/features/` is minimized; raw captures remain
268
+ private. `anomaly_detection` and `model_training` are explicitly
269
+ `not_requested`. Equivalence does not imply healthy data, anomaly detection,
270
+ model quality, absence of leakage or scientific validity. R/M/B/H/O are not
271
+ redefined or coupled by this preparation check.
272
+
273
+ ## G. External snapshot integration
274
+
275
+ **User/problem:** an architect adapts an independently managed source through
276
+ `SnapshotClient` and `SnapshotDataSource`, without adding a mandatory transport
277
+ or benchmark dependency. `MemoryClient` contains explicitly authored synthetic
278
+ Arrow IPC bytes; its `example.invalid` URI is an identifier and is never fetched.
279
+ It accepts only fixed identity `synthetic.snapshot.20261006.v1`.
280
+
281
+ A manifest declares domain/extraction revisions, provenance, byte size/hash,
282
+ row count and schema. The source fetches the manifest once and downloads once;
283
+ the native DuckDB identity execution records the pinned snapshot and manifest
284
+ fingerprint. Expected rows are authored separately: `(1, Decimal("1.10"))` and
285
+ `(2, NULL)`.
286
+
287
+ `different` has intact bytes but value 1.11, so integrity passes and semantics
288
+ fail. `error` changes one known payload byte **after** manifest creation;
289
+ `schema_error` declares the wrong physical schema while keeping byte integrity.
290
+ Both produce `artifact_integrity_error`, invalid input and no output artifact.
291
+ These are ordinary functional integrity regressions, not a resumed security audit.
292
+
293
+ **Acceptance/artifacts:** one fixed-ID request, pinned provenance, faithful
294
+ execution, independent expected assertion, private snapshot evidence and a
295
+ minimized `reports/snapshot/` only when comparison exists. The complete
296
+ [SQLite integration](sqlite-snapshots.md) adds a real DB-API transactional producer
297
+ through the same ports, outside core.
298
+
299
+ **Limits:** hashes detect changed bytes but do not authenticate a producer.
300
+ Provider immutability, authorization, transport timeout, coordination and storage
301
+ retention remain external. Manifest fetching precedes run budgets; a cooperative
302
+ checkpoint cannot preempt blocked client code. No real service/DW acceptance is
303
+ claimed by either synthetic integration.
304
+
305
+ ## H. Portable review and CI
306
+
307
+ **User/problem:** a reviewer needs to move complete evidence without depending on
308
+ the original machine, keep a small report and reject unavailable or differing
309
+ results in CI. `capture_duckdb` executes a trusted bound synthetic query and
310
+ closes its owned connection. The expected is a separate Arrow literal with two
311
+ IDs and counts 10/20; `different` produces 10/21.
312
+
313
+ `verify` requires that expected. The finalized verification is exported, its
314
+ manifest hash pinned from this trusted local export, and the original evidence
315
+ directory renamed so its old artifact paths no longer exist. `import_bundle`
316
+ and `inspect_bundle` then verify closed inventory/integrity using captured
317
+ members, without rerunning SQL. The imported typed comparisons generate default
318
+ minimized reports before their explicit assertion gate. `different` has valid
319
+ integrity but failed semantics. `not_evaluable` retains a real budget failure.
320
+ `error` corrupts the imported root document and must refuse it without making a
321
+ report or accepting data.
322
+
323
+ **Acceptance:** intact imported inventory, requested Verify checks publishable,
324
+ at least one comparison, all comparison assertion gates accepted. Required
325
+ non-evaluability exits 3. `bool(result)`, a successful export/import and report
326
+ creation are never acceptance shortcuts. No independent review is requested or
327
+ invented. A received bundle needs a trusted out-of-band expected digest if its
328
+ identity must be pinned; the hash itself remains unsigned.
329
+
330
+ **Artifacts/privacy:** `private/portable`, `private/imported` and
331
+ `private/retired-original` contain complete raw evidence. Only `reports/` is
332
+ minimized. Tests verify report inventory hashes and absence of synthetic secret
333
+ IDs, local paths and file URIs. Minimization does not erase the raw bundle or
334
+ certify that any adapted real dataset is safe to share.
335
+
336
+ ## Automated checks and interpretation
337
+
338
+ The sdist's `tests/test_product_journeys.py` copies the directory outside its
339
+ source location, runs all scenario CLIs, verifies actual return codes and
340
+ independent values, reads raw comparisons/migrations, checks Parquet totals,
341
+ asserts typed failures, verifies report inventories/redaction, and checks that
342
+ an existing output cannot be overwritten. Separate checks verify import-light
343
+ modules and explicit missing-dependency failures. It also demonstrates the direct
344
+ pytest assertion and checks the dependency lock remains the existing pinned
345
+ route. Run with the package's locked developer environment:
346
+
347
+ ```bash
348
+ python -m pytest tests/test_product_journeys.py -q
349
+ ```
350
+
351
+ The outside-checkout harness can be run from a notebook with subprocess or each
352
+ module's `run(Path("fresh"), "good")`. Inspect `accepted` and `exit_code`; never
353
+ use the truth value of an EquiFrame result. In an orchestrator, invoke the same
354
+ Python function or module command as a normal task, keep raw artifacts in a
355
+ private run directory, and let nonzero exits fail the task. No new orchestration
356
+ framework or service is required. Retries require a new output directory and
357
+ must account for any effects added by your own callbacks.
358
+
359
+ No five-minute human diagnosis, user pilot, performance speedup, general volume
360
+ capacity, universal platform support, producer authenticity, production service
361
+ acceptance or scientific conclusion is established by these small tests.
362
+ Resource controls are cooperative; use process/OS isolation for hard limits.