Skip to content

fix(cli): report skipped doc generators in every meta gen output form - #428

Merged
dmealing merged 3 commits into
mainfrom
fm/mo-1-1-0-docs-door-signals
Oct 11, 2026
Merged

dmealing merged 3 commits into
mainfrom
fm/mo-1-1-0-docs-door-signals

Conversation

@dmealing

Copy link
Copy Markdown
Member

What Changed

  • meta gen --format json|toon now carries every warning the run prints in warnings[], not only unknown-attribute findings. A skipped docsFile() or apiDocsFile() adds a meta docs next step to help[]. runGen() returns a new skippedDocGenerators list, and @metaobjectsdev/codegen-ts exports isPackagedDocsGenerator and isNeutralGeneratorName. Shared doc-generator definitions live in a new codegen-ts module, packaged-docs-generators.ts, which the runner and the CLI catalog both read.
  • meta gen --list marks the api-docs and docs rows as run by meta docs, with a note under the row. A wired row reads WIRED but skipped by meta gen. --probe reports no count for these rows. The JSON form adds note and door to each row. The unknown-generator error no longer lists api-docs.
  • meta verify adds an advisory row for each doc generator listed under generators (rule doc-generator-in-gen, or doc-generator-refused-by-gen for a neutral name given as a string). Exit code is unchanged. Adds doc-generator-advisory.ts in the CLI lib.

Runs: 1 (no gate runs yet on this branch)

Validation

Risk Assessment

✅ Low: Both intent gaps are closed (runner warnings reach json/toon warnings[]; the api-docs row names meta docs as its door), both round-1 decisions are honoured (mermaid-er refusal and deprecation wording restored, refused strings reported as refused), the additions are advisory or additive with no exit-code change, and the only defect found is one mislabelled warning for a string-wired api-docs.

Testing

I built disposable projects and drove the real meta CLI (bun bin/meta.ts) against them. The runner's skip warning for apiDocsFile() and docsFile() now appears in warnings[] for both json and toon, with a meta docs hint in help. A mixed ["entity", apiDocsFile()] config still generates Talk.ts and records the warning. A clean config produces no warnings key, so there are no false positives. meta gen --list marks api-docs as run by meta docs, and as "WIRED but skipped by meta gen" when wired. meta verify reports the new doc-generator-in-gen advisory without failing the gate. A string-wired "docs" is reported as refused by meta gen (exit 1) rather than skipped, matching the recorded decision. "mermaid-er" as a string is refused as neutral, and its catalog note says it is deprecated. A constructed mermaidErDiagram() still runs. meta docs still writes its pages. The full regression (ci-local.sh --quick) passed. The C#, Java, Python and Kotlin lanes, the Java reactor, the Docker integration tests and the Cube live check were skipped by --quick; the change touches only TypeScript and docs. One cosmetic nit: a string-wired "api-docs" warning reads "remove apiDocsFile()" even though a string was wired. That text comes from the runner's shared warning.

  • Live validation: ✅ go - 11 of 11 scenarios driven live against the product
Scenario Result Live Evidence
Agent runs meta gen --format json|toon with apiDocsFile() wired and sees the skip reason in the result's warnings[] ✅ pass live gen-doc-generators.txt: warnings[] holds "[api-docs] docs are produced by 'meta docs' (ADR-0025); remove apiDocsFile() from generators. Skipped." in json and toon, with a summary and help line pointin…
Same for docsFile() wired (docs-file) ✅ pass live gen-doc-generators.txt: warnings[] carries the docsFile() skip line in json and toon
Text output and stderr still show the warning ✅ pass live gen-doc-generators.txt: stderr still prints the warning; the text form says "Nothing was generated ... Run meta docs"
Mixed config ["entity", apiDocsFile()] still generates entity code and records the warning ✅ pass live gen-mixed-docs.txt: Talk.ts written/unchanged, warnings[] has the api-docs line, and help notes "skipped 1 doc generator(s)"
Clean config produces no spurious warnings (adversarial control) ✅ pass live gen-other-and-verify.txt: ["entity"] gives no warnings key and an empty stderr
meta gen --list api-docs row names meta docs as its door and marks it skipped when wired ✅ pass live gen-other-and-verify.txt and gen-mixed-docs.txt: row note says it is the api surface of meta docs; the json row carries door "meta docs"; it is marked "WIRED but skipped by meta gen" when wired
String-wired "docs" is reported as refused by meta gen, not skipped (adversarial) ✅ pass live gen-other-and-verify.txt: gen exits 1 with 'generator "docs" is neutral (owned by meta docs)'; meta verify says '"docs" is listed under generators, and meta gen refuses it, so the run fails'
mermaid-er recorded decision holds: string "mermaid-er" refused as neutral, constructed mermaidErDiagram() still runs, catalog note states the back-compat fact ✅ pass live gen-other-and-verify.txt: the string spec exits 1 as neutral; the constructed generator writes generated/docs/model.md; the list note says deprecated, a wired one still runs, and meta docs draws the…
meta verify surfaces the doc-generator-in-gen advisory without failing the build ✅ pass live gen-other-and-verify.txt: an antiPatterns row with rule doc-generator-in-gen, exitCode 0, and a help line naming meta docs
meta docs still produces documentation after the change ✅ pass live gen-mixed-docs.txt: wrote the overview, entity pages and api pages
Full TypeScript regression suite (ci-local --quick) ✅ pass live ci-local-quick.log: LOCAL CI PASSED; the four skipped lanes are other-language ports, the Java reactor, Docker integration tests and the Cube live check
Evidence: gen with apiDocsFile()/docsFile() in json, toon and text
=== api --format json
{
  "gen": [],
  "summary": "every wired generator is a doc generator, which `meta gen` skips, so nothing was generated",
  "help": [
    "run `meta docs` for documentation, and remove the doc generators from `generators` in metaobjects.config.ts"
  ],
  "antiPatterns": {
    "status": "ran",
    "total": 0,
    "rows": []
  },
  "warnings": [
    "[api-docs] docs are produced by 'meta docs' (ADR-0025); remove apiDocsFile() from generators. Skipped."
  ]
}
[exit 0]
--stderr:
meta: [api-docs] docs are produced by 'meta docs' (ADR-0025); remove apiDocsFile() from generators. Skipped.
=== api --format toon
gen: []
summary: "every wired generator is a doc generator, which `meta gen` skips, so nothing was generated"
help[1]: "run `meta docs` for documentation, and remove the doc generators from `generators` in metaobjects.config.ts"
antiPatterns:
  status: ran
  total: 0
  rows: []
