Skip to content

Latest commit

 

History

History
291 lines (236 loc) · 64.1 KB

File metadata and controls

291 lines (236 loc) · 64.1 KB

MetaObjects Roadmap

Last refreshed 2026-07-16.

This file is the single source of truth for the roadmap. GitHub Milestones + Issues + the Project board mirror it. Keeping them in sync: docs/ROADMAP-PROCESS.md.

FR registry

Every feature request, its status, target release, and tracking issue. Shipped FRs are detailed under Shipped; planned FRs under Planned + the Release plan. ✅ shipped · 🔵 active · 📋 planned.

FR Title Status Release Issue
FR-002 Client/web package split
FR-003 Java RDB persistence & projections
FR-004 Cross-language prompt construction ✅ (MCP remains) #18
FR-005 Actionable loader errors (FR5 a–e)
FR-006 template.output parser-on-receipt
FR-007 Codegen conformance corpus
FR-008 Universal REST API contract
FR-009 Filter operators per port
FR-010 Output-format prompt + tolerant extract
FR-011 Extract hardening (enum coercion + nesting)
FR-012 Nested-object prompt expansion
FR-013 Field read-only
FR-014 TPH discriminator
FR-015 Source parameter-ref
FR-016 source.rdb name/kind aliases
FR-017 TPH polymorphic codegen
FR-018 Many-to-many relationships
AI LLM-call trace persistence 🔵 active
FR-019 Shared / externally-provided enums 📋 1.1 #5
FR-020 @inheritance joined strategy 📋 1.x #6
FR-021 api metadata + contract projections 📋 1.3 #7
FR-022 Contract emitters (JSON Schema/OpenAPI/protobuf) 📋 1.3 #8
FR-023 Metadata packages (cross-project sharing) 📋 1.x #9
FR-024 Entity surfaces (projection/value + declared API) 🟢 taxonomy + B3/B4a/B4b/B5/B6 validation parity + projection codegen shipped 5 ports (1.0); declared-API surface (api.operational/operation/binding.rest) deferred to 1.1 (foundation for FR-034) 1.0 · 1.1 #10
FR-025 Cross-port package-binding codegen config 📋 1.1 #11
FR-026 Forms completeness (edit forms + view parity) 📋 1.0 #12
FR-027 DataGrid downloads (CSV/XLSX/PDF/TXT) 📋 1.2 #13
FR-028 Strict serializer parity + meta export CLI parity 📋 1.1 #14
FR-029 Metadata API + runtime-driven UI 📋 1.4 #15
FR-030 Runtime serializers (SPI/XML/binary/round-trip) 📋 1.1 #16
FR-031 MetaData read-path caching + perf ✅ shipped 1.0 #17
FR-032 Canonical FQN refs (YAML-only relative paths) ✅ shipped (5 ports) 1.0 #21
FR-033 Provider definitions as declarative data + metamodel docs for LLMs 📋 designed 1.x #23
FR-034 Ecosystem tier — connected systems (system/container/surface/environment) 📋 designed (draft, deferred post-1.0) 1.1
FR-035 Present-key PATCH tristate (mutation surface) 🟢 shipped 5 ports (absent→untouched / present-null→clears / null-on-@required→400); coordinated breaking release held for FR-036 1.0
FR-036 Constraint-validation enforcement + semantic pins 🟢 shipped 5 ports in the coordinated 0.16.0/7.8.0 breaking release (required-string = non-empty·accept-whitespace · @Pattern = full-match · strictest-wins length; HTTP-tier enforcement all 5 ports; TPH tristate) 1.0

(FR-001 was the original metamodel foundation — pre-dates the FR-numbered tracking.) (FR-032 was developed under the working number "FR-026" — see commit history; renumbered to avoid the FR-026=Forms collision. Design: docs/superpowers/specs/2026-06-13-fr-032-canonical-fqn-refs-design.md, ADR-0032.)

Shipped

