Skip to content

Commit 7ce0552

Browse files
dmealingclaude
andcommitted
refactor(ai,java): author voRequest/voResponse columns; remove deriveTraceFields + preFreeze hook
The AI-trace design changed: trace entities now AUTHOR their typed voRequest/voResponse jsonb columns explicitly instead of deriving them by injecting synthetic field.object nodes into the loaded metadata tree at load time. This mirrors the TypeScript reference revert and removes the load-time metadata mutation entirely. Removed (the derivation + its generic load-time mutation hook): - LlmTraceFieldDeriver + its test + trace-derive.yaml fixture (metadata). - The generic preFreeze loader option on MetaDataLoader (field, setPreFreeze, the 4-arg fromUris overload, and the in-load invocation after resolvePendingExtends) — MetaDataLoader.java is byte-restored to its pre-hook state. - The deriveTraceFields pre-pass call in AbstractMetaDataMojo (meta:gen). - The redundant PromptTemplate.getPayloadRef() override added for the deriver (the base MetaTemplate.getPayloadRef() is identical and is what every generator already calls). Kept (these never mutate metadata): - The OMDB recorder (omdb .../manager/db/ai/). - LlmTraceHelperGenerator (codegen-spring record<Entity> generator) — it already carries its own local LLM_CALL_BASE constant, no deriver dependency. - @responseRef stays first-class cross-port vocabulary (registry manifest untouched). Tests now author the columns instead of relying on derivation: - integration meta.ai-trace.yaml restored to the Slice-1 authored shape (hand-declared voResponse field.object; no template.prompt, no GreetingRequest). - LlmCallTraceRoundTripTest uses the plain fromUris (no deriver hook); DDL restored to voResponse-only. - The codegen-spring compile-run fixture already authored voResponse/voRequest, so it needed no change. Verified: metadata 983/0/0; codegen-spring 144/0/0 (incl. GeneratedTraceHelper compile-run); RegistryManifestConformanceTest 3/0/0; integration LlmCallTraceRoundTripTest 2/2 against real Postgres (authored voResponse jsonb persisted end-to-end, no derivation). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 378db17 commit 7ce0552

8 files changed

Lines changed: 10 additions & 383 deletions

File tree

server/java/integration-tests/src/test/java/com/metaobjects/integration/LlmCallTraceRoundTripTest.java

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package com.metaobjects.integration;
22

33
import com.metaobjects.loader.MetaDataLoader;
4-
import com.metaobjects.loader.ai.LlmTraceFieldDeriver;
54
import com.metaobjects.loader.uri.URIHelper;
65
import com.metaobjects.manager.ObjectConnection;
76
import com.metaobjects.manager.db.ObjectManagerDB;
@@ -209,12 +208,7 @@ private static MetaDataLoader loadAiTraceMetadata() {
209208
Path libraryYaml = findRepoFile("library/ai/llm-call.yaml");
210209
URI libUri = URIHelper.toURI("model:file:" + libraryYaml.toAbsolutePath());
211210
URI entityUri = URIHelper.toURI("model:resource:meta.ai-trace.yaml");
212-
// Wire the AI-trace deriver as a preFreeze hook: voRequest/voResponse are
213-
// NOT authored in the fixture — they are derived in-load from the prompt's
214-
// @payloadRef/@responseRef, so the OMDB runtime sees the typed jsonb
215-
// columns (Slice 3, the metadata-driven-runtime divergence from TS).
216-
return MetaDataLoader.fromUris("test-ai-trace", List.of(libUri, entityUri),
217-
null, LlmTraceFieldDeriver::deriveTraceFields);
211+
return MetaDataLoader.fromUris("test-ai-trace", List.of(libUri, entityUri));
218212
}
219213

