Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,20 @@
# Changelog

## Unreleased

### Added

- Explicitly selected official SPSS Frontend 0.3 using the existing strict
request/parser/binder/compiler pipeline; Frontend 0.2 remains the default.
Support comments, dictionary-order TO and grouped commands, NOT and comparison
aliases, finite open RECODE ranges, and ordered typed ADD VALUE LABELS.
- Check all 90 effective official cases against the unchanged specification pin,
inherited Plan 0.1/0.2 objects and hashes, and native SQLite in-place provenance
and identity. Service CI is pending; no new network runtime claim is made.
- Document the parent precedence decision: comparisons, NOT, AND, OR;
parentheses override. No STRING/DELETE or schema extension, version, codec,
dependency, publication or prepared 0.7.2 scope change.

## [0.7.2] - Unreleased

### Fixed
Expand Down
10 changes: 7 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,8 +141,12 @@ Pass only loss codes consciously accepted for that conversion. `operation_catalo
The adapter claims official Transformation Plan 0.1/0.2, SPSS Syntax Frontend
0.2, and In-Place Transformation 0.1/0.2 conformance. Compile an alias-based
frontend request, then bind that alias to the existing dataset at apply time.
The specification pin does not claim support for optional Transformation Plan,
SPSS Syntax Frontend, or In-Place Transformation 0.3.
Unreleased opt-in SPSS Syntax Frontend 0.3 is implemented: explicitly set the
request `contract` to `openstatspec-spss-syntax-frontend-v0.3` (or use
`SpssFrontendRequest::CONTRACT_V03`). It emits only Plan 0.1/0.2; default 0.2
syntax and APIs remain unchanged. All 90 effective fixtures and native SQLite
apply are tested locally; service CI is pending, not a new runtime claim.
Transformation Plan and In-Place Transformation 0.3 remain unimplemented.

```php
use OpenStatSpec\Frontend\Spss\Request\SpssFrontendRequest;
Expand Down Expand Up @@ -182,7 +186,7 @@ supported operations, and atomicity guarantees.
- `src/Sql` - PDO profiles, strict-wide DDL, import/export and catalogues.
- `src/Spss` - SAV/ZSAV gating, typed V3 engine bridge and public adapter API.
- `src/Transformation` - official plans, compact apply audit, and in-place execution.
- `src/Frontend/Spss` - official SPSS Frontend 0.2 request compilation.
- `src/Frontend/Spss` - SPSS Frontend 0.2 and explicitly selected 0.3 request compilation.

See [docs/architecture.md](docs/architecture.md) for the complete relational contract.
See [docs/transformations.md](docs/transformations.md) for frontend boundaries,
Expand Down
4 changes: 3 additions & 1 deletion docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,9 @@ Encrypted files, Portable (`.por`) files and arbitrary external-engine formats a

`src/Transformation/Plan` owns the official Transformation Plan 0.1/0.2 model,
strict codec, validation, and deterministic plan identity.
`src/Frontend/Spss` is the separate official SPSS Frontend 0.2 boundary.
`src/Frontend/Spss` is the separate SPSS Frontend 0.2 boundary, with opt-in
Frontend 0.3 using the same strict request validator, parser, binder and compiler.
Frontend 0.3 emits only Plan 0.1/0.2; its service CI claim is pending.
`src/Transformation/Execution` binds an alias-based plan to one existing
dataset and applies it through the active PDO profile; it never invokes the
frontend. The Stata and SAS directories are placeholders only.
Expand Down
7 changes: 5 additions & 2 deletions docs/release-readiness.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,11 @@ files. Unknown patches, including 2.2.4, fail before mutation. Read-only export
still verifies server identity but does not require a write-version claim.