warnings[1]: "[api-docs] docs are produced by 'meta docs' (ADR-0025); remove apiDocsFile() from generators. Skipped."
[exit 0]
--stderr:
meta: [api-docs] docs are produced by 'meta docs' (ADR-0025); remove apiDocsFile() from generators. Skipped.
=== api --format text
meta gen — sqlite, generated

  Nothing was generated: every wired generator is a doc generator, and `meta gen` skips those. Run `meta docs`.

[exit 0]
--stderr:
meta: [api-docs] docs are produced by 'meta docs' (ADR-0025); remove apiDocsFile() from generators. Skipped.
=== docs --format json
{
  "gen": [],
  "summary": "every wired generator is a doc generator, which `meta gen` skips, so nothing was generated",
  "help": [
    "run `meta docs` for documentation, and remove the doc generators from `generators` in metaobjects.config.ts"
  ],
  "antiPatterns": {
    "status": "ran",
    "total": 0,
    "rows": []
  },
  "warnings": [
    "[docs-file] docs are produced by 'meta docs' (ADR-0025); remove docsFile() from generators. Skipped."
  ]
}
[exit 0]
--stderr:
meta: [docs-file] docs are produced by 'meta docs' (ADR-0025); remove docsFile() from generators. Skipped.
=== docs --format toon
gen: []
summary: "every wired generator is a doc generator, which `meta gen` skips, so nothing was generated"
help[1]: "run `meta docs` for documentation, and remove the doc generators from `generators` in metaobjects.config.ts"
antiPatterns:
  status: ran
  total: 0
  rows: []
warnings[1]: "[docs-file] docs are produced by 'meta docs' (ADR-0025); remove docsFile() from generators. Skipped."
[exit 0]
--stderr:
meta: [docs-file] docs are produced by 'meta docs' (ADR-0025); remove docsFile() from generators. Skipped.
=== docs --format text
meta gen — sqlite, generated

  Nothing was generated: every wired generator is a doc generator, and `meta gen` skips those. Run `meta docs`.

