feat(query-tool): align lineage model and tighten timeline mapping
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
schema: spec-driven
|
||||
created: 2026-02-22
|
||||
152
openspec/changes/query-tool-lineage-model-alignment/design.md
Normal file
152
openspec/changes/query-tool-lineage-model-alignment/design.md
Normal file
@@ -0,0 +1,152 @@
|
||||
## Context
|
||||
|
||||
「批次追蹤工具」目前已拆成三個頁籤(正向/反向/設備),但 lineage 核心仍以 `SPLITFROMID` 與 `DW_MES_PJ_COMBINEDASSYLOTS` 為主,資料語意不足以完整表達現場流程:
|
||||
|
||||
- GC 並非 GA 的必經節點,且非 1:1;部分批次只有 GC 抽點,部分完全不經 GC。
|
||||
- Wafer LOT(`DW_MES_CONTAINER.FIRSTNAME`)是 GA/GC 共同上游錨點,應獨立建模。
|
||||
- GD 重工追溯主鏈在 `DW_MES_CONTAINER`:`ORIGINALCONTAINERID` + `FIRSTNAME` + `SPLITFROMID`,僅靠 COMBINED 表無法表達完整重工來源。
|
||||
|
||||
已驗證資料特徵(實查):
|
||||
|
||||
- GD lot 可由 `DW_MES_PJ_COMBINEDASSYLOTS.FINISHEDNAME` 反解至 `GDxxxx-Axx`。
|
||||
- 該 GD lot 在 `DW_MES_CONTAINER` 中可取得 `MFGORDERNAME=GD...` 與 `ORIGINALCONTAINERID`、`FIRSTNAME`。
|
||||
- `ORIGINALCONTAINERID` 對應來源 lot 可回接 Wafer LOT(`FIRSTNAME`)。
|
||||
|
||||
約束條件:
|
||||
|
||||
- 需沿用現有 `/api/query-tool/*`、`/api/trace/*` 路由,不做破壞式移除。
|
||||
- 需保留 staged trace 的快取與 rate limit 行為。
|
||||
- 需維持查詢效能,避免以 Wafer LOT 為起點時產生不可控 fan-out。
|
||||
|
||||
## Goals / Non-Goals
|
||||
|
||||
**Goals:**
|
||||
|
||||
- 以「語意化節點/邊」重建 query-tool 的追溯模型,明確區分 split、merge、wafer-origin、gd-rework。
|
||||
- 明確支持兩種入口集合:
|
||||
- 正向:Wafer LOT / GA-GC 工單 / GA-GC LOT
|
||||
- 反向:成品流水號 / GD 工單 / GD LOT ID
|
||||
- 前端樹圖可視化要能辨識「GA 無 GC」與「GD 重工分支」。
|
||||
- 將 GD 追溯落在 lot/workorder 層級保證可追,並保留 serial 層級可得資訊。
|
||||
|
||||
**Non-Goals:**
|
||||
|
||||
- 不承諾舊成品流水號與新成品流水號 1:1 映射。
|
||||
- 不調整設備頁籤功能。
|
||||
- 不在本變更導入新資料來源(僅使用既有 DWH 表)。
|
||||
|
||||
## Decisions
|
||||
|
||||
### D1. 建立 Typed Lineage Graph(節點/邊雙語意)
|
||||
|
||||
後端 lineage 輸出新增語意欄位,與現有欄位並存(過渡期兼容):
|
||||
|
||||
- `nodes`: 依 `container_id` 聚合節點屬性(`node_type`, `container_name`, `mfgorder_name`, `wafer_lot`)
|
||||
- `edges`: 邊列表(`from_cid`, `to_cid`, `edge_type`)
|
||||
- `edge_type` 固定枚舉:
|
||||
- `split_from`
|
||||
- `merge_source`
|
||||
- `wafer_origin`
|
||||
- `gd_rework_source`
|
||||
|
||||
`node_type` 判定優先順序:
|
||||
|
||||
1. `MFGORDERNAME LIKE 'GD%'` 或 `CONTAINERNAME LIKE 'GD%'` → `GD`
|
||||
2. `MFGORDERNAME LIKE 'GC%'` 或 `CONTAINERNAME LIKE 'GC%'` → `GC`
|
||||
3. `MFGORDERNAME LIKE 'GA%'` 或 `CONTAINERNAME LIKE 'GA%'` → `GA`
|
||||
4. `OBJECTTYPE='LOT'` 且為 Wafer 錨點節點 → `WAFER`
|
||||
5. COMBINED `FINISHEDNAME` 的虛擬節點 → `SERIAL`
|
||||
|
||||
保留現有 `children_map` / `parent_map` 等欄位,前端逐步切換到 typed graph。
|
||||
|
||||
### D2. 以 Profile 區分 seed-resolve 輸入語意
|
||||
|
||||
`/api/trace/seed-resolve` 改為 profile-aware 的 resolve type 規則:
|
||||
|
||||
- `query_tool`(正向)允許:`wafer_lot`, `lot_id`, `work_order`
|
||||
- `query_tool_reverse`(反向)允許:`serial_number`, `gd_work_order`, `gd_lot_id`
|
||||
|
||||
其中:
|
||||
|
||||
- `wafer_lot`: 以 `DW_MES_CONTAINER.FIRSTNAME` 解析種子 lot 集合
|
||||
- `gd_work_order`: 僅允許 `GD%` 前綴,對 `DW_MES_CONTAINER.MFGORDERNAME` 解析
|
||||
- `gd_lot_id`: 以 `DW_MES_CONTAINER.CONTAINERNAME` 解析,且需同時符合 GD 規則(`CONTAINERNAME LIKE 'GD%'` 或 `MFGORDERNAME LIKE 'GD%'`)
|
||||
- `work_order`(正向)限定 GA/GC(非 GD)
|
||||
|
||||
此設計避免正反向模式語意混用,且可在 API 層即早回饋錯誤。
|
||||
|
||||
### D3. GD 反向追溯採「Container 主鏈 + Combined 輔鏈」
|
||||
|
||||
GD 反向演算法(三種起點共用):
|
||||
|
||||
1. 種子為 serial 時,先由 `DW_MES_PJ_COMBINEDASSYLOTS.FINISHEDNAME` 找到 lot(常為 `GDxxxx-Axx`);種子為 `gd_lot_id` 時直接命中該 lot;種子為 `gd_work_order` 時直接展開該工單 lot 群。
|
||||
2. 對 serial 或 `gd_lot_id` 起點,讀取 lot 的 `MFGORDERNAME` 以展開同 GD 工單 lot 群。
|
||||
3. 對每個 GD lot 取來源:
|
||||
- 主來源:`ORIGINALCONTAINERID`
|
||||
- 回退來源:`SPLITFROMID`(當 ORIGINAL 為空或無效)
|
||||
4. 來源 lot 再透過 `FIRSTNAME` 接回 Wafer LOT 錨點。
|
||||
5. COMBINED 僅負責「lot -> 成品流水號」映射,不作為 GD 來源主依據。
|
||||
|
||||
這可涵蓋「成品流水號 -> GD -> 來源 lot -> wafer」與「GD 工單 -> lot 群 -> 來源 lot」兩條路徑。
|
||||
|
||||
### D4. 前端改為語意化樹圖且保持明細過濾邊界
|
||||
|
||||
`LineageTreeChart` 調整為語意視覺:
|
||||
|
||||
- 節點顏色/形狀區分 `WAFER/GC/GA/GD/SERIAL`
|
||||
- 邊樣式區分 `split/merge/wafer-origin/gd-rework`
|
||||
- 無 GC 時強制顯示 `WAFER -> GA` 直接鏈路,不用「缺失」呈現
|
||||
|
||||
互動邊界:
|
||||
|
||||
- 點擊節點僅更新 detail panel 的 container scope
|
||||
- 不重新過濾/改寫樹本身(避免「點樹即變樹」)
|
||||
|
||||
### D5. 效能策略:分段查詢 + 批次 + 快取
|
||||
|
||||
- lineage 查詢維持分段與批次(IN clause batching)策略。
|
||||
- Wafer LOT 展開加入結果上限與分頁/裁切策略(避免單一查詢過大)。
|
||||
- GD 關係查詢以 Redis/L2 做短期快取(可由 env 配置 TTL)。
|
||||
- 監控新增 typed-edge 命中統計,觀察 `wafer_origin` 與 `gd_rework_source` 的覆蓋率。
|
||||
|
||||
### D6. 向後相容與漸進切換
|
||||
|
||||
- API contract 採「新增欄位」方式,不先移除舊欄位。
|
||||
- 前端先讀新欄位,保留舊欄位 fallback 一個版本週期。
|
||||
- 若生產異常,可切回舊渲染路徑(feature flag 或 runtime config)。
|
||||
|
||||
## Risks / Trade-offs
|
||||
|
||||
- [Risk] Wafer LOT fan-out 過大導致查詢壓力
|
||||
Mitigation: 設定種子展開上限、分段查詢、UI 提示「僅顯示前 N 筆」。
|
||||
|
||||
- [Risk] `FIRSTNAME` 同名造成跨流程誤連
|
||||
Mitigation: 邊生成時加上 `OBJECTTYPE='LOT'` 與工單/時間窗交叉約束;疑似多義連線以低信任度標記。
|
||||
|
||||
- [Risk] GD 舊/新 serial 無法 1:1 對映引發期待落差
|
||||
Mitigation: 在規格與 UI 說明明確宣告 serial 層級的限制,保證 lot/workorder 層級完整可追。
|
||||
|
||||
- [Risk] 新舊欄位並存造成前後端邏輯複雜
|
||||
Mitigation: 設定移除時程,待新前端穩定後再移除舊欄位讀取。
|
||||
|
||||
## Migration Plan
|
||||
|
||||
1. 後端先落地 typed lineage(不改前端),確認 API 回傳兼容。
|
||||
2. 前端切換至 typed graph 視覺與新 resolve 類型。
|
||||
3. 啟用 GD reverse 路徑與 GC-optional 顯示規則。
|
||||
4. 以實例資料驗證三種主流程:
|
||||
- WAFER -> GA(無 GC)
|
||||
- WAFER -> GC -> GA
|
||||
- SERIAL -> GD -> SOURCE LOT -> WAFER
|
||||
5. 穩定後移除舊渲染相依欄位(若決議移除)。
|
||||
|
||||
Rollback:
|
||||
|
||||
- 關閉 typed graph 功能開關,前端退回舊欄位渲染。
|
||||
- 保留新 SQL/欄位但不被前端使用,避免熱修回滾需 DB 變更。
|
||||
|
||||
## Open Questions
|
||||
|
||||
- Wafer LOT 輸入值格式是否需要強制前綴或正則,以降低同名誤連?
|
||||
- 正向 `work_order` 是否嚴格限制 GA/GC,或允許 GD 但提示「請用反向頁籤」?
|
||||
- `WAFER -> GA` 直接鏈路在視覺上要以虛線還是實線呈現(避免與 split 混淆)?
|
||||
@@ -0,0 +1,77 @@
|
||||
## Why
|
||||
|
||||
目前「批次追蹤工具」雖已拆成正向/反向/設備三個頁籤,但追溯模型仍以 `SPLITFROMID + COMBINEDASSYLOTS` 為主,與實際 GA/GC/GD/WAFER LOT 關係不完全一致。已完成的資料探索也顯示:GC→GA 常透過共同 `FIRSTNAME`(Wafer LOT)而非 split 直接可見,GD 重工鏈也主要落在 `DW_MES_CONTAINER`(`ORIGINALCONTAINERID` / `FIRSTNAME` / `SPLITFROMID`),若不補齊模型,前端樹圖會持續出現「可顯示但語意不正確」的問題。
|
||||
|
||||
## What Changes
|
||||
|
||||
- 釐清並統一「批次追蹤」資料語意,將追溯關係分成可辨識的邊類型,而不只是一般 parent/child:
|
||||
- `split_from`(拆批)
|
||||
- `merge_source`(併批)
|
||||
- `wafer_origin`(`FIRSTNAME` 對應 Wafer LOT)
|
||||
- `gd_rework_source`(GD 重工來源,依 `ORIGINALCONTAINERID`/`FIRSTNAME`)
|
||||
- 明確納入 GC 非必經站規則:
|
||||
- GC 與 GA 非 1:1,也不是必經關係(可能僅抽點,也可能完全不經 GC)
|
||||
- 追溯主錨點改為 Wafer LOT;GC 視為「可選節點」,不存在時不視為斷鏈
|
||||
- 前端需顯示 `WAFER -> GA` 直接鏈路(無 GC 時),讓使用者可視覺辨識「跳過 GC」情境
|
||||
- 調整查詢入口,對齊你定義的使用情境:
|
||||
- 正向頁籤支援:Wafer LOT、GA/GC 工單、GA/GC LOT 作為起點
|
||||
- 反向頁籤支援:成品流水號、GD 工單、GD LOT ID 作為起點
|
||||
- 讓正反向追溯輸出採同一份「語意化關係圖」資料結構,只在起點與展開方向不同,避免結果解讀不一致。
|
||||
- 補齊 GA 無 GC 時的可視化語意:若無 GC 節點,仍須明確顯示 Wafer LOT 補充鏈路,不可隱性省略。
|
||||
- 前端樹圖改為「節點類型 + 關係類型」雙重視覺表達(非僅 root/branch/leaf):
|
||||
- 節點至少區分:WAFER、GC、GA、GD、SERIAL
|
||||
- 關係邊樣式區分:split、merge、wafer-origin、gd-rework
|
||||
- 保留點選節點只過濾下方明細,不回頭過濾樹本身。
|
||||
- 增加查詢效能與風險控制策略:
|
||||
- 先做 seed resolve,再按需分段展開關係,避免一次全量 fan-out
|
||||
- 對 GD 關係查詢加入快取策略(可配置 TTL,預設使用既有 Redis 快取層)
|
||||
- 補上追溯鏈路命中統計與慢查監控欄位,便於驗證模型是否正確覆蓋。
|
||||
|
||||
### GD 追溯策略(補充)
|
||||
|
||||
- 反向起點為「成品流水號」時:
|
||||
1. 先用 `DW_MES_PJ_COMBINEDASSYLOTS.FINISHEDNAME` 解析到 GD lot(例如 `GDxxxx-A01`)
|
||||
2. 取得 GD lot 對應 `MFGORDERNAME=GD...`
|
||||
3. 以 `DW_MES_CONTAINER` 展開同 GD 工單全部 lot
|
||||
4. 每一個 GD lot 以 `ORIGINALCONTAINERID`(主)與 `FIRSTNAME`(輔)回溯來源 lot
|
||||
5. 來源 lot 再透過 `FIRSTNAME` 連到 Wafer LOT 錨點
|
||||
- 反向起點為「GD 工單」時:
|
||||
- 直接從 `DW_MES_CONTAINER` 取 GD lot 群,後續同上回溯來源 lot 與 Wafer LOT
|
||||
- 反向起點為「GD LOT ID」時:
|
||||
- 以 `DW_MES_CONTAINER.CONTAINERNAME` 精準命中 GD lot(需符合 GD 規則),再沿用同一條回溯鏈
|
||||
- 適用「已知單顆/單批 GD lot,未知整張 GD 工單」的快速反查情境
|
||||
- 正向時,若查到來源 lot 存在 GD 再製分支,需額外顯示 `gd_rework_source` 邊,形成「原 lot -> GD lot -> 新成品」分支。
|
||||
- 限制聲明:
|
||||
- 目前資料可穩定追出「來源 lot 與 GD lot 關係」;
|
||||
- 舊成品流水號與新成品流水號不保證存在 1:1 可直接映射,提案先保證 lot/workorder 層級完整可追。
|
||||
|
||||
### 現況/需求/整合比較
|
||||
|
||||
| 面向 | 目前實作 | 新需求 | 本提案整合方向 |
|
||||
|---|---|---|---|
|
||||
| 正向入口 | `lot_id` / `work_order` | Wafer LOT + GA/GC 工單 + GA/GC LOT | 擴充 resolve type 與正向查詢入口 |
|
||||
| 反向入口 | 僅成品流水號 | 成品流水號 + GD 工單 + GD LOT ID | 反向 QueryBar 增加 GD 工單/GD LOT 模式 |
|
||||
| GD 關聯 | 主要倚賴 COMBINED 映射 | 需追出重工來源與重測後新結果 | 改以 `DW_MES_CONTAINER` 欄位為 GD 主鏈,COMBINED 僅作輔助 |
|
||||
| GC 缺失情境 | 樹上不易看出補線來源 | GA 無 GC 時仍要看見 WAFER LOT | 新增 `wafer_origin` 邊與視覺標示 |
|
||||
| 前端語意 | 泛化 root/branch/leaf | 要看得出流程語意 | 改成節點/邊語意化圖例與樣式 |
|
||||
|
||||
## Capabilities
|
||||
|
||||
### New Capabilities
|
||||
|
||||
- _(none)_
|
||||
|
||||
### Modified Capabilities
|
||||
|
||||
- `query-tool-lot-trace`: 查詢入口、正反向頁籤語意、樹圖互動與可視化規則更新。
|
||||
- `lineage-engine-core`: 從單一 split/merge 模型擴充為可輸出 wafer/GD 關係的語意化關係圖。
|
||||
- `trace-staged-api`: seed resolve 與 lineage response contract 擴充(新 resolve type、typed edges、節點分類欄位)。
|
||||
- `progressive-trace-ux`: 正反向追溯在同一 UX 規則下顯示,並保持分段載入與快取策略一致。
|
||||
|
||||
## Impact
|
||||
|
||||
- **前端**:`frontend/src/query-tool/App.vue`、`frontend/src/query-tool/components/QueryBar.vue`、`frontend/src/query-tool/components/LineageTreeChart.vue`、相關 composables(`useLotResolve.js`、`useLotLineage.js`、`useReverseLineage.js`)
|
||||
- **後端 API**:`src/mes_dashboard/routes/query_tool_routes.py`、`src/mes_dashboard/routes/trace_routes.py`
|
||||
- **服務層**:`src/mes_dashboard/services/query_tool_service.py`、`src/mes_dashboard/services/lineage_engine.py`
|
||||
- **SQL/資料來源**:`src/mes_dashboard/sql/lineage/*.sql`、`src/mes_dashboard/sql/query_tool/*resolve*.sql`(含 `DW_MES_CONTAINER` 欄位關聯補強)
|
||||
- **快取/監控**:沿用既有 Redis/L2 cache 與 slow-query logger,新增追溯關係命中統計欄位
|
||||
@@ -0,0 +1,42 @@
|
||||
## MODIFIED Requirements
|
||||
|
||||
### Requirement: LineageEngine SHALL provide combined genealogy resolution
|
||||
`LineageEngine.resolve_full_genealogy()` SHALL produce a semantic lineage graph that includes split, merge, wafer-origin, and GD-rework relationships.
|
||||
|
||||
#### Scenario: Combined genealogy includes typed edges
|
||||
- **WHEN** `resolve_full_genealogy()` is called with seed container IDs
|
||||
- **THEN** the response SHALL include lineage relationships with explicit edge types
|
||||
- **THEN** split, merge, wafer-origin, and gd-rework edges SHALL be distinguishable
|
||||
|
||||
#### Scenario: GA without GC remains traceable by wafer origin
|
||||
- **WHEN** seed lots have GA lineage without GC nodes
|
||||
- **THEN** the engine SHALL still link GA lineage to wafer origin via `FIRSTNAME`
|
||||
- **THEN** lineage output SHALL remain connected without synthetic GC nodes
|
||||
|
||||
#### Scenario: Backward compatibility fields preserved during migration
|
||||
- **WHEN** callers still depend on legacy ancestry maps
|
||||
- **THEN** the engine SHALL continue returning legacy-compatible fields during migration window
|
||||
- **THEN** typed graph fields SHALL be additive, not replacing legacy fields immediately
|
||||
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: LineageEngine SHALL resolve wafer-origin relationships from container data
|
||||
The engine SHALL derive wafer-origin links using `DW_MES_CONTAINER.FIRSTNAME` and valid LOT nodes.
|
||||
|
||||
#### Scenario: Wafer-origin edge creation
|
||||
- **WHEN** a lot node has a non-empty `FIRSTNAME` that maps to a wafer lot node
|
||||
- **THEN** the engine SHALL create a `wafer_origin` edge between the lot and wafer nodes
|
||||
- **THEN** wafer-origin resolution SHALL avoid duplicate edges per node pair
|
||||
|
||||
### Requirement: LineageEngine SHALL resolve GD rework source relationships from container data
|
||||
The engine SHALL derive GD rework source links primarily from `ORIGINALCONTAINERID`, with `SPLITFROMID` as fallback.
|
||||
|
||||
#### Scenario: GD source via ORIGINALCONTAINERID
|
||||
- **WHEN** a GD lot has a valid `ORIGINALCONTAINERID`
|
||||
- **THEN** the engine SHALL create a `gd_rework_source` edge from source lot to GD lot
|
||||
- **THEN** this edge SHALL be included in reverse and forward lineage outputs where applicable
|
||||
|
||||
#### Scenario: GD source fallback to SPLITFROMID
|
||||
- **WHEN** `ORIGINALCONTAINERID` is null or invalid and `SPLITFROMID` is available
|
||||
- **THEN** the engine SHALL fallback to `SPLITFROMID` for gd-rework source linkage
|
||||
- **THEN** the fallback linkage SHALL be marked with edge type `gd_rework_source`
|
||||
@@ -0,0 +1,24 @@
|
||||
## MODIFIED Requirements
|
||||
|
||||
### Requirement: query-tool lineage tab SHALL load on-demand
|
||||
The query-tool lineage experience SHALL keep progressive loading behavior while supporting forward and reverse tracing semantics with independent caches.
|
||||
|
||||
#### Scenario: Forward resolve auto-fires lineage progressively
|
||||
- **WHEN** forward seed resolution completes with N lots
|
||||
- **THEN** lineage requests SHALL auto-fire with concurrency control
|
||||
- **THEN** the tree SHALL progressively render as responses arrive
|
||||
|
||||
#### Scenario: Reverse resolve supports serial, GD work-order, and GD lot-id modes
|
||||
- **WHEN** reverse tab resolves seeds using `serial_number`, `gd_work_order`, or `gd_lot_id`
|
||||
- **THEN** lineage SHALL render upstream graph from resolved roots
|
||||
- **THEN** reverse tab behavior SHALL not depend on forward tab state
|
||||
|
||||
#### Scenario: Cache isolation per tab context
|
||||
- **WHEN** lineage data is fetched in forward tab
|
||||
- **THEN** forward cache SHALL be reusable within forward context
|
||||
- **THEN** reverse tab lineage cache SHALL be isolated from forward cache state
|
||||
|
||||
#### Scenario: Tree interaction does not mutate graph scope
|
||||
- **WHEN** user clicks nodes to inspect details
|
||||
- **THEN** detail panel scope SHALL update immediately
|
||||
- **THEN** lineage graph visibility SHALL remain unchanged unless a new resolve is executed
|
||||
@@ -0,0 +1,65 @@
|
||||
## MODIFIED Requirements
|
||||
|
||||
### Requirement: Query-tool page SHALL use tab-based layout separating LOT tracing from equipment queries
|
||||
The query-tool page SHALL present three top-level tabs with independent state: `批次追蹤(正向)`, `流水批反查(反向)`, and `設備生產批次追蹤`.
|
||||
|
||||
#### Scenario: Tab switching preserves independent state
|
||||
- **WHEN** the user switches between forward, reverse, and equipment tabs
|
||||
- **THEN** each tab SHALL retain its own input values, resolved seeds, selected nodes, and detail sub-tab state
|
||||
- **THEN** switching tabs SHALL NOT clear another tab's query context
|
||||
|
||||
#### Scenario: URL state reflects active tab and tab-local inputs
|
||||
- **WHEN** the user is on a specific tab
|
||||
- **THEN** the URL SHALL include `tab` and corresponding tab-local query parameters
|
||||
- **THEN** reloading the page SHALL restore the active tab and its tab-local state
|
||||
|
||||
### Requirement: QueryBar SHALL resolve LOT/Serial/WorkOrder inputs
|
||||
The query bar SHALL support profile-specific input types. Forward tracing SHALL support wafer/lot/work-order inputs, and reverse tracing SHALL support serial, GD work-order, and GD lot-id inputs.
|
||||
|
||||
#### Scenario: Forward query supports wafer-lot seeds
|
||||
- **WHEN** the user selects `wafer_lot` in forward tab and submits values
|
||||
- **THEN** the system SHALL call resolve API with `input_type=wafer_lot`
|
||||
- **THEN** resolved lots under the wafer origin SHALL appear as forward tree roots
|
||||
|
||||
#### Scenario: Reverse query supports GD work-order seeds
|
||||
- **WHEN** the user selects `gd_work_order` in reverse tab and submits `GD%` work orders
|
||||
- **THEN** the system SHALL call resolve API with `input_type=gd_work_order`
|
||||
- **THEN** resolved GD lots SHALL appear as reverse tree roots
|
||||
|
||||
#### Scenario: Reverse query supports GD lot-id seeds
|
||||
- **WHEN** the user selects `gd_lot_id` in reverse tab and submits GD lot IDs
|
||||
- **THEN** the system SHALL call resolve API with `input_type=gd_lot_id`
|
||||
- **THEN** resolved GD lot roots SHALL be used for reverse lineage expansion
|
||||
|
||||
#### Scenario: Invalid GD work-order input is rejected
|
||||
- **WHEN** reverse tab input type is `gd_work_order` and a value does not match `GD%`
|
||||
- **THEN** the system SHALL return validation error without issuing lineage query
|
||||
- **THEN** the UI SHALL keep user input and display actionable error text
|
||||
|
||||
#### Scenario: Invalid GD lot-id input is rejected
|
||||
- **WHEN** reverse tab input type is `gd_lot_id` and a value does not match GD lot rules
|
||||
- **THEN** the system SHALL return validation error without issuing lineage query
|
||||
- **THEN** invalid values SHALL be reported in the UI without clearing user input
|
||||
|
||||
### Requirement: LineageTree SHALL display as a decomposition tree with progressive growth animation
|
||||
The lineage tree SHALL render semantic node/edge relationships and SHALL preserve progressive loading behavior.
|
||||
|
||||
#### Scenario: GC is optional and wafer linkage remains visible
|
||||
- **WHEN** a GA lot has no GC node in its upstream chain
|
||||
- **THEN** the tree SHALL still render a direct `WAFER -> GA` relationship
|
||||
- **THEN** this SHALL NOT be treated as a broken lineage
|
||||
|
||||
#### Scenario: GD rework branch is explicitly rendered
|
||||
- **WHEN** lineage includes GD rework data
|
||||
- **THEN** the tree SHALL render `source lot -> GD lot -> new serial/lot` using GD-specific node/edge style
|
||||
- **THEN** users SHALL be able to distinguish GD rework edges from split/merge edges
|
||||
|
||||
#### Scenario: Auto-fire lineage after forward resolve
|
||||
- **WHEN** forward lot resolution completes with N resolved lots
|
||||
- **THEN** lineage SHALL be fetched automatically with concurrency-limited requests
|
||||
- **THEN** the tree SHALL progressively grow as lineage responses arrive
|
||||
|
||||
#### Scenario: Node click only scopes detail panel
|
||||
- **WHEN** the user clicks one or more nodes in the tree
|
||||
- **THEN** only the detail panel query scope SHALL change
|
||||
- **THEN** the tree structure and node visibility SHALL remain unchanged
|
||||
@@ -0,0 +1,42 @@
|
||||
## MODIFIED Requirements
|
||||
|
||||
### Requirement: Staged trace API SHALL expose seed-resolve endpoint
|
||||
`POST /api/trace/seed-resolve` SHALL resolve seed lots based on profile-specific resolve types.
|
||||
|
||||
#### Scenario: Forward profile resolve types
|
||||
- **WHEN** request body contains `{ "profile": "query_tool", "params": { "resolve_type": "<type>", "values": [...] } }`
|
||||
- **THEN** `<type>` SHALL be one of `wafer_lot`, `lot_id`, or `work_order`
|
||||
- **THEN** non-supported types for this profile SHALL return HTTP 400 with `INVALID_PARAMS`
|
||||
|
||||
#### Scenario: Reverse profile resolve types
|
||||
- **WHEN** request body contains `{ "profile": "query_tool_reverse", "params": { "resolve_type": "<type>", "values": [...] } }`
|
||||
- **THEN** `<type>` SHALL be one of `serial_number`, `gd_work_order`, or `gd_lot_id`
|
||||
- **THEN** invalid `gd_work_order` values not matching `GD%` SHALL return HTTP 400
|
||||
|
||||
#### Scenario: GD lot-id validation
|
||||
- **WHEN** reverse profile uses `resolve_type=gd_lot_id`
|
||||
- **THEN** each value SHALL be validated against GD lot rules before resolution
|
||||
- **THEN** invalid values SHALL return HTTP 400 with `INVALID_PARAMS`
|
||||
|
||||
#### Scenario: Seed response payload compatibility
|
||||
- **WHEN** seed resolution succeeds
|
||||
- **THEN** response SHALL include `stage`, `seeds`, `seed_count`, and `cache_key`
|
||||
- **THEN** each seed SHALL include `container_id` and displayable lot/container name fields
|
||||
|
||||
### Requirement: Staged trace API SHALL expose lineage endpoint
|
||||
`POST /api/trace/lineage` SHALL return semantic lineage graph fields while preserving legacy-compatible fields during migration.
|
||||
|
||||
#### Scenario: Lineage response contains typed graph fields
|
||||
- **WHEN** lineage is resolved for `query_tool` or `query_tool_reverse`
|
||||
- **THEN** response SHALL include typed lineage fields (`nodes` and typed `edges`)
|
||||
- **THEN** each edge SHALL declare edge type sufficient to distinguish split/merge/wafer/gd-rework
|
||||
|
||||
#### Scenario: Legacy compatibility during frontend migration
|
||||
- **WHEN** existing clients still consume legacy lineage fields
|
||||
- **THEN** lineage response SHALL continue to include existing compatibility fields for a migration period
|
||||
- **THEN** typed fields SHALL be additive and not break current clients
|
||||
|
||||
#### Scenario: Profile-aware cache keys
|
||||
- **WHEN** lineage requests have same container IDs but different profiles
|
||||
- **THEN** cache keys SHALL remain profile-aware to prevent cross-profile response mixing
|
||||
- **THEN** repeated requests with same profile and same sorted IDs SHALL hit cache
|
||||
31
openspec/changes/query-tool-lineage-model-alignment/tasks.md
Normal file
31
openspec/changes/query-tool-lineage-model-alignment/tasks.md
Normal file
@@ -0,0 +1,31 @@
|
||||
## 1. Backend lineage model (typed graph)
|
||||
|
||||
- [x] 1.1 Extend `LineageEngine` output to include typed `nodes` and `edges` while keeping legacy-compatible fields
|
||||
- [x] 1.2 Implement edge builders for `wafer_origin` (via `DW_MES_CONTAINER.FIRSTNAME`) and `gd_rework_source` (via `ORIGINALCONTAINERID`, fallback `SPLITFROMID`)
|
||||
- [x] 1.3 Add node classification helper for `WAFER/GC/GA/GD/SERIAL` and ensure deterministic priority rules
|
||||
- [x] 1.4 Add/adjust SQL fragments needed for wafer-origin and GD-source resolution with bind-safe `QueryBuilder` usage
|
||||
|
||||
## 2. Trace API and resolve contract updates
|
||||
|
||||
- [x] 2.1 Extend resolve service to support `wafer_lot`, `gd_work_order`, and `gd_lot_id` input types with profile-aware validation
|
||||
- [x] 2.2 Update `/api/trace/seed-resolve` to enforce profile-specific resolve-type allowlists (`query_tool` vs `query_tool_reverse`)
|
||||
- [x] 2.3 Update `/api/trace/lineage` response contract to return typed graph payload additively (no immediate legacy break)
|
||||
- [x] 2.4 Verify lineage cache behavior remains profile-safe and does not mix forward/reverse responses
|
||||
|
||||
## 3. Query-tool frontend integration
|
||||
|
||||
- [x] 3.1 Update query bars and tab logic to expose forward types (`wafer_lot/lot_id/work_order`) and reverse types (`serial_number/gd_work_order/gd_lot_id`)
|
||||
- [x] 3.2 Refactor lineage composables to consume typed graph fields and map them into rendering data structures
|
||||
- [x] 3.3 Update `LineageTreeChart` to render semantic node styles and edge semantics for split/merge/wafer/gd-rework
|
||||
- [x] 3.4 Implement explicit UI handling for GC-optional flow (`WAFER -> GA` visible when GC is absent)
|
||||
- [x] 3.5 Ensure node click only updates detail scope and does not mutate tree visibility
|
||||
|
||||
## 4. Validation, regression, and documentation
|
||||
|
||||
- [x] 4.1 Add backend tests for resolve-type validation (`gd_work_order` + `gd_lot_id`), wafer-origin edges, and GD-source linkage
|
||||
- [x] 4.2 Add API contract tests for typed lineage fields and backward-compatible fields
|
||||
- [x] 4.3 Run manual data validation on representative scenarios:
|
||||
- [x] 4.4 Validate `WAFER -> GA` path without GC
|
||||
- [x] 4.5 Validate `WAFER -> GC -> GA` path
|
||||
- [x] 4.6 Validate `SERIAL -> GD -> source lot -> WAFER` reverse path
|
||||
- [x] 4.7 Update user-facing documentation/help text for new query modes and GD/GC interpretation rules
|
||||
Reference in New Issue
Block a user