220214
/** Walk up from the working dir to locate a repo-relative file. */
@@ -251,7 +245,6 @@ private static void provisionSchema(PostgresContainer pg) throws SQLException {
251245
+ " \"startedAt\" timestamp,\n"
252246
+ " \"llmRequest\" jsonb,\n"
253247
+ " \"llmResponse\" jsonb,\n"
254-
+ " \"voRequest\" jsonb,\n"
255248
+ " \"voResponse\" jsonb\n"
256249
+ ")");
257250
}
Lines changed: 9 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,10 @@
11
# Test-only trace entity for the AI-trace recorder PG round-trip.
22
# Extends the SHIPPED metaobjects::ai::LlmCallBase (loaded from
3-
# library/ai/llm-call.yaml). The typed voRequest/voResponse jsonb columns are
4-
# NOT declared here — they are DERIVED by LlmTraceFieldDeriver (Slice 3) from the
5-
# nested template.prompt's @payloadRef/@responseRef when the loader runs with the
6-
# deriver wired as a preFreeze hook. This proves derivation reaches the
7-
# metadata-driven OMDB runtime (the Java-specific divergence from the TS
8-
# codegen-only reference).
3+
# library/ai/llm-call.yaml) and adds a typed voResponse jsonb column.
94
metadata:
105
package: metaobjects::ai
116
children:
12-
# Typed request payload VO (referenced by @payloadRef → derived voRequest).
13-
- object.value:
14-
name: GreetingRequest
15-
object: com.metaobjects.object.value.ValueObject
16-
children:
17-
- field.string: { name: prompt }
18-
19-
# Typed response VO (referenced by @responseRef → derived voResponse).
7+
# Typed value object stored in the voResponse jsonb column.
208
- object.value:
219
name: GreetingResponse
2210
object: com.metaobjects.object.value.ValueObject
@@ -25,15 +13,16 @@ metadata:
2513
- field.int: { name: score, column: score }
2614

2715
# Concrete trace entity: inherits the 18 LlmCallBase fields, declares its
28-
# table + primary identity + a template.prompt. The deriver injects
29-
# voRequest/voResponse field.object jsonb columns from the prompt refs.
16+
# table + primary identity + a typed voResponse jsonb column (@objectRef +
17+
# @storage:jsonb the owned-object typed-jsonb codec path).
3018
- object.entity:
3119
name: GreetingCall
3220
extends: metaobjects::ai::LlmCallBase
3321
children:
3422
- source.rdb: { table: llm_call, role: primary }
3523
- identity.primary: { name: primary, fields: ["spanId"] }
36-
- template.prompt:
37-
name: greet
38-
payloadRef: metaobjects::ai::GreetingRequest
39-
responseRef: metaobjects::ai::GreetingResponse
24+
- field.object:
25+
name: voResponse
26+
column: voResponse
27+
storage: jsonb
28+
objectRef: metaobjects::ai::GreetingResponse

server/java/maven-plugin/src/main/java/com/metaobjects/mojo/AbstractMetaDataMojo.java

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -86,14 +86,6 @@ public void execute() throws MojoExecutionException, MojoFailureException
8686

8787
MetaDataLoader loader = createLoader(projectClassLoader);
8888

89-
// AI-trace pre-pass: derive typed voRequest/voResponse jsonb columns onto
90-
// LlmCallBase-derived entities so the trace-helper generator (and any
91-
// entity/schema codegen) sees them without the author restating them.
92-
// Idempotent + a no-op for projects with no trace entities. The loader is
93-
// already loaded here (no hard freeze in Java); generators re-read children
94-
// fresh, so post-load derivation is sufficient for codegen.
95-
com.metaobjects.loader.ai.LlmTraceFieldDeriver.deriveTraceFields( loader );
96-
9789
List<Generator> generatorImpls = buildGenerators( projectClassLoader, null );
9890

9991
executeGenerators( loader, generatorImpls );

server/java/metadata/src/main/java/com/metaobjects/loader/MetaDataLoader.java

Lines changed: 0 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -110,15 +110,6 @@ public class MetaDataLoader implements LoaderConfigurable {
110110
// ClassLoader used for resolving metadata-referenced Java classes.
111111
private ClassLoader metaDataClassLoader = null;
112112

113-
// Optional pre-freeze enrichment hook. Mirrors the TypeScript loader's
114-
// generic `preFreeze` option: a callback that runs inside {@link #load} once
115-
// the tree is parsed and {@code extends} refs are resolved, but before the
116-
// validation passes. This is the designated injection point for programmatic
117-
// tree enrichment (e.g. codegen/runtime pre-passes that DERIVE additional
118-
// nodes from validated metadata). The injected nodes participate in the
119-
// subsequent validation passes. Null by default (no enrichment).
120-
private java.util.function.Consumer<MetaDataLoader> preFreeze = null;
121-
122113
// v6.0.0: Unified registry
123114
private MetaDataRegistry typeRegistry = null;
124115
private MetaDataLoaderRegistry loaderRegistry = null;
@@ -400,26 +391,9 @@ public static MetaDataLoader fromUris(String name, List<URI> uris) {
400391
* @return a fully-initialized loader with all URIs loaded
401392
*/
402393
public static MetaDataLoader fromUris(String name, List<URI> uris, LoaderOptions opts) {
403-
return fromUris(name, uris, opts, null);
404-
}
405-
406-
/**
407-
* Build + load with a pre-freeze enrichment hook (see {@link #setPreFreeze}).
408-
* The hook runs in-load (after extends-resolution, before validation), so any
409-
* derived nodes are validated and registered atomically with this build.
410-
*
411-
* @param name the loader name
412-
* @param uris model URIs to load
413-
* @param opts loader options (may be {@code null} for defaults)
414-
* @param preFreeze pre-freeze enrichment hook (may be {@code null})
415-
* @return a fully-initialized loader with all URIs loaded
416-
*/
417-
public static MetaDataLoader fromUris(String name, List<URI> uris, LoaderOptions opts,
418-
java.util.function.Consumer<MetaDataLoader> preFreeze) {
419394
MetaDataLoader loader = (opts == null)
420395
? createManual(false, name)
421396
: new MetaDataLoader(opts, SUBTYPE_MANUAL, name);
422-
if (preFreeze != null) loader.setPreFreeze(preFreeze);
423397
try {
424398
loader.init();
425399
List<MetaDataSource> sources = new ArrayList<>(uris.size());
@@ -698,19 +672,6 @@ public ClassLoader getMetaDataClassLoader() {
698672
return getDefaultMetaDataClassLoader();
699673
}
700674

701-
/**
702-
* Register a pre-freeze enrichment hook (mirrors the TS loader's generic
703-
* {@code preFreeze} option). The hook runs inside {@link #load} after
704-
* {@code extends} refs are resolved and before the validation passes, so any
705-
* nodes it injects are validated like hand-authored ones. Fluent; pass
706-
* {@code null} to clear. Must be set before {@link #load} runs.
707-
*/
708-
@SuppressWarnings("unchecked")
709-
public <T extends MetaDataLoader> T setPreFreeze(java.util.function.Consumer<MetaDataLoader> hook) {
710-
this.preFreeze = hook;
711-
return (T) this;
712-
}
713-
714675
///////////////////////////////////////////////////////////////////////
715676
// Source URIs (H3a Task 5: lifted from SimpleLoader)
716677

@@ -1289,14 +1250,6 @@ public MetaDataLoader load(List<MetaDataSource> sources) {
12891250
// becomes ERR_UNRESOLVED_SUPER.
12901251
resolvePendingExtends();
12911252

1292-
// Pre-freeze enrichment hook (mirrors TS): runs after extends-resolution
1293-
// and before validation, so DERIVED nodes (e.g. AI-trace voRequest/
1294-
// voResponse jsonb columns) are visible to the validation passes and to
1295-
// every downstream reader (codegen + runtime) just like authored nodes.
1296-
if (preFreeze != null) {
1297-
preFreeze.accept(this);
1298-
}
1299-
13001253
// Run post-load validation passes after all sources in this batch are parsed.
13011254
// Fires both when called from init() (via loadSourceURIsIfPresent) and when
13021255
// called directly by tests or the conformance runner. The loader handle is

server/java/metadata/src/main/java/com/metaobjects/loader/ai/LlmTraceFieldDeriver.java

Lines changed: 0 additions & 121 deletions
This file was deleted.

server/java/metadata/src/main/java/com/metaobjects/template/PromptTemplate.java

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -77,11 +77,4 @@ public String getResponseRef() {
7777
? getMetaAttr(ATTR_RESPONSE_REF, false).getValueAsString()
7878
: null;
7979
}
80-
81-
/** Returns the raw value of {@code @payloadRef}, or {@code null} if absent. */
82-
public String getPayloadRef() {
83-
return hasMetaAttr(ATTR_PAYLOAD_REF, false)
84-
? getMetaAttr(ATTR_PAYLOAD_REF, false).getValueAsString()
85-
: null;
86-
}
8780
}

0 commit comments

Comments
 (0)