Skip to content

Commit 99d173b

Browse files
dmealingclaude
andcommitted
docs(audit-skill): score names ADOPTION, not just emission, and make a deferral carry its number
Signature 11 already told an auditor to find physical-name literals and to treat an un-wired names generator as the first finding and the first remedy. What it did not say is what to do once the generator IS wired — and that is the half that goes wrong. Measured on an adopter this round: its audit found the literals, ran the generator to prove the artifact emits correctly, recorded the remedy, and adopted it at 0 of 53 sites (37 table + 16 column). Emission is the cheap half and it is the half that gets done. Wiring the generator moves the scorecard while every query in the codebase still uses the second spelling, so an audit reporting only "artifact emitted" makes the estate read as upgraded when nothing a reader of the code experiences has changed. The signature now demands two numbers — emitted?, and the adoption ratio as <adopted>/<total> sites — and states that emitting the artifact while importing it nowhere scores WORSE than not having started, because the repo now carries a third spelling claiming to be the source of truth. The second half is about the deferral. Postponing the names tier was a defensible call there: a new generated tier, a new dev-loop step, a new `verify --codegen` gate and edits to 4 service and 6 test modules that could only be validated against a live database, against a branch that deliberately changed nothing in the running application. That belongs in the report. But it was recorded as intent with no measurement attached, and intent with no number reads as a nice-to-have on the next pass and quietly becomes permanent. A deferral must now carry the site count, the exact command that emits the artifact, and the modules that would change — and be re-raised by every later audit until the ratio moves. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NTcEKXTQMYt84fAjuw5A2M
1 parent 309ed33 commit 99d173b

1 file changed

Lines changed: 4 additions & 0 deletions

File tree

  • agent-context/skills/metaobjects-audit

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,10 @@ Per finding: `file:line` → what → generated-equivalent exists? → recommend
343343
10. **N declarations of one FIELD across objects (same-name-field census)** — the field-level sibling of signature 6. Census field names across `object.*` nodes (`grep -rn 'name: <field>'` the metadata dir); a name recurring in ≥2 objects where a canonical owner exists — one whose name the field embeds (`<owner><Field>`: `wizardId``Wizard.id`, `orderTotal``Order.total`) or whose type+constraints it matches — is provenance loss → `extends: Owner.field` (dotted child targets, ADR-0029). **VERIFY by diffing the copies' attrs: a `@maxLength` / `@required` / validator divergence across them is drift already shipping — cite it.** Evidence multiplier: `extends` already used elsewhere in the repo raises confidence. Do NOT flag: generic names on unrelated concepts (`id` / `name` / `status` with no owner-embedding name and no matching constraints); required per-node attrs a loader forces (e.g. `payloadRef` / `format` on sibling `template.prompt` nodes — a product constraint, not a copy).
344344
11. **A physical table / column / schema name spelled as a literal outside its metadata declaration** — in a hand-written repository, raw SQL, a migration script, a log line, or a hand-maintained body-to-column map. Every port emits a per-object names artifact (`<Entity>Names` / `<entity_snake>_names.py`) from the declaration, so a literal is a second spelling of the same fact; and because the physical column is free-form, deriving it from the field name is a guess that fails silently. **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. **Do NOT flag:** a typed ORM handle in its place (a Drizzle column object, an Exposed `Column`, an EF property — replacing one with a string is a regression); a physical name inside a `source.rdb` hand-written SQL body (a metadata document cannot import a constant, which is why that body is fingerprinted); a flattened value-object composite column (it belongs to no single field of either object); a write-through entity's replica view name (the artifact holds the PRIMARY source's); a relationship-synthesized foreign-key column (derived, never declared). A hand-written repository that imports `<Entity>Names` is the gold standard — call it out as good.
345345

346+
**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.
347+
348+
**A deferral must carry its measurement forward.** "Wire the names tier" is a real thing to postpone — on the observed estate it meant a new generated tier, a new dev-loop step, a new `verify --codegen` gate and edits to 4 service and 6 test modules that could only be validated against a live database, and the branch in hand deliberately changed nothing in the running application. That is a legitimate decision and belongs in the report. But record it with **the site count, the exact command that emits the artifact, and the modules that would change** — never as intent alone — and **re-raise it in every later audit until the ratio moves**. A deferral with no number attached reads as a nice-to-have on the next reading and silently becomes permanent; the one carrying `0/53` does not.
349+
346350
---
347351

348352
## Owned-codegen & scaffold-and-own assessment

0 commit comments

Comments
 (0)