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,171 @@
|
|
|
1
|
+
# Contributing to EquiFrame
|
|
2
|
+
|
|
3
|
+
[Handbook](index.md) · [Compatibility](compatibility.md) · [Release process](releasing.md)
|
|
4
|
+
|
|
5
|
+
The 0.12.4 release contract uses MIT for project-owned code; third-party materials
|
|
6
|
+
retain their notices and licenses. Redistribution rights follow those licenses.
|
|
7
|
+
Hernán Troya (`htroya`) maintains the project and owns releases/security
|
|
8
|
+
coordination on a best-effort basis without a promised backup or response-time SLA.
|
|
9
|
+
|
|
10
|
+
The public repository contains the library source, user documentation and tests.
|
|
11
|
+
Open a nonsensitive issue or contribute a focused patch using your own account.
|
|
12
|
+
Never include credentials, private datasets, models or execution results.
|
|
13
|
+
The benchmark remains a separate package in this repository.
|
|
14
|
+
|
|
15
|
+
The owner has authorized manual TestPyPI/PyPI preparation and publication subject
|
|
16
|
+
to the [release gates](releasing.md). This is not permission for a contributor or
|
|
17
|
+
an ordinary CI run to publish. Historical private candidate notes retain their
|
|
18
|
+
original versions and outcomes.
|
|
19
|
+
|
|
20
|
+
## Boundaries to preserve
|
|
21
|
+
|
|
22
|
+
- Read the API, compatibility and semantic-contract guides before a change
|
|
23
|
+
- Preserve Decimal, currency, keys, multiplicity, NULL/NaN and temporal distinctions
|
|
24
|
+
according to contract; never normalize differences just to pass a test
|
|
25
|
+
- Keep R, M, B, H and O independent. Detectors/profiles must not receive labels,
|
|
26
|
+
mutation definitions or another engine's output. pandas is not an oracle
|
|
27
|
+
- Never map failure, invalid input, missing support or not-estimable output to
|
|
28
|
+
success or no alert. Test fail-closed behavior, not just the happy path
|
|
29
|
+
- Native engines execute their own implementations; do not compute once and
|
|
30
|
+
convert the result to simulate independent implementations
|
|
31
|
+
- Core code must not depend on OCI, SERCOP, the experimental package or a specific
|
|
32
|
+
external service. Use explicit typed ports and trusted registrations
|
|
33
|
+
- Honor component ownership: core/benchmark work does not authorize infrastructure,
|
|
34
|
+
data-gateway or domain-warehouse redesign
|
|
35
|
+
- Do not execute untrusted callbacks, SQL, plugins or models. The library is not a
|
|
36
|
+
sandbox. Do not introduce shared DuckDB files with independent process writers
|
|
37
|
+
- Keep credentials, real datasets, private reports, databases, model binaries and
|
|
38
|
+
environments out of Git. Small identified synthetic fixtures are appropriate
|
|
39
|
+
|
|
40
|
+
## Reproducible local checks
|
|
41
|
+
|
|
42
|
+
The commands below describe checks to run; they do not assert this artifact has
|
|
43
|
+
already passed them. Use an authorized source checkout or the identified sdist,
|
|
44
|
+
Python 3.12 and a suitable `uv` installation. Dependency installation may access
|
|
45
|
+
your configured package index unless a reviewed offline cache is supplied.
|
|
46
|
+
From the core package directory:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
uv sync --locked --all-extras --python 3.12
|
|
50
|
+
uv run --locked --all-extras ruff check .
|
|
51
|
+
uv run --locked --all-extras ruff format --check .
|
|
52
|
+
uv run --locked --all-extras mypy --python-version 3.12
|
|
53
|
+
uv run --locked --all-extras python tools/generate_assets.py --check
|
|
54
|
+
uv run --locked --all-extras pytest -q
|
|
55
|
+
uv run --locked --all-extras python -m build --no-isolation
|
|
56
|
+
uv run --locked --all-extras twine check --strict dist/*.whl dist/*.tar.gz
|
|
57
|
+
uv run --locked --all-extras python tools/verify_distribution.py
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
The distribution verifier uses isolated installed consumers outside the checkout,
|
|
61
|
+
checks runtime bytes, exercises examples and compares the rebuilt wheel from
|
|
62
|
+
sdist. It is distinct from source tests and from a remote CI job. The first-use
|
|
63
|
+
kit verifier preserves deliberate negative recipe exits; do not turn them into
|
|
64
|
+
unconditional success.
|
|
65
|
+
|
|
66
|
+
The candidate driver provides a byte-bound aggregate receipt:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
python tools/check_candidate.py --package . --output /absolute/path/new-checks.json
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Every invocation needs a fresh receipt name and matching log/pytest paths. The
|
|
73
|
+
driver refuses existing output evidence before starting checks and reserves its
|
|
74
|
+
receipt exclusively. After a failed or interrupted attempt, keep that output
|
|
75
|
+
and choose another `--output` name for the retry.
|
|
76
|
+
|
|
77
|
+
The aggregate candidate driver and `release_manifest.py` require a Git checkout
|
|
78
|
+
to bind the complete source tree to a commit. An extracted sdist can run the
|
|
79
|
+
package's lint, types, assets, tests and build checks, but it cannot create that
|
|
80
|
+
Git-bound release receipt by itself. Keep the original source revision and
|
|
81
|
+
artifact receipt from the provider. The benchmark distribution verifier also
|
|
82
|
+
expects the monorepo layout, including the adjacent matching core source and
|
|
83
|
+
built wheel; an isolated benchmark sdist does not supply those inputs.
|
|
84
|
+
|
|
85
|
+
For the benchmark, work from `packages/equiframe-benchmark`, build the matching
|
|
86
|
+
core wheel first, and run the same lint/type/assets/test/build/Twine/distribution
|
|
87
|
+
sequence after:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
uv sync --locked --all-extras --reinstall-package equiframe
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Reinstallation matters when editing a local unreleased candidate with the same
|
|
94
|
+
version string: dependency caches
|
|
95
|
+
can otherwise retain an old local core. The candidate driver checks runtime
|
|
96
|
+
source hashes and reinstalls local dependencies; installed artifact verification
|
|
97
|
+
still consumes the exact wheels, not an editable checkout.
|
|
98
|
+
Published distribution files remain immutable; a local development reinstall
|
|
99
|
+
does not authorize replacing them.
|
|
100
|
+
|
|
101
|
+
Changing dependencies requires reviewed lock changes and the relevant
|
|
102
|
+
`tools/verify_compatibility.py` cells. Minimum/recent direct resolutions, platforms,
|
|
103
|
+
extras, corpus, hashes, failures and skips must be recorded accurately. A narrower
|
|
104
|
+
focused test does not replace all affected checks. Never update a compatibility
|
|
105
|
+
fingerprint automatically just to silence a regression.
|
|
106
|
+
|
|
107
|
+
## Reviewable change procedure
|
|
108
|
+
|
|
109
|
+
1. Describe the problem, affected contract/capability and evidence of failure
|
|
110
|
+
2. Work on a branch based on the agreed candidate/base; identify dependencies
|
|
111
|
+
on unmerged changes. Do not assume the candidate is already on main
|
|
112
|
+
3. Implement real behavior with minimal synthetic regression fixtures, including
|
|
113
|
+
positive, negative, invalid and not-evaluable cases
|
|
114
|
+
4. Update public English usage, reference/limits, schemas and compatibility
|
|
115
|
+
classification when affected. Record observable changes and migration guidance
|
|
116
|
+
5. Preserve historical fixture bytes and unknown-version rejection. New incompatible
|
|
117
|
+
writes need a new format, not retrospective reinterpretation
|
|
118
|
+
6. Run affected source and installed-artifact checks against final bytes and retain
|
|
119
|
+
receipts. Distinguish passed, failed, blocked and unexecuted checks
|
|
120
|
+
7. Request review with scope, rationale, artifacts, test outcomes and known limits.
|
|
121
|
+
A PR convention is not proof of enforced branch protection or independent approval
|
|
122
|
+
|
|
123
|
+
Methodological changes require explicit rationale, version and consequences in
|
|
124
|
+
the repository's decision/traceability documents. Do not describe synthetic
|
|
125
|
+
fixtures, untrained models, planned APIs, pending pilots or unexecuted tests as
|
|
126
|
+
scientific evidence or external acceptance.
|
|
127
|
+
|
|
128
|
+
Public-facing current documentation is English. Historical design and the
|
|
129
|
+
reinforced roadmap can remain Spanish with their original context. Keep the
|
|
130
|
+
installed handbook self-contained; essential instructions must not depend on
|
|
131
|
+
private monorepo links. Run examples against the exact distribution, and label
|
|
132
|
+
signature sketches or consumer-specific request templates as such.
|
|
133
|
+
|
|
134
|
+
## CI and publishing permissions
|
|
135
|
+
|
|
136
|
+
The public repository ships no GitHub Actions workflows, and this release uses
|
|
137
|
+
local manual checks. Pushing a branch or creating a PR does not execute or prove
|
|
138
|
+
a compatibility matrix. Identify the actual command, source, environment and
|
|
139
|
+
artifacts before claiming results. Any future hosted CI requires separate review
|
|
140
|
+
and least privilege; publication remains a separate protected owner decision.
|
|
141
|
+
|
|
142
|
+
Building locally, checking Twine metadata, producing an SBOM or installing by
|
|
143
|
+
local wheel does not publish, reserve a project name or approve licensing.
|
|
144
|
+
Do not upload to PyPI, deploy a service, grant sharing access or activate a remote
|
|
145
|
+
release flow without the specific authorization and completed gates in
|
|
146
|
+
[releasing.md](releasing.md).
|
|
147
|
+
|
|
148
|
+
## Adoption and maintenance evidence
|
|
149
|
+
|
|
150
|
+
The [adoption record checker](adoption.md#check-the-structured-record-locally)
|
|
151
|
+
is a developer-only sdist tool. Its exit 0 establishes input consistency, never
|
|
152
|
+
consent, human independence or adoption. Keep the example registry empty and
|
|
153
|
+
real observations outside Git. The [maintenance process](maintenance.md) requires
|
|
154
|
+
minimal permitted reproductions and separate technical/consumer confirmation;
|
|
155
|
+
Hernán Troya (`htroya`) is the confirmed owner; no backup, response deadline or
|
|
156
|
+
SLA is promised.
|
|
157
|
+
|
|
158
|
+
## Fast source feedback
|
|
159
|
+
|
|
160
|
+
Use the [quick CI layer](fast-ci.md) for bounded PR/change feedback and the
|
|
161
|
+
`tools/check_architecture.py --check` from the source distribution.
|
|
162
|
+
Its smoke receipt is separate from the full candidate/distribution/matrix checks.
|
|
163
|
+
The installed [product journeys](journeys.md) make positive, different and
|
|
164
|
+
unavailable outcomes reproducible without a source checkout.
|
|
165
|
+
|
|
166
|
+
Type-check each selected Python with its own resolved dependency/stub set and
|
|
167
|
+
matching `mypy --python-version X.Y`. The aggregate driver observes that version
|
|
168
|
+
after sync and supplies it automatically. The checked-in minimum target remains
|
|
169
|
+
3.10 and strict mode remains enabled; no error codes or imports are suppressed.
|
|
170
|
+
A 3.11+ stub package requiring newer typing syntax is not evidence about the
|
|
171
|
+
3.10 dependency branch. Each branch must pass under its actual interpreter.
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
# Dependency inventory, licenses and advisory evidence
|
|
2
|
+
|
|
3
|
+
The package metadata declares allowed version ranges; `uv.lock` records exact
|
|
4
|
+
resolutions, including conditional branches for supported environments. Neither
|
|
5
|
+
means that every possible version combination has passed the test matrix.
|
|
6
|
+
Keep the exact Python/platform marker environment with the resolved inventory.
|
|
7
|
+
|
|
8
|
+
The `pandas` and `engines` extras exclude Pandas 3.0.3–3.0.6. Their upstream
|
|
9
|
+
`ZoneInfo.from_file` regression can ignore the supplied rules and silently alter
|
|
10
|
+
historical timestamps; the correction is documented in
|
|
11
|
+
[Pandas 3.1.0](https://pandas.pydata.org/pandas-docs/version/3.1.0/whatsnew/v3.1.0.html).
|
|
12
|
+
The minimum supported Pandas range remains available on Python 3.10. A changed
|
|
13
|
+
resolved profile requires fresh native evidence; previous 3.0.6 receipts retain
|
|
14
|
+
their actual version and outcome.
|
|
15
|
+
|
|
16
|
+
Runtime is deliberately separated from optional engines and ML: base contracts,
|
|
17
|
+
models and CLI depend on Pydantic, Typer and tzdata; Arrow and each native engine
|
|
18
|
+
are opt-in; ML is opt-in; the benchmark is a separate distribution. Build and
|
|
19
|
+
validation tools are development dependencies, not required by a normal core
|
|
20
|
+
import. The benchmark's dependency must resolve to the exact core candidate
|
|
21
|
+
wheel supplied with its evidence, not another private wheel with the same
|
|
22
|
+
version string.
|
|
23
|
+
|
|
24
|
+
TLS trust is also part of the build and advisory-query environment. The
|
|
25
|
+
[Python security notice for the emSign incident](https://discuss.python.org/t/information-for-python-users-regarding-emudhra-emsign-ca-certificate-security-incident/109576)
|
|
26
|
+
requires corrected CA bundles and identifies minimum repaired versions including
|
|
27
|
+
`certifi>=2026.10.19`, `pip>=26.2.2` and `uv>=0.13.4`. The release locks use
|
|
28
|
+
`certifi==2026.10.23`. A standalone tool can embed its own CA bundle, so inspecting
|
|
29
|
+
installed Python distributions alone does not cover `uv` or other native tools.
|
|
30
|
+
Do not disable certificate verification to work around a download failure.
|
|
31
|
+
|
|
32
|
+
Use a maintained Python security patch release and an updated operating-system
|
|
33
|
+
trust store. The same notice recommends Python 3.13.18 (and corrected releases of
|
|
34
|
+
other maintained branches) as an additional mitigation independent of CA bundles.
|
|
35
|
+
The package's Python compatibility floor is not a claim that an end-of-life
|
|
36
|
+
interpreter still receives upstream security fixes. Updating a QA runtime must
|
|
37
|
+
not silently replace a consumer's system interpreter or certificate store.
|
|
38
|
+
|
|
39
|
+
The optional `files` profile adds Pandas/Arrow, openpyxl for XLSX/XLSM, xlrd for
|
|
40
|
+
legacy XLS and defusedxml for XML. Imports occur only when a selected operation
|
|
41
|
+
needs that reader; no automatic installation occurs. Target conversion additionally
|
|
42
|
+
uses the existing `polars` or `duckdb` profile. The exact allowed ranges are in
|
|
43
|
+
the [compatibility table](compatibility.md#declared-runtime-dependencies).
|
|
44
|
+
`equiframe doctor --extra files` diagnoses installation metadata without reading
|
|
45
|
+
user data. File discovery, inference and conversion are documented in
|
|
46
|
+
[the file guide](lectura-conversion.md).
|
|
47
|
+
|
|
48
|
+
The optional [language-R review](r_review.md) uses a user-installed `Rscript`
|
|
49
|
+
and base R. It does not add an R package dependency or install a runtime.
|
|
50
|
+
R's observed version and the reviewer source hash belong to each returned
|
|
51
|
+
review; Python wheel metadata alone cannot identify the external R executable.
|
|
52
|
+
Validation of the 26 October source additions and lock updates is reported
|
|
53
|
+
separately; lock resolution alone does not establish native or semantic behavior.
|
|
54
|
+
|
|
55
|
+
## Reproducible evidence workflow
|
|
56
|
+
|
|
57
|
+
The source distribution carries `tools/dependency_inventory.py` and the pinned
|
|
58
|
+
CycloneDX schemas. Run the tool with the locked core development interpreter.
|
|
59
|
+
`generate` is offline: it inspects the selected package, exact wheel and sdist,
|
|
60
|
+
lock profiles and installed metadata. `scan` is explicitly networked, querying
|
|
61
|
+
version-specific PyPI metadata and OSV for registry dependencies. `verify`
|
|
62
|
+
rederives the inventory, validates the artifact bindings and schemas, and checks
|
|
63
|
+
snapshot consistency/freshness. Consult `--help` for exact options.
|
|
64
|
+
|
|
65
|
+
Run these from the repository root after both packages have been built and their
|
|
66
|
+
locked development environments have been prepared. The following paths use
|
|
67
|
+
POSIX virtual environments; on Windows use the corresponding `Scripts/python.exe`.
|
|
68
|
+
Output directories must be new so an earlier receipt cannot be overwritten.
|
|
69
|
+
|
|
70
|
+
```sh
|
|
71
|
+
PY=.venv/bin/python
|
|
72
|
+
TOOL=tools/dependency_inventory.py
|
|
73
|
+
CORE=.
|
|
74
|
+
BENCH=packages/equiframe-benchmark
|
|
75
|
+
|
|
76
|
+
$PY $TOOL generate --package "$CORE" \
|
|
77
|
+
--artifact "$CORE/dist/equiframe-0.12.4-py3-none-any.whl" \
|
|
78
|
+
--artifact "$CORE/dist/equiframe-0.12.4.tar.gz" \
|
|
79
|
+
--output evidence/dependencies/core
|
|
80
|
+
|
|
81
|
+
$PY $TOOL generate --package "$BENCH" \
|
|
82
|
+
--artifact "$BENCH/dist/equiframe_benchmark-0.12.4-py3-none-any.whl" \
|
|
83
|
+
--artifact "$BENCH/dist/equiframe_benchmark-0.12.4.tar.gz" \
|
|
84
|
+
--environment-python "$BENCH/.venv/bin/python" \
|
|
85
|
+
--local-artifact "$CORE/dist/equiframe-0.12.4-py3-none-any.whl" \
|
|
86
|
+
--output evidence/dependencies/benchmark
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Each directory contains `inventory.json` (`equiframe.dependencies/1.0`) and two
|
|
90
|
+
`<artifact filename>.cdx.json` files. The BOMs are CycloneDX 1.6, validated against
|
|
91
|
+
the unmodified official draft-07 JSON schemas with pinned SHA-256 and a closed,
|
|
92
|
+
local schema registry. They contain a clearly labelled union of profile closures;
|
|
93
|
+
they do not imply that build/dev dependencies are embedded in, or required by,
|
|
94
|
+
the wheel. Each component lists its profile membership. Only explicitly stated,
|
|
95
|
+
valid SPDX expressions are represented as license expressions; other source
|
|
96
|
+
metadata is retained for review rather than converted to an invented license.
|
|
97
|
+
|
|
98
|
+
The tool needs `packaging` and `jsonschema` from the existing core development
|
|
99
|
+
lock. It installs nothing and does not add runtime dependencies. It reads
|
|
100
|
+
installed metadata and license files without importing dependency/project code.
|
|
101
|
+
Declared `License-File` members, including names such as `AUTHORS` and legacy
|
|
102
|
+
`mit.LICENSE`, are collected alongside conventional `LICENSE`, `LICENCE`, copying
|
|
103
|
+
and notice files inside the distribution metadata boundary. Paths outside that
|
|
104
|
+
boundary are not followed. Missing files or declarations still require review;
|
|
105
|
+
collecting a file does not establish a compatible license.
|
|
106
|
+
The interpreter selected by `--environment-python` supplies the observed marker
|
|
107
|
+
environment and distribution metadata. Other-platform lock branches are not
|
|
108
|
+
claimed to have been installed or scanned. Missing installed metadata is recorded
|
|
109
|
+
as unknown; exact lock versions are never relabelled as installed when absent.
|
|
110
|
+
|
|
111
|
+
An advisory refresh requires an inspected public-only allowlist and an offline
|
|
112
|
+
request preview. Create `public-allowlist.json` containing only exact reviewed
|
|
113
|
+
public `name`/`version` objects from the artifact-bound inventory; exclude the
|
|
114
|
+
project, all private consumers/internal packages and any ambiguous provenance.
|
|
115
|
+
A registry label by itself is insufficient. This file and the preview remain
|
|
116
|
+
local; neither the complete inventory nor its metadata is uploaded.
|
|
117
|
+
|
|
118
|
+
```sh
|
|
119
|
+
$PY $TOOL prepare-scan --inventory evidence/dependencies/core/inventory.json \
|
|
120
|
+
--public-allowlist public-allowlist.json --output public-requests.json
|
|
121
|
+
# Inspect public-requests.json: URLs, bodies, anonymous headers and exclusions.
|
|
122
|
+
$PY $TOOL scan --inventory evidence/dependencies/core/inventory.json \
|
|
123
|
+
--public-allowlist public-allowlist.json --request-plan public-requests.json \
|
|
124
|
+
--output evidence/dependencies/core-advisories
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Repeat with the benchmark inventory and its own reviewed allowlist/preview.
|
|
128
|
+
Preparation is offline and proves no provider coverage. Execution rejects a
|
|
129
|
+
changed preview, names absent from the allowlist, private/local sources, extra
|
|
130
|
+
payload fields, URL query/userinfo/insecure destinations and all redirects.
|
|
131
|
+
No project-identifying User-Agent, credentials, cookies or referer is supplied.
|
|
132
|
+
Provider pagination tokens are validated and remain bound to the same query.
|
|
133
|
+
Platform-denied requests must stop; changing a route is not authorization.
|
|
134
|
+
|
|
135
|
+
`scan` writes `advisories.json` (`equiframe.advisories/1.0`) and one snapshot per
|
|
136
|
+
public package/version/provider. It preserves the exact UTF-8 JSON response,
|
|
137
|
+
its SHA-256, parsed content, request, source URL, time and failures. It queries
|
|
138
|
+
PyPI's release endpoint and OSV, retaining GHSA IDs/advisories supplied through
|
|
139
|
+
those sources. It does not claim an independent direct GitHub Advisory API scan.
|
|
140
|
+
Private/local project packages are explicitly excluded from public name lookups.
|
|
141
|
+
The command exits 0 for complete `no_known_advisories`, 2 for `findings` or
|
|
142
|
+
`unknown`, and 1 for invalid inputs. Failure receipts remain available.
|
|
143
|
+
|
|
144
|
+
Reverify the final artifact bytes, lock, selected environment, BOMs and audit:
|
|
145
|
+
|
|
146
|
+
```sh
|
|
147
|
+
$PY $TOOL verify --package "$CORE" \
|
|
148
|
+
--artifact "$CORE/dist/equiframe-0.12.4-py3-none-any.whl" \
|
|
149
|
+
--artifact "$CORE/dist/equiframe-0.12.4.tar.gz" \
|
|
150
|
+
--inventory evidence/dependencies/core/inventory.json \
|
|
151
|
+
--advisories evidence/dependencies/core-advisories/advisories.json \
|
|
152
|
+
--max-age-hours 24 --require-clean
|
|
153
|
+
|
|
154
|
+
$PY $TOOL verify --package "$BENCH" \
|
|
155
|
+
--artifact "$BENCH/dist/equiframe_benchmark-0.12.4-py3-none-any.whl" \
|
|
156
|
+
--artifact "$BENCH/dist/equiframe_benchmark-0.12.4.tar.gz" \
|
|
157
|
+
--environment-python "$BENCH/.venv/bin/python" \
|
|
158
|
+
--local-artifact "$CORE/dist/equiframe-0.12.4-py3-none-any.whl" \
|
|
159
|
+
--inventory evidence/dependencies/benchmark/inventory.json \
|
|
160
|
+
--advisories evidence/dependencies/benchmark-advisories/advisories.json \
|
|
161
|
+
--max-age-hours 24 --require-clean
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
For an offline-only verification, omit `--advisories` and `--require-clean`;
|
|
165
|
+
that result establishes no advisory coverage. `--require-clean` always needs a
|
|
166
|
+
complete fresh audit. Freshness defaults to 24 hours; an explicit larger window
|
|
167
|
+
is bounded at 168 hours and must be justified by release policy. Missing snapshots,
|
|
168
|
+
changed hashes, changed local core wheel, stale timestamps, omitted packages,
|
|
169
|
+
inconsistent summaries and changed source declarations fail verification.
|
|
170
|
+
The verifier reconstructs the expected inventory and BOM instead of trusting
|
|
171
|
+
positive fields in a receipt. Receipts are unsigned: consistent total replacement
|
|
172
|
+
of artifacts and evidence is outside their authenticity guarantee.
|
|
173
|
+
|
|
174
|
+
The evidence distinguishes runtime base, individual extras, all extras, dev and
|
|
175
|
+
build profiles. It records declared requirements, resolved versions, lock and
|
|
176
|
+
artifact hashes, observed dependency metadata and license-file hashes. A
|
|
177
|
+
CycloneDX BOM is tied to each artifact rather than to an unspecified checkout.
|
|
178
|
+
Local project dependencies require an explicit candidate wheel. The schemas
|
|
179
|
+
are retained with source URLs and hashes for offline validation; their upstream
|
|
180
|
+
license notices apply to those schemas, not to EquiFrame.
|
|
181
|
+
|
|
182
|
+
An installed dependency's license expression, classifiers, free-form metadata
|
|
183
|
+
and files may disagree or be incomplete. Preserve those observations and their
|
|
184
|
+
provenance; do not guess a missing license or treat metadata as legal clearance.
|
|
185
|
+
Native wheels can bundle third-party libraries that are not separate Python
|
|
186
|
+
distributions. The Python dependency inventory is not an exhaustive inventory
|
|
187
|
+
of every bundled native component, the operating system or build infrastructure.
|
|
188
|
+
Redistribution review must inspect the applicable binary notices and conditions.
|
|
189
|
+
|
|
190
|
+
The optional legacy XLS reader `xlrd==2.0.2` illustrates why a generic `BSD`
|
|
191
|
+
metadata label is insufficient: its [license text](https://github.com/python-excel/xlrd/blob/2.0.2/LICENSE)
|
|
192
|
+
contains both a later three-clause notice and an earlier notice with advertising
|
|
193
|
+
and retained-acknowledgement conditions. Preserve both when redistributing that
|
|
194
|
+
dependency and retain the required acknowledgement:
|
|
195
|
+
|
|
196
|
+
> This product includes software developed by David Giffin <david@giffin.org>.
|
|
197
|
+
|
|
198
|
+
SciPy binary notices separately identify OpenBLAS/LAPACK, the GCC runtime with
|
|
199
|
+
its runtime exception, and libquadmath under their respective terms. Docutils
|
|
200
|
+
identifies its public-domain files and separately licensed exceptions. These
|
|
201
|
+
notices must not be replaced by EquiFrame's MIT license or collapsed into a
|
|
202
|
+
guessed single SPDX expression. Normal dependency installation retains upstream
|
|
203
|
+
notices; repackaging dependencies requires a separate review of the actual files.
|
|
204
|
+
|
|
205
|
+
## Interpreting advisory results
|
|
206
|
+
|
|
207
|
+
Retain the query time, exact name/version, provider, URL, returned bytes/hash and
|
|
208
|
+
errors. A successful response with no listed advisories means only that the
|
|
209
|
+
provider returned none for that version at that time. Missing releases, blocked
|
|
210
|
+
networks, HTTP errors, incomplete provider coverage, stale or malformed evidence
|
|
211
|
+
are **unknown**, never zero vulnerabilities. A provider identifier is not a
|
|
212
|
+
confirmed exploitability assessment of EquiFrame's usage.
|
|
213
|
+
|
|
214
|
+
Inspect primary advisory records for affected/fixed ranges, severity and relevant
|
|
215
|
+
runtime paths. Record each correction, justified exception or unresolved result.
|
|
216
|
+
Changing a dependency requires rebuilding the lock/first-use pins as applicable,
|
|
217
|
+
rerunning the affected profiles and full release checks, and regenerating all
|
|
218
|
+
artifact-bound evidence. Do not suppress an advisory merely to obtain a green
|
|
219
|
+
release status. Recheck close to publication; an old snapshot cannot establish
|
|
220
|
+
current safety. `--require-clean` fails closed if coverage is unknown, findings
|
|
221
|
+
remain or the snapshot is stale.
|
|
222
|
+
|
|
223
|
+
## Release limits
|
|
224
|
+
|
|
225
|
+
The inventory and advisory scan are separate from source review and the partial
|
|
226
|
+
historical STEP9 assessment. They do not prove publisher identity, grant rights
|
|
227
|
+
over dependencies or establish that the software is secure. EquiFrame's own
|
|
228
|
+
license and bundled notices do not replace third-party redistribution conditions.
|
|
229
|
+
Publication follows the [release decisions and gates](releasing.md), including
|
|
230
|
+
resolution of real findings and explicit treatment of unknown coverage. Bind the
|
|
231
|
+
completed checks to the final four artifact hashes; do not transfer acceptance
|
|
232
|
+
from an earlier wheel, sdist, dependency resolution or source snapshot.
|
|
233
|
+
|
|
234
|
+
Standards and provider documentation:
|
|
235
|
+
[CycloneDX 1.6](https://cyclonedx.org/docs/1.6/json/),
|
|
236
|
+
[PyPI JSON API](https://docs.pypi.org/api/json/),
|
|
237
|
+
[OSV query API](https://google.github.io/osv.dev/api/)
|
equiframe/docs/eda.md
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
# Optional standalone dataset EDA
|
|
2
|
+
|
|
3
|
+
[Handbook](index.md) · [Outcome gates](outcome-gates.md) · [Compatibility](compatibility.md)
|
|
4
|
+
|
|
5
|
+
Private Alpha **0.12.0a14** introduced `equiframe.eda`; that subpackage remains
|
|
6
|
+
experimental in 0.12.4, separately from the stable comparison/migration interfaces.
|
|
7
|
+
It diagnoses one fixed dataset independently of ETL or a migration. It never
|
|
8
|
+
changes a plan, tolerance, expected output, detector bundle or publication gate.
|
|
9
|
+
Install the identified wheel and its `eda` extra (DuckDB and Arrow),
|
|
10
|
+
or `eda-charts` for portable Plotly HTML. No public PyPI release is implied.
|
|
11
|
+
Imports remain lazy: importing EquiFrame, EDA contracts or CLI does not import
|
|
12
|
+
DuckDB, Arrow, Plotly or the ML engines.
|
|
13
|
+
|
|
14
|
+
## Python API
|
|
15
|
+
|
|
16
|
+
```python
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
from equiframe.eda import EdaConfig, NumericRule, Source, analyze, read_result
|
|
19
|
+
|
|
20
|
+
result = analyze(
|
|
21
|
+
Source(path="/absolute/input/numbers.parquet", snapshot_id="numbers-v1"),
|
|
22
|
+
config=EdaConfig(numeric=(NumericRule(column="value", outliers="iqr"),)),
|
|
23
|
+
output=Path("/absolute/private-runs/numbers-run-001"),
|
|
24
|
+
)
|
|
25
|
+
print(result.state, result.reason) # Inspect each metric's availability as well.
|
|
26
|
+
checked = read_result(Path("/absolute/private-runs/numbers-run-001"))
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Paths above are placeholders, not proof of execution. The supplied synthetic
|
|
30
|
+
example uses real generated CSV, independent expected counts and exact money:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
python examples/eda_generic.py --work-dir /absolute/new-private-example
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
The wheel includes `equiframe/examples/integrations/eda_generic.py`; extract
|
|
37
|
+
that resource into a fresh project to run it outside the checkout. Files and
|
|
38
|
+
reports remain private. Use a new work directory every time.
|
|
39
|
+
|
|
40
|
+
`analyze_artifact(TableArtifact, config=..., output=...)` reuses a captured
|
|
41
|
+
table's SHA/size without making an execution. `analyze_migration(path,
|
|
42
|
+
side="source"|"target", config=..., output=...)` first calls the existing verified
|
|
43
|
+
migration/bundle reader. It resolves only an inventoried captured output and
|
|
44
|
+
records its original evidence identity/state separately. Revalidation precedes
|
|
45
|
+
the EDA commit marker. A changed evidence document makes EDA fail; it does not
|
|
46
|
+
rewrite the original. Existing index artifacts are not profiled; the link says so.
|
|
47
|
+
Standalone ETL input/output files can be diagnosed in separate runs with the
|
|
48
|
+
same explicit config. Their profiles are diagnostics, not a second verifier.
|
|
49
|
+
|
|
50
|
+
## CLI
|
|
51
|
+
|
|
52
|
+
The same implementation is exposed as `equiframe eda` and `equiframe-eda`:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
equiframe eda run input.parquet --output /private/runs/new-run \
|
|
56
|
+
--snapshot-id snapshot-v1 --expected-sha256 ACTUAL_TRUSTED_SHA \
|
|
57
|
+
--config eda-config.json
|
|
58
|
+
equiframe eda inspect /private/runs/new-run
|
|
59
|
+
equiframe eda migration /private/migration --side target \
|
|
60
|
+
--output /private/runs/new-migration-eda --config eda-config.json
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
`run`/`migration`: 0 completed diagnostics, 2 invalid configuration/preflight,
|
|
64
|
+
3 persisted unavailable/failed/cancelled diagnostics. `inspect`: 0 intact
|
|
65
|
+
closed evidence, including stored unavailable results; 3 integrity/read failure.
|
|
66
|
+
None of these codes authorizes a DW or establishes equivalence/correctness.
|
|
67
|
+
API results reject boolean evaluation. Compare full content through the existing
|
|
68
|
+
`diff`/`compare`/Verify APIs and use their explicit assertions/outcomes.
|
|
69
|
+
|
|
70
|
+
## Original representation and conversion
|
|
71
|
+
|
|
72
|
+
Parquet and Arrow IPC file snapshots admit scalar representations the initial
|
|
73
|
+
backend can preserve; CSV is explicit UTF-8/header/delimiter text, including
|
|
74
|
+
empty fields and textual `NaN`. Original names are checked before DuckDB can
|
|
75
|
+
deduplicate them. Case-insensitive/reserved-name collisions are rejected.
|
|
76
|
+
The MVP admits raw null, boolean, integer, float32/64, string/large string,
|
|
77
|
+
date32, naive second/millisecond/microsecond timestamps and decimals with
|
|
78
|
+
precision at most 38 and nonnegative scale within precision. Other raw types
|
|
79
|
+
(including time, duration, nested/binary/dictionary types, date64, float16,
|
|
80
|
+
nanosecond/zoned timestamps and wider decimals) remain explicitly unavailable
|
|
81
|
+
because the report/transport cannot preserve those types faithfully.
|
|
82
|
+
Timestamp strings remain strings in the raw profile.
|
|
83
|
+
|
|
84
|
+
`Conversion` creates a new column with original text retained. Decimal requires
|
|
85
|
+
plain decimal text within configured precision/scale; excess fraction digits,
|
|
86
|
+
overflow and invalid lexemes are counted, never rounded. Integer requires
|
|
87
|
+
integral text; date requires ISO date; timestamp requires a valid explicit
|
|
88
|
+
offset/Z and at most six fraction digits. Original offsets/text remain intact,
|
|
89
|
+
with derived instants in UTC. Blank is invalid unless `empty="missing"` is
|
|
90
|
+
declared. No identifiers are converted. Unknown NULL distinctions lost by an
|
|
91
|
+
export cannot be reconstructed. `typed.parquet` is a separate derived artifact.
|
|
92
|
+
|
|
93
|
+
## Meaning of results
|
|
94
|
+
|
|
95
|
+
Raw profiles distinguish NULL, numeric NaN, empty text, numeric zero and
|
|
96
|
+
nonfinite values. Valid excludes NULL/NaN/empty/nonfinite; distinct present
|
|
97
|
+
excludes NULL/NaN and retains empty text. Each count/rate records its row
|
|
98
|
+
denominator; an empty denominator has no rate. Nonfinite includes NaN, so
|
|
99
|
+
these two categories overlap and must not be summed as disjoint populations.
|
|
100
|
+
Frequencies are bounded top categories with complete counts, not sampled counts.
|
|
101
|
+
|
|
102
|
+
Full-row repetitions and declared keys report repeated groups, involved rows,
|
|
103
|
+
excess rows and denominator. Key policy includes/excludes/rejects incomplete
|
|
104
|
+
NULL/NaN and optionally empty text keys. `require_unique=False` records an
|
|
105
|
+
observation: repeated OCID/history is not automatically an error. Nothing is
|
|
106
|
+
removed. Examples and zero-based row references are bounded and tied to the
|
|
107
|
+
snapshot hash; counts scan the complete table.
|
|
108
|
+
|
|
109
|
+
`NumericRule` selects a native numeric or explicitly converted column and
|
|
110
|
+
comparable groups. Money requires Decimal and text currency grouping; missing
|
|
111
|
+
currency groups report unavailable counts without pooling amounts. Group types
|
|
112
|
+
are text/bool/64-bit integer/Decimal/finite float; other types are explicit
|
|
113
|
+
capability limitations. Groups above `max_groups` are not silently dropped.
|
|
114
|
+
|
|
115
|
+
Integer/Decimal sum, min/max and **discrete quantiles** are exact. Quantiles use
|
|
116
|
+
DuckDB `quantile_disc`, Hyndman–Fan type 1, including the discrete median. Mean
|
|
117
|
+
also records the exact sum/count rational for integer/Decimal. Float64 mean,
|
|
118
|
+
stddev and visualization/histogram binning are labeled approximate. Population
|
|
119
|
+
or sample stddev is explicit. NULL/nonfinite are excluded with counts; failed
|
|
120
|
+
conversions are recorded separately. Approximate display never changes money.
|
|
121
|
+
|
|
122
|
+
IQR uses `[Q1 − multiplier×IQR, Q3 + multiplier×IQR]`; unscaled MAD uses median
|
|
123
|
+
± multiplier×median absolute deviation. Bounds are strict: equality is not an
|
|
124
|
+
outlier. Support minimum, method and multiplier are recorded. Insufficient
|
|
125
|
+
support, zero dispersion, missing comparable group or unrepresentable exact
|
|
126
|
+
bound leaves a reason and **count=null**, never zero alerts. Decimal bindings
|
|
127
|
+
use the existing typed transport guard; no float fallback for exact money.
|
|
128
|
+
Only transient bounds may remove exact trailing zeros to fit native precision.
|
|
129
|
+
An outlier remains a case to investigate, including legitimate extremes.
|
|
130
|
+
|
|
131
|
+
Unavailable requested metrics give run state `not_evaluable` while preserving
|
|
132
|
+
calculated quality and available statistics. Failure, cancellation and source
|
|
133
|
+
changes remain distinct. A completed run without findings does not prove a
|
|
134
|
+
transformation correct. Two different tables can have identical statistics;
|
|
135
|
+
two engines can agree on the same error. R/M/B/H/O and model fitting are unchanged.
|
|
136
|
+
|
|
137
|
+
## Resources and evidence
|
|
138
|
+
|
|
139
|
+
Source, output, manifest and evidence paths reject symlinks and Windows reparse
|
|
140
|
+
points, including directory ancestors, before resolving the path. Source-delivery
|
|
141
|
+
members must be normalized relative paths inside that delivery. The delivery
|
|
142
|
+
manifest is limited to 16 MiB and 2,000 entries; its trusted SHA-256 identifies
|
|
143
|
+
the exact bytes read. These checks do not grant operating-system access or make
|
|
144
|
+
this library a sandbox for untrusted callbacks.
|
|
145
|
+
|
|
146
|
+
`Resources` records memory, threads, timeout, temp spill, input bytes/rows,
|
|
147
|
+
columns/groups, top categories, examples, histogram bins and chart rows/bytes.
|
|
148
|
+
DuckDB memory controls its buffer manager, not process RSS. Temporary-disk cap
|
|
149
|
+
covers DuckDB spill; fixed snapshots, typed files and reports use extra disk.
|
|
150
|
+
Byte/row/group caps and callback cancellation are cooperative. A timer
|
|
151
|
+
interrupts DuckDB queries; callbacks are checked before/after operations and
|
|
152
|
+
chart exports, without promising immediate preemption or hard RSS quotas.
|
|
153
|
+
|
|
154
|
+
Every exclusive run writes config/source, fixed snapshot, optional typed
|
|
155
|
+
Parquet, findings/summary JSON, HTML and a closed hashed manifest. A partial
|
|
156
|
+
snapshot is labeled `snapshot_complete=False`. The final manifest is the
|
|
157
|
+
commit marker: no readable completed run without it. Publication I/O failure
|
|
158
|
+
can leave an interrupted directory that the reader rejects; do not reuse it.
|
|
159
|
+
`calculation_elapsed_seconds` and elapsed time through report preparation are
|
|
160
|
+
separate; filesystem commit overhead is not a performance guarantee. Report
|
|
161
|
+
budgets can produce an unavailable HTML stub with full JSON diagnostics.
|
|
162
|
+
|
|
163
|
+
HTML embeds Plotly JavaScript locally. Full histograms and quality counts are
|
|
164
|
+
distinct from the declared first-finite-row sample used for box/scatter display;
|
|
165
|
+
that sample is not representative and its box quartiles are not population
|
|
166
|
+
quantiles. Plotly is never required by migration, comparison or Verify.
|