@qijenchen/design-system 0.1.0-beta.134 → 0.1.0-beta.135
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ds-canonical/fork/consumer/lock.json +4 -4
- package/ds-canonical/fork/governance.lock +2 -2
- package/ds-canonical/fork/hooks/check_ds_anchor_preflight.sh +2 -2
- package/ds-canonical/fork/manifest.json +10 -10
- package/ds-canonical/hooks/README.md +6 -4
- package/ds-canonical/hooks/check_ds_anchor_preflight.sh +2 -2
- package/ds-canonical/hooks/session_start_governance_check.sh +5 -5
- package/ds-canonical/references/ssot-index.md +2 -2
- package/ds-canonical/rules/README.md +1 -1
- package/ds-canonical/rules/meta-patterns.md +3 -3
- package/ds-canonical/skills/design-system-audit/references/rule-placement.md +10 -6
- package/ds-canonical/skills/governance-health/SKILL.md +3 -1
- package/package.json +1 -1
- package/src/components/AgentPanel/agent-panel.spec.md +3 -3
- package/src/components/Checkbox/checkbox.spec.md +1 -1
- package/src/components/Select/select.spec.md +1 -1
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
"schemaVersion": 1,
|
|
4
4
|
"role": "template-consumer",
|
|
5
5
|
"release": {
|
|
6
|
-
"designSystem": "0.1.0-beta.
|
|
7
|
-
"storybookConfig": "0.1.0-beta.
|
|
6
|
+
"designSystem": "0.1.0-beta.135",
|
|
7
|
+
"storybookConfig": "0.1.0-beta.135"
|
|
8
8
|
},
|
|
9
9
|
"upgradeTrust": {
|
|
10
10
|
"schemaVersion": 1,
|
|
@@ -42,10 +42,10 @@
|
|
|
42
42
|
"implementationSha256": "98b74118fb5b410b77ad2994aa9105fa7609c7353822f8c5213cce54d94f0af4"
|
|
43
43
|
},
|
|
44
44
|
"payload": {
|
|
45
|
-
"forkCorpusLockSha256": "
|
|
45
|
+
"forkCorpusLockSha256": "81e7127ec2940ff82ddc339cb546e00d8de3bf484f9927bd78a75cd08c7d938a",
|
|
46
46
|
"discoveryPolicySha256": "fba289aeeb5a3f11139b9589f7ab08b5e8c8799c7bdf8f0ea57ebfeb8e7c9da6",
|
|
47
47
|
"providerMaterializersSha256": "732e85b01a12e7dd19469e26e4427f0e0cfe5117a78fc9f69c2f0f89702f463a",
|
|
48
|
-
"providerLifecycleSha256": "
|
|
48
|
+
"providerLifecycleSha256": "ac8e1eb513cb195f7afdb6c7300f3341ec0c3ebf11684c70b598c0351ffce85e",
|
|
49
49
|
"providerInventorySha256": "00adf1c4f6b3367055a9cc3fdfe658660771b4c9931f696e12761a95076ad92c",
|
|
50
50
|
"executionRuntimeSha256": "d9377cc45308731f287d7b1711b7c38fc4e02ff8f84729bcbbf01bb52d136904",
|
|
51
51
|
"commonInstructionSha256": "a72c51a412d6cdb3961d691744013c8362e826626a330cecf4a296a6f4d93a5c",
|
|
@@ -679,7 +679,7 @@
|
|
|
679
679
|
{
|
|
680
680
|
"schemaVersion": 1,
|
|
681
681
|
"file": "hooks/check_ds_anchor_preflight.sh",
|
|
682
|
-
"sha256": "
|
|
682
|
+
"sha256": "b2dee125fc51d840a6b18e8dcdfd61b0b3e52e30b2d3e8bf8f9d190d96cdc12b",
|
|
683
683
|
"source": "check_ds_anchor_preflight.sh",
|
|
684
684
|
"classification": "SHIP_REWRITTEN",
|
|
685
685
|
"destination": null
|
|
@@ -919,7 +919,7 @@
|
|
|
919
919
|
{
|
|
920
920
|
"schemaVersion": 1,
|
|
921
921
|
"file": "manifest.json",
|
|
922
|
-
"sha256": "
|
|
922
|
+
"sha256": "26cea7e1ce9d053f9b45472a2c221383bf04a7796db149bb995b67b4fc8d3da3",
|
|
923
923
|
"source": null,
|
|
924
924
|
"classification": null,
|
|
925
925
|
"destination": null
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
# Detection:scan transcript 過去 ~30 turns:
|
|
22
22
|
# (a) 有 Grep / Read tool call hit `node_modules/@qijenchen/design-system/src/**/*.spec.md` OR
|
|
23
23
|
# `**/*.stories.tsx`(canonical baseline) → PASS
|
|
24
|
-
# (b) 無 →
|
|
24
|
+
# (b) 無 → P0 BLOCKER(exit 2),並在 stderr 印出「grep canonical → 3-column owner table」的修法。
|
|
25
25
|
#
|
|
26
26
|
# 對齊 meta-patterns.md M29 「視覺/結構 propose 前必 grep DS spec.md 找 owner SSOT(M29)— 出 3-column 表」+
|
|
27
27
|
# `packages/design-system/ds-canonical/rules/self-verify.md` Pre-edit phase
|
|
@@ -185,7 +185,7 @@ fi
|
|
|
185
185
|
|
|
186
186
|
REL_PATH=${FILE_PATH#"$GOVERNANCE_PROJECT_DIR"/}
|
|
187
187
|
|
|
188
|
-
#
|
|
188
|
+
# BLOCKER 訊息本體(hybrid:先印修法、再 exit 2;對齊 check_substantive_edit_approval_preflight.sh)
|
|
189
189
|
cat >&2 <<EOF
|
|
190
190
|
🚨 M29 DS Anchor Preflight — visual/structural edit 偵測
|
|
191
191
|
|
|
@@ -104,20 +104,20 @@
|
|
|
104
104
|
},
|
|
105
105
|
"providerLifecycle": {
|
|
106
106
|
"schemaVersion": 4,
|
|
107
|
-
"releaseVersion": "0.1.0-beta.
|
|
107
|
+
"releaseVersion": "0.1.0-beta.135",
|
|
108
108
|
"immutableHead": {
|
|
109
109
|
"providerInventorySha256": "86e9d0668cb54ad1bf05c36e78b4aa80417d5f468c929dd3ddcf69c1afbf32e4",
|
|
110
|
-
"releaseVersion": "0.1.0-beta.
|
|
111
|
-
"snapshotSha256": "
|
|
110
|
+
"releaseVersion": "0.1.0-beta.134",
|
|
111
|
+
"snapshotSha256": "684bf42d3c7a9e075f60cebce0c68d442239cda935624c4dbe8d07acbcae8fcd"
|
|
112
112
|
},
|
|
113
|
-
"ledgerSha256": "
|
|
114
|
-
"previousSnapshotSha256": "
|
|
115
|
-
"currentSnapshotSha256": "
|
|
113
|
+
"ledgerSha256": "80d4cf5f0edfc7b221880a0e236280a4a32bf3971013e9e6aa60ec811753dc89",
|
|
114
|
+
"previousSnapshotSha256": "684bf42d3c7a9e075f60cebce0c68d442239cda935624c4dbe8d07acbcae8fcd",
|
|
115
|
+
"currentSnapshotSha256": "8814d3c2a71f1eae73408864def3b566bbcb88a45377dc53a28fec00b90e7a3a",
|
|
116
116
|
"currentProviderInventorySha256": "86e9d0668cb54ad1bf05c36e78b4aa80417d5f468c929dd3ddcf69c1afbf32e4",
|
|
117
117
|
"retiredProviders": [],
|
|
118
118
|
"currentSnapshot": {
|
|
119
|
-
"releaseVersion": "0.1.0-beta.
|
|
120
|
-
"previousSnapshotSha256": "
|
|
119
|
+
"releaseVersion": "0.1.0-beta.135",
|
|
120
|
+
"previousSnapshotSha256": "684bf42d3c7a9e075f60cebce0c68d442239cda935624c4dbe8d07acbcae8fcd",
|
|
121
121
|
"providers": [
|
|
122
122
|
{
|
|
123
123
|
"id": "claude",
|
|
@@ -193,8 +193,8 @@
|
|
|
193
193
|
"retiredProviders": []
|
|
194
194
|
},
|
|
195
195
|
"immutableHeadSnapshot": {
|
|
196
|
-
"releaseVersion": "0.1.0-beta.
|
|
197
|
-
"previousSnapshotSha256": "
|
|
196
|
+
"releaseVersion": "0.1.0-beta.134",
|
|
197
|
+
"previousSnapshotSha256": "a1705fece9423f8a78302334d599428db3e364c6c8f6d7634ed639dfa2ffa7ab",
|
|
198
198
|
"providers": [
|
|
199
199
|
{
|
|
200
200
|
"id": "claude",
|
|
@@ -56,15 +56,17 @@
|
|
|
56
56
|
|------|--------|
|
|
57
57
|
| `stop_passive_logging.sh` | **Dispatcher**(2026-05-13 prune):一次跑 5 rule(tsc sanity / harvest corrections / capture metrics / governance drift / infra best-practice score)— stop hook count 3 → 2 |
|
|
58
58
|
| `stop_self_audit.sh` | turn 行為 audit(claim 沒 verify / prune trigger / topic 重複 ≥ 3 次 → BLOCKER inject,M20 100+ failure mode 升級 2026-05-13) |
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
59
|
+
|
|
60
|
+
Stop 只有上面兩支**檔案**。2026-05-13 prune 把 `stop_harvest_corrections.sh`(user 糾正信號)、
|
|
61
|
+
`stop_capture_metrics.sh`(session metric snapshot)、`stop_meta_self_audit.sh`(infra-score,
|
|
62
|
+
8 維 score 跌 ≥ 5 / 任何 dim < 80 → silent log)折進 `stop_passive_logging.sh` 的 R2 / R3 / R5,
|
|
63
|
+
**舊檔名已不存在**;要看那三條邏輯去 dispatcher 內對應的 rule function。
|
|
62
64
|
|
|
63
65
|
### SessionStart
|
|
64
66
|
|
|
65
67
|
| Hook | 做什麼 |
|
|
66
68
|
|------|--------|
|
|
67
|
-
| `session_start_governance_check.sh` |
|
|
69
|
+
| `session_start_governance_check.sh` | 多個 check(行數 / prune 逾期 / corrections / benchmark 新鮮度 / fire-weighted test gap / scan-similar-bugs / hook 數 / memory 數 / branch sprawl / counter drift / cross-repo smoke)。**數量與門檻不在本檔硬寫** — 以該腳本的 `^# Check N` 段落與 AGENTS.md `# 治理 canonical` 為準 |
|
|
68
70
|
|
|
69
71
|
### UserPromptSubmit
|
|
70
72
|
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
# Detection:scan transcript 過去 ~30 turns:
|
|
22
22
|
# (a) 有 Grep / Read tool call hit `packages/design-system/src/**/*.spec.md` OR
|
|
23
23
|
# `**/*.stories.tsx`(canonical baseline) → PASS
|
|
24
|
-
# (b) 無 →
|
|
24
|
+
# (b) 無 → P0 BLOCKER(exit 2),並在 stderr 印出「grep canonical → 3-column owner table」的修法。
|
|
25
25
|
#
|
|
26
26
|
# 對齊 meta-patterns.md M29 「視覺/結構 propose 前必 grep DS spec.md 找 owner SSOT(M29)— 出 3-column 表」+
|
|
27
27
|
# `packages/design-system/ds-canonical/rules/self-verify.md` Pre-edit phase
|
|
@@ -185,7 +185,7 @@ fi
|
|
|
185
185
|
|
|
186
186
|
REL_PATH=${FILE_PATH#*/my-project/}
|
|
187
187
|
|
|
188
|
-
#
|
|
188
|
+
# BLOCKER 訊息本體(hybrid:先印修法、再 exit 2;對齊 check_substantive_edit_approval_preflight.sh)
|
|
189
189
|
cat >&2 <<EOF
|
|
190
190
|
🚨 M29 DS Anchor Preflight — visual/structural edit 偵測
|
|
191
191
|
|
|
@@ -217,12 +217,12 @@ elif [ -d "$HOOKS_DIR" ]; then
|
|
|
217
217
|
2>/dev/null | wc -l | tr -d ' ')
|
|
218
218
|
HOOK_COUNT=${HOOK_COUNT:-0}
|
|
219
219
|
fi
|
|
220
|
-
# 2026-08-05
|
|
221
|
-
#
|
|
222
|
-
#
|
|
223
|
-
#
|
|
220
|
+
# 現值**不在此硬寫**:本檔曾同時留下「59、headroom=1」(2026-08-05 註解)與「已為 60、零 headroom」
|
|
221
|
+
# (2026-07-31 訊息字串)兩個互相矛盾的庫存數,兩個都會過期。真值一律由下方 find predicate 當場算,
|
|
222
|
+
# 或 `npm run sync:counters` 跑出;60 是邊界不是基準,下一支 first-class hook 必先由
|
|
223
|
+
# /knowledge-prune retire / consolidate 既有 hook 騰出空間。
|
|
224
224
|
if [ "$HOOK_COUNT" -gt 60 ]; then
|
|
225
|
-
BLOCKERS="${BLOCKERS}\n- Hook count ${HOOK_COUNT}(hard 60 — Anthropic guideline ~15;含 root + lib/,排 retired/tests
|
|
225
|
+
BLOCKERS="${BLOCKERS}\n- Hook count ${HOOK_COUNT}(hard 60 — Anthropic guideline ~15;含 root + lib/,排 retired/tests/ 與 _* helper)。超 60 = 先跑 /knowledge-prune 評估 retire / consolidate,不直接 re-raise。"
|
|
226
226
|
elif [ "$HOOK_COUNT" -gt 26 ]; then
|
|
227
227
|
# 2026-05-15 raised soft cap 25→26 per /knowledge-prune D2 audit:
|
|
228
228
|
# 26 wired hooks reflects M30 wrapper-schema-drift 新增 dedicated hook(justified evolution
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
| **DataTable scroll**(3-region synced + cross-OS scrollbar)| `data-table.spec.md:245-251` | 「center body 用 native overflow-x-auto(非 ScrollArea),pinned column 三 region 同步」 | ✅ aligned(v15.13 interim CSS parity for Windows Bug H,deferred ScrollArea full migration)| 2026-04-30 / 2026-05-07 |
|
|
23
23
|
| **Cell view vs edit content position**(picker offset)| `field.spec.md`「Layout Family 4」段 + `data-table.spec.md`「Body cell internal」row | 「Field control view + edit 共用同 wrapper geometry(Model A:view×default = edit 幾何減 chrome,保留 px/py)」 | ✅ aligned:DataTable cell 場景走 Field naked(`showDisplayEndIcon` opt-in);standalone `mode="view"` 走 view×default = edit 幾何減 chrome(2026-07-16 Model A,原 bare-span deferral 已兌現;值內容層 4-mode 共享 renderer,見 select.tsx 檔頭 `@renderer-symmetry-allow`)| 2026-05-07~08 round 1-5 → 2026-07-16 Model A resolved |
|
|
24
24
|
| **Field state machine focus dominates**(v13.3)| `field-wrapper.tsx` cva compoundVariants + `field.spec.md`「focus dominates」段 + `check_field_family_invariants.sh` A.3 | 「focus dominates everything;naked 不寫平行 outline ring」 | ✅ aligned;hook A.3 enforce | 2026-05-06 v9-v13.3 5 round refinement |
|
|
25
|
-
| **Protected solo workflow**(1 task = 1 branch + 1 PR / required CI / standing engineering delegation)| `infra/governance/release-workflow.json` + `feedback_solo_dev_workflow.md` + AGENTS.md
|
|
25
|
+
| **Protected solo workflow**(1 task = 1 branch + 1 PR / required CI / standing engineering delegation)| `infra/governance/release-workflow.json` + `feedback_solo_dev_workflow.md` + AGENTS.md「# Git / release canonical」 | protected main 禁 direct push;PR 建立正常;required CI/conversations resolved **且 user 對當前 PR head 說過「發版」**後,由 `release:auto` 走 `pr-checks → merge → publish → readback → consumer`(缺同意收據會停在 `AWAITING_USER_RELEASE_CONSENT`;規則 SSOT = AGENTS.md「# Git / release canonical」1.5);preview/canary/attestation 非 blocking | ✅ aligned(M28 + hooks + GitHub ruleset)| 2026-07-20 migration / 2026-08-02 five-step reconciliation |
|
|
26
26
|
| **Wrapper-vs-primitive schema unify**(SelectOption / MenuItemProps 等)| `SelectMenu/select-menu.tsx` SelectMenuOption + `Combobox/combobox.tsx` extends + `PeoplePicker/people-picker.tsx` extends | 「wrapper API schema 必 `extends primitive`,wrapper 內部 mapping 必 forward 全 primitive surface field(M30)」 | ✅ aligned(2026-05-10 Round 1 commit `561945b` Combobox extends + forward 全 field;PeoplePicker 對齊 + hook `check_wrapper_primitive_schema_drift.sh` BLOCKER)| 2026-05-10 M30 codify |
|
|
27
27
|
| **空值顯示符號 + 分流**(empty value display)| `field-context.ts` `useFieldEmptyDisplay()`(分流 hook)+ `field-wrapper.tsx` `EMPTY_DISPLAY = '-'`(半形常數)+ `field-controls.spec.md`「null / undefined 值」段 | 「符號 = 半形 hyphen `-`(U+002D),**非**全形 em dash;`surface==='table-cell' && isEditable ? '' : '-'`;可編輯 form edit 走 native placeholder。全 Field family 空值渲染必經 hook,consumer 禁直引 `EMPTY_DISPLAY`」 | ✅ aligned(2026-07-08 user 拍板半形;hook `check_field_family_invariants.sh` A.6 BLOCKER — 禁非 owner 直引常數 + 禁 hardcode 全形 em dash;DescriptionList / ProfileCard / FileViewer consumer 同步半形)| 2026-07-08 user directive |
|
|
28
28
|
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
|
|
36
36
|
## 與 hook 關係
|
|
37
37
|
|
|
38
|
-
- `check_ds_anchor_preflight.sh`(live,P0 BLOCKER exit 2,2026-07-07 升級)— 偵測 production tsx / apps consumer 內 DS primitive wrap 而無 canonical read trace → block;bypass `
|
|
38
|
+
- `check_ds_anchor_preflight.sh`(live,P0 BLOCKER exit 2,2026-07-07 升級)— 偵測 production tsx / apps consumer 內 DS primitive wrap 而無 canonical read trace → block;bypass `GOVERNANCE_BYPASS_DS_ANCHOR=1`(audit-logged)
|
|
39
39
|
- `check_field_family_invariants.sh` A.3 — 機械化 enforce v13.3 SSOT
|
|
40
40
|
- `check_pattern_invariants.sh` C.4 — 機械化 enforce row slot SSOT
|
|
41
41
|
- `check_canonical_propagation.sh` E.2 — 機械化 enforce L3 primitive import
|
|
@@ -27,7 +27,7 @@ paths:
|
|
|
27
27
|
|
|
28
28
|
| | Canonical/provider bootstrap | Canonical rules |
|
|
29
29
|
|---|---|---|
|
|
30
|
-
| 載入時機 | 每 session start 載入(
|
|
30
|
+
| 載入時機 | 每 session start 載入(行數預算見 `AGENTS.md`「行數預算」,本檔不硬寫數值)| 支援 path scope 的 adapter 於編對應 file 時載入;其他 provider 按 index 讀取 |
|
|
31
31
|
| 內容 | 6 mindset + 治理 / 稽核 / SSOT canonical / 任務導航 / fundamental rules | 該 file family 細節規則(spec 撰寫 / UI 開發 / story / self-verify)|
|
|
32
32
|
|
|
33
33
|
## 新增 rule 流程
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
| **M7** | **新 protocol / skill / rule 寫完,必反向 cross-check 既有 Meta-Principle 是否該套用**。尤其:consistency-class 的 protocol 必走「一致性類稽核必先全掃再判」(本章節);audit skill 必加「Self-improvement capture」Phase F step;Rule 觸及「canonical」「SSOT」「rationale」keyword → 必明示 substantive vs 表達層分權。**+ Sub-rule M34 (folded 2026-05-22)**:Hook detection regex 必對齊 spec wording 廣度。Triple test before merge new hook — (1) Spec rule wording 是「一般類別」(broad)還是「特定 keyword」(narrow)?(2) Hook regex 匹配「一般類別」還是只「特定 keyword subset」?(3) Spec broad + Hook narrow → **gap**,必擴 hook regex(unicode pattern / negative-list approach / counter-example DS-wide scan)。Propose 新 hook 必先寫 3-column table:`Spec wording` / `Hook regex` / `Gap?(broad-vs-narrow)`。 | principle-audit-protocol v1 漏套既有 Phase 0 全掃;2026-05-17 story name `照妳` `決策N` 等中英人話 detection regex 漏 |
|
|
48
48
|
| **M8** | **訂立 / 修改 cross-component canonical 前必 world-class benchmark**。任何 predicate / decision tree / taxonomy 類 spec,**必先 grep 至少 3 家世界級 DS**(Polaris / Material / Atlassian / Ant Design / Carbon / Apple HIG / VS Code / Figma 等)列對照表,再訂 rule。**絕對禁止**憑直覺開場寫 predicate,user 問才補對照。每個 category / variant / case 必附世界級 reference(實作名或 API 指向);沒有對照的 rule 視同未成熟,工程 rule 先擴大 research,task/deliverable 明確要求 peer 時才因缺 review 標 `REVIEW-BLOCKED`;只有採用 OG-only 產品/UI/UX原則是真人決策。 | item-anatomy Inline Action 疊代 4 次才有世界級對照 |
|
|
49
49
|
| **M9** | **Predicate / decision tree 寫完,present 前必 4 題自測**,防 membership drift。(a) 每 example 回跑決策樹;(b) cap / constraint cross-check;(c) 每 example 對 ≥3 家 world-class DS;(d) 每 category ≥1 example。任一題失敗 → 重收斂,**禁止 present**。 | Cat 1 IA 塞 endAction / FileItem sm 違 ≤24 cap |
|
|
50
|
-
| **M10** | **Proactive exhaustive scan**:canonical migration 完成前禁止只改「直覺相關」元件;final report 前禁止省略「我知道但沒講」的 tech debt。**Mechanical 落地**:batch-end(session ≥2 fix commits)跑一次 `/scan-similar-bugs` grep DS-wide(2026-05-12 per-fix → batch-end 重構);`session_start_governance_check.sh` Check 6 偵測 24h 內 fix commit 漏跑 → soft 提醒。**+ Sub-rule 掃描不得截斷(2026-08-07)**:盤「誰在讀這個值 / 誰呼叫這個函式」時,grep 一律**禁接 `head -N` / `-m`** —— 截斷是假陰性,會把還有人讀的東西誤判成死狀態而刪掉。要收斂輸出改用 `-l`(只列檔)或 `\| wc -l` 先看總數,確認總數後再全看。同理 `cmd \| head` 的 exit code 屬於 head,`&&` 分支會報出相反結論,判斷成敗必看 `PIPESTATUS`。**刪除/歸零任何欄位前,必須先把 reader 清單列完整**,只查到一個入口就下結論 = 違反。**+ Sub-rule 自檢不得只做單句層級(2026-08-09)**:任何「全盤檢查/稽核/確認沒問題」都必須跑**兩個維度**——(1) **逐句驗證據**(cite/數字/引文逐字);(2) **全體結論兩兩相容性**——把文件所有結論列成清單,逐對問「這兩條能同時為真嗎」。只做 (1) = **假檢查**,因為矛盾在單句層級恆為隱形(每句單看都成立)。且**任何一旦成立的結論必須當場登記進該文件的結論總帳**——沒登記的結論會在後續回合被重新當成未決題辯論。 | dismiss migration 漏 FileViewer / 7 題 silent tech debt user 一次炸;2026-08-07 grep 接 head 截斷 = 假陰性鎖死升級路線;2026-08-09 結論未入總帳 → 兩輪無謂辯論(詳 historical-bugs.md) |
|
|
50
|
+
| **M10** | **Proactive exhaustive scan**:canonical migration 完成前禁止只改「直覺相關」元件;final report 前禁止省略「我知道但沒講」的 tech debt。**Mechanical 落地**:batch-end(session ≥2 fix commits)跑一次 `/scan-similar-bugs` grep DS-wide(2026-05-12 per-fix → batch-end 重構);`session_start_governance_check.sh` Check 6 偵測 24h 內 fix commit 漏跑 → soft 提醒。**+ Sub-rule 掃描不得截斷(2026-08-07)**:盤「誰在讀這個值 / 誰呼叫這個函式」時,grep 一律**禁接 `head -N` / `-m`** —— 截斷是假陰性,會把還有人讀的東西誤判成死狀態而刪掉。要收斂輸出改用 `-l`(只列檔)或 `\| wc -l` 先看總數,確認總數後再全看。同理 `cmd \| head` 的 exit code 屬於 head,`&&` 分支會報出相反結論,判斷成敗必看 `PIPESTATUS`。**刪除/歸零任何欄位前,必須先把 reader 清單列完整**,只查到一個入口就下結論 = 違反。**+ Sub-rule 自檢不得只做單句層級(2026-08-09)**:任何「全盤檢查/稽核/確認沒問題」都必須跑**兩個維度**——(1) **逐句驗證據**(cite/數字/引文逐字);(2) **全體結論兩兩相容性**——把文件所有結論列成清單,逐對問「這兩條能同時為真嗎」。只做 (1) = **假檢查**,因為矛盾在單句層級恆為隱形(每句單看都成立)。且**任何一旦成立的結論必須當場登記進該文件的結論總帳**——沒登記的結論會在後續回合被重新當成未決題辯論。 | dismiss migration 漏 FileViewer / 7 題 silent tech debt user 一次炸;2026-08-07 grep 接 head 截斷 = 假陰性鎖死升級路線;2026-08-09 結論未入總帳 → 兩輪無謂辯論(詳 historical-bugs.md);**2026-09-18/19 只修同族一條還明文寫「另一條不變」→ 隔天被同一種方式咬**:CI 比值閘的「長工單一最長」因尾端噪音誤紅,改成比合計時同一段註解寫下「frameGap 那條不變」,隔天 frameGap 就在**零個執行期檔案改動**的 commit 上誤紅(同一份建置量到 215 與 311,尾端散布 ±45% > 門檻 ±25%)。修任一條有同族的缺陷時,**必當場列出同族全部呼叫點逐一判定**,不得只改觸發的那一個;「另一條不變」這種話出現在 commit 裡就是沒掃完的訊號 |
|
|
51
51
|
| **M11** | **User-perspective interactive state walk**:改完 UI 後 present 前必親自走 7 題 self-test(static / hover / focus-visible / active / keyboard / 範例真實性 / CSS 對稱)。每 UI 改動未跑 7 題就 commit = 違反。 | ListBody 修完 user 連抓 5 波 |
|
|
52
52
|
| **M12** | **Binary strict rule + fix-time root-invariant pre-question(「必 X」/「禁 Y」/ bug fix)前必 benchmark + invariant test**。3 題自測:≥3 家世界級一致 / counter-example scan / root invariant vs surface observation。震盪症狀(A→not A→A)= meta invariant 沒抓到,**停下 present**。**Fix-time 延伸**(2026-05-12 absorbs 原 M32(b)):visual / behavior bug 改前必 inline 答 3 題 — Q1「root invariant 是什麼?」Q2「symptom 在哪 layer?」Q3「fix 是 root-layer 還是 surface-layer?」。surface-only 修(改 symptom 不動 invariant)違反。對齊 5-whys / Toyota TPS / Linux kernel「fix the root not symptom」canonical。 | hover bg 震盪 4 次(bg-edge vs content-padding invariant);2026-05-12 cell-align fix surface-modify Field padding 不動 inline-flex `!h-full` root invariant |
|
|
53
53
|
| **M13** | **User 第 2 次提相關問題 → 自動截圖 verify**。當 user 就同一視覺 / 行為主題第 2 次問 / 糾正,AI 必 invoke 截圖 verify(`visual-audit.mjs --scope=component:XXX`)。第 3 次才 verify = 違反。**Corollary**:user 指定「所有 X 都要 Y」,同 session 全部做完 + 建 hook 防線。 | avatar-NameCard migration 分批拖延 user 第 2 次催才全改 |
|
|
@@ -64,8 +64,8 @@
|
|
|
64
64
|
| **M24** | **State 顯著性 precedence:disabled > muted > emphasis**。元件在 disabled state 時,內部所有文字載體(label / value / placeholder / icon)統一切 disabled token(`text-fg-disabled` neutral-6),**不**繼續 muted token(`text-fg-muted` neutral-7)。muted 是裝飾,disabled 是語意 state — state 勝 emphasis。同理:error / warning state 內 placeholder 應對應 state token。Hook `check_field_family_invariants.sh` A.4(原 check_disabled_placeholder_color folded,live P1 stderr)。 | 2026-05-04 5+ violation:`bareInputStyles` 永遠 muted / `select.tsx` 3 處 plain&tag empty 不分 mode / `textarea.tsx` 同;Input.tsx 唯一做對。User 5+ 次糾正才 codify |
|
|
65
65
|
| **M25** | **Layered chain invariant 必整鏈 forward(viewport-aware overlay scroll 範例)**。Overlay surface(Popover / HoverCard / Dialog / Sheet)的 viewport-aware scroll 機制要求 root → SurfaceBody 之間**所有中間 wrapper 都 forward `flex flex-col h-full`**;任何中間 div 沒 forward → SurfaceBody flex-1 失效 → body 不 scroll。同類 chain pattern:density 透傳 / fieldCtx 鏈 / theme subtree(M3 portal 逃逸對偶)。Hook `check_pattern_invariants.sh` C.1(原 check_overlay_panel_scroll_chain folded,live P1 WARN)。 | 2026-05-04:Filter / Sort panel root `<div w-[640px]>` 無 flex-col → user 縮 viewport 時 body 不 scroll。NameCard 因自設 max-h flex-col 才繞過(無中間 wrapper) |
|
|
66
66
|
| **M26** | **Behavior / visual canonical decision 前必跑 WebFetch + WebSearch 取 ≥ 3 source,不可憑印象 propose**。M22 升級版 — M22 管「寫 spec / tsx 含 claim 必附 cite」(實作後),M26 管「propose / 決策前必先 fetch」(實作前)。Pipeline:(1) WebFetch 3 家世界級 source(Atlassian / Material / Polaris / Ant / Carbon / Apple HIG / shadcn / Radix);(2) 全 403 → WebSearch fallback 用 snippet,**明示「search-only confidence」**;(3) WebFetch + WebSearch 都失敗 → STOP propose,告知 user「無法 verify,要看 screenshot/實機」。Hook `check_propose_without_benchmark.sh`(2026-05-26 backfill — 前期 doc claim 但 file missing;UserPromptSubmit 偵測 user prompt 含 propose / visual / behavior decision keyword + 近 20 turn WebFetch/WebSearch < 2 → soft inject 提醒)。 | 2026-05-05:user 反覆糾「為什麼每次都沒 webfetch 只憑印象」— Jira drag handle / cell display 兩題我憑印象 propose 多輪;升級成硬規範 |
|
|
67
|
-
| **M28** | **Git ops 必先 grep canonical**(mindset #2 AI-ops 子規則)。AI 執行 branch/PR/merge/release ops 前必讀 `governance/memory/feedback_solo_dev_workflow.md` + `AGENTS.md # Git / release canonical`。鐵律:1 task = 1 working branch + 1 PR;protected main 禁 direct push;PR 建立是正常路徑;standard release 只走 `infra/governance/release-workflow.json`
|
|
68
|
-
| **M29** | **DS Anchor Preflight invariant — 視覺 / 結構 propose 前必 grep `*.spec.md` 找 owner SSOT**。動 component / pattern / token 視覺結構前,**必先**:(a) `rg <touched component> + <behavior keyword>` in `packages/design-system/src/**/*.spec.md` (b) 出 **3-column owner table**(`candidate owner spec` / `canonical sentence/table row` / `conflicting code/comment if any`)(c) 若 spec ≠ code → STOP 寫 RFC 不直接 propose implementation。沒 3-column = anti-pattern,提案不被接受。SSOT index `packages/design-system/ds-canonical/references/ssot-index.md`(high-risk interface owner mapping)Step 0.1 先查再 grep verify。Hook `check_ds_anchor_preflight.sh` P0 BLOCKER(exit 2,2026-07-07 升級;bypass
|
|
67
|
+
| **M28** | **Git ops 必先 grep canonical**(mindset #2 AI-ops 子規則)。AI 執行 branch/PR/merge/release ops 前必讀 `governance/memory/feedback_solo_dev_workflow.md` + `AGENTS.md # Git / release canonical`。鐵律:1 task = 1 working branch + 1 PR;protected main 禁 direct push;PR 建立是正常路徑;standard release 只走 `infra/governance/release-workflow.json` 的五步,由 `release:auto` 續跑 —— **但合併前有一道發版同意閘**(user 對當前 PR head 說「發版」才落 receipt;缺則停在 `AWAITING_USER_RELEASE_CONSENT`)。五步與同意閘的散文 SSOT = `AGENTS.md`「# Git / release canonical」,本條不重述。Hook `check_solo_workflow.sh` 只機械攔 R1 第二 branch / R2 direct-main push;retired tag-preflight、preview/canary、attestation、soak、fleet ceremony 不得回到 blocking graph。Break-glass override audit-logged,仍不能繞 GitHub ruleset。 | 2026-05-08 的 branch/PR sprawl促成機械化;2026-07-20 保留一任務一分支與 protected PR;2026-07-26 淘汰 chat-keyword gate,2026-08-02 再移除 retired local tag-preflight branch。 |
|
|
68
|
+
| **M29** | **DS Anchor Preflight invariant — 視覺 / 結構 propose 前必 grep `*.spec.md` 找 owner SSOT**。動 component / pattern / token 視覺結構前,**必先**:(a) `rg <touched component> + <behavior keyword>` in `packages/design-system/src/**/*.spec.md` (b) 出 **3-column owner table**(`candidate owner spec` / `canonical sentence/table row` / `conflicting code/comment if any`)(c) 若 spec ≠ code → STOP 寫 RFC 不直接 propose implementation。沒 3-column = anti-pattern,提案不被接受。SSOT index `packages/design-system/ds-canonical/references/ssot-index.md`(high-risk interface owner mapping)Step 0.1 先查再 grep verify。Hook `check_ds_anchor_preflight.sh` P0 BLOCKER(exit 2,2026-07-07 升級;bypass GOVERNANCE_BYPASS_DS_ANCHOR=1 audit-logged)。codex-collab/SKILL.md Step 0.1 mandatory pre-grep。對齊 Carbon「design spec is source of truth」+ Atlassian「system-wide coordination first」。 | 2026-05-08:Claude+Codex 連 5 round 跳過 spec anchor pre-grep,直覺加 primitive(D path / Path A);user 抓「為何沒研讀設計原則」 |
|
|
69
69
|
| **M30** | **Wrapper-vs-primitive schema unify invariant — wrapper API option / config schema 必 `extends` primitive SSOT,且 wrapper 內部轉換 mapping 必 forward 全 primitive surface field**。Primitive(`SelectMenuOption` / `MenuItemProps` / `ItemAnatomyProps` 等)宣告 SSOT 後,所有 wrapper(`Select.SelectOption` / `Combobox.SelectOption` / `PeoplePicker` 等)若有同類 schema,(a) 用 TypeScript `extends primitive` 機械繼承,**不可平行 declare** weak schema(同名 / 部分欄位)(b) wrapper 內部 `xxxToYyy()` mapping 必 forward 全 primitive surface field(不可只 forward `value` + `label`,silently drop avatar / description / disabled 等)(c) wrapper-only field 加在 `extends body`(不污染 primitive)。Hook `check_wrapper_primitive_schema_drift.sh` 機械強制(P0 BLOCKER):grep `export interface .*Option \{` cross components/,同名 ≥ 2 處且未 `extends` primitive → BLOCK。對齊 Polaris ChoiceList / Material Autocomplete / Carbon Dropdown wrapper-vs-primitive schema-extension idiom。 | 2026-05-10 PeoplePicker weak schema 漏 avatar,mapping 只 forward 2 fields(詳 historical-bugs.md) |
|
|
70
70
|
| **M32** | **Audit script 必 pixel-quantified verify ≠ attribute existence**(2026-05-12)。Audit 必驗 `rect.top / .left / .height` numeric pixel,**不**可只驗 `getAttribute('data-state')` / `class.includes(...)` = false-positive trap(DOM-pass ≠ visual-pass)。對齊 Material X-DataGrid / AG Grid playwright pixel snapshot / Polaris visual diff canonical。Hook `check_pixel_quantified_audit.sh` 機械強制(scans `getAttribute(` without paired `getBoundingClientRect(`)。**+ Sub-invariant(2026-05-30,doc-claim layer)**:story/anatomy/a11y/spec 的**文字宣稱 ≠ code 真實**——audit 必 adversarial **讀元件 .tsx +(其 wrap 的 Radix/cmdk/react-day-picker 等 lib)source**,逐句驗 keyboard map/ARIA role/focus 行為/prop 存在性/native-vs-custom;prose-skim「looks fine」= false-pass(prose-pass ≠ source-verified)。**「無 code 改動」≠ 可跳過**。`/deep-audit-cross-codex` A.1b + CP-A1b + report-validator F 機械強制。Anchor:2026-05-30 獨立 adversarial 抓 403 findings/64 單元/202 FALSE_CLAIM(前期 prose-skim story dim 全漏);prop-existence deterministic detector 因 passthrough over-flag 證實此類本質需 LLM 讀 source → 用 mandatory-dim + report-validator 保證真跑。**+ Sub-invariant「儀器要先有對照組」(2026-09-08 folded,absorbs 4 bugs)**:任何量測/閘在拿它的**綠燈**當證據前,必須先證明它**在該紅的時候會紅** —— 把被驗的東西弄壞一次,看它是否指名該處,再還原。缺這一步的綠燈是零證據。四個錨(同一天):(a) 22 支瀏覽器腳本因缺沙箱參數永遠回 `SKIPPED-ENV`,332 條不變式從沒真的跑過;(b) 自己寫的 C5/G2 測試假綠(抓到鎖定欄、用滿捲位置),補對照組才發現;(c) `transition-colors` 的 transition-property 含 `outline-color`,聚焦後立刻量抓到過渡中間值,差點寫成「全 DS 焦點框失效」;(d) 本輪新建的 7 組閘 `grep -rl <name> .github` 回 **0** —— 從沒被 CI 呼叫,跟 ci.yml 註解裡記過兩次的 distribute-column-widths / pagination 同一種病;(e) Playwright headless 預設帶 `--hide-scrollbars`,任何量捲軸厚度的探針永遠得 0 —— Bug H(Windows 捲軸溢出)五個月沒人量到就是這樣,要 `ignoreDefaultArgs` 拿掉再用根規則 `::-webkit-scrollbar{width:17px}` 造 Windows 幾何(2026-09-08);(f) 同頁多個目標逐一 `scrollIntoView` 後,先前算好的視窗座標拿去截圖是**全白** —— 截圖前一刻才對該元素重算(同日)。(g) **headless Chromium 的 rAF 被釘在 16.7ms**,連故意把每列加上 box-shadow+blur 都不動,CPU 降速 6 倍也不動 —— 任何「每幀時間」類量具在 headless 一律無效,綠燈是零證據;同一天建了兩版都被自我檢查判死(2026-09-15)。要量幀時間只能在真瀏覽器(而且分頁必須是可見的,背景分頁 rAF 不跑);headless 改用 CDP `Tracing`(看光柵/主執行緒任務)或 `LayerTree.profileSnapshot`(光柵成本),那兩個會紅。(h) **跨網域/跨主機的效能比較無效;先歸因再消融**(2026-09-15,兩天教訓):user 機器「main 17ms / 分支 33ms」追了兩天、DS 內部消融七項全 33、本機永遠重現不出 —— 最後用 Long Animation Frames API 在他機器上看長幀 `scripts[].sourceURL`,5301ms 全在 `thin-client-min.js`(那台機器的網路/安全產品對 `*.netlify.app` 注入的遠端隔離 thin client),而 main 在 github.io 是白名單本地渲染、main 放到 Netlify 一樣慢。**唯一變數是網域**。機械問法:(1) A/B 兩頁同網域嗎?(2) 長幀裡的 script 來源是我們建置裡的檔嗎?兩題沒答完前,任何消融都是白做(`governance/memory/reference_perf_validation_same_host.md`)。**機械化問法**:寫完任一閘立刻問三題 —— 「弄壞它會紅嗎(跑一次)」「誰呼叫它(grep CI)」「它的量測值會不會受動畫/時序影響(等穩態再量)」。**Split note**:原 mega 8 sub-invariants 拆 4 home — (b) fix-time root-invariant → M12 extension / (c)(d)(h) batch + parallel + claim-verify → `/bug-fix-rhythm` skill / (e) tool preflight(CLI binary 必跑 4-test discovery:which / npx / package.json / auth.json,禁短路「not installed」假警報)— 原 memory `feedback_tool_binary_preflight_sweep.md` 已 retire,invariant 一行收容於此 / (f) ship gate → AGENTS.md `# 稽核 canonical` / (g) Layer marker → M31 + hook。git blame 2026-05-12 commit 留 audit trail。 | 2026-05-12 4 audit-vs-visual gap absorbed:cell-align / divider 2px / breadcrumb tooltip / row-alignment 全 audit「Δ=0 ALL PASS」但 user 抓視覺壞(詳 historical-bugs.md)。|
|
|
71
71
|
| **M31** | **Provider-adaptive adversarial two-track 5-step canonical**。**Activation boundary**:只有 task/deliverable 明確要求 independent review 時才啟動;exact run waiver 必記 receipt,optional review 缺席不得阻擋一般工程、deep audit 或 standard release。執行 authority = `packages/design-system/ds-canonical/skills/independent-review/SKILL.md` / `deep-audit-cross-codex/SKILL.md` + `packages/governance/canonical/providers.json` + `packages/governance/src/provider-review-binding.mjs#resolveProviderReviewBinding`;skill 舊名稱只保留 discovery compatibility,不指定 reviewer。**Step 0 入口 gate**:啟動後 primary author 先完成獨立 Phase A,再由 resolver 選出不同 provider、不同 context、read-only、已認證的 peer;無可用 peer/transport/certification/evidence = required-review claim `REVIEW-BLOCKED`,禁止同模型或同 context 假扮 second opinion。**Step 1-5**(啟動後每題必過):(1)兩方各自在隔離 context 熟讀相同完整 inventory/spec/canonical/source,NO-SAMPLE;(2)兩方各自驗證 deterministic gates + applicable runtime/visual evidence,不可只一方 verify;(3)需要視覺判斷時兩方各自執行 target-bound browser/DOM/pixel 稽核;(4)每個 finding 都附 owner path/精確證據/reasoning,未證實即撤回;(5)closed synthesis 比較兩份 content-addressed artifact,agree 時補齊缺漏,disagree 時以 canonical evidence 較強者勝,保留 unresolved,不得 pass-through。legacy-named compatibility hook `check_codex_collab_5step.sh` 只檢查流程證據,不是 provider 或 transport authority。對齊 RFC 學術同儕審查 / Linux kernel-mailinglist cite source / Google ML eng-design-review。 | 2026-05-10 的 pass-through 事故證明「拿 peer 結論代替 primary 驗證」會造成 drift;後續 cite battle 以 `field-controls.spec.md` + `item-anatomy.spec.md` 找回雙 owner,現已抽象成 provider-neutral second-opinion invariant。 |
|
|
@@ -69,12 +69,16 @@
|
|
|
69
69
|
- **判斷法**:這條規則能「機械化在 tool 執行前後自動跑」嗎? 是 → canonical hook + `registrations.json`;否 → canonical rule 或 spec
|
|
70
70
|
- **當前 inventory**:以 `packages/design-system/ds-canonical/hooks/registrations.json`、canonical hook tree 與 `scripts/sync-governance-counters.mjs --check` 動態結果為準;本文件不硬寫數量或複製 hook 清單。
|
|
71
71
|
|
|
72
|
-
### Level 8 — Command workflow (`packages/design-system/ds-canonical/commands/*.md`)
|
|
73
|
-
|
|
74
|
-
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
72
|
+
### Level 8 — Command workflow (`packages/design-system/ds-canonical/commands/*.md`)— **相容層,不是新居民的去處**
|
|
73
|
+
|
|
74
|
+
- **現狀**:居民 0。各家 agent runtime 已把單步 command 併進 skills 面,新的 `/<name>` 一律由同名 skill 提供。
|
|
75
|
+
此判準與該 home 自己的 charter(`ds-canonical/commands/README.md`)一致 —— 兩邊曾分歧:本表原本把
|
|
76
|
+
Level 8 寫成「重複使用 ≥ 3 次就放這」的活躍去處,charter 卻寫「只保留舊 consumer 的相容 pointer」。
|
|
77
|
+
以 charter + 空 inventory 為準。
|
|
78
|
+
- **唯一還可以留在這裡的東西**:外部 consumer 仍固定呼叫舊路徑時的 thin pointer,且必須只是同名 skill 的
|
|
79
|
+
指標,不得持有第二份 substantive workflow。
|
|
80
|
+
- **新增單步 action 的正確去處** → Level 7 Skill(單步就是只有一個 step 的 skill,不需要另一個 home)
|
|
81
|
+
- **inventory**:以 canonical commands 目錄實況為準,本文件不硬寫數量
|
|
78
82
|
|
|
79
83
|
### Level 9 — Planning (`governance/planning/`)
|
|
80
84
|
|
|
@@ -67,7 +67,9 @@ Output: 「`check_sideoffset_canonical.sh`(retired;已移入 hooks/retired/,此
|
|
|
67
67
|
|
|
68
68
|
#### 2c. Pending corrections → codify 候選
|
|
69
69
|
|
|
70
|
-
`user-corrections.jsonl`
|
|
70
|
+
`user-corrections.jsonl` 未 codify 數超過門檻 = user 反覆糾正類似錯誤,該升級到 canonical。
|
|
71
|
+
**門檻不在本檔硬寫**(同檔 Phase 2 表格曾寫 20、此處曾寫 10,兩個都會漂):唯一 SSOT 是
|
|
72
|
+
`session_start_governance_check.sh` Check 3 的 `-gt` 判斷(現行 soft 20 / hard 40)。
|
|
71
73
|
|
|
72
74
|
Output: 「過去 4 週 user 糾正 15 條,sample: ..., 提議:升級 M19「XX pattern」或擴充 `# Meta-Pattern 預警`」
|
|
73
75
|
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"type": "git",
|
|
5
5
|
"url": "git+https://github.com/ajenchen/design-system.git"
|
|
6
6
|
},
|
|
7
|
-
"version": "0.1.0-beta.
|
|
7
|
+
"version": "0.1.0-beta.135",
|
|
8
8
|
"private": false,
|
|
9
9
|
"description": "World-class design system — components, patterns, tokens, hooks (single source of truth for team distribution).",
|
|
10
10
|
"type": "module",
|
|
@@ -114,9 +114,9 @@ SMIL keySplines 無法消費 CSS var,`agent-panel-logo.tsx` 內常數為 swell/s
|
|
|
114
114
|
M23(f)「無內建行為的 callback 一律必填 prop(型別層擋)」必為必填。鍵盤路徑不變(Esc 照舊)。
|
|
115
115
|
- **遮罩** = `lib/overlay-coexistence.ts` 的 `CoexistenceMask`,與並存 Dialog 同一層 `z-30`、同一顆 `--overlay`、同樣替 `persistentElements` 挖洞
|
|
116
116
|
(層級句見 `../Dialog/dialog.spec.md`「並存」段:遮罩 z-30 < 並存 modal z-40 < 代理蓋板 z-[45] < 一般 modal z-50);它是面板根節點的**兄弟**,
|
|
117
|
-
|
|
117
|
+
**接住**留白處的指標:**點它會關閉面板**(2026-09-17 裁示,見上方「與 app 的推擠與斷點」),但不會穿到底下去關掉並存的 modal 或碰到宿主
|
|
118
118
|
(2026-09-16 user 第二次回報:第一版遮罩 `pointer-events:none`,點擊穿過去打到 modal 的外部點擊偵測、把 modal 關掉;修法 = 遮罩在面板的保留集合裡、
|
|
119
|
-
modal 的外部點擊守衛把常駐殼子樹裡的目標視為不關,Dialog 遮罩算洞時「遮罩不是洞」)
|
|
119
|
+
modal 的外部點擊守衛把常駐殼子樹裡的目標視為不關,Dialog 遮罩算洞時「遮罩不是洞」);面板的關閉有三條路(× / 入口鈕 / 蓋板態點遮罩,見「Esc 與關閉語意」);
|
|
120
120
|
- **淡入** = 與面板同相的 `--motion-duration-surface`(見「動畫總表」),偏好減少動態時不淡入。
|
|
121
121
|
「像 Sheet」只到外觀:面板**不是** Sheet、也不用 `SheetOverlay`(Sheet 遮罩是 z-50,會壓過並存 modal;且面板永不進 Radix 的 DismissableLayer 疊,見負向鐵律)。
|
|
122
122
|
世界級對照:各家**預設**都是點遮罩即關 —— Material Components Web dialog 的 `scrimClickAction` 預設 `close`
|
|
@@ -615,7 +615,7 @@ Esc 則是「關最內層的暫時性浮層」,面板不是暫時性浮層,所
|
|
|
615
615
|
|
|
616
616
|
- `dismissable-layer.tsx:59-61` 把 Esc 只送給疊最上層 → 面板一旦入疊,就會在「它剛好是最上層」時被 Esc 關掉,和上表第二列直接相反;
|
|
617
617
|
- 入疊還連帶吃到 `disableOutsidePointerEvents`(外點關閉)與焦點 trap,面板會從常駐 app UI 變成暫時性浮層。
|
|
618
|
-
- 蓋板態的遮罩是面板自家渲染的 `CoexistenceMask`(
|
|
618
|
+
- 蓋板態的遮罩是面板自家渲染的 `CoexistenceMask`(點擊 = 關閉面板,不是 Radix 的 dismiss 語意),**不是** Radix Overlay;「像 Sheet」只到外觀,不得改用 Sheet / SheetContent 承載面板。
|
|
619
619
|
|
|
620
620
|
因為靜默,所以配一支機械閘:`scripts/agent-panel-dismissable-layer-invariant.mjs`。
|
|
621
621
|
|
|
@@ -20,7 +20,7 @@ benchmark:
|
|
|
20
20
|
- Polaris Checkbox: github.com/Shopify/polaris/tree/main/polaris-react/src/components/Checkbox
|
|
21
21
|
---
|
|
22
22
|
|
|
23
|
-
<!-- @spec-budget-exception: SSOT-heavy 例外(`AGENTS.md`「行數預算」的 foundational SSOT 例外 ≤800-1200)— 本檔持有跨元件 SSOT:「與 Switch 的分界」(~45 行)+「Clamp 政策(Label/Description 行數)」(~35 行);2026-07-14 knowledge-prune P2 結論「殘餘超標內容全是 canonical,再砍必動 meaning」(
|
|
23
|
+
<!-- @spec-budget-exception: SSOT-heavy 例外(`AGENTS.md`「行數預算」的 foundational SSOT 例外 ≤800-1200)— 本檔持有跨元件 SSOT:「與 Switch 的分界」(~45 行)+「Clamp 政策(Label/Description 行數)」(~35 行);2026-07-14 knowledge-prune P2 結論「殘餘超標內容全是 canonical,再砍必動 meaning」(該次掃描明細留在 provider home 的 log,屬歷史 provenance,不是本例外的 authority —— 例外成立與否只看本句陳述的理由)。 -->
|
|
24
24
|
|
|
25
25
|
|
|
26
26
|
# Checkbox 設計原則
|
|
@@ -13,7 +13,7 @@ benchmark:
|
|
|
13
13
|
- Polaris Select: github.com/Shopify/polaris/tree/main/polaris-react/src/components/Select
|
|
14
14
|
---
|
|
15
15
|
|
|
16
|
-
<!-- @spec-budget-exception: SSOT-heavy 例外(`AGENTS.md`「行數預算」的 foundational SSOT 例外 ≤800-1200)— 本檔持有跨元件 SSOT:「與 RadioGroup 的分界」(~40 行)+ 3 筆拍板記錄(2026-07-13 D2 hidden-input mirror / 2026-05-21 D3 dual-mode / 2026-06-12 R2 open-pair 例外);2026-07-14 knowledge-prune P2 結論「殘餘超標內容全是 canonical,再砍必動 meaning」(
|
|
16
|
+
<!-- @spec-budget-exception: SSOT-heavy 例外(`AGENTS.md`「行數預算」的 foundational SSOT 例外 ≤800-1200)— 本檔持有跨元件 SSOT:「與 RadioGroup 的分界」(~40 行)+ 3 筆拍板記錄(2026-07-13 D2 hidden-input mirror / 2026-05-21 D3 dual-mode / 2026-06-12 R2 open-pair 例外);2026-07-14 knowledge-prune P2 結論「殘餘超標內容全是 canonical,再砍必動 meaning」(該次掃描明細留在 provider home 的 log,屬歷史 provenance,不是本例外的 authority —— 例外成立與否只看本句陳述的理由)。 -->
|
|
17
17
|
|
|
18
18
|
# Select 設計原則
|
|
19
19
|
|