返回正文目录

Summary

Launcher 0.1.26 中,QM v2 为嵌套维度 ID/caption 列显式配置 name + alias,模型校验、登记和刷新均成功,但实时 JSON/Markdown 仍公开 TM 原字段名;以 QM 配置的新名称构造 DSL 时,query.validate 返回 FIELD_NOT_FOUND。同一个 QM 改用原字段名即可通过校验并正确执行。

此问题影响通过 QM 为 AI 提供稳定业务字段名;不是把 TM 的维度 alias 当成 QM alias 使用,也不是只测试整个维度 ref 的前缀展开。

Issue Routing

Environment

Reproduction

  1. 从上述 Release 下载启动脚本及相邻 JAR,按 README 启动独立实例。示意:./start-foggy-runtime.ps1 -Port 18068 -WorkDir ./work。
  2. 将公开 Chinook SQLite 副本登记为 named datasource chinook-sqlite,绑定 chinook,连接测试成功。不是内置 demo 数据源。
  3. 保存以下 TM/QM 到 models/model/、models/query/,保存后面的 DSL 到 alias-payload.json。
  4. 执行以下公开 CLI 命令(各行均附 --base-url http://127.0.0.1:18068 --namespace chinook):
foggy-runtime models validate --models-dir ./models
foggy-runtime bundles add --name qm-alias-repro --path ./models
foggy-runtime models refresh
foggy-runtime models describe MinimalArtistAliasQueryModel
foggy-runtime models describe MinimalArtistAliasQueryModel --format markdown
foggy-runtime query validate MinimalArtistAliasQueryModel --payload ./alias-payload.json

最后一条退出码为 2;被校验拒绝的请求没有继续执行。

TM: MinimalArtistAliasLineModel.tm

export const model = {
    name: 'MinimalArtistAliasLineModel', caption: '账单明细别名复现', tableName: 'InvoiceLine', idColumn: 'InvoiceLineId',
    properties: [{ column: 'InvoiceLineId', name: 'invoiceLineId', caption: '明细 ID', type: 'INTEGER' }],
    dimensions: [
        { name: 'invoice', caption: '账单', tableName: 'Invoice', foreignKey: 'InvoiceId', primaryKey: 'InvoiceId', captionColumn: 'InvoiceId',
          properties: [{ column: 'InvoiceDate', name: 'invoiceDate', caption: '账单日期', type: 'DATETIME' }] },
        { name: 'track', caption: '曲目', tableName: 'Track', foreignKey: 'TrackId', primaryKey: 'TrackId', captionColumn: 'Name',
          dimensions: [
              { name: 'album', caption: '专辑', tableName: 'Album', foreignKey: 'AlbumId', primaryKey: 'AlbumId', captionColumn: 'Title',
                dimensions: [
                    { name: 'artist', caption: '艺术家', tableName: 'Artist', foreignKey: 'ArtistId', primaryKey: 'ArtistId', captionColumn: 'Name' }
                ] }
          ] }
    ],
    measures: [{ column: 'UnitPrice', name: 'lineAmount', caption: '明细金额', type: 'MONEY', aggregation: 'sum',
        formulaDef: { builder: (alias) => `${alias}.UnitPrice * ${alias}.Quantity` } }]
};

QM: MinimalArtistAliasQueryModel.qm

const line = loadTableModel('MinimalArtistAliasLineModel');
export const queryModel = {
    name: 'MinimalArtistAliasQueryModel', caption: '艺术家别名复现', loader: 'v2', model: line,
    columnGroups: [{ caption: '复现字段', items: [
        { ref: line.invoiceLineId },
        { ref: line.invoice$invoiceDate },
        { ref: line.track.album.artist$id, name: 'albumArtistId', alias: 'albumArtistId' },
        { ref: line.track.album.artist$caption, name: 'albumArtistName', alias: 'albumArtistName' },
        { ref: line.lineAmount }
    ] }],
    accesses: []
};

DSL: alias-payload.json

{
  "columns": [
    "albumArtistId",
    "albumArtistName",
    "count(invoiceLineId) as lineCount",
    "sum(lineAmount) as totalAmount"
  ],
  "slice": [
    {
      "field": "invoice$invoiceDate",
      "op": "[)",
      "value": [
        "2012-01-01",
        "2013-01-01"
      ]
    },
    {
      "field": "albumArtistId",
      "op": "=",
      "value": 90
    }
  ],
  "groupBy": [
    "albumArtistId",
    "albumArtistName"
  ],
  "orderBy": [
    "albumArtistId"
  ],
  "limit": 5
}

Expected

Actual / Evidence

{
  "code": "FIELD_NOT_FOUND",
  "message": "Field 'albumArtistId' not found in model 'MinimalArtistAliasQueryModel'. Did you mean 'track.album.artist$id'?",
  "model": "MinimalArtistAliasQueryModel",
  "phase": "query.validate",
  "safeToAutoRepair": true,
  "suggestedNextAction": "Call model describe and retry with an existing field."
}
[
  {
    "artist$caption": "Iron Maiden",
    "artist$id": 90,
    "lineCount": 34,
    "totalAmount": 33.66
  }
]

原有复现的三个变体也已复测

QM 写法 模型校验/加载 JSON/Markdown 新名称 新名称 DSL 校验 同 QM 原名称对照
整维度 ref: line.track.album.artist, alias: 'albumArtist' 通过 未出现 FIELD_NOT_FOUND 通过,34 条 / 33.66
ID/caption 各自配置 alias 通过 未出现 FIELD_NOT_FOUND 通过,34 条 / 33.66
ID/caption 各自配置相同 name + alias 通过 未出现 FIELD_NOT_FOUND 通过,34 条 / 33.66

三个 DSL 与此前 0.1.25 复现请求保持不变。整维度 ref 的 alias 是否应作为展开前缀,可以另行明确合同;即使该写法不支持,最小复现中对具体 ID/caption 列显式设置 name/alias 的问题仍存在。

Source leads (需要维护者确认)

在该 Release commit 中,SelectColumnDef 描述了 QM name/alias,DbQueryColumnImpl 也保存这些值;而 SemanticServiceV3Impl 的维度字段元数据构建使用 dimension.getEffectiveName() 生成 ID/caption 名称。推测 QM 列覆盖名未完整传到语义字段注册链路,尚未把这一点当作已确定的根因。

建议回归覆盖:QM 具体嵌套 ID/caption 的 name/alias、JSON/Markdown 一致性、columns/slice/groupBy/orderBy、执行结果输出键,以及两个同名嵌套维度通过 QM 别名消歧。整维度 alias 不支持时也应有明确诊断。