Skip to content

Commit 6f11da4

Browse files
dmealingclaude
andcommitted
docs(agent-context): ten shipped-skill claims promised a default suite this branch deleted
`29f84b461` removed `cli._default_generators()` and `GenCommand.DefaultGeneratorNames`, which made ADR-0034 Amendment 2 true on every port. Ten places in the shipped skills went on describing the world before it — and these are not repo docs, they assemble into every adopter's stack, so the wrong answer arrives wherever an agent is doing the work. The sharpest was a table in `metaobjects-codegen/SKILL.md` naming both removed symbols as "a real default" and answering "does an existing project upgrading get it?" with **Yes, with no edit** for C# and Python. The same claim drove a COUNT in two other skills — "on three of five ports an existing project emits none" — which is now five of five, so the fix is arithmetic, not a word swap. Alongside it, `meta init` no longer scaffolds `namesFile()`; it writes `generators: []` and an empty `codegen/generators/`, so the paragraph that offered the scaffold as the port's exception had no exception left to offer. The rest were `--template-spec` entries "appended to the default suite" (C# and Python) and three "`names` is in the default suite" asides. Every surviving mention of the phrase in `agent-context/` is now a negation. The conformance corpus is regenerated in this commit rather than a later one: the expected trees are byte-compared against `assemble()`, so prose and corpus moving apart by even one commit is a red lane on a docs-only push. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011cQxyVuTkdPmAduLiedNEg
1 parent 306136d commit 6f11da4

24 files changed

Lines changed: 121 additions & 114 deletions

File tree

‎agent-context/skills/metaobjects-audit/SKILL.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,7 @@ Per finding: `file:line` → what → generated-equivalent exists? → recommend
351351

352352
**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.
353353

354-
**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 THREE of five ports an existing project emits none**. C# and Python have a real default suite and get it by upgrading; TypeScript's `generators: [...]` and the JVM's `<generators>` are each the COMPLETE list, so `meta init` scaffolding `namesFile()` covers only a project initialized at 1.0 and upgrading the package never edits a config written earlier. 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.
354+
**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 `<generators>` 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.
355355

356356
**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 `<adopted>/<total> 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.
357357

‎agent-context/skills/metaobjects-audit/references/capability-checklist.md‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,10 +71,10 @@ classify it (using the classification scheme in `SKILL.md`) and route the cutove
7171
migration script, a body-to-column map (drift signature 11). Every port emits a per-object
7272
names artifact from the declaration, so a literal is a second source of truth even when it
7373
agrees with the naming strategy today. A typed ORM handle in its place is correct. **Check
74-
the artifact is emitted at all before scoring the literals: on TypeScript and the JVM the
75-
generator list in the config IS the complete list, so an existing project emits none and the
76-
un-wired generator is the finding FIRST** (C# and Python have a real default suite and get it
77-
by upgrading). **This entry is the physical-name INSTANCE of signature 11.** The rule that
74+
the artifact is emitted at all before scoring the literals: on every port the selection IS
75+
the complete list — the config's on TypeScript and the JVM, `--generators` on C# and Python —
76+
so an existing project emits none and the un-wired generator is the finding FIRST** (no port
77+
ships a default suite; ADR-0034 Amendment 2). **This entry is the physical-name INSTANCE of signature 11.** The rule that
7878
generates the rest — and the reason an enum member compared as a bare string is NOT one — is
7979
the Cross-cutting entry below.
8080
- **`@kind` = `view` / `materializedView`** — hunt hand-written SQL views where an authored

‎agent-context/skills/metaobjects-audit/references/csharp.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ rejected (exit 2).
5151
| `FromSqlInterpolated(` outside `.g.cs` | stored-proc call — candidate for the `callable` generator |
5252
| `// keep in sync with` / `// mirrors the` | second-source-of-truth comment — always a finding |
5353
| `HasPrecision(` hand-coded | `field.decimal` with `@precision`/`@scale` drives this from the `entity` generator |
54-
| a table/column string in raw-SQL EF calls, or `nameof(Entity.Prop)` standing in for a column | second spelling of a declared physical name — reference `<Entity>Names.g.cs` (`AuthorNames.SourcePrimaryTable` / `<Field>Column`, default suite — `Names.Name` is the OBJECT's name, not the table); an EF property inside LINQ is the typed handle — correct |
54+
| a table/column string in raw-SQL EF calls, or `nameof(Entity.Prop)` standing in for a column | second spelling of a declared physical name — reference `<Entity>Names.g.cs` (`AuthorNames.SourcePrimaryTable` / `<Field>Column`, emitted when `names` is named in `--generators` — `Names.Name` is the OBJECT's name, not the table); an EF property inside LINQ is the typed handle — correct |
5555

5656
---
5757

@@ -66,7 +66,7 @@ selection uses stable names via `dotnet meta gen --generators <names>`, over a
6666
**So do not score a C# project down for "not owning its generators", and do not
6767
recommend writing one.** The customization path here is the **declarative template**:
6868
`dotnet meta gen --template-spec <json> --template-root <dir>`, whose entries append to
69-
the default suite. A finding of the form "the built-ins do not emit the shape this
69+
your `--generators` selection. A finding of the form "the built-ins do not emit the shape this
7070
project needs" resolves to a template-spec, not to generator code. Worked example with
7171
the full JSON: `docs/ports/csharp.md`.
7272

‎agent-context/skills/metaobjects-audit/references/python.md‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ regardless of server language — see the migration reference.
5252
| `def get_all_` / `def create_` / `def update_` / `def delete_` in non-generated files | hand-rolled CRUD — compare to the generated router |
5353
| `# keep in sync with` / `# mirrors the` | second-source-of-truth comment — always a finding |
5454
| `try: ... except KeyError` / `?? ''` around format strings in prompt code | silent-degradation hack around a prompt payload — flag it |
55-
| a table/column string in the repository implementation (SQLAlchemy Core, asyncpg/psycopg SQL) | second spelling of a declared physical name — reference `<entity>_names.py` (`AUTHOR_SOURCE_PRIMARY_TABLE` / `AUTHOR_<FIELD>_COLUMN`, default suite); no typed handle exists on this port, so that is never the reason to waive it |
55+
| a table/column string in the repository implementation (SQLAlchemy Core, asyncpg/psycopg SQL) | second spelling of a declared physical name — reference `<entity>_names.py` (`AUTHOR_SOURCE_PRIMARY_TABLE` / `AUTHOR_<FIELD>_COLUMN`, emitted when `names` is named in `--generators`); no typed handle exists on this port, so that is never the reason to waive it |
5656

5757
---
5858

@@ -66,8 +66,8 @@ seam to register a generator of your own. (`--provider module:symbol` registers
6666

6767
**So do not score a Python project down for "not owning its generators", and do not
6868
recommend writing one.** The customization path here is the **declarative template**:
69-
`metaobjects gen --template-spec <json> --templates <dir>`, whose entries append to the
70-
default suite. A finding of the form "the built-ins do not emit the shape this project
69+
`metaobjects gen --template-spec <json> --templates <dir>`, whose entries append to your
70+
`--generators` selection. A finding of the form "the built-ins do not emit the shape this project
7171
needs" resolves to a template-spec, not to generator code. Worked example with the full
7272
JSON: `docs/ports/python.md`.
7373

‎agent-context/skills/metaobjects-codegen/SKILL.md‎

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -489,7 +489,8 @@ generator sets are **closed built-in registries** — `--generators` *selects* f
489489
ships, and there is no seam to register a `Generator` of your own. (Python's
490490
`--provider module:symbol` registers **metamodel vocabulary**, not a generator; do not
491491
reach for it here.) Use `--template-spec <json>` — plus `--templates <dir>` on Python or
492-
`--template-root <dir>` on C# — and your entries are appended to the default suite. Worked
492+
`--template-root <dir>` on C# — and your entries are appended to your `--generators`
493+
selection. Worked
493494
examples with the full JSON: `docs/ports/python.md` and `docs/ports/csharp.md`.
494495

495496
**The spec is auto-discovered, and that is load-bearing.** With no `--template-spec`, both
@@ -544,21 +545,21 @@ everywhere — **each physical name is spelled once, and generated code referenc
544545
| Kotlin | `<Entity>Names.kt` | `ProgramNames.CREATED_AT_COLUMN` |
545546
| Python | `<entity_snake>_names.py` | `PROGRAM_CREATED_AT_COLUMN` |
546547

547-
**Check that it is actually wired before you reference it — on three of five ports an
548-
EXISTING project emits none.** "In the default suite" and "what a fresh scaffold writes"
549-
are different facts, and only C# and Python have the first:
548+
**Check that it is actually wired before you reference it — on ALL FIVE ports a project
549+
emits none until it asks for it.** ADR-0034 Amendment 2 made codegen opt-in everywhere: no
550+
port ships a default suite, so there is no port on which upgrading the package starts
551+
emitting this artifact. "Wired" is the only fact there is.
550552

551-
| Port | Where the suite is decided | An existing project upgrading gets it? |
553+
| Port | Where the selection is declared | An existing project upgrading gets it? |
552554
|---|---|---|
553-
| C# | `GenCommand.DefaultGeneratorNames` — a real default | **Yes**, with no edit |
554-
| Python | `cli.py` `_default_generators()` — a real default | **Yes**, with no edit |
555-
| TypeScript | `metaobjects.config.ts` `generators: [...]` — **the complete list; there is no default suite** | **No** — add `namesFile()` |
555+
| C# | `--generators <csv>` on `dotnet meta gen` — required, no default | **No** — name `names` |
556+
| Python | `--generators <csv>` on `metaobjects gen` — required, no default | **No** — name `names` |
557+
| TypeScript | `metaobjects.config.ts` `generators: [...]` — the complete list | **No** — add `namesFile()` |
556558
| Java / Kotlin | the pom's `<generators>` — the complete list | **No** — add `SpringNamesGenerator` / `KotlinNamesGenerator` |
557559

558-
TypeScript's `meta init` scaffolds `namesFile()`, so a project *initialized* at 1.0 has it;
559-
a project initialized earlier has the config `meta init` wrote then, and upgrading the
560-
package never edits a config. So on TypeScript the artifact is opt-in exactly as it is on
561-
the JVM — the scaffold is not a default. To wire it into an existing TS project:
560+
`meta init` scaffolds `generators: []` and an empty `codegen/generators/`, so even a
561+
project *initialized* at 1.0 has to choose this one — the scaffold is deliberately not a
562+
default by another name. To wire it into a TS project:
562563

563564
```ts
564565
import { namesFile } from "./codegen/generators/names.js"; // after `meta eject names`

‎agent-context/skills/metaobjects-runtime-ui/references/csharp.md‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,9 @@ the Java, Kotlin, and Python backends byte-for-byte.
9494
Inside LINQ keep the property (`db.Authors.Where(a => a.Name == …)`): it is type-checked
9595
against the model, and a string constant there trades a compile error for a runtime one.
9696
Where LINQ does not reach — raw SQL, a migration script, a log line — take the physical
97-
name from the generated `<Entity>Names.g.cs`. `names` is in the default suite, and the
98-
generated entity and `AppDbContext` already read it, so it cannot disagree with the
97+
name from the generated `<Entity>Names.g.cs`. `names` is opt-in — name it in
98+
`--generators` — and once selected the generated entity and `AppDbContext` already read
99+
it, so it cannot disagree with the
99100
mapping: `AuthorNames.SourcePrimaryTable` is the table (the member is named for the
100101
source's `@kind`, so a view reads `SourceReplicaView` / `SourcePrimaryView` and a stored
101102
procedure `SourcePrimaryProc`), `AuthorNames.<Field>Column` the column,

‎agent-context/skills/metaobjects-runtime-ui/references/python.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ resolve the column themselves, so that path never needs a physical name. The mom
100100
repository `Protocol` is backed by your own SQLAlchemy Core / asyncpg / psycopg code, it
101101
does — and nothing Python generates carries one: the Pydantic models, create/patch
102102
shapes, router and allowlist all key by field. Take it from the generated
103-
`<entity_snake>_names.py` (`names` is in the default suite):
103+
`<entity_snake>_names.py` (`names` is opt-in — name it in `--generators`):
104104

105105
```python
106106
from generated.author_names import (

‎fixtures/agent-context-conformance/java-kotlin-react-tanstack/expected/.claude/skills/metaobjects-audit/SKILL.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,7 @@ Per finding: `file:line` → what → generated-equivalent exists? → recommend
351351

352352
**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.
353353

354-
**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 THREE of five ports an existing project emits none**. C# and Python have a real default suite and get it by upgrading; TypeScript's `generators: [...]` and the JVM's `<generators>` are each the COMPLETE list, so `meta init` scaffolding `namesFile()` covers only a project initialized at 1.0 and upgrading the package never edits a config written earlier. 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.
354+
**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 `<generators>` 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.
355355

356356
**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 `<adopted>/<total> 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.
357357

‎fixtures/agent-context-conformance/java-kotlin-react-tanstack/expected/.claude/skills/metaobjects-audit/references/capability-checklist.md‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,10 +71,10 @@ classify it (using the classification scheme in `SKILL.md`) and route the cutove
7171
migration script, a body-to-column map (drift signature 11). Every port emits a per-object
7272
names artifact from the declaration, so a literal is a second source of truth even when it
7373
agrees with the naming strategy today. A typed ORM handle in its place is correct. **Check
74-
the artifact is emitted at all before scoring the literals: on TypeScript and the JVM the
75-
generator list in the config IS the complete list, so an existing project emits none and the
76-
un-wired generator is the finding FIRST** (C# and Python have a real default suite and get it
77-
by upgrading). **This entry is the physical-name INSTANCE of signature 11.** The rule that
74+
the artifact is emitted at all before scoring the literals: on every port the selection IS
75+
the complete list — the config's on TypeScript and the JVM, `--generators` on C# and Python —
76+
so an existing project emits none and the un-wired generator is the finding FIRST** (no port
77+
ships a default suite; ADR-0034 Amendment 2). **This entry is the physical-name INSTANCE of signature 11.** The rule that
7878
generates the rest — and the reason an enum member compared as a bare string is NOT one — is
7979
the Cross-cutting entry below.
8080
- **`@kind` = `view` / `materializedView`** — hunt hand-written SQL views where an authored

0 commit comments

Comments
 (0)