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.
- equiframe/__init__.py +832 -0
- equiframe/__main__.py +3 -0
- equiframe/_base.py +84 -0
- equiframe/_cli_support.py +125 -0
- equiframe/_comparison_io.py +161 -0
- equiframe/_dataset_provenance.py +146 -0
- equiframe/_decimal.py +22 -0
- equiframe/_diff_capture.py +433 -0
- equiframe/_doctor.py +123 -0
- equiframe/_document_io.py +61 -0
- equiframe/_documents.py +79 -0
- equiframe/_duckdb_transport.py +149 -0
- equiframe/_error_reporting.py +52 -0
- equiframe/_first_use.py +102 -0
- equiframe/_path_compat.py +26 -0
- equiframe/_physical.py +133 -0
- equiframe/_r_review.R +308 -0
- equiframe/_regular_io.py +167 -0
- equiframe/_report_format_v1.py +298 -0
- equiframe/_report_io.py +591 -0
- equiframe/_stability_inventory.py +1421 -0
- equiframe/_timezones.py +257 -0
- equiframe/_vendor/cyclonedx/LICENSE +201 -0
- equiframe/_vendor/cyclonedx/PROVENANCE.md +18 -0
- equiframe/_vendor/cyclonedx/bom-1.6.schema.json +5673 -0
- equiframe/_vendor/cyclonedx/jsf-0.82.schema.json +240 -0
- equiframe/_vendor/cyclonedx/spdx.schema.json +712 -0
- equiframe/adapters.py +454 -0
- equiframe/assertion_types.py +122 -0
- equiframe/assertions.py +271 -0
- equiframe/benchmark.py +101 -0
- equiframe/bundle.py +240 -0
- equiframe/cli.py +693 -0
- equiframe/comparison.py +937 -0
- equiframe/comparison_report.py +660 -0
- equiframe/comparison_types.py +257 -0
- equiframe/compatibility.py +546 -0
- equiframe/contracts.py +879 -0
- equiframe/datasets.py +1301 -0
- equiframe/decision.py +34 -0
- equiframe/destinations.py +295 -0
- equiframe/detector_types.py +431 -0
- equiframe/detectors.py +389 -0
- equiframe/diff.py +192 -0
- equiframe/diff_contracts.py +523 -0
- equiframe/docs/adoption.md +329 -0
- equiframe/docs/api.md +534 -0
- equiframe/docs/arquitecto.md +143 -0
- equiframe/docs/choosing-api.md +84 -0
- equiframe/docs/cientifico.md +180 -0
- equiframe/docs/compatibility.md +254 -0
- equiframe/docs/contributing.md +171 -0
- equiframe/docs/dependencies.md +237 -0
- equiframe/docs/eda.md +166 -0
- equiframe/docs/extending.md +158 -0
- equiframe/docs/fast-ci.md +52 -0
- equiframe/docs/first-use.md +78 -0
- equiframe/docs/index.md +142 -0
- equiframe/docs/ingestion.md +145 -0
- equiframe/docs/inicio.md +129 -0
- equiframe/docs/installed-private.md +97 -0
- equiframe/docs/journeys.md +362 -0
- equiframe/docs/lectura-conversion.md +211 -0
- equiframe/docs/licensing.md +17 -0
- equiframe/docs/maintenance.md +233 -0
- equiframe/docs/migration-ir.md +333 -0
- equiframe/docs/option-audit.md +45 -0
- equiframe/docs/outcome-gates.md +134 -0
- equiframe/docs/performance.md +263 -0
- equiframe/docs/piloto-simulado.md +56 -0
- equiframe/docs/quickstart.md +156 -0
- equiframe/docs/r_review.md +212 -0
- equiframe/docs/recipes.md +248 -0
- equiframe/docs/releasing.md +183 -0
- equiframe/docs/security.md +218 -0
- equiframe/docs/semantics.md +274 -0
- equiframe/docs/sqlite-snapshots.md +262 -0
- equiframe/docs/universal-sources.md +49 -0
- equiframe/docs/universalidad-cinco-pasos.md +107 -0
- equiframe/docs/upgrading.md +538 -0
- equiframe/duckdb_capture.py +410 -0
- equiframe/eda/__init__.py +36 -0
- equiframe/eda/__main__.py +3 -0
- equiframe/eda/_backend.py +612 -0
- equiframe/eda/_inventory.py +49 -0
- equiframe/eda/_paths.py +49 -0
- equiframe/eda/_report.py +291 -0
- equiframe/eda/api.py +535 -0
- equiframe/eda/cli.py +102 -0
- equiframe/eda/models.py +239 -0
- equiframe/errors.py +83 -0
- equiframe/evidence.py +375 -0
- equiframe/examples/integrations/eda_generic.py +60 -0
- equiframe/examples/integrations/outcome_gates.py +94 -0
- equiframe/examples/integrations/sqlite_snapshot.py +246 -0
- equiframe/examples/integrations/sqlite_snapshot_demo.py +226 -0
- equiframe/examples/integrations/universal_first_use.py +296 -0
- equiframe/examples/journeys/README.md +31 -0
- equiframe/examples/journeys/__init__.py +1 -0
- equiframe/examples/journeys/a_pandas_refactor.py +88 -0
- equiframe/examples/journeys/b_native_migration.py +181 -0
- equiframe/examples/journeys/c_retail_etl.py +460 -0
- equiframe/examples/journeys/common.py +136 -0
- equiframe/examples/journeys/d_financial_reconciliation.py +96 -0
- equiframe/examples/journeys/e_telemetry.py +135 -0
- equiframe/examples/journeys/f_data_science_preparation.py +84 -0
- equiframe/examples/journeys/g_external_snapshots.py +197 -0
- equiframe/examples/journeys/h_portable_ci.py +129 -0
- equiframe/examples/journeys/requirements.lock +249 -0
- equiframe/examples/journeys/verify_journeys.py +117 -0
- equiframe/examples/load_convert_compare.py +85 -0
- equiframe/execution.py +355 -0
- equiframe/execution_types.py +177 -0
- equiframe/ingestion.py +744 -0
- equiframe/local.py +126 -0
- equiframe/migration/__init__.py +94 -0
- equiframe/migration/_physical.py +8 -0
- equiframe/migration/backends/_timestamp_transport.py +109 -0
- equiframe/migration/backends/duckdb.py +651 -0
- equiframe/migration/backends/duckdb_decimal.py +125 -0
- equiframe/migration/backends/duckdb_time.py +87 -0
- equiframe/migration/backends/pandas.py +544 -0
- equiframe/migration/backends/polars.py +915 -0
- equiframe/migration/backends/polars_decimal.py +231 -0
- equiframe/migration/io.py +198 -0
- equiframe/migration/ports.py +96 -0
- equiframe/migration/runner.py +545 -0
- equiframe/migration/runner_types.py +405 -0
- equiframe/migration/types.py +354 -0
- equiframe/migration/validation.py +619 -0
- equiframe/normalization.py +358 -0
- equiframe/pipeline.py +274 -0
- equiframe/pipeline_types.py +247 -0
- equiframe/ports.py +39 -0
- equiframe/preprocessing.py +110 -0
- equiframe/profile_types.py +343 -0
- equiframe/profiles.py +447 -0
- equiframe/py.typed +0 -0
- equiframe/r_review.py +706 -0
- equiframe/reduction.py +518 -0
- equiframe/registry.py +121 -0
- equiframe/report_rendering.py +366 -0
- equiframe/report_types.py +294 -0
- equiframe/reporting.py +26 -0
- equiframe/rule_types.py +178 -0
- equiframe/rules.py +819 -0
- equiframe/schemas/r-execution-binding-1.0.schema.json +46 -0
- equiframe/schemas/r-review-binding-1.0.schema.json +28 -0
- equiframe/schemas/r-review-options-1.0.schema.json +38 -0
- equiframe/schemas/r-review-result-1.0.schema.json +207 -0
- equiframe/schemas/reviewed-decision-1.0.schema.json +3394 -0
- equiframe/serialization.py +152 -0
- equiframe/snapshot.py +296 -0
- equiframe/sources.py +283 -0
- equiframe/tables.py +459 -0
- equiframe/types.py +71 -0
- equiframe/values.py +252 -0
- equiframe/verification_request.py +35 -0
- equiframe/verify.py +799 -0
- equiframe/verify_types.py +255 -0
- equiframe/workflow.py +510 -0
- equiframe/workflow_request.py +38 -0
- equiframe-0.12.4.dist-info/METADATA +268 -0
- equiframe-0.12.4.dist-info/RECORD +170 -0
- equiframe-0.12.4.dist-info/WHEEL +4 -0
- equiframe-0.12.4.dist-info/entry_points.txt +3 -0
- equiframe-0.12.4.dist-info/licenses/LICENSE +21 -0
- equiframe-0.12.4.dist-info/licenses/THIRD_PARTY_NOTICES.md +42 -0
- equiframe-0.12.4.dist-info/licenses/tools/cyclonedx/LICENSE +201 -0
- equiframe-0.12.4.dist-info/licenses/tools/cyclonedx/PROVENANCE.md +18 -0
equiframe/docs/inicio.md
ADDED
|
@@ -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.
|