[exit 0]
--stderr:
meta: [docs-file] docs are produced by 'meta docs' (ADR-0025); remove docsFile() from generators. Skipped.
Evidence: string specs, mermaid-er, clean control, verify advisory, gen --list
=== str gen json
[exit 1]
--stderr:
meta: gen failed: generator "docs" is neutral (owned by 'meta docs'); not selectable in the gen suite.
=== strapi gen json
{
  "gen": [],
  "summary": "every wired generator is a doc generator, which `meta gen` skips, so nothing was generated",
  "help": [
    "run `meta docs` for documentation, and remove the doc generators from `generators` in metaobjects.config.ts"
  ],
  "antiPatterns": {
    "status": "ran",
    "total": 0,
    "rows": []
  },
  "warnings": [
    "[api-docs] docs are produced by 'meta docs' (ADR-0025); remove apiDocsFile() from generators. Skipped."
  ]
}
[exit 0]
--stderr:
meta: [api-docs] docs are produced by 'meta docs' (ADR-0025); remove apiDocsFile() from generators. Skipped.
=== strmer gen json
[exit 1]
--stderr:
meta: gen failed: generator "mermaid-er" is neutral (owned by 'meta docs'); not selectable in the gen suite.
=== mer gen json
{
  "gen": [
    {
      "file": "generated/docs/model.md",
      "status": "new"
    }
  ],
  "summary": "1 written",
  "help": [
    "typecheck the generated code with `npx tsc`"
  ],
  "antiPatterns": {
    "status": "ran",
    "total": 0,
    "rows": []
  }
}
[exit 0]
--stderr:
=== clean gen json
{
  "gen": [
    {
      "file": "generated/Talk.ts",
      "status": "new"
    }
  ],
  "summary": "1 written",
  "help": [
    "typecheck the generated code with `npx tsc`",
    "create your database tables with `meta migrate --from-db --db <url> --dialect sqlite --slug init --apply`"
  ],
  "antiPatterns": {
    "status": "ran",
    "total": 0,
    "rows": []
  }
}
[exit 0]
--stderr:
=== verify api (json)
meta: meta verify — running --templates (default). Explicit subverbs: --templates (prompt drift), --db/--dialect d1 (schema drift), --codegen (codegen drift), --docs (docs drift), --deps (dependency drift), --replay/--replay-snapshot (the committed migration chain replays from empty).
meta: meta verify — no template.* nodes found; the template gate had nothing to check.
meta: meta verify — 1 doc generator(s) listed under `generators`, which `meta gen` does not run (advisory — does not fail the build):
meta:   metaobjects.config.ts: apiDocsFile() is listed under `generators`, and `meta gen` skips it — `meta docs` writes documentation and `meta verify --docs` checks it. Remove apiDocsFile() from `generators`.
meta: meta verify — not run: schema (--db <url>), codegen (--codegen), docs (--docs), deps (--deps), replay (--replay) — a bare 'meta verify' runs only the template gate (plus the requirement ledger); name each gate to run it
{
  "verify": [
    {
      "gate": "templates",
      "ran": true,
      "ok": true
    },
    {
      "gate": "schema",
      "ran": false,
      "ok": true
    },
    {
      "gate": "codegen",
      "ran": false,
      "ok": true
    },
    {
      "gate": "docs",
      "ran": false,
      "ok": true
    },
    {
      "gate": "deps",
      "ran": false,
      "ok": true
    },
    {
      "gate": "requirements",
      "ran": true,
      "ok": true
    },
    {
      "gate": "replay",
      "ran": false,
      "ok": true
    }
  ],
  "exitCode": 0,
  "summary": "2 gate(s) ran, all clean; 1 advisory finding(s)",
  "help": [
    "1 doc generator(s) listed under `generators`, which `meta gen` skips — see antiPatterns.rows[] (rule \"doc-generator-in-gen\"); `meta docs` writes documentation"
  ],
  "antiPatterns": {
    "status": "ran",
    "total": 1,
    "rows": [
      {
        "file": "metaobjects.config.ts",
        "line": 0,
        "rule": "doc-generator-in-gen",
        "construct": "meta docs",
        "message": "metaobjects.config.ts: apiDocsFile() is listed under `generators`, and `meta gen` skips it — `meta docs` writes documentation and `meta verify --docs` checks it. Remove apiDocsFile() from `generators`."
      }
    ]
[exit 0]
=== verify str (text)
meta verify — running --templates (default). Explicit subverbs: --templates (prompt drift), --db/--dialect d1 (schema drift), --codegen (codegen drift), --docs (docs drift), --deps (dependency drift), --replay/--replay-snapshot (the committed migration chain replays from empty).
meta verify — no template.* nodes found; the template gate had nothing to check.
meta: meta verify — 1 doc generator(s) listed under `generators`, which `meta gen` does not run (advisory — does not fail the build):
meta:   metaobjects.config.ts: "docs" is listed under `generators`, and `meta gen` refuses it, so the run fails — `meta docs` writes documentation and `meta verify --docs` checks it. Remove "docs" from `generators`.
meta verify — not run: schema (--db <url>), codegen (--codegen), docs (--docs), deps (--deps), replay (--replay) — a bare 'meta verify' runs only the template gate (plus the requirement ledger); name each gate to run it
=== verify clean (json)
meta: meta verify — running --templates (default). Explicit subverbs: --templates (prompt drift), --db/--dialect d1 (schema drift), --codegen (codegen drift), --docs (docs drift), --deps (dependency drift), --replay/--replay-snapshot (the committed migration chain replays from empty).
meta: .metaobjects/.gen-state/.hashes.json is git-ignored, so it never reaches another machine — on a fresh clone or CI runner 'meta gen' cannot tell your hand edits from its own stale output, and will refuse to overwrite rather than guess. The rule is '__tmp__/' at .gitignore:17 — replace it there with a '/*' form plus a '!' negation for the manifest (e.g. '__tmp__/*' and '!__tmp__/.hashes.json') (the glob matters — git will not descend into an excluded directory, so a negation INSIDE an excluded directory can never apply), then commit the manifest. If you deliberately do not commit generated output, ignore this.
meta: meta verify — no template.* nodes found; the template gate had nothing to check.
meta: meta verify — not run: schema (--db <url>), codegen (--codegen), docs (--docs), deps (--deps), replay (--replay) — a bare 'meta verify' runs only the template gate (plus the requirement ledger); name each gate to run it
{
  "verify": [
    {
      "gate": "templates",
      "ran": true,
      "ok": true
    },
    {
      "gate": "schema",
      "ran": false,
      "ok": true
    },
    {
      "gate": "codegen",
      "ran": false,
      "ok": true
    },
    {
      "gate": "docs",
      "ran": false,
      "ok": true
    },
    {
      "gate": "deps",
      "ran": false,
      "ok": true
    },
    {
      "gate": "requirements",
      "ran": true,
      "ok": true
    },
    {
      "gate": "replay",
      "ran": false,
      "ok": true
=== gen --list
docs  —  on by default; the canonical door is `meta docs`
  api-docs           —  Per-entity/template SDK API reference (the generated code's API, human + agent forms).  [package-only, run by `meta docs`, WIRED but skipped by `meta gen`]
                        the api surface of `meta docs` (the single docs door, ADR-0025), which runs it with nothing wired.
  docs               —  Neutral per-entity / per-template Markdown documentation pages.  [neutral, package-only, run by `meta docs`]
                        neutral artifact — use `meta docs` (the single docs door, ADR-0021 D1); not part of the recommended `meta gen` native suite.
  mermaid-er         —  Mermaid ER diagram of the entity/relationship model.  [neutral, package-only]
                        neutral artifact owned by the docs engine (ADR-0020), deprecated under `meta gen`: do not add it to a new config. A `mermaidErDiagram()` already wired in `generators` still runs; `meta docs` draws the same diagram on its overview page.
=== gen --list json (api)
  },
  {
    "name": "api-docs",
    "kind": "generator",
    "layer": "docs",
    "tier": "native",
    "package": "@metaobjectsdev/codegen-ts",
    "description": "Per-entity/template SDK API reference (the generated code's API, human + agent forms).",
    "note": "the api surface of `meta docs` (the single docs door, ADR-0025), which runs it with nothing wired.",
    "door": "meta docs",
    "install": {
      "dev": [
        "@metaobjectsdev/codegen-ts@^1.1.0"
      ],
      "runtime": []
Evidence: mixed config still generates and warns; meta docs still works
=== mixed entity+apiDocsFile gen json
meta: .metaobjects/.gen-state/.hashes.json is git-ignored, so it never reaches another machine — on a fresh clone or CI runner 'meta gen' cannot tell your hand edits from its own stale output, and will refuse to overwrite rather than guess. The rule is '__tmp__/' at .gitignore:17 — replace it there with a '/*' form plus a '!' negation for the manifest (e.g. '__tmp__/*' and '!__tmp__/.hashes.json') (the glob matters — git will not descend into an excluded directory, so a negation INSIDE an excluded directory can never apply), then commit the manifest. If you deliberately do not commit generated output, ignore this.
meta: [api-docs] docs are produced by 'meta docs' (ADR-0025); remove apiDocsFile() from generators. Skipped.
{
  "gen": [
    {
      "file": "generated/Talk.ts",
      "status": "unchanged"
    }
  ],
  "summary": "1 unchanged",
  "help": [
    "typecheck the generated code with `npx tsc`",
    "`meta gen` skipped 1 doc generator(s) — see warnings[]; run `meta docs` for documentation, and remove the doc generators from `generators` in metaobjects.config.ts"
  ],
  "antiPatterns": {
    "status": "ran",
    "total": 0,
    "rows": []
  },
  "warnings": [
    ".metaobjects/.gen-state/.hashes.json is git-ignored, so it never reaches another machine — on a fresh clone or CI runner 'meta gen' cannot tell your hand edits from its own stale output, and will refuse to overwrite rather than guess. The rule is '__tmp__/' at .gitignore:17 — replace it there with a '/*' form plus a '!' negation for the manifest (e.g. '__tmp__/*' and '!__tmp__/.hashes.json') (the glob matters — git will not descend into an excluded directory, so a negation INSIDE an excluded directory can never apply), then commit the manifest. If you deliberately do not commit generated output, ignore this.",
    "[api-docs] docs are produced by 'meta docs' (ADR-0025); remove apiDocsFile() from generators. Skipped."
  ]
}
=== meta docs still works
meta: --format is honored by: gen, verify, migrate, types, deps, eject. `meta docs` ignores it and prints text.
meta docs — wrote 1 overview + 1 entity page(s) + 0 template page(s); 3 api page(s); agent/schema.md → ~/.no-mistakes/worktrees/5b8c6c97e760/01M4NXG2YC0ZFP63RMPGVK3ERF/server/typescript/packages/cli/test/fixtures/__tmp__/live-mix/docs/generated
=== strapi gen --list text
  api-docs           —  Per-entity/template SDK API reference (the generated code's API, human + agent forms).  [package-only, run by `meta docs`, WIRED but skipped by `meta gen`]
                        the api surface of `meta docs` (the single docs door, ADR-0025), which runs it with nothing wired.
Evidence: full TypeScript regression (ci-local --quick) log
metaobjects local CI  (mode: quick — TS + drift gates only)

── ▶ leak-scan (security) ──────────────────────────────────────────────
leak-scan: clean

── ▶ pom-version parity ──────────────────────────────────────────────
check-pom-versions: ✓ 3 parent + 1 property pom(s) match reactor 8.1.0

── ▶ bun-version parity ──────────────────────────────────────────────
check-bun-version: bun 1.3.14 matches the workflow pin.

── ▶ uv.lock version parity ──────────────────────────────────────────────
check-uv-lock-version: uv.lock agrees with pyproject.toml (1.1.0)

── ▶ publish-intent parity ──────────────────────────────────────────────
publish-intent parity: OK (lockstep 1.1.0; 2 declared source-only)

── ▶ publish-set parity ──────────────────────────────────────────────
   1. @metaobjectsdev/metadata  (server/typescript/packages/metadata)
   2. @metaobjectsdev/render  (server/typescript/packages/render)
   3. @metaobjectsdev/codegen-ts  (server/typescript/packages/codegen-ts)
   4. @metaobjectsdev/runtime-ts  (server/typescript/packages/runtime-ts)
   5. @metaobjectsdev/migrate-ts  (server/typescript/packages/migrate-ts)
   6. @metaobjectsdev/sdk  (server/typescript/packages/sdk)
   7. @metaobjectsdev/docs-site  (server/typescript/packages/docs-site)
   8. @metaobjectsdev/runtime-web  (client/web/packages/runtime-web)
   9. @metaobjectsdev/codegen-ts-react  (server/typescript/packages/codegen-ts-react)
  10. @metaobjectsdev/codegen-ts-tanstack  (server/typescript/packages/codegen-ts-tanstack)
  11. @metaobjectsdev/react  (client/web/packages/react)
  12. @metaobjectsdev/tanstack  (client/web/packages/tanstack)
  13. @metaobjectsdev/cli  (server/typescript/packages/cli)
  14. @metaobjectsdev/ai-runtime  (server/typescript/packages/ai-runtime)
publish set: OK (lockstep 1.1.0; 14 packages, tier-ordered, closed over sibling deps)
ok:   happy path: private + off-lockstep excluded, order [metadata, render, docs-site, cli]
ok:   untiered member: threw on "publish order undeclared"
ok:   unclosed set: threw on "not closed over its own runtime dependencies"
ok:   inverted tier order: threw on "publishes a dependency AFTER its dependent"
ok:   regression: docs-site (#6) publishes before cli (#12) in the real tree
ok:   regression: docs-site has a declared tier

publish-set tests: all passed

── ▶ no committed pre-release version ──────────────────────────────────────────────
check-no-prerelease-versions: ✓ no pre-release version in any version declaration

── ▶ script-name hook collisions ──────────────────────────────────────────────
script-name-hooks: ✓ 10 root scripts, no lifecycle-hook collisions

── ▶ ci lane selection ──────────────────────────────────────────────
ok:   [server/typescript/packages/cli/src/x.ts] -> 'ts'
ok:   [client/web/packages/react/src/y.tsx] -> 'ts'
ok:   [server/java/metadata/src/main/java/A.java] -> 'java'
ok:   [server/java/codegen-kotlin/src/main/kotlin/B.kt] -> 'java'
ok:   [server/python/src/metaobjects/loader.py] -> 'python'
ok:   [server/csharp/MetaObjects/Loader.cs] -> 'csharp'
ok:   [fixtures/conformance/foo/meta.json] -> 'ts java python csharp'
ok:   [spec/metamodel.md] -> 'ts java python csharp'
ok:   [scripts/ci-local.sh] -> 'ts java python csharp'
ok:   [.github/workflows/local-ci.yml] -> 'ts java python csharp'
ok:   [agent-context/skills/x.md] -> 'ts java python csharp'
ok:   [weird-new-toplevel/file.txt] -> 'ts java python csharp'
ok:   [docs/features/cli.md] -> ''
ok:   [README.md CHANGELOG.md] -> ''
ok:   [server/typescript/a.ts server/python/b.py] -> 'ts python'
ok:   [docs/x.md fixtures/y.json] -> 'ts java python csharp'
ALL PASS
ok:   union all -> 'ts java python csharp'
ok:   union reorders to canonical -> 'ts java python csharp'
ok:   union deduplicates -> 'ts java'
ok:   union single -> 'python'
ok:   union empty -> ''
ok:   union drops unknown tokens -> 'ts'
ok:   every lane green -> nothing to re-run -> ''
ok:   docs-only run skips a red java -> java still not green -> 'java'
ok:   one red ts lane selects the whole ts port -> 'ts'
ok:   skipped is walked past to the real verdict -> ''
ok:   cancelled is not green -> 'csharp'
ok:   a lane with no verdict in the window is not green -> 'python'
ok:   no history at all -> everything -> 'ts java python csharp'
ok:   every port-testing job in .github/workflows/local-ci.yml is mapped by lane_port -> ''
ok:   every lane in lane_port exists as a job in .github/workflows/local-ci.yml -> ''
all checks passed

── ▶ extract field kinds ──────────────────────────────────────────────
extract FieldKind: 4 ports agree on [STRING, INT, LONG, DOUBLE, BOOLEAN, ENUM, OBJECT] (1 sanctioned deviation(s): csharp)

── ▶ no-magic gate wired (5 ports) ──────────────────────────────────────────────
no-magic gate coverage: 5 ports wired; 13 shapes tracked, 0 known gaps

── ▶ test-file references resolve ──────────────────────────────────────────────
test-file references: 32 named, all resolve

── ▶ metamodel-version bump ──────────────────────────────────────────────
  metamodel-version: additive change since v1.0.13; declared 1.1 (1.0 → 1.1) — ok.
ok:   no change classifies as nothing
ok:   a removed subtype is BREAKING
ok:   an added subtype is ADDITIVE
ok:   a removed attr is BREAKING
ok:   an added OPTIONAL attr is ADDITIVE
ok:   an added REQUIRED attr is BREAKING
ok:   optional → required is BREAKING
ok:   required → optional is ADDITIVE
ok:   a changed valueType is BREAKING
ok:   a changed isArray is BREAKING
ok:   an enum member REMOVED is BREAKING
ok:   an enum member ADDED is ADDITIVE
ok:   an OPEN attr becoming a closed enum is BREAKING
ok:   a closed enum OPENING is ADDITIVE
ok:   a removed child rule is BREAKING
ok:   an added OPTIONAL child rule is ADDITIVE
ok:   an added MANDATORY child rule is BREAKING
ok:   raising min is BREAKING
ok:   lowering min is ADDITIVE
ok:   capping an unbounded max is BREAKING
ok:   lifting a cap is ADDITIVE
ok:   lowering a finite max is BREAKING
ok:   a removed commonAttr is BREAKING
ok:   a changed default subtype is BREAKING (it changes what an unqualified declaration MEANS)
ok:   a removed default subtype is BREAKING
ok:   an added default subtype is ADDITIVE
ok:   a type description change is PROSE ONLY
ok:   a `rules` change is PROSE ONLY — this is exactly #210, and why prose only warns
ok:   an attr description change is PROSE ONLY
ok:   no change requires no bump
ok:   additive requires a minor
ok:   post-1.0 breaking requires a major
ok:   pre-1.0 breaking requires a minor, not a major
ok:   post-1.0 a correction requires a minor, NOT a major
ok:   a correction must still move the version
ok:   pre-1.0 the correction flag changes nothing
ok:   a correction over `none` is still none
ok:   a correction over `additive` is still a minor
ok:   an unmoved version must NOT satisfy a minor
ok:   1.0 → 1.1 satisfies a minor
ok:   a major over-satisfies a minor
ok

... [463828 bytes truncated] ...

inPackage;

[Survived] EqualityOperator
src/super-resolve.ts:229:9
-       if (inPackage !== undefined) return inPackage;
+       if (inPackage === undefined) return inPackage;

[Survived] ArrayDeclaration
src/super-resolve.ts:296:31
-     const pending: MetaData[] = [];
+     const pending: MetaData[] = ["Stryker was here"];

[Survived] ConditionalExpression
src/super-resolve.ts:298:9
-       if (n.superRef !== undefined) pending.push(n);
+       if (true) pending.push(n);

[Survived] ConditionalExpression
src/super-resolve.ts:302:40
-       if (node.superRef === undefined || node.superResolved !== undefined) return;
+       if (node.superRef === undefined || false) return;

[Survived] ConditionalExpression
src/super-resolve.ts:303:9
-       if (attempted.has(node)) return; // already resolved-or-failed this pass — never re-report
+       if (false) return; // already resolved-or-failed this pass — never re-report

[Survived] LogicalOperator
src/super-resolve.ts:305:26
-       const effectivePkg = node.package ?? node.fileDefaultPackage ?? "";
+       const effectivePkg = (node.package ?? node.fileDefaultPackage) && "";

[Survived] LogicalOperator
src/super-resolve.ts:305:26
-       const effectivePkg = node.package ?? node.fileDefaultPackage ?? "";
+       const effectivePkg = node.package && node.fileDefaultPackage ?? "";

[Survived] StringLiteral
src/super-resolve.ts:305:69
-       const effectivePkg = node.package ?? node.fileDefaultPackage ?? "";
+       const effectivePkg = node.package ?? node.fileDefaultPackage ?? "Stryker was here!";

[Survived] ConditionalExpression
src/super-resolve.ts:311:9
-       if (isChildTargetingRef(node.superRef)) {
+       if (true) {

[Survived] ConditionalExpression
src/super-resolve.ts:313:11
-         if (parsed !== undefined) {
+         if (true) {

[Survived] ConditionalExpression
src/super-resolve.ts:315:13
-           if (ownerNode !== undefined) resolveNode(ownerNode);
+           if (true) resolveNode(ownerNode);

[Survived] ObjectLiteral
src/super-resolve.ts:346:19
-             target: { type: target.type, subType: target.subType },
+             target: {},

[Survived] ObjectLiteral
src/super-resolve.ts:347:21
-             referrer: { type: node.type, subType: node.subType },
+             referrer: {},

[Survived] StringLiteral
src/super-resolve.ts:365:15
-           kind: "unresolved",
+           kind: "",

Ran 0.99 tests per mutant on average.
--------------------|------------------|----------|-----------|------------|----------|----------|
                    | % Mutation score |          |           |            |          |          |
File                |  total | covered | # killed | # timeout | # survived | # no cov | # errors |
--------------------|--------|---------|----------|-----------|------------|----------|----------|
All files           |  52.76 |   52.76 |      886 |        13 |        805 |        0 |        0 |
 parser-core.ts     |  45.81 |   45.81 |      492 |         0 |        582 |        0 |        0 |
 provider.ts        |  61.54 |   61.54 |       39 |         1 |         25 |        0 |        0 |
 serializer-json.ts |  60.26 |   60.26 |      129 |         9 |         91 |        0 |        0 |
 subtype-rules.ts   |  69.23 |   69.23 |      117 |         0 |         52 |        0 |        0 |
 super-resolve.ts   |  67.07 |   67.07 |      109 |         3 |         55 |        0 |        0 |
--------------------|--------|---------|----------|-----------|------------|----------|----------|
�[32m13:36:48 (3460343) INFO MutationTestReportHelper�[39m Final mutation score of 52.76 is greater than or equal to break threshold 35
�[32m13:36:49 (3460343) INFO HtmlReporter�[39m Your report can be found at: file://~/.no-mistakes/worktrees/5b8c6c97e760/01M4NXG2YC0ZFP63RMPGVK3ERF/server/typescript/packages/metadata/reports/mutation/mutation.html
�[32m13:36:49 (3460343) INFO MutationTestExecutor�[39m Done in 5 minutes and 38 seconds.

── ▶ doc-template drift ──────────────────────────────────────────────
synced: ~/.no-mistakes/worktrees/5b8c6c97e760/01M4NXG2YC0ZFP63RMPGVK3ERF/templates/docs/entity-page.md.mustache -> ~/.no-mistakes/worktrees/5b8c6c97e760/01M4NXG2YC0ZFP63RMPGVK3ERF/server/typescript/packages/codegen-ts/templates/docs/entity-page.md.mustache
synced: ~/.no-mistakes/worktrees/5b8c6c97e760/01M4NXG2YC0ZFP63RMPGVK3ERF/templates/docs/template-page.md.mustache -> ~/.no-mistakes/worktrees/5b8c6c97e760/01M4NXG2YC0ZFP63RMPGVK3ERF/server/typescript/packages/codegen-ts/templates/docs/template-page.md.mustache
synced: ~/.no-mistakes/worktrees/5b8c6c97e760/01M4NXG2YC0ZFP63RMPGVK3ERF/templates/api/agent-api.md.mustache -> ~/.no-mistakes/worktrees/5b8c6c97e760/01M4NXG2YC0ZFP63RMPGVK3ERF/server/typescript/packages/codegen-ts/templates/api/agent-api.md.mustache
synced: ~/.no-mistakes/worktrees/5b8c6c97e760/01M4NXG2YC0ZFP63RMPGVK3ERF/templates/api/entity-api.md.mustache -> ~/.no-mistakes/worktrees/5b8c6c97e760/01M4NXG2YC0ZFP63RMPGVK3ERF/server/typescript/packages/codegen-ts/templates/api/entity-api.md.mustache
synced: ~/.no-mistakes/worktrees/5b8c6c97e760/01M4NXG2YC0ZFP63RMPGVK3ERF/templates/api/index.md.mustache -> ~/.no-mistakes/worktrees/5b8c6c97e760/01M4NXG2YC0ZFP63RMPGVK3ERF/server/typescript/packages/codegen-ts/templates/api/index.md.mustache
generated ~/.no-mistakes/worktrees/5b8c6c97e760/01M4NXG2YC0ZFP63RMPGVK3ERF/server/typescript/packages/codegen-ts/src/render-engine/embedded-templates.generated.ts (5 template(s): api/agent-api.md, api/entity-api.md, api/index.md, docs/entity-page.md, docs/template-page.md)
doc templates synced from canonical root: ~/.no-mistakes/worktrees/5b8c6c97e760/01M4NXG2YC0ZFP63RMPGVK3ERF/templates (docs api)

── ▶ embedded-library drift ──────────────────────────────────────────────
wrote 6 embedded library file(s) + 2 manifest(s) to server/typescript/packages/metadata/src/library/embedded-library.generated.ts, server/java/metadata/src/main/java/com/metaobjects/library/EmbeddedLibrary.java and server/csharp/MetaObjects/Library/EmbeddedLibrary.cs

── ⊘ --quick: SKIPPING the other-language ports (csharp/java/python/kotlin),
        the full Java reactor, the docker integration suite and the cube live
        check. Run the full `scripts/ci-local.sh` (no flag) before opening/merging
        a PR or tagging.

══════════════════════ SUMMARY ══════════════════════
  ✓ leak-scan (security)
  ✓ pom-version parity
  ✓ bun-version parity
  ✓ uv.lock version parity
  ✓ publish-intent parity
  ✓ publish-set parity
  ✓ no committed pre-release version
  ✓ script-name hook collisions
  ✓ ci lane selection
  ✓ extract field kinds
  ✓ no-magic gate wired (5 ports)
  ✓ test-file references resolve
  ✓ metamodel-version bump
  ✓ positioning claims
  ✓ migration guides vs registry
  ✓ dependencies installed
  ✓ peer-range bounds
  ✓ owned template copies current
  ✓ reference templates lint
  ✓ shipped doc examples load
  ✓ no retired $apiPrefix
  ✓ site payload is true
  ✓ site reference is fresh
  ✓ release tag gate
  ✓ scripts/ typecheck
  ✓ requirements ledger verifies
  ✓ requirements cover vocabulary
  ✓ metamodel scaffolder
  ✓ requirement harness
  ✓ fixture-lint
  ✓ ts build + typecheck
  ✓ conformance: typescript
  ✓ ts unit suites
  ✓ completeness-gate (mutation)
  ✓ doc-template drift
  ✓ embedded-library drift
  ⊘ csharp/java/python/kotlin conformance (--quick)
  ⊘ java-reactor (--quick)
  ⊘ integration-tests (--quick)
  ⊘ cube-model live check (--quick)
══════════════════════════════════════════════════════
LOCAL CI PASSED (with 4 skipped — see ⊘ above).

Pipeline

Updates from git push no-mistakes

✅ **Intent** - passed

✅ No issues found.

✅ **Rebase** - passed

✅ No issues found.

⚠️ **Review** - 1 info
  • ℹ️ server/typescript/packages/codegen-ts/src/packaged-docs-generators.ts:35 - Wrong label when the skipped doc generator is wired as a stable-name string. Trace: generators: [&#34;entity&#34;, &#34;api-docs&#34;] then meta gen --format json. normalizeConfig resolves the string to a generator named api-docs, the runner skips it (runner.ts:690), and warnings[] now carries [api-docs] docs are produced by &#39;meta docs&#39; (ADR-0025); remove apiDocsFile() from generators. Skipped. The config contains no apiDocsFile(); the entry to remove is &#34;api-docs&#34;. The wording predates this change, but this change is what delivers it to the structured document an agent acts on, and meta verify already names the string form correctly for the same config (doc-generator-advisory.ts:68, &#34;api-docs&#34; is listed under generators). Same class as the round-1 string-spec label fix; only this one site remains. Fix: resolveGenerators maps specs 1:1, so in the runner loop read opts.config.generators[i], and when it is a string name the quoted string in the warning instead of the factory call. Keep the constructed-generator wording unchanged (pinned by runner-docs-shim.test.ts).
✅ **Test** - passed

✅ No issues found.

  • Live validation: ✅ go - 11 of 11 scenarios driven live against the product
Scenario Result Live Evidence
Agent runs meta gen --format json|toon with apiDocsFile() wired and sees the skip reason in the result's warnings[] ✅ pass live gen-doc-generators.txt: warnings[] holds "[api-docs] docs are produced by 'meta docs' (ADR-0025); remove apiDocsFile() from generators. Skipped." in json and toon, with a summary and help line pointin…
Same for docsFile() wired (docs-file) ✅ pass live gen-doc-generators.txt: warnings[] carries the docsFile() skip line in json and toon
Text output and stderr still show the warning ✅ pass live gen-doc-generators.txt: stderr still prints the warning; the text form says "Nothing was generated ... Run meta docs"
Mixed config ["entity", apiDocsFile()] still generates entity code and records the warning ✅ pass live gen-mixed-docs.txt: Talk.ts written/unchanged, warnings[] has the api-docs line, and help notes "skipped 1 doc generator(s)"
Clean config produces no spurious warnings (adversarial control) ✅ pass live gen-other-and-verify.txt: ["entity"] gives no warnings key and an empty stderr
meta gen --list api-docs row names meta docs as its door and marks it skipped when wired ✅ pass live gen-other-and-verify.txt and gen-mixed-docs.txt: row note says it is the api surface of meta docs; the json row carries door "meta docs"; it is marked "WIRED but skipped by meta gen" when wired
String-wired "docs" is reported as refused by meta gen, not skipped (adversarial) ✅ pass live gen-other-and-verify.txt: gen exits 1 with 'generator "docs" is neutral (owned by meta docs)'; meta verify says '"docs" is listed under generators, and meta gen refuses it, so the run fails'
mermaid-er recorded decision holds: string "mermaid-er" refused as neutral, constructed mermaidErDiagram() still runs, catalog note states the back-compat fact ✅ pass live gen-other-and-verify.txt: the string spec exits 1 as neutral; the constructed generator writes generated/docs/model.md; the list note says deprecated, a wired one still runs, and meta docs draws the…
meta verify surfaces the doc-generator-in-gen advisory without failing the build ✅ pass live gen-other-and-verify.txt: an antiPatterns row with rule doc-generator-in-gen, exitCode 0, and a help line naming meta docs
meta docs still produces documentation after the change ✅ pass live gen-mixed-docs.txt: wrote the overview, entity pages and api pages
Full TypeScript regression suite (ci-local --quick) ✅ pass live ci-local-quick.log: LOCAL CI PASSED; the four skipped lanes are other-language ports, the Java reactor, Docker integration tests and the Cube live check
  • scripts/ci-local.sh --only ts-fast --only ts-unit --strict-toolchains
  • bun bin/meta.ts gen --format json|toon|text in disposable projects wiring apiDocsFile() and docsFile()
  • meta gen with string specs &#34;api-docs&#34;, &#34;docs&#34;, &#34;mermaid-er&#34; and with a constructed mermaidErDiagram()
  • meta gen with [&#34;entity&#34;, apiDocsFile()] (mixed), then meta docs on the same project
  • meta gen with a clean [&#34;entity&#34;] config (control)
  • meta verify --format json|text on the api-docs and string-docs projects
  • meta gen --list text and json for the api-docs and mermaid-er rows
  • scripts/ci-local.sh --quick --strict-toolchains (full TS regression: hygiene gates, ts build + typecheck, TypeScript conformance, ts unit suites, mutation gate, doc-template and embedded-library drift)
✅ **Document** - passed

✅ No issues found.

✅ **Lint** - passed

✅ No issues found.

✅ **Push** - passed

✅ No issues found.

@dmealing

Copy link
Copy Markdown
Member Author

Validation took 2 no-mistakes runs. Run 1 passed the configured test command and then failed in the test step when the pipeline's test agent hit a provider error; that was not a code failure. Run 2 passed on the same change plus the review fix round and the CHANGELOG move under 1.1.0. The forge CI step was skipped for this run, so the validation is the local pipeline result.

…ery output form

ADR-0025 made `meta docs` the door for documentation, so `meta gen` warns about
and skips a docsFile() or apiDocsFile() listed under `generators`. The skip is
right; the signal was not reaching every reader.

- 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. `warnings[]` now carries every warning the run printed: all of
  the runner's, a generator's 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.
- A config wiring only doc generators was told "no entities to generate" and to
  author entities. The summary, next step and text line name the real reason.
- meta gen --list printed no note on any row (the registry notes stopped being
  rendered when the catalog was rewritten) and presented api-docs as a generator
  to wire. The api-docs and docs rows now say they are run by `meta docs`, a
  wired one reads as skipped, and --probe gives them no file count. The JSON row
  carries `note` and `door`.
- meta verify reports the wiring as an advisory row, rule doc-generator-in-gen.
- The unknown-generator error no longer offers api-docs.

mermaid-er is stated everywhere as what it is: a generator `meta gen` runs.
`meta docs` has never run it; it draws the ER diagram on its overview page,
while mermaidErDiagram() writes the same diagram as a file of its own, which
only `meta gen` writes. The catalog note said "surfaced via meta docs" and the
stable name was refused in `generators` as "neutral (owned by 'meta docs')"
while the factory wired beside it ran. The note now names the command that runs
it, and `generators: ["mermaid-er"]` resolves. `"docs"` is still refused.

One definition of what the runner skips (packaged-docs-generators.ts) is read by
the runner, resolveGenerators and the catalog. runGen() returns
skippedDocGenerators beside warnings, so a caller decides from the fact instead
of matching a sentence.

TypeScript only: the C#, Java, Kotlin and Python ports register no doc
generator for code generation, so there is nothing to wire and nothing to skip.
… as refused

Assisted-by: no-mistakes:claude:claude-opus-5-5
1.1.0 has not shipped, so the entry belongs in its Fixed list, not under
Unreleased.
@dmealing
dmealing force-pushed the fm/mo-1-1-0-docs-door-signals branch from 1206180 to f7b8430 Compare October 11, 2026 18:05
@dmealing
dmealing merged commit 5891971 into main Oct 11, 2026
1 check passed
@dmealing
dmealing deleted the fm/mo-1-1-0-docs-door-signals branch October 11, 2026 18:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant