Skip to content

Commit 5d173c8

Browse files
dmealingclaude
andcommitted
feat(metadata): SP-G Java recon Unit6b-fin/6c — exclude @object/@objectadapter binding facets + refactor field-validation to validator children
Part A (Unit 6b-finish): exclude the two per-port type-BINDING facets @object (ADR-0001 class-FQN type binding for OO ports) and @objectadapter (ADR-0005 hybrid value-access seam) from the registry manifest. These are the same category as the already-excluded native type bindings — legitimate per-port binding mechanisms, not cross-port logical vocabulary. Added 'object' + 'objectAdapter' to the shared per-type-attr exclusion set in all 4 emitters (TS/C#/Python no-op; filters Java's object.* binding attrs); they stay REGISTERED in Java (load-bearing runtime mechanisms read by the value-access representation, IO readers, and OMDB). README EXCLUDED list documents them alongside the native-type-bindings entry. object.* rows now match the canonical (residual only the object.base db* set → Unit 7). Part B (Unit 6c): refactor Java's field-level validation attrs to the cross-port validator-children form. Dropped the redundant/vestigial field-level registrations: @pattern/@minlength (string), @minValue/@MaxValue (int/long/ float/double/decimal), @format/@dateFormat/@minDate/@maxDate (date), @format/@minTime/@maxtime (time), @dateFormat/@minDate/@maxDate (timestamp), and field-level @Locale (currency). Investigation confirmed NONE are read by codegen/runtime/loader: codegen-spring/codegen-kotlin already emit validation from validator CHILD nodes (validator.regex @pattern, validator.length @min/@max, validator.numeric @min/@max) per the SP-C validator-parity work, so the field-level attrs were a redundant second path; the temporal-format / currency-locale attrs were vestigial (no canonical peer, no consumer — the currency @Locale wire contract lives on view.currency). Kept the canonical per-field attrs maxLength/precision/scale/currency. Constants retained (harmless; referenced by tests). Migrated the orphaned valid-complete-metadata.json example + the embedded test metadata to validator-children form; updated the registration-assertion tests to assert NAMED-requirement absence (field.base's open wildcard attr policy still accepts arbitrary attrs via acceptsChild). field.* rows now match the canonical (residual only the physical db* set → Unit 7). Java metadata 926/926 green; codegen-base/codegen-spring/codegen-kotlin/omdb BUILD SUCCESS; TS/C#/Python registry-conformance still byte-green (no-op). Gated RegistryManifestConformanceTest stays @ignore (Unit 8); un-skipped locally to confirm object.* + field.* now match canonical and the residual is ONLY the physical db* set (dbType/dbIndex/dbLength/dbNullable/dbForeignKey/dbPrecision/ dbScale/dbUnique/dbSequenceName/dbIndexName/dbTablespace/previousName — Unit 7), then re-skipped. Gate Javadoc updated accordingly. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 1e4b905 commit 5d173c8

21 files changed

Lines changed: 221 additions & 201 deletions

File tree

fixtures/registry-conformance/README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,16 @@ deferral.
105105
- Node factory / `NodeConstructor` / Java `Class` — per-port physical wiring.
106106
- Native type bindings (Java `DataTypes` value-class, TS native TS-type, EF/CLR
107107
types, the coarse `DataType` classification) — physical, per-port.
108+
- **The per-port type-binding facets `@object` + `@objectAdapter`**`@object`
109+
is the ADR-0001 class-FQN type binding for OO ports (the Java runtime resolves
110+
an object's native class from this attr) and `@objectAdapter` is the ADR-0005
111+
hybrid value-access seam. These are the same category as the native type
112+
bindings above — legitimate per-port BINDING mechanisms, not cross-port logical
113+
vocabulary. Java registers them as per-type attrs on `object.*` (load-bearing
114+
runtime mechanisms read by the value-access representation, IO readers, and
115+
OMDB — kept registered in Java); the emitter filters them by name from each
116+
type's `attrs` list (uniform across all four emitters; a no-op for
117+
TS/C#/Python, which never register them). See SP-G Unit 6b-finish.
108118
- Codegen targets/options.
109119
- The TS-only `D1` dialect and any other documented port-unique surface.
110120
- Ordering (we sort everything).

server/csharp/MetaObjects/RegistryManifest.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,14 +50,20 @@ public static class RegistryManifest
5050
private const string AttrNameImplements = "implements";
5151
private const string AttrNameIsInterface = "isInterface";
5252

53-
/// <summary>Per-type attr names filtered from a type's <c>attrs</c> list (structural / OO-shape keywords + the description commonAttr).</summary>
53+
/// <summary>The two per-port type-BINDING facet attr names: <c>object</c> (ADR-0001 class-FQN type binding for OO ports) and <c>objectAdapter</c> (ADR-0005 hybrid value-access seam). Same category as the excluded native type bindings — legitimate per-port binding mechanisms, not cross-port logical vocabulary. No-op for C# (never registers them); the filter drops Java's per-type <c>object.*</c> registrations. See SP-G Unit 6b-finish.</summary>
54+
private const string AttrNameObject = "object";
55+
private const string AttrNameObjectAdapter = "objectAdapter";
56+
57+
/// <summary>Per-type attr names filtered from a type's <c>attrs</c> list (structural / OO-shape keywords + the per-port type-binding facets <c>object</c>/<c>objectAdapter</c> + the description commonAttr).</summary>
5458
private static readonly HashSet<string> ExcludedPerTypeAttrNames = new(StringComparer.Ordinal)
5559
{
5660
Structural.RESERVED_KEY_IS_ARRAY,
5761
AttrNameIsAbstract,
5862
Structural.RESERVED_KEY_EXTENDS,
5963
AttrNameImplements,
6064
AttrNameIsInterface,
65+
AttrNameObject,
66+
AttrNameObjectAdapter,
6167
DocumentationConstants.DOC_ATTR_DESCRIPTION,
6268
};
6369

server/java/codegen-base/src/test/resources/schema-validation/valid-complete-metadata.json

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
"name": "username",
2828
"subType": "string",
2929
"@maxLength": 50,
30-
"@pattern": "^[a-zA-Z0-9_]+$",
3130
"children": [
3231
{
3332
"attr": {
@@ -97,16 +96,7 @@
9796
{
9897
"field": {
9998
"name": "createdDate",
100-
"subType": "date",
101-
"children": [
102-
{
103-
"attr": {
104-
"name": "format",
105-
"subType": "string",
106-
"value": "yyyy-MM-dd"
107-
}
108-
}
109-
]
99+
"subType": "date"
110100
}
111101
},
112102
{

server/java/metadata/src/main/java/com/metaobjects/field/CurrencyField.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,16 +38,17 @@ public static void registerTypes(MetaDataRegistry registry) {
3838
try {
3939
registry.registerType(CurrencyField.class, def -> {
4040
def.type(TYPE_FIELD).subType(SUBTYPE_CURRENCY)
41-
.description("Currency field — integer minor units; carries @currency (ISO 4217) and optional @locale")
41+
.description("Currency field — integer minor units; carries @currency (ISO 4217)")
4242
.inheritsFrom(TYPE_FIELD, SUBTYPE_BASE);
4343

4444
def.optionalAttributeWithConstraints(ATTR_CURRENCY)
4545
.ofType(StringAttribute.SUBTYPE_STRING)
4646
.asSingle();
4747

48-
def.optionalAttributeWithConstraints(ATTR_LOCALE)
49-
.ofType(StringAttribute.SUBTYPE_STRING)
50-
.asSingle();
48+
// @currency is the one canonical (cross-port) currency field attr. The
49+
// currency presentation @locale (BCP 47) wire contract lives on the
50+
// view.currency child, not the field — the field-level @locale had no
51+
// canonical peer and no consumer; dropped SP-G Unit 6c.
5152
});
5253
if (log != null) log.debug("Registered CurrencyField type with unified registry");
5354
} catch (Exception e) {

server/java/metadata/src/main/java/com/metaobjects/field/DateField.java

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -44,25 +44,14 @@ public DateField( String name ) {
4444
public static void registerTypes(MetaDataRegistry registry) {
4545
registry.registerType(DateField.class, def -> {
4646
def.type(TYPE_FIELD).subType(SUBTYPE_DATE)
47-
.description("Date field with format and range validation")
47+
.description("Date field")
4848
.inheritsFrom(TYPE_FIELD, SUBTYPE_BASE);
4949

50-
// DATE-SPECIFIC ATTRIBUTES WITH FLUENT CONSTRAINTS
51-
def.optionalAttributeWithConstraints(ATTR_DATE_FORMAT)
52-
.ofType(StringAttribute.SUBTYPE_STRING)
53-
.asSingle();
54-
55-
def.optionalAttributeWithConstraints(ATTR_FORMAT)
56-
.ofType(StringAttribute.SUBTYPE_STRING)
57-
.asSingle();
58-
59-
def.optionalAttributeWithConstraints(ATTR_MIN_DATE)
60-
.ofType(StringAttribute.SUBTYPE_STRING)
61-
.asSingle();
62-
63-
def.optionalAttributeWithConstraints(ATTR_MAX_DATE)
64-
.ofType(StringAttribute.SUBTYPE_STRING)
65-
.asSingle();
50+
// No date-specific per-field attrs in the cross-port vocabulary: the
51+
// field-level @format/@dateFormat (presentation) and @minDate/@maxDate
52+
// (range) attrs had no canonical peer and no consumer (codegen / runtime /
53+
// loader) — vestigial. Range validation is expressed via a validator child
54+
// (validator.numeric @min/@max); dropped SP-G Unit 6c.
6655
});
6756

6857
if (log != null) {

server/java/metadata/src/main/java/com/metaobjects/field/DecimalField.java

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -61,13 +61,10 @@ public static void registerTypes(MetaDataRegistry registry) {
6161
.ofType(IntAttribute.SUBTYPE_INT)
6262
.asSingle(); // Decimal places (e.g., 2)
6363

64-
def.optionalAttributeWithConstraints(ATTR_MIN_VALUE)
65-
.ofType(StringAttribute.SUBTYPE_STRING)
66-
.asSingle(); // String to preserve precision
67-
68-
def.optionalAttributeWithConstraints(ATTR_MAX_VALUE)
69-
.ofType(StringAttribute.SUBTYPE_STRING)
70-
.asSingle(); // String to preserve precision
64+
// precision + scale are the canonical (cross-port) decimal attrs.
65+
// Range validation is expressed via a validator.numeric @min/@max
66+
// CHILD node (the cross-port form), not field-level @minValue/@maxValue
67+
// attrs (dropped SP-G Unit 6c — validation emits from validator children).
7168
});
7269

7370
if (log != null) {

server/java/metadata/src/main/java/com/metaobjects/field/DoubleField.java

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -55,14 +55,9 @@ public static void registerTypes(MetaDataRegistry registry) {
5555
// INHERIT FROM BASE FIELD
5656
.inheritsFrom(TYPE_FIELD, SUBTYPE_BASE);
5757

58-
// DOUBLE-SPECIFIC ATTRIBUTES WITH FLUENT CONSTRAINTS
59-
def.optionalAttributeWithConstraints(ATTR_MIN_VALUE)
60-
.ofType(DoubleAttribute.SUBTYPE_DOUBLE)
61-
.asSingle();
62-
63-
def.optionalAttributeWithConstraints(ATTR_MAX_VALUE)
64-
.ofType(DoubleAttribute.SUBTYPE_DOUBLE)
65-
.asSingle();
58+
// Range validation is expressed via a validator.numeric @min/@max
59+
// CHILD node (the cross-port form), not field-level @minValue/@maxValue
60+
// attrs (dropped SP-G Unit 6c — validation emits from validator children).
6661
});
6762

6863
if (log != null) {

server/java/metadata/src/main/java/com/metaobjects/field/FloatField.java

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,14 +43,9 @@ public static void registerTypes(MetaDataRegistry registry) {
4343
.description("Float field with range validation")
4444
.inheritsFrom(TYPE_FIELD, SUBTYPE_BASE);
4545

46-
// FLOAT-SPECIFIC ATTRIBUTES WITH FLUENT CONSTRAINTS
47-
def.optionalAttributeWithConstraints(ATTR_MIN_VALUE)
48-
.ofType(DoubleAttribute.SUBTYPE_DOUBLE)
49-
.asSingle();
50-
51-
def.optionalAttributeWithConstraints(ATTR_MAX_VALUE)
52-
.ofType(DoubleAttribute.SUBTYPE_DOUBLE)
53-
.asSingle();
46+
// Range validation is expressed via a validator.numeric @min/@max
47+
// CHILD node (the cross-port form), not field-level @minValue/@maxValue
48+
// attrs (dropped SP-G Unit 6c — validation emits from validator children).
5449
});
5550
}
5651

server/java/metadata/src/main/java/com/metaobjects/field/IntegerField.java

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -46,14 +46,11 @@ public static void registerTypes(MetaDataRegistry registry) {
4646
// INHERIT FROM BASE FIELD
4747
.inheritsFrom(TYPE_FIELD, SUBTYPE_BASE);
4848

49-
// INTEGER-SPECIFIC ATTRIBUTES WITH FLUENT CONSTRAINTS
50-
def.optionalAttributeWithConstraints(ATTR_MIN_VALUE)
51-
.ofType(IntAttribute.SUBTYPE_INT)
52-
.asSingle();
53-
54-
def.optionalAttributeWithConstraints(ATTR_MAX_VALUE)
55-
.ofType(IntAttribute.SUBTYPE_INT)
56-
.asSingle();
49+
// Range validation is expressed via a validator.numeric @min/@max
50+
// CHILD node (the cross-port form), not field-level @minValue/@maxValue
51+
// attrs. The redundant field-level registrations were dropped in
52+
// SP-G Unit 6c (validation already emits from validator children per
53+
// the SP-C validator-parity work).
5754
});
5855

5956
if (log != null) {

server/java/metadata/src/main/java/com/metaobjects/field/LongField.java

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -46,14 +46,9 @@ public static void registerTypes(MetaDataRegistry registry) {
4646
// INHERIT FROM BASE FIELD
4747
.inheritsFrom(TYPE_FIELD, SUBTYPE_BASE);
4848

49-
// LONG-SPECIFIC ATTRIBUTES WITH FLUENT CONSTRAINTS
50-
def.optionalAttributeWithConstraints(ATTR_MIN_VALUE)
51-
.ofType(LongAttribute.SUBTYPE_LONG)
52-
.asSingle();
53-
54-
def.optionalAttributeWithConstraints(ATTR_MAX_VALUE)
55-
.ofType(LongAttribute.SUBTYPE_LONG)
56-
.asSingle();
49+
// Range validation is expressed via a validator.numeric @min/@max
50+
// CHILD node (the cross-port form), not field-level @minValue/@maxValue
51+
// attrs (dropped SP-G Unit 6c — validation emits from validator children).
5752
});
5853

5954
if (log != null) {

0 commit comments

Comments
 (0)