You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 58e22b2
Browse filesBrowse the repository at this point in the historyBrowse files
feat(metadata): resolve references once after the tree (#444)
* feat(codegen): orphan sweep in every port, JVM hash manifest, per-generator handEdits
- gen deletes a recorded, untouched file no generator emits any more (TS, Python, C#, Java, Kotlin)
- Java/Kotlin decide overwrites from the committed hash manifest (ADR-0059)
- handEdits: keep|overwrite per generator in all five ports
* no-mistakes(review): Add JVM manifest owners and fix nested-dir and verify sweeps
* no-mistakes(review): Key JVM manifest owners on generator and outputDir
* no-mistakes(review): Limit JVM shared-path error to differing owned emissions
* no-mistakes(review): Count profile-declared generators as configured in JVM sweep
* no-mistakes(review): Read profile generators via Maven; ports keep JVM entries
* feat(metadata): references resolve once, after the tree, in every port (ADR-0059)
A reference was interpreted in two places: the YAML desugar rewrote
reference values while lowering, and canonical JSON took them as written,
refused `::` and `..::`, and resolved them later in each port's loader.
The two paths disagreed, so the same model loaded differently from YAML
and from JSON, and depended on file order.
Now every source keeps references exactly as written. One resolver per
port binds them after the whole tree has loaded and validated, records
the bound target and the authored spelling, and rewrites each value to
its canonical spelling before freeze.
- One grammar in every source: `::Name` (root-absolute), `..::Name`
(parent-relative, over-drop is ERR_BAD_ATTR_VALUE), `pkg::Name`, and a
bare name (own file's package, then root). ERR_RELATIVE_REF_IN_CANONICAL
is retired.
- The referrer package is the package of the top-level node that declares
the attribute, so an inherited reference means what it meant where it
was written. `@of` after `@via` uses the package the walk reaches, and
`@spine` uses the report's `@from` package.
- The default package is per file, nested nodes included.
- The serializer writes canonical values plus a package rule that lets a
multi-package export load back to itself. `meta fmt` keeps authored
spellings.
- Consumers in codegen and runtime read the bound target (TS
`refTarget`), never a short-name match. `findObject` accepts canonical
values. Human-facing text keeps quoting the authored spelling.
- Two new gates in every port: the YAML twin (each fixture loads to the
same model from JSON and from YAML) and the round trip (each
expected.json serializes back to itself), with zero exclusions.
- YAML-twin defects fixed: C# YAML overlays now defer, and Java accepts a
non-string field `default:` and list-valued `aliases`/`seeAlso`.
- Shared goldens regenerated from the TypeScript oracle. Ten new
conformance fixtures; one retired.
* no-mistakes(review): Align gen and verify sweeps; union JVM profile owners
* no-mistakes(review): Memoize JVM configured owners and compute them lazily
* no-mistakes(review): Qualify per-port manifest generator records in docs and ADR
* no-mistakes(review): Sweep shared JVM generator pairs only in last execution
* no-mistakes(review): Refuse one generator/outputDir in two JVM executions at build time
* no-mistakes(review): Exclude phase-none executions from JVM duplicate-pair check
* no-mistakes(review): Keep phase-none executions' generators configured for sweep and verify
* no-mistakes(review): Resolve inherited refs by bound target; fix Python @from regression
* no-mistakes(review): Apply JVM handEdits overwrite verdict over all configured directory writers
* no-mistakes(review): Bind post-load references by bound target across ports
* no-mistakes(review): Make public payload resolvers exact canonical lookups
* chore(showcase): refresh site payload fixture count (395)
* fix(java,kotlin): keep pre-1.1.0 helper signatures so ejected generators compile
A review round renamed KotlinGenUtil.resolveObjectByShortOrFqn and changed
RelationshipReferences' target parameter from a String to the bound node.
Generators an adopter ejected before 1.1.0 call the old forms, so
EjectedAtBaseGeneratorsCompatTest no longer compiled them. Restore the old
signatures as deprecated delegates that do the exact canonical lookup
(ADR-0059 R7), never a short-name match.
* no-mistakes(review): apply reviewer inline fixes
* no-mistakes(document): Fixed stale template-header overwrite claims in three docs and one stale audit-axis reference; ADRs, CHANGELOG and JVM docs already matched the change.
Copy file name to clipboardExpand all lines: AGENTS.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -72,7 +72,7 @@ PyPI has had no product change since `0.25.0` — nothing is broken.
72
72
-**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.
73
73
74
74
**Cross-port conformance corpora** (every port runs the shared corpus):
75
-
- Metamodel: `fixtures/conformance/` (384 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/` (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.
- 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".)
78
78
- 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.
Copy file name to clipboardExpand all lines: docs/features/cli.md
+18Lines changed: 18 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -234,6 +234,24 @@ one-time fix.
234
234
|`--baseline=adopt`| TS · Python · C# | record the files you HAVE as the merge base and **write nothing**|
235
235
|`--baseline=fresh`| TS only | overwrite the refused files from fresh output and re-baseline (**discards** hand edits). A local snapshot body for a path the manifest has no record of is ignored, not merged against, so stale content from an earlier checkout is not kept as a hand edit |
236
236
237
+
`--baseline` answers for one run. To decide once, per generator, set `handEdits` on its
238
+
entry instead:
239
+
240
+
| setting | ports | what it does |
241
+
|---|---|---|
242
+
|`handEdits: keep`| all | the default: an edited generated file is refused, and so is an edited file no generator emits any more |
243
+
|`handEdits: overwrite`| all | replace that generator's edited files with fresh output and re-baseline them; the orphan sweep deletes an edited file no generator emits any more when every generator writing into its directory overwrites. Each discarded file is named. A file the manifest has no record of is still refused |
244
+
245
+
||`--baseline=fresh`|`handEdits: overwrite`|
246
+
|---|---|---|
247
+
| scope | one run, every generator | every run, one generator |
248
+
| a file with no manifest record | overwritten | refused |
249
+
| an edited orphan | untouched | deleted (when the whole directory overwrites) |
250
+
|`verify --codegen`| not affected | reports the edit as drift that `gen` fixes |
0 commit comments