Repository navigation
feat(metadata): add one physical naming setting read by every port - #441
Merged
Merged
Conversation
…the rc.3 application-build test found An agent following the shipped 1.1.0 skills and the migration guide got wrong output or broken builds in four places. Each gets its root-cause fix: - Python and C# declare the run's column naming (and Python its template directory) in the generator list: `columnNaming` / `templates` in metaobjects.config.yaml, `ColumnNaming` on a C# GeneratorList. gen and verify --codegen read them, a contradicting flag is refused, and verify names a column-naming mismatch instead of advising a regeneration. - The Java and Kotlin skill pom examples list the whole REST tier, and the Maven plugin refuses a list whose generators' requires are not declared. Every requires closure and both examples are compiled over the fitness corpus in tests; that found the Kotlin extractor's dependency on the parser tier. - Every docs example gives each port its own docs directory, with the reason. - Every removal message and skill names the migration guide by its full public URL. Also: C# --list prints each generator's Generators.cs expression and options; the C# staleness notice ignores build metadata; meta verify --docs prints once; Python verify --templates reads the config; the skills stop asserting metaobjects/ is where metadata lives; prerelease:publish reads "released" from npm and the tags, refuses to skip an unpublished CHANGELOG section, pages the iteration counter and restores on SIGTERM; prerelease-link.sh handles nested per-port projects and the .NET tool manifest.
…a directory The removal messages now name the migration guide by its GitHub URL, whose repository segment the hardcoded-directory guard read as the default metadata directory. The guard skips that one form, and a pinned case keeps the exemption that narrow.
…rators are missing
… sits, and its plugin dependencies The block-buffer flushed a <plugin> at its first <configuration> or <executions>, so a <version> declared after them was never repinned, and a plugin's own <dependencies> were not read at all. Each <dependency> or <plugin> is now read whole, and only its own <version> moves.
…p, one npm fetch and shared helpers simplify-qwen pass over the branch. Behaviour unchanged: C# CLI 297 and Codegen 844 tests, maven-plugin 217, Python codegen 892, and the prerelease-link and prerelease-version suites pass on it. Its foreign-roots cache was dropped: project_find runs in subshells, so the array never persisted.
…aced Python roots
…ference alone Walking every pom reached modules that reference the parent's property; the awk rewrote that reference to a literal, and unlink never restored it.
…ts conformance corpus The naming block of .metaobjects/config.json names the column and table rules; metadata overrides win, both rules default to snake_case in every port, and every former per-port source refuses. The two corpora that pin a committed literal-column schema declare it.
…n guide and the skills (ADR-0058) Column and table names the metadata does not give come from naming in .metaobjects/config.json, carried by the loaded root: meta migrate, codegen, the ObjectManager and verify all read it there. columnNamingStrategy in metaobjects.config.ts, on ObjectManager and on agentDocsFile() is refused with the setting and the guide; meta migrate and meta verify refuse it too instead of falling back to the default. The engine options that carried the rule read the model instead. The TypeScript harness gives each corpus its naming from the corpus's own .metaobjects/config.json, and the physical-names corpus runs through the sdk config reader and the shared resolvers.
NeutralConfig parses naming from .metaobjects/config.json; the project-aware load sets it on the root, and every resolver (codegen, EF mapping, names, verify, the table rule in MetaSource.PhysicalName) reads it there. --column-naming is refused on gen and verify; the unreleased GeneratorList.ColumnNaming is removed and init scaffolds the plain list again. The default is snake_case. The physical-names corpus runs through NeutralConfig and CSharpNaming. The persistence corpus's naming file moves above canonical/, where directory loaders no longer read it as metadata.
…aming their own DDL uses They provision their tables in snake_case by hand, while the api-contract corpus declares literal columns for the reference servers; each lane now sets the root to the rule its DDL was written in, as the report lanes do. The whole integration suite passes on it.
The neutral config reader parses naming; the project-aware load sets it on the root, and codegen (the *_names.py generator included), the ObjectManager, verify and the table rule in MetaSource.physical_name read it there. A model loaded outside the project gets it with attach_naming(root, project_dir). --column-naming, ObjectManager(column_naming=) and the release candidates' columnNaming key are refused; the default is snake_case. The physical-names corpus runs through the neutral config reader and the shared resolvers.
…DR-0058) NeutralConfig parses naming; the Maven plugin's load and the Spring loader (metaobjects.physical-naming-config) set it on the root, and ColumnNaming.resolve and MetaSource.getPhysicalName read it there, so Java codegen, Kotlin codegen, the names generators, OMDB and the mustache helpers resolve the same names. The columnNaming generator arg and SimpleMappingHandlerDB.setColumnNaming are refused; the default is snake_case. The mustache dbColumn/dbTable helpers, which derived names on their own, now use the shared resolvers. The physical-names corpus runs through NeutralConfig.
…config, not the removed option
The registry prose for @column and @table still said the default name came "via columnNamingStrategy", a setting 1.1.0 removes. They now name the naming.columns / naming.tables rule in .metaobjects/config.json (ADR-0058). Regenerated the embedded TS definition, expected-registry.json, the metamodel docs fixture and the reference pages. Prose only, so metamodelVersion does not move. The codegen-ts README's naming paragraph also pointed at the removed setting and at @dbColumn, which is @column.
verify --codegen in C# and Python reported a naming mismatch only when another column rule reproduced the committed output. Output committed under the other naming.tables rule fell through to "regenerate", which binds the code to a table the database does not have. Both ports now try every other combination: another column rule alone, then another table rule alone, then both together, and print the same message naming the full naming block that reproduces the committed tree. No new setting or flag; the table rule reaches codegen through the loaded root, so each probe sets the candidate there and restores it.
…ndidate The probe re-pointed the already-generated root at each candidate naming. A loaded tree caches the table name it resolved (MetaObject.DbTable), so with only the entity generator selected, whose [Table(...)] carries that name, a table-only mismatch still read as drift and verify advised a regenerate. Each candidate now regenerates from its own load. Also: the ADR-0058 status says expected-registry.json changes in prose only.
…sage, comment, helper test
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What Changed
namingblock to.metaobjects/config.json(columns:snake_case|literal|kebab-case;tables:snake_case|literal). Every port's codegen,meta migrate, runtimeObjectManagerandverifyread it from the loaded model. Both rules default tosnake_case, which changes generated column names in C#, Java, Kotlin's runtime and Python unless the project sets"columns": "literal".columnNamingStrategy,--column-naming, thecolumnNamingpom arg,ObjectManager(column_naming=),SimpleMappingHandlerDB.setColumnNaming) are refused with a message that names the new setting and the migration guide. Engine functions that took the rule as an option now read it from the model.verify --codegen(Python, C#) reports when committed output was generated under a different column or table rule and names thenamingsetting that reproduces it. Adds thefixtures/naming-conformance/physical-names/corpus run by every port, anddocs/features/migrations/physical-naming.md. Also addsrequireschecking to the Mavenmetaobjects:generategoal and fixes theprereleasetooling scripts.Validation runs and size
--skip cibecause CI is local for this repository.git diff --shortstat main...HEADgives 329 files changed, 7071 insertions(+), 1752 deletions(-). Most of that is regenerated docs, fixtures and the five-port naming corpus.d74f3b8cd):scripts/prerelease.mjsnow runs each build and publish step as an awaited child in its own process group. SIGINT, SIGTERM and SIGHUP kill the active step, restore the version files and exit. Before, a SIGTERM during a synchronous publish waited for the whole script and publishing went on. Also fixed: the repin message intools/prerelease/prerelease-link.shprints only when the manifest changed, a stale Python comment, and a test for the Java Mustache table-name helper. Known tradeoff, accepted: a signal the script does not handle, sent to the whole process group (for example a group SIGKILL), no longer reaches the running step, which then finishes. No later step starts.requirescheck, realmvn metaobjects:generatein a scratch project (private-Dmaven.repo.local). This was captured on an earlier head of this branch. At that head the refusal named only direct companions. The current head names the transitive closure, whichGeneratorRequiresCompileTestcovers and which passed in run 4.SpringControllerGeneratoralone: exit 1, nothing written:SpringControllerGenerator ("routes") needs "dto" (SpringDtoGenerator), "repository" (SpringRepositoryGenerator), "filter-allowlist" (SpringFilterAllowlistGenerator) in the same <generators>: its output references what those generators write, so without it the generated code does not compile.-Dmetaobjects.allowUnmetRequires=true: exit 0, the same text as a warning, 40 controllers written.naming.tables. Such an entity has no table, so the name has no effect.Validation
Risk Assessment
✅ Low: The fix round fixes all four summary items, and each fix is bounded. Prerelease steps now run as awaited, group-killable children; a probe under bun confirmed they stop on SIGTERM. The repin message is now conditional, the stale comment is corrected, and the Mustache helper is tested against the shared naming corpus. The only remaining note is an informational tradeoff for signals the script does not handle.
Testing
Live checks: Python gen with literal and default naming, and the removed --column-naming flag refused on gen and verify (exit 2). Script, conformance and JUnit suites for prerelease, naming, TS refusals and the Java requires closure pass but were not live product runs. Quick CI exited 0 and skipped the csharp/java/python/kotlin conformance lanes, java-reactor, integration-tests and the cube live check, so those remain unverified.
Pipeline
Updates from git push no-mistakes
✅ **Intent** - passed
✅ No issues found.
✅ **Rebase** - passed
✅ No issues found.
✅ No issues found.
🔧 Fix applied.
1 info still open:
scripts/prerelease-version.mjs:106- Tradeoff introduced by the round-1 fix (review-summary-1 item 1).runnow spawns each step withdetached: true. On Linux that calls setsid, so every build or publish step runs in its own session. The three handled signals (SIGINT, SIGTERM, SIGHUP) are covered: the handler SIGKILLs each active group, restores the files and exits. I checked this under bun 1.3.14, the runtimeprerelease:publishactually uses. A signal sent to the whole process group that the script does not handle no longer reaches the step. Examples: SIGQUIT from Ctrl-,kill -9 -<pgid>, or a supervisor that escalates to a group SIGKILL. In those cases only node dies, the currentbun publishormvn deploykeeps running to completion, and the version files stay bumped. With execSync, the step shared the group and died with it. This needs no action: the handled signals are the realistic paths, and a group kill still stops every later step.✅ **Test** - passed
✅ No issues found.
scripts/ci-local.sh --only ts-fast --only ts-unit --strict-toolchainsscripts/ci-local.sh --only ts-fast --only ts-unit --strict-toolchains (baseline, green)node scripts/test-prerelease-version.mjs: all passbash tools/prerelease/test-prerelease-link.sh: all passbun test test/physical-naming-conformance.test.ts (sdk): 11 passuv run pytest tests/conformance/test_naming_conformance.py tests/unit/test_column_naming_strategy.py tests/codegen/test_config_run_settings.py: 33 passdotnet test MetaObjects.Codegen.Tests (NamingConformanceTests, GeneratorListEntryTests, AgentContextStalenessTests): 12 passmvn -q test -pl metadata -Dtest=PhysicalNamingConformanceTest: 5 passbun test gen-docs-generators.test.ts and migrate-config-dir.test.ts (cli): 30 passbun test physical-naming-refusals.test.ts and metaobjects-config.test.ts (codegen-ts): 15 passmvn -q test -pl maven-plugin -am -Dtest=GeneratorRequiresCompileTest: exit 0scripts/ci-local.sh --quick: passed, 4 lanes skippedLIVE python gen: literal naming yields firstName, default yields first_nameLIVE python gen/verify with --column-naming: exit 2 with shared removal message✅ **Document** - passed
✅ No issues found.
✅ **Lint** - passed
✅ No issues found.
✅ **Push** - passed
✅ No issues found.