Foundation

  • H1 — Polyglot monorepo migration (2026-05-14) TS code consolidated under server/typescript/; package names normalized to @metaobjectsdev/*; CLI binary renamed to meta; config file metaobjects.config.ts; tool-state dir .metaobjects/.
  • H2 — Shared conformance fixtures (2026-05-15) Fixtures extracted into fixtures/conformance/; per-port conformance runners; canonical serializer (fused-key form); format documented in spec/conformance-tests.md.
  • H7 — npm publish: first public release (2026-05-23) All publish-candidate @metaobjectsdev/* packages published to npm at 0.5.0 then 0.6.0 (latest). The JS/TS workspace root was hoisted to the repo root so workspace:* resolves uniformly across the server + client package trees at publish time.
  • H8 — First TS consumer on published packages (2026-05-23) A real TS consumer migrated off link: filesystem deps onto the published packages and builds clean end-to-end — validating the published dist, .d.ts types, and runtime imports through a real pnpm install.

Per-port ports + codegen layers

  • TypeScript@metaobjectsdev/metadata + codegen-ts (Vite-style plugins) + runtime-ts + migrate-ts + the universal web client packages (runtime-web, react, tanstack). The reference port for everything cross-language.
  • C# full-stack targetMetaObjects (loader + canonical serializer + conformance) + MetaObjects.Render (Mustache + payload-VO codegen + verify) + MetaObjects.Codegen (EF Core entities + AppDbContext/owned-types via OwnsOne + CRUD minimal-API routes + Postgres DDL with full-CREATE + incremental introspect/diff/migrate via meta migrate --from-db).
  • Java portmetadata + omdb + om + dynamic + core-spring + metadata-ktx (Kotlin facade) + codegen-spring (Spring REST controllers + DTOs + repos + filter allowlists) + codegen-mustache + codegen-plantuml + codegen-base + render + maven-plugin (with meta:gen / meta:editor; schema migrations are owned by the TS toolchain — the Java diff-and-converge engine and its meta:migrate / live-DB-drift meta:verify goals were removed).
  • Kotlincodegen-kotlin (KotlinPoet on JVM): entity + Exposed table + Spring controller + Spring config + payload + relations + filter allowlist + validator + stored-proc + output-parser generators; integration-tests-kotlin runs the persistence-conformance corpus through Exposed against Testcontainers Postgres.
  • Python portmetaobjects (metadata loader + canonical serializer + conformance) + migrate + ObjectManager runtime + render (Mustache) + output-parser codegen.

Cross-port conformance corpora (every port runs the shared corpus)

  • Metamodel conformancefixtures/conformance/ (~90 fixtures + CAPABILITIES manifest). TS / C# / Java / Python all green.
  • Render conformancefixtures/render-conformance/. TS / C# / Java / Kotlin / Python byte-identical.
  • Persistence conformancefixtures/persistence-conformance/. TS / C# / Kotlin / Python all 12/12 against Testcontainers Postgres / Derby (per port). Java runs the query scenarios only (it no longer owns schema migrations); its runtime auto-create path bootstraps the schema, and the aggregate-projection view scenario is deferred (the view-body builder was part of the removed migration engine).
  • API-contract conformancefixtures/api-contract-conformance/. TS / C# / Java / Kotlin / Python all 20/20.
  • Extract conformancefixtures/extract-conformance/ (22 dirty-input cases, incl. default-scalar-int + array-of-enum). TS / C# / Java / Python all green; Kotlin reuses the shared JVM engine.
  • Output-prompt conformancefixtures/output-prompt-conformance/ (12 cases × 3 @promptStyle styles). Pins the FR-010 output-format prompt fragment byte-identically across all 5 ports (zero-drift, no ledger) + a render→extract round-trip skew guard. Fragments expand nested objects + arrays-of-objects + scalar arrays (FR-012). TS pilot; C# / Java / Python reproduce the bytes natively; Kotlin drives the shared JVM engine. Backlog item R13. (Also added three fixtures/conformance/error-enum-* negative fixtures pinning FR-011 enum-coercion attr-validation — @coerceDefault/@default membership + @normalize mode — across the 4 loader ports.)
  • Object-model conformancefixtures/object-model-conformance/ (7 scenarios). Pins the cross-port runtime object model: newInstance factory (map-backed ValueObject default, or a self-registered code-generated type), instance→MetaObject back-reference (MetaObjectAware), nested-object + array-of-objects field IO, overflow, and the codegen'd-or-not invariant. All 5 ports 7/7 (Java reference + reconcile; Kotlin over the JVM model; TS/Python/C# native, reflection-free). ADR-0017. (Phase A; metadata-driven extract + generalized @default build on it next.)
  • YAML / verify corpora — green across the ports that ship those layers.

Key cross-language features

  • Source v2 paradigmsource.rdb + @kind: table|view|materializedView|storedProc|tableFunction; multi-source via @role. ADR-0007.
  • FR-003 — Java RDB persistence & projections (Plans 1/2/3/4a + Plan 4): port of dynamic/om/omdb onto current core; build-time FQN-keyed binding registry + typed jsonb value-objects + Spring-tx connection; source.*+origin.* metamodel registered in Java; OMDB engine-debt remediation (atomic mapping cache, JDBC codec registry per ADR-0002, inTransaction template). The diff-and-converge schema-migration engine that originally shipped under FR-003 (SchemaMigrationEngine + introspector + emitter + the meta:migrate goal) was removed when schema migrations consolidated onto the TS toolchain (@metaobjectsdev/cli migrate); the Java port retains runtime persistence + a dev/test runtime auto-create path only.
  • FR5 family — actionable loader errors (a/b/c/d/e + WARN envelope-shape). ADR-0009.
    • FR5a: source-on-node + envelope-shaped errors (formatjson|yaml|merged|resolved|database|code)
    • FR5b: YAML source positions on yaml-input envelopes
    • FR5c: multi-file merge attribution (MergedSource + contributors[] + ERR_MERGE_CONFLICT + WARN_DUPLICATE_DECLARATION)
    • FR5d: reference-resolution errors (format: "resolved" + referrer + target)
    • FR5e: database-source envelope schema reserved + per-port shape tests + design questions resolved. Real DB-source loader is a future FR.
    • WARN envelope-shape assertion finalized across all 4 ports.
  • FR-006 — template.output parser-on-receipt codegen. ADR-0010. Shipped in all 5 ports (TS / C# / Java / Python / Kotlin); meta verify extended to cover output drift.
  • FR-010 — output-format prompt fragment + tolerant extract parser. Shipped in all 5 ports. One template.output drives three artifacts: a comment-free output-format prompt fragment (3 styles × json/xml via @promptStyle), a tolerant extractLenient() (8-stage, never-throws, returns an all-nullable mirror of the payload) that complements FR-006's strict parser, and the @example/@instruction/@enumAlias/@enumDoc field-teaching attrs. Pinned by the shared fixtures/extract-conformance/ corpus; tolerance is at classification + canonical value (not byte-identity). (Originally named recover; cross-port-renamed to extract pre-GA — #87.) Designed in docs/superpowers/specs/2026-05-29-fr-010-output-format-prompt-and-tolerant-parsing-design.md.
  • FR-011 — extract hardening (enum coercion + nested-object extraction). Shipped in all 5 ports (TS pilot → C# / Java / Kotlin / Python). Hardens FR-010's extractLenient() in place: an enum coercion pipeline (exact → @normalize none|collapse|strip@enumAlias@coerceDefault → MALFORMED), @default fills an absent enum (emitting the now-live DEFAULTED state, which satisfies @required), and uniform nested/embedded-object recovery via dotted child paths (meta.score, items[i].label) across JSON + XML (the renamed extract engine). Normalization is ASCII-only (manual case-fold, byte-identical cross-port); @normalize/@coerceDefault/@default are member-validated on field.enum at load time, with an object-level @normalize default. Fuzzy matching deferred (reserved pipeline slot). Corpus expanded 10 → 20 cases. Designed in docs/superpowers/specs/2026-05-30-fr-011-recover-hardening-design.md.
  • FR-012 — nested-object prompt expansion. Shipped in all 5 ports (TS pilot → Java / C# / Python; Kotlin inherits the shared JVM engine). The FR-010 output-format prompt renderer now recurses into nested OBJECT fields, arrays-of-objects, and scalar arrays (instead of a flat {name} placeholder) across all 3 styles (guide/inline/exampleOnly) × json/xml, with an identity-based cycle guard + MAX_NEST_DEPTH. Closes the FR-010 request/response asymmetry (extract already handled nesting). Output-prompt-conformance corpus 10 → 12 cases (added json-deep-nest + json-array-of-objects; json-nested/xml-nested now round-trip). Designed in docs/superpowers/specs/2026-05-30-fr-012-nested-object-prompt-expansion-design.md.
  • Cross-port runtime object model (Phase A). MetaObject.newInstance() factory → a map-backed ValueObject default or a self-registered code-generated type, with an instance→MetaObject back-reference (MetaObjectAware), a self-registering FQN→constructor ObjectClassRegistry, and a field get/set-by-name SPI — all reflection-free (the ValueObject path resolves no native class; typed binding is generated self-registration, never Class.forName/Type.GetType/reflect-metadata/importlib). Brought Java's runtime object model to TS/Python/C# (Kotlin reuses the JVM model). Pinned by object-model-conformance (7 scenarios, all 5 ports). ADR-0017.
  • Metadata-driven extract (Phase B). Runtime extract(MetaObject, text) → ExtractionResult<Object> assembles a typed object graph (nested objects + arrays-of-objects) via the Phase A model — never-throws, opt-in orThrow(), cycle/depth guard. Adds array-of-enum per-element coercion and generalizes @default to all field types (engine fill → DEFAULTED + per-type load validation in all 4 loader ports; Java legacy setDefaultValues/getDefaultValue unified). Each port's codegen extractLenient() delegates to the runtime (codegen-wrapping-runtime), closing the nested-object/array codegen gap ("Plan 2.1") while keeping a self-contained scalar/enum baked extractLenient() for back-compat. All 5 ports; extract-conformance byte-green. (Originally named recover; cross-port-renamed to extract pre-GA — extract is the industry-standard term and avoids colliding with the retry-loop sense of "recovery" — #87.) Designed in docs/superpowers/specs/2026-05-30-recover-codegen-nested-design.md.
  • Prompt-construction pillar — per-port building blocks complete. Render (Mustache) + payload-VO codegen + verify (FR-004), the output parser (FR-006), and the output-format prompt + extract (FR-010) all ship in all 5 ports. The library-side primitives of the fourth pillar are delivered; what remains is MCP exposure (see Planned).
  • Java flavored object + extractor codegen (shipped 2026-05-31, Java only). Direct (code-as-code, no templates) generation of objects that carry their MetaObject and extract a typed graph (nested + arrays-of-objects), in two selectable flavors via a flavor generator option: pojoAware (extends PojoObject) and valueObject (extends ValueObject, perf-tuned cached per-field value-holder accessors), plus a self-registering ObjectClassBindingProvider and a <Name>Extractor wrapping the Phase-B runtime extract. Reuses the legacy direct object-codegen framework byte-unchanged (extends via hooks; downstream-extensible protected seams + createWriter factory). Compile-and-run gated per flavor + Extractor + a downstream-customization proof. Other ports frozen until Java is correct; designed in docs/superpowers/specs/2026-05-31-java-flavored-object-codegen-design.md.
  • Cross-port <Name>Extractor codegen (shipped 2026-05-31, TS / Python / C# / Kotlin — capability parity with Java). A generated <Name>Extractor per template.output adds a strict extract tier over the existing lenient tier: extract returns the port's idiomatic strict typed payload (TS inferred type, Python Pydantic model, C# record, Kotlin data class) and throws on lost-required; extractLenient (never-throws, all-nullable mirror) is re-exposed. It reuses each port's existing nested-capable runtime-delegating lenient extract and a generated recursive mirror→strict mapper (nested objects + arrays-of-objects, one-shot construct), with no registry / binding / factory (codegen knows the type graph statically) and no new flavored object-class generation (constructs each port's existing idiomatic types). Compile-and-run gated per port (incl. non-string scalar arrays). Surfaced + fixed a latent cross-port scalar-array extract bug (JVM DataConverter array conversions were dead/throwing; the JVM/C# lenient extract emitted scalar arrays as non-arrays). Idiom divergence (intentional): TS/Python honor @required optionality in the strict payload; C#/Kotlin payloads are all-required (no optional-absent modeling) — extract works into each port's existing payload shape. The cross-port recover → extract rename (#87) then swept all 5 ports together. Designed in docs/superpowers/specs/2026-05-31-cross-port-extractor-codegen-design.md.
  • Typed enums in payload VOs (shipped 2026-05-31, all 5 ports). The strict extract<Name> payload types a field.enum (and enum arrays) with a value-constrained, idiomatic type instead of the prior inconsistent unknown/str/object/String: TS string-literal union, Python Literal[...], C# nested enum, Kotlin enum class, Java generated enum. The extract mapper coerces the engine-validated mirror string to the typed value — identity for TS (cast as <Union>, gated by tsc --strict) / Python (Literal, Pydantic runtime-validated); Enum.Parse/valueOf for C#/Java/Kotlin (the call IS the bridge; gated by Roslyn/javac/kotlin-compile-testing). Reuses each port's established entity enum-type emitter + the shared <Super>/<Owner><Field> naming + dedup (two fields extending one abstract field.enum → one generated type, proven per port). The lenient mirror stays raw string (Java has no separate mirror — its single typed payload record is shared by parse/extract/extractLenient with null-safe valueOf, a documented idiomatic divergence; never-throws preserved because the engine yields a valid member or null). Engine + fixtures/extract-conformance/ unchanged (codegen-typing only). Surfaced + fixed the enum-array "check-enum-before-isArray" lenient-mirror collapse bug in TS/Python/C#. Follow-up: super-resolution naming diverges only for 2+ level abstract-enum chains (immediate-super TS/C#/Python vs root-super JVM — pre-existing in the entity emitters, latent). Designed in docs/superpowers/specs/2026-05-31-typed-enums-payload-design.md.
  • template.output render-helper codegen (phase 1 shipped 2026-06-01, TS + Java; C#/Python/Kotlin = phase 2). template.output gains @kind (document default | email); a new per-port generator emits a typed render helper wrapping the existing shared render() engine — render<Name>(payload, provider): string for a document (renders @textRef in @format), render<Name>(payload, provider): EmailDocument {subject, htmlBody, textBody?} for an email (renders @subjectRef/@htmlBodyRef/@textBodyRef). The build-time mustache↔VO drift gate is the headline: the generator resolves each referenced in-repo .mustache and runs the existing verify() at codegen, FAILING the build when a {{field}} isn't on the payload VO (runtime check stays too). Replaces hand-written render({ref, payload, format, provider, verify}) boilerplate (the email-rendering hack). Reuses render()/verify()/the filesystem provider/the payload field-tree walk + EmailDocument — engine + render-conformance UNCHANGED (codegen + small metamodel only). Shared fixtures/template-output-render-conformance/ (document + email + drift) pins identical TS/Java output. (The recollected template.document metatype never existed — this is template.output + codegen.) Designed in docs/superpowers/specs/2026-06-01-template-output-render-helper-design.md.
  • Cross-port templateGenerator() (shipped 2026-05-28). TS reference + Python / C# / Java factories; 3/3 conformance fixtures byte-equivalent. Java ships lightweight types under com.metaobjects.render.templategen (its legacy Generator interface was incompatible). See design-docs/2026-05-28-cross-port-template-generator.md.
  • SP-1b — JVM declarative Mustache template generator (shipped 2026-06-28, Java + Kotlin). Wires the cross-port template generator into the JVM as a Maven-wirable TemplateScopeGenerator (com.metaobjects.generator.template, in codegen-base) over the byte-equivalent render engine — closing the prior "Maven-plugin integration is a follow-up" gap. Implements the three named scope walks (perEntity/perPackage/perModel), the neutral structural data dict, and the output-pattern grammar ({name}/{Name}/{package}), all gated byte-identical for both Java and Kotlin against the shared fixtures/template-codegen-conformance/ corpus (the same corpus the TS port passes). Kotlin gains a template generator for the first time (reuses the shared JVM engine — no KotlinPoet). Part of the SP-1 codegen authoring-parity program; designed in docs/superpowers/specs/2026-06-28-mustache-codegen-parity-design.md.
  • SP-1d — C# declarative Mustache template generator (shipped 2026-06-28). The last of the four SP-1 ports — all changes under server/csharp/. Brings the declarative template generator (scope perEntity/perPackage/perModel + outputPattern, no walk code) to C# in MetaObjects.Codegen.TemplateCodegen (OutputPattern.Expand, the TemplateData neutral data dict, ScopeWalk.ForScope, TemplateSpec.Parse/ToGenerators), and exposes it via a --template-spec <json> (+ --template-root <dir>) JSON surface on dotnet meta gen — turning the previously no-op templateGenerator() registry primitive into a real consumer-usable generator. A target field is rejected (C# has no output-target concept, same decision as Python), and a bad template ref / wrong --template-root yields a clean error not a stack trace. Gated byte-identical against the SAME fixtures/template-codegen-conformance/ corpus the TS + JVM + Python ports pass — all four ports now produce identical output. Part of the SP-1 codegen authoring-parity program; designed in docs/superpowers/specs/2026-06-28-mustache-codegen-parity-design.md.
  • OMDB Spring Boot 3 starter (shipped 2026-05-30). Autoconfiguration wires a DataSourceObjectManagerDB with Spring-tx; closes the OMDB-modernization open question (jOOQ migration ruled out as a non-goal).
  • FR-008/FR-009 — Cross-port REST API contract + 10 filter operators. Shipped in all 5 ports.
  • FR-018 — Many-to-many relationships. Shipped in all 5 ports. Slim vocabulary (@through/@sourceRefField/@symmetric, with @joinEntity/@joinFields removed; FK fields derived from the junction's identity.reference SSOT) + a generic runtime M:N resolver (TS / Java / Kotlin / Python / C#) + codegen (entity navigation + idiomatic ORM wiring [Drizzle m2m / EF Core UsingEntity / Spring repo+JPA / Exposed / Pydantic+route as the SQLAlchemy-secondary equivalent]) + REST traversal (GET /<source-plural>/{id}/<relation>) + Tier-2 docs. Gated by the shared api-contract m2m corpus in both lanes (reference-server + generated-artifact-over-HTTP) + persistence-conformance, across hetero / directed-self-join / symmetric modes. Remaining: a typed TanStack M:N client hook (client-ergonomics follow-up). Designed in docs/superpowers/specs/2026-06-02-fr-018-many-to-many-relationship-design.md.
  • SP-G — registry-conformance gate. Shipped in all 5 ports (TS / C# / Java / Kotlin / Python, live + green). A structural enforcer of the "metamodel subtype vocabularies must be identical across languages" contract: each port emits its registry as a canonical, fully-sorted, byte-stable JSON manifest matched to the single committed fixtures/registry-conformance/expected-registry.json. Reconciled the Java/Kotlin registries at source (the JVM runners compose from the defined metamodel provider set so codegen/om SPI doesn't pollute the measured vocabulary). Plus an untested-vocabulary coverage report (coverage-report.json) surfacing every registered (type, subType)/attr no fixture exercises. See fixtures/registry-conformance/README.md.
  • SP-H — field-subtype end-to-end hardening + write-path conformance. Shipped in all 5 ports. Every concrete field.* subtype now write+read round-trips through each port's runtime/ORM, gated cross-port: the persistence corpus gained an op: roundtrip scenario type (INSERT via the port's write codec, NOT raw SQL → read-back → assert wire-normalized value) whose AllTypes entity carries one field of every persistable subtype against Testcontainers PG — the structural complement to SP-G (which gated vocabulary). Cut field.byte/field.short/field.class as non-functional registration-only stubs; reconciled uuid/currency filter-op bands cross-port + a loader guard for @filterable-without-op-band; Java write-codecs (timestamp/currency/enum/native-uuid/time) + Spring field.time arm; TS decimal string-exact dataType; Kotlin runs the shared metamodel corpus + a mapper-else negative test; bare field.object rejected at load (ADR-0013). The write-gate surfaced + drove latent breakage "all corpora green" had masked (TS enum-CHECK, Java timestamp/native-uuid/time/jsonb writes, Kotlin LocalTime-write, C# read-back-caching, the filter-op divergences). Designed in docs/superpowers/specs/2026-06-03-sp-h-field-subtype-hardening-design.md.
  • Per-target output directories (TS codegen). Each generator routes to a named output target ({ outDir, importBase?, outputLayout?, dbImport? }).
  • 0.6.x → 0.7.0 consumer-friction batch. Stock promptRender() generator; db-parameter generated repo helpers (ADR-0008); Cloudflare Workers deploy recipe; CHANGELOG.md backfill + camelCase ↔ snake_case docs. (Currently published as 0.7.0-rc.2; GA promotion is the next release move.)

Active

  • 0.7.0 GA promotion — currently 0.7.0-rc.2. Diff vs rc.2 is essentially one additive type (warningEnvelopes? on LoadOutcome in @metaobjectsdev/conformance). Procedure: docs/RELEASING.md (bun publish, regen lockfile, external install smoke in npm + pnpm).
  • AI LLM-call trace persistence — cross-port rollout. A metaobjects-native typed-trace store: each LLM call is persisted in the adopter's own DB with request/response as typed value objects (the same payload projection the prompt pillar declares + drift-checks), the one thing blob-only observability tools (Langfuse/Helicone/OTel) structurally can't do. Scope locked by ADR-0024: MetaObjects owns the typed trace + recorder seam + the vendor-NEUTRAL call glue; the provider call + pricing are bring-your-own (plug the stack's LLM library — Vercel AI SDK / LiteLLM / Spring AI — behind the one-method LlmClient). Shipped in TypeScript (the reference port): shipped library/ai/llm-call.yaml (LlmCallBase) + opt-in libraries loader; the recorder (recordLlmCall, never-throws, redaction seam) + buildLlmCallRow whose key set is gated == LlmCallBase's fields; deriveTraceFields (typed voRequest/voResponse jsonb columns derived from a nested template.prompt's @payloadRef/@responseRef); generated record<Entity>/call<Entity> (extract + persist base + typed in one row); @metaobjectsdev/ai-runtime (LlmClient seam, runLlmCall, callLlm, CompositeRecorder + optional LangfuseRecorder/OtelRecorder exporters); shared-table STI (@discriminator/@discriminatorValue, reuses FR-017 TPH). Cross-port (P3) in progress, JVM first: the Java metamodel slice shipped (@responseRef on template.prompt + template.* admitted as object.entity children + a TS_PILOT_VOCAB registry-manifest exclusion; ai-trace-prompt-nested + ai-trace-sti un-ledgered in Java). Remaining: the Java recording half (OMDB recorder + the deriveTraceFields loader pre-pass + record<Entity> Spring codegen + a persistence round-trip), then Python → C# → Kotlin, then the atomic carve-out close (register @responseRef in every port + remove TsPilotVocab from all ports + add it to expected-registry.json). Phased plan: docs/superpowers/plans/2026-06-06-ai-trace-descope-and-cross-port.md.

Planned

  • #195 follow-ups — projection read-model origins. The four capabilities (origin.aggregate @agg:any|all|collect, origin.computed @expr, origin.first) shipped (validate + type in all 5 ports; TS meta migrate view synthesis; see CHANGELOG.md [Unreleased] + docs/superpowers/specs/2026-07-15-issue-195-projection-readmodel-origins-design.md). Remaining as fast-follows: (a) the "not-migrate-managed" escape valve — now tracked as #208 in the projection/view-materialization epic below (an @sqlView-style attribute carrying hand-written view DDL PLUS a distinct "managed elsewhere" marker, generalizing to any DB object, so a genuinely-irreducible view no longer aborts the whole meta migrate run); (b) a collect native-array persistence roundtrip gate (Postgres text[] vs SQLite json_group_array → same wire) in fixtures/persistence-conformance/. The TS-side real-engine value gate now EXISTS (integration-tests/test/view-lifecycle-{pg,sqlite}.test.ts value-probe all four #195 origin kinds — any/all/collect/computed/first — incl. the empty-set pins any=false/all=true/collect=[]/first=null on real PG and real SQLite). The remaining work is the CROSS-PORT persistence-conformance scenario (a projection with a collect array column read by all 5 ports' runtimes), which is blocked on per-port native-array read support: TS + Python already read a text[] → JSON array (native driver decode + a list branch in each normalizer); C# needs an array/IEnumerable case in MetaObjects.Conformance Normalization.NormalizeValue (emit a JsonArray) + a generated/mapped ProgramInsights EF entity; Java needs an OMDB JDBC array-read codec (java.sql.ArrayList) for field.string @isArray (its Normalization already has a List branch, but JdbcCodecs never produces a List); Kotlin needs a ProgramInsightsView Exposed table with a native-array column type registered in QueryScenarioRunner.tableFor (+ its DEFERRED_SCENARIOS skip valve in the interim). Note the ports pure-glob-discover queries/*.yaml (Java/Python/C# have no skip mechanism), so the scenario cannot land until C#/Java array reads exist. normalization.md will gain the "SQL array → JSON array (empty {}[], NULL→null)" contract when it lands. (c) #204 — SHIPPED (codegen-ts projection-decl now carries a projection field's isArray/storage:jsonb through extends into both the Drizzle view column and the Zod read schema, so collect → T[] types correctly; TS-only, pending the next npm release). origin.computed's expression grammar is designed so #159's arithmetic / case / @via-joined refs slot in as additive node kinds.

  • Projection / view-materialization epic (#206–212). Follow-ons from #195 + adopter feedback on migrating legacy SQL-view-heavy schemas. Grouped by effort × 1.0-timing; Group A is TS-meta migrate-owned (schema is TS-only per ADR-0015 → single-port, no 5-port fan-out).

    • Group A — concrete, 1.0-shippable (TS migrate/codegen):
      • #206 — Docs on-ramp: surface entity read-views (FR-024 §7) as the first answer for legacy SELECT A.*, extras views + an entity-vs-projection decision table. Docs-only, no metamodel change. Shipped. #213 — SHIPPED (schema/write half): meta migrate now excludes derived (origin.*) fields from the write table DDL (new MetaField.isDerived()) AND emits the replica read-view (isWriteThrough wired into buildProjectionViews, entity-host mode in extractViewSpec — "one emitter, two hosts"); the TS write codecs (Drizzle table + Insert/Update Zod schemas) exclude them too. Gated by a real-Postgres round-trip (emit → apply → introspect → re-diff EMPTY) in view-lifecycle-pg. Was a real correctness bug (silent wrong-table + missing view). #214 — SHIPPED (unreleased): the FR-024 §7 codegen READ half across all five ports — generated reads route to the replica view, the entity read type carries the derived fields via a by-PK re-read (read-your-writes), writes target the table and exclude derived fields. (Flattened field.object on a write-through entity is a tracked sub-limitation.) A shared cross-port #214 gate SHIPPED (unreleased) — and found+fixed a real TS bug. Building it surfaced that the TS reference port's generated REST routes for a write-through entity were never wired to the view: routes-file.ts mounted vanilla mountCrudRoutes(table) (no view concept), so the deployed HTTP surface returned GET/POST responses OMITTING the derived field — the read-half had shipped in queries.ts + the view but the routes layer was left behind. Fixed: mountCrudRoutes gained an optional readView (list/get + post-write re-read route through the view; writes stay on the table), and routes-file.ts passes it for write-through entities. The shared gate lives in fixtures/api-contract-conformance/write-through/ (a Customer + write-through Order corpus: POST create returns the derived customerName, GET reads it through the replica view) and runs on TS / C# / Kotlin — the ports whose GENERATED artifact re-reads through the view (TS readView, C# EF .ToView read-model, Kotlin inline Exposed OrderView). Java and Python are intentionally excluded (weak signal): their generated controller delegates read-your-writes to the runtime (Python ObjectManager) or the consumer persistence seam (Java), which the api-contract in-memory-repo lane bypasses — so a gate there would test a hand-written seam repo, not the generated re-read. A persistence-conformance op: roundtrip gate was ruled out as the route because that corpus exercises the runtime read path, where write-through view-routing exists only in Python's ObjectManager (TS runtime-ts, Java OMDB, C# EF FindAsync, Kotlin/Exposed all read the write table).
      • #209 — SHIPPED (released in 0.17.0): derive INNER vs LEFT OUTER join from reference optionality — a NOT-NULL belongs-to FK renders INNER JOIN (matching the hand-written view + keeping verify --db fingerprints aligned), a nullable belongs-to or any has-many hop stays LEFT OUTER, with nested-chain demotion (an INNER hop under a LEFT ancestor demotes to LEFT to avoid dropping base rows). extract-view-spec.ts + view-ddl-emit.ts, gated by join-type-derivation.test.ts. The optional explicit @join: inner|left override is not needed (the optionality-derived default is correct); defer until an adopter wants to force it.
      • #207 — SHIPPED (unreleased): View-level @filter (row-scope WHERE) reusing the 5-port attr.filter AST, lowered to an outer WHERE in emitViewDdl. Closed the single largest functional gap for filtered views (soft-delete / status / type views). Semantic (field + op), never raw SQL. Cross-port validation (dangling + aggregate-derived); op-band / malformed-shape checks are TS-only.
      • #208 — SHIPPED (unreleased): DDL-ownership escape valvessource.rdb @sql (a hand-written view body migrate registers + fingerprints + drift-checks but never authors/parses, adopted via migrate --allow adopt-view) + @unmanaged (skip create/drop/drift for a Flyway/hand-migration-owned view or table). The load-bearing piece is the suppression rule (classify DDL-ownership before viewIsDerived), which closes a silent-wrong-synthesis hole. Registration + 6 loader-validation rules cross-port (5 ports); migrate/verify lowering TS-only (ADR-0015). See ADR-0043 + docs/superpowers/specs/2026-07-17-issue-208-ddl-ownership-escape-valves-design.md. Deferred follow-ups: (a) @dependsOn for @sql views — an opaque body's dependsOn is derived from extends-anchors only, so a JOINed-but-unanchored table is not tracked for auto-recreate around a column ALTER (add the explicit attr when an adopter hits it); (b) the matview managed path (@sql on @kind: materializedView — needs pg_matviews introspection + COMMENT-on-matview + REFRESH); (c) opaque-body column-name verification (verify cross-checks an @sql view's information_schema.columns against the declared field set).
    • Group B — 1.0-freeze-window vocab decision (needs an owner ruling before the freeze):
      • #210 — Retire origin.* on object.value (total value purity: no identity, no source, no origins). Pre-1.0 per ADR-0035's window; cross-port payload-VO churn but "mostly node-type relabeling" since the payload path already shares the projection codegen path. Ruling: do the churn now vs. accept the fallback rule-of-thumb and leave the two-spellings seam.
    • Group C — post-1.0 backend generalization (design-now, build-later):
      • #212 — Events emit projections: resolve the ADR-0007 vs ADR-0028 contradiction (a stream is a channel, not a source). The ADR amendment (drop source.event; model emission at the surface as api.eventing/operation.event/binding.messaging with a payload→projection ref) is cheap to decide now; the eventing surface builds post-1.0. Lands the CQRS+events symmetry: queries return projections, commands take values, events emit projections.
      • #211Backend-agnostic projection materialization (one derivation spec, N lowerings): generalize SelectSpec from RDB-only to document/search/… with an origin × (paradigm, @kind) capability matrix + load-time errors. Large FR; its foundation is Group A landing with the "semantic, not RDB-specific" lens (#207/#208/#209 become the first lowerings). Post-1.0; composes with FR-034 (ecosystem tier).
  • FR-019 — Shared + externally-provided enums. Stop redeclaring a field.enum inline in every consuming entity: a package-level abstract field.enum materializes ONE standalone enum type per port (the existing D6 extends reuse vocabulary), and @provided: true — a provenance flag on the named-type declaration (not the field), shared cross-type with value objects — references an existing hand-written type instead of emitting one (per-port namespace via codegen config, never a metadata FQN — retires the C#-only @csEnumType). Decision in ADR-0026; implementation spec docs/superpowers/specs/2026-06-06-fr-019-shared-and-provided-enums-design.md. (Generators are now subclass-extensible across all 5 ports, so this lands on open seams.)

  • FR-020 — @inheritance persistence strategy (single-table vs joined). TPH (one physical table, nullable subtype columns) is the single implicit strategy today (FR-014/FR-017). FR-020 adds an @inheritance attr to choose joined (a base table + per-subtype tables, joined on read) as an alternative — additive, default stays TPH (no breaking change). Status: design (proposed, sequenced after FR-017, which shipped). Design: docs/superpowers/specs/2026-06-07-fr-020-inheritance-strategy-design.md. (Was not previously surfaced in this roadmap.)

  • FR-025 — Cross-port package-binding codegen config. Config for how a metadata FQN/package maps to each port's native namespace/package at codegen time (the ADR-0001 build-time binding), so cross-package references (and metadata shared across projects, FR-023) emit correct imports per language. Status: design (ready for implementation). Design: docs/superpowers/specs/2026-06-08-fr-025-cross-port-package-binding-config-design.md. (Was not previously surfaced in this roadmap.)

  • MCP exposure of declared prompts/tools — the remaining library-side piece of the prompt-construction pillar. Surface a template.output / tool declaration over the Model Context Protocol (model-agnostic) so an LLM host can discover + register it, built on the shipped render / payload / verify / FR-006 / FR-010 primitives. Designed in docs/superpowers/specs/2026-05-22-fr-004-cross-language-prompt-construction-design.md.

  • FR-024 — Entity surfaces: object.projection, universal field-extends, and the declared API. A third object subtype (derived, read-only, borrowed identity via extends; the declared field set IS the exposure — fail-closed), universal Entity.child extends-resolution (load-time drift gate on every contract shape), @via single-hop-unique inference, multi-source entity view behavior, and the api.operational / operation.query|command / binding.rest surface — across all 5 ports, conformance-gated; the two pre-taxonomy spellings (entity-extends-entity views, proc-results-as-entities) are removed outright (hard cutover, pre-GA). Decisions: ADR-0028 / ADR-0029 / ADR-0030. Design: docs/superpowers/specs/2026-06-12-fr-024-entity-surfaces-projections-design.md; program plan: docs/superpowers/plans/2026-06-12-fr-024-entity-surfaces-program.md. Supersedes the shape-vocabulary half of the FR-021 sketch (its api/wireId direction stands, retyped onto projection/value).

  • FR-021 — api metadata type + contract projections. Declared API surfaces (operations + per-protocol bindings) over the derived-CRUD default; operation payloads are object.value projections (the same origin.* machinery as prompts and views); wire-stable wireId numbering lives on the contract projection (never the entity) so domain evolution can't break wire compat. Design sketch: docs/superpowers/specs/2026-06-11-fr-021-api-metadata-and-contract-projections-design.md. Revised by FR-024: contract shapes are object.projection (query outputs) / object.value (command inputs); subtype vocabulary api.base/api.operational; see ADR-0030.

  • FR-034 — Ecosystem tier: connecting meta-modeled systems over a network. A semantic topology layer that models the ecosystem — many meta-modeled systems and how they call each other — rather than a single system's shapes. C4-style two-level nesting: system (logical software system) → container.service|client (the deployable network participants), each carrying surface.provided|consumed edges whose @apiRef resolves (FQN, ADR-0041) to an api.* node in the same or a dependency package; plus environment.deployment (the named instantiation that keys a generated per-environment address-config matrix). URLs are not metadata (a generated, fail-closed address contract keyed per environment carries them); the logical topology moves into core (superseding ADR-0030 §5) while the physical tier stays permanently out. Reuses FR-023 (metadata-package transport), ADR-0041 (resolution), and ADR-0029 (the load-time drift gate, now spanning repos → cross-system drift detection = pillar 3, one tier up). Depends on the FR-024 declared-API surface. Owner rulings (2026-07-10): C4-nesting, topology-into-core, names-only environments, defer third-party. Draft, deferred post-1.0. Design: docs/superpowers/specs/2026-07-10-fr-034-ecosystem-tier-connected-systems-design.md. Downstream convergence evidence (a consumer independently re-deriving the consumed-edge address contract + protocol-off-the-type-axis): spec/design-docs/2026-07-11-downstream-convergence-outbound-adapters.md.

  • FR-022 — Contract emitters (Tier-2): JSON Schema 2020-12 (canonical + strict structured-output profile) → OpenAPI 3.1 → protobuf. One shared neutral engine per ADR-0020; strict profile targets the cross-provider structured-output intersection (also MCP input schemas); proto emission consumes FR-021 wireIds, maps types per the locked table (Decimal/minor-units/uuid-string/optional/UNSPECIFIED-enum-zero), and inherits wire-compat regression detection via buf breaking on the emitted artifacts. Design sketch: docs/superpowers/specs/2026-06-11-fr-022-contract-emitters-design.md.

  • FR-023 — Metadata packages: cross-repo distribution + reuse. A code-free, versioned artifact (the metaobjects/ tree + manifest) published through each ecosystem's registry (npm/Maven/PyPI/NuGet) and declared via metadataDependencies in config; loader source composition + overlay/extends across package boundaries (mechanics already shipped) with dependency-then-local merge order, collision rules, and per-package provenance attribution. Design sketch: docs/superpowers/specs/2026-06-11-fr-023-metadata-packages-design.md.

    • Near-term doc-first quick wins (available now, no new code): the mechanics of cross-project sharing already work — overlay merge, deferred cross-package extends, and dir/URI loaders — so before the full package-resolution build, ship recipes: (a) a monorepo pattern (one shared metaobjects/ dir loaded by TS + Java + Python projects), (b) a git-submodule pattern (pull upstream metadata into a local metaobjects/), and (c) wire the already-defined-but-unused .metaobjects/config.json sources field (TS) to the loader so { kind: "path" } overlays compose. These cover most "share a model across our backends" needs with documentation; FR-023 proper adds true dependency resolution + the metaobjects.pkg.json manifest. TS-only libraries mechanism (metaobjects::ai) is the single existing precedent — generalize it under FR-023.
  • FR-026 — Forms completeness: edit forms, view-render parity, validator wiring (TS web client). Builds on what ships today — create forms (@emitFormformFileuseEntityForm + Zod InsertSchema), field display via view.* cell renderers (~10 of 13 subtypes), and client form rules (required/length/regex). Gaps to close: (1) edit formsUpdateSchema is already generated but no codegen consumes it; emit <Entity>EditForm (load existing values as defaults, PATCH, same field-visibility rules as create); (2) view-render parity — register datetime as a view.* subtype (its renderer exists but no metadata path selects it) and add renderers for hotlink / month / radio; (3) validator wiringvalidator.numeric / validator.array are emitted to Zod but NOT to the client form rules (only field attrs are); (4) view attrs — only @locale is schema'd; @placeholder / @helpText / @step / @rows / @pattern are currently ad-hoc; (5) optional layout.form (field grouping / sections / conditional visibility). TS-web-only by architecture (the browser is the TS-native UI surface). Supersedes the Future "Forms codegen revival" note. Status map from the 2026-06-13 audit.

  • FR-027 — DataGrid data export + grid completeness (TS web client). layout.dataGrid + the TanStack grid codegen (columns + grid hook) + runtime (server-driven sort / paginate / filter / free-text search, 9 filter ops, withCount envelope, extensible cell renderers, React + Angular variants) ship solid. Headline gap: data export / download does not exist anywhere. Add CSV / XLSX / PDF / TXT export driven by the grid's current columns + filter/sort state: client-side for the loaded page, plus an optional server-side bulk-export endpoint (GET /<entity>/export?format=…, pagination off, streamed) for full-dataset export; reuse the existing render escapers.ts CSV formula-injection guard. Optional @exportFormats attr on layout.dataGrid. Secondary grid gaps: column width / visibility / reorder / resize metadata (meta.width is reserved but never populated; no @hidden/@columnWidth), row (multi-)selection, and making server-side search behavior consistent cross-port. Status map from the 2026-06-13 audit.

  • FR-028 — Strict object serializers (cross-port parity) + meta export CLI parity. (Baseline for FR-030.) The metadata canonical serializer (loaded metadata → canonical JSON, raw + effective) already ships in all 5 ports, and the meta export CLI ships in TS. The object-graph strict serializers are uneven: object → JSON strict (with symmetric read) ships only in TS (objectToJson/jsonToObject) and Java (JsonObjectWriter/JsonObjectReader) — missing in Python / C# / Kotlin; object → XML strict write is missing in every port (only the tolerant extract XML read side exists). Backlog: (1) port object→JSON strict to Python / C# / Kotlin (conformance-gated alongside the existing op: roundtrip gate); (2) add meta export to the Java / Python / C# / Kotlin CLIs. Status map from the 2026-06-13 audit.

  • FR-029 — Metadata API + runtime-metadata-driven UI (backend-agnostic). The web UI is TS (browser-native) but must be drivable by metadata fetched from any backend over APIs, so the same grid/forms work regardless of server language. Two delivery modes, both supported + demoed: today's codegen UI, and a new runtime mode that fetches the model and builds the UI dynamically. Gaps: a metadata API endpoint per backend (serve canonical metadata as JSON over HTTP), a browser runtime metadata loader (runtime-web → in-browser MetaData read-model), a runtime-driven dataGrid + runtime-driven create/edit forms, a both-ways reference app, and a backend-agnostic guarantee (the TS UI verified against all 5 backends serving the metadata + data APIs). Detail: §"Theme 1" of docs/superpowers/specs/2026-06-13-metadata-runtime-ui-and-serializers-gaps.md.

  • FR-030 — Runtime metadata-driven serializers: protocols, round-trip, field-subset. Serialize/deserialize an object graph driven by the MetaData itself (honoring normalization.md), on Pojo or ValueObject instances, resolving the MetaObject via MetaObjectAware (fast path) or the ObjectClassRegistry. A pluggable serializer SPI so new protocols slot in uniformly: JSON + XML write (revive the legacy metaobjects-core/dynamic JSON+XML), plus a binary protocol (protobuf — reuse FR-022's wireId/type mapping — and/or MessagePack/CBOR) "to show how standardized it is." Per port: a thin adapter over the native serializer (Jackson / System.Text.Json / Pydantic / kotlinx) where one fits, fully custom otherwise. A field-subset/projection serialization parameter (reuses FR-024 projections; shared with grid JSON/XML downloads). Round-trip integrity conformancejson → xml → binary → json, assert no data loss, cross-port. Open ADR: keep bidirectional serialization separate from one-way (lossy) data download, sharing JSON/XML via the field-subset param. Detail: §"Theme 3" of the gap doc.

  • FR-031 — MetaData read-path caching (general; serialization is the example). Repeatedly walking the MetaData tree for field/attr/validator/view/children lookups is a hot path for every consumer — codegen, runtime, the UI, and (as the headline example) serializing 100k+ large objects re-queries the tree per object. The MetaData read-model is immutable after load, so memoize these lookups on the MetaData class once. Deliberately not serialization-specific: it's a general read-path cache that any processing benefits from, validated by a throughput benchmark gate (process 100k+ objects, cached-vs-uncached delta) per port, using serialization as the example workload. Low effort, high leverage. (The serialization-specific perf — a per-MetaObject compiled plan + streaming large sets — rides with FR-030, building on this cache.) Detail: §"Theme 4" of the gap doc.

Tracked outside this library repo (not roadmap work here)

These are exercised in adopter projects on top of the shipped per-port primitives, and are deliberately not tracked as open items in this repo:

  • Consumer-adoption validation — downstream consumers migrating onto metaobjects-emitted code across the language paths (the former H5 / H9 / H10). The library surface they exercise (codegen-spring, MetaObjects.Codegen, the web-client packages, etc.) already ships.
  • Application-level prompt-pillar consolidation — the end-to-end declared-prompt orchestration and prompt eval harness that sit on top of the per-port primitives (the former H6, minus MCP exposure, which remains a library item above).

Release plan (1.0 → 1.x)

Grouping of the Planned work into releases. Multiple items per release is fine. Before 1.0 we keep it lean — consistency fixes + cheap, broadly-leveraged foundations; the big new themes (serializers, downloads, runtime-driven UI) land post-GA where they can be built properly without holding the GA.

Before 1.0 (tackle now — consistency + cheap foundations)

  • FR-031 — MetaData read-path caching + throughput benchmark. Low effort, high leverage, benefits everything; serialization is the example, not the only consumer. (Doug-prioritized.)
  • FR-026 — codegen edit forms + view-render parity (TS web only, small). Create forms ship but edit forms don't — create/edit symmetry is table-stakes for a GA.
  • meta export CLI parity (Java/Python/C#/Kotlin) — trivial cross-port CLI consistency (the carve-out of FR-028 that's cheap; object↔JSON port-parity itself rides 1.1).
  • GA mechanics — the 0.10.0 publish (npm + NuGet/PyPI/Maven re-cut so meta docs / verify --codegen/--db / the SDK-docs parity are installable) → smoke → promote to 1.0.
  • [RESOLVED 2026-07-10] FR-024 — entity surfaces (projection/value taxonomy + declared API). The breaking half — the projection/value taxonomy + B3–B6 validation parity + projection codegen — shipped in the 1.0 line across all 5 ports (the pre-GA hard cutover is done, and the serializer/download field-subset (SER-7) can build on the now-shipped object.projection). The declared-API surface (api.operational/operation/binding.rest) is confirmed not a 1.0 gate and slips to 1.1, where it becomes the foundation for FR-034 (ecosystem tier). Rationale: it is greenfield additive vocabulary (nothing registered yet), so deferring costs no compatibility and keeps the 1.0 line lean.
  • [OPTIONAL] FR-019 — shared/provided enums (small, already designed) — slot here or 1.1.
  • [OPTIONAL] FR-025 — cross-port package-binding codegen config (ready for implementation) — pulls into 1.0 if FR-024's cross-package generated imports need it; otherwise 1.1.
  • [OPTIONAL] MCP exposure — completes the prompt pillar's library side; pull to 1.0 only if "4 complete pillars" is a GA marketing bar, else 1.1.
  • Reference-app coordination (wizardsofodd). A live adopter reference — wizardsofodd.com, source at Draagon/wizardsofodd — is public: one metadata spine drives its Cloudflare D1 schema, API types, LLM prompts, and SSE protocol, drift-gated in CI. As part of the 1.0 launch: (1) bump the reference to the 1.0 packages via a public, drift-gated PR — a green gate publicly demonstrates upgrade safety (the Dependabot @metaobjectsdev/* group PR does this); (2) link it from metaobjects.dev as the "see it in production" proof (play it live / read the source / watch the drift gate catch a rename); (3) keep it ≤ one published line behind — fold "bump the reference app" into the release checklist so it never lags.

1.1 — Serialization foundation + connected-systems tier

  • FR-024 declared-API surface — the deferred half of FR-024: api.base/api.operational, operation.query|command, binding.rest, inputRef/outputRef/many; loader ref-resolution + path-template↔identity validation; per-port route-shell codegen (typed handler seam, verb bodies hand-written); meta verify + meta docs; atomic expected-registry.json flip across 5 ports. The foundation FR-034 references.
  • FR-034 — ecosystem tier (connected systems). Semantic topology for connecting meta-modeled systems over a network: system (logical) → container.service|client (deployable participants) → surface.provided|consumed (the API edge, @apiRef → an api.* node) + environment.deployment (named instantiation, names-only in v1). URLs stay out of the metamodel (a generated address contract, keyed per environment); supersedes ADR-0030 §5 for the logical tier. Reuses FR-023 (transport) + ADR-0041 (resolution) + ADR-0029 (cross-repo drift gate) — additive vocabulary, no new machinery. Design: docs/superpowers/specs/2026-07-10-fr-034-ecosystem-tier-connected-systems-design.md.
  • FR-028 finish — object↔JSON strict parity (Python / C# / Kotlin).
  • FR-030 core — serializer SPI; XML write (revive the legacy core/dynamic JSON+XML); field-subset via FR-024 projections; Pojo/ValueObject/MetaObjectAware support; json↔xml round-trip conformance. Realizes ADR-0031.
  • FR-030 serialization perf — per-MetaObject compiled plan + streaming (on FR-031's cache).

1.2 — DataGrid downloads

  • FR-027 — client export (CSV/XLSX/PDF/TXT) + server bulk-export endpoint (all backends) + JSON/XML download via the 1.1 serializer & field-subset + export conformance + the secondary grid gaps (column width/visibility/selection, consistent server search).

1.3 — Binary protocols + contract emitters

  • FR-030 binary — protobuf / MessagePack / CBOR over the SPI → completes the json → xml → binary → json no-data-loss round-trip gate.
  • FR-022 — contract emitters (JSON Schema / OpenAPI / protobuf) — overlaps the protobuf serializer (shared wireId/type mapping); do together.

1.4 — Metadata API + runtime-driven UI

  • FR-029 — metadata API endpoint (all backends) → browser runtime metadata loader → runtime-driven dataGrid + create/edit forms → both-ways (codegen vs runtime) demo → backend-agnostic verification (the TS UI against all 5 backends).

1.x / later

  • FR-023 — metadata sharing (full package resolution; the doc-first quick wins can land any time, independent of release).
  • FR-020 — @inheritance joined strategy (additive; pairs with a persistence release).
  • MCP exposure (if not pulled earlier — see below).
  • Database-source metadata loader (currently Future).

Future (sketched)

Candidate directions, not actively tracked — pulled up into Planned only when scheduled.

  • Database-source metadata loader — load the metamodel itself from a database (a metaobjects-table schema + a loader that reads it) instead of JSON/YAML files, for a central / runtime-editable metadata registry. FR5e already reserves the format: "database" error envelope (table + id + optional jsonPath), so the error contract is in place; the loader itself is unbuilt.
  • Date / case transforms.
  • Materialized views, federated entities, search-index sources.

Theme — metadata as the substrate for LLM-authored software

A forward-looking cluster: today the LLM is a consumer of metaobjects (it reads the model, proposes metadata, writes against generated code). The next inflection is the LLM as author of the model — it emits typed metadata (the durable spine), verify gates it before it runs, codegen produces disposable per-language code, and escape hatches cover what metadata can't express. This sits in the seam between "the LLM writes the code" (maximally expressive, opaque, ungovernable output) and "the LLM writes config/flows" (safe but locked to a fixed node/component vocabulary). The same typed-payload + declarative-template + verify mechanism already describes the data model and prompts — extending it to the UI makes the model the single spine an LLM authors across all three render targets. These build on shipped primitives + the planned FRs noted; none are scheduled yet.

  • Declared LLM-operation — a metadata node binding a complete I/O unit (input payload VO + prompt template + output VO + parse strategy) as one codegen'd, runtime-resolvable, verify-able unit. The pieces exist separately today (payload, template, render, output parser); this composes them. Completes the prompt pillar; relates to the MCP-exposure item above.
  • Bindable view/layout fields + UI action model — a binding attr (literal / data-pointer path / function-call) on view.*/layout.* nodes, with pointer-resolution validated in verify exactly as a {{slot}} is validated against a prompt payload; plus a typed UI action/event output VO — the UI's response contract, peer to a prompt's output VO. Makes metadata-driven UI symmetric with metadata-driven prompts. Builds on FR-026/FR-029.
  • Generative-UI interop — emit a declarative generative-UI catalog (e.g. the A2UI shape: catalog + components + dynamic binding) from native view/layout metadata, and import external catalogs — a standards-interop codegen target alongside Drizzle / EF Core / Pydantic. Builds on FR-022 (contract emitters) machinery.
  • Portable model interchange — a vendor-neutral, diffable export/import for a whole declared model (data VOs + prompts + UI + actions), building on the canonical serializer (FR-028/FR-030) and metadata packages (FR-023). The fragmentation evidence is real: declarative-flow/agent platforms each ship their own JSON and none interoperate. A neutral interchange for declared app/agent metadata is unclaimed ground.
  • Runtime model authoring loop — dynamic VO instantiation from a field tree with no regen step, pluggable template providers (filesystem / database / custom) behind the render resolver, and verify promoted to a first-class runtime gate (validate an LLM-authored-or-mutated template/model before persisting or rendering). Overlaps FR-029's runtime mode; the authoring-gate framing is the new piece.

(Forms codegen revival has been promoted to FR-026 in Planned.)


Note on H4 ("TS-codegen Java target") — retired

An earlier version of this roadmap listed H4 — TS codegen Java target as a 2-3 week project to refactor codegen-ts into pluggable targets so a Java target could emit Spring code from TS. That framing is obsolete and retired.

The pattern that has actually shipped across all four language ports is: each port has its own codegen layer in its host language.

Port Codegen module Emits
TS codegen-ts TS entities, Drizzle, Zod, Fastify routes
C# MetaObjects.Codegen EF Core entities, AppDbContext, ASP.NET routes, Postgres DDL
Java codegen-spring Spring @RestController, DTO records, repositories, filter allowlists
Kotlin codegen-kotlin KotlinPoet output: Exposed tables, Spring controllers, payload VOs, output parsers, stored procs
Python metaobjects.codegen Pydantic models, FastAPI routes, output parsers

A polyglot codegen engine in TS would have meant forcing every Java consumer to install Node/bun just to generate Java — and the C# / Kotlin / Python ports already proved this isn't necessary. Java's codegen-spring is real, shipped, and emits the full cross-port surface (FR-006 / FR-008 / FR-009 / FR-010) alongside the other ports; there is no remaining per-port codegen gap.