Launcher 0.1.29 中,嵌套维度 InvoiceLine → Track → Album → Artist 的专用 members list 返回错误对象或 500:查询艺术家目录却返回 Track 数据;使用已公开的艺术家 ID 字段会触发 query model slot/name mismatch。CLI 还收到旧式 code/data 或 code/msg 信封,成功形状未符合 Runtime CLI success 合同。
归属:Java Runtime / synthetic member-QM、维度来源绑定与 Runtime API 响应。不能只修改 CLI 退出码,因为数据对象本身已错。与 #145 的 DISTINCT 排序、#146 的具体列命名问题分开;这两项在同一 0.1.29 已复测通过。#75 是前端 memberSelect 选择字段问题,当前证据是直接 CLI 调用,不依赖该前端。
a3693d0a812129f51966ef9c18247b0094a4f7f7;内部 Java project version:9.3.0-SNAPSHOT。f02ee6fabced558543b7da11c7b97da0469aaab5b0a32ff23d03a42b1eaf8595。六项 GitHub asset digest 与 SHA256SUMS 五项全部匹配,实际 JAR/进程命令行/监听 PID 已核对。http://127.0.0.1:18068;Namespace chinook,named datasource chinook-sqlite,none-dev-test-only;匿名本地开发查询。foggy-runtime-api/v1,schema 2026-06-06,engine java。相关 capabilities 声明 supported。bdf635be69850bd3be09c9a2dbeef7ddfb80036bd3ef3381383cd03b61e4a61a。将发行启动脚本及 JAR 放在同一目录。下载公开 SQLite 为当前目录的 Chinook.sqlite,将下文源码按文件名保存到 ./models/model/ 与 ./models/query/。以下目录均为调用者自己的练习目录。
.\start-foggy-runtime.ps1 -Port 18068 -WorkDir "$PWD/work"
foggy-runtime --base-url http://127.0.0.1:18068 --namespace chinook wait-ready --timeout-seconds 45
foggy-runtime --base-url http://127.0.0.1:18068 --namespace chinook capabilities
$dbPath = (Resolve-Path ./Chinook.sqlite).Path -replace '\\', '/'
foggy-runtime --base-url http://127.0.0.1:18068 --namespace chinook datasources add --name chinook-sqlite --type sqlite --jdbc-url "jdbc:sqlite:$dbPath"
foggy-runtime --base-url http://127.0.0.1:18068 --namespace chinook datasources bind --namespace chinook --data-source chinook-sqlite
foggy-runtime --base-url http://127.0.0.1:18068 --namespace chinook datasources test chinook-sqlite
后续每条 foggy-runtime 均在命令名前附加全局参数 --base-url http://127.0.0.1:18068 --namespace chinook。
本轮实际先使用旧字段 QM(源码见下文),六文件校验通过,再登记 Bundle、刷新并 describe。下方提供实际涉及的明细 TM/QM,供后续缩减复现;尚未额外执行仅此两文件的新进程缩减复现,实际证据来自六文件教学 Bundle。
foggy-runtime models validate --models-dir ./models
foggy-runtime bundles add --name chinook-members-repro --path ./models
foggy-runtime models refresh
foggy-runtime models describe ChinookInvoiceLineQueryModel
foggy-runtime members list ChinookInvoiceLineQueryModel artist
foggy-runtime members list ChinookInvoiceLineQueryModel artist$id
公开元数据包含 artist$id、artist$caption。先调用 artist,返回 code=200、total=3503、前十条曲目;随后 artist$id 报 slot/name mismatch。album$id 同样返回曲目,完整点路径/下划线路径也另有 synthetic member-QM 解析错误。
后续已将该隔离测试副本 QM 改为具体列 name/alias(见第二份 QM),使用同 WorkDir/registry 重启 0.1.29,再按 artist$id → albumArtistId → artist 的顺序调用。下面是重启后保留的响应;三个 CLI 退出码均为 2:
[
{
"field": "artist$id",
"cliExitCode": 2,
"response": {
"code": 500,
"exCode": "B500",
"msg": "服务器内部错误: query model slot/name mismatch: ChinookInvoiceLineQueryModel#album"
}
},
{
"field": "albumArtistId",
"cliExitCode": 2,
"response": {
"code": 500,
"exCode": "B500",
"msg": "服务器内部错误: cannot resolve synthetic member-QM from fieldName: albumArtistId"
}
},
{
"field": "artist",
"cliExitCode": 2,
"response": {
"code": 200,
"data": {
"empty": false,
"hasNext": false,
"items": [
{
"caption": "For Those About To Rock (We Salute You)",
"id": 1
},
{
"caption": "Balls to the Wall",
"id": 2
},
{
"caption": "Fast As a Shark",
"id": 3
},
{
"caption": "Restless and Wild",
"id": 4
},
{
"caption": "Princess of the Dawn",
"id": 5
},
{
"caption": "Put The Finger On You",
"id": 6
},
{
"caption": "Let's Get It Up",
"id": 7
},
{
"caption": "Inject The Venom",
"id": 8
},
{
"caption": "Snowballed",
"id": 9
},
{
"caption": "Evil Walks",
"id": 10
}
],
"limit": 10,
"pageNumber": 1,
"pageSize": 10,
"start": 0,
"total": 3503,
"totalData": {
"total": 3503
},
"totalPage": 350
}
}
}
]
这说明 slot/name mismatch 不仅发生在先调用 artist 后。重启后的别名 QM 是补充条件,不能冒称是未改 QM 的完全同请求新进程复现。
实际错误对象首项是 Track ID=1 的 For Those About To Rock (We Salute You),不是 Artist ID=1 的 AC/DC;total=3503 也与 Track 数量吻合。本轮通过只读原表计数与 ID/name 核对,不以 success 或 HTTP 状态推断业务正确。
默认 lite 进程日志(脱敏路径,保留原行号):
167: 2026-10-21 10:01:12.843 [http-nio-127.0.0.1-18068-exec-3] ERROR c.f.d.m.c.FoggyDatasetExceptionHandler - 系统异常:
168: java.lang.IllegalArgumentException: query model slot/name mismatch: ChinookInvoiceLineQueryModel#album
169: at com.foggyframework.dataset.model.lifecycle.catalog.CatalogSnapshot.validateQueryModelSlot(CatalogSnapshot.java:216)
170: at com.foggyframework.dataset.model.lifecycle.catalog.CatalogSnapshot.lambda$validateCatalogIntegrity$3(CatalogSnapshot.java:126)
171: at java.base/java.util.LinkedHashMap.forEach(LinkedHashMap.java:721)
172: at java.base/java.util.Collections$UnmodifiableMap.forEach(Collections.java:1553)
173: at com.foggyframework.dataset.model.lifecycle.catalog.CatalogSnapshot.validateCatalogIntegrity(CatalogSnapshot.java:125)
174: at com.foggyframework.dataset.model.lifecycle.catalog.CatalogSnapshot.<init>(CatalogSnapshot.java:44)
175: at com.foggyframework.dataset.model.lifecycle.catalog.CatalogCandidate.freeze(CatalogCandidate.java:582)
176: at com.foggyframework.dataset.model.lifecycle.catalog.CatalogSnapshotStore.lambda$publishAdditive$2(CatalogSnapshotStore.java:456)
177: at com.foggyframework.fsscript.lifecycle.CommittedSourceRevisionRegistry.publishIfCurrent(CommittedSourceRevisionRegistry.java:106)
178: at com.foggyframework.dataset.model.DbModelAutoConfiguration$1.publishIfCurrent(DbModelAutoConfiguration.java:157)
179: at com.foggyframework.dataset.model.lifecycle.catalog.CatalogSnapshotStore.publishIfSourceCurrent(CatalogSnapshotStore.java:525)
180: at com.foggyframework.dataset.model.lifecycle.catalog.CatalogSnapshotStore.publishAdditive(CatalogSnapshotStore.java:433)
181: at com.foggyframework.dataset.model.lifecycle.catalog.CatalogSnapshotStore$CandidateScope.commitAdditive(CatalogSnapshotStore.java:625)
182: at com.foggyframework.runtime.api.service.RuntimeNamedDataSourceResolver.publishGuarded(RuntimeNamedDataSourceResolver.java:284)
183: at com.foggyframework.runtime.api.service.RuntimeNamedDataSourceResolver.lambda$publishGuarded$22(RuntimeNamedDataSourceResolver.java:288)
184: at com.foggyframework.runtime.api.service.RuntimeNamedDataSourceResolver.continueComposite(RuntimeNamedDataSourceResolver.java:330)
185: at com.foggyframework.runtime.api.service.RuntimeNamedDataSourceResolver.lambda$publishGuarded$23(RuntimeNamedDataSourceResolver.java:287)
186: at com.foggyframework.runtime.api.service.RuntimeDatasourceRegistryService.publishIfCurrent(RuntimeDatasourceRegistryService.java:497)
187: at com.foggyframework.runtime.api.service.RuntimeNamedDataSourceResolver.publishGuarded(RuntimeNamedDataSourceResolver.java:290)
188: at com.foggyframework.runtime.api.service.RuntimeNamedDataSourceResolver.publishIfCurrent(RuntimeNamedDataSourceResolver.java:125)
189: at com.foggyframework.dataset.model.engine.query_model.QueryModelLoaderImpl.commitIfBindingsCurrent(QueryModelLoaderImpl.java:542)
190: at com.foggyframework.dataset.model.engine.query_model.QueryModelLoaderImpl.buildAndPublish(QueryModelLoaderImpl.java:423)
191: at com.foggyframework.dataset.model.engine.query_model.QueryModelLoaderImpl.lambda$resolveWithSingleFlight$1(QueryModelLoaderImpl.java:214)
192: at com.foggyframework.dataset.model.lifecycle.concurrent.ModelBuildSingleFlight.execute(ModelBuildSingleFlight.java:58)
193: at com.foggyframework.dataset.model.engine.query_model.QueryModelLoaderImpl.resolveWithSingleFlight(QueryModelLoaderImpl.java:212)
194: at com.foggyframework.dataset.model.engine.query_model.QueryModelLoaderImpl.resolveJdbcQueryModel(QueryModelLoaderImpl.java:164)
195: at com.foggyframework.dataset.model.service.impl.QueryFacadeImpl.resolveAndPin(QueryFacadeImpl.java:314)
196: at com.foggyframework.dataset.model.service.impl.QueryFacadeImpl.doQuery(QueryFacadeImpl.java:153)
重启后日志节选:
91: 2026-10-21 10:05:39.936 [http-nio-127.0.0.1-18068-exec-9] ERROR c.f.d.m.c.FoggyDatasetExceptionHandler - 系统异常:
92: java.lang.IllegalArgumentException: query model slot/name mismatch: ChinookInvoiceLineQueryModel#album
93: at com.foggyframework.dataset.model.lifecycle.catalog.CatalogSnapshot.validateQueryModelSlot(CatalogSnapshot.java:216)
94: at com.foggyframework.dataset.model.lifecycle.catalog.CatalogSnapshot.lambda$validateCatalogIntegrity$3(CatalogSnapshot.java:126)
95: at java.base/java.util.LinkedHashMap.forEach(LinkedHashMap.java:721)
96: at java.base/java.util.Collections$UnmodifiableMap.forEach(Collections.java:1553)
97: at com.foggyframework.dataset.model.lifecycle.catalog.CatalogSnapshot.validateCatalogIntegrity(CatalogSnapshot.java:125)
98: at com.foggyframework.dataset.model.lifecycle.catalog.CatalogSnapshot.<init>(CatalogSnapshot.java:44)
99: at com.foggyframework.dataset.model.lifecycle.catalog.CatalogCandidate.freeze(CatalogCandidate.java:582)
100: at com.foggyframework.dataset.model.lifecycle.catalog.CatalogSnapshotStore.lambda$publishAdditive$2(CatalogSnapshotStore.java:456)
101: at com.foggyframework.fsscript.lifecycle.CommittedSourceRevisionRegistry.publishIfCurrent(CommittedSourceRevisionRegistry.java:106)
102: at com.foggyframework.dataset.model.DbModelAutoConfiguration$1.publishIfCurrent(DbModelAutoConfiguration.java:157)
103: at com.foggyframework.dataset.model.lifecycle.catalog.CatalogSnapshotStore.publishIfSourceCurrent(CatalogSnapshotStore.java:525)
104: at com.foggyframework.dataset.model.lifecycle.catalog.CatalogSnapshotStore.publishAdditive(CatalogSnapshotStore.java:433)
105: at com.foggyframework.dataset.model.lifecycle.catalog.CatalogSnapshotStore$CandidateScope.commitAdditive(CatalogSnapshotStore.java:625)
106: at com.foggyframework.runtime.api.service.RuntimeNamedDataSourceResolver.publishGuarded(RuntimeNamedDataSourceResolver.java:284)
107: at com.foggyframework.runtime.api.service.RuntimeNamedDataSourceResolver.lambda$publishGuarded$22(RuntimeNamedDataSourceResolver.java:288)
108: at com.foggyframework.runtime.api.service.RuntimeNamedDataSourceResolver.continueComposite(RuntimeNamedDataSourceResolver.java:330)
同 QM 的语义查询校验和执行通过:按日期筛选、按艺术家 ID/名称分组,得到 119 位 2012 年有成交记录的艺术家。它只作为字段/关联查询可用的对照,不作为完整目录,也不算 members 接口修复:
{
"columns": [
"artist$id",
"artist$caption",
"count(invoiceLineId) as lineCount"
],
"slice": [
{
"field": "invoice$invoiceDate",
"op": "[)",
"value": [
"2012-01-01",
"2013-01-01"
]
}
],
"groupBy": [
"artist$id",
"artist$caption"
],
"orderBy": [
"artist$id"
],
"limit": 500,
"returnTotal": true
}
export const model = {
name: 'ChinookInvoiceLineModel',
caption: 'Chinook 账单明细',
description: '一行是一条账单明细。分类分析累计交易明细金额,不累计账单总金额,不改用目录单价。',
tableName: 'InvoiceLine',
idColumn: 'InvoiceLineId',
properties: [
{ column: 'InvoiceLineId', name: 'invoiceLineId', caption: '明细 ID', type: 'INTEGER' },
{ column: 'InvoiceId', name: 'invoiceId', caption: '账单 ID', type: 'INTEGER' },
{ column: 'TrackId', name: 'trackId', caption: '曲目或媒体 ID', type: 'INTEGER' },
{ column: 'UnitPrice', name: 'unitPrice', caption: '交易单价', type: 'MONEY',
description: '账单明细上的交易单价,不是 Track 目录单价。样例原始单位,币种未指定。' }
],
dimensions: [
{
name: 'invoice', caption: '账单', tableName: 'Invoice',
foreignKey: 'InvoiceId', primaryKey: 'InvoiceId', captionColumn: 'InvoiceId',
properties: [
{ column: 'InvoiceDate', name: 'invoiceDate', caption: '账单日期', type: 'DATETIME',
description: '按账单记录日期统计,不自行做时区转换。' },
{ column: 'BillingCountry', name: 'billingCountry', caption: '账单国家', type: 'STRING' },
{ column: 'CustomerId', name: 'customerId', caption: '客户 ID', type: 'INTEGER' }
],
dimensions: [
{
name: 'customer', caption: '客户', tableName: 'Customer',
foreignKey: 'CustomerId', primaryKey: 'CustomerId', captionColumn: 'LastName',
properties: [
{ column: 'FirstName', name: 'fullName', caption: '客户姓名', type: 'STRING',
description: 'FirstName 与 LastName 拼接;与客户 ID 一起使用。',
formulaDef: { builder: (alias) => `${alias}.FirstName || ' ' || ${alias}.LastName` } }
]
}
]
},
{
name: 'track', caption: '曲目或媒体', tableName: 'Track',
foreignKey: 'TrackId', primaryKey: 'TrackId', captionColumn: 'Name',
properties: [
{ column: 'Name', name: 'title', caption: '曲目或媒体名称', type: 'STRING' }
],
dimensions: [
{
name: 'genre', caption: '内容分类', tableName: 'Genre',
foreignKey: 'GenreId', primaryKey: 'GenreId', captionColumn: 'Name',
description: '包含音乐和影视内容;分类缺失不应丢弃交易金额。',
properties: [
{ column: 'GenreId', name: 'genreId', caption: '分类 ID', type: 'INTEGER' },
{ column: 'Name', name: 'genreName', caption: '内容分类名称', type: 'STRING' }
]
},
{
name: 'album', caption: '专辑', tableName: 'Album',
foreignKey: 'AlbumId', primaryKey: 'AlbumId', captionColumn: 'Title',
description: '曲目所属专辑,包含音乐及影视专辑;用 ID 区分同名专辑。',
dimensions: [
{
name: 'artist', caption: '艺术家', tableName: 'Artist',
foreignKey: 'ArtistId', primaryKey: 'ArtistId', captionColumn: 'Name',
description: '以专辑所属艺术家归属交易金额,不等同于 Track.Composer 作曲者;用 ID 区分同名。'
}
]
}
]
}
],
measures: [
{ column: 'UnitPrice', name: 'lineAmount', caption: '明细金额', type: 'MONEY', aggregation: 'sum',
description: '交易单价乘数量,沿用样例原始单位,不除以 100,不指定币种。',
formulaDef: { builder: (alias) => `${alias}.UnitPrice * ${alias}.Quantity` } },
{ column: 'Quantity', name: 'salesQuantity', caption: '销售数量', type: 'INTEGER', aggregation: 'sum',
description: '累计 Quantity;本样例全部为 1,也不能将数量定义成明细条数。' }
]
};
const line = loadTableModel('ChinookInvoiceLineModel');
export const queryModel = {
name: 'ChinookInvoiceLineQueryModel',
caption: 'Chinook 明细分析',
description: '按账单日期、客户、曲目或媒体、内容分类、专辑及其所属艺术家分析明细金额和销售数量。每行是一条明细,不提供可累计的账单总金额。艺术家按 Album.ArtistId 归属,不使用 Track.Composer。金额沿用样例原始单位,不指定币种、不做分元换算,不代表利润、回款或退款。',
loader: 'v2',
model: line,
columnGroups: [
{ caption: '交易明细', items: [
{ ref: line.invoiceLineId },
{ ref: line.invoiceId },
{ ref: line.trackId },
{ ref: line.unitPrice },
{ ref: line.invoice$invoiceDate },
{ ref: line.invoice$billingCountry },
{ ref: line.invoice$customerId },
{ ref: line.invoice.customer$fullName },
{ ref: line.track$title },
{ ref: line.track.genre$genreId },
{ ref: line.track.genre$genreName }
] },
{ caption: '专辑与艺术家', items: [
{ ref: line.track.album },
{ ref: line.track.album.artist }
] },
{ caption: '明细指标', items: [
{ ref: line.lineAmount },
{ ref: line.salesQuantity }
] }
],
accesses: []
};
const line = loadTableModel('ChinookInvoiceLineModel');
export const queryModel = {
name: 'ChinookInvoiceLineQueryModel',
caption: 'Chinook 明细分析',
description: '按账单日期、客户、曲目或媒体、内容分类、专辑及其所属艺术家分析明细金额和销售数量。每行是一条明细,不提供可累计的账单总金额。艺术家按 Album.ArtistId 归属,不使用 Track.Composer。金额沿用样例原始单位,不指定币种、不做分元换算,不代表利润、回款或退款。',
loader: 'v2',
model: line,
columnGroups: [
{ caption: '交易明细', items: [
{ ref: line.invoiceLineId },
{ ref: line.invoiceId },
{ ref: line.trackId },
{ ref: line.unitPrice },
{ ref: line.invoice$invoiceDate },
{ ref: line.invoice$billingCountry },
{ ref: line.invoice$customerId },
{ ref: line.invoice.customer$fullName },
{ ref: line.track$title },
{ ref: line.track.genre$genreId },
{ ref: line.track.genre$genreName }
] },
{ caption: '专辑与艺术家', items: [
{ ref: line.track.album$id, name: 'albumId', alias: 'albumId' },
{ ref: line.track.album$caption, name: 'albumName', alias: 'albumName' },
{ ref: line.track.album.artist$id, name: 'albumArtistId', alias: 'albumArtistId' },
{ ref: line.track.album.artist$caption, name: 'albumArtistName', alias: 'albumArtistName' }
] },
{ caption: '明细指标', items: [
{ ref: line.lineAmount },
{ ref: line.salesQuantity }
] }
],
accesses: []
};
覆盖嵌套 Artist/Album 与直接 Track 的来源绑定、当前公开字段/维度参数、别名投影、调用次序、fresh process、信封与 CLI 退出码。修复还应对成员范围与主查询权限保持一致;本轮为匿名本地开发测试,未把生产权限标为已验收。
原始 CLI JSON、精确命令及完整 stdout/stderr 均在本地留档;上述是可公开的精确响应与必要日志,未上传整份本机日志。测试实例已停止,无数据库写入、无产品代码改动。