diff --git a/AGENTS.md b/AGENTS.md index f5d5cf47e..6b51e229a 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -6,7 +6,7 @@ MetaObjects is a **cross-language metadata standard** for declaring typed entity The metamodel is the **durable spine**; generated code is the **disposable artifact**. Substrate is local-first: typed metadata lives in your repo, generated code is idiomatic per-language output with **no proprietary runtime**: the generated entity and model code imports nothing from MetaObjects at runtime, and the REST, prompt, client and runtime tiers import ordinary Apache-2.0 packages you can vendor, fork or replace. If `@metaobjectsdev/*` disappears tomorrow, you keep working code. -**Core vs helpers (ADR-0034 Amendment 3, 2026-09-22).** Only the core is a product promise: the metamodel, loader, canonical format and registry; runtime metadata access (the `ObjectManager` and its drivers; the HTTP adapters that mount it on a web framework are helpers, 2026-09-24 ruling); schema migrations (`meta migrate`); the drift gates (`meta verify`); prompt render and the reply parser. Every generator that writes application code into an adopter's repo — routes, controllers, ORM wiring, DTOs, forms, grids, hooks, filter allowlists — is a **reference helper**: it must compile and pass its reference fixtures, and the adopter copies it with `meta eject` and owns the copy. Mechanical test: what the tool guarantees is core; what it writes into your repo is a helper. Every port can eject: `meta eject` (TypeScript), `metaobjects eject` (Python), `mvn metaobjects:eject` (Java/Kotlin), `dotnet meta eject` (C#). Not every generator ships a reference copy: `meta gen --list` marks the ones that do not `package-only` (in TypeScript: `template`, which is exempt for good, and `requirements` and `agent-docs`, which are pending; ADR-0034 Amendment 3 correction, 2026-09-26, narrowed by Amendments 5 and 7, and held to the shared manifest by Amendment 8). When you find a generator defect, fix the reference; do not describe it as a broken core guarantee. +**Core vs helpers (ADR-0034 Amendment 3, 2026-09-22).** Only the core is a product promise: the metamodel, loader, canonical format and registry; runtime metadata access (the `ObjectManager` and its drivers; the HTTP adapters that mount it on a web framework are helpers, 2026-09-24 ruling); schema migrations (`meta migrate`); the drift gates (`meta verify`); prompt render and the reply parser. Every generator that writes application code into an adopter's repo — routes, controllers, ORM wiring, DTOs, forms, grids, hooks, filter allowlists — is a **reference helper**: it must compile and pass its reference fixtures, and the adopter copies it with `meta eject` and owns the copy. Mechanical test: what the tool guarantees is core; what it writes into your repo is a helper. Every port can eject: `meta eject` (TypeScript), `metaobjects eject` (Python), `mvn metaobjects:eject` (Java/Kotlin), `dotnet meta eject` (C#). Not every generator ships a reference copy: `meta gen --list` marks the ones that do not `package-only` (in TypeScript: `template`, which is exempt for good, and `docs-site`, whose builder stays packaged and whose theme `meta eject docs-site` copies; ADR-0034 Amendment 3 correction, 2026-09-26, narrowed by Amendments 5 and 7, and held to the shared manifest by Amendment 8). When you find a generator defect, fix the reference; do not describe it as a broken core guarantee. ## Six pillars @@ -16,13 +16,13 @@ The first four ship per-language today across the five ports (TS / C# / Java / P 2. **Runtime metadata** — load metadata at runtime, drive behavior dynamically (CRUD, validation, relationships, dynamic admin UIs, LLM tool registration). On Kysely (TS), a DB-API 2 driver via ObjectManager (Python), modernized JDBC + Spring-tx via OMDB (Java), Exposed (Kotlin). **C# runtime metadata is on the roadmap** — its EF Core output is generated code, not a metadata-driven runtime; the runtime `MetaObjects` package depends only on YamlDotNet and ships no data access. 3. **Drift detection** — `meta verify` catches divergence between code and metadata (covers entity codegen, prompt templates, output parsers, schema). Quality-of-life on top of codegen + runtime. 4. **Prompt construction** — a prompt is code, not a string scattered across services. Declare a prompt's payload as a typed projection (payload bloat becomes a diff), keep its text external and provider-resolved, and render it deterministically: snapshot-testable, cache-stable (no whitespace change silently breaking exact-prefix prompt-cache hits), and drift-checked at build time so a renamed field can't degrade a prompt. Conformance-gated, so the guarantee holds in every language port. **Render + payload-VO codegen + `verify` + parser-on-receipt for a *responding* `template.prompt` — one carrying `@responseRef` (FR-006) — + the output-format prompt fragment & tolerant `extract` parser (FR-010) ship in all five ports today** (since 0.24.0 the whole inbound tier keys off `@responseRef`; a `template.output` is outbound-only and emits no parser — ADR-0052) — the library-side building blocks of the pillar are complete. The one remaining library-side piece is MCP exposure of declared prompts/tools (see `spec/roadmap.md`); the application-level consolidation (eval harness, end-to-end declared-prompt orchestration) and consumer adoption are exercised in adopter projects, not in this library repo. Designed in `docs/superpowers/specs/2026-05-22-fr-004-cross-language-prompt-construction-design.md`. -5. **Requirements and testing** — declare what the software is supposed to *do* in the same model as the entities, so a capability claim is checkable instead of prose. The other four pillars keep the code honest about the *model*; this one asks whether the thing you said the software does is actually built — an absence no test can fail on, because a test exercises code that exists. `requirement.functional` (existence: `meta verify` WARNS when nothing implements it) and `requirement.architectural` (universality: `meta verify` FAILS a live policy applied to nothing, and does not check that each claimed node complies) are registered vocabulary in all five ports, with the loader enforcing the closed `@status` enum. `@implementedBy` is **resolved, not trusted** — it names a real member of the real model, so a claim whose implementation was renamed or deleted fails the build instead of going quietly stale. `meta verify` reports the ledger on every run (unresolved links, entities no claim covers, gaps recorded versus gaps nobody has ruled on) plus an authoring lint whose findings can never fail a build; `meta docs` renders it for humans and for agents. **The port split, stated exactly: the vocabulary loads and validates in all five ports; the requirement gate runs in every port's `verify` (ADR-0057 — `docs/CONFORMANCE.md` "Split coverage"); every port ships an ejectable `requirement-tests` generator — which scaffolds a test per claim; the seven authoring-lint advisories are TypeScript-only.** A green run proves referential integrity, never that a status is true or an implementation correct (`docs/features/requirements.md`, "What a green run does not prove"). A project that declares no `requirement.*` nodes sees no change at all. Note the standing carve-out: `agent-context/skills/metaobjects-fit-assessment/SKILL.md` deliberately does NOT treat `requirement.*` as an assessment axis — the ruling is in `docs/superpowers/specs/2026-07-12-metaobjects-fit-assessment-maintainer-notes.md`; read it before "finishing the job" there. +5. **Requirements and testing** — declare what the software is supposed to *do* in the same model as the entities, so a capability claim is checkable instead of prose. The other four pillars keep the code honest about the *model*; this one asks whether the thing you said the software does is actually built — an absence no test can fail on, because a test exercises code that exists. `requirement.functional` (existence: `meta verify` WARNS when nothing implements it) and `requirement.architectural` (universality: `meta verify` FAILS a live policy applied to nothing, and does not check that each claimed node complies) are registered vocabulary in all five ports, with the loader enforcing the closed `@status` enum. `@implementedBy` is **resolved, not trusted** — it names a real member of the real model, so a claim whose implementation was renamed or deleted fails the build instead of going quietly stale. `meta verify` reports the ledger on every run (unresolved links, entities no claim covers, gaps recorded versus gaps nobody has ruled on) plus an authoring lint whose findings can never fail a build; the documentation generators render it for humans and for agents (`requirementsFile()`, `agentDocsFile()` and their counterparts in the other ports). **The port split, stated exactly: the vocabulary loads and validates in all five ports; the requirement gate runs in every port's `verify` (ADR-0057 — `docs/CONFORMANCE.md` "Split coverage"); every port ships an ejectable `requirement-tests` generator — which scaffolds a test per claim; the seven authoring-lint advisories are TypeScript-only.** A green run proves referential integrity, never that a status is true or an implementation correct (`docs/features/requirements.md`, "What a green run does not prove"). A project that declares no `requirement.*` nodes sees no change at all. Note the standing carve-out: `agent-context/skills/metaobjects-fit-assessment/SKILL.md` deliberately does NOT treat `requirement.*` as an assessment axis — the ruling is in `docs/superpowers/specs/2026-07-12-metaobjects-fit-assessment-maintainer-notes.md`; read it before "finishing the job" there. 6. **Libraries** — reusable declared design, shipped as metadata and opted into by name (`"libraries": ["iam"]` in `.metaobjects/config.json`). Not a sixth verb: a library is the **reuse unit that composes the other five** — entities, requirements, the generators its design implies, its runtime packages — as one named, opt-in, drift-gated artifact. What makes it a pillar rather than a folder of YAML is the fifth: without requirements a library is a schema snippet; with them it is design an adopter's build is held to, which is the same test the requirements pillar passes (*does it change what an agent can be checked against?*). **A library is LAYERED and its core layer is INERT** — the core declares no `source.rdb`, and a sourceless object generates nothing and migrates to nothing (#248), so `["iam"]` adds zero tables and zero generated code while making the design present and resolvable; `["iam", "iam/db"]` is the separate opt-in that proposes the schema. **Copy is the expected mode** (`meta eject ` — ADR-0034's ruling applied to metadata), and an ejected copy still named in `libraries` is refused at load (`ERR_LIBRARY_PACKAGE_COLLISION`) rather than merging asymmetrically. Object coverage activates on ADOPTER-authored requirements only, so a library cannot volunteer a project for a gate it did not ask for. `iam` (preview) and `ai` (stable) ship today; rows appear in `meta gen --list` beside the generators. See [docs/features/libraries.md](docs/features/libraries.md) and `docs/superpowers/specs/2026-09-13-fr-043-feature-and-nfr-packages-design.md`. ## Status -_Last refreshed 2026-10-10._ +_Last refreshed 2026-10-14._ **1.0 gating — the quiet period is RETIRED (2026-09-06).** `docs/1.0-readiness.md` §G3 no longer asks for "one coordinated release with no metamodel-breaking change." It measured a @@ -39,10 +39,11 @@ because a conformance corpus gates the ports against each other and never agains in ADR-0035 **Amendment 3**. Do not reintroduce a waiting gate in any form. -**Where the versions are.** `latest` is **`1.1.0`** on npm, **`8.1.0`** on Maven Central, -**`1.1.0`** on PyPI and **`1.1.0`** on NuGet (the Maven major is always **npm major + 7**, so -1.1.0 is 8.1.0). 1.0.13 was the last 1.0.x release; the four registries moved together on 1.0.13, 1.0.12, 1.0.11, 1.0.10 and 1.0.9 (Maven skipped 8.0.8), and earlier Maven alone took 1.0.6 (8.0.6) while the other three skipped that -number. Both patterns are the convergent-publishing rule working as intended. **1.0 is CUT** and **1.1 is shipped**: the 1.0.0-rc candidates through 1.0.13 are superseded, and npm's `next` tag is REPOINTED onto each release — not deleted, because +**Where the versions are.** `latest` is **`1.0.13`** on npm, **`8.0.13`** on Maven Central, +**`1.0.13`** on PyPI and **`1.0.13`** on NuGet (the Maven major is always **npm major + 7**, so +1.1.0 will be 8.1.0). **1.1.0 is not released yet**: the `CHANGELOG.md` section headed +`[1.1.0]` is the release being prepared, not a published one. 1.0.13 is the last 1.0.x release; the four registries moved together on 1.0.13, 1.0.12, 1.0.11, 1.0.10 and 1.0.9 (Maven skipped 8.0.8), and earlier Maven alone took 1.0.6 (8.0.6) while the other three skipped that +number. Both patterns are the convergent-publishing rule working as intended. **1.0 is CUT** and **1.1 is in preparation**: the 1.0.0-rc candidates through 1.0.13 are superseded, and npm's `next` tag is REPOINTED onto each release — not deleted, because `dist-tag rm` 403s for every token we hold (`docs/RELEASING.md` §4). `metamodelVersion` read **`1.0`** through 1.0.13 — C4 landed and G4 shipped it, and no 1.0.x patch moved it (1.0.4 relaxed `@sourceRefField` onto `@cardinality: one` with a prose-only @@ -80,7 +81,7 @@ PyPI has had no product change since `0.25.0` — nothing is broken. **Key cross-language features shipped:** FR5 family (a/b/c/d/e + WARN envelope-shape — actionable loader errors per ADR-0009); FR-003 (Java RDB runtime persistence + projections; schema migrations are TS-only — the Java migration engine was removed); FR-006 (template.output parser-on-receipt codegen per ADR-0010 in all 5 ports); FR-008 + FR-009 (cross-port REST API contract + the nine filter operators); FR-018 (M:N relationship codegen in all 5 ports — entity navigation + idiomatic ORM wiring [Drizzle m2m / EF Core `UsingEntity` / Spring repo+JPA / Exposed / Pydantic+route as the SQLAlchemy-secondary equivalent] + REST traversal `GET //{id}/` + Tier-2 docs, gated by the shared api-contract m2m corpus in both lanes + persistence-conformance; the TanStack M:N client hook is a deferred client-ergonomics follow-up); SP-H (field-subtype end-to-end hardening: every concrete `field.*` subtype write+read round-trips cross-port via the persistence `op: roundtrip` gate; cut `field.byte`/`field.short`/`field.class` non-functional stubs; cross-port filter-op reconciliation for uuid/currency); source v2 paradigm (ADR-0007); metadata-ktx Kotlin facade; per-target output directories (TS codegen); FR-044 (the reporting vocabulary — `dimension.attribute`/`dimension.time`, `measure.aggregate`/`measure.ratio`, `segment.filter`, `object.report`, `@spine` on a report to take rows from a to-one dimension entity, `@default` on a measure for empty aggregates, plus the relative-date filter value — registered and loader-validated in all five ports; a report that declares a read-only `source.rdb @kind: view` is lowered to a SQL view by `meta migrate` and read by every port, and served by a generated read-only list route in every port, gated by the api-contract `report/` sub-corpus; the TypeScript `cube-model` reference generator writes the vocabulary as Cube data-model files, gated by the `fixtures/cube-model/` corpus and a `cube` lane that loads the output into a real Cube; a served report gets the generated TanStack list hook (`useList`) but no grid or form, see [docs/features/reporting.md](docs/features/reporting.md) and [docs/features/cube-export.md](docs/features/cube-export.md)). -**Latest release: 1.1.0** (2026-10-10) — npm `1.1.0`, PyPI `1.1.0`, NuGet `1.1.0` and Maven Central `8.1.0`. The reporting release (FR-044): declare dimensions, measures, segments and an `object.report`, and get a SQL view, a served read-only list route in every port, a generated TanStack list hook, and a Cube data model, with `@spine` for rows that have no facts and `@default` for an empty measure. Also carries the first slice of requirements (the gate in every port's `verify`), the derived-key parity fix across the ports, and the list-hook and nested-average fixes found by the first adopter. See the `CHANGELOG.md` 1.1.0 section for the full scope, pre-release RC history, and the diffs to expect when you upgrade (ejected generators and keyless projections). The previous release, 1.0.13 (2026-10-03), was a PATCH on 1.0.x. +**Next release: 1.1.0** (in preparation; npm `1.1.0`, PyPI `1.1.0`, NuGet `1.1.0` and Maven Central `8.1.0` when cut). The reporting release (FR-044): declare dimensions, measures, segments and an `object.report`, and get a SQL view, a served read-only list route in every port, a generated TanStack list hook, and a Cube data model, with `@spine` for rows that have no facts and `@default` for an empty measure. Also carries the first slice of requirements (the gate in every port's `verify`), the derived-key parity fix across the ports, and the list-hook and nested-average fixes found by the first adopter. See the `CHANGELOG.md` 1.1.0 section for the full scope, pre-release RC history, and the diffs to expect when you upgrade (ejected generators and keyless projections). It also makes documentation a set of generators in every port (ADR-0034 Amendment 9): the docs commands are removed, and `docs/features/migrations/docs-are-generators.md` is the upgrade path. The latest release, 1.0.13 (2026-10-03), was a PATCH on 1.0.x. Active and planned work lives in GitHub: issues labelled `FR`, milestones for releases, and the MetaObjects Roadmap project board. `spec/roadmap.md` keeps the release direction and the FR → issue → spec index. Process: `docs/ROADMAP-PROCESS.md`. @@ -421,9 +422,9 @@ meta eject [--list] # copy a reference generator into the repo meta migrate # diff metadata vs DB schema; emit migration SQL meta migrate --dry-run # preview without writing migration file meta migrate apply-pending # replay the committed chain against --db (no diff, no metadata) -meta verify --codegen --docs --templates # drift gates: generated code, docs pages, prompt bodies +meta verify --codegen --templates # drift gates: generated code and docs pages, prompt bodies meta verify --db | --replay # schema drift vs a live DB | the chain applies to an empty one -meta docs [--agent] # neutral model/api pages; --agent writes the three agent/ pages +meta gen --generators docs,api-docs # only these declared entries; docs are generators (docsFile(), apiDocsFile(), agentDocsFile(), ...) meta upgrade --apply # rewrite metadata a retirement made illegal meta types [] --format json|toon # what vocabulary this build actually registers meta fmt [...] [--check] # rewrite metadata into canonical form; --check lists drift (#304, every port) diff --git a/CHANGELOG.md b/CHANGELOG.md index 10089c882..ef7c00ce1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,19 +12,19 @@ here.** ### Fixed -- `meta verify --docs` now reports a generated page in the docs root that no current object - produces (for example the `.md` page of an object that was removed) as drift. It was - silent about every such page outside `agent/`, so an adopter kept ten orphan pages with the - gate green. Ownership rests on the `@generated` marker, so hand-written files in the docs root - and the `api/` subtree are still left alone. No other port ships a docs-verify surface, so - none shares the gap. +- A generated documentation page that no current object produces (for example the + `.md` page of an object that was removed) is reported as drift. 1.0's + `meta verify --docs` was silent about every such page outside `agent/`, so an adopter kept + ten orphan pages with the gate green. `meta verify --codegen`, which checks documentation in + 1.1.0 (see **Removed** under 1.1.0), reports each as a file a fresh run would not write. + Hand-written files in the docs directory are left alone. - The `hand-rolled-aggregate` advisory now names `object.report` for grouped, served or reported figures, and says an `object.projection` with `origin.aggregate` still fits a per-row figure. -- **`meta docs` honours `routesFile({ expose })` and `routesFileHono({ expose })`.** The API - pages listed all five verbs for an entity whose routes file mounts fewer (`DELETE` for an entity +- **The api reference (`apiDocsFile()`) honours `routesFile({ expose })` and + `routesFileHono({ expose })`.** The API pages listed all five verbs for an entity whose routes file mounts fewer (`DELETE` for an entity exposed as `["list", "get"]`), so the adopter overrode the pages by hand. The generators now - carry the option in a `mountsRoutes` marker, `meta docs` reads it off the resolved suite - (`runRoutesExpose`) per routes surface, so a narrowed Fastify routes file beside a default Hono + carry the option in a `mountsRoutes` marker, and `meta gen` reads it off the declared list + (`runRoutesExpose`) per routes surface, even in a run narrowed by `--generators`, so a narrowed Fastify routes file beside a default Hono one (or the reverse) narrows only its own section, and documents only the verbs mounted: `update` lists both `PATCH` and `PUT`, a read-only projection or report still lists `GET`, and a TPH base is narrowed from its read-only pair. Output without `expose` is byte-identical. **An owned (ejected) copy needs the @@ -41,6 +41,19 @@ changes only where the Java and Python parser fixes under **Fixed** bring those with TypeScript, and each entry says which models that affects. This is a MINOR because the metamodel moved and reporting is a new feature, not because the package surface broke._ +**Breaking, in every port: documentation is generated the way code is.** Every generator, +documentation included, is an entry in the project's generator list; one command runs the +list; nothing is generated that the list does not declare. The docs commands are removed: +`meta docs` and `meta verify --docs` (TypeScript), `dotnet meta docs` (C#), `metaobjects docs` +(Python) and the `metaobjects:docs` goal (Java and Kotlin, 8.1.0). Each prints where its work +went and exits 2. A gen command given a 1.0 docs configuration fails before it writes anything +rather than running and writing no documentation, and in TypeScript a project with no +`metaobjects.config.ts` fails `meta gen` with a pointer instead of having its pages written +from defaults. There is no upgrade script: [docs-are-generators.md](docs/features/migrations/docs-are-generators.md) +has a section per port, written for a coding agent to apply to the config by hand. Ruling: +ADR-0034 Amendment 9, which numbers the release 1.1.0 (Maven 8.1.0) by the maintainer's +explicit decision. The entries are under **Removed** and **Changed**. + **What 1.1.0 is.** The reporting release (FR-044): declare dimensions, measures, segments and an `object.report`, and get a SQL view, a served read-only list route in every port, a generated TanStack list hook, and a Cube data model, with `@spine` for rows that have no facts and @@ -75,7 +88,7 @@ Total hand-written lines did not fall, so do not read it as a total line reducti never ejected needs nothing. - **A keyless projection regenerates differently (G12).** `meta gen` rewrites the read-only surface of a keyless projection (no `/:id` route, no by-id function, and no write verbs in the - API docs), and `meta verify --docs` reports the affected pages as stale until they are + API docs), and `meta verify --codegen` reports the affected pages as stale until they are regenerated. Run `meta gen` and review the diff; three-way merge preserves hand edits. - **A multi-hop enum field references the shared enum.** A field that reaches a package-level abstract enum through another field, with no `@values` or `@intValueMap` @@ -122,11 +135,11 @@ generator catalog and the Atlas evaluation are 1.2 work. release candidate is allowed. No generator emits different bytes because of this change. - **Seven generators that no registry listed are registered**, so `--list`, the eject commands and the registry-driven tests see them. TypeScript: `requirements` (the ledger - pages `meta docs` writes) and `agent-docs` (the pages `meta docs --agent` writes), both - neutral and both still run by `meta docs`; a `generators` entry naming either string is - refused the way `"docs"` is. Java: `plantuml`, `html-docs`, `ai-docs`, `json-schema` and the + pages) and `agent-docs` (the `agent/` pages), both neutral, listed in `generators` like + every other generator (`requirementsFile()`, `agentDocsFile()`). Java: `plantuml`, `html-docs`, `ai-docs`, `json-schema` and the deprecated `mustache`, each by the class name a pom already uses. `mustache` will not ship - eject source. The four Java generators that can ship it do: see **Java and Kotlin** below. + eject source. The two TypeScript generators are ejectable (see the TypeScript entry below), + and the four Java generators that can ship it do: see **Java and Kotlin** below. - **Java and Kotlin: eject hands over the emitters a generator writes through, and `api-docs`, `plantuml`, `html-docs`, `ai-docs` and `json-schema` are ejectable.** An ejected @@ -176,6 +189,54 @@ generator catalog and the Atlas evaluation are 1.2 work. so a copy owns emit code only; the old static methods and constants on the two generators stay as deprecated forwarders. +- **A TypeScript generator is ejected whole: the code that writes its output comes with it.** + `meta eject ` used to copy a thin generator that decided what to emit and called the + package to write it: an owned `entity` was 223 lines over about 3,500 packaged ones. It now + also copies the transitive closure of the template modules the generator calls into + `codegen/templates/`, the way it already copies the HTTP adapter into `codegen/runtime/`, + and the owned generator imports them from there. This covers every stock generator except + `template`, the Mustache primitive, which has no emit logic of its own (the ruling every + port shares). Ruling and reasoning: ADR-0034 Amendment 8; how it works: + [own-your-codegen](docs/features/own-your-codegen.md#what-the-copy-holds). + - **What stays in the package is the engine.** The generator base, the model walks, the + naming and type-mapping tables (`names`, `naming`, `column-mapper`), the primary-key and + TPH walks (`pk-resolver`, `tph`) and the projection and report lowering `meta migrate` + also runs. The list is `ENGINE_MODULES`, and every name an owned file takes from the + engine is exported from a new entry, `@metaobjectsdev/codegen-ts/engine`, with `ts-poet`'s + `code`, `imp` and `joinCode`. The package root is unchanged: nothing it exported in 1.0.13 + was removed from it except the docs configuration types under **Removed**. A module a + generator reaches that is not on the list is copied. + - **A copy differs from the package in its import lines only.** A relative import of an + engine module becomes an import of `@metaobjectsdev/codegen-ts/engine`, a relative import of + another template module becomes the path to your copy, and `ts-poet` becomes the engine's + own, so a copy cannot split the `Code` class identity. `meta eject --list` compares every + file under `codegen/templates/` as it compares the generators, and prints the `diff` + command for each that differs. `--format json` gains `templates[]` on each ejected row. + The install line names what the copies import, with the range the package declares + (`@toon-format/toon` for `requirements`). + - **Eject alone, from an empty project, and it works.** A test derived from the catalog + ejects each of the 25 generators by itself, then checks that nothing it holds imports a + packaged module that writes output, that every file typechecks the way an adopter's + `tsconfig.codegen.json` checks it, and that it writes what the packaged generator writes, + byte for byte, over six models that make every generator emit. + - **`requirements`, `agent-docs` and `metamodel-docs` are in the catalog and ejectable.** + The first two were the generators behind `meta docs --requirements` and + `meta docs --agent`, and had no registry row, so no listing, no eject and no gate saw + them; `metamodel-docs` is new (see **Changed**). An owned copy goes in `generators` in + place of the packaged factory, like every other owned copy. `meta gen` hands the agent + pages the physical schema it computes, on `ctx.docs`, when `generators` lists + `agentDocsFile()`; the packaged generator reads it there when its options give none. + - **Copies made before 1.1.0 keep working and gain nothing.** They import their renderers + from the package entry, which still exports them. `meta eject ` over one leaves it + alone and copies no template module it would never call; `meta eject --force` + takes the new shape, so merge your own edits into the new file first. + - **The reference templates changed their imports, not their output.** Each imports the + template modules it calls by path (`../templates/…`) and the engine from + `@metaobjectsdev/codegen-ts/engine`. Four template modules gained a package subpath so + another codegen package can reach them by path: + `@metaobjectsdev/codegen-ts/templates/{entity-meta-file,field-meta,filter-shared,tph-discriminator}`. + This repository's own owned copies (the `test-generators` package and the two examples) + carry their template modules too; `scripts/sync-owned-template-copies.ts` writes them. - **The Java `entity` and `extractor` generators can be ejected.** `mvn metaobjects:eject -Dnames=entity,extractor -Dport=java` copies each generator, with the rest of its emit, into your `codegen/` module. They were the two Java generators that @@ -364,7 +425,9 @@ generator catalog and the Atlas evaluation are 1.2 work. own: which objects get a module and where it lands. The module body stays in the package (`renderCallableFile`, `renderTraceHelper`, now exported from `@metaobjectsdev/codegen-ts`), the same split the prompt tier uses. The rule is that every stock generator can be - ejected except the `template` primitive, which has no emit logic of its own to own. + ejected except the `template` primitive, which has no emit logic of its own to own, and + the TypeScript `docs-site`, whose builder stays packaged while `meta eject docs-site` + copies its templates and assets. `shared-model`, `docs` and `api-docs` follow in their own entry below (ADR-0034 Amendment 7), and the Java `entity` and `extractor` generators became ejectable in ADR-0034 Amendment 6. @@ -593,8 +656,8 @@ generator catalog and the Atlas evaluation are 1.2 work. zero are null, and a count is zero. The TypeScript `ObjectManager`, Java OMDB and the Python `ObjectManager` read a view-backed report (list and count, with filter, sort and limit on the derived fields; by-id and writes are refused); C# generates a keyless EF Core row type and - `DbContext` mapping for it and Kotlin an Exposed table object. `meta docs` lists the view on - the agent schema page. **Still absent:** no `measure.derived` and no query-time grouping (the + `DbContext` mapping for it and Kotlin an Exposed table object. `agentDocsFile()` lists the + view on the agent schema page. **Still absent:** no `measure.derived` and no query-time grouping (the next entry says how a report is served). Six shared persistence scenarios (`report-*.yaml`) and `report-shapes.json` hold the ports to the same columns; the `metaobjects-authoring` skill now teaches reports (`references/reporting.md`). @@ -649,12 +712,12 @@ generator catalog and the Atlas evaluation are 1.2 work. `!isAbstract` as the `meta generator` scaffold does, now receives a served report's read model: gate grid or form output on `servesClientTier` (a hook is wanted for a report: see the list hook below). -- **Reports have model and API pages in `meta docs` (FR-044).** Every report gets a model page +- **Reports have model and API pages in the documentation generators (FR-044).** Every report gets a model page (its `@from`, its view or "Not served" with the reason, its row scope, and a column table with a definition per column) listed under `## Reports` on the model index, and a page on the site. An entity that declares dimensions, measures or segments, or that a report reads from, gains a "Reporting" section. A served report gets one API page (row model, `GET `, the - list query) in `meta docs` and in every port's api-docs builder; a report that is not served + list query) in `apiDocsFile()` and in every port's api-docs builder; a report that is not served gets none. `EntityDocData` gains four optional keys for an owned `docs/entity-page.md` template: `hasReport`, `reportBlock`, `hasReporting`, `reportingBlock`. A model with no reporting nodes renders the same model pages as before. @@ -712,7 +775,7 @@ generator catalog and the Atlas evaluation are 1.2 work. `decimal`, `double` or `float` measure and for a ratio, so the column keeps one storage class; MySQL reads a defaulted ratio of zero as `0.0000`). `meta migrate` refuses a derived `@spine` report, by name, when the spine entity or an entity on the way has no table, is a TPH subtype, - or a hop has no `identity.reference`. In `meta docs` a defaulted measure's definition ends + or a hop has no `identity.reference`. On the model pages a defaulted measure's definition ends "; `n` when there is nothing to aggregate" (a defaulted ratio no longer says "null when the denominator is 0"), and a `@spine` report's page gains a **Rows** line and a row scope that reads "aggregating only …". Gated by three new persistence scenarios (42 in all, nine for @@ -726,6 +789,8 @@ generator catalog and the Atlas evaluation are 1.2 work. three, every stock TypeScript generator can be ejected except `template`, the Mustache primitive: you already supply its template and it has no emit logic of its own to own, so it stays `package-only` (the C#, Java and Python ports rule the same way). The + `docs-site` generator, new in this release, is the other `package-only` entry: its builder + stays packaged, and `meta eject docs-site` copies the site's templates and assets. The standalone `mermaid-er` generator is not among them: it is removed (see **Removed** below). Ruling and reasoning: ADR-0034 Amendment 7. Nothing changes for a project that ejects none of them: packaged output is byte-identical, and gated to be. @@ -736,17 +801,12 @@ generator catalog and the Atlas evaluation are 1.2 work. closure check, serialize, core-vocabulary re-load) and `renderSharedModelFiles` (the file names, the hash, the manifest). A test publishes with an ejected copy and has a consumer sync, lock and verify the result. - - **`meta eject docs` and `meta eject api-docs`** copy the generators behind - `meta docs`. List the copy in the docs block of `metaobjects.config.ts`, a new key: - `docs: { generators: [docsFile()] }`. It carries a `docsSurface` marker, and - `meta docs` and `meta verify --docs` run it in place of the packaged generator for that - surface. `meta eject` prints exactly that wiring, and its JSON row carries - `wire.into: "docs.generators"`. The copy owns which nodes get a page, - where a page lands, the overview page and which forms of the API reference are written. - A docs generator does not go in the top-level `generators`: `meta gen` skips one there - with a warning that names `docs.generators`. Two entries for one surface, or an entry - with no `docsSurface`, are refused by name. The `requirements` and `agent` pages stay - packaged. + - **`meta eject docs` and `meta eject api-docs`** copy the model-page and api-reference + generators. The copy goes in `generators` in place of the packaged factory, like every + other owned copy, and `meta eject` prints that wiring. The copy owns which nodes get a + page, where a page lands, the overview page and which forms of the API reference are + written. (`requirements`, `agent-docs` and `metamodel-docs` eject the same way; see the + TypeScript eject entry above.) - To change only the wording of a model page you still need no generator: a `templates/docs/entity-page.md.mustache` in your project wins over the packaged one. - Steps and what each copy owns: @@ -755,15 +815,13 @@ generator catalog and the Atlas evaluation are 1.2 work. project directory. Under `meta gen` it equals `ctx.projectRoot`. Under `meta verify --codegen` the run writes into a temporary tree and `ctx.projectRoot` is that tree, as before, because owned `entity` and `routes` copies compute an import path - against it. Under `meta docs` and `meta verify --docs` it is the directory that holds - `metaobjects.config.ts`, and `--templates` does not move it. Read files through - `ctx.inputRoot`; `runGen` takes it as `inputRoot`. + against it. Read files through `ctx.inputRoot`; `runGen` takes it as `inputRoot`. The + docs generators read a project's template overrides and owned site theme through it. ### Changed Eight corrections that shipped with report serving and reach models that declare no report. -Each one changes generated code on the next `gen`, or generated docs on the next `meta docs` -or Python api-docs build, as its entry says. A drift gate that covers that output reports it +Each one changes generated code or generated docs on the next gen run, as its entry says. A drift gate that covers that output reports it until you regenerate. - **TypeScript and Python: a read-only projection with no declared identity loses its item @@ -807,11 +865,11 @@ until you regenerate. schema disagreed with the row it parsed. Code that treated the parsed field as a `number` stops typechecking. - **TypeScript API docs: a read-only object's page documents only what is generated.** In - `meta docs` API pages, a read-only projection's page no longer lists `create`, `update` or + the `apiDocsFile()` pages, a read-only projection's page no longer lists `create`, `update` or `delete` functions, write REST verbs or Insert/Update schemas, none of which were ever generated for it, and a keyless one (the shape above) no longer lists `/:id` or the by-id - function. Write-through projections and entities are unchanged. `meta verify --docs` reports - the affected pages as stale until regenerated. + function. Write-through projections and entities are unchanged. `meta verify --codegen` + reports the affected pages as stale until regenerated. - **Python API docs: a read-only projection's page gains the read surface it was missing.** The api-docs builder documented a view-backed projection by its model alone. Its page now also lists what the read-only router emits: the repository Protocol, `GET `, @@ -847,6 +905,40 @@ until you regenerate. ### Changed +- **TypeScript: every page of documentation is a generator in `generators` (ADR-0034 + Amendment 9).** `meta gen` writes it and `meta verify --codegen` checks it, with the code. + - The factories, from `@metaobjectsdev/codegen-ts/generators`: `docsFile()` (model pages), + `apiDocsFile()` (api reference), `requirementsFile()` (requirement ledger), + `agentDocsFile()` (the `agent/` pages), and two new ones: `metamodelDocsFile()` + (`metamodel-docs`, the reference of the built-in vocabulary that `meta docs --metamodel` + wrote) and `docsSiteFile({ prompts })` (`docs-site`, the HTML site `meta docs --site` + wrote). Each writes to the target named `docs` unless given `target`; a run that lists one + while `targets` declares no `docs` is refused by name, so documentation is never written + into the code's output directory by default. + - The model pages and the api reference link to each other from what the list declares: + the runner reads `apiDocsFile()`'s directory and `docsFile()`'s presence per target and + hands both to every generator on `ctx.docs`, beside the agent schema `meta gen` builds when + `agentDocsFile()` is listed. An option given explicitly wins (`docsFile({ apiSurfaces })`). + A generator of your own declares the same facts with `emitsModelDocs` and `emitsApiDocs`. + - `apiDocsFile()` writes under `api/` by default, as `meta docs` did; it took `docs/api` when + called directly, so a direct call with no `subDir` moves its pages. It gains `modelBaseUrl`, + the base of its links back to model pages hosted elsewhere. + - `meta gen --generators ` narrows a run to entries the config declares, by registry + name (`meta gen --generators docs,api-docs` writes only the documentation). A name the + config does not declare is refused; the flag never adds a generator. A narrowed run reads + the run's facts (routes, markers, the UI tier) from the whole list, so it writes what a full + run writes for those entries. + - `meta eject docs-site` copies the site's templates and assets to `codegen/docs-site/`, as + `meta docs --scaffold-site` did, preserving files you edited unless `--force`. + `docsSiteFile()` renders with them. + - The site's footer no longer prints the date of the run, so its pages depend on the model + alone and `meta verify --codegen` can check them. `docsSiteFile({ stamp })` adds text. + - The documentation generators document the whole loaded model, as `meta docs` did: `scope` + and the `meta gen ` selection do not narrow the model pages, the api reference, + the agent pages or the site, so a scoped project sees the same pages and no cross-link + points at a page that was not written. + - A config that declares no generator writes nothing, `.metaobjects/.gen-state/` included. + - **A report's `count` and `sum` columns are `bigint` (`Long` on the JVM).** Replacing a hand-written view with a report can change its column types: a view that cast its counts to `int` now returns `bigint`, so the replacement must be a `DROP VIEW` and a `CREATE VIEW`, not a @@ -888,13 +980,9 @@ until you regenerate. - **The config loader no longer rejects an import of the four generators.** 1.0.x answered `import { entityFile } from "@metaobjectsdev/codegen-ts/generators"` with a message naming `meta eject`. That import now loads. -- **`meta docs` stops on a `metaobjects.config.ts` that fails to load.** It prints the load - error, exits 2 and writes nothing, as `meta gen` does. `meta verify --docs` calls - `meta docs`, so it fails on the same config. Before, `meta docs` warned, wrote the model - pages without the config and exited 0. With an owned docs generator listed in - `docs: { generators: [...] }` that would have overwritten your pages with the packaged - generator's output, so the fallback is removed. A project with no `metaobjects.config.ts` - is unaffected: `meta docs` still writes the model pages from metadata alone. +- **Documentation stops on a `metaobjects.config.ts` that fails to load.** In 1.0 `meta docs` + warned, wrote the model pages without the config and exited 0. Documentation is written by + `meta gen` now (see **Removed**), which prints the load error, exits 2 and writes nothing. **To upgrade**, if a docs build has been passing with a config-load warning, fix the config. A config that still imports the removed `mermaidErDiagram` is one such case (see **Removed** below). @@ -1014,6 +1102,29 @@ until you regenerate. naming args and `` ([migration](docs/features/migrations/docs-are-generators.md#java-and-kotlin)). +- **TypeScript: `meta docs`, `meta verify --docs` and the config's `docs` block.** The + documentation `meta docs` wrote is written by `meta gen` from entries in `generators`, and + `meta verify --codegen` checks it with everything else the list declares (see **Changed**). + Nothing is generated that `generators` does not declare, documentation included. Ruling: + ADR-0034 Amendment 9. + - `meta docs` prints `` `meta docs` was removed in 1.1.0. `meta gen` writes documentation + now: declare each docs generator in `generators` in metaobjects.config.ts. See + docs/features/migrations/docs-are-generators.md, section "TypeScript". `` and exits 2. + `meta verify --docs` prints the same shape, naming `meta verify --codegen`, and exits 2. + - A config with a `docs` key fails `meta gen` and `meta verify --codegen` before anything + is written, naming the block and the migration section. A project with no + `metaobjects.config.ts` fails `meta gen` the same way: in 1.0 `meta docs` wrote its pages + with no config at all, and in 1.1.0 nothing is generated until a config declares it. + - `meta init` writes no `docs` block, and its next steps no longer name `meta docs`. + - Removed from `@metaobjectsdev/codegen-ts`: `DocsConfig`, `ResolvedDocsConfig`, + `DocsSurface` and `resolveDocsConfig`, which typed and resolved the `docs` block. + `ApiSurface` stays, as the type of `docsFile({ apiSurfaces })`, and so does + `DEFAULT_DOCS_DIR`. + - **To upgrade**, move each page set into `generators` and the block's settings into + `targets.docs` and the factories' options. Before and after configs, each flag's and + key's new home, the scripts and CI change and the no-config case are in + [docs-are-generators.md, "TypeScript"](docs/features/migrations/docs-are-generators.md#typescript). + - **The standalone `mermaid-er` generator (TypeScript).** `mermaidErDiagram()`, its `MermaidErOptions` type and the stable name `"mermaid-er"` are gone from `@metaobjectsdev/codegen-ts/generators`, the generator catalog and the cross-port @@ -1026,7 +1137,8 @@ until you regenerate. - **To upgrade**, if your `metaobjects.config.ts` wires it: delete the `mermaidErDiagram` import and its entry in `generators` (or the `"mermaid-er"` name), delete the file it wrote (`docs/model.md` under your output directory, unless you moved - it with `outFile`), and run `meta docs`. `meta verify --codegen` reports that file as + it with `outFile`), and list `docsFile()` with a `docs` target (see the entry above). + `meta verify --codegen` reports that file as no longer generated until it is deleted. - **A config that still wires it fails with a message that says this**, instead of the runtime's own words for a missing export. The import is diagnosed in the config and in @@ -1042,56 +1154,17 @@ until you regenerate. suites and both failed. A package with no parent now draws no parent namespace. Output for a multi-segment package is unchanged. -- **A doc generator skipped by `meta gen` is now reported in every output form.** `meta docs` - is the door for documentation (ADR-0025), so `meta gen` warns about and skips a `docsFile()` - or `apiDocsFile()` listed under `generators`. That has not changed. What changed is who hears - about it: - - **`meta gen --format json|toon`** (the default on a pipe) printed the runner's warnings to - stderr only, and the result's `warnings` carried unknown-attribute findings alone, so the - document described a clean run with no API docs and no reason. `warnings[]` now carries - every warning the run printed: all of the runner's (not only this one), a generator's own - `ctx.warn`, the runtime-boundary advisory, and the stale-agent-context and ignored-manifest - advisories. `help[]` gains a `meta docs` next step when a doc generator was skipped. Text - output is unchanged. - - **A config that wires only doc generators** was told `no entities to generate` and to - `author entities in this project's metadata sources`, for a project that has them. The - summary, the next step and the text line now name the real reason. - - **`meta gen --list`** presented `api-docs` as one more generator to wire, and printed no - note on any row: the registry's notes for `docs` and `mermaid-er` stopped being rendered - when the catalog was rewritten. The `api-docs` and `docs` rows now read ``run by `meta - docs` `` with the reason under the row, a wired one reads ``WIRED but skipped by `meta - gen` ``, and `--probe` no longer prints `would emit 0` for them. In `--format json` the row - carries `note` and `door: "meta docs"`, and `project.wouldEmit` is `null` instead of `0`. - There is no `mermaid-er` row any more: the generator is removed in this release (see - **Removed** above). The neutral name `"docs"` wired as a string, which `meta gen` - refuses, reads ``WIRED by name, which `meta gen` refuses`` (`project.refused` in - `--format json`). - - **`meta verify`** said nothing about a config wired this way. It now reports each one as an - advisory row (rule `doc-generator-in-gen`, in `antiPatterns.rows[]`) that names - `meta verify --docs` as the gate that checks documentation. A neutral name wired as a - string is reported under rule `doc-generator-refused-by-gen`, because `meta gen` fails on - it rather than skipping it. The removed name `"mermaid-er"` is reported under the same - rule, with the message `meta gen` fails with. Advisory: the exit code is unchanged. - - **An owned docs generator under `generators`** (a copy made with `meta eject docs` or - `meta eject api-docs`) is skipped by the same rule and reported in the same places. Its - fix is the opposite one, so each message says to move it to - `docs: { generators: [...] }`, where `meta docs` runs it, and not to remove it: the - runner's warning, the `help[]` next step and the `doc-generator-in-gen` advisory row. A - config that wires only such a copy is no longer told `no entities to generate`. Listed - in the docs block, its `meta gen --list` row reads ``WIRED in `docs.generators` `` - (`project.wiredInDocsDoor` in `--format json`). - - **The unknown-generator error** listed `api-docs` among the names `meta gen` accepts. It no - longer does, and it says documentation comes from `meta docs`. - - `runGen()` returns a new `skippedDocGenerators: string[]` beside `warnings`, with - `skippedOwnedDocGenerators` naming the owned copies among them, and - `@metaobjectsdev/codegen-ts` exports `isPackagedDocsGenerator` (skipped), - `isNeutralGeneratorName` (refused) and `removedGeneratorMessage` (refused as removed), so - a caller embedding the runner can ask rather than match a sentence. TypeScript only: in - the C#, Java, Kotlin and Python - ports documentation is a separate command (`dotnet meta docs`, `mvn metaobjects:docs`, - `metaobjects docs`) and no doc generator is registered for code generation, so there is - nothing to wire and nothing to skip. +- **`meta gen --format json|toon` carries every warning the run printed.** In the structured + form (the default on a pipe, so the form an agent reads) the runner's warnings went to stderr + only, and the result's `warnings` carried unknown-attribute findings alone, so a run that + skipped work could read as clean. `warnings[]` now carries every warning the run printed: all + of the runner's, a generator's own `ctx.warn`, the runtime-boundary advisory, and the + stale-agent-context and ignored-manifest advisories. Text output is unchanged. The unknown- + generator error names every registered generator `meta gen` accepts, the documentation + generators included, and `@metaobjectsdev/codegen-ts` exports `removedGeneratorMessage`, so a + caller embedding the runner can ask whether a name was removed rather than match a sentence. + (`meta gen --list` lost its notes on every row when the catalog was rewritten; each row prints + its registry note again.) - **One shared-enum rule in all five ports: a field keeps the shared type through any number of `extends` hops.** An enum field that extends another field which itself reaches a shared (package-level abstract) enum was resolved only when it extended the abstract directly, so a diff --git a/agent-context/servers/csharp.meta.json b/agent-context/servers/csharp.meta.json index a41c5d26e..aeb474cb4 100644 --- a/agent-context/servers/csharp.meta.json +++ b/agent-context/servers/csharp.meta.json @@ -2,8 +2,8 @@ "displayName": "C#", "install": "install the MetaObjects .NET tool (dotnet tool install) + add the MetaObjects.Codegen package", "codegenCommand": "dotnet meta gen", - "docsCommand": "dotnet meta docs", - "docsCondition": "", - "docsMissing": "", + "docsCommand": "dotnet meta gen", + "docsCondition": " (when the project's generator list declares the ApiDocsGenerator)", + "docsMissing": "Declare `ApiDocsGenerator` in the generator list in codegen/Generators.cs if it is missing", "apiSubDir": "api/csharp" } diff --git a/agent-context/servers/python.meta.json b/agent-context/servers/python.meta.json index bfb1a8e27..f6ab39c48 100644 --- a/agent-context/servers/python.meta.json +++ b/agent-context/servers/python.meta.json @@ -2,8 +2,8 @@ "displayName": "Python", "install": "pip install metaobjects", "codegenCommand": "metaobjects gen", - "docsCommand": "metaobjects docs", - "docsCondition": "", - "docsMissing": "", + "docsCommand": "metaobjects gen", + "docsCondition": " (when a target's generator list declares `api-docs`)", + "docsMissing": "Declare `api-docs` in that target's `generators` in metaobjects.config.yaml if it is missing", "apiSubDir": "api/python" } diff --git a/agent-context/servers/typescript.meta.json b/agent-context/servers/typescript.meta.json index 255274675..65f9e1dbd 100644 --- a/agent-context/servers/typescript.meta.json +++ b/agent-context/servers/typescript.meta.json @@ -2,7 +2,7 @@ "displayName": "TypeScript", "install": "npm install -D @metaobjectsdev/cli @metaobjectsdev/codegen-ts", "codegenCommand": "npx meta gen", - "docsCommand": "npx meta docs", + "docsCommand": "npx meta gen", "docsCondition": "", "docsMissing": "", "apiSubDir": "api" diff --git a/agent-context/skills/metaobjects-audit/references/capability-checklist.md b/agent-context/skills/metaobjects-audit/references/capability-checklist.md index 9b79805a1..bd8e3486f 100644 --- a/agent-context/skills/metaobjects-audit/references/capability-checklist.md +++ b/agent-context/skills/metaobjects-audit/references/capability-checklist.md @@ -88,9 +88,11 @@ classify it (using the classification scheme in `SKILL.md`) and route the cutove names artifact from the declaration, so a literal is a second source of truth even when it agrees with the naming strategy today. A typed ORM handle in its place is correct. **Check the artifact is emitted at all before scoring the literals: on every port the selection IS - the complete list — the config's on TypeScript and the JVM, `--generators` on C# and Python — + the complete list, documentation included — `generators: [...]` in `metaobjects.config.ts` + (TypeScript), `codegen/Generators.cs` (C#), a target's `generators` in + `metaobjects.config.yaml` (Python), `` in the pom (Java, Kotlin) — so an existing project emits none and the un-wired generator is the finding FIRST** (no port - ships a default suite; ADR-0034 Amendment 2). **This entry is the physical-name INSTANCE of signature 11.** The rule that + ships a default suite; ADR-0034 Amendments 2 and 9). **This entry is the physical-name INSTANCE of signature 11.** The rule that generates the rest — and the reason an enum member compared as a bare string is NOT one — is the Cross-cutting entry below. - **`@kind` = `view` / `materializedView`** — hunt hand-written SQL views where an authored @@ -272,8 +274,8 @@ to nothing, and does not check that each claimed node complies). accepted. - **The doc slots behave differently on this node type** — do not audit them by the generic rule below. `title` is CHARTERED here (a requirement's `name` is an identifier, so the label - lives in `title`) and is **rendered** by `meta docs`, heading each entry after its dotted - path; `summary` is INERT (nothing reads it, and `@statement` is already the required + lives in `title`) and is **rendered** by `meta gen`'s `requirementsFile()`, heading each + entry after its dotted path; `summary` is INERT (nothing reads it, and `@statement` is already the required one-liner) and `meta verify` warns on one. So an absent `summary` is correct, a populated one is the finding, and a populated `title` is correct. - **CALIBRATION — entirely opt-in and warning-only where it counts.** A project declaring no diff --git a/agent-context/skills/metaobjects-audit/references/csharp.md b/agent-context/skills/metaobjects-audit/references/csharp.md index e569f647e..41944575c 100644 --- a/agent-context/skills/metaobjects-audit/references/csharp.md +++ b/agent-context/skills/metaobjects-audit/references/csharp.md @@ -26,8 +26,9 @@ Generated files are named `.g.cs` and carry an `@generated` guard commen The metadata source directory is the first positional arg (``); `--out` is required (errors if absent, no default). The runner overwrites only files bearing this header; it refuses to touch files without it. Locate the output directory from -how the team invokes `dotnet meta gen` (or a CI script) — the arg is explicit, there -is no config file equivalent on the C# side. +`codegen/Generators.cs` (the project's generator list, each entry's `OutDir` init +property — scaffolded by `dotnet meta init`, new in 1.1.0) or, for a project that predates +it, from how the team invokes `dotnet meta gen` (or a CI script). --- @@ -73,7 +74,7 @@ copies the helper runtime the generated routes call (`FilterParser`, `EfCoreFilt `codegen/runtime/` under the namespace `Codegen.Runtime`. That folder is owned code, not a hand-rolled filter parser: do not flag it. `dotnet meta gen --list` marks each owned copy `identical` or `DIFFERS`. A generator the project WRITES is an `IGenerator` listed in -`codegen/Program.cs` the same way. +`codegen/Generators.cs` the same way. **A finding of the form "the built-ins do not emit the shape this project needs", or a hand-written layer the model fully describes, resolves to a generator the project writes** diff --git a/agent-context/skills/metaobjects-audit/references/drift-signatures.md b/agent-context/skills/metaobjects-audit/references/drift-signatures.md index edab253ff..351893deb 100644 --- a/agent-context/skills/metaobjects-audit/references/drift-signatures.md +++ b/agent-context/skills/metaobjects-audit/references/drift-signatures.md @@ -39,7 +39,7 @@ Per finding: `file:line` → what → generated-equivalent exists? → recommend **Score only where a constant actually exists.** A fact declared in the project's CODEGEN CONFIG rather than in metadata — a bespoke route mount path, a hand-chosen JSON envelope key — is genuinely spelled twice when a client re-types it, but no generated constant holds it. That is a GENERATOR GAP, reported as one, never a literal-site finding: never invent a constant that the emitters do not emit. - **No verify subverb sees this** — `--codegen` diffs generated files, `--db` compares schema to metadata — so this audit is the only gate. Remedy: reference the constant — but **check the artifact is emitted at all before scoring the literals, because on ALL FIVE ports an existing project emits none until it asks**. ADR-0034 Amendment 2 made codegen opt-in everywhere: C# and Python require `--generators`, TypeScript's `generators: [...]` and the JVM's `` are each the COMPLETE list, and `meta init` scaffolds `generators: []` — so no port begins emitting this artifact merely because the package was upgraded. Where no artifact exists, the un-wired generator is the FIRST finding and the first remedy (`namesFile()` on TS after `meta eject names`; `SpringNamesGenerator` / `KotlinNamesGenerator` in the pom) — score the literals under it rather than as N independent findings, since one config line fixes the cause and generated code stops embedding the names too. + **No verify subverb sees this** — `--codegen` diffs generated files, `--db` compares schema to metadata — so this audit is the only gate. Remedy: reference the constant — but **check the artifact is emitted at all before scoring the literals, because on ALL FIVE ports an existing project emits none until it asks**. ADR-0034 Amendment 2 made codegen opt-in everywhere, and on every port the project's own generator list is the COMPLETE list, documentation included (Amendment 9) — `generators: [...]` in `metaobjects.config.ts` (TypeScript), `codegen/Generators.cs` (C#), a target's `generators` in `metaobjects.config.yaml` (Python), `` in the pom (Java, Kotlin) — and `meta init` scaffolds `generators: []` — so no port begins emitting this artifact merely because the package was upgraded. Where no artifact exists, the un-wired generator is the FIRST finding and the first remedy (`namesFile()` on TS after `meta eject names`; `SpringNamesGenerator` / `KotlinNamesGenerator` in the pom) — score the literals under it rather than as N independent findings, since one config line fixes the cause and generated code stops embedding the names too. **Report TWO numbers for this signature, always, and never just the first: (a) is the artifact EMITTED, and (b) how many of the literal sites actually IMPORT it — the adoption ratio, as `/ sites`.** Emission is the cheap half and it is the half that gets done: measured on an adopter whose audit proved the artifact emitted correctly, ran the generator to show it, and then adopted it at **0 of 53 sites** (37 table + 16 column). Wiring the generator changes the scorecard; it changes nothing a reader of the code experiences, because the second spelling is still the one every query uses. An audit that reports only (a) makes the estate look upgraded while every literal it found is still there — so a project that emits the artifact and imports it nowhere scores WORSE than one that has not started, not better, because it now carries a third spelling that claims to be the source of truth. diff --git a/agent-context/skills/metaobjects-audit/references/requirements.md b/agent-context/skills/metaobjects-audit/references/requirements.md index f7e2c9f66..5c48284f2 100644 --- a/agent-context/skills/metaobjects-audit/references/requirements.md +++ b/agent-context/skills/metaobjects-audit/references/requirements.md @@ -82,8 +82,9 @@ functional one. model. If the tree is flat, or every entry is L3, the levels are carrying no information and should be simplified rather than defended. -**6. Titles that are not labels.** `title` is now **rendered** — `meta docs` heads each entry -`## checkout.payment — Payment capture`, the path first and the label after it — so a slot +**6. Titles that are not labels.** `title` is now **rendered** — `meta gen`'s +`requirementsFile()` heads each entry `## checkout.payment — Payment capture`, the path +first and the label after it — so a slot that used to be inert is read by every reader of the generated page. The lint catches only the id-shaped case (`FR-448 …`); it cannot tell a *useless* label from a good one. Read the titles: one that restates `@statement`, or repeats the path in prose, is now visible noise in diff --git a/agent-context/skills/metaobjects-authoring/references/reporting.md b/agent-context/skills/metaobjects-authoring/references/reporting.md index 33b2ae977..37fa747e2 100644 --- a/agent-context/skills/metaobjects-authoring/references/reporting.md +++ b/agent-context/skills/metaobjects-authoring/references/reporting.md @@ -167,7 +167,7 @@ A concrete report whose read source is `@kind: view` is served by every port's g - **Every derived field with filter operators is filterable and sortable**, dimension and measure alike, with its type's own operators. You cannot narrow that set: a report has no field to put `@filterable` on. A field of the `@from` entity that the report does not expose is refused with a `400`. - A time dimension at `day` or coarser is `YYYY-MM-DD`; a null measure is `null` with the key present (a measure with `@default` is never null); `currency` is integer minor units. - **A decimal (`avg`, a ratio, a `sum` of a decimal) has no agreed JSON spelling**: each port sends its own (TypeScript a string). Do not compare one across backends as text. -- `meta docs` writes a model page for every report (a sourceless one is marked "Not served") and an API page for a served one. +- `meta gen` writes a model page for every report (`docsFile()`; a sourceless one is marked "Not served") and an API page for a served one (`apiDocsFile()`) — each an ordinary entry in `generators`. The files each port generates are in the `metaobjects-codegen` skill's reference for that language ("Reports"). diff --git a/agent-context/skills/metaobjects-codegen/SKILL.md b/agent-context/skills/metaobjects-codegen/SKILL.md index f4b4af165..b4fe9bcaf 100644 --- a/agent-context/skills/metaobjects-codegen/SKILL.md +++ b/agent-context/skills/metaobjects-codegen/SKILL.md @@ -45,7 +45,7 @@ exact config, generator names and commands for this project; read it. The other | `references/typescript-mysql.md` | a TypeScript project on a MySQL database | | `references/typescript-retargeting.md` | a TypeScript project on a framework other than Fastify, Hono or React | | `references/typescript-templates.md` | declarative Mustache template-codegen in a TypeScript project | -| `references/typescript-docs.md` | `meta docs` in a TypeScript project | +| `references/typescript-docs.md` | the docs generators (`docsFile`, `apiDocsFile`, `agentDocsFile`, `requirementsFile`, `metamodelDocsFile`, `docsSiteFile`) in a TypeScript project | ## Need an output? Write the generator — this is the primary path @@ -90,7 +90,7 @@ what it emits. |---|---|---| | TypeScript | import it in `metaobjects.config.ts`, add it to `generators: [...]` (the scaffold does both) | `@metaobjectsdev/codegen-ts`: `objectRefTarget`, `enumValues`, `effectivePackage`, `packageToPath`, `servedPath`, `toCamelCase`/`toPascalCase`/`toSnakeCase`/`pluralize`, `isAbstract`, `hasAnyRdbSource`, `servesReadApi`/`servesWriteApi` | | Python | a `module:symbol` entry in `--generators` or a target's `generators` in `metaobjects.config.yaml`; the symbol is an instance or a function returning one, never the class | `metaobjects.codegen.model_walk` | -| C# | `new YourGenerator()` in the owned `codegen/Program.cs`; `dotnet meta gen` / `verify --codegen` hand off to `codegen/` whenever `codegen/Codegen.csproj` exists | node accessors, `ValueObjectNames.ResolveFieldRef`, `CSharpNaming.RoutePath` | +| C# | `new YourGenerator()` in the owned `codegen/Generators.cs` list, which `codegen/Program.cs` passes to `CodegenCli.Run`; `dotnet meta gen` / `verify --codegen` hand off to `codegen/` whenever `codegen/Codegen.csproj` exists | node accessors, `ValueObjectNames.ResolveFieldRef`, `CSharpNaming.RoutePath` | | Java / Kotlin | `` plus ``, from a module on the plugin's classpath; extend `FileEmittingGenerator` | `com.metaobjects.generator.ModelWalk` | **Verify it** — nothing to register. `verify --codegen` (`mvn metaobjects:verify` on the @@ -243,11 +243,16 @@ reads as an invitation to adopt the surface you decided against. ## Selecting generators — NOTHING is generated until you choose it -**`meta init` wires no generators, and no port ships a default suite.** A fresh -scaffold has `generators: []` and an empty `codegen/generators/`; `--generators` is -required on the C# and Python CLIs; Java has never had a default set. Choosing what an -application needs is a judgment over its purpose and stack, and the tool's job is to -make that choice cheap and truthful, not to make it for you. +**`meta init` wires no generators, and no port ships a default suite.** A fresh TypeScript +scaffold has `generators: []` and an empty `codegen/generators/`; a fresh C# scaffold +(`dotnet meta init`) has an empty `codegen/Generators.cs`; Java and Python have never had a +default set. In every port the project's own generator list — `generators` in +`metaobjects.config.ts`, `codegen/Generators.cs`, a target's `generators` in +`metaobjects.config.yaml`, or `` in the pom — is the COMPLETE list, +documentation included (ADR-0034 Amendment 9); `--generators` (Maven: a second +``) only narrows a run to entries already in it. Choosing what an application +needs is a judgment over its purpose and stack, and the tool's job is to make that choice +cheap and truthful, not to make it for you. Each generator has a **stable name** (kebab-case) that is the same in every port and surfaces in diagnostics — reference generators by that name, never by inlining what @@ -301,7 +306,7 @@ implies that you have not wired. | `persistence` | how rows are read and written | app shape | | `api` | the HTTP surface — pick one framework | app shape | | `client` | the browser tier | app shape | -| `docs` | on by default; the canonical door is `meta docs` | — | +| `docs` | model pages, api reference, agent pages, requirement ledger — each its own generator entry, like any other | app shape | | `capability` | prompts, parsers, payloads, traces, test stubs | **`--probe`** | At intent level: a **headless data service** is `model` + `persistence`; an **HTTP API** diff --git a/agent-context/skills/metaobjects-codegen/references/csharp.md b/agent-context/skills/metaobjects-codegen/references/csharp.md index 8c829447b..0693a4aeb 100644 --- a/agent-context/skills/metaobjects-codegen/references/csharp.md +++ b/agent-context/skills/metaobjects-codegen/references/csharp.md @@ -9,7 +9,7 @@ is **schema-migrations only** on the C# side (ADR-0015): `meta migrate` / - Install - Run - `MetaObjects.Codegen` generators -- Docs — `dotnet meta docs` +- Docs — one more entry in `codegen/Generators.cs` - Persistence + routes are the deployed artifact - Write your own generator - Extending the generators (open-for-extension, ADR-0002) @@ -49,10 +49,17 @@ Node `meta` tool (see the migration reference). ## `MetaObjects.Codegen` generators -Wire generators by their stable name — **`--generators ` is REQUIRED**. There is -no default set: a run that names none is a usage error and writes nothing (ADR-0034 -Amendment 2). `dotnet meta gen --list` is the catalog. Output lands under `--namespace` -in `--output-dir`. +Wire generators as a list in **`codegen/Generators.cs`** — a static list of constructed +generators, with their options as init properties (ADR-0034 Amendment 9); `codegen/Program.cs` +is a two-line entry point that passes the list to `CodegenCli.Run`. `dotnet meta init` +(new in 1.1.0) scaffolds both files; `dotnet meta eject` writes them when either is missing. +`dotnet meta gen` runs the declared list, documentation included — there is no default +set and no separate docs command. `--generators ` narrows a run to entries the +list already declares, by stable name; it never adds one, and naming an entry the list +does not declare is refused. `dotnet meta gen --list` is the catalog of what the port +registers, not what this project runs. Output lands under `--namespace` in +`--output-dir` unless a generator's own init properties say otherwise — documentation +does (below). | Stable name | Output | |---|---| @@ -118,31 +125,29 @@ implicit `public void req_…()` goes stale silently. Give the generator its own `dotnet meta gen … --out --generators requirement-tests` run (a run has one `--out`, and the test project needs xunit), and pass `--namespace` to `verify --codegen` for that directory. Options (`TestNamespace`, `WitnessClass`, `Grain`, -`Filter`, `Renderer`, `WarnUncovered`) are public properties set in an owned -`codegen/Program.cs`; `Grain` needs `using MetaObjects.Core.Requirement;`. A filter +`Filter`, `Renderer`, `WarnUncovered`) are init properties set on the entry in an owned +`codegen/Generators.cs`; `Grain` needs `using MetaObjects.Core.Requirement;`. A filter REPLACES the default of functional L4/L5. `dotnet meta eject requirement-tests` copies the generator with its default rendering. The requirement checks in `dotnet meta verify` are core and are not ejectable. -## Docs — `dotnet meta docs` +## Docs — one more entry in `codegen/Generators.cs` -```bash -dotnet meta docs metaobjects --out Docs # → Docs/api/csharp (AGENT-API.md + per-entity pages) +There is no `dotnet meta docs` command (removed in 1.1.0, ADR-0034 Amendment 9): the api +reference is `ApiDocsGenerator`, an ordinary entry in the same list as every other +generator: + +```csharp +new ApiDocsGenerator { OutDir = "Docs" } // → Docs/api/csharp (AGENT-API.md + per-entity pages) ``` -`dotnet meta docs` emits this project's C# SDK api surface (`api/csharp`), including -`AGENT-API.md` — the exact imports, signatures, and payload field shapes for the +`dotnet meta gen` writes it, alongside everything else `codegen/Generators.cs` declares. +`AGENT-API.md` has the exact imports, signatures, and payload field shapes for the generated code. **Before calling any generated code, read `api/csharp/AGENT-API.md`.** - -**The two `docs` positionals are NOT the same argument.** This one is the METADATA -directory. The Node `meta docs` positional — used by every stack, since `migrate`, -`verify --db` and the neutral model docs are Node-only — is the PROJECT ROOT that -CONTAINS the metadata. Run `meta docs` with no positional, from the project root: - -```bash -dotnet meta docs metaobjects --out Docs # C#: the METADATA dir -meta docs --out Docs # Node: run from the PROJECT ROOT (no positional) -``` +Options (init properties): `OutDir` (required), `ApiSubDir` (default `api/csharp`), +`ProjectName`, `ModelBaseUrl`. To write only the documentation, +`dotnet meta gen --generators api-docs`. Migrating a project that ran `dotnet meta docs`: +`docs/features/migrations/docs-are-generators.md`, section "C#". ## Persistence + routes are the deployed artifact @@ -177,9 +182,10 @@ public sealed class FieldListGenerator : IGenerator } ``` -List it in `codegen/Program.cs` — `IReadOnlyList generators = [new -FieldListGenerator()]; return CodegenCli.Run(args, generators);`. An owned generator the -`--generators` selection does not name still runs. Model reads: `Fields()`, `Attr(n)`, +List it in `codegen/Generators.cs` — `IReadOnlyList Generators = [new +FieldListGenerator()];` — which `codegen/Program.cs` passes to `CodegenCli.Run`. An owned +generator a `--generators` selection does not name still exists in the list but does not +run that invocation. Model reads: `Fields()`, `Attr(n)`, `ResolvedIsArray()`, `EffectiveEnumValues`, `MaxLength` resolve; `IsArray`, `OwnAttr`, `EnumValues` do not. `ValueObjectNames.ResolveFieldRef(field, ctx.Root)` resolves an `@objectRef`; `CSharpNaming.RoutePath(obj)` is the REST segment; constants come from diff --git a/agent-context/skills/metaobjects-codegen/references/owning-generators.md b/agent-context/skills/metaobjects-codegen/references/owning-generators.md index 3de6cf6b9..d67ccc2f3 100644 --- a/agent-context/skills/metaobjects-codegen/references/owning-generators.md +++ b/agent-context/skills/metaobjects-codegen/references/owning-generators.md @@ -17,9 +17,9 @@ it there, in the same change, and keep going: | Port | Where the fix goes | |---|---| -| **TypeScript** | Your ejected copy under `codegen/generators/` — and, for routes, the HTTP adapter it calls: `meta eject routes` / `routes-hono` / `entity` also copy that adapter's source (mount helpers, filter parser, error envelopes, pagination) into `codegen/runtime/`, and the ejected output imports it from there, so a bug in a route's behaviour is fixed in that copy. If you are running a generator you never ejected (imported from its package), `meta eject ` it first and swap the import for the local one eject prints. Every stock generator can be ejected except the `template` primitive, which has no emit logic of its own to own. An ejected `docs` or `api-docs` goes in `docs: { generators: [...] }`, not in `generators`: `meta docs` runs it. A generator `meta gen --list` marks `package-only` has no reference template: replace it in `generators` with your own `Generator`, starting from its source in the installed package. | +| **TypeScript** | Your ejected copy under `codegen/generators/` — and, for routes, the HTTP adapter it calls: `meta eject routes` / `routes-hono` / `entity` also copy that adapter's source (mount helpers, filter parser, error envelopes, pagination) into `codegen/runtime/`, and the ejected output imports it from there, so a bug in a route's behaviour is fixed in that copy. If you are running a generator you never ejected (imported from its package), `meta eject ` it first and swap the import for the local one eject prints. Every stock generator can be ejected except the `template` primitive, which has no emit logic of its own to own, and `docs-site`, whose builder stays in the package (`meta eject docs-site` copies the site's templates and assets into `codegen/docs-site/`); an ejected generator comes with the template modules that write its output (`codegen/templates/`): the text of what it emits is yours to change too. An ejected `docs` or `api-docs` goes in `generators`, like any other owned copy — there is no separate docs list, and `meta gen` runs it. A generator `meta gen --list` marks `package-only` has no reference template: replace it in `generators` with your own `Generator`, starting from its source in the installed package. | | **Java / Kotlin** | Your own generator class. Subclass the reference generator and override the `protected` method that emits the wrong piece; when that piece is `private`, copy the reference generator's source (Apache-2.0) into your own package and edit it. Put the class in a codegen module that the module running `metaobjects:generate` depends on — the plugin loads `` from that module's compile classpath, and `provided` scope keeps it out of your packaged app — then point `` at it. Full steps: the Java and Kotlin references. | -| **C# / Python** | Your owned copy (`dotnet meta eject ` / `metaobjects eject `, then edit it), or a generator of your own that replaces the artifact — an `IGenerator` in `codegen/Program.cs` on C#, a `module:symbol` entry on Python — or a template spec (`--template-spec`). | +| **C# / Python** | Your owned copy (`dotnet meta eject ` / `metaobjects eject `, then edit it), or a generator of your own that replaces the artifact — an `IGenerator` in `codegen/Generators.cs` on C#, a `module:symbol` entry on Python — or a template spec (`--template-spec`). | Then do **not**: diff --git a/agent-context/skills/metaobjects-codegen/references/physical-names.md b/agent-context/skills/metaobjects-codegen/references/physical-names.md index 5086f31cd..83f836424 100644 --- a/agent-context/skills/metaobjects-codegen/references/physical-names.md +++ b/agent-context/skills/metaobjects-codegen/references/physical-names.md @@ -54,8 +54,8 @@ emitting this artifact. "Wired" is the only fact there is. | Port | Where the selection is declared | An existing project upgrading gets it? | |---|---|---| -| C# | `--generators ` on `dotnet meta gen` — required, no default | **No** — name `names` | -| Python | `--generators ` on `metaobjects gen` — required, no default | **No** — name `names` | +| C# | `codegen/Generators.cs` — the complete list, documentation included | **No** — add the `names` entry | +| Python | a target's `generators` in `metaobjects.config.yaml` — the complete list | **No** — add `names` | | TypeScript | `metaobjects.config.ts` `generators: [...]` — the complete list | **No** — add `namesFile()` | | Java / Kotlin | the pom's `` — the complete list | **No** — add `SpringNamesGenerator` / `KotlinNamesGenerator` | diff --git a/agent-context/skills/metaobjects-codegen/references/python.md b/agent-context/skills/metaobjects-codegen/references/python.md index e181065cb..8adbe6cdd 100644 --- a/agent-context/skills/metaobjects-codegen/references/python.md +++ b/agent-context/skills/metaobjects-codegen/references/python.md @@ -9,7 +9,7 @@ through the Node `meta` tool — the Python CLI has **no `migrate` subcommand** ## Contents - Install - Run -- Docs — `metaobjects docs` +- Docs — one more entry in a target's `generators` - Write your own generator - Generators - Discriminator inheritance (TPH) @@ -42,26 +42,36 @@ the exact `gen` code path so the two can't diverge). `--templates` is the prompt drift gate (see the prompts reference). Schema migration + live-DB drift are **not** `metaobjects` — they run through the Node `meta` tool (see the migration reference). -## Docs — `metaobjects docs` +## Docs — one more entry in a target's `generators` -```bash -metaobjects docs ./metadata --out ./docs # → ./docs/api/python (AGENT-API.md + per-entity pages) -``` - -`metaobjects docs` emits this project's Python SDK api surface (`api/python`), including -`AGENT-API.md` — the exact imports, signatures, and payload field shapes for the -generated code. **Before calling any generated code, read `api/python/AGENT-API.md`.** +There is no `metaobjects docs` command (removed in 1.1.0, ADR-0034 Amendment 9): the api +reference is the `api-docs` generator, named in a target's `generators` in +`metaobjects.config.yaml` like any other: -**The two `docs` positionals are NOT the same argument.** This one is the METADATA -directory. The Node `meta docs` positional — used by every stack, since `migrate`, -`verify --db` and the neutral model docs are Node-only — is the PROJECT ROOT that -CONTAINS the metadata. Run `meta docs` with no positional, from the project root: - -```bash -metaobjects docs ./metadata --out ./docs # Python: the METADATA dir -meta docs --out ./docs # Node: run from the PROJECT ROOT (no positional) +```yaml +targets: + docs: + outDir: ./docs + generators: [api-docs] +apiDocs: + apiSubDir: api/python # default ``` +`metaobjects gen` writes it (→ `./docs/api/python`: `AGENT-API.md` + per-entity pages), +alongside everything else that target's `generators` declares. `AGENT-API.md` has the +exact imports, signatures, and payload field shapes for the generated code. **Before +calling any generated code, read `api/python/AGENT-API.md`.** Options live in the +top-level `apiDocs` block: `apiSubDir` (default `api/python`), `projectName`, +`modelBaseUrl`. To write only the documentation, `metaobjects gen --generators api-docs`. +Migrating a project that ran `metaobjects docs`: +`docs/features/migrations/docs-are-generators.md`, section "Python". + +**The neutral model pages are a Node `meta gen` generator, not something this port emits.** +`meta docs`'s language-neutral model surface was retired along with the rest of +`meta docs` in 1.1.0 (ADR-0034 Amendment 9); a TypeScript project in the same repo lists +`docsFile()` in its own `generators` for that surface. This port's `api-docs` writes only +its own api reference. + ## Write your own generator For any output the model describes and no reference emits, write one. A generator is an diff --git a/agent-context/skills/metaobjects-codegen/references/typescript-docs.md b/agent-context/skills/metaobjects-codegen/references/typescript-docs.md index 6f643d55d..016c7dc9e 100644 --- a/agent-context/skills/metaobjects-codegen/references/typescript-docs.md +++ b/agent-context/skills/metaobjects-codegen/references/typescript-docs.md @@ -1,76 +1,74 @@ -# TypeScript docs — `meta docs` +# TypeScript docs — generator entries, not a separate command > Part of the `metaobjects-codegen` skill's TypeScript reference. Read it when generating or wiring documentation. ## Contents -- Never wire `docsFile()` or `apiDocsFile()` into `generators` -- An owned docs generator goes in `docs: { generators: [...] }`, never in `generators` +- Six docs factories, each one more entry in `generators` +- Give them a `docs` target +- An owned docs generator goes in `generators`, like any other owned copy - There is no `mermaidErDiagram()` generator -- Before calling any generated code, read `./docs/api/AGENT-API.md` +- Before calling any generated code, read `/api/AGENT-API.md` - Ejecting routes hands over the adapter too - Wire a generator only for output you consume, and narrow it with its `filter` -Documentation is NOT a `meta gen` generator. The single door is the `meta docs` -command, which emits three cross-linked **surfaces** under one output dir (default -`./docs`): - -- **model surface** (`./docs/.md`, `./docs/