Transformation claims remain Transformation Plan 0.1/0.2, SPSS Syntax Frontend
0.2, and In-Place Transformation 0.1/0.2. The specification's optional 0.3
contracts are not implemented or claimed. Existing target pre-provisioning and
0.2, and In-Place Transformation 0.1/0.2 for the prepared patch.
Separate Unreleased work implements opt-in SPSS Syntax Frontend 0.3 against
this unchanged pin: 90 effective fixtures and native SQLite apply are locally
covered; exact-commit service CI remains pending. Transformation Plan 0.3 and
In-Place Transformation 0.3 remain unimplemented. Existing target pre-provisioning and
caller-owned Dolt commit rules remain unchanged; see the
[transformation migration notes](transformations.md#v060-migration).

Expand Down
48 changes: 47 additions & 1 deletion docs/transformations.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ The PHP adapter conforms to these pinned OpenStatSpec contracts:
- `openstatspec-in-place-transformation-v0.1` and
`openstatspec-in-place-transformation-v0.2`.

Unreleased opt-in `openstatspec-spss-syntax-frontend-v0.3` is also implemented,
with local fixture/SQLite evidence and service CI pending. It is separately
listed as `implemented_service_ci_pending` in the capability declaration, not
added to its existing conformant contract lists. Plan 0.3 and In-Place 0.3 are
not implemented.

Plans are source-neutral, alias-based, and deterministic. The canonical plan
contains only its contract, input alias, and ordered operations. Dataset UUIDs,
SQL identifiers, actor identity, and Dolt context are supplied only when the
Expand Down Expand Up @@ -81,6 +87,37 @@ Names bind ASCII case-insensitively while plans retain exact catalog spelling.
Multi-variable `RECODE` reads all sources from the pre-command schema. Commands,
expressions, comments, and syntax outside the official subset fail closed.

## Opt-in Frontend 0.3

Select the exact `openstatspec-spss-syntax-frontend-v0.3` request contract, also
available as `SpssFrontendRequest::CONTRACT_V03`. `CONTRACT` and the public
parse/bind defaults remain 0.2. The existing `fromArray()` production boundary
rejects unknown/missing fields and wrong types, including nested schema and
typed-label fields. No physical identifiers or schema extensions are accepted.

The shared parser/binder adds command-boundary `*` and `COMMENT` comments,
non-nested block comments wherever whitespace is legal, dictionary-order `TO`,
grouped RECODE/labels/formats/levels, numeric `NOT` and `NE`/`<>`/`~=`, finite
LOWEST/HIGHEST bounds, and ordered typed `ADD VALUE LABELS`. Comments end at
the next command period (or `*/` for blocks); nested/unterminated blocks and
comment-only programs fail. Hashing retains original comments and normalizes
only CRLF/CR to LF. ADD updates existing typed codes in place and appends new
codes, including after preceding VALUE LABELS replacements. Its initial label
state comes from the supplied input schema; callers must supply the current
dictionary when compiling.

**Parent decision:** use conventional SPSS precedence: comparisons, then NOT,
then AND, then OR. Thus `NOT a = 1 AND b = 2 OR c = 3` means
`((NOT (a = 1)) AND (b = 2)) OR (c = 3)`. Parentheses override that order.
Negation complements comparisons and applies De Morgan's laws without changing
UNKNOWN; canonical lowering flattens maximal same-operator nodes in source
order, including across parentheses. Double NOT retains the original predicate.

These additions emit exact Plan 0.1 when possible and Plan 0.2 for existing
0.2-only operations. `STRING`, `DELETE VARIABLES`, arbitrary expressions and
implicit type coercions remain rejected. No codec, catalog or executor schema
change is involved.

## In-place and atomicity contract

Every successful apply preserves the existing logical dataset UUID, registered
Expand Down Expand Up @@ -143,6 +180,15 @@ composer check
```

They cover all 4 Plan 0.1, 26 Plan 0.2, 44 Frontend 0.2, 6 In-Place 0.1,
and 11 In-Place 0.2 manifest cases. SQLite runs locally. PostgreSQL, MySQL,
and 11 In-Place 0.2 manifest cases, plus all 90 effective Frontend 0.3 cases
(35 declared plus inherited cases minus the two comment supersessions).
Frontend checks compare source/plan hashes, exact inherited plans, diagnostics
and declared metadata preservation. Use
`OPENSTATSPEC_SPECIFICATION_DIR=/tmp/openstatspec-alignment-spec` for the
alignment checkout at unchanged commit `864e84479f554b8ee250ffed44c4dfb963750d4a`.
The public Frontend 0.3 → native SQLite apply regression checks UNKNOWN,
metadata, provenance and unchanged dataset/table identity without extra data
artifacts or history. This change has no local network-service evidence; its
service CI gate remains pending. SQLite runs locally. PostgreSQL, MySQL,
MariaDB, and Dolt cases run when their `OPENSTATSPEC_*` service configuration
is supplied; CI configures every service family.
3 changes: 3 additions & 0 deletions src/Core/CapabilityDeclaration.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ public function toArray(): array
'official_frontend_contracts' => [
'openstatspec-spss-syntax-frontend-v0.2',
],
'opt_in_frontend_contracts' => [
'openstatspec-spss-syntax-frontend-v0.3' => 'implemented_service_ci_pending',
],
'official_binding_contracts' => [
'openstatspec-in-place-transformation-v0.1',
'openstatspec-in-place-transformation-v0.2',
Expand Down
2 changes: 1 addition & 1 deletion src/Frontend/Spss/Ast/FormatTarget.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
final readonly class FormatTarget
{
public function __construct(
public string $variable,
public string|VariableRange $variable,
public string $family,
public int $width,
public int $decimals,
Expand Down
17 changes: 17 additions & 0 deletions src/Frontend/Spss/Ast/NotPredicate.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

declare(strict_types=1);

namespace OpenStatSpec\Frontend\Spss\Ast;

use OpenStatSpec\Transformation\Diagnostic\SourceSpan;

final readonly class NotPredicate implements Predicate
{
public function __construct(public Predicate $operand, public SourceSpan $span) {}

public function span(): SourceSpan
{
return $this->span;
}
}
2 changes: 1 addition & 1 deletion src/Frontend/Spss/Ast/Program.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@
final readonly class Program
{
/** @param list<Statement> $statements */
public function __construct(public array $statements) {}
public function __construct(public array $statements, public bool $officialV03 = false) {}
}
2 changes: 1 addition & 1 deletion src/Frontend/Spss/Ast/RecodeStatement.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
final readonly class RecodeStatement implements Statement
{
/**
* @param non-empty-list<string> $sources
* @param non-empty-list<string|VariableRange> $sources
* @param non-empty-list<RecodeRule> $rules
* @param list<string> $targets
*/
Expand Down
2 changes: 1 addition & 1 deletion src/Frontend/Spss/Ast/ValueLabelGroup.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
final readonly class ValueLabelGroup
{
/**
* @param non-empty-list<string> $variables
* @param non-empty-list<string|VariableRange> $variables
* @param non-empty-list<ValueLabel> $labels
*/
public function __construct(
Expand Down
1 change: 1 addition & 0 deletions src/Frontend/Spss/Ast/ValueLabelsStatement.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ public function __construct(
public int $sourceLine,
public array $groups,
public SourceSpan $span,
public bool $add = false,
) {}

public function line(): int
Expand Down
2 changes: 1 addition & 1 deletion src/Frontend/Spss/Ast/VariableLabelAssignment.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
final readonly class VariableLabelAssignment
{
public function __construct(
public string $variable,
public string|VariableRange $variable,
public string $label,
public SourceSpan $variableSpan,
public SourceSpan $span,
Expand Down
2 changes: 1 addition & 1 deletion src/Frontend/Spss/Ast/VariableLevelGroup.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

final readonly class VariableLevelGroup
{
/** @param non-empty-list<string> $variables */
/** @param non-empty-list<string|VariableRange> $variables */
public function __construct(
public array $variables,
/** @var non-empty-list<SourceSpan> */
Expand Down
16 changes: 16 additions & 0 deletions src/Frontend/Spss/Ast/VariableRange.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

declare(strict_types=1);

namespace OpenStatSpec\Frontend\Spss\Ast;

use OpenStatSpec\Transformation\Diagnostic\SourceSpan;

final readonly class VariableRange
{
public function __construct(
public string|self $first,
public string $last,
public SourceSpan $span,
) {}
}
Loading