Skip to content

Commit c8b168b

Browse files
authored
fix: canonicalize decimal wire and close 1.1.0 release review findings (#445)
* fix: close the 1.1.0 release review findings before rc.7 Fixes everything the 1.1.0 release review found, plus the adopter-found `eject --list` defect, and closes the test gaps it named. - Decimals: one canonical string on the wire in every port (W1-W4), a shared decimal-wire corpus and an api-contract decimal/ sub-corpus, exact filter operands, and 400 validation past @precision/@scale. The stronger assertions found the TypeScript TPH polymorphic read sending a subtype-only decimal uncanonicalized; fixed in the generator. - Report lanes: every port runs the report scenarios on SQLite and MySQL (Java OMDB SQLiteDriver, Python SQLite/MySQL drivers), the Java report lane is database-backed, and the Cube lane queries every exporter shape. - Loader: four more report shapes refused (D5, M10, R10, R11), an integral float accepted where an int is declared, the requirement package and ERR_UNRESOLVED_SUPER hint fixed. - eject --list reports owned companion files; JVM and Python naming discovery; TS forms step/inputMode; config unknown keys warn. - Breaking (recorded in CHANGELOG and the 1.0-to-1.1 upgrade guide): C# scalar and enum arrays are IList<T>; a Java POJO redeclaring an inherited field with another subtype is standalone; Kotlin gains per-package MetaDecimalWire.kt and MetaPortableColumnTypes.kt. * no-mistakes(review): Canonicalize decimal arrays element-wise; document fractional validator bounds * no-mistakes(review): Coerce and range-check decimal array elements in Python and Kotlin * no-mistakes(document): Fixed stale decimal-array and eject docs. Review-2 CHANGELOG and upgrade-guide fixes were already present in the diff. Edited the reporting skill decimal line (source plus five fixture copies, which mirror it) to the canonical-string rule, and added the companion-file clause to the own-your-codegen eject --list bullet.
1 parent 58e22b2 commit c8b168b

688 files changed

Lines changed: 24116 additions & 2463 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.github/workflows/publish-csharp.yml‎

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,13 @@ jobs:
4141
steps:
4242
- uses: actions/checkout@v4
4343

44+
# The tag must name the version the manifest commits: these workflows publish the
45+
# manifest's version whatever tag started them (scripts/check-release-tag.mjs).
46+
- name: Tag matches the manifest version
47+
env:
48+
VERSION_INPUT: ${{ github.event.inputs.version }}
49+
run: node scripts/check-release-tag.mjs csharp "$VERSION_INPUT"
50+
4451
# A final version is not published while the eject pending list has entries
4552
# (ADR-0034 Amendment 8). A release candidate passes, which is why the `version`
4653
# input is read first.
@@ -75,9 +82,17 @@ jobs:
7582
with:
7683
user: ${{ secrets.NUGET_USER }}
7784

85+
# --skip-duplicate lets a re-run finish a push that failed part way. A run that pushed
86+
# NOTHING, because every package was already on nuget.org, is a re-run of a published
87+
# version and fails rather than reporting green.
7888
- name: NuGet push
7989
run: |
90+
set -o pipefail
8091
dotnet nuget push "artifacts/*.nupkg" \
8192
--api-key ${{ steps.login.outputs.NUGET_API_KEY }} \
8293
--source https://api.nuget.org/v3/index.json \
83-
--skip-duplicate
94+
--skip-duplicate | tee push.log
95+
if ! grep -q "Your package was pushed" push.log; then
96+
echo "::error::nothing was pushed: every package is already on nuget.org at this version"
97+
exit 1
98+
fi

‎.github/workflows/publish-java.yml‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,11 @@ jobs:
3333
steps:
3434
- uses: actions/checkout@v4
3535

36+
# The tag must name the version the manifest commits: these workflows publish the
37+
# manifest's version whatever tag started them (scripts/check-release-tag.mjs).
38+
- name: Tag matches the manifest version
39+
run: node scripts/check-release-tag.mjs java
40+
3641
# A final version is not published while the eject pending list has entries
3742
# (ADR-0034 Amendment 8). A release candidate passes.
3843
- name: Eject release gate

‎.github/workflows/publish-npm.yml‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,11 @@ jobs:
3939
steps:
4040
- uses: actions/checkout@v4
4141

42+
# The tag must name the version the manifest commits: these workflows publish the
43+
# manifest's version whatever tag started them (scripts/check-release-tag.mjs).
44+
- name: Tag matches the manifest version
45+
run: node scripts/check-release-tag.mjs npm
46+
4247
# A final version is not published while the eject pending list has entries
4348
# (ADR-0034 Amendment 8). A release candidate passes.
4449
- name: Eject release gate

‎.github/workflows/publish-python.yml‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@ jobs:
2828
steps:
2929
- uses: actions/checkout@v4
3030

31+
# The tag must name the version the manifest commits: these workflows publish the
32+
# manifest's version whatever tag started them (scripts/check-release-tag.mjs).
33+
- name: Tag matches the manifest version
34+
run: node scripts/check-release-tag.mjs python
35+
3136
# A final version is not published while the eject pending list has entries
3237
# (ADR-0034 Amendment 8). A release candidate passes.
3338
- name: Eject release gate

‎AGENTS.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ PyPI has had no product change since `0.25.0` — nothing is broken.
7272
- **Kotlin** — `codegen-kotlin` (KotlinPoet on JVM): entity + Exposed table + Spring controller + payload + relations + filter allowlist + validator + stored-proc + output-parser generators. `integration-tests-kotlin` runs the persistence-conformance corpus through Exposed against Testcontainers Postgres.
7373

7474
**Cross-port conformance corpora** (every port runs the shared corpus):
75-
- Metamodel: `fixtures/conformance/` (395 fixtures; 29 shared corpora in total — per-corpus counts + the corpus x port matrix live in `docs/CONFORMANCE.md`). TS / C# / Java / Python all green.
75+
- Metamodel: `fixtures/conformance/` (410 fixtures; 30 shared corpora in total — per-corpus counts + the corpus x port matrix live in `docs/CONFORMANCE.md`). TS / C# / Java / Python all green.
7676
- Render: `fixtures/render-conformance/`. TS / C# / Java / Kotlin / Python byte-identical.
7777
- Persistence: `fixtures/persistence-conformance/`. **Query** scenarios run on every port (TS / C# / Java / Kotlin / Python), each provisioning its test DB by executing the committed, TS-produced `canonical/schema.postgres.sql` (Postgres only — Derby dropped for the cross-port query corpus, ADR-0015; the FR-044 `report-*` scenarios also run on SQLite, MySQL and D1 where a port has the engine, see [docs/CONFORMANCE.md](docs/CONFORMANCE.md)). The **migration** scenarios are exercised by **TS only** (TS owns schema migrations). **The corpus now gates WRITES, not just reads (SP-H):** an `op: roundtrip` scenario type INSERTs through each port's runtime/ORM write codec (NOT raw SQL), reads the row back, and asserts the wire-normalized value. The `AllTypes` entity (`roundtrip-all-types.yaml`) carries one field of **every** persistable `field.*` subtype — string/int/long/double/float/decimal/boolean/date/time/timestamp(+tz)/currency/enum/uuid/object — plus an **array-of-VO** `field.object @isArray @storage:jsonb` column (`labels`, written as 2-element / empty-`[]` / single-element arrays across the three rows) — so every subtype write+read (incl. the array-of-value-object jsonb codec) round-trips through every port against Testcontainers PG. (`field.byte`/`field.short`/`field.class` were cut as non-functional registration-only stubs — the matrix tracks only genuinely-supported subtypes; see `fixtures/registry-conformance/README.md` → "Per-subtype write-round-trip matrix".)
7878
- API-contract: `fixtures/api-contract-conformance/`. TS / C# / Java / Kotlin / Python all green — each port runs **two lanes**: a hand-rolled reference server AND its **generated** API artifact booted over HTTP (the deployed controller/routes; TS+C# full-stack vs Testcontainers PG, Java/Kotlin/Python generated controller + in-memory repo behind the consumer seam). The generated fan-out found 10 real deployment bugs golden snapshots missed. Three sub-corpora run the **generated lane only, on all five ports** — `write-through/`, `projection/` (F22: a view-only `object.projection` serves GET list + GET by id and answers every write verb with `405 {"error": "method_not_allowed"}`) and `report/` (FR-044: a view-backed `object.report` serves GET list, answers `POST` with that same `405`, and mounts no `/{id}` route). That is deliberate, not a gap: what is under test is whether a port's GENERATOR emits those routes, and a hand-rolled reference server would answer every scenario by construction. The `m2m/` sub-corpus also gates **TPH x M:N together** (base-declared, subtype-declared, abstract-mid-declared, a non-subtype source onto a subtype TARGET, and the cross-subtype source id answering `200 []`) — the two corpora were originally built disjoint (`tph/` had no relationships, `m2m/` no discriminators), which is precisely how that defect class survived.

0 commit comments

Comments
 (0)