Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
65007ff
feat: pai-lenses 初版 — parallel-ai-agents 的 lens pack (0.1.0)
BananaBay69 Aug 1, 2026
fa92873
docs: 修正缺 version 時的 cache 目錄名敘述
BananaBay69 Aug 1, 2026
dc32e24
fix: workflow YAML 解析失敗 —— heredoc 內容放在第 0 欄會跳出 block scalar
BananaBay69 Aug 1, 2026
331b642
Add 'plugins/pai-lenses/' from commit 'dc32e24e2825a50404f086c8f10921…
kiki830621 Aug 4, 2026
7d95d96
feat: 併入 pai-lenses 為第二個 plugin,marketplace 改相對路徑 (#33)
kiki830621 Aug 4, 2026
6dfdf8a
feat: ensemble-contribute-lenses skill — user 層 lens 的回流路徑 (#33)
kiki830621 Aug 4, 2026
44cbaef
chore: bump 2.23.0(pai-lenses 併回 + 貢獻 skill)(#33)
kiki830621 Aug 4, 2026
058f024
fix: verify R1 修正 —— 貢獻路徑照著做走不完、走完也送不到 (#33)
kiki830621 Aug 7, 2026
f74e32f
fix: verify R2 修正 —— 貢獻流程改為真正的腳本,不是文件裡的 bash 區塊 (#33)
kiki830621 Aug 8, 2026
63af9f5
refactor: PR 收斂為「併回 + 基礎建設」,層 ③ 回流工具拆到 #39 (#33)
kiki830621 Aug 8, 2026
1cb4233
fix: verify R4 修正 —— 三個是我這輪自己造的 (#33)
kiki830621 Aug 9, 2026
1e89eec
fix: verify R5 修正 —— 閘門比對錯基準、擋掉合法貢獻、以及只修一份文件
kiki830621 Aug 9, 2026
6b47743
fix: verify R6 修正 —— 閘門只走單向、containment 檢查錯路徑、缺撞名檢查
kiki830621 Aug 10, 2026
85bd278
fix: verify R6 的 MEDIUM 批次 —— 位置耦合、判準寫反、以及三個文件缺口
kiki830621 Aug 10, 2026
275ef72
fix: verify R7 —— 補上 validate.py 自己的測試,並修掉三個 HIGH
kiki830621 Aug 10, 2026
50ccf5b
fix: verify R8 —— 測試套件自己是套套邏輯;改成可量測而非可宣稱
kiki830621 Aug 10, 2026
c7bcbb7
fix: 測試環境只在一個地方建 —— 移除第二處寫死的 GITHUB_ACTIONS
kiki830621 Aug 10, 2026
4482826
fix: verify R9 —— 修好的閘門沒退化,但通往閘門的路有洞
kiki830621 Aug 12, 2026
f72f1a1
fix: verify R10 —— R9 的修正又是半成品,且兩道閘門出貨時零鑑別力
kiki830621 Aug 12, 2026
b97ce64
fix: 消毒移到輸出邊界 —— 我的 R10 修法本身就是「同類只修一處」
kiki830621 Aug 12, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 4 additions & 7 deletions .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
{
"name": "parallel-ai-agents",
"source": "./plugins/parallel-ai-agents",
"description": "v2.21.0: 三層 lens 疊加 built-in → lens pack → user (#29) — lens 可由外部 pai-lenses plugin 與 ~/.claude/pai-lenses/ 疊加,新增一條 lens 從「改 JS + bump plugin」降為「改 CSV」;撞名需顯式 override,報表附 provenance 行。v2.20.1: codex-call 補上 SSE error 事件的 message 提取路徑 (#25)。v2.20.0: first-party codex-pro governance deep-integration (#23). v2.19.0: codexModel/codexEffort contract args (#22, caller-governed cross-model leg). 平行派發任務給多個 AI agent(Claude + Codex),獨立執行後交叉比對結果。Codex 改走直接 HTTP wrapper(bin/codex-call,Swift script)取代 codex exec subprocess,解決 hang 問題且避開 Python 版本飄移",
"version": "2.22.0",
"description": "平行派發任務給多個 AI agent(Claude + Codex),獨立執行後交叉比對結果 —— distinct-lens reviewers + devil's-advocate 對抗 + 跨模型盲驗,merge/dedup 後報告。Codex 走直接 HTTP wrapper(bin/codex-call,Swift script)而非 codex exec subprocess,避開 hang 與 Python 版本飄移。v2.23.0: pai-lenses 併回本 repo 為第二個 plugin(marketplace 改相對路徑)、三層 lens 疊加的文件與 CI 閘門補齊。層 ③ 的自動回流路徑另行處理(#39)。",
"version": "2.23.0",
"author": {
"name": "Che Cheng"
},
Expand All @@ -25,12 +25,9 @@
},
{
"name": "pai-lenses",
"source": {
"source": "github",
"repo": "PsychQuant/pai-lenses"
},
"source": "./plugins/pai-lenses",
"description": "parallel-ai-agents 的 lens pack(層 ②):以 CSV 提供可疊加的 reviewer lens。裝了之後四個 ensemble skill 的 lens 集合會自動疊上;撞名需在 CSV 標 override 才取代。新增一條 lens = 改 CSV + bump 版本,不必動 plugin 程式碼。",
"version": "0.1.0",
"version": "0.2.0",
"author": {
"name": "Che Cheng"
},
Expand Down
85 changes: 84 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ jobs:
# shellcheck 已預裝在 ubuntu-latest runner

- name: shellcheck
run: shellcheck bin/pai-build-diff bin/pai-parse-verdict bin/pai-iter-commit
# 寫死清單的形式本身是問題(下一個新增的 script 預設不會被檢查)—— 追蹤於 #30。
# 這裡先把本 PR 新增的 pai-list-profiles 補進來,不留一支未檢查的新腳本。
run: shellcheck bin/pai-build-diff bin/pai-parse-verdict bin/pai-iter-commit bin/pai-list-profiles

- name: py_compile
run: python3 -m py_compile bin/pai-parse-lens-csv bin/pai-collect-lens-layers
Expand Down Expand Up @@ -98,3 +100,84 @@ jobs:
fi
grep -q '^ok' "$TAP" || { echo "::error::no tests ran (empty glob or bats bail-out)"; exit 1; }
exit "$rc"

manifests-and-lens-pack:
# 名稱刻意不叫 `pai-lenses-validate`(#33 verify R6):這支跑的
# `check_marketplace_sync` 檢查的是 **repo 內每一個 plugin** 的 manifest —— 包含主
# plugin —— 不只是 lens pack。掛在一個以 pack 命名的 job 底下會讓人以為主 plugin 的
# 版本閘門不存在。**指令碼本身仍住在 pack 裡**(`plugins/pai-lenses/scripts/validate.py`)
# —— 那是刻意的取捨:貢獻者要能在本機跑同一支。代價是主 plugin 的 manifest 閘門實作在
# 一個資料 pack 底下,這個位置耦合尚未解決,改名只是讓它在 CI 介面上不再誤導。
#
# 併回本 repo 前,這個檢查住在 PsychQuant/pai-lenses 自己的 validate.yml。併入後該檔
# 落在 plugins/pai-lenses/.github/ —— GitHub 只執行 repo root 的 .github/workflows/,
# 所以它形同失效。改掛成本 repo 的獨立 job。
runs-on: ubuntu-latest
defaults:
run:
working-directory: plugins/pai-lenses
steps:
- uses: actions/checkout@v4
with:
# fetch-depth: 0 是必要的 —— 預設 shallow clone 只有一個 commit,base SHA
# 不在本地歷史裡,bump 檢查就跑不了。(validate.py 現在對此**報錯**而非略過,
# 所以缺了不會安靜消失;但報錯也不等於檢查過 —— 還是要把歷史抓齊。)
fetch-depth: 0

# #33 verify R7:validate.py 有十餘道閘門卻零測試覆蓋 —— 所有錯誤分支只在
# CI 的 happy path 被執行(也就是都沒被執行)。六輪 verify 有超過二十個 finding
# 落在這一支,反覆出現的形狀是「閘門在某條件下安靜蒸發並印肯定式綠燈」,
# 那種缺陷用讀的抓不到。每條測試對應一個真實發生過的缺陷。
# 這套測試自己的鑑別力**用 scripts/mutation_check.py 量**,不靠宣稱(#33 verify R8:
# 初版的 20 個閘門 mutation 有 18 個存活,而當時三處文件都寫著「都做過 mutation」)。
# mutation_check.py 手動跑、不進 CI(一輪 = 靶數 × 全套測試,約十分鐘)——
# 這裡刻意不寫靶數,寫了就會過期,而過期的數字正是本 PR 一路在修的東西。
# #33 verify R9 M20:py_compile 的寫死清單只涵蓋主 plugin 的兩支,本 pack 新增的
# 三支 Python 只有 validate.py / test_validate.py 因為被執行而間接驗過語法,
# mutation_check.py **在任何地方都沒被語法檢查**。用 glob 而非清單。
- name: py_compile(pack 內所有 Python)
run: python3 -m py_compile scripts/*.py

- name: validate.py 自身的回歸測試(stdlib unittest,無額外依賴)
run: python3 scripts/test_validate.py

# 完整的 mutation 量測太慢(靶數 × 全套 ≈ 十分鐘),不進 CI。但**靶清單相對
# validate.py 的漂移**便宜就能擋:改動被 mutate 的那幾行、或搬走一道閘門,靶就對不上。
# 先前這只有在有人手動跑整輪時才會發現,而「忘了跑」是預設(#33 verify R9 M11/M24)。
- name: mutation 靶清單沒有漂移(秒級;完整量測仍是手動)
run: python3 scripts/mutation_check.py --check-targets

# 檢查的內容不寫進 workflow 而放在 scripts/validate.py:`run: |` 區塊裡的
# heredoc 一旦把內容放在第 0 欄就會跳出 YAML block scalar,workflow 靜默停止解析。
- name: validate manifests + lens pack (每個 plugin 的版本/entry 雙向同步、改 lens 必 bump、profile 名稱、CSV 形狀與撞名)
# --base 讓 validate 能判斷「改了 lenses/*.csv 卻沒 bump 版本」——
# 只驗「兩處一致」守不住這個(#33 verify R2 H5/H10)。
# base SHA 走 env 而非直接內插進 run(workflow-injection 的標準防護形狀)。
# push 事件沒有 pull_request.base.sha —— 先前那條路會讓 validate 不帶 --base,
# 而「改了 lens 必須 bump」這道閘門在 push-to-main 上就結構性不存在(#33 verify R4)。
# push 改用 event.before;首次 push / force-push 後它可能是全零 SHA,那時傳空字串。
# --event 一併傳進去(#33 verify R5):它決定兩件事 ——
# (1) base 的比較語意:push 用 base 本身做兩點 exact-tree 比較(問「這次 push
# 讓 main 變成什麼」),其餘收斂成 merge-base(問「這個分支引入了什麼」)。
# 先前變更清單用三點、舊版本用 `git show base:`,是兩個不同基準。
# **注意 force-push 不在守備範圍**(#33 verify R6):舊 tip 不被任何 ref 指到,
# actions/checkout 拿不到它,validate 會 fail-loud 說「沒有跑」而非假裝比較過。
# (2) 沒有 base 時該報錯還是留紀錄:workflow_dispatch **結構上**兩個 base 都沒有,
# R4 的無條件 fail-loud 讓它永遠紅 —— 一個不可能綠的檢查,下一個人會直接把
# fail-loud 拿掉,連 PR/push 的守備一起賠掉。
env:
PR_BASE: ${{ github.event.pull_request.base.sha }}
PUSH_BEFORE: ${{ github.event.before }}
EVENT_NAME: ${{ github.event_name }}
run: |
BASE="$PR_BASE"
if [ -z "$BASE" ] && [ -n "$PUSH_BEFORE" ] \
&& [ "$PUSH_BEFORE" != "0000000000000000000000000000000000000000" ]; then
BASE="$PUSH_BEFORE"
fi
if [ -n "$BASE" ]; then
python3 scripts/validate.py --base "$BASE" --event "$EVENT_NAME"
else
echo "::warning::沒有可用的 base ref(事件 $EVENT_NAME)—— 交給 validate 判定"
python3 scripts/validate.py --event "$EVENT_NAME"
fi
26 changes: 17 additions & 9 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,34 @@
## 結構

- `.claude-plugin/marketplace.json` — marketplace manifest
- `plugins/parallel-ai-agents/` — 唯一的 plugin(含 skills、`bin/codex-call` wrapper 等所有實作)
- `plugins/parallel-ai-agents/` — 主 plugin(含 skills、`bin/codex-call` wrapper 等所有實作)
- `plugins/pai-lenses/` — **第二個 plugin**:官方 lens pack(三層疊加的層 ②,見 `plugins/parallel-ai-agents/references/lens-layers.md`)。只有 CSV 與 validator,無程式碼
- `README.md` — marketplace 對外介紹
- `LICENSE` — MIT

## 給未來 Claude 的 note

當使用者要求改 ensemble 審閱邏輯、調整 agent 派發、改 Codex wrapper 時:**所有實作都在 `plugins/parallel-ai-agents/` 底下**,root 只保留 marketplace metadata 與整體文件。plugin 內部開發指引見 `plugins/parallel-ai-agents/CLAUDE.md`。
當使用者要求改 ensemble 審閱邏輯、調整 agent 派發、改 Codex wrapper 時:**實作都在 `plugins/parallel-ai-agents/` 底下**,root 只保留 marketplace metadata 與整體文件。plugin 內部開發指引見 `plugins/parallel-ai-agents/CLAUDE.md`。

要**新增或修改一條 lens** 則看目標層:既有 profile 加 lens → `plugins/pai-lenses/lenses/<profile>.csv`;需要新 profile → `plugins/parallel-ai-agents/workflows/ensemble-workflow.js` 的 `PROFILES`。判準見 `plugins/parallel-ai-agents/references/lens-layers.md`。**自動回流工具(層 ③ → 公共層)尚未就緒**,見 #39 —— 目前請照該文件的決策表手動做。**`references/builtin-lenses.csv` 是 generated 的唯讀投影,編它不改變任何行為。**

## 重要區分

- 「marketplace」=本 repo 整體(散發容器)
- 「plugin」=`plugins/parallel-ai-agents/`(功能本體)
- 「marketplace」=本 repo 整體(散發容器),對應 `.claude-plugin/marketplace.json`
- 「plugin」=`plugins/` 底下的**一個**目錄。現在有兩個:`parallel-ai-agents`(功能本體)
與 `pai-lenses`(官方 lens pack,純資料)

不要把兩者混在一起
不要把 marketplace 與 plugin 混在一起,也不要假設「plugin」單指主 plugin

## 版本同步(CRITICAL)

bump 版本時兩處必須一致:
bump 版本時兩處必須一致。**這條對每一個 plugin 各自成立**,現在有兩個:

| plugin | plugin.json | marketplace.json entry |
|---|---|---|
| `parallel-ai-agents` | `plugins/parallel-ai-agents/.claude-plugin/plugin.json` | `name: "parallel-ai-agents"` |
| `pai-lenses` | `plugins/pai-lenses/.claude-plugin/plugin.json` | `name: "pai-lenses"` |

- `plugins/parallel-ai-agents/.claude-plugin/plugin.json` 的 `version`
- `.claude-plugin/marketplace.json` 對應 plugin entry 的 `version`
兩者不同步 → 使用者 `/plugin update` 會看到舊版或裝不到新功能,**而且沒有任何錯誤訊息**。

兩者不同步 → 使用者 `/plugin update` 會看到舊版或裝不到新功能
**兩個 plugin 都有機械閘門守這條**:`plugins/pai-lenses/scripts/validate.py` 的 `check_marketplace_sync` 會逐一比對 marketplace.json 裡**每一個在本 repo 內的** plugin(不只 pai-lenses),CI job `manifests-and-lens-pack` 會跑。新增第三個 plugin 時自動涵蓋
65 changes: 55 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,59 @@

Claude Code marketplace,散發 **平行多 AI agent 審閱** plugin。

目前只裝一個 plugin:`parallel-ai-agents`。把任務平行派發給多個 AI agent(Claude teammates + Codex GPT-5.5),各自**獨立執行**後交叉比對,找出共識與盲點。
散發**兩個** plugin。把任務平行派發給多個 AI agent(Claude teammates + Codex),各自**獨立執行**後交叉比對,找出共識與盲點。

| Plugin | 是什麼 |
|---|---|
| **`parallel-ai-agents`** | 主 plugin —— ensemble 審閱的 skill、harness、`bin/` 工具 |
| **`pai-lenses`** | 官方 **lens pack**(三層疊加的層 ②):以 CSV 提供可疊加的 reviewer lens。純資料,無程式碼 |

## 安裝

```bash
/plugin marketplace add PsychQuant/parallel-ai-agents
/plugin install parallel-ai-agents@parallel-ai-agents
/plugin install pai-lenses@parallel-ai-agents # 官方 lens pack(建議一併安裝)
```

安裝後即可使用三個 skill:
> **已經裝過舊版(`0.1.0`,來自獨立的 `PsychQuant/pai-lenses` repo)的人**:那個 repo 已封存,
> pack 現在由本 marketplace 提供。跑
> `/plugin marketplace update parallel-ai-agents` 再 `/plugin update pai-lenses` 即可切過來
> (marketplace 名稱與 plugin 名稱都沒變,只有 source 從 github 改成本 repo 的相對路徑)。
> ⚠️ 這條路徑**尚未實測**(見 [#33](https://github.com/PsychQuant/parallel-ai-agents/issues/33)
> 的 verify R6)—— 若 `/plugin` 仍顯示 0.1.0,先移除再重裝。

> **`pai-lenses` 是選配但建議裝。** 沒裝時 ensemble 只會用 harness 內建的 lens ——
> 不會報錯、不會警告(缺席是靜默的,這是刻意設計),所以**「沒裝」與「裝了但沒生效」
> 從輸出上看不出差別**。報表的 provenance 行會列出實際載入了哪幾層,可據此確認。
>
> ⚠️ **層 ②③ 只在 Backend A(`Workflow` harness)生效。** 沒有 `Workflow` tool 的舊版
> Claude Code 會 fallback 到 Backend B(legacy TeamCreate fan-out),那條路的 reviewer 是
> 固定的一組 prompt —— **裝了 `pai-lenses` 也不會生效,且同樣沒有警告**。

安裝後可用的 skill:

| Skill | 用途 |
|-------|------|
| `/ensemble-code-review` | 程式碼/技術文件審閱:4 個 Claude teammates(architecture、correctness、securitydevils-advocate+ Codex 獨立審一遍,最後合成比較表 |
| `/ensemble-code-review` | 程式碼/技術文件審閱:architecture、correctness、security + devils-advocate + Codex 獨立審一遍,最後合成比較表 |
| `/ensemble-academic-review` | 學術論文審閱:methodology、writing、reference verification(che-zotero-mcp 抓幻覺文獻)、number-verification(R/Python 重跑 ground-truth 抓幻覺數字)、devils-advocate。支援 independent/hybrid/mix N 三種模式 |
| `/ensemble-lecture-review` | 教學講義審閱:4 個 Claude teammates 各自獨立審閱講義品質(可帶對應逐字稿 `--srt`) |
| `/ensemble-lecture-review` | 教學講義審閱:內容正確性/可讀性/逐字稿覆蓋率(可帶 `--srt`) |
| `/ensemble-minutes-review` | 會議記錄審閱:fidelity/completeness(一正一反)+ attribution + actionability。⚠️ 目前**尚未**接上 lens 疊加,`minutes` 的層 ②③ lens 只在 `/ensemble-compose --base minutes` 生效([#40](https://github.com/PsychQuant/parallel-ai-agents/issues/40))|
| `/ensemble-compose` | 自由組合:跨 profile 挑 lens + 自訂 reviewer(`--include` / `--lens` / `--lens-file`)|
| `/ensemble-eval` | **dev 工具**:對埋好缺陷的 fixture 跑 K 次真 ensemble,量偵測率 |

## 三層 lens 疊加

reviewer 的 lens 由三層疊出來,順序即優先序:

| 層 | 來源 | 誰能改 |
|---|---|---|
| ① built-in | 主 plugin 的 `PROFILES`(harness 內) | 改 code + 發版 |
| ② lens pack | `pai-lenses` 的 `lenses/<profile>.csv` | 改 CSV + bump 版本 |
| ③ user | `~/.claude/pai-lenses/<profile>.csv` | 直接編,立即生效、不必發布 |

撞名時預設 first-wins,CSV 標了 `override` 才取代。寫在層 ③ 的 lens 目前**還沒有**回流上游的路徑(實作中,見 [#39](https://github.com/PsychQuant/parallel-ai-agents/issues/39))。完整契約見
[`references/lens-layers.md`](plugins/parallel-ai-agents/references/lens-layers.md)。

## 為什麼

Expand All @@ -30,14 +67,22 @@ Claude Code marketplace,散發 **平行多 AI agent 審閱** plugin。
├── .claude-plugin/
│ └── marketplace.json # marketplace manifest
├── plugins/
│ └── parallel-ai-agents/ # 唯一的 plugin
│ ├── parallel-ai-agents/ # 主 plugin
│ │ ├── .claude-plugin/
│ │ │ └── plugin.json
│ │ ├── bin/
│ │ │ ├── codex-call # Swift script:直接 HTTP 呼叫 Codex
│ │ │ └── pai-list-profiles # 查 PROFILES 真源
│ │ ├── skills/ # 六個 skill
│ │ ├── workflows/ # ensemble harness
│ │ ├── references/ # lens-layers 契約、built-in lens catalog
│ │ ├── CHANGELOG.md
│ │ └── CLAUDE.md # plugin internal guide
│ └── pai-lenses/ # 官方 lens pack(層 ②)
│ ├── .claude-plugin/
│ │ └── plugin.json
│ ├── bin/
│ │ └── codex-call # Swift script:直接 HTTP 呼叫 Codex
│ ├── skills/ # 三個 ensemble-review skill
│ ├── CHANGELOG.md
│ └── CLAUDE.md # plugin internal guide
│ ├── lenses/ # <profile>.csv
│ └── scripts/validate.py # CI 閘門
├── README.md # 本檔案:marketplace 說明
├── LICENSE # MIT
└── .gitignore
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,26 @@

- **日期**:2026-07-29
- **相關 issue**:[PsychQuant/parallel-ai-agents#24](https://github.com/PsychQuant/parallel-ai-agents/issues/24)(agents/lens 設定更新現況盤點)
- **狀態**:設計已確認;§10 的唯一未驗證前提已於 2026-08-01 驗證成立,待寫實作計畫
- **狀態**:⚠️ **部分已被推翻 —— 本檔為歷史紀錄,不是現行設計**

> ## ⚠️ D1 / D7 已於 2026-08 撤回(#33 / PR #34)
>
> 本檔第 68 行的 **D1「lens 抽成獨立 repo」** 與第 75 行的 **D7「lens pack 與本 repo 為平行
> repo」**,連同「D1 補述:獨立 repo 的兩個理由」,**已經被推翻**。pack 現在住在
> `plugins/pai-lenses/`。
>
> 推翻的理由:`bin/pai-collect-lens-layers` 的 `PACK_PLUGIN` **寫死單一 pack 名**、只 glob
> `*/pai-lenses` —— 架構從一開始就只認一個官方 pack,不是多 pack 生態。因此 D1 補述的
> 「理由二:外部貢獻的出口成本」不但不成立,**反過來是障礙**(層 ③ 想回流時,判定目標層
> 與開 PR 都得跨兩個 repo)。完整說明見
> [`plugins/pai-lenses/README.md`](../../../plugins/pai-lenses/README.md) 的「為什麼不是獨立 repo」。
>
> **另一條也已失效**:第 93 行 D7 反駁欄的「CI 整合測試應以 fixture CSV 測試,不應吃真實
> lens repo」。併回後 `test/pai-collect-lens-layers.bats` 刻意新增了一個讀**真實 pack** 的
> 整合錨點 —— 那是刻意接受的耦合,理由寫在該檔檔頭。
>
> 其餘決策(D2–D6、D8:三層疊加的語意、override、provenance 行、CSV 契約)仍然成立,
> 且已實作。**判斷現行契約請看 `references/lens-layers.md`,不要看本檔。**

---

Expand Down
Loading
Loading