@metaobjectsdev/sdk 0.13.1 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/agent-context/README.md +1 -1
- package/agent-context/skills/metaobjects-audit/SKILL.md +262 -0
- package/agent-context/skills/metaobjects-audit/references/capability-checklist.md +189 -0
- package/agent-context/skills/metaobjects-audit/references/csharp.md +104 -0
- package/agent-context/skills/metaobjects-audit/references/java.md +106 -0
- package/agent-context/skills/metaobjects-audit/references/kotlin.md +107 -0
- package/agent-context/skills/metaobjects-audit/references/python.md +109 -0
- package/agent-context/skills/metaobjects-audit/references/typescript.md +110 -0
- package/agent-context/skills/metaobjects-codegen/references/typescript.md +0 -1
- package/agent-context/templates/always-on.md.mustache +3 -3
- package/dist/agent-context/types.d.ts +1 -1
- package/dist/agent-context/types.d.ts.map +1 -1
- package/dist/agent-context/types.js +1 -0
- package/dist/agent-context/types.js.map +1 -1
- package/dist/forge-types.d.ts.map +1 -1
- package/dist/forge-types.js +25 -1
- package/dist/forge-types.js.map +1 -1
- package/dist/memory.d.ts +7 -0
- package/dist/memory.d.ts.map +1 -1
- package/dist/memory.js +1 -0
- package/dist/memory.js.map +1 -1
- package/package.json +2 -2
- package/src/agent-context/types.ts +1 -0
- package/src/forge-types.ts +30 -0
- package/src/memory.ts +8 -0
package/README.md
CHANGED
|
@@ -26,7 +26,7 @@ import { AGENT_DOCS_BODY, withContentHash } from "@metaobjectsdev/sdk/agent-docs
|
|
|
26
26
|
## agent-context
|
|
27
27
|
|
|
28
28
|
`@metaobjectsdev/sdk/agent-context` assembles the downstream AI-assistant context
|
|
29
|
-
(the slim `.metaobjects/AGENTS.md`/`CLAUDE.md` + the
|
|
29
|
+
(the slim `.metaobjects/AGENTS.md`/`CLAUDE.md` + the six `metaobjects-*` Claude
|
|
30
30
|
skills with only the project's language reference fragments) from the repo-root
|
|
31
31
|
`agent-context/` source tree. `makeStack`/`detectStack` resolve the project's
|
|
32
32
|
server+client axes; `assemble({ contentRoot, stack })` emits the files. Design:
|
package/agent-context/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
This tree is the single source the assembler (`@metaobjectsdev/sdk`,
|
|
4
4
|
`src/agent-context/`) turns into the files scaffolded into a consumer project:
|
|
5
|
-
the slim always-on Markdown (`.metaobjects/AGENTS.md` + `CLAUDE.md`) and the
|
|
5
|
+
the slim always-on Markdown (`.metaobjects/AGENTS.md` + `CLAUDE.md`) and the six
|
|
6
6
|
`metaobjects-*` Claude skills (each a universal `SKILL.md` plus the
|
|
7
7
|
`references/<token>.md` fragments matching the project's resolved stack).
|
|
8
8
|
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: metaobjects-audit
|
|
3
|
+
description: Use when assessing how well a project has adopted MetaObjects — greenfield first-pass or deep double-check; produces a scored, prioritized adoption-audit report covering codegen, runtime, drift-gates, and prompts.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# MetaObjects adoption audit
|
|
7
|
+
|
|
8
|
+
**Thesis.** Typed metadata is the durable spine; generated code is the disposable
|
|
9
|
+
artifact. Hand-writing a layer the metadata could own creates a second source of
|
|
10
|
+
truth for one fact — it will drift. This audit hunts those second sources of truth
|
|
11
|
+
and proposes folding them into the spine.
|
|
12
|
+
|
|
13
|
+
**Boundary — read-only.** Deliverables: `.metaobjects/adoption-audit.json` (machine-readable
|
|
14
|
+
findings) + a rendered Markdown report. The audit **never edits code, never authors
|
|
15
|
+
metadata** — `metadata_sketch` per finding is a read-only proposal for human review.
|
|
16
|
+
Actual cutovers run through the existing skills mapped per finding tier (§ Bridge).
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Phase 0 — Triage (fast, mechanical)
|
|
21
|
+
|
|
22
|
+
- [ ] MetaObjects present? (`metaobjects/` dir, metadata sources, `@metaobjectsdev/*` /
|
|
23
|
+
`com.metaobjects:*` / `metaobjects` / `MetaObjects.*` deps).
|
|
24
|
+
- [ ] Count metadata source lines + all `@generated` / `DO NOT EDIT` files repo-wide.
|
|
25
|
+
- [ ] **Owned-generators check:** does the project own generators at `codegen/generators/*`
|
|
26
|
+
(scaffold-and-own via `meta init`), or still import the **deprecated** package export
|
|
27
|
+
(`@metaobjectsdev/codegen-ts/generators`)? Not owning is itself a finding.
|
|
28
|
+
- [ ] Classify: **Greenfield** (none/minimal) · **Partial** · **Deep** → choose path below.
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## Phase 1a — Greenfield path
|
|
33
|
+
|
|
34
|
+
- [ ] **Shape inventory.** Catalog modelable shapes: entities/tables, DTOs, validation
|
|
35
|
+
schemas, routes, UI lists/forms, prompt sites.
|
|
36
|
+
- [ ] **Pick wedge:** one real entity (single-column PK, standard CRUD) to model first.
|
|
37
|
+
- [ ] **From-zero roadmap:** `meta init` → model the wedge → `meta gen` the data layer →
|
|
38
|
+
author a projection view → expand to routes/UI → add prompt pillar where LLM calls exist.
|
|
39
|
+
Owning the generators from day 1 is part of the roadmap.
|
|
40
|
+
|
|
41
|
+
## Phase 1b — Partial / Deep path
|
|
42
|
+
|
|
43
|
+
**Census:** generated output line/file counts + metadata/owned-generator lines.
|
|
44
|
+
Compute **leverage ratio** = `generated_lines / (metadata_lines + generator_lines)`;
|
|
45
|
+
healthy = multi-× (example: ~4.7k spine → ~15.7k generated ≈ 3.3×).
|
|
46
|
+
|
|
47
|
+
**Coverage matrix:** per entity/projection/value — query helpers? view? routes? UI?
|
|
48
|
+
The gap between "modeled + query helpers" and "has view + route + UI" is the headline
|
|
49
|
+
lopsidedness.
|
|
50
|
+
|
|
51
|
+
**Surface review — 8 axes (independently runnable).**
|
|
52
|
+
Work the full `references/capability-checklist.md` on every axis. Check calibration
|
|
53
|
+
guards (§ Calibration) before raising a finding. **Verify, don't assume** — read the
|
|
54
|
+
code behind a grep hit; a "duplicate" validator's *divergence* is the finding.
|
|
55
|
+
|
|
56
|
+
- [ ] **A. Codegen candidates — API / server routes.** Catalog + classify every handler.
|
|
57
|
+
- [ ] **B. Codegen candidates — web / client.** Pages, data layer (hooks, central fetch),
|
|
58
|
+
grids/forms/filters vs `layout.dataGrid` / form generators / filter-allowlist.
|
|
59
|
+
- [ ] **C. Drift hotspot — validators, mappers, runtime models.** Hand validators / DTO-mappers /
|
|
60
|
+
dataclasses shadowing a generated shape. Diff field-by-field; the divergence is the bug.
|
|
61
|
+
- [ ] **D. Prompt pillar.** Every LLM prompt-construction site (see § Prompt anti-patterns).
|
|
62
|
+
- [ ] **E. Owned generators & scaffold-and-own** (see § Owned-codegen assessment).
|
|
63
|
+
- [ ] **F. Drift-gate adoption.** Is `meta verify` wired into CI / pre-commit? Which
|
|
64
|
+
subverbs (`--codegen` / `--templates` / `--db`)? Committed-codegen freshness gate?
|
|
65
|
+
Advisories heeded? Routine `--no-verify` bypass? Loader `ERR_*` / warnings addressed?
|
|
66
|
+
Parse the stable `code` field, not message text (ADR-0009).
|
|
67
|
+
- [ ] **G. Runtime-contract anti-patterns.** Module-global `db` vs context-as-parameter
|
|
68
|
+
(ADR-0008); wire-canonicalization in the query path vs native in-process return types
|
|
69
|
+
(ADR-0019); runtime reflection to resolve a type from FQN vs generated static imports /
|
|
70
|
+
FQN registry (ADR-0001 / 0017); process-global registry vs per-loader (ADR-0014); code
|
|
71
|
+
that **mutates the loaded metadata tree** (read-only after load); JVM/Kotlin missing
|
|
72
|
+
startup validator; writes not routed to the `@role: primary` source.
|
|
73
|
+
- [ ] **H. Authoring-correctness / ADR-conformance (deep).** Invented/unregistered
|
|
74
|
+
`@`-attrs or post-bootstrap registration (ADR-0023 — custom attrs belong in a registered
|
|
75
|
+
provider or `attr.properties`); retired source-v2 forms (`source.dbTable` / `@name` /
|
|
76
|
+
`@dbColumn` → use `source.rdb` + `@kind` + `@table` / `@column` + `@role`, ADR-0007/0018);
|
|
77
|
+
taxonomy impurity (entity over read-only primary source; read model that should be
|
|
78
|
+
`object.projection`; `value` carrying identity/source, ADR-0028); copy-pasted base-field
|
|
79
|
+
blocks instead of abstract + `extends`; `@`-prefixed YAML keys (ADR-0006); relative refs
|
|
80
|
+
in committed canonical JSON (ADR-0032); DB-type-as-logical-subtype (ADR-0013); per-port
|
|
81
|
+
migration engine where schema is Node-`meta`-owned (ADR-0015).
|
|
82
|
+
|
|
83
|
+
**Phase 4 — Synthesize** into the tiered roadmap and populate both artifacts.
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## Classification scheme (every surface; classify on codegen AND runtime)
|
|
88
|
+
|
|
89
|
+
| Class | Meaning | Action |
|
|
90
|
+
|---|---|---|
|
|
91
|
+
| **GENERATED** | Driven by metadata (regenerable). | Confirm it regenerates clean. |
|
|
92
|
+
| **OWNED-GENERATOR** | `codegen/generators/*` file the project owns. | Confirm clean regen; flag drift from reference template. |
|
|
93
|
+
| **CODEGEN CANDIDATE (high)** | Standard CRUD/list/form over a modeled or modelable entity. | Author the view + generate; parity-gate. |
|
|
94
|
+
| **CODEGEN CANDIDATE (partial)** | Generatable data layer, bespoke presentation. | Generate data layer; keep viz hand-written. |
|
|
95
|
+
| **DYNAMIC-RUNTIME CANDIDATE** | Behavior that could be metadata-driven at runtime. | Assess runtime-metadata feasibility. |
|
|
96
|
+
| **BESPOKE (keep)** | Genuine custom: aggregations, graph, SSE, auth, search, viz. | Leave hand-written — still import generated types. |
|
|
97
|
+
|
|
98
|
+
**Gold-standard exception.** A hand-written component that *derives* from generated metadata
|
|
99
|
+
cannot drift — flag as good. A "bespoke" component hardcoding a shape metadata knows is a
|
|
100
|
+
hidden candidate. **Stub trap:** demo-data routes have nothing to replace — classify
|
|
101
|
+
"candidate (future) — not DB-backed".
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## Drift signatures (highest-value; grep-then-verify)
|
|
106
|
+
|
|
107
|
+
Per finding: `file:line` → what → generated-equivalent exists? → recommendation.
|
|
108
|
+
|
|
109
|
+
1. **Hand validators shadowing a generated schema** — diff field-by-field; divergence is the bug.
|
|
110
|
+
2. **Field-by-field serialize / deserialize / DTO↔model / row mappers** — silently drops a field when metadata grows one.
|
|
111
|
+
3. **camelCase↔snake_case / body↔column maps** maintained beside a generated view that already renames.
|
|
112
|
+
4. **Drift-admitting comments** — grep: `"keep in sync with"` / `"mirrors the"` / `"matching the"`.
|
|
113
|
+
5. **Runtime schema patching** (`ALTER TABLE … ADD COLUMN IF NOT EXISTS`, `_ensure_schema()`) — N schema owners.
|
|
114
|
+
6. **N declarations of one shape** — same entity as Drizzle table + Zod schema + Pydantic model + hand dataclass; target is 1 + N generated.
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## Owned-codegen & scaffold-and-own assessment
|
|
119
|
+
|
|
120
|
+
- If config imports deprecated `@metaobjectsdev/codegen-ts/generators` instead of
|
|
121
|
+
owned `codegen/generators/*`, recommend the scaffold-and-own migration (`meta init`).
|
|
122
|
+
- Audit owned generators: (a) regenerate clean? (b) drifted from reference templates —
|
|
123
|
+
intentional (good) vs stale/accidental (missed upstream fix)? (c) hand-rolling a walk
|
|
124
|
+
that a declarative `scope` + `outputPattern` could replace? (d) bespoke shape better as
|
|
125
|
+
a `templateGenerator` than a forked generator?
|
|
126
|
+
- **Authoring ladder:** built-in fits → use it · close → **own + customize** (the default)
|
|
127
|
+
· new shape → **author a declarative template-spec / custom generator from the metadata**
|
|
128
|
+
· genuinely un-modelable → hand-write (still import the generated types).
|
|
129
|
+
- **Generator-gap check:** missing generators that block the biggest wins? Recommend per gap:
|
|
130
|
+
own + customize / author a template-spec / fix upstream / stopgap.
|
|
131
|
+
- **Verify the DB artifact, not just the types** — computed view columns may appear in the
|
|
132
|
+
contract but be dropped from the view DDL; the contract may lie.
|
|
133
|
+
- **Version skew:** check *actually-resolved* package versions, not declared; consuming a fix
|
|
134
|
+
requires a coordinated lockstep bump, not a source-file copy.
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## Prompt anti-patterns (hunt per site; classify: fully-modeled / partial / fully-inline)
|
|
139
|
+
|
|
140
|
+
- Inline prompt strings (triple-quoted / template-literal constants in service code).
|
|
141
|
+
- Untyped payloads (`str.format(**dict)` / f-strings / ad-hoc dicts) — payload should be an
|
|
142
|
+
`object.value` with `origin.*` (`passthrough` / `aggregate` / `collection`) fields.
|
|
143
|
+
- Silent-degradation hack (`try/except KeyError` or `?? ''` around formatting) — flag every instance.
|
|
144
|
+
- Hand-rolled output parsing (regex / XML / ad-hoc JSON) vs declared `template.output` +
|
|
145
|
+
generated `parse*` / `safeParse*` / `extract*` parser. **Java hand-writes the Jackson
|
|
146
|
+
one-liner — do NOT flag it** (§ Calibration).
|
|
147
|
+
- Engine-side formatting breaking byte-identical render (prompt-cache exact-prefix hits
|
|
148
|
+
depend on byte-stability).
|
|
149
|
+
- `template.toolcall` candidates: LLM tool schemas hand-defined per call vs modeled
|
|
150
|
+
`toolcall @toolName/@payloadRef`.
|
|
151
|
+
- `@responseRef` + AI-trace: hand-parsed responses with no typed response shape; note that
|
|
152
|
+
`voRequest` / `voResponse` jsonb columns must be authored `field.object` — the loader
|
|
153
|
+
must not mutate the tree; vendor SDK client + pricing are BYO (ADR-0024).
|
|
154
|
+
- No `meta verify --templates` gate; no declared `@maxChars` / `@maxTokens` budget.
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
## Semantic-constraint ratification (prevents over-modeling)
|
|
159
|
+
|
|
160
|
+
When folding hand validators into metadata, apply human judgment per constraint.
|
|
161
|
+
A constraint enters **shared metadata** only if it is a **true cross-language domain
|
|
162
|
+
invariant**; a one-consumer preference stays in a thin local refinement layer.
|
|
163
|
+
|
|
164
|
+
Cross-field rules **are** modelable (`comparison` / `atLeastOne` / `requiredWhen` /
|
|
165
|
+
`presentIff`); ratification decides *which* belong in shared metadata. Output a
|
|
166
|
+
**ratification table**: KEEP-IN-METADATA / LOCAL-REFINEMENT / DROP + rationale —
|
|
167
|
+
human-approved, never applied silently. Distinguish `required` from has-a-safe-default
|
|
168
|
+
(`@default` often fixes the over-requiring bug). A core attr ripples cross-port; for a
|
|
169
|
+
one-consumer need, read it codegen-locally.
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## Scoring & maturity model — three surfaces (no single global score; bands not decimals)
|
|
174
|
+
|
|
175
|
+
1. **Headline MATURITY TIER** — Greenfield → Partial → Deep → Exemplary; worst-of with
|
|
176
|
+
prerequisite gating (a missing pillar can't be averaged away); rendered with **the single
|
|
177
|
+
next unmet check** ("you're Partial; the next rung needs `verify` in CI").
|
|
178
|
+
2. **Per-pillar breakdown (never rolled into one number)** — `pillar | tier | top gap` over
|
|
179
|
+
codegen / runtime / drift-gate / prompts. This is the core deliverable.
|
|
180
|
+
3. **Binary CI drift gate** — prominent and separate: **"Is `meta verify` drift detection
|
|
181
|
+
wired into CI?"** It is binary because the risk is binary.
|
|
182
|
+
|
|
183
|
+
Coarse bands only (none / some / most / all). Worst-of within a pillar. On re-run, grade
|
|
184
|
+
the delta. Lead with gaps, not the grade.
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
## Report
|
|
189
|
+
|
|
190
|
+
**Two artifacts:** `.metaobjects/adoption-audit.json` + rendered Markdown.
|
|
191
|
+
|
|
192
|
+
**Markdown sections (lead with Scorecard):** 0. Scorecard (tier + pillar table + CI gate) ·
|
|
193
|
+
1. Triage + census · 2. Coverage matrix · 3. Per-surface classification tables · 4. Drift
|
|
194
|
+
findings (active bugs first) · 5. Owned-codegen + generator gaps · 6. Drift-gate adoption ·
|
|
195
|
+
7. Runtime-contract + authoring-correctness (axes G+H) · 8. Semantic-constraint ratification ·
|
|
196
|
+
9. Prompt-pillar assessment · 10. Prioritized roadmap: Tier 1 drift kill → Tier 2 existing
|
|
197
|
+
generators → Tier 3 new generators/projections → Tier 4 dynamic-runtime/prompts/cross-port.
|
|
198
|
+
Each roadmap item: LOC retired, prerequisite, **parity-gate before deleting hand-written code**.
|
|
199
|
+
|
|
200
|
+
**Each finding in `.metaobjects/adoption-audit.json`:**
|
|
201
|
+
|
|
202
|
+
| Field | Content |
|
|
203
|
+
|---|---|
|
|
204
|
+
| `id` | stable kebab id (e.g. `handwritten-crud-route`, `manual-zod-validator`) |
|
|
205
|
+
| `title` | "you hand-wrote X that metadata can generate / model" |
|
|
206
|
+
| `pillar` | `codegen` / `runtime` / `drift` / `prompt` |
|
|
207
|
+
| `surface` | `entity` / `route` / `validator` / `repository` / `dto` / `hooks` / `prompt` / `migration` |
|
|
208
|
+
| `capability` | the capability-checklist capability this maps to (e.g. `field.currency`, `relationship.@through`) |
|
|
209
|
+
| `locations[]` | exact `file:line` spans |
|
|
210
|
+
| `impact` | LOC eliminated + N call-sites + drift-risk (high/med/low) |
|
|
211
|
+
| `effort` | `trivial` / `small` / `medium` / `large` |
|
|
212
|
+
| `confidence` | bias to under-flagging (false-positive rate >15% is a kill criterion) |
|
|
213
|
+
| `metadata_sketch` | metadata you'd author to replace it — **read-only proposal only; never applied** |
|
|
214
|
+
| `next_command` | the exact command / skill that performs the cutover (see bridge below) |
|
|
215
|
+
| `parity_gate` | the specific check proving behavior-equivalence |
|
|
216
|
+
| `tier` | 1–4 |
|
|
217
|
+
|
|
218
|
+
Within each tier, sort by impact ÷ effort (quick wins first). Tier 1 leads.
|
|
219
|
+
|
|
220
|
+
### Audit → action bridge
|
|
221
|
+
|
|
222
|
+
The audit never edits code. Pattern: **dry-run → review the diff → apply**.
|
|
223
|
+
|
|
224
|
+
- Propose metadata → `metaobjects-authoring` + brainstorming flow (human reviews).
|
|
225
|
+
- Generate → `meta gen`; **`meta gen --dry-run`** is the review-the-diff step → skill:
|
|
226
|
+
`metaobjects-codegen`.
|
|
227
|
+
- Prove parity → **`meta verify --codegen`** is the drift gate → skill: `metaobjects-verify`.
|
|
228
|
+
- Routes / runtime / web → skill: `metaobjects-runtime-ui`.
|
|
229
|
+
- Prompts → skill: `metaobjects-prompts`.
|
|
230
|
+
- Cut over **one surface at a time, one commit each**.
|
|
231
|
+
- A separate guided-cutover skill (not this one) reads `adoption-audit.json` and walks
|
|
232
|
+
findings one tier/surface at a time with human approval at each step.
|
|
233
|
+
|
|
234
|
+
---
|
|
235
|
+
|
|
236
|
+
## Guardrails
|
|
237
|
+
|
|
238
|
+
- **Parity-gate every cutover** — prove behavior-equivalent before deleting hand-written code; generated schemas are often looser.
|
|
239
|
+
- **Verify, don't assume** — read the code behind a grep hit.
|
|
240
|
+
- **Verify the DB artifact, not just the types** — the contract may claim a column the view DDL dropped.
|
|
241
|
+
- **Don't let one bespoke action block generating the entity** — generate CRUD; mount the custom action alongside.
|
|
242
|
+
- **Consumption ≠ a dist copy across versions** — bump + rebuild lockstep and install.
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
246
|
+
## Calibration — port gaps & non-defects (do NOT flag these as adopter fault)
|
|
247
|
+
|
|
248
|
+
- **Filter-operator route codegen** is full only in **TS**; Java/Kotlin/C#/Python generate
|
|
249
|
+
pagination/sort/`withCount` but defer filter ops — do not flag hand-added filter handling.
|
|
250
|
+
- **Output-parser codegen** ships TS/C#/Python/Kotlin; **Java hand-writes the Jackson parse** — not a defect.
|
|
251
|
+
- **Python** still hand-wires the FastAPI router + repository impl around a generated
|
|
252
|
+
`APIRouter`; relationship / non-`table` source-kind / `field.object flattened` codegen is partial.
|
|
253
|
+
- **C#** has no ObjectManager runtime tier (EF Core is the runtime) — hand services over the generated `DbContext` are expected.
|
|
254
|
+
- **Cut subtypes** — `field.byte` / `field.short` / `field.class` are removed; never recommend them.
|
|
255
|
+
- **TS/web-only** — `view.*` widget subtypes exist only for TS/web consumers; only `view.base` / `view.currency` are cross-port-gated.
|
|
256
|
+
- **Planned, not shipped** — `api.*` / `operation.*` / `binding.*` (FR-024) and MCP exposure of declared prompts/tools are not yet in the registry; their absence is not an adopter defect.
|
|
257
|
+
- **Cross-port version skew is by design** — TS/C#/Python `0.x` vs Java/Kotlin `7.x` Maven is correct; never flag it. Flag only *intra-port* drift (mixed versions within one port, or a runtime package in `devDependencies`).
|
|
258
|
+
- **Stale upstream prose** — "hand-write the Spring controller" (Java/Kotlin) is out of date; trust `meta gen --list`, not stale prose.
|
|
259
|
+
|
|
260
|
+
---
|
|
261
|
+
|
|
262
|
+
For this project's port specifics and the exhaustive capability checklist, read every `references/*.md` in this skill's directory.
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
# MetaObjects capability checklist (registry-grounded)
|
|
2
|
+
|
|
3
|
+
The **exhaustive** list of every modelable MetaObjects capability, each with its one-line
|
|
4
|
+
audit hunt: *"find a hand-written shape the metadata already describes."* Every
|
|
5
|
+
`type.subtype` and every `@`-prefixed attribute named here is verbatim from the cross-port vocabulary in
|
|
6
|
+
`fixtures/registry-conformance/expected-registry.json` (the
|
|
7
|
+
`agent-context-capability-grounding.test.ts` guard fails the build if a line claims a token
|
|
8
|
+
the registry lacks). Work this checklist on every axis so coverage is exhaustive; respect
|
|
9
|
+
the **inline calibration flags** so a per-port gap is never scored as the adopter's fault.
|
|
10
|
+
|
|
11
|
+
How to use a line: the capability is what the metamodel can express; the hunt is the
|
|
12
|
+
hand-written second-source-of-truth that should have been derived from it. Found one →
|
|
13
|
+
classify it (using the classification scheme in `SKILL.md`) and route the cutover to the right sibling skill.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Object — `object.*`
|
|
18
|
+
|
|
19
|
+
- **`object.entity`** (`@discriminator` / `@discriminatorValue` for STI/TPH) — hunt
|
|
20
|
+
hand-written entity classes, DTOs, and repositories whose field list duplicates a modeled
|
|
21
|
+
entity; hand-rolled single-table-inheritance / type-discriminator switches that
|
|
22
|
+
`@discriminator`+`@discriminatorValue` already model.
|
|
23
|
+
- **`object.value`** — hunt hand-authored request / command / payload value objects (no
|
|
24
|
+
identity, no source) that restate a modeled `value` shape.
|
|
25
|
+
- **`object.projection`** — hunt hand-written read-model DTOs and the SQL views behind them
|
|
26
|
+
that a derived read-only projection (extends + origin-derived fields) already describes.
|
|
27
|
+
- **`object.base`** — abstract base; hunt copy-pasted shared field blocks that should be an
|
|
28
|
+
abstract base + `extends` (see cross-cutting).
|
|
29
|
+
|
|
30
|
+
## Field — `field.*`
|
|
31
|
+
|
|
32
|
+
- **`field.string`** (`@maxLength`) — hunt hand-validated string-length checks the field
|
|
33
|
+
models.
|
|
34
|
+
- **`field.int` / `field.long` / `field.double` / `field.float`** — hunt ad-hoc numeric
|
|
35
|
+
columns / parsing the subtype already types.
|
|
36
|
+
- **`field.decimal`** (`@precision` / `@scale`) — hunt money or quantity stored as `float`/
|
|
37
|
+
`double` (lossy); the decimal subtype carries exact precision/scale.
|
|
38
|
+
- **`field.boolean`** — hunt int-or-string flags standing in for a boolean.
|
|
39
|
+
- **`field.currency`** (`@currency`, + `view.currency` `@locale`) — hunt money as float,
|
|
40
|
+
hand `*100` / `/100` minor-unit math, or server-side `Intl.NumberFormat`; storage is
|
|
41
|
+
integer minor units, formatting is client-side.
|
|
42
|
+
- **`field.date` / `field.time` / `field.timestamp`** (`@autoSet`) — hunt hand-stamped
|
|
43
|
+
`createdAt` / `updatedAt` assignments and ad-hoc temporal parsing; `@autoSet` stamps them.
|
|
44
|
+
- **`field.enum`** (`@values`) — hunt hand-written TS unions, language `enum`s, or DB
|
|
45
|
+
`CHECK ... IN (...)` lists that restate a modeled enum's members.
|
|
46
|
+
- **`field.uuid`** — hunt UUIDs typed as bare strings / hand-validated.
|
|
47
|
+
- **`field.object`** (`@objectRef`, `@storage`) — hunt hand-flattened owned columns or
|
|
48
|
+
hand-rolled jsonb (de)serialization the `@storage` mode (`flattened`/`jsonb`/`subdocument`)
|
|
49
|
+
already drives.
|
|
50
|
+
- **`field.map`** (`@valueType`) — hunt ad-hoc open-keyed key/value bags stuffed into a jsonb
|
|
51
|
+
column by hand.
|
|
52
|
+
- **Common field attrs** — `@column` (hand column-name mapping), `@default` (hand default
|
|
53
|
+
assignment), `@required` (hand presence checks), `@unique` (hand uniqueness), `@readOnly`
|
|
54
|
+
(hand write-guards), `@filterable` / `@sortable` (hand filter/sort allowlists),
|
|
55
|
+
`@dbColumnType` (hand native-type override), `@example` / `@instruction` (hand prompt
|
|
56
|
+
hints), `@xmlText` (hand XML-text mapping). Indexed-without-filter suppression is the
|
|
57
|
+
`db.indexed` attr (cite without the `@` sigil — it is a dotted attr name).
|
|
58
|
+
- **CALIBRATION — cut subtypes:** `field.byte`, `field.short`, `field.class` are
|
|
59
|
+
non-functional removed stubs. **Do NOT audit for them and never recommend them.**
|
|
60
|
+
|
|
61
|
+
## Source — `source.rdb`
|
|
62
|
+
|
|
63
|
+
- **`source.rdb`** (`@table`, `@schema`) — hunt hard-coded physical table/schema names that
|
|
64
|
+
diverge from the default naming the source models.
|
|
65
|
+
- **`@kind` = `view` / `materializedView`** — hunt hand-written SQL views where an authored
|
|
66
|
+
projection source (read-only `@kind`) belongs.
|
|
67
|
+
- **`@kind` = `storedProc` / `tableFunction`** (`@parameterRef`) — hunt hand-called procs /
|
|
68
|
+
table functions that a modeled callable source with `@parameterRef` already describes.
|
|
69
|
+
- **`@role` = `primary`** (multi-source write-through) — hunt manual CQRS / write-through
|
|
70
|
+
wiring; exactly one `primary` source per object models it.
|
|
71
|
+
- **`source.base`** — abstract source base (no audit target of its own).
|
|
72
|
+
|
|
73
|
+
## Relationship — `relationship.*`
|
|
74
|
+
|
|
75
|
+
- **1:N / N:1** (`@cardinality`, `@objectRef`) — hunt hand-written FK joins and type-unsafe
|
|
76
|
+
finders the cardinality + target reference already model.
|
|
77
|
+
- **M:N** (`@through`) — hunt hand junction-table queries where `@through` + the junction's
|
|
78
|
+
two `identity.reference` children generate the traversal.
|
|
79
|
+
- **Self-join** (`@symmetric`, `@sourceRefField`) — hunt hand-coded self-join / graph queries
|
|
80
|
+
that an undirected (`@symmetric`) or directed (`@sourceRefField`) self-relationship models.
|
|
81
|
+
- **Referential actions** (`@onDelete`, `@onUpdate`) — hunt app-code cascade/null-out logic
|
|
82
|
+
the relationship's referential actions express.
|
|
83
|
+
- **`relationship.association` / `relationship.aggregation` / `relationship.composition`** —
|
|
84
|
+
hunt ownership/lifecycle semantics (delete-with-parent, shared vs owned) coded by hand
|
|
85
|
+
instead of by the relationship subtype.
|
|
86
|
+
- **`relationship.base`** — abstract base.
|
|
87
|
+
|
|
88
|
+
## Identity — `identity.*`
|
|
89
|
+
|
|
90
|
+
- **`identity.primary`** (`@generation`) — hunt hand-assigned primary keys / ID generation
|
|
91
|
+
the primary identity's `@generation` strategy models.
|
|
92
|
+
- **`identity.secondary`** (`@unique`, `@where`, `@expr`) — hunt raw-SQL partial or functional
|
|
93
|
+
unique indexes a secondary identity with `@where` / `@expr` describes.
|
|
94
|
+
- **`identity.reference`** (`@references`, `@enforce`) — hunt hand-written FK constraints /
|
|
95
|
+
reference enforcement the reference identity already declares.
|
|
96
|
+
|
|
97
|
+
## Origin — `origin.*` (projection-field derivation)
|
|
98
|
+
|
|
99
|
+
- **`origin.aggregate`** (`@agg`, `@of`, `@via`) — hunt hand `COUNT` / `SUM` / `AVG`
|
|
100
|
+
subqueries or in-app rollups a derived aggregate field models.
|
|
101
|
+
- **`origin.passthrough`** (`@from`, `@via`) — hunt denormalized-by-hand copied fields that a
|
|
102
|
+
passthrough origin pulls across a relationship.
|
|
103
|
+
- **`origin.collection`** (`@via`) — hunt hand-assembled child-collection loading a collection
|
|
104
|
+
origin derives.
|
|
105
|
+
- **`origin.base`** — abstract base.
|
|
106
|
+
|
|
107
|
+
## Validator — `validator.*`
|
|
108
|
+
|
|
109
|
+
- **`validator.required` / `validator.length` / `validator.numeric` / `validator.array` /
|
|
110
|
+
`validator.regex`** — hunt hand field-level validation (presence, length, numeric range,
|
|
111
|
+
array bounds, `@pattern` regex) the validator subtypes model.
|
|
112
|
+
- **Cross-field validators** — `validator.comparison` (`@left`/`@op`/`@right`, e.g.
|
|
113
|
+
"end ≥ start"), `validator.atLeastOne` (one-of-N present), `validator.requiredWhen`
|
|
114
|
+
(conditional-required), `validator.presentIff` (mutual presence). Hunt these as hand-coded
|
|
115
|
+
multi-field rules — they ARE modelable (see the Semantic-constraint ratification section in
|
|
116
|
+
`SKILL.md` to decide what belongs in shared metadata vs port-local).
|
|
117
|
+
- **`validator.base`** — abstract base.
|
|
118
|
+
|
|
119
|
+
## View / Layout — `view.*`, `layout.*`
|
|
120
|
+
|
|
121
|
+
- **`view.currency`** (`@locale`) — hunt hand-passed currency locale / `Intl.NumberFormat`
|
|
122
|
+
options the currency view models. **Cross-port-gated** (with `view.base`).
|
|
123
|
+
- **`layout.dataGrid`** (`@columns`, `@defaultSortField`, `@defaultSortOrder`, `@pageSize`) —
|
|
124
|
+
hunt hand-written grid column definitions + data hooks a data-grid layout generates.
|
|
125
|
+
- **CALIBRATION — TS/web-only:** the `view.*` widget subtypes exist only for TS/web consumers
|
|
126
|
+
and are NOT in the cross-port registry — `view.text`, `view.textarea`, `view.date`,
|
|
127
|
+
`view.month`, `view.hotlink`, `view.dropdown`, `view.radio`, `view.checkbox`, `view.number`,
|
|
128
|
+
`view.password`, `view.hidden`, `view.web`. **Audit these only for TS adopters.** Only
|
|
129
|
+
`view.base` / `view.currency` are cross-port-gated.
|
|
130
|
+
|
|
131
|
+
## Template — `template.*` (prompt pillar)
|
|
132
|
+
|
|
133
|
+
- **`template.prompt`** (`@payloadRef`, `@textRef`, `@responseRef`, `@requiredSlots`,
|
|
134
|
+
`@maxTokens`, `@maxChars`, `@format`, `@model`, `@promptStyle`) — hunt prompt strings
|
|
135
|
+
assembled inline in services, payloads built ad-hoc, output parsing without a typed
|
|
136
|
+
`@responseRef`, or token/char budgets enforced by hand.
|
|
137
|
+
- **`template.output`** (`@kind` = `document` | `email`; `@subjectRef`, `@htmlBodyRef`,
|
|
138
|
+
`@textBodyRef`) — hunt hand-built document/email rendering + hand-written
|
|
139
|
+
parse-on-receipt the output template + generated render helper/parser cover.
|
|
140
|
+
- **`template.toolcall`** (`@toolName`, `@payloadRef`) — hunt hand-declared LLM tool schemas
|
|
141
|
+
a modeled tool call describes.
|
|
142
|
+
- **`template.base`** — abstract base.
|
|
143
|
+
|
|
144
|
+
## Attr — `attr.*`
|
|
145
|
+
|
|
146
|
+
- **`attr.properties`** — the sanctioned author key/value escape hatch; hunt ad-hoc metadata
|
|
147
|
+
stuffed into code comments / side-maps that could instead ride the properties bag.
|
|
148
|
+
- **`attr.filter`** — hunt hand-maintained preset filter definitions a modeled filter attr
|
|
149
|
+
holds.
|
|
150
|
+
- **`attr.class`** — binding facet (`field.class` binding); hunt hand-wired type-binding
|
|
151
|
+
facets. (`attr.base`, `attr.string`, `attr.int`, `attr.long`, `attr.double`, `attr.boolean`
|
|
152
|
+
are the value-type primitives behind typed attrs — not direct audit targets.)
|
|
153
|
+
|
|
154
|
+
## Common documentation attrs (any node)
|
|
155
|
+
|
|
156
|
+
- `@description`, `@title`, `@summary`, `@notes`, `@deprecated`, `@replacedBy`, `@seeAlso`,
|
|
157
|
+
`@aliases` — hunt weak/absent generated docs and deprecation tracked only in code comments;
|
|
158
|
+
these doc attrs flow into JSDoc / XML-doc / Postgres `COMMENT` / Mermaid doc-gen, and
|
|
159
|
+
`@deprecated` / `@replacedBy` model lifecycle the codebase tracks by hand. (`@notes` is the
|
|
160
|
+
internal-only rationale slot — never emitted to user-facing doc-gen.)
|
|
161
|
+
|
|
162
|
+
## Cross-cutting
|
|
163
|
+
|
|
164
|
+
- **`extends`** (any depth, cross-package `::`) — hunt copy-pasted base-entity field blocks
|
|
165
|
+
that should be an abstract base inherited via `extends` (the inheritance mechanism;
|
|
166
|
+
`origin.*` never inherits).
|
|
167
|
+
- **Filter + sort + pagination REST layer** — hunt hand-written query parsing, `LIMIT`/
|
|
168
|
+
`OFFSET` pagination, total-count queries, and filter/sort handling the generated CRUD layer
|
|
169
|
+
(8 filter operators + sort + `?limit=N&offset=N` + count) already provides.
|
|
170
|
+
- **CALIBRATION — per-port codegen gaps:** filter-operator route codegen is full only in
|
|
171
|
+
**TS**; Java / Kotlin / C# / Python generate pagination/sort/count but **defer filter
|
|
172
|
+
ops** — do NOT flag hand-added filter handling there. Output-parser codegen ships
|
|
173
|
+
TS/C#/Python/Kotlin; **Java hand-writes** the Jackson parse (acceptable). **Python**
|
|
174
|
+
still hand-wires the FastAPI router around a generated `APIRouter` (relationship /
|
|
175
|
+
non-`table` source-kind / flattened-object codegen is partial). **C#** has no
|
|
176
|
+
ObjectManager runtime tier (EF Core *is* the runtime) — hand services over the generated
|
|
177
|
+
`DbContext` are expected.
|
|
178
|
+
- **Single-source config** — `apiPrefix` (URL prefix wired into routes + hooks) and
|
|
179
|
+
`columnNamingStrategy` (snake_case / literal / kebab-case) and per-target output dirs:
|
|
180
|
+
hunt these values hard-coded in multiple places instead of resolved from config.
|
|
181
|
+
- **CALIBRATION — planned, not yet shipped:** the declared-API surface (`api.base`,
|
|
182
|
+
`api.operational`, `operation.query`, `operation.command`, `binding.rest`) and MCP exposure
|
|
183
|
+
of declared prompts/tools are **not yet in the registry** — their absence is not an adopter
|
|
184
|
+
defect; do NOT audit for them.
|
|
185
|
+
- **CALIBRATION — cross-port version skew is by design:** TS/C#/Python on the `0.x` line vs
|
|
186
|
+
Java/Kotlin on the `7.x` Maven line is correct — **never flag it.** Flag only *intra-port*
|
|
187
|
+
version drift (mixed package versions within one port, or a runtime package in
|
|
188
|
+
`devDependencies`). Trust the port docs + `meta gen --list`, not stale upstream prose
|
|
189
|
+
(e.g. the out-of-date "hand-write the Spring controller" note — controllers ARE generated).
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# C# port — audit reference
|
|
2
|
+
|
|
3
|
+
The C# port targets .NET consumers (EF Core + ASP.NET Minimal API). Codegen runs
|
|
4
|
+
through the `dotnet meta` .NET tool (`MetaObjects.Cli`). Schema migration and
|
|
5
|
+
live-DB drift are **Node-`meta`-only** (ADR-0015) — `dotnet meta` has no `migrate`
|
|
6
|
+
subcommand and `dotnet meta verify --db` is rejected with exit 2.
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## Finding generated files
|
|
11
|
+
|
|
12
|
+
Generated files are named `<Entity>.g.cs` and carry an `@generated` guard comment:
|
|
13
|
+
|
|
14
|
+
```csharp
|
|
15
|
+
// @generated by MetaObjects.Codegen
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
The metadata source directory is the first positional arg (`<metadataDir>`); `--out`
|
|
19
|
+
is required (errors if absent, no default). The runner overwrites only files bearing
|
|
20
|
+
this header; it refuses to touch files without it. Locate the output directory from
|
|
21
|
+
how the team invokes `dotnet meta gen` (or a CI script) — the arg is explicit, there
|
|
22
|
+
is no config file equivalent on the C# side.
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Run codegen + verify
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
dotnet meta gen metaobjects --out Generated --namespace Acme.Generated
|
|
30
|
+
|
|
31
|
+
dotnet meta gen --list # list all registered generators
|
|
32
|
+
dotnet meta gen --generators entity,db-context,routes # select a subset
|
|
33
|
+
|
|
34
|
+
dotnet meta verify --codegen # regenerate to temp, diff vs committed output
|
|
35
|
+
dotnet meta verify --templates # check {{field}} refs vs payload VO (bare default)
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Schema migration + live-DB drift run through the **Node `meta` CLI** regardless of
|
|
39
|
+
server language — see the migration reference. `dotnet meta verify --db` is
|
|
40
|
+
rejected (exit 2).
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Drift signatures (what to grep for)
|
|
45
|
+
|
|
46
|
+
| Signature | What it means |
|
|
47
|
+
|---|---|
|
|
48
|
+
| `[Column(...)]` / `[Table(...)]` in hand-written `.cs` (not `.g.cs`) | hand-authored EF Core entity — candidate to generate |
|
|
49
|
+
| `DbSet<T>` in a hand-written `DbContext` subclass | generated `AppDbContext` (`db-context` generator) should own this |
|
|
50
|
+
| `HasConversion<string>()` by hand | the `entity` generator emits this for `field.enum`; duplicate if entity is modeled |
|
|
51
|
+
| `FromSqlInterpolated(` outside `.g.cs` | stored-proc call — candidate for the `callable` generator |
|
|
52
|
+
| `// keep in sync with` / `// mirrors the` | second-source-of-truth comment — always a finding |
|
|
53
|
+
| `HasPrecision(` hand-coded | `field.decimal` with `@precision`/`@scale` drives this from the `entity` generator |
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## Owned generators
|
|
58
|
+
|
|
59
|
+
C# does not scaffold-and-own generators — the generators are provided by
|
|
60
|
+
`MetaObjects.Codegen` and are not meant to be copied into the consumer project.
|
|
61
|
+
There is no analog to the TS `codegen/generators/*.ts` pattern here. Generator
|
|
62
|
+
selection uses stable names via `dotnet meta gen --generators <names>`.
|
|
63
|
+
|
|
64
|
+
To re-scaffold the agent-context into a C# project, use the Node `meta` CLI (the
|
|
65
|
+
single agent-docs assembler per ADR-0033):
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
npx meta agent-docs --server csharp [--out <dir>]
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
(`dotnet meta agent-docs` is a non-executing stub — it prints this redirect and exits 1.)
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## Version-skew check
|
|
76
|
+
|
|
77
|
+
The resolved NuGet package version is what actually ran codegen — check the lock file
|
|
78
|
+
or the restore log, not the `.csproj` range:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
dotnet list package --include-transitive | grep -i MetaObjects
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
`MetaObjects` (loader), `MetaObjects.Codegen`, `MetaObjects.Render`, and
|
|
85
|
+
`MetaObjects.Cli` all publish in lockstep on the C# `0.x` line. A mixed resolved
|
|
86
|
+
version across these packages is an intra-port skew finding.
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## Calibration gaps (do NOT flag these)
|
|
91
|
+
|
|
92
|
+
- **No ObjectManager runtime tier.** C# has no `ObjectManager` equivalent — EF Core
|
|
93
|
+
(the generated `AppDbContext` + generated entity classes) **is** the runtime persistence
|
|
94
|
+
layer. Hand-written service classes over the generated `AppDbContext` are the expected
|
|
95
|
+
pattern, not a defect.
|
|
96
|
+
- **No C# migrate command.** Schema migration is Node-`meta`-owned for every port
|
|
97
|
+
(ADR-0015). `dotnet meta` has no migrate subcommand; `meta migrate` is correct.
|
|
98
|
+
- **Filter-operator route codegen deferred.** The generated `<Entity>Routes.cs` (Minimal
|
|
99
|
+
API) supports `?sort`, `?limit`/`?offset`, and `?withCount=1` envelope, but filter
|
|
100
|
+
operators (`?filter[field][op]=value`) are not yet generated. Do NOT flag hand-added
|
|
101
|
+
C# filter handling as an adopter defect.
|
|
102
|
+
- **Output-parser codegen ships in C#.** `output-parser` / `extractor` / `render-helper`
|
|
103
|
+
generators are available (`dotnet meta gen --generators output-parser`). Absence of
|
|
104
|
+
wired output parsers where `template.output` nodes exist IS a finding.
|