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
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
# Performance and safe resource budgets
|
|
2
|
+
|
|
3
|
+
[Handbook](index.md) · [Semantics](semantics.md) · [Compatibility](compatibility.md)
|
|
4
|
+
|
|
5
|
+
EquiFrame favors declared semantics and reviewable evidence over an unconditional
|
|
6
|
+
speed claim. Native assertions may be the smaller service when you only need a
|
|
7
|
+
verdict. There is no universal row limit, latency guarantee, process-RSS quota,
|
|
8
|
+
larger-than-RAM promise or demonstrated advantage over every comparison tool.
|
|
9
|
+
|
|
10
|
+
## Understand the work you request
|
|
11
|
+
|
|
12
|
+
`diff` first captures native inputs, then compares. `compare` can read local
|
|
13
|
+
captured Arrow IPC/Parquet in batches and uses private SQLite working files for
|
|
14
|
+
exact grouping/alignment. It still validates schema, keys, values, multiplicity
|
|
15
|
+
and all requested evidence. A displayed sample limit does not skip the remaining
|
|
16
|
+
data. Wide strings, many differences and approximate matching can cost more than
|
|
17
|
+
an equal narrow table with the same row count.
|
|
18
|
+
|
|
19
|
+
Common default budgets, as declared by the installed models:
|
|
20
|
+
|
|
21
|
+
| Options | Defaults and scope |
|
|
22
|
+
|---|---|
|
|
23
|
+
| `DiffCaptureOptions` | 1,000,000 rows and 256 MiB per eager input |
|
|
24
|
+
| `ComparisonOptions.batch_rows` | 4,096 rows per comparison batch |
|
|
25
|
+
| `max_batch_bytes`, `max_row_bytes` | 64 MiB per batch; 1 MiB per row |
|
|
26
|
+
| `max_rows`, `max_work` | 10,000,000 rows; 100,000,000 accounted work units |
|
|
27
|
+
| `max_disk_bytes`, `max_evidence_bytes` | 4 GiB comparison working budget; 512 MiB difference evidence |
|
|
28
|
+
| `max_matching_rows`, `max_matching_bytes`, `max_pair_checks` | 2,000 matching rows; 32 MiB; 2,000,000 candidate pair checks |
|
|
29
|
+
| `partitions`, `sqlite_cache_kib` | 16 partitions; 4,096 KiB SQLite cache setting |
|
|
30
|
+
| `max_examples` | 20 summary examples; does not limit evaluation |
|
|
31
|
+
| `timeout_seconds` | None by default; explicit timeouts are cooperative |
|
|
32
|
+
| `DuckDBCaptureOptions` | 4,096-row batches; 1,000,000 rows; 64 MiB batch and 256 MiB file budgets |
|
|
33
|
+
|
|
34
|
+
These are operational checks, not an admission guarantee for every case below
|
|
35
|
+
the numbers. Capture/conversion can allocate before a check. File sizes, Arrow
|
|
36
|
+
buffers, engine-managed memory, working disk and process RSS are distinct.
|
|
37
|
+
`duckdb_memory_mb` constrains engine-managed memory, not all Python/Arrow/native
|
|
38
|
+
allocations. Core callback and Polars collection cancellation are cooperative;
|
|
39
|
+
a callback that does not check can run until it returns. DuckDB query interruption
|
|
40
|
+
does not impose a hard deadline on all Python capture/publication work.
|
|
41
|
+
|
|
42
|
+
Choose a private output directory on a suitable disk-backed filesystem, leave
|
|
43
|
+
space for inputs, temporary files, snapshots and full differences, and avoid
|
|
44
|
+
concurrent benchmark workloads. For large inputs prefer captured files and an
|
|
45
|
+
explicit contract over eager conversion. Set work/time/evidence budgets based on
|
|
46
|
+
a small representative run. Preserve insufficient-budget results instead of
|
|
47
|
+
silently loosening exactness or dropping duplicates.
|
|
48
|
+
|
|
49
|
+
## Reproducible engineering measurements
|
|
50
|
+
|
|
51
|
+
The separate `equiframe-benchmark` package offers experimental `ScaleSpec`,
|
|
52
|
+
`ScaleTrial`, `ScaleRun`, `measure_scale`, `read_scale` and `summarize_scale`.
|
|
53
|
+
Install its identified matching wheel with the required dependency profile before
|
|
54
|
+
running this complete small example outside the checkout:
|
|
55
|
+
|
|
56
|
+
```python
|
|
57
|
+
from pathlib import Path
|
|
58
|
+
import equiframe as ef
|
|
59
|
+
import equiframe_benchmark as eb
|
|
60
|
+
|
|
61
|
+
spec = eb.ScaleSpec(
|
|
62
|
+
case_id="keyed-last-batch-1k",
|
|
63
|
+
rows=1_000,
|
|
64
|
+
width=4,
|
|
65
|
+
alignment="keyed",
|
|
66
|
+
null_every=11,
|
|
67
|
+
difference_last=True,
|
|
68
|
+
repetitions=3,
|
|
69
|
+
comparison_options=ef.ComparisonOptions(batch_rows=256),
|
|
70
|
+
concurrent_loads="Record actual known concurrent work; host load is uncontrolled",
|
|
71
|
+
)
|
|
72
|
+
result = eb.measure_scale(spec, work_dir=Path("scale-runs"))
|
|
73
|
+
verified = eb.read_scale(Path("scale-runs") / result.run_id)
|
|
74
|
+
summary = eb.summarize_scale(verified)
|
|
75
|
+
print(summary)
|
|
76
|
+
if not verified.complete:
|
|
77
|
+
raise SystemExit(3)
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
For meaningful CPU/RSS monitoring install the benchmark's `resources` extra;
|
|
81
|
+
missing or failed monitoring remains explicit. The optional `engines` extra
|
|
82
|
+
permits applicable native baselines. This script measures a deliberately
|
|
83
|
+
**different** case: completion means the expected verdict occurred, not that the
|
|
84
|
+
two tables should pass an equivalence assertion.
|
|
85
|
+
|
|
86
|
+
The generator uses deterministic synthetic integer/text/NULL data with exact keys
|
|
87
|
+
or multisets. Width, string length, cardinality, skew, duplicate multiplicity,
|
|
88
|
+
NULLs, difference density and final-row differences are controlled explicitly.
|
|
89
|
+
It does not establish performance for Decimal, timestamps, approximate matching,
|
|
90
|
+
unknown SQL, remote services, data warehouses or larger-than-RAM datasets.
|
|
91
|
+
|
|
92
|
+
One isolated trusted worker runs 2–10 repetitions sequentially, default 3. The
|
|
93
|
+
first uses a fresh Python worker; subsequent trials reuse it. OS caches are
|
|
94
|
+
uncontrolled. Raw labels distinguish `fresh_process_os_cache_uncontrolled` and
|
|
95
|
+
`warm_process_os_cache_uncontrolled`; summaries retain n/median/min/max, failures
|
|
96
|
+
and missing observations. One fresh observation is not a variability estimate.
|
|
97
|
+
|
|
98
|
+
The recorded stages are capture, snapshot hashing/counting, local transfer,
|
|
99
|
+
contract planning, public comparison, additional standalone serialization,
|
|
100
|
+
persistence, rendering and verification. Public `compare` includes its own
|
|
101
|
+
capture/snapshot/planning/evidence work; the additional serialization/persistence
|
|
102
|
+
stages do not isolate its internals. End-to-end trial time brackets these stages.
|
|
103
|
+
Supervisor elapsed time additionally includes startup, repetitions, baselines,
|
|
104
|
+
monitoring and reaping. Parent final inventory verification/publication is outside
|
|
105
|
+
that measured interval. Do not subtract unlike scopes to invent a component cost.
|
|
106
|
+
|
|
107
|
+
## What the resource figures mean
|
|
108
|
+
|
|
109
|
+
- RSS is an absolute sampled **lower bound on peak**, not an allocation delta or
|
|
110
|
+
hard maximum. Sample gaps and monitoring failures remain visible
|
|
111
|
+
- Worker CPU/I/O counters are last available observations; physical storage bytes
|
|
112
|
+
and logical syscall bytes are different. Missing final totals stay unknown
|
|
113
|
+
- Disk apparent/allocated peaks are sampled within the owned worker tree and
|
|
114
|
+
temporary directory. Hard links count once; deleted-between-sample or
|
|
115
|
+
open-unlinked files may be missed
|
|
116
|
+
- Engine allocator peak is not supplied by this protocol. Supervisor resources
|
|
117
|
+
and unrelated host work are not included in worker RSS
|
|
118
|
+
- Observed RSS/disk thresholds reactively terminate work and may overshoot; they
|
|
119
|
+
are not cgroups, containers or a sandbox
|
|
120
|
+
- A watchdog can terminate the trusted worker's private process group on POSIX
|
|
121
|
+
or direct child elsewhere. Scheduling delays and unsupported escaping children
|
|
122
|
+
prevent a universal hard-time/containment claim
|
|
123
|
+
- `complete` describes operation/verdict completion;
|
|
124
|
+
`resource_measurement_complete` separately states observation quality
|
|
125
|
+
|
|
126
|
+
Native pandas assertions and DuckDB bidirectional `EXCEPT ALL` baselines are
|
|
127
|
+
restricted to the generator's exact integer/text/NULL policies and original
|
|
128
|
+
Arrow-schema check. They provide less evidence: no complete EquiFrame difference
|
|
129
|
+
files, snapshots, reports and integrity inspection. Ratios are service-cost
|
|
130
|
+
comparisons, not proof one equivalent service is faster. DataComPy is not pinned
|
|
131
|
+
in this candidate and no measurement is invented for it.
|
|
132
|
+
|
|
133
|
+
## Historical baseline, not a new-artifact speed claim
|
|
134
|
+
|
|
135
|
+
The STEP8 identified Linux x86_64/CPython 3.12.14 artifacts recorded nine synthetic
|
|
136
|
+
cases with three sequential trials each. The narrow 1M-row/two-column last-batch
|
|
137
|
+
case had an all-trial median end-to-end pipeline time of **207.985 seconds**,
|
|
138
|
+
range **206.989–211.278 seconds** and sampled worker peak RSS about **396.8 MiB**.
|
|
139
|
+
The corresponding restricted DuckDB verdict baseline was about **0.493 seconds**
|
|
140
|
+
median, providing substantially less evidence. There is no raw verdict-speed
|
|
141
|
+
advantage for EquiFrame in that example.
|
|
142
|
+
|
|
143
|
+
Those results belong to core wheel SHA-256
|
|
144
|
+
`61030f6755d943954920ef989939fae845bb8b77c69886a347b4fc00e05de1be`
|
|
145
|
+
and benchmark wheel SHA-256
|
|
146
|
+
`e7a227e13c0ea2db926d24e5e6625025bdf4a052e7eac8a0406cb48d6a5a3d96`.
|
|
147
|
+
They are **not measurements of a later rebuilt STEP9 wheel**. All nine runs
|
|
148
|
+
retained `resource_measurement_complete=False` due to incomplete final I/O
|
|
149
|
+
monitoring; some RSS sampling was partial. Host load and OS caches were not
|
|
150
|
+
controlled. These numbers are orientation with explicit limits, not a sizing SLA.
|
|
151
|
+
|
|
152
|
+
The measured narrow 1M recipe used a 1 GiB sampled RSS threshold, 2 GiB sampled
|
|
153
|
+
disk threshold, 1 billion comparison work units, 540 seconds per-comparison
|
|
154
|
+
cooperative timeout and 1,800 seconds supervised allowance for three trials.
|
|
155
|
+
Admission additionally reserves at least disk budget + 256 MiB free space. These
|
|
156
|
+
are fixture-specific budgets, not recommendations for every 1M-row workload.
|
|
157
|
+
The default 100 million work units was insufficient for that fixture.
|
|
158
|
+
|
|
159
|
+
## Failure, finalization and cleanup
|
|
160
|
+
|
|
161
|
+
`equiframe-benchmark scale spec.json --output scale-runs` and
|
|
162
|
+
`verify-scale scale-runs/scale-ID` return 3 for incomplete/failed measurement or
|
|
163
|
+
invalid finalization. Exit zero by itself is insufficient. The worker's completion
|
|
164
|
+
receipt, finalized aggregate and `finished.json` inventory binding must all
|
|
165
|
+
validate. A native kill, incorrect verdict, corrupted inventory or incomplete
|
|
166
|
+
comparison is not successful measurement.
|
|
167
|
+
|
|
168
|
+
After reaping the worker, only known disposable SQLite files in owned comparison
|
|
169
|
+
directories are removed; partial captures, diagnostics and logs remain. A reader
|
|
170
|
+
does not execute workloads or delete evidence. Receipts retain original local
|
|
171
|
+
paths and are not portable bundles; reproduce from the specification and exact
|
|
172
|
+
artifacts. If the parent dies before publication, `read_scale` fails closed.
|
|
173
|
+
|
|
174
|
+
Tests use bounded subprocesses, genuine SIGKILL and injected ENOSPC rather than
|
|
175
|
+
filling a host disk or causing host OOM. No destructive whole-host stress result
|
|
176
|
+
is claimed. The consumer must treat missing finalization, abnormal exit and
|
|
177
|
+
insufficient evidence as failure or unavailable evaluation, never equivalence.
|
|
178
|
+
|
|
179
|
+
## Bounded consolidation suite
|
|
180
|
+
|
|
181
|
+
`tools/measure_bounded.py` adds a repeatable developer suite. It reuses
|
|
182
|
+
`ScaleSpec`, `measure_scale`, `read_scale`, `summarize_scale` and their existing
|
|
183
|
+
isolated-worker supervisor for final-row differences, dense differences,
|
|
184
|
+
duplicate multiplicity, wide strings and ordinary disk/evidence costs. A separate
|
|
185
|
+
small Decimal supplement measures exact cents through Arrow and pandas, including
|
|
186
|
+
an explicitly timed Arrow-to-pandas conversion. It does not change historical
|
|
187
|
+
scale schemas or introduce a core dependency on the benchmark.
|
|
188
|
+
|
|
189
|
+
Use a benchmark environment containing the **matching installed** core and
|
|
190
|
+
benchmark builds, including pandas, Arrow and the benchmark `resources` extra.
|
|
191
|
+
From the checkout, after the identified artifacts have been installed:
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
packages/equiframe-benchmark/.venv/bin/python -I \
|
|
195
|
+
tools/measure_bounded.py \
|
|
196
|
+
--output /new/private/bounded-costs --rows 512 --repetitions 3
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
The scale supervisor deliberately ignores `PYTHONPATH`; pointing the parent at
|
|
200
|
+
changed source while its isolated worker has an older installed wheel fails the
|
|
201
|
+
producer-identity check. Install the matching artifacts instead of weakening the
|
|
202
|
+
check. `suite.json` retains imported-source fingerprints, tool hash, versions,
|
|
203
|
+
individual stage boundaries, raw supervision records and explicit completion.
|
|
204
|
+
An older version string alone is not a matching artifact. Failed attempts remain
|
|
205
|
+
separate; each run requires a new output directory.
|
|
206
|
+
|
|
207
|
+
Defaults run sequentially at 512 rows/side (1,024 for the disk/evidence fixture),
|
|
208
|
+
three repetitions, 128-row batches, a 512 MiB sampled RSS threshold, 64 MiB sampled
|
|
209
|
+
disk threshold and 120 seconds per supervised case. Comparison budgets are 32 MiB
|
|
210
|
+
disk, 8 MiB differences and 30 cooperative seconds. The suite admits only
|
|
211
|
+
8–2,048 rows and 2–5 repetitions and requires at least 384 MiB initially free.
|
|
212
|
+
These are conservative test boundaries, not hard quotas or workload sizing advice.
|
|
213
|
+
The disk fixture writes complete snapshots and dense differences without trying
|
|
214
|
+
to fill the host disk. The small tests simulate interruption and ENOSPC; they do
|
|
215
|
+
not exhaust memory or storage.
|
|
216
|
+
|
|
217
|
+
The Decimal supplement has its own developer-receipt format rather than claiming
|
|
218
|
+
the historical `ScaleSpec` supports Decimal. It retains the independently expected
|
|
219
|
+
one-cent final-record difference, all comparison records and a redacted report.
|
|
220
|
+
`diff` includes its own conversion/capture, inference, complete comparison and
|
|
221
|
+
publication. Additional conversion, capture, hashing, serialization and durable
|
|
222
|
+
write timings describe additional work; they are not disjoint pieces extracted
|
|
223
|
+
from the internal `diff` timing. A completed comparison followed by failed receipt
|
|
224
|
+
publication is an incomplete measurement. Pre-contract cancellation can raise
|
|
225
|
+
`ExecutionCancelled` before a final comparison exists.
|
|
226
|
+
|
|
227
|
+
### Measured reference at the consolidation base
|
|
228
|
+
|
|
229
|
+
On 2026-10-06, the installed core and benchmark Python sources were independently
|
|
230
|
+
matched to commit `c4be1c5a29d9f58b2628882bd986de2bb5ca4184`. This **base reference**,
|
|
231
|
+
not a final rebuilt-consolidation measurement, ran all six families with three
|
|
232
|
+
repetitions and complete expected outcomes. Linux x86_64, CPython 3.12.14,
|
|
233
|
+
PyArrow 25.0.1, pandas 3.0.6 and psutil 7.2.2; shared cloud host, uncontrolled OS
|
|
234
|
+
caches and concurrent development work. Each case has one fresh worker trial and
|
|
235
|
+
two warm-worker trials; medians below combine those three explicitly identified
|
|
236
|
+
observations and do not imply cold-cache repeatability.
|
|
237
|
+
|
|
238
|
+
| Case | Rows/side | Pipeline median (range), seconds | Sampled worker RSS, MiB | Sampled apparent disk, MiB |
|
|
239
|
+
|---|---:|---:|---:|---:|
|
|
240
|
+
| Final-row difference | 512 | 0.221 (0.207–0.485) | 147.8 | 1.74 |
|
|
241
|
+
| Every-row difference | 512 | 0.243 (0.228–0.497) | 148.8 | 2.47 |
|
|
242
|
+
| Eight distinct rows, duplicates | 512 | 0.131 (0.130–0.365) | 148.0 | 1.21 |
|
|
243
|
+
| Eight columns, wider strings | 512 | 0.275 (0.271–0.530) | 158.8 | 15.90 |
|
|
244
|
+
| Dense differences plus disk evidence | 1,024 | 0.755 (0.650–0.967) | 160.0 | 24.98 |
|
|
245
|
+
| Exact Decimal final cent | 512 | 0.184 (0.181–0.186) | 149.2 | 1.31 |
|
|
246
|
+
|
|
247
|
+
The public comparison stage dominates these small cases. For example, the
|
|
248
|
+
Decimal median stages were 0.00051 s construction, 0.00087 s additional conversion,
|
|
249
|
+
0.00027 s additional IPC capture, 0.00007 s hashing, 0.17618 s full `diff`,
|
|
250
|
+
0.00007 s extra serialization, 0.00005 s extra durable write, 0.00314 s report and
|
|
251
|
+
0.00146 s readback. Very short stages are below useful stable sizing resolution.
|
|
252
|
+
No algorithm was optimized from these observations and no percentage improvement
|
|
253
|
+
or comparison against a lower-guarantee service is claimed.
|
|
254
|
+
|
|
255
|
+
All six resource receipts remain incomplete because the final I/O sampling
|
|
256
|
+
reported `AccessDenied`. Missing final I/O totals are unknown, not zero. RSS and
|
|
257
|
+
disk columns remain observed lower bounds over the supervised worker and retained
|
|
258
|
+
evidence tree; disk is for the case's three repetitions, not one input file.
|
|
259
|
+
Raw receipts also retain allocated-disk observations and sampling gaps. No new
|
|
260
|
+
macOS/Windows/ARM64, large-volume, storage-saturation or human usability result is
|
|
261
|
+
implied. Preserve the supplied private raw receipts when using this reference;
|
|
262
|
+
source/tool fingerprints and actual environment take precedence over these
|
|
263
|
+
rounded display values.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Tres perfiles ficticios para ensayar el protocolo
|
|
2
|
+
|
|
3
|
+
[Protocolo de adopción](adoption.md) · [Arquitecto](arquitecto.md) · [Científico](cientifico.md)
|
|
4
|
+
|
|
5
|
+
**SIMULADO.** Hernán autorizó preparar perfiles ficticios. No representan personas,
|
|
6
|
+
empresas o proyectos reales; no tienen consentimiento otorgado ni observaciones
|
|
7
|
+
humanas. No se introducen en el registro de pilotos como `human_pilot` y no suman
|
|
8
|
+
al índice U12. No se fabrican firmas, independencia, tiempos o satisfacción.
|
|
9
|
+
|
|
10
|
+
## Perfil ficticio A: arquitectura e integración SQL
|
|
11
|
+
|
|
12
|
+
- Rol ficticio: arquitecta de datos que integra una comprobación en un orquestador existente
|
|
13
|
+
- Proyecto simulado: comparar una consulta DuckDB de inventario sintético con un
|
|
14
|
+
esperado literal por SKU, conservando clave compuesta y unidades
|
|
15
|
+
- Ruta: guía del arquitecto, captura propia SQL, reporte y aserción; ampliar con
|
|
16
|
+
el recorrido G para fijación de snapshot local
|
|
17
|
+
- Decisiones a ensayar: elegir `[duckdb]`, distinguir snapshot fijado de servicio
|
|
18
|
+
real, localizar B=21 frente a B=20 y detener el siguiente paso
|
|
19
|
+
- Escenario de seguimiento propuesto: una consulta posterior añade un filtro;
|
|
20
|
+
el control debe permanecer. No se afirma que ese cambio haya ocurrido
|
|
21
|
+
|
|
22
|
+
## Perfil ficticio B: ciencia de datos y preparación
|
|
23
|
+
|
|
24
|
+
- Rol ficticio: científico de datos que conserva identidad y tiempo al preparar features
|
|
25
|
+
- Proyecto simulado: dataset sintético de tres muestras con IDs, Decimal y NULL
|
|
26
|
+
- Ruta: guía del científico; primero `good`, luego desplazamiento temporal,
|
|
27
|
+
pérdida de fila y ausencia reemplazada por cero
|
|
28
|
+
- Decisiones a ensayar: interpretar la diferencia y la consecuencia en ventanas,
|
|
29
|
+
cobertura y joins; mantener el esperado independiente y las ausencias
|
|
30
|
+
- Escenario de seguimiento propuesto: una revisión vectoriza la preparación sin
|
|
31
|
+
cambiar semántica. No hay modelo entrenado ni utilidad científica observada
|
|
32
|
+
|
|
33
|
+
## Perfil ficticio C: mantenimiento de una regresión CI
|
|
34
|
+
|
|
35
|
+
- Rol ficticio: ingeniera que mantiene pruebas de regresión Python de un proyecto
|
|
36
|
+
- Proyecto simulado: comprobar totales sintéticos después de un refactor,
|
|
37
|
+
conservar el reporte aunque falle pytest y mantener el retorno no cero
|
|
38
|
+
- Ruta: test local de la guía del arquitecto y recorrido A/H
|
|
39
|
+
- Decisiones a ensayar: distinguir cero del arnés que espera fallos del gate que
|
|
40
|
+
acepta datos; usar carpeta nueva y separar una salida completa de equivalencia
|
|
41
|
+
- Escenario de seguimiento propuesto: otro commit cambia el cálculo; el test y
|
|
42
|
+
diagnóstico siguen disponibles. No se ejecuta ni acredita CI remota
|
|
43
|
+
|
|
44
|
+
## Hoja vacía de ensayo, sin resultados humanos
|
|
45
|
+
|
|
46
|
+
Antes de ensayar, anotar guía/artefactos, propósito y escenario. Si se ejecutan
|
|
47
|
+
comandos, registrarlos como reproducción técnica sintética con sus resultados
|
|
48
|
+
reales. El tiempo automático solo mide comandos; no mide comprensión humana.
|
|
49
|
+
No llenar el consentimiento ni la independencia con valores ficticios positivos.
|
|
50
|
+
|
|
51
|
+
Para pasar de estos perfiles a U12 se requieren personas y proyectos reales,
|
|
52
|
+
consentimiento con alcance/lectores/retención, revisión humana de independencia,
|
|
53
|
+
interpretación y ayuda observadas, tres diagnósticos iniciales <=300 s con reloj
|
|
54
|
+
predeclarado e integración retenida tras un cambio real posterior. Todo ello
|
|
55
|
+
permanece pendiente. El permiso de ensayar perfiles no es permiso de contactar
|
|
56
|
+
personas, compartir datos o publicar resultados.
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
# Quick start
|
|
2
|
+
|
|
3
|
+
[Handbook](index.md) · [Recipes](recipes.md) · [Semantics](semantics.md)
|
|
4
|
+
|
|
5
|
+
This guide targets **0.12.4** artifacts and uses synthetic local data. Its
|
|
6
|
+
commands require identified artifacts after the [release gates](releasing.md)
|
|
7
|
+
pass. Check the official index for availability and verify the artifact hashes.
|
|
8
|
+
It works outside a source checkout. The supported range is Python 3.10–3.13;
|
|
9
|
+
use the exact interpreter/platform dependency closure reviewed for your artifact.
|
|
10
|
+
The first-use builder produces a separate hash lock for the selected minor.
|
|
11
|
+
Metadata admission is not a claim of support for every platform. See
|
|
12
|
+
[compatibility](compatibility.md).
|
|
13
|
+
|
|
14
|
+
## 1. Install the artifact you were given
|
|
15
|
+
|
|
16
|
+
The commands below demonstrate the optional [offline wheelhouse](installed-private.md)
|
|
17
|
+
route, with normal pip resolution and a separate hash-locked trial. For registry
|
|
18
|
+
installation, use the README after the corresponding [release gates](releasing.md)
|
|
19
|
+
have verified ownership and publication. For an offline delivery, obtain:
|
|
20
|
+
|
|
21
|
+
- `equiframe-0.12.4-py3-none-any.whl`
|
|
22
|
+
- A receipt identifying its commit and expected SHA-256, received through a
|
|
23
|
+
channel you trust independently of the artifact
|
|
24
|
+
- A wheelhouse containing the reviewed runtime dependency wheels for your
|
|
25
|
+
Python/platform and chosen extra, with their pins, hashes and inventory
|
|
26
|
+
|
|
27
|
+
A hash checks bytes against a trusted reference; a manifest packaged with the
|
|
28
|
+
same untrusted archive cannot authenticate its sender. Check the supplied wheel
|
|
29
|
+
against the separate receipt before installing. For example, from its directory:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
python3.12 -c "from pathlib import Path; import hashlib; p=Path('equiframe-0.12.4-py3-none-any.whl'); print(hashlib.sha256(p.read_bytes()).hexdigest())"
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Compare the printed value with the receipt. Stop on a mismatch. Do not copy the
|
|
36
|
+
observed hash back into the expected receipt to make it pass.
|
|
37
|
+
|
|
38
|
+
Create a fresh directory **outside the repository**, then create an environment.
|
|
39
|
+
The following commands use a POSIX shell. Set both paths to your verified local
|
|
40
|
+
locations; `/absolute/path/...` is a placeholder, not a download URL:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
mkdir equiframe-consumer
|
|
44
|
+
cd equiframe-consumer
|
|
45
|
+
python3.12 -m venv .venv
|
|
46
|
+
. .venv/bin/activate
|
|
47
|
+
WHEEL=/absolute/path/equiframe-0.12.4-py3-none-any.whl
|
|
48
|
+
WHEELHOUSE=/absolute/path/reviewed-wheelhouse
|
|
49
|
+
python -m pip install --no-index --find-links "$WHEELHOUSE" "${WHEEL}[arrow]"
|
|
50
|
+
python -m pip check
|
|
51
|
+
python -I -c "import equiframe, sys; print(sys.version); print(equiframe.__version__); print(equiframe.__file__)"
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
The import must point into this environment's installed package, not the checkout.
|
|
55
|
+
This command cannot fetch missing dependencies from an index. A missing compatible
|
|
56
|
+
wheel is a blocker to resolve with the artifact provider, not a reason to remove
|
|
57
|
+
integrity checks or install an unrelated `equiframe` from PyPI. For exact hashed
|
|
58
|
+
dependency installation, follow the kit's `--require-hashes` recipe. Do not use an
|
|
59
|
+
editable install or add the checkout to `PYTHONPATH` as an installation test.
|
|
60
|
+
|
|
61
|
+
On Windows, `py -3.12 -m venv .venv` creates the environment and
|
|
62
|
+
`.venv\Scripts\python.exe` can be used directly instead of activation. Do not
|
|
63
|
+
change security policy to activate it. These command conventions do not establish
|
|
64
|
+
that this candidate was verified on Windows. Each Python minor needs its matching
|
|
65
|
+
reviewed dependency set; do not reuse a 3.12 kit lock as a claim of compatibility
|
|
66
|
+
with 3.10, 3.11 or 3.13.
|
|
67
|
+
|
|
68
|
+
## 2. Compare two complete outputs
|
|
69
|
+
|
|
70
|
+
Save this complete script as `quickstart.py` in the new consumer directory:
|
|
71
|
+
|
|
72
|
+
```python
|
|
73
|
+
from pathlib import Path
|
|
74
|
+
|
|
75
|
+
import equiframe as ef
|
|
76
|
+
import pyarrow as pa
|
|
77
|
+
|
|
78
|
+
expected = pa.table({"id": ["A", "B"], "quantity": [10, 20]})
|
|
79
|
+
candidate = pa.table({"id": ["B", "A"], "quantity": [21, 10]})
|
|
80
|
+
private_root = Path("private-evidence")
|
|
81
|
+
result = ef.diff(candidate, expected, keys=["id"], work_dir=private_root)
|
|
82
|
+
assert result.state == "different" and result.complete
|
|
83
|
+
assert result.counts.final
|
|
84
|
+
|
|
85
|
+
# Default report hides values, names and paths. It does not delete the originals.
|
|
86
|
+
report = ef.write_comparison_report(result, Path("comparison-report"))
|
|
87
|
+
print(report.to_text())
|
|
88
|
+
print(ef.read_diff_contract(result).reference)
|
|
89
|
+
|
|
90
|
+
try:
|
|
91
|
+
ef.assert_equivalent(result)
|
|
92
|
+
except ef.EquivalenceDifferentError:
|
|
93
|
+
print("The regression was correctly rejected")
|
|
94
|
+
else:
|
|
95
|
+
raise AssertionError("A different result must not pass")
|
|
96
|
+
|
|
97
|
+
fixed = ef.diff(expected, expected, keys=["id"], work_dir=private_root)
|
|
98
|
+
ef.assert_equivalent(fixed)
|
|
99
|
+
print(fixed.state, fixed.complete)
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Run it once in that clean directory:
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
python -I quickstart.py
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
The first comparison is `different`; the corrected one prints `equivalent True`.
|
|
109
|
+
The key aligns `B` with `B` even though row order differs. Its quantity is 21
|
|
110
|
+
instead of 20. The script catches the deliberate failure only to demonstrate the
|
|
111
|
+
API; real tests should let `assert_equivalent` fail.
|
|
112
|
+
|
|
113
|
+
`comparison-report/` contains `report.json`, `report.txt`, `report.html` and a
|
|
114
|
+
publication inventory. Use a new report directory on repetition. `private-evidence/`
|
|
115
|
+
contains original snapshots and differences and can reveal your data. Do not
|
|
116
|
+
upload it automatically. With these known synthetic values only, explicit
|
|
117
|
+
`ReportOptions(include_values=True, include_metadata=True)` makes the diagnosis
|
|
118
|
+
visible. Review disclosure permission before using those options with real data.
|
|
119
|
+
|
|
120
|
+
## 3. Read states before acting
|
|
121
|
+
|
|
122
|
+
| Comparison state | Meaning | Equivalence gate |
|
|
123
|
+
|---|---|---|
|
|
124
|
+
| `equivalent` | Complete evaluation, no differences under the declared contract | Accepted only if the required guarantee/evidence also passes |
|
|
125
|
+
| `different` | Complete evaluation found a difference or contract violation | Fails |
|
|
126
|
+
| `not_evaluable` | Required judgment cannot be established | Fails, even if `complete=True` |
|
|
127
|
+
|
|
128
|
+
Use `ef.assert_equivalent(result)` or inspect
|
|
129
|
+
`ef.equivalence_decision(result).accepted`. `if result`, `bool(result)` and
|
|
130
|
+
`assert result` raise `TypeError` in every state. A returned object, zero displayed
|
|
131
|
+
examples, a successful HTML export or an integrity reader's exit zero is not an
|
|
132
|
+
equivalence decision.
|
|
133
|
+
|
|
134
|
+
`diff` infers a conservative contract from the right-hand schema, never from a
|
|
135
|
+
search for policies that make the pair agree. Inferred units are `unspecified`,
|
|
136
|
+
numbers are exact, only NULL is a missing-value representation, and nullable is
|
|
137
|
+
a visible default rather than inferred from observed rows. Use reviewed explicit
|
|
138
|
+
`ColumnSpec` definitions for domain units, allowed values and nullability.
|
|
139
|
+
|
|
140
|
+
## 4. Choose only the dependencies you need
|
|
141
|
+
|
|
142
|
+
| Extra | Purpose |
|
|
143
|
+
|---|---|
|
|
144
|
+
| None | Contract models/validation, serialization, CLI and local artifact support |
|
|
145
|
+
| `arrow` | Tabular comparison and Arrow capture/readers |
|
|
146
|
+
| `pandas`, `polars`, `duckdb` | The named native engine plus PyArrow |
|
|
147
|
+
| `engines` | All three native engines plus PyArrow |
|
|
148
|
+
| `ml` | Fit Isolation Forest with scikit-learn and NumPy |
|
|
149
|
+
|
|
150
|
+
Change `[arrow]` in the local wheel command to the extra you need. Use
|
|
151
|
+
`[engines,ml]` when you need both. Extra names do not supply missing binaries in an
|
|
152
|
+
offline wheelhouse. `import equiframe` itself does not import the optional engines,
|
|
153
|
+
Arrow, NumPy or scikit-learn. Missing optional dependencies fail explicitly.
|
|
154
|
+
|
|
155
|
+
Continue with [the three reproducible recipes](recipes.md),
|
|
156
|
+
[API reference](api.md), and [upgrade/failure guidance](upgrading.md).
|