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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 1 addition & 1 deletion .claude/rules/codegen-architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ origins live on `object.projection` only.
Gated end-to-end by `fixtures/api-contract-conformance/projection/` (view-only)
and `.../write-through/` (table + replica view).

**Column and table naming** is `naming` in `.metaobjects/config.json` (ADR-0058), read by every port: `columns` `snake_case` (default) | `literal` | `kebab-case`, `tables` `snake_case` (default) | `literal`. Generators read it as `ctx.columnNamingStrategy` (set from the loaded root); `metaobjects.config.ts` no longer takes it.
**Column and table naming** is `naming` in `.metaobjects/config.json` (ADR-0058), read by every port: `columns` `snake_case` (default) | `literal` | `kebab-case` | `pascal` (upper-cases the first letter only) | a name the application registered (ADR-0058 Amendment 1), `tables` `snake_case` (default) | `literal`. Generators read it as `ctx.columnNamingStrategy` (set from the loaded root); `metaobjects.config.ts` no longer takes it.

### Currency (Project F)

Expand Down
2 changes: 1 addition & 1 deletion .claude/rules/cross-language-porting.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ Preserve the following contracts exactly across all language ports:
- Currency attrs: `@currency` (ISO 4217), `@locale` (BCP 47)
- Schema attrs: `@schema` on `source.rdb` (DB schema name; Postgres default `public`, SQLite rejects non-default values)
- Storage attrs: `@storage` on `field.object` (with `@objectRef`) — values `flattened` / `jsonb` / `subdocument`. Unifies "owned types" (flattened storage) and "structured JSONB" (jsonb storage). Defaults to single-jsonb-column when absent (back-compat).
- Enum: `field.enum` is a first-class field subtype (peer of `currency`), string-backed. Required `@values` string-array attr (member symbols). Members must be a non-empty set, each matching `^[A-Za-z_][A-Za-z0-9_]*$`, no duplicates — every port's loader enforces this (own-only) emitting `ERR_BAD_ATTR_VALUE` (missing `@values` → `ERR_MISSING_REQUIRED_ATTR`). Reuse via abstract `field.enum` + `extends`. Codegen: TS union + `z.enum`, C# `enum` + EF `HasConversion<string>()`, DB `varchar` + `CHECK`. **Int-backed storage shipped** (`@intValueMap`, a `{memberSymbol: int}` map, switches the column to `integer` + int `CHECK` while the wire format, the generated type and every runtime value stay the member SYMBOL; a MAP rather than a positional array so reordering `@values` cannot silently re-map every member; `@isArray` + `@intValueMap` is a LOAD ERROR, and an unmapped stored integer THROWS in all five ports). Display labels and native PG enum remain deferred (see `docs/superpowers/specs/2026-05-23-enum-datatype-design.md`).
- Enum: `field.enum` is a first-class field subtype (peer of `currency`), string-backed. Required `@values` string-array attr (member symbols). Members must be a non-empty set, each matching `^[A-Za-z_][A-Za-z0-9_]*$`, no duplicates — every port's loader enforces this (own-only) emitting `ERR_BAD_ATTR_VALUE` (missing `@values` → `ERR_MISSING_REQUIRED_ATTR`). Reuse via abstract `field.enum` + `extends`. Codegen: TS union + `z.enum`, C# `enum` + EF `HasConversion<string>()`, DB `varchar` + `CHECK`. **Int-backed storage shipped** (`@intValueMap`, a `{memberSymbol: int}` map, switches the column to `integer` + int `CHECK` while the wire format, the generated type and every runtime value stay the member SYMBOL; a MAP rather than a positional array so reordering `@values` cannot silently re-map every member; an int-backed enum array loads in every port and stores each element as its declared integer — TypeScript and C# persist it on every engine, Python on Postgres only, Java's OMDB refuses it at the codec, and Kotlin's Exposed generator emits no enum array column yet; an unmapped stored integer THROWS in all five ports). Display labels and native PG enum remain deferred (see `docs/superpowers/specs/2026-05-23-enum-datatype-design.md`).
- Documentation common attrs (any node): `description`, `title`, `notes`, `deprecated`, `replacedBy`, `seeAlso`, `aliases`. Registered via the cross-language `commonAttrs` registry hook (`registerCommonAttrs` / `RegisterCommonAttrs` / `register_common_attrs` / Java `MetaDataRegistry.registerCommonAttribute` — wired in all four ports). `notes` is the internal-only rationale slot — never emitted to user-facing doc-gen (JSDoc / XML-doc / Postgres `COMMENT ON` / Mermaid prose). **The `description` / `notes` split is by CONTENT KIND, not audience** — an audience split invites writing the same content twice at two levels of politeness. `description` states what the element IS and COVERS (scope and boundary, derivable from the model); `notes` states what you had to look OUTSIDE the model to learn (evidence, citations, what breaks if it changes). Mechanical test: a sentence belongs in `notes` exactly when it would have to change because the IMPLEMENTATION changed while the model did not. `title` is a noun phrase, `summary` a one-line sentence. TS doc-gen ships all three tiers; C# ships XML-doc + COMMENT ON. See `docs/superpowers/specs/2026-05-24-documentation-provider-design.md`.

**Wire format:**
Expand Down
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ PyPI has had no product change since `0.25.0` — nothing is broken.
- **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.

**Cross-port conformance corpora** (every port runs the shared corpus):
- Metamodel: `fixtures/conformance/` (449 fixtures; 38 shared corpora in total — per-corpus counts + the corpus x port matrix live in `docs/CONFORMANCE.md`). TS / C# / Java / Python all green.
- Metamodel: `fixtures/conformance/` (451 fixtures; 38 shared corpora in total — per-corpus counts + the corpus x port matrix live in `docs/CONFORMANCE.md`). TS / C# / Java / Python all green.
- Render: `fixtures/render-conformance/`. TS / C# / Java / Kotlin / Python byte-identical.
- 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".)
- 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.
Expand Down
Loading
Loading