openstatspec 0.2.0__tar.gz → 0.3.0__tar.gz

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 (57) hide show
  1. {openstatspec-0.2.0 → openstatspec-0.3.0}/.github/workflows/ci.yml +23 -10
  2. {openstatspec-0.2.0 → openstatspec-0.3.0}/.github/workflows/release.yml +1 -1
  3. {openstatspec-0.2.0 → openstatspec-0.3.0}/CHANGELOG.md +33 -0
  4. {openstatspec-0.2.0 → openstatspec-0.3.0}/PKG-INFO +74 -5
  5. {openstatspec-0.2.0 → openstatspec-0.3.0}/README.md +73 -4
  6. openstatspec-0.3.0/docs/in-place-transformation.md +41 -0
  7. {openstatspec-0.2.0 → openstatspec-0.3.0}/docs/release-readiness.md +25 -15
  8. {openstatspec-0.2.0 → openstatspec-0.3.0}/docs/sav-profile.md +21 -6
  9. {openstatspec-0.2.0 → openstatspec-0.3.0}/pyproject.toml +1 -1
  10. openstatspec-0.3.0/src/openstatspec/__init__.py +32 -0
  11. {openstatspec-0.2.0 → openstatspec-0.3.0}/src/openstatspec/api.py +30 -1
  12. {openstatspec-0.2.0 → openstatspec-0.3.0}/src/openstatspec/cli.py +30 -1
  13. {openstatspec-0.2.0 → openstatspec-0.3.0}/src/openstatspec/sql/capabilities.py +42 -16
  14. openstatspec-0.3.0/src/openstatspec/sql/inplace_transform.py +556 -0
  15. openstatspec-0.3.0/src/openstatspec/transform/__init__.py +33 -0
  16. openstatspec-0.3.0/src/openstatspec/transform/binding.py +298 -0
  17. openstatspec-0.3.0/src/openstatspec/transform/compiler.py +50 -0
  18. openstatspec-0.3.0/src/openstatspec/transform/errors.py +59 -0
  19. openstatspec-0.3.0/src/openstatspec/transform/plan.py +416 -0
  20. openstatspec-0.3.0/src/openstatspec/transform/syntax.py +478 -0
  21. {openstatspec-0.2.0 → openstatspec-0.3.0}/tests/test_cli.py +3 -3
  22. openstatspec-0.3.0/tests/test_inplace_transform.py +309 -0
  23. {openstatspec-0.2.0 → openstatspec-0.3.0}/tests/test_sql_profiles.py +122 -25
  24. openstatspec-0.3.0/tests/test_transform_frontend.py +330 -0
  25. openstatspec-0.2.0/src/openstatspec/__init__.py +0 -22
  26. {openstatspec-0.2.0 → openstatspec-0.3.0}/.github/verify_release_ref.py +0 -0
  27. {openstatspec-0.2.0 → openstatspec-0.3.0}/.gitignore +0 -0
  28. {openstatspec-0.2.0 → openstatspec-0.3.0}/THIRD_PARTY_NOTICES.md +0 -0
  29. {openstatspec-0.2.0 → openstatspec-0.3.0}/docs/architecture.md +0 -0
  30. {openstatspec-0.2.0 → openstatspec-0.3.0}/docs/pyspssio-spike.md +0 -0
  31. {openstatspec-0.2.0 → openstatspec-0.3.0}/docs/sql-transformation-workflow.md +0 -0
  32. {openstatspec-0.2.0 → openstatspec-0.3.0}/src/openstatspec/core/__init__.py +0 -0
  33. {openstatspec-0.2.0 → openstatspec-0.3.0}/src/openstatspec/core/results.py +0 -0
  34. {openstatspec-0.2.0 → openstatspec-0.3.0}/src/openstatspec/spss/__init__.py +0 -0
  35. {openstatspec-0.2.0 → openstatspec-0.3.0}/src/openstatspec/spss/dictionary.py +0 -0
  36. {openstatspec-0.2.0 → openstatspec-0.3.0}/src/openstatspec/spss/raw_dictionary.py +0 -0
  37. {openstatspec-0.2.0 → openstatspec-0.3.0}/src/openstatspec/spss/sav.py +0 -0
  38. {openstatspec-0.2.0 → openstatspec-0.3.0}/src/openstatspec/sql/__init__.py +0 -0
  39. {openstatspec-0.2.0 → openstatspec-0.3.0}/src/openstatspec/sql/catalog_api.py +0 -0
  40. {openstatspec-0.2.0 → openstatspec-0.3.0}/src/openstatspec/sql/normative.py +0 -0
  41. {openstatspec-0.2.0 → openstatspec-0.3.0}/src/openstatspec/sql/profiles.py +0 -0
  42. {openstatspec-0.2.0 → openstatspec-0.3.0}/src/openstatspec/sql/wide.py +0 -0
  43. {openstatspec-0.2.0 → openstatspec-0.3.0}/src/openstatspec/sql/workflow.py +0 -0
  44. {openstatspec-0.2.0 → openstatspec-0.3.0}/tests/conformance.py +0 -0
  45. {openstatspec-0.2.0 → openstatspec-0.3.0}/tests/test_atomic_import.py +0 -0
  46. {openstatspec-0.2.0 → openstatspec-0.3.0}/tests/test_attribute_catalog.py +0 -0
  47. {openstatspec-0.2.0 → openstatspec-0.3.0}/tests/test_document_round_trip.py +0 -0
  48. {openstatspec-0.2.0 → openstatspec-0.3.0}/tests/test_loss_reports.py +0 -0
  49. {openstatspec-0.2.0 → openstatspec-0.3.0}/tests/test_normative_catalog.py +0 -0
  50. {openstatspec-0.2.0 → openstatspec-0.3.0}/tests/test_official_conformance.py +0 -0
  51. {openstatspec-0.2.0 → openstatspec-0.3.0}/tests/test_pyspssio_catalog_authority.py +0 -0
  52. {openstatspec-0.2.0 → openstatspec-0.3.0}/tests/test_release_ref.py +0 -0
  53. {openstatspec-0.2.0 → openstatspec-0.3.0}/tests/test_sav_sqlite.py +0 -0
  54. {openstatspec-0.2.0 → openstatspec-0.3.0}/tests/test_spss_catalog_preflight.py +0 -0
  55. {openstatspec-0.2.0 → openstatspec-0.3.0}/tests/test_sql_services.py +0 -0
  56. {openstatspec-0.2.0 → openstatspec-0.3.0}/tests/test_sql_workflow.py +0 -0
  57. {openstatspec-0.2.0 → openstatspec-0.3.0}/tests/test_vls_compatible_names.py +0 -0
@@ -20,7 +20,7 @@ jobs:
20
20
  uses: actions/checkout@v7
21
21
  with: &specification-checkout
22
22
  repository: OpenStatSpec/specification
23
- ref: fef0dc6f4b17ff7141dad3f49d0524c63efbfed5
23
+ ref: 79339ec3d8f8aa81789b7e85f6b8afa6f1374e50
24
24
  path: openstatspec-specification
25
25
  - name: Checkout required SPSS engine
26
26
  uses: actions/checkout@v7
@@ -63,7 +63,7 @@ jobs:
63
63
  strategy:
64
64
  fail-fast: false
65
65
  matrix:
66
- postgres: ["17", "18"]
66
+ postgres: ["17.10", "18.4"]
67
67
  services:
68
68
  postgres:
69
69
  image: postgres:${{ matrix.postgres }}
@@ -77,6 +77,7 @@ jobs:
77
77
  --health-interval 10s --health-timeout 5s --health-retries 5
78
78
  env:
79
79
  OPENSTATSPEC_POSTGRES_URL: postgresql+psycopg://openstatspec:openstatspec@localhost:5432/openstatspec
80
+ OPENSTATSPEC_EXPECTED_POSTGRES_VERSION: ${{ matrix.postgres }}
80
81
  steps: &sql-test-steps
81
82
  - uses: actions/checkout@v7
82
83
  - name: Checkout OpenStatSpec specification fixtures
@@ -99,7 +100,7 @@ jobs:
99
100
  strategy:
100
101
  fail-fast: false
101
102
  matrix:
102
- mysql: ["8.4", "9.7"]
103
+ mysql: ["8.4.11", "9.7.2"]
103
104
  services:
104
105
  mysql:
105
106
  image: mysql:${{ matrix.mysql }}
@@ -114,6 +115,7 @@ jobs:
114
115
  --health-interval 10s --health-timeout 5s --health-retries 10
115
116
  env:
116
117
  OPENSTATSPEC_MYSQL_URL: mysql+pymysql://openstatspec:openstatspec@localhost:3306/openstatspec
118
+ OPENSTATSPEC_EXPECTED_MYSQL_VERSION: ${{ matrix.mysql }}
117
119
  steps: *sql-test-steps
118
120
 
119
121
  mariadb-integration:
@@ -122,7 +124,7 @@ jobs:
122
124
  strategy:
123
125
  fail-fast: false
124
126
  matrix:
125
- mariadb: ["11.4", "11.8", "12.3"]
127
+ mariadb: ["11.4.12", "11.8.8", "12.3.2"]
126
128
  services:
127
129
  mariadb:
128
130
  image: mariadb:${{ matrix.mariadb }}
@@ -137,13 +139,24 @@ jobs:
137
139
  --health-interval 10s --health-timeout 5s --health-retries 10
138
140
  env:
139
141
  OPENSTATSPEC_MARIADB_URL: mysql+pymysql://openstatspec:openstatspec@localhost:3306/openstatspec
142
+ OPENSTATSPEC_EXPECTED_MARIADB_VERSION: ${{ matrix.mariadb }}
140
143
  steps: *sql-test-steps
141
144
 
142
145
  dolt-integration:
143
- name: Dolt 2.2.2 integration
146
+ name: Dolt ${{ matrix.dolt }} integration
144
147
  runs-on: ubuntu-latest
148
+ strategy:
149
+ fail-fast: false
150
+ matrix:
151
+ include:
152
+ - dolt: "2.2.2"
153
+ image: dolthub/dolt:2.2.2@sha256:ae85afdd95317f0a982cab87fa3092a5a2e6689bc5de822ad7ae4f65b86d39a1
154
+ - dolt: "2.2.3"
155
+ image: dolthub/dolt:2.2.3@sha256:1a651e738a2e7275b9c69fec8c5f42c6e23954314405c412f4dc9287ee7c0080
145
156
  env:
146
157
  OPENSTATSPEC_DOLT_URL: mysql+pymysql://openstatspec:openstatspec@127.0.0.1:13308/openstatspec
158
+ OPENSTATSPEC_EXPECTED_DOLT_VERSION: ${{ matrix.dolt }}
159
+ OPENSTATSPEC_DOLT_IMAGE: ${{ matrix.image }}
147
160
  steps:
148
161
  - uses: actions/checkout@v7
149
162
  - name: Checkout OpenStatSpec specification fixtures
@@ -155,29 +168,29 @@ jobs:
155
168
  - uses: actions/setup-python@v7
156
169
  with:
157
170
  python-version: "3.12"
158
- - name: Initialize Dolt 2.2.2
171
+ - name: Initialize Dolt ${{ matrix.dolt }}
159
172
  run: |
160
173
  mkdir -p "$RUNNER_TEMP/openstatspec-dolt"
161
174
  docker run --rm \
162
175
  --volume "$RUNNER_TEMP/openstatspec-dolt:/var/lib/dolt" \
163
176
  --workdir /var/lib/dolt \
164
- dolthub/dolt:2.2.2 init \
177
+ "$OPENSTATSPEC_DOLT_IMAGE" init \
165
178
  --name "OpenStatSpec CI" --email "ci@openstatspec.org"
166
179
  docker run --rm \
167
180
  --volume "$RUNNER_TEMP/openstatspec-dolt:/var/lib/dolt" \
168
181
  --workdir /var/lib/dolt \
169
- dolthub/dolt:2.2.2 sql \
182
+ "$OPENSTATSPEC_DOLT_IMAGE" sql \
170
183
  -q "CREATE DATABASE openstatspec"
171
184
  docker run --rm \
172
185
  --volume "$RUNNER_TEMP/openstatspec-dolt:/var/lib/dolt" \
173
186
  --workdir /var/lib/dolt \
174
- dolthub/dolt:2.2.2 sql \
187
+ "$OPENSTATSPEC_DOLT_IMAGE" sql \
175
188
  -q "CREATE USER 'openstatspec'@'%' IDENTIFIED BY 'openstatspec'; GRANT ALL PRIVILEGES ON openstatspec.* TO 'openstatspec'@'%'"
176
189
  docker run --detach --name openstatspec-dolt \
177
190
  --publish 127.0.0.1:13308:3306 \
178
191
  --volume "$RUNNER_TEMP/openstatspec-dolt:/var/lib/dolt" \
179
192
  --workdir /var/lib/dolt \
180
- dolthub/dolt:2.2.2 sql-server -H 0.0.0.0 -l warning
193
+ "$OPENSTATSPEC_DOLT_IMAGE" sql-server -H 0.0.0.0 -l warning
181
194
  - run: python -m pip install --upgrade pip
182
195
  - run: python -m pip install ./openstatspec-pyspssio
183
196
  - run: python -m pip install -e ".[dev,sql]"
@@ -47,7 +47,7 @@ jobs:
47
47
  uses: actions/checkout@v7
48
48
  with:
49
49
  repository: OpenStatSpec/specification
50
- ref: fef0dc6f4b17ff7141dad3f49d0524c63efbfed5
50
+ ref: 79339ec3d8f8aa81789b7e85f6b8afa6f1374e50
51
51
  path: openstatspec-specification
52
52
  - name: Checkout required SPSS engine
53
53
  uses: actions/checkout@v7
@@ -2,6 +2,39 @@
2
2
 
3
3
  All notable changes to this reference implementation are documented here.
4
4
 
5
+ ## 0.3.0 — 2026-07-31
6
+
7
+ ### Added
8
+
9
+ - Added a bounded SPSS-like `RECODE`, `VARIABLE LABELS`, and `VALUE LABELS`
10
+ parser with stable diagnostics and conformance fixtures.
11
+ - Added canonical Transformation Plan serialization, RFC 8785 hashes, schema
12
+ binding, deterministic typed operations, and an agent-facing CLI/API.
13
+ - Added product-neutral in-place execution with same dataset/table identity,
14
+ direct data and metadata mutation, and compact operation audit. Dolt adds
15
+ expected branch/HEAD and clean-working-set checks.
16
+
17
+ ### Changed
18
+
19
+ - Version history, diff, rollback, restoration, and commit remain database
20
+ responsibilities; the transformer creates no derived/copy/snapshot/recovery
21
+ layer and performs no `DOLT_COMMIT`.
22
+ - SQL server support now distinguishes conservative family claims from exact
23
+ CI evidence: PostgreSQL 17.x/18.x at 17.10/18.4, MySQL 8.4.x/9.7.x at
24
+ 8.4.11/9.7.2, and MariaDB 11.4.x/11.8.x/12.3.x at
25
+ 11.4.12/11.8.8/12.3.2. Each service job verifies the live normalized version.
26
+ - Dolt remains an independent core profile, now claiming canonical stable
27
+ versions `>=2.2.2,<2.3.0` and running its complete service suite at exact
28
+ versions 2.2.2 and 2.2.3 from immutable container-image pins.
29
+ SQLite retains its core `>=3.24.0,<4.0.0` and optional workflow
30
+ `>=3.35.0,<4.0.0` tiers. MSSQL remains unsupported and roadmap-only.
31
+
32
+ ### Specification basis
33
+
34
+ - CI, release validation, and machine-readable capabilities use OpenStatSpec
35
+ specification release `v0.2.0` at exact commit
36
+ `79339ec3d8f8aa81789b7e85f6b8afa6f1374e50`.
37
+
5
38
  ## 0.2.0 — 2026-07-30
6
39
 
7
40
  This release extends the reference adapter while keeping imported source
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: openstatspec
3
- Version: 0.2.0
3
+ Version: 0.3.0
4
4
  Summary: Reference adapter for the OpenStatSpec relational contract
5
5
  Author: OpenStatSpec
6
6
  License: Apache-2.0
@@ -69,12 +69,58 @@ derived datasets through a public catalog API. It uses a separate profile
69
69
  catalog and never presents SQL output as an imported source dataset.
70
70
  Workflow operations support SQLite only in this milestone and fail closed on
71
71
  PostgreSQL/MySQL/MariaDB; core import/export database support is unchanged.
72
+ The core SQLite import/export profile accepts SQLite `>=3.24.0,<4.0.0`; the
73
+ optional transformation workflow deliberately has the narrower
74
+ `>=3.35.0,<4.0.0` runtime preflight. These independent tiers do not change the
75
+ server-profile matrix. Microsoft SQL Server is not supported; its future
76
+ dialect is scoped only in the specification's
77
+ [MSSQL roadmap](https://github.com/OpenStatSpec/specification/blob/main/docs/mssql-dialect-roadmap.md).
72
78
 
73
79
  See [the SQL transformation workflow](docs/sql-transformation-workflow.md) for
74
80
  Python and CLI examples, migration behavior, hashing, atomicity, and the exact
75
81
  implemented capability boundary.
76
82
 
77
- ## 0.2.0 support status
83
+ ## SPSS-like transformation frontend
84
+
85
+ The transformation frontend accepts `RECODE`, `VARIABLE LABELS`, and
86
+ `VALUE LABELS`, lowers them to a canonical OpenStatSpec Transformation Plan,
87
+ and mutates the same logical dataset and physical wide table. SQLite,
88
+ PostgreSQL, MySQL, MariaDB, and Dolt connections are allowed. It creates no
89
+ derived dataset, copied table, snapshot, or OpenStatSpec rollback/version layer.
90
+
91
+ Install the compact operation-audit relation separately, then apply syntax:
92
+
93
+ ```python
94
+ from openstatspec import (
95
+ apply_spss_in_place,
96
+ install_in_place_transformation_schema,
97
+ )
98
+
99
+ database_url = "postgresql+psycopg://user:password@host/database"
100
+ install_in_place_transformation_schema(database_url=database_url)
101
+ result = apply_spss_in_place(
102
+ database_url=database_url,
103
+ dataset_id="...",
104
+ actor="agent@example.org",
105
+ source_text="""
106
+ RECODE age (18 THRU 34 = 1) (35 THRU 64 = 2) INTO age_group.
107
+ VARIABLE LABELS age_group 'Age group'.
108
+ VALUE LABELS age_group 1 '18-34' 2 '35-64'.
109
+ """,
110
+ )
111
+ ```
112
+
113
+ Existing-target recodes and metadata mutations use direct DML. SQLite and
114
+ PostgreSQL may also add a target column in the same native transaction. MySQL,
115
+ MariaDB, and Dolt reject such schema-changing plans before mutation because
116
+ their implicit-commit DDL could otherwise leave a partial apply. On Dolt, the
117
+ caller additionally supplies expected branch and HEAD identities, and the
118
+ working set must be clean. The transformer never calls `DOLT_COMMIT`.
119
+
120
+ See [in-place transformations](docs/in-place-transformation.md) for the full
121
+ execution boundary and CLI form.
122
+
123
+ ## Current support status
78
124
 
79
125
  The adapter requires `openstatspec-pyspssio==0.5.1.post2` as its sole SPSS
80
126
  engine. Its import module remains `pyspssio`; the exact source commit is recorded
@@ -82,13 +128,36 @@ in operation metadata. There is no fallback reader or writer. It supports unencr
82
128
  SAV/ZSAV export for the semantics exposed by that engine. SQLite is the local
83
129
  reference path.
84
130
  PostgreSQL, MySQL, MariaDB, and Dolt are each covered by separate service-backed CI
85
- conformance checks. Dolt support is an independent core profile pinned to 2.2.2;
86
- other Dolt versions and unknown MySQL-wire products fail closed. Use these explicit SQLAlchemy URLs:
131
+ conformance checks. Dolt support is an independent core profile for the
132
+ canonical stable range `>=2.2.2,<2.3.0`; earlier patches, other families,
133
+ noncanonical versions, and unknown MySQL-wire products fail closed.
134
+
135
+ The supported family claims are broader than the deliberately exact CI
136
+ evidence points: PostgreSQL 17.x/18.x is exercised at 17.10/18.4, MySQL
137
+ 8.4.x/9.7.x at 8.4.11/9.7.2, and MariaDB 11.4.x/11.8.x/12.3.x at
138
+ 11.4.12/11.8.8/12.3.2. Each service job checks the normalized live server
139
+ version against its exact matrix entry before that run can count as evidence.
140
+ Dolt claims the conservative 2.2.x range `>=2.2.2,<2.3.0`; its full service
141
+ suite is exercised independently at exact versions 2.2.2 and 2.2.3 using
142
+ immutable container-image digests.
143
+
144
+ | Engine/profile | Runtime supported policy | Exact CI-tested versions |
145
+ | --- | --- | --- |
146
+ | SQLite core / optional workflow | Core `>=3.24.0,<4.0.0`; optional workflow `>=3.35.0,<4.0.0` | Runtime-provided SQLite on Python 3.11–3.14 runners; not a pinned server image |
147
+ | PostgreSQL | 17.x and 18.x | 17.10 and 18.4 |
148
+ | MySQL | 8.4.x and 9.7.x | 8.4.11 and 9.7.2 |
149
+ | MariaDB | 11.4.x, 11.8.x, and 12.3.x | 11.4.12, 11.8.8, and 12.3.2 |
150
+ | Dolt | 2.2.x with `>=2.2.2,<2.3.0` | 2.2.2 and 2.2.3 |
151
+
152
+ Microsoft SQL Server (MSSQL) remains roadmap-only and is not a supported
153
+ runtime profile; see the specification's [MSSQL roadmap](https://github.com/OpenStatSpec/specification/blob/main/docs/mssql-dialect-roadmap.md).
154
+
155
+ Use these explicit SQLAlchemy URLs:
87
156
 
88
157
  - SQLite: `sqlite:///dataset.sqlite`
89
158
  - PostgreSQL: `postgresql+psycopg://user:password@host/database`
90
159
  - MySQL/MariaDB: `mysql+pymysql://user:password@host/database`
91
- - Dolt 2.2.2: `mysql+pymysql://user:password@host/database` (detected by server identity)
160
+ - Dolt `>=2.2.2,<2.3.0`: `mysql+pymysql://user:password@host/database` (detected by server identity)
92
161
 
93
162
  The Dolt core profile supports strict wide-table import, validation, and export;
94
163
  the separate Transformation Workflow is unsupported.
@@ -50,12 +50,58 @@ derived datasets through a public catalog API. It uses a separate profile
50
50
  catalog and never presents SQL output as an imported source dataset.
51
51
  Workflow operations support SQLite only in this milestone and fail closed on
52
52
  PostgreSQL/MySQL/MariaDB; core import/export database support is unchanged.
53
+ The core SQLite import/export profile accepts SQLite `>=3.24.0,<4.0.0`; the
54
+ optional transformation workflow deliberately has the narrower
55
+ `>=3.35.0,<4.0.0` runtime preflight. These independent tiers do not change the
56
+ server-profile matrix. Microsoft SQL Server is not supported; its future
57
+ dialect is scoped only in the specification's
58
+ [MSSQL roadmap](https://github.com/OpenStatSpec/specification/blob/main/docs/mssql-dialect-roadmap.md).
53
59
 
54
60
  See [the SQL transformation workflow](docs/sql-transformation-workflow.md) for
55
61
  Python and CLI examples, migration behavior, hashing, atomicity, and the exact
56
62
  implemented capability boundary.
57
63
 
58
- ## 0.2.0 support status
64
+ ## SPSS-like transformation frontend
65
+
66
+ The transformation frontend accepts `RECODE`, `VARIABLE LABELS`, and
67
+ `VALUE LABELS`, lowers them to a canonical OpenStatSpec Transformation Plan,
68
+ and mutates the same logical dataset and physical wide table. SQLite,
69
+ PostgreSQL, MySQL, MariaDB, and Dolt connections are allowed. It creates no
70
+ derived dataset, copied table, snapshot, or OpenStatSpec rollback/version layer.
71
+
72
+ Install the compact operation-audit relation separately, then apply syntax:
73
+
74
+ ```python
75
+ from openstatspec import (
76
+ apply_spss_in_place,
77
+ install_in_place_transformation_schema,
78
+ )
79
+
80
+ database_url = "postgresql+psycopg://user:password@host/database"
81
+ install_in_place_transformation_schema(database_url=database_url)
82
+ result = apply_spss_in_place(
83
+ database_url=database_url,
84
+ dataset_id="...",
85
+ actor="agent@example.org",
86
+ source_text="""
87
+ RECODE age (18 THRU 34 = 1) (35 THRU 64 = 2) INTO age_group.
88
+ VARIABLE LABELS age_group 'Age group'.
89
+ VALUE LABELS age_group 1 '18-34' 2 '35-64'.
90
+ """,
91
+ )
92
+ ```
93
+
94
+ Existing-target recodes and metadata mutations use direct DML. SQLite and
95
+ PostgreSQL may also add a target column in the same native transaction. MySQL,
96
+ MariaDB, and Dolt reject such schema-changing plans before mutation because
97
+ their implicit-commit DDL could otherwise leave a partial apply. On Dolt, the
98
+ caller additionally supplies expected branch and HEAD identities, and the
99
+ working set must be clean. The transformer never calls `DOLT_COMMIT`.
100
+
101
+ See [in-place transformations](docs/in-place-transformation.md) for the full
102
+ execution boundary and CLI form.
103
+
104
+ ## Current support status
59
105
 
60
106
  The adapter requires `openstatspec-pyspssio==0.5.1.post2` as its sole SPSS
61
107
  engine. Its import module remains `pyspssio`; the exact source commit is recorded
@@ -63,13 +109,36 @@ in operation metadata. There is no fallback reader or writer. It supports unencr
63
109
  SAV/ZSAV export for the semantics exposed by that engine. SQLite is the local
64
110
  reference path.
65
111
  PostgreSQL, MySQL, MariaDB, and Dolt are each covered by separate service-backed CI
66
- conformance checks. Dolt support is an independent core profile pinned to 2.2.2;
67
- other Dolt versions and unknown MySQL-wire products fail closed. Use these explicit SQLAlchemy URLs:
112
+ conformance checks. Dolt support is an independent core profile for the
113
+ canonical stable range `>=2.2.2,<2.3.0`; earlier patches, other families,
114
+ noncanonical versions, and unknown MySQL-wire products fail closed.
115
+
116
+ The supported family claims are broader than the deliberately exact CI
117
+ evidence points: PostgreSQL 17.x/18.x is exercised at 17.10/18.4, MySQL
118
+ 8.4.x/9.7.x at 8.4.11/9.7.2, and MariaDB 11.4.x/11.8.x/12.3.x at
119
+ 11.4.12/11.8.8/12.3.2. Each service job checks the normalized live server
120
+ version against its exact matrix entry before that run can count as evidence.
121
+ Dolt claims the conservative 2.2.x range `>=2.2.2,<2.3.0`; its full service
122
+ suite is exercised independently at exact versions 2.2.2 and 2.2.3 using
123
+ immutable container-image digests.
124
+
125
+ | Engine/profile | Runtime supported policy | Exact CI-tested versions |
126
+ | --- | --- | --- |
127
+ | SQLite core / optional workflow | Core `>=3.24.0,<4.0.0`; optional workflow `>=3.35.0,<4.0.0` | Runtime-provided SQLite on Python 3.11–3.14 runners; not a pinned server image |
128
+ | PostgreSQL | 17.x and 18.x | 17.10 and 18.4 |
129
+ | MySQL | 8.4.x and 9.7.x | 8.4.11 and 9.7.2 |
130
+ | MariaDB | 11.4.x, 11.8.x, and 12.3.x | 11.4.12, 11.8.8, and 12.3.2 |
131
+ | Dolt | 2.2.x with `>=2.2.2,<2.3.0` | 2.2.2 and 2.2.3 |
132
+
133
+ Microsoft SQL Server (MSSQL) remains roadmap-only and is not a supported
134
+ runtime profile; see the specification's [MSSQL roadmap](https://github.com/OpenStatSpec/specification/blob/main/docs/mssql-dialect-roadmap.md).
135
+
136
+ Use these explicit SQLAlchemy URLs:
68
137
 
69
138
  - SQLite: `sqlite:///dataset.sqlite`
70
139
  - PostgreSQL: `postgresql+psycopg://user:password@host/database`
71
140
  - MySQL/MariaDB: `mysql+pymysql://user:password@host/database`
72
- - Dolt 2.2.2: `mysql+pymysql://user:password@host/database` (detected by server identity)
141
+ - Dolt `>=2.2.2,<2.3.0`: `mysql+pymysql://user:password@host/database` (detected by server identity)
73
142
 
74
143
  The Dolt core profile supports strict wide-table import, validation, and export;
75
144
  the separate Transformation Workflow is unsupported.
@@ -0,0 +1,41 @@
1
+ # In-place SPSS-like transformation
2
+
3
+ `openstatspec.apply_spss_in_place` is the public execution path for the
4
+ SPSS-like frontend. It accepts `RECODE`, `VARIABLE LABELS`, and `VALUE LABELS`,
5
+ binds them to the existing core dataset, and applies the canonical plan to that
6
+ same SQL wide table and metadata catalog.
7
+
8
+ The caller supplies a supported SQL URL, the existing normative `dataset_id`,
9
+ and a non-empty actor identity. For Dolt, the caller also supplies the expected
10
+ active branch and current `HEAD` hash.
11
+
12
+ Install the compact audit relation once with
13
+ `openstatspec.install_in_place_transformation_schema(database_url=...)` before
14
+ the first apply. Apply never creates schema-management objects itself.
15
+
16
+ The adapter uses the engine's ordinary transaction behavior. On Dolt it first
17
+ checks branch and HEAD and requires `dolt_status` to be empty. Existing-target
18
+ recodes are one direct `UPDATE`. SQLite and PostgreSQL can add a new numeric
19
+ `INTO` target to the same table. MySQL, MariaDB, and Dolt require that target
20
+ column and variable metadata to exist before apply because their DDL can commit
21
+ independently of the following data and metadata changes. Label commands
22
+ update/replace the same dataset's normative and compatibility metadata rows.
23
+
24
+ One compact `transformation_apply` row records operation identity, canonical
25
+ plan/source hashes, actor, status, timestamps, and the observed Dolt branch and
26
+ HEAD. It contains no row values and points to no copied table.
27
+
28
+ The adapter does not create `derived_dataset` rows, persistent output tables,
29
+ full-table copies, staging datasets, snapshots, rollback tables, retirement
30
+ records, or a recovery/version catalog. It does not call `DOLT_COMMIT`, change
31
+ branches, merge, reset, or tag. After success, the caller reviews `dolt diff`
32
+ and independently decides whether to commit or restore the working set.
33
+
34
+ The local SQLite tests exercise the public mutation path and assert that
35
+ dataset/table counts and identities do not change. Live PostgreSQL/MySQL/MariaDB and
36
+ exact-version Dolt service evidence remains required before release execution
37
+ claims for those engines.
38
+
39
+ ```text
40
+ openstatspec apply-spss --database-url mysql+pymysql://user:password@host/database --dataset-id ... --actor agent@example.org --expected-branch feature/recode --expected-head ... --syntax-file transform.sps
41
+ ```
@@ -1,4 +1,4 @@
1
- # 0.2.0 release readiness
1
+ # 0.3.0 release readiness
2
2
 
3
3
  This page records the expected release contract, not a publication event.
4
4
  Creating a version tag remains a separate maintainer action.
@@ -14,21 +14,30 @@ database contract.
14
14
 
15
15
  ## SQL profiles
16
16
 
17
- | Profile | Connection URL | Verification |
18
- | --- | --- | --- |
19
- | SQLite | `sqlite:///dataset.sqlite` | Python 3.11–3.14 local reference jobs |
20
- | PostgreSQL | `postgresql+psycopg://…` | PostgreSQL 17 and 18 service jobs |
21
- | MySQL | `mysql+pymysql://…` | MySQL 8.4 and 9.7 service jobs |
22
- | MariaDB | `mysql+pymysql://…` | MariaDB 11.4, 11.8, and 12.3 service jobs |
23
- | Dolt | `mysql+pymysql://…` | Exact Dolt 2.2.2 service job |
17
+ | Profile | Connection URL | Claimed versions | Exact CI evidence |
18
+ | --- | --- | --- | --- |
19
+ | SQLite | `sqlite:///dataset.sqlite` | `>=3.24.0,<4.0.0` | Active Python 3.11–3.14 runner version |
20
+ | PostgreSQL | `postgresql+psycopg://…` | 17.x and 18.x | 17.10 and 18.4 |
21
+ | MySQL | `mysql+pymysql://…` | 8.4.x and 9.7.x | 8.4.11 and 9.7.2 |
22
+ | MariaDB | `mysql+pymysql://…` | 11.4.x, 11.8.x, and 12.3.x | 11.4.12, 11.8.8, and 12.3.2 |
23
+ | Dolt | `mysql+pymysql://…` | 2.2.x with `>=2.2.2,<2.3.0` | 2.2.2 and 2.2.3 |
24
24
 
25
25
  Separate service matrices test the shared MySQL/MariaDB profile contract while
26
26
  retaining distinct active-server identities and version claims. Dolt is an
27
- independent core profile that fails closed unless the product version is exactly
28
- 2.2.2; the optional Transformation Workflow remains SQLite-only. This does not
27
+ independent core profile that accepts only canonical stable versions in
28
+ `>=2.2.2,<2.3.0`; the optional Transformation Workflow remains SQLite-only. This does not
29
29
  claim coverage for every server configuration. The machine-readable capability
30
30
  declaration reports both the theoretical profile boundaries and effective
31
31
  limits observed from the active connection.
32
+ Every server service job compares the normalized live product version with its
33
+ exact matrix entry, so a moved or mismatched image cannot substantiate the CI
34
+ declaration. SQLite's optional Transformation Workflow retains its narrower
35
+ `>=3.35.0,<4.0.0` live preflight alongside the core `>=3.24.0,<4.0.0` policy.
36
+ Microsoft SQL Server remains unsupported and must not appear in runtime
37
+ capabilities; future implementation requirements are documented in the
38
+ specification's
39
+ [MSSQL dialect roadmap](https://github.com/OpenStatSpec/specification/blob/main/docs/mssql-dialect-roadmap.md).
40
+
32
41
 
33
42
  ## Export-loss policy
34
43
 
@@ -53,14 +62,15 @@ machine-readable loss report with the export result.
53
62
  first and confirm that a clean environment can download it from PyPI. The
54
63
  main package has no fallback SPSS engine.
55
64
  2. Run `python -m pytest -m "not services"`.
56
- 3. Confirm the GitHub Actions matrix is green for PostgreSQL 17/18, MySQL
57
- 8.4/9.7, MariaDB 11.4/11.8/12.3, and exact Dolt 2.2.2.
65
+ 3. Confirm the GitHub Actions matrix is green for exact PostgreSQL 17.10/18.4,
66
+ MySQL 8.4.11/9.7.2, MariaDB 11.4.12/11.8.8/12.3.2, and exact Dolt
67
+ 2.2.2/2.2.3 service evidence from the immutable image pins in CI.
58
68
  4. Build with `python -m build` and install the generated wheel in a clean
59
69
  environment.
60
70
  5. Confirm `openstatspec capabilities` reflects the intended support boundary.
61
- 6. Confirm the `v0.2.0` tag matches package version `0.2.0`, and that CI and
62
- release fixtures use specification release `v1.0.0-rc.1` at exact commit
63
- `fef0dc6f4b17ff7141dad3f49d0524c63efbfed5`.
71
+ 6. Confirm the release tag matches the package version and that CI, release
72
+ fixtures, and capabilities use OpenStatSpec specification release `v0.2.0`
73
+ at exact commit `79339ec3d8f8aa81789b7e85f6b8afa6f1374e50`.
64
74
  7. Review this document, the README, and CHANGELOG for accurate scope.
65
75
 
66
76
  The tag-triggered release workflow repeats the non-service test suite, builds
@@ -15,12 +15,27 @@ unencrypted .sav and .zsav files, and writes both formats through the same imple
15
15
 
16
16
  SQLite has a local reference fixture. PostgreSQL, MySQL, MariaDB, and Dolt have
17
17
  separate service-backed conformance checks in GitHub Actions that import,
18
- validate, and export the supported fixture. Dolt is an independent core profile
19
- pinned to exact server version 2.2.2 and detected over `mysql+pymysql` by active
20
- server identity; other Dolt versions and unknown MySQL-wire products fail closed.
21
- The core Dolt profile does not claim support for the separate Transformation
22
- Workflow. An import that exceeds a target's strict single-table column or row
23
- envelope fails before it creates a dataset.
18
+ validate, and export the supported fixture. The family claims and exact CI
19
+ points are PostgreSQL 17.x/18.x at 17.10/18.4, MySQL 8.4.x/9.7.x at
20
+ 8.4.11/9.7.2, and MariaDB 11.4.x/11.8.x/12.3.x at
21
+ 11.4.12/11.8.8/12.3.2. CI compares each live normalized server version with
22
+ that exact evidence point.
23
+
24
+ Dolt is an independent core profile for canonical stable versions in
25
+ `>=2.2.2,<2.3.0`, detected over `mysql+pymysql` by active server identity and
26
+ service-tested at exact versions 2.2.2 and 2.2.3. Earlier patches, other
27
+ families, noncanonical versions, and unknown MySQL-wire products fail closed.
28
+ The core Dolt profile does not
29
+ claim support for the separate Transformation Workflow. An import that exceeds
30
+ a target's strict single-table column or row envelope fails before it creates a
31
+ dataset.
32
+
33
+ The core SQLite profile remains `>=3.24.0,<4.0.0`; only the optional
34
+ Transformation Workflow requires `>=3.35.0,<4.0.0`. Microsoft SQL Server is
35
+ not a supported profile. Its driver, SQL-difference, preflight, CI,
36
+ conformance, security, and atomicity work is future scope in the
37
+ specification's
38
+ [MSSQL dialect roadmap](https://github.com/OpenStatSpec/specification/blob/main/docs/mssql-dialect-roadmap.md).
24
39
 
25
40
  ## Fidelity contract
26
41
 
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "openstatspec"
7
- version = "0.2.0"
7
+ version = "0.3.0"
8
8
  description = "Reference adapter for the OpenStatSpec relational contract"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -0,0 +1,32 @@
1
+ """Public API for the OpenStatSpec Python reference implementation."""
2
+
3
+ from .api import (
4
+ apply_spss_in_place, capabilities, capability_matrix, derive_sql_dataset,
5
+ execute_sql_transformation,
6
+ export_sav, get_dataset, import_sav, inspect,
7
+ install_in_place_transformation_schema, list_datasets,
8
+ register_sql_transformation, reconcile_derived_removals,
9
+ reconcile_sql_transformation_runs,
10
+ remove_derived_physical_relation, retire_derived, validate, validate_derived,
11
+ )
12
+ from .core import CapabilityDeclaration, LossReport, UnsupportedOperationError
13
+ from .sql.workflow import TransformationError
14
+ from .transform import (
15
+ SpssFrontendCompilation, TransformationFrontendError,
16
+ VariableDefinition, VariableSchema, compile_spss_syntax,
17
+ )
18
+
19
+ __all__ = [
20
+ "CapabilityDeclaration", "LossReport", "SpssFrontendCompilation",
21
+ "TransformationError", "TransformationFrontendError",
22
+ "VariableDefinition", "VariableSchema",
23
+ "UnsupportedOperationError", "capabilities", "capability_matrix",
24
+ "apply_spss_in_place", "compile_spss_syntax", "derive_sql_dataset",
25
+ "execute_sql_transformation", "export_sav",
26
+ "get_dataset", "import_sav", "inspect",
27
+ "install_in_place_transformation_schema", "list_datasets",
28
+ "register_sql_transformation", "reconcile_derived_removals",
29
+ "reconcile_sql_transformation_runs",
30
+ "remove_derived_physical_relation", "retire_derived", "validate",
31
+ "validate_derived",
32
+ ]
@@ -20,6 +20,11 @@ from .sql.workflow import (
20
20
  remove_derived_relation as _remove_derived_relation,
21
21
  retire_derived_dataset as _retire_derived_dataset,
22
22
  )
23
+ from .sql.inplace_transform import (
24
+ apply_spss_in_place as _apply_spss_in_place,
25
+ in_place_transformation_capabilities,
26
+ install_in_place_transformation_schema as _install_in_place_schema,
27
+ )
23
28
  from .sql.capabilities import (
24
29
  SPECIFICATION_COMMIT, SPECIFICATION_RELEASE, active_connection, catalog_binding,
25
30
  )
@@ -37,7 +42,7 @@ def capability_matrix(database_url: str | None = None) -> Mapping[str, Any]:
37
42
  """
38
43
  declaration = {
39
44
  "specification": "OpenStatSpec",
40
- "specification_status": "release_candidate",
45
+ "specification_status": "released",
41
46
  "specification_release": SPECIFICATION_RELEASE,
42
47
  "specification_commit": SPECIFICATION_COMMIT,
43
48
  "profile": "SPSS SAV/ZSAV 1.0",
@@ -84,6 +89,9 @@ def capability_matrix(database_url: str | None = None) -> Mapping[str, Any]:
84
89
  "sql_profiles": declared_profiles(database_url),
85
90
  "optional_profiles": {
86
91
  "sql_transformation_workflow": transformation_capabilities(database_url),
92
+ "spss_in_place_transformation": (
93
+ in_place_transformation_capabilities()
94
+ ),
87
95
  },
88
96
  }
89
97
  return declaration
@@ -130,6 +138,27 @@ def derive_sql_dataset(*, database_url: Any, **options: Any) -> Mapping[str, Any
130
138
  return result(_derive_dataset(database_url=str(database_url), **options))
131
139
 
132
140
 
141
+ def apply_spss_in_place(
142
+ *, database_url: Any, dataset_id: str, source_text: str,
143
+ actor: str, expected_branch: str | None = None,
144
+ expected_head: str | None = None,
145
+ ) -> Mapping[str, Any]:
146
+ """Apply supported SPSS-like syntax to the same SQL dataset/table."""
147
+ return result(_apply_spss_in_place(
148
+ database_url=str(database_url),
149
+ dataset_id=dataset_id,
150
+ source_text=source_text,
151
+ actor=actor,
152
+ expected_branch=expected_branch,
153
+ expected_head=expected_head,
154
+ ))
155
+
156
+
157
+ def install_in_place_transformation_schema(*, database_url: Any) -> None:
158
+ """Install the compact apply-audit relation before the first apply."""
159
+ _install_in_place_schema(database_url=str(database_url))
160
+
161
+
133
162
  def validate_derived(*, database_url: Any, derived_dataset_id: str) -> Mapping[str, Any]:
134
163
  return result(_validate_derived_dataset(
135
164
  database_url=str(database_url), derived_dataset_id=derived_dataset_id,