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,211 @@
1
+ # Lectura de archivos y conversión de DataFrames
2
+
3
+ La API `load_dataset`, incluida en el alcance estable de 0.12.0, lee un archivo local, descubre su estructura
4
+ y crea un **DataFrame real de Pandas**. Si se selecciona Polars o DuckDB,
5
+ convierte ese mismo DataFrame y entrega el objeto nativo correspondiente.
6
+ Esta ruta convierte datos; no traduce un programa ni ejecuta transformaciones
7
+ independientes en tres motores. Tampoco entrena detectores ni ejecuta R.
8
+
9
+ La implementación se añadió el 26 de octubre de 2026. Su estabilización protege
10
+ la interfaz, las conversiones admitidas y sus errores; no promete todas las
11
+ variantes de cada formato o combinación de dependencias. La
12
+ [compatibilidad](compatibility.md) identifica las verificaciones ejecutadas y
13
+ sus límites, sin atribuirlas a otros artefactos.
14
+
15
+ ## Uso desde Python
16
+
17
+ ```python
18
+ import equiframe as ef
19
+
20
+ datos = ef.load_dataset("ventas.json")
21
+ pandas_df = datos.pandas
22
+ print(datos.info.to_dict()) # columnas, tipos observados, nulos, NaN y número de filas
23
+
24
+ polars_datos = ef.convert_dataset(datos, target="polars")
25
+ polars_df = polars_datos.frame
26
+
27
+ # Las conversiones encadenadas consumen el objeto nativo actual.
28
+ with ef.convert_dataset(polars_datos, target="duckdb") as duckdb_datos:
29
+ pandas_de_vuelta = ef.convert_dataset(duckdb_datos, target="pandas")
30
+
31
+ # También puede seleccionarse el destino en la misma llamada.
32
+ with ef.load_dataset("ventas.parquet", target="duckdb") as datos_sql:
33
+ relacion = datos_sql.frame
34
+ resultado = relacion.limit(10).df()
35
+ # La relación DuckDB depende de la conexión privada, cerrada al salir del with.
36
+ ```
37
+
38
+ `DatasetResult.pandas` conserva el DataFrame de origen y `frame` contiene el
39
+ objeto del destino seleccionado: DataFrame de Pandas, DataFrame de Polars o
40
+ DuckDBPyRelation. `close()` libera la conexión DuckDB que pertenece al resultado;
41
+ no abre archivos DuckDB compartidos. El usuario puede trabajar con esos objetos
42
+ mediante las APIs de sus motores. `inspect_dataset(path)` devuelve solamente
43
+ `DatasetInfo`, pero realiza la lectura completa dentro de los límites declarados.
44
+
45
+ ## Identidad de la fuente y de la conversión
46
+
47
+ Cada lectura utiliza una única captura de los bytes del archivo y devuelve
48
+ `DatasetResult.provenance`, también accesible desde `info.provenance`.
49
+ `DatasetSource` identifica URI, formato, SHA-256 y tamaño de esos bytes; conserva
50
+ las opciones efectivas en `read_options_json`, consultables como un objeto con
51
+ la propiedad `read_options`. Esto incluye la hoja, el delimitador o el modo de
52
+ texto resueltos durante la lectura, no solamente las opciones iniciales.
53
+
54
+ `DatasetProvenance` vincula esa fuente con `pandas_sha256`, el destino `target`
55
+ y `target_sha256`. Las conversiones admiten las seis direcciones entre Pandas,
56
+ Polars y DuckDB; leen el objeto nativo seleccionado, sin releer el archivo ni
57
+ sustituirlo por una copia anterior. La conversión rechaza una modificación del
58
+ objeto nativo o del Pandas original posterior a la captura. El esquema nativo
59
+ de Polars o DuckDB se verifica antes de convertir a Arrow; una exportación Arrow
60
+ coincidente no sustituye esa comprobación de tipos. La exportación del origen
61
+ también rechaza una modificación del Pandas original. Para trabajar sobre datos modificados,
62
+ el consumidor debe establecer una nueva entrada y su identidad, sin reutilizar
63
+ la procedencia original como si describiera esos cambios.
64
+
65
+ ```python
66
+ print(datos.provenance.source.sha256)
67
+ print(datos.provenance.source.read_options)
68
+ print(datos.info.to_dict(include_provenance=True))
69
+ ```
70
+
71
+ `info.to_dict()` omite esa procedencia por defecto, porque su URI puede contener
72
+ una ruta privada. `include_provenance=True` la añade explícitamente;
73
+ `include_metadata=True` controla por separado los metadatos originales.
74
+ Estas huellas identifican los datos y opciones observados; no autentican al
75
+ productor del archivo ni aprueban una migración de programas.
76
+
77
+ ## Formatos y decisiones que puede requerir el lector
78
+
79
+ | Archivo | Representación y opciones |
80
+ |---|---|
81
+ | JSON | Un objeto de registro o una lista de registros. Los escalares y listas de valores se conservan en una columna `value`, sin aplanar sus objetos o arrays. Los números fraccionarios se leen como `Decimal`. Para un contenedor de registros se exige `records_path`, sin expandir otras colecciones. |
82
+ | JSONL / NDJSON | Un registro o valor por línea no vacía. Se rechazan miembros JSON duplicados, NaN e Infinity no estándar. |
83
+ | CSV | Detecta delimitadores consistentes entre coma, punto y coma, tabulación y barra vertical. Si más de uno encaja, solicita elección. Por defecto la primera fila es el encabezado. |
84
+ | TXT / TSV | Texto libre: una columna `text`, una fila por línea. Si también puede interpretarse como tabla, pregunta `lines` o `delimited`. Se puede fijar `delimiter`, `header` y `text_mode`. No se inventa un esquema para texto libre. |
85
+ | Excel | `.xlsx` y `.xlsm` mediante openpyxl; `.xls` mediante xlrd. Selecciona automáticamente solo cuando hay una hoja. Con varias hojas exige `sheet`. Lee las filas/celdas observadas sin truncarlas según dimensiones declaradas por el productor. No ejecuta macros; XLSX/XLSM con fórmulas o errores exige un archivo con valores. |
86
+ | XML | Usa defusedxml y rechaza DTD, entidades y referencias externas. Conserva atributos, campos y elementos repetidos; `records_path` permite seleccionar registros. El XML de contenido mixto que no pueda representarse fielmente se rechaza. |
87
+ | Parquet | Conserva tipos Arrow, unidades, zonas y máscaras de ausencia al construir Pandas con ArrowDtype. |
88
+ | GeoJSON | FeatureCollection, Feature y geometrías. Conserva `geometry` y `properties` originales; expone además `properties.nombre` y los otros miembros como `feature.nombre`. Los metadatos de la colección quedan en `info.metadata`. No requiere GIS ni cambia el sistema de coordenadas. |
89
+
90
+ Ejemplos de desambiguación:
91
+
92
+ ```python
93
+ opciones = ef.DatasetReadOptions(sheet="Ventas")
94
+ datos = ef.load_dataset("libro.xlsx", options=opciones, target="polars")
95
+
96
+ opciones = ef.DatasetReadOptions(records_path="/respuesta/ventas")
97
+ datos = ef.load_dataset("respuesta.json", options=opciones)
98
+
99
+ opciones = ef.DatasetReadOptions(delimiter="\t", header=False)
100
+ datos = ef.load_dataset("mediciones.txt", options=opciones)
101
+ ```
102
+
103
+ En JSON `records_path` es un JSON Pointer RFC 6901. En XML es una ruta de
104
+ elementos de ElementTree, por ejemplo `./ventas/venta` o `.//venta`.
105
+ No se descargan esquemas, no se ejecuta XPath arbitrario ni se evalúa código.
106
+
107
+ ## Tipos y preservación
108
+
109
+ La inferencia textual es conservadora: enteros canónicos se convierten en
110
+ enteros y números decimales inequívocos se convierten en `Decimal`, sin pasar
111
+ por float. Los ceros iniciales, espacios, representaciones mezcladas y fechas
112
+ permanecen como texto. Un campo vacío sigue siendo una cadena vacía; no se
113
+ interpreta automáticamente como nulo ni se adivinan tokens como `NA`.
114
+ Los números ya almacenados por Excel tienen la precisión que conserva el
115
+ libro; no se recuperan dígitos perdidos antes de llegar a EquiFrame. Los formatos
116
+ Excel de enteros con ceros de relleno, como `000000`, se conservan como texto y
117
+ se informa esa decisión. Las fechas tipadas de Excel conservan su tipo.
118
+ XLS expone valores almacenados o cacheados; su lector no identifica
119
+ independientemente todas las fórmulas del archivo heredado.
120
+
121
+ `DatasetInfo.notes` informa las inferencias. Para conservar todo texto o
122
+ declarar unas pocas columnas:
123
+
124
+ ```python
125
+ opciones = ef.DatasetReadOptions(
126
+ infer_text_types=False,
127
+ column_types={"importe": "decimal", "cantidad": "integer", "codigo": "string"},
128
+ )
129
+ datos = ef.load_dataset("ventas.csv", options=opciones)
130
+ ```
131
+
132
+ Tipos explícitos admitidos: `string`, `integer`, `decimal`, `boolean` y `json`.
133
+ `json` conserva un objeto o array como texto JSON sin convertir sus Decimal a
134
+ float. Es una representación explícita útil para geometrías heterogéneas o
135
+ propiedades anidadas que no admitan una única estructura Arrow:
136
+
137
+ ```python
138
+ opciones = ef.DatasetReadOptions(column_types={"geometry": "json", "properties": "json"})
139
+ datos = ef.load_dataset("mapa.geojson", options=opciones, target="polars")
140
+ ```
141
+
142
+ No se cambia automáticamente a texto cuando un motor no admite un tipo.
143
+ La ruta de conversión comprueba la representación Arrow inicial y recorre por
144
+ completo el resultado nativo para rechazar cambios de contenido, nulos/NaN,
145
+ orden, precisión, escala o zona temporal. Permite cambios de transporte como
146
+ `string` a `large_string` que conservan los valores. Un tipo incompatible genera
147
+ `CapabilityError`; el resultado no se declara equivalente ni se normaliza.
148
+
149
+ Los campos JSON ausentes se materializan como nulos en las columnas unificadas;
150
+ sus posiciones originales quedan en `info.metadata["absent_json_members_by_row"]`.
151
+ `info.to_dict()` omite metadatos originales por defecto; use
152
+ `info.to_dict(include_metadata=True)` cuando quiera incluirlos explícitamente.
153
+ Los metadatos de una colección GeoJSON pueden contener información del usuario.
154
+
155
+ ## Un comando para leer y elegir destino
156
+
157
+ ```console
158
+ equiframe dataset load ventas.json
159
+ ```
160
+
161
+ La misma invocación muestra la estructura, pregunta las ambigüedades del archivo
162
+ y pregunta: «¿A qué motor quiere migrar desde Pandas? pandas / polars / duckdb».
163
+ Para scripts y entradas no interactivas se pasa el destino:
164
+
165
+ ```console
166
+ equiframe dataset load ventas.json --target polars
167
+ equiframe dataset load libro.xlsx --sheet Ventas --target duckdb
168
+ equiframe dataset load ventas.csv --target polars --output copia.parquet
169
+ equiframe dataset inspect mapa.geojson
170
+ ```
171
+
172
+ Opciones de lectura: `--format`, `--sheet`, `--records-path`, `--delimiter`
173
+ (`tab` significa tabulación), `--header/--no-header`, `--text-mode`,
174
+ `--infer-types/--keep-text`, `--encoding`, `--max-bytes` y `--max-rows`.
175
+ Sin `--output`, el objeto convertido existe durante el comando; en Python
176
+ la API devuelve el objeto para continuar trabajando. `--output` y
177
+ `DatasetResult.to_parquet()` exportan el **Pandas original cargado** a un Parquet
178
+ nuevo; no exportan transformaciones que el usuario aplique después a `frame`.
179
+ La exportación escribe y sincroniza primero un temporal hermano, y publica
180
+ exclusivamente el archivo completo mediante un enlace duro en el mismo sistema
181
+ de archivos. El destino no se sobrescribe. Si el sistema no admite esa operación,
182
+ la exportación falla; no usa una copia parcial como alternativa. El temporal
183
+ propio se retira al terminar. No se promete durabilidad ante corte de energía.
184
+ Un error posterior a la publicación puede dejar el Parquet completo visible;
185
+ inspeccione y compruebe su contenido antes de decidir una recuperación, sin
186
+ suponer que cualquier archivo existente pertenece al intento fallido.
187
+ La conversión no equivale a una comparación
188
+ semántica de dos implementaciones; para esa tarea siguen disponibles `diff`
189
+ y los contratos de equivalencia.
190
+
191
+ Los fallos CLI conservan el código estable en la primera línea de stderr y la
192
+ guía fija `hint[...]` después. Un `DatasetChoiceRequired` puede añadir entonces
193
+ un objeto JSON con `required_option` y `choices` para resolver una ambigüedad.
194
+ Un error de lectura/configuración termina con código 2; dependencias no
195
+ disponibles y fallos técnicos terminan con código 3. El código 0 sólo indica que
196
+ se completó la lectura y conversión solicitadas, sin aprobar equivalencia.
197
+
198
+ ## Dependencias y límites
199
+
200
+ El extra `files` añade Pandas, Arrow, openpyxl, xlrd y defusedxml. Polars y DuckDB
201
+ se seleccionan mediante sus extras existentes. Los lectores y motores se importan
202
+ solo al usarlos; un extra faltante produce `MissingDependencyError` con la
203
+ dependencia necesaria. No hay instalaciones automáticas.
204
+
205
+ Por defecto se admiten hasta 128 MiB de archivo, un millón de filas y dos
206
+ millones de celdas. Son límites de admisión; no son cuotas duras de RAM ni de
207
+ descompresión. La lectura es local y completa, no distribuida ni en streaming.
208
+ Las rutas locales pueden seguir enlaces simbólicos; el llamante debe elegir
209
+ archivos y directorios de confianza. Se rechazan nombres de columnas duplicados,
210
+ filas CSV irregulares y conversiones sin representación fiel. No se infieren
211
+ claves de negocio, monedas, fechas, CRS ni reglas de aceptación del proyecto.
@@ -0,0 +1,17 @@
1
+ # License
2
+
3
+ The owner selected MIT on 2026-10-27 for the original EquiFrame and EquiFrame
4
+ Benchmark code and accompanying project documentation, examples and tools.
5
+ Copyright (c) 2026 Hernán Troya. Each distribution carries the full LICENSE.
6
+
7
+ MIT permits use, modification, commercial use and redistribution under its
8
+ terms, including preservation of the copyright and permission notice. The
9
+ software is provided without warranty as stated in the license.
10
+
11
+ Third-party material keeps its existing license. Both core distributions
12
+ include unmodified CycloneDX schemas under Apache-2.0; their upstream license,
13
+ provenance and notices are preserved. See THIRD_PARTY_NOTICES.md in the package.
14
+
15
+ This decision does not relicense downloaded datasets, the thesis manuscript,
16
+ external dependencies or separately owned components. Publication remains a
17
+ separate owner-authorized task.
@@ -0,0 +1,233 @@
1
+ # Maintenance, support and trust incidents
2
+
3
+ [Handbook](index.md) · [Adoption](adoption.md) · [Compatibility](compatibility.md) ·
4
+ [Upgrading](upgrading.md) · [Security](security.md) · [Release/rollback](releasing.md)
5
+
6
+ ## Maintainer and best-effort support
7
+
8
+ The project owner has assigned **Hernán Troya (`htroya`)**
9
+ responsibility for maintenance, releases and security coordination. This is
10
+ best-effort maintenance by one owner, not a staffed service or support contract.
11
+ No backup, on-call coverage, numeric response deadline or SLA is promised.
12
+
13
+ | Role | Scope | Named owner | Backup |
14
+ |---|---|---|---|
15
+ | Core | Comparison/contracts, typed states, assertions, evidence integrity and historical readers | Hernán Troya (`htroya`) | Not designated |
16
+ | Adapters | Native capture/execution, capabilities, dependencies and measured matrix cells | Hernán Troya (`htroya`) | Not designated |
17
+ | Documentation | Installation, diagnosis, migration guidance and reproducible examples | Hernán Troya (`htroya`) | Not designated |
18
+ | Releases | Exact-byte checks, manual publication/withdrawal and recovery | Hernán Troya (`htroya`) | Not designated |
19
+ | Security | Private intake, exposure review and vulnerability coordination | Hernán Troya (`htroya`) | Not designated |
20
+
21
+ The core remains independent of a service, domain schema and infrastructure.
22
+ Service/DW ownership, concurrency, authorization and aggregate quotas stay with
23
+ those components' owners; an adapter issue does not authorize redesigning them.
24
+ Keep experimental benchmark/scientific acceptance distinct from operational
25
+ comparison maintenance.
26
+
27
+ ## Report a problem
28
+
29
+ Use [the public issue channel](https://github.com/htroya/equiframe/issues)
30
+ for nonsensitive bugs and minimal synthetic reproductions. Use
31
+ [private vulnerability reporting](https://github.com/htroya/equiframe/security/advisories/new)
32
+ for sensitive security reports. Both routes belong to the project's single
33
+ public repository. For each release, the maintainer must enable both routes
34
+ and verify their availability. If private intake cannot be verified, retain
35
+ sensitive details locally until confidential intake can be arranged; do not
36
+ move them to a public issue.
37
+
38
+ Do not put credentials, real data, personal information or sensitive exploit
39
+ details in a public issue, an ordinary issue with a broader audience, or a
40
+ guessed email address. A repository issue is not automatically a private
41
+ security channel. If a safe route cannot be verified, retain sensitive details
42
+ locally and stop using the affected acceptance path.
43
+
44
+ Provide only the minimal permitted reproduction:
45
+
46
+ 1. Classify installation, comprehension, semantics, integration, performance
47
+ and/or evidence; state impact and whether false `equivalent` is suspected
48
+ 2. Identify exact package/commit, wheel/sdist and dependency-lock hashes, Python,
49
+ OS/architecture, engine versions and selected extras. Redact account/path data
50
+ 3. Give a small synthetic fixture and trusted code/SQL that someone can inspect
51
+ before executing. Include the contract, relevant policy, budgets and explicit
52
+ reproduction commands; do not upload a complete private run or environment
53
+ 4. State independently expected versus observed state, completeness, acceptance
54
+ and exit code. Explain the expected-output provenance. Separate engine
55
+ agreement from correctness and report integrity from semantic acceptance
56
+ 5. Attach only a reviewed minimized report when permitted, with its inventory
57
+ verification outcome and hash. Mark missing/partial evidence explicitly
58
+ 6. Identify the last known-good **artifact**, if known, repeatability and any safe
59
+ workaround. Preserve earlier failures; do not silently replace the baseline
60
+
61
+ The [adoption guide](adoption.md) describes consent and minimal observation.
62
+ Permission to participate does not authorize sharing the person's data or posting
63
+ to an issue. Do not request additional private data until its necessity, recipient
64
+ and handling have been agreed. Raw exception causes can reveal more than the
65
+ ordinary report; inspect diagnostics before sending them.
66
+
67
+ ## Triage priorities without response deadlines
68
+
69
+ The maintainer uses the following best-effort triage order. It does not establish
70
+ staffed coverage, response deadlines or a service guarantee.
71
+
72
+ | Priority | Examples | Triage goal |
73
+ |---|---|---|
74
+ | P0: critical trust incident | Suspected false `equivalent`, acceptance of incomplete/invalid evidence, or material disclosure/integrity risk | Stop relying on the affected claim, preserve evidence and seek owner-led containment/escalation before restoring acceptance |
75
+ | P1: blocking defect | Reproducible installation/integration failure, documented supported case incorrectly rejected, or an unusable evidence reader | Establish scope and a safe workaround, then reproduce and verify a focused correction |
76
+ | P2: nonblocking friction | Comprehension gaps, minor diagnosis problems, performance outside an unpromised target | Preserve observations, assess impact and prioritize repeated real pain without weakening semantics |
77
+ | P3: capability proposal | New engine, integration or unsupported representation | Require repeated real need, ownership, corpus, budget and an explicit support decision before implementation commitment |
78
+
79
+ Category and severity are separate. A semantics report is not automatically a
80
+ confirmed defect; an evidence issue may be critical. Safe `not_evaluable` is
81
+ not false equivalence. If the owner is unavailable, leave the issue pending;
82
+ there is no designated backup or automatic escalation promise. Do not promise a
83
+ reply or reopen a potentially unsafe path merely because time has passed.
84
+
85
+ ## Reproduce, correct and reconfirm
86
+
87
+ Use a local incident/issue record with source evidence, scope, category, proposed
88
+ priority, triage decision, assigned owner when accepted, correction and validation
89
+ references. Keep review, release approval and consumer confirmation separately
90
+ pending. A suggested workflow is: reported, scoped, reproduced or needs evidence,
91
+ correction under review, technically verified, awaiting consumer reconfirmation,
92
+ then resolved. Unsupported, duplicate or withdrawn reports need an explicit
93
+ rationale; do not erase the original observation.
94
+
95
+ For a reproducible defect:
96
+
97
+ 1. Preserve the failing artifact, permitted evidence and independent expectation.
98
+ Reduce a copy to a minimal synthetic case while retaining the same failure
99
+ 2. Add a regression that fails against the affected version for the stated reason.
100
+ Include relevant equivalent, different, invalid and incomplete cases; tests
101
+ derived only from the implementation can confirm the same error
102
+ 3. Make a narrow correction with review of API/format/adapter/contract impacts.
103
+ Do not rename a stable surface experimental to evade compatibility duties
104
+ 4. Run affected semantic and historical-reader tests, full candidate checks,
105
+ outside-checkout installed recipes and affected compatibility matrix cells
106
+ against new immutable bytes. Record failed, blocked and unexecuted checks
107
+ 5. Document scope, behavior changes, migration, exact hashes and residual limits.
108
+ Follow [release approval](releasing.md); technical verification does not
109
+ authorize distribution, a public issue, dependency access or a remote CI run
110
+ 6. Through the authorized channel, ask the affected consumer to test the original
111
+ use case and the relevant later real change with the identified correction.
112
+ Record whether the integration is retained and reporting/updating is understood
113
+ 7. Mark consumer reconfirmation only after their actual response and evidence.
114
+ If they cannot repeat it, keep that gap open rather than treating internal tests
115
+ as their approval. Reopen the issue if their case still fails
116
+
117
+ Track actual triage/reproduction/review/documentation effort and unresolved work.
118
+ Sustainable support needs observed capacity and accepted owners, not estimates
119
+ presented as delivered service.
120
+
121
+ ## False `equivalent`: critical trust incident procedure
122
+
123
+ A plausible false-equivalence report triggers precautionary containment while
124
+ validation proceeds. This means the evaluated contract admitted a difference or
125
+ invalid/incomplete evaluation as acceptance; a deliberate permissive contract or
126
+ two engines sharing the same bug needs separate diagnosis. Do not dismiss the
127
+ report merely because existing tests pass or a manifest has valid hashes.
128
+
129
+ 1. **Contain.** Stop using the suspect result/path as an acceptance gate. Preserve
130
+ original artifacts and private evidence; suspend distribution/recommendation
131
+ of affected candidate hashes within the authorized scope. Do not silently
132
+ weaken a contract, remove the check or convert `not_evaluable` to success
133
+ 2. **Escalate safely.** Seek an accepted incident owner and relevant core/adapter,
134
+ release and security reviewers through verified routes. Keep sensitive details
135
+ restricted. No staffed response or automatic external notification is implied
136
+ 3. **Bound impact.** Identify affected package commits and wheel hashes, exact
137
+ dependency versions, APIs, adapter stages, data types, contract revisions and
138
+ policies, output/evidence formats and environments. Distinguish confirmed,
139
+ possibly affected and untested scopes; inventory downstream decisions that
140
+ relied on the suspect result without uploading their raw data
141
+ 4. **Reproduce independently.** Build the smallest permitted case with an expected
142
+ result reviewed independently of the failing path. Compare the identified
143
+ previous and current artifacts; keep counterexamples and original decisions
144
+ 5. **Correct and verify.** Add the failing regression, repair the narrow cause and
145
+ exercise adjacent policies, all affected native adapters, interruption/limits,
146
+ invalid expected inputs and persisted readers. Re-run full affected source,
147
+ distribution and compatibility gates. A fail-closed fix may reject formerly
148
+ accepted input immediately; explain that boundary explicitly
149
+ 6. **Prepare safe recovery.** Supply a new approved artifact with exact pins,
150
+ change notes and validation evidence. Test upgrade in an isolated environment
151
+ and re-evaluate affected consumer cases. Roll back only to a demonstrated
152
+ known-safe artifact/environment; if none exists, suspend acceptance. Never
153
+ rewrite historic evidence or downgrade format markers to force readability
154
+ 7. **Notify with approval.** The owner approves the recipient scope, channel and
155
+ consequential content before an affected-user notice is sent. Explain affected
156
+ and uncertain versions/contracts/adapters, impact, containment, safe upgrade
157
+ or rollback and cases requiring re-evaluation. Reach only authorized recipients
158
+ through verified channels and share no other consumer's private data. Record
159
+ actual dispatch/acknowledgment separately from a prepared draft
160
+ 8. **Reconfirm and close.** Obtain affected-consumer confirmation on their original
161
+ and later-change cases, record any downstream corrective decision, and document
162
+ residual exposure. Keep unreached consumers and unverified environments open.
163
+ Owner review closes containment only with evidence; a green internal suite
164
+ alone does not close the trust incident
165
+
166
+ For a future public release, advisory and index actions require the owner's
167
+ separate approval. A yank does not remove installed or exactly pinned copies.
168
+ Published artifacts must not be overwritten. Before a first registry publication
169
+ there is no public release to withdraw; afterwards use the same identified-byte
170
+ withdrawal/recovery process in [releasing](releasing.md).
171
+
172
+ ## Upgrade, dependency and support decisions
173
+
174
+ Preserve package version, contract revision and evidence format as separate
175
+ identities. Follow the [compatibility policy](compatibility.md), including its
176
+ deprecation window and fail-closed exception, and [upgrade checks](upgrading.md).
177
+ New evidence must not change the meaning of historical records. Unknown formats
178
+ remain rejected; migration needs explicit review and new traceable artifacts.
179
+
180
+ Support claims must cite exact measured cells. The current maturity plan requires
181
+ Python 3.10/3.11/3.12/3.13 with per-interpreter first-use closures and explicit
182
+ platform receipts. Do not expand support from metadata, configured but unexecuted CI, or past results
183
+ for different candidate hashes. Dependency changes require fresh affected-cell
184
+ validation and updated artifact-bound inventories; timestamps and old advisory
185
+ receipts cannot certify changed dependencies.
186
+
187
+ The retained STEP9 minimum-profile advisory match for **CVE-2026-25087** remains
188
+ visible. The recorded advisory states the affected Arrow C++ functionality is
189
+ not exposed through Python bindings, which are excluded from vulnerability;
190
+ this does not turn the retained package-version match into a clean scan, prove
191
+ all native dependencies safe or complete the source-security assessment.
192
+ That historical result does not substitute for triage of the dependencies in a
193
+ new release. See [dependency evidence](dependencies.md) and current release gates.
194
+
195
+ The earlier stopped source-security assessment remains historical and is not
196
+ relabeled as a pass. The owner has now authorized stable-release preparation and
197
+ manual TestPyPI/PyPI publication subject to current security and release gates.
198
+ MIT licensing and the maintainer role are owner decisions. The reporting routes
199
+ must be enabled and their availability verified for each release. Registry
200
+ ownership, final artifact checks and publication remain separate observable
201
+ steps. Do not claim that authorization fixes a vulnerability or completes a
202
+ security assessment. Scientific acceptance and human adoption are independent
203
+ of interface stability and registry publication.
204
+
205
+ ## Admitting a new engine or integration
206
+
207
+ Do not expand the adapter catalog because a feature is popular or a synthetic
208
+ demo passed. Before accepting an implementation commitment, require:
209
+
210
+ - Repeated, documented blockers in independent real uses and why existing
211
+ supported routes cannot meet the need without semantic loss
212
+ - A named willing maintainer with boundaries agreed by component owners; any
213
+ backup or staffed coverage must be explicit rather than assumed
214
+ - A permitted representative corpus with independent expectations, positive,
215
+ negative, unsupported, invalid and incomplete cases, including key/multiplicity,
216
+ NULL/NaN, Decimal and time boundaries relevant to the integration
217
+ - An explicit resource and maintenance budget covering native dependencies,
218
+ CI/platform cells, performance, evidence readers, security and upgrade costs
219
+ - An owner-approved support decision: supported subset, version/platform matrix,
220
+ stability, failure/abstention rules, migration/deprecation and exit criteria
221
+
222
+ Record the decision and its evidence before adding an engine. Preserve genuine
223
+ native execution and explicit registration; do not simulate a new engine by
224
+ converting another engine's already-computed output. Missing demand, ownership,
225
+ corpus, budget or support approval leaves the proposal pending.
226
+
227
+ ## Python 3.10 runtime policy
228
+
229
+ The supported compatibility range includes Python 3.10 through 3.13, with the
230
+ measured scope in [compatibility](compatibility.md). Application deployment
231
+ owners remain responsible for the interpreter's lifecycle, dependency risks and
232
+ their upgrade path. Passing package tests does not provide upstream/vendor
233
+ security maintenance, a backup maintainer or a response deadline.