@qijenchen/design-system 0.1.0-beta.46 → 0.1.0-beta.48
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/CLAUDE.md +1 -1
- package/ds-canonical/hooks/check_consumer_ds_primitive_misuse.sh +9 -0
- package/ds-canonical/hooks/check_post_main_ssot_propagate.sh +8 -6
- package/ds-canonical/hooks/check_story_invariants.sh +2 -3
- package/ds-canonical/hooks/tests/test_check_story_invariants.sh +18 -3
- package/ds-canonical/references/composition-fidelity.md +27 -81
- package/ds-story-manifest.json +1 -1
- package/package.json +1 -1
- package/src/components/Sidebar/sidebar.stories.tsx +3 -2
package/CLAUDE.md
CHANGED
|
@@ -107,7 +107,7 @@ CLAUDE.md target ≤ 200(Anthropic best-practice)/ transition ≤ 400 / hard cap
|
|
|
107
107
|
| 3 告訴 user 主要 change(or preview URL)| 讓 user 知道看什麼 |
|
|
108
108
|
| 4 等 user trigger | **「push / OK / 好 / 合 main」** → step 5;**「改 X / 不對 / 等等」** → 繼續 step 1 |
|
|
109
109
|
| 5 Squash merge to main | 不開 PR(可 GitHub API squash-merge OR fast-forward)|
|
|
110
|
-
| 5.5 **SSOT propagation gate**(2026-05-26 加 per user verbatim「push main 後所有 repo 都能獲得更新」)| Hook `check_post_main_ssot_propagate.sh` 偵測 `git push origin main` + diff HEAD~..HEAD 含 SSOT-affecting paths(`packages/design-system/src` + `packages/storybook-config/{addons,addons-preset.ts,preview.tsx}`(無 src/ dir)/ `.claude/{rules,hooks,skills,commands,references}` / `.claude-plugin/*.json` / `hooks/hooks.json` / `CLAUDE.md`)→ inject context
|
|
110
|
+
| 5.5 **SSOT propagation gate**(2026-05-26 加 per user verbatim「push main 後所有 repo 都能獲得更新」)| Hook `check_post_main_ssot_propagate.sh` 偵測 `git push origin main` + diff HEAD~..HEAD 含 SSOT-affecting paths(`packages/design-system/src` + `packages/storybook-config/{addons,addons-preset.ts,preview.tsx}`(無 src/ dir)/ `.claude/{rules,hooks,skills,commands,references}` / `.claude-plugin/*.json` / `hooks/hooks.json` / `CLAUDE.md`)→ inject context。**AI 必「全自動執行」整條發版鏈、不需 user 再問也不需 user 再確認(2026-06-02 user directive Option A verbatim「我說 push main 時,應該就一切要自動弄得完整弄得好」)**:動到 skill/hook/spec/token/CLAUDE 等 SSOT-affecting paths + user 已給 merge trigger → AI 自動 bump → preflight → tag → publish → `npm view` 驗證,全程不停下問;preflight(發版前 gate)+ `npm view`(發版後驗)= 安全網,故全自動不增風險;user 隨時可喊停。bump npm `0.1.0-beta.<N+1>`。**bump 版本後、tag 前必跑單一指令 `npm run release:preflight`**(sync version 5-manifest + sync ds-canonical + 全 deterministic gate + build + dogfood + 5-manifest verify,fail-fast,全過寫 HEAD-bound pass-marker)—— 取代舊「手動逐道跑」checklist,根治 beta.43/45 連環 push 失敗(漏 sync 步驟)。全過才 tag + push tag → Release workflow auto-fire → npm publish → ds-product-template + fork repos Dependabot daily auto-PR(整鏈 1 trigger 涵蓋所有 SSOT-affecting 來源)|
|
|
111
111
|
| 6 砍 remote branch | `git push origin --delete <branch>` ;sandbox HTTP 403 → 提醒 user GitHub UI 手動 |
|
|
112
112
|
| 7 Local 對齊 | `git checkout main && git fetch && git reset --hard origin/main && git branch -d <branch>` |
|
|
113
113
|
|
|
@@ -72,6 +72,15 @@ if echo "$CONTENT" | grep -qE '<DS\.Empty[^>]+title=' && \
|
|
|
72
72
|
VIOLATIONS="${VIOLATIONS} - <Empty title=...> 無 icon 無 description = 違反 Empty.tsx:11「預設只需 description」minimal mock looks weird\n"
|
|
73
73
|
fi
|
|
74
74
|
|
|
75
|
+
# Pattern 8: 硬寫色值 / 字級 / shadow 繞過 DS token(2026-06-02 CF conformance-model 補主防線 —
|
|
76
|
+
# composition-fidelity 從 pixel-identity 收窄成 identity-opt-in 後,「consumer 用對 DS token」改由靜態
|
|
77
|
+
# conformance 防線保證,對齊 Polaris stylelint-polaris / Atlassian eslint-plugin / Carbon stylelint。
|
|
78
|
+
# 既有 check_layout_space_magic_numbers 守「間距」;此 pattern 補「色值/字級/shadow」缺口。
|
|
79
|
+
# 零誤判優先:只抓 hardcoded(`-[var(--...)]` token 用法不匹配)。
|
|
80
|
+
if echo "$CONTENT" | grep -qE '\b[a-z][a-z-]*-\[(#[0-9a-fA-F]{3,8}|rgb|rgba|hsl|hsla)[(]?|\btext-\[[0-9]|\bshadow-(sm|md|lg|xl|2xl)\b'; then
|
|
81
|
+
VIOLATIONS="${VIOLATIONS} - 硬寫色值/字級/shadow 繞過 DS token(bg-[#hex] / text-[14px] / shadow-md)→ 改 semantic color token / text-body 等 typography token / shadow-[var(--elevation-N)](per ui-development.md「Tailwind 5 條核心」rule 3)\n"
|
|
82
|
+
fi
|
|
83
|
+
|
|
75
84
|
# Pattern 6: Overlay trigger without defaultOpen state for visual demo
|
|
76
85
|
# (Skip in production .tsx; only enforce in .stories.tsx where visual snapshot matters)
|
|
77
86
|
if echo "$FILE" | grep -qE '\.stories\.tsx$'; then
|
|
@@ -68,17 +68,19 @@ cat <<EOF
|
|
|
68
68
|
|
|
69
69
|
📊 偵測:HEAD~1..HEAD 含 $SSOT_COUNT 個 SSOT-affecting file changes
|
|
70
70
|
📦 目前 npm version:$PKG_VERSION
|
|
71
|
-
🎯
|
|
71
|
+
🎯 AI 必「全自動執行」(不需 user 再問 / 再確認 — per Step 5.5 2026-06-02 user directive Option A):
|
|
72
|
+
bump → release:preflight → tag → push tag → Release workflow → npm publish → npm view 驗證
|
|
72
73
|
→ 24h 內 product-workspace + 所有 fork repo 自動拿最新
|
|
73
74
|
|
|
74
75
|
Touched(top 5):
|
|
75
76
|
$(echo "$SSOT_DIFF" | head -5 | sed 's/^/ - /')
|
|
76
77
|
|
|
77
|
-
|
|
78
|
-
1.
|
|
79
|
-
2.
|
|
80
|
-
3. git push origin main
|
|
81
|
-
4. Release workflow auto-fire → npm publish + Dependabot
|
|
78
|
+
AI 全自動執行步驟(user 已給 merge trigger → 以下不需再問;user 隨時可喊停):
|
|
79
|
+
1. bump packages/design-system/package.json → node scripts/sync-version-to-all-manifests.mjs(同步全 5 manifest)
|
|
80
|
+
2. npm run release:preflight(全過才寫 HEAD-bound pass-marker;R4 hook 認它才放行 tag)
|
|
81
|
+
3. git tag v0.1.0-beta.<N+1> + git push origin main + git push origin v0.1.0-beta.<N+1>
|
|
82
|
+
4. Release workflow auto-fire → npm publish + Dependabot 日常 cross-repo sweep
|
|
83
|
+
5. npm view <pkg> version 驗證真上架(非看 CI 綠燈)
|
|
82
84
|
|
|
83
85
|
對應 canonical:
|
|
84
86
|
- CLAUDE.md \`# Git solo-work canonical\` Step 5.5
|
|
@@ -534,7 +534,7 @@ rule_story_baseline_reference() {
|
|
|
534
534
|
# `.claude/references/story-baseline-registry.json` antiPatterns regex,逐條 scan 寫入內容。
|
|
535
535
|
# Severity=block → record_worst 2;severity=warn → stderr only。Allowlist
|
|
536
536
|
# `// @story-baseline-allow: <reason>` 整檔豁免。
|
|
537
|
-
#
|
|
537
|
+
# 2026-06-02 升 P0 BLOCKER(block-severity antiPattern):DS + consumer 全掃確認零現有違規後升級。
|
|
538
538
|
|
|
539
539
|
rule_story_archetype_registry() {
|
|
540
540
|
case "$TOOL" in
|
|
@@ -592,8 +592,7 @@ rule_story_archetype_registry() {
|
|
|
592
592
|
echo " 修法:Read baseline story + helpers,抄 production archetype。" >&2
|
|
593
593
|
echo " 或加 \`// @story-baseline-allow: <reason>\` 檔頭豁免(audit-logged)。" >&2
|
|
594
594
|
echo " 詳 .claude/rules/meta-patterns.md M35 + memory/feedback_nearest_same_purpose_canonical.md" >&2
|
|
595
|
-
#
|
|
596
|
-
# Future:zero existing violation → 改 record_worst 2 升 P0 BLOCKER
|
|
595
|
+
record_worst 2 # 2026-06-02 升 P0 BLOCKER:DS + consumer(ds-product-template)全掃確認零現有違規後升級(原 2026-05-20 ship-as-warn 的 TODO 條件達成);只 block-severity antiPattern(warn-severity 仍 stderr-only)
|
|
597
596
|
fi
|
|
598
597
|
done <<< "$PATTERNS"
|
|
599
598
|
done
|
|
@@ -10,10 +10,11 @@
|
|
|
10
10
|
# R5 name_jargon(PostToolUse;reads disk;L<n> layer / canonical / 中英夾雜 jargon)
|
|
11
11
|
# R6 description_jargon(PostToolUse;TS generic in description: → stderr warn)
|
|
12
12
|
# R7 story_baseline_reference(PreToolUse;wrap Sidebar/ChromeHeader/DataTable 無 baseline marker → stderr warn)
|
|
13
|
-
# R8 story_archetype_registry(PreToolUse;讀 .claude/references/story-baseline-registry.json
|
|
13
|
+
# R8 story_archetype_registry(PreToolUse;讀 .claude/references/story-baseline-registry.json;
|
|
14
|
+
# block-severity antiPattern → P0 record_worst 2,2026-06-02 升 P0)
|
|
14
15
|
#
|
|
15
16
|
# Test 重點:silent skip / 各 rule fire / allowlist marker escape。
|
|
16
|
-
# 不測 R3
|
|
17
|
+
# 不測 R3(需 spec.md frontmatter);R8 P0 block-severity 已測(#11,2026-06-02)。
|
|
17
18
|
|
|
18
19
|
set -u
|
|
19
20
|
|
|
@@ -194,12 +195,26 @@ STORIES_APP="/foo/my-project/packages/design-system/src/components/AppShell/app-
|
|
|
194
195
|
run_hook "PreToolUse" "Write" "$STORIES_APP" '
|
|
195
196
|
export const Default = () => (
|
|
196
197
|
<Sidebar>
|
|
197
|
-
<SidebarHeader><
|
|
198
|
+
<SidebarHeader><WorkspaceBrand /></SidebarHeader>
|
|
198
199
|
</Sidebar>
|
|
199
200
|
);
|
|
200
201
|
'
|
|
201
202
|
expect_warn "10. R7 wrap <Sidebar> no @story-baseline → stderr warn" "R7 story_baseline_reference"
|
|
202
203
|
|
|
204
|
+
# 11. R8 archetype registry P0(2026-06-02 升 P0;DS+consumer 零違規確認後升級):
|
|
205
|
+
# wrap <Sidebar> + simplified <SidebarHeader><span> mock(registry block-severity antiPattern)→ BLOCK
|
|
206
|
+
# 有 @story-baseline marker(R7 missing-marker 不 fire)→ exit 2 純由 R8 record_worst 2 造成
|
|
207
|
+
STORIES_R8="/foo/my-project/packages/design-system/src/components/AppShell/app-shell-r8.stories.tsx"
|
|
208
|
+
run_hook "PreToolUse" "Write" "$STORIES_R8" '
|
|
209
|
+
// @story-baseline: @qijenchen/design-system/components/Sidebar/sidebar.stories.tsx#IconCollapse
|
|
210
|
+
export const Default = () => (
|
|
211
|
+
<Sidebar>
|
|
212
|
+
<SidebarHeader><span>Acme</span></SidebarHeader>
|
|
213
|
+
</Sidebar>
|
|
214
|
+
);
|
|
215
|
+
'
|
|
216
|
+
expect_block "11. R8 simplified-mock <SidebarHeader><span> → P0 BLOCK" "R8 story_archetype_registry"
|
|
217
|
+
|
|
203
218
|
echo ""
|
|
204
219
|
echo "=== Summary ==="
|
|
205
220
|
echo "Passed: $PASS / $((PASS + FAIL))"
|
|
@@ -1,101 +1,47 @@
|
|
|
1
|
-
# Composition Fidelity
|
|
1
|
+
# Composition Fidelity(SSOT,2026-05-27 初版 / 2026-06-02 conformance-model 修正)
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**目標**:驗證「DS components 在 consumer(ds-product-template / fork)被正確使用、沒違反設計原則 / SSOT token」。
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
**2026-06-02 模型修正(per CF research + world-class benchmark + 專案 2026-05-27 自身結論)**:
|
|
6
|
+
驗的是「**consumer 有沒有用對 DS(conformance)**」,**不是**「consumer 畫面跟 DS showcase 長得一模一樣(pixel-identity)」。後者對「內容刻意不同的產品範本」是 **false-positive 來源、世界級公認反 pattern**。
|
|
6
7
|
|
|
7
|
-
## 對齊世界級
|
|
8
|
+
## 對齊世界級(2026-06-02 WebFetch verified,修正初版未驗 benchmark)
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
- **Material UI X** PR snapshot gate:`mui-x` package consumer apps 用 `@mui/x-data-grid` 必過 visual snapshot
|
|
11
|
-
- **Carbon Design System**(IBM):Percy visual diff cross DS storybook + consumer-app sample
|
|
12
|
-
- **Atlassian Design System**:VR(visual regression)CI on consumer repos pulling DS
|
|
10
|
+
初版宣稱「Polaris/MUI/Carbon/Atlassian 都做 cross DS+consumer pixel diff」= **未驗證 + 不實**(M22/M26 違反)。實證(URL):
|
|
13
11
|
|
|
14
|
-
|
|
12
|
+
- **Consumer 用對 DS = 一律靜態 lint,非截圖**:Polaris [`stylelint-polaris`](https://polaris-react.shopify.com/tools/stylelint-polaris)(40+ rule promote DS adoption in consuming apps;「Please use a Polaris color token」)/ Atlassian [`@atlaskit/eslint-plugin-design-system`](https://atlassian.design/components/eslint-plugin-design-system/)(`ensure-design-token-usage` / `prefer-primitives` / `use-tokens-space`,帶 auto-fix)/ Carbon [`stylelint-plugin-carbon-tokens`](https://github.com/carbon-design-system/stylelint-plugin-carbon-tokens)(「enforce Carbon tokens ... rather than hard-coded values」)/ MUI(TS theme 型別 + eslint)。
|
|
13
|
+
- **Visual regression = 同一個 story 跨 commit 比自己的 baseline**(抓 DS 改壞自己),非跨 repo 比不同畫面:[Chromatic](https://www.chromatic.com/docs/branching-and-baselines/)(「baseline = last known good state of the story ... from a previous commit on that same branch」)/ [Storybook](https://storybook.js.org/docs/writing-tests/visual-testing)(「compare rendered pixels of every story against known baselines」+ 測 component-in-isolation)。
|
|
14
|
+
- **VR deterministic 鐵律**:seed 靜態 fixture + mask 動態區。產品 app 內容本質跟 DS showcase 不同 → 拿來 pixel 比必全紅 = 100% false positive。
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
## 機制三層(conformance 主、pixel identity 窄)
|
|
17
|
+
|
|
18
|
+
| 層 | 驗什麼 | 落地 |
|
|
17
19
|
|---|---|---|
|
|
18
|
-
| 1
|
|
19
|
-
| 2
|
|
20
|
-
| 3
|
|
20
|
+
| **1 marker(conformance 意圖)** | consumer wrap 高風險 primitive 必標 `// @story-baseline: <DS-path>#<export>` cite canonical | `check_consumer_story_baseline.sh`(P0)+ `check_story_invariants.sh` R7 |
|
|
21
|
+
| **2 靜態 conformance(主防線)** | consumer 用對 token/primitive、沒 simplified mock、沒硬寫色值/字級/間距/shadow、沒 API-misuse | `check_consumer_ds_primitive_misuse.sh`(P0,含 2026-06-02 Pattern 8 硬寫 token)+ `check_layout_space_magic_numbers.sh`(P0 間距)+ `check_story_invariants.sh` R8(P0,registry antiPattern)+ `check_chrome_header_avatar_canonical.sh` / `check_sidebar_menu_button_implicit_wrap.sh` |
|
|
22
|
+
| **3 pixel/DOM identity(opt-in,窄用)** | 僅「忠實複製 replica」或「同 story 跨版本回歸」才比 render identity | `scripts/composition-fidelity-visual-diff.mjs`,**只比標了 `@composition-fidelity-mode` 的 mapping**;單獨 `@story-baseline` = conformance 不做 identity diff |
|
|
21
23
|
|
|
22
|
-
|
|
24
|
+
**層 3 為何 opt-in(2026-06-02)**:`@story-baseline` 單獨 = conformance 意圖(交層 2 驗)。pixel/DOM identity 只在該 consumer story **額外標** `@composition-fidelity-mode: pixel|shell-only|structural` 才跑(用於忠實複製 / same-story 回歸)。0 個 opt-in → script exit 0(conformance 由層 2 保證)。**禁** 拿產品範本(內容刻意不同)去 pixel 比 DS showcase。
|
|
23
25
|
|
|
24
|
-
## 層 3 用法
|
|
26
|
+
## 層 3 用法(opt-in 時)
|
|
25
27
|
|
|
26
28
|
```bash
|
|
27
|
-
|
|
28
|
-
npm run composition-fidelity -- \
|
|
29
|
-
--ds-url=http://localhost:9001 \
|
|
30
|
-
--consumer-url=http://localhost:9002 \
|
|
31
|
-
--consumer-root=/path/to/ds-product-template \
|
|
32
|
-
--out=.claude/snapshots/composition-fidelity \
|
|
33
|
-
--threshold-pct=2
|
|
34
|
-
|
|
35
|
-
# CI — against built storybook-static dirs:
|
|
36
|
-
npm run composition-fidelity -- \
|
|
29
|
+
node scripts/composition-fidelity-visual-diff.mjs \
|
|
37
30
|
--ds-static=storybook-static \
|
|
38
31
|
--consumer-static=/path/to/ds-product-template/storybook-static \
|
|
39
|
-
--consumer-root=/path/to/ds-product-template
|
|
40
|
-
--threshold-pct=0.5
|
|
32
|
+
--consumer-root=/path/to/ds-product-template --threshold-pct=0.5
|
|
41
33
|
```
|
|
42
34
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
**Exit codes**:0 = all within threshold / 1 = at least one exceeds / 2 = setup error。
|
|
46
|
-
|
|
47
|
-
## Threshold guidance
|
|
48
|
-
|
|
49
|
-
- `0.5%` — strict baseline change(intentional fix必 update baseline)
|
|
50
|
-
- `2%` — typical(allows brand text difference like "Acme Inc" vs "Acme Product")
|
|
51
|
-
- `5%` — initial bootstrap(consumer 多元化內容差異)
|
|
52
|
-
|
|
53
|
-
**Initial ds-product-template baseline 1.41%**(measured 2026-05-27):brand text + NAV labels content-level diff。Structural composition byte-equal。
|
|
54
|
-
|
|
55
|
-
## CI workflow(shipped)
|
|
56
|
-
|
|
57
|
-
Actual gate is centralized in DS repo at `.github/workflows/composition-fidelity.yml`:checkout DS + `ajenchen/ds-product-template`,build both Storybooks,and run the local DS script against the two `storybook-static` directories.
|
|
58
|
-
|
|
59
|
-
```yaml
|
|
60
|
-
# .github/workflows/composition-fidelity.yml(design-system)
|
|
61
|
-
on: [push, pull_request]
|
|
62
|
-
jobs:
|
|
63
|
-
composition-fidelity:
|
|
64
|
-
runs-on: ubuntu-latest
|
|
65
|
-
steps:
|
|
66
|
-
- uses: actions/checkout@v4
|
|
67
|
-
with: { path: design-system }
|
|
68
|
-
- uses: actions/checkout@v4
|
|
69
|
-
with: { repository: ajenchen/ds-product-template, path: ds-product-template }
|
|
70
|
-
- run: npm ci --legacy-peer-deps
|
|
71
|
-
working-directory: design-system
|
|
72
|
-
- run: npm ci --legacy-peer-deps
|
|
73
|
-
working-directory: ds-product-template
|
|
74
|
-
- run: npm run build-storybook
|
|
75
|
-
working-directory: design-system
|
|
76
|
-
- run: npm run build-storybook
|
|
77
|
-
working-directory: ds-product-template
|
|
78
|
-
- run: |
|
|
79
|
-
node scripts/composition-fidelity-visual-diff.mjs \
|
|
80
|
-
--ds-static=storybook-static \
|
|
81
|
-
--consumer-static=../ds-product-template/storybook-static \
|
|
82
|
-
--consumer-root=../ds-product-template \
|
|
83
|
-
--threshold-pct=0.5
|
|
84
|
-
working-directory: design-system
|
|
85
|
-
```
|
|
35
|
+
掛在 `.github/workflows/composition-fidelity.yml`(checkout DS + ds-product-template,build 兩邊 storybook 後比對;**build-storybook 前必先 `build:lib`** 否則 storybook-config tsc 找不到 `@qijenchen/design-system` 型別 = TS2307)。
|
|
86
36
|
|
|
87
37
|
## 不該做的事
|
|
88
38
|
|
|
89
|
-
- ❌
|
|
90
|
-
- ❌
|
|
91
|
-
- ❌
|
|
92
|
-
- ❌ 抽樣
|
|
93
|
-
|
|
94
|
-
## 反 pattern 錨例
|
|
39
|
+
- ❌ **拿產品範本 demo 當 pixel-identity baseline 對 DS showcase 比**(內容刻意不同 = false positive,world-class 公認反 pattern)— 2026-06-02 改 identity opt-in 修正
|
|
40
|
+
- ❌ baseline story 用 `Math.random()` 等非確定性產值(render 不可重現 → 任何 diff 都是 noise)— 2026-06-02 修 `sidebar.stories.tsx` PageContent
|
|
41
|
+
- ❌ 把 baseline screenshots commit 進 consumer repo(stale)— fetch from DS Pages live
|
|
42
|
+
- ❌ 抽樣 N stories(M-rule 不抽樣)
|
|
95
43
|
|
|
96
|
-
|
|
97
|
-
1. Source byte-equivalent(DS sidebar.stories.tsx WorkspaceBrand 跟 product-workspace App.tsx 同 pattern)
|
|
98
|
-
2. Stale build artifact:DS storybook-static built BEFORE commit 4e3256c1 fix → DS render 用 ItemAvatar wrapper / consumer 用 raw Avatar
|
|
99
|
-
3. User screenshot 從 stale deploy 看到「DS-rendered」vs「consumer-rendered」structural diff
|
|
44
|
+
## 歷史錨例
|
|
100
45
|
|
|
101
|
-
**Lesson
|
|
46
|
+
- **2026-05-27**:user 抓 AppShell Avatar+Label drift。Root cause = stale build artifact(DS storybook-static built BEFORE fix commit)。Lesson:byte-identity ≠ visual ≠ deployed identity。
|
|
47
|
+
- **2026-06-02**:CF check 從建立起 30 次全紅 = 把產品範本(App.tsx,Acme Product / 自訂 nav / dashboard 內容)硬比 DS `sidebar#IconCollapse`(Acme Inc / 不同 nav / 隨機亂數內容),pixel/DOM identity 物理上不可能。修法:層 3 改 opt-in、補層 2 靜態 conformance(Pattern 8 + R8 升 P0)、修 baseline 隨機亂數。對齊專案 2026-05-27 自身結論(memory `feedback_ai_ground_truth_unreliable_mechanical_primary`:render fidelity 由架構保障、template-vs-canonical pixel diff = noise 非 drift)。
|
package/ds-story-manifest.json
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"scripts/composition-fidelity-visual-diff.mjs",
|
|
8
8
|
"product-workspace apps/template/src/AllDsComponents.stories.tsx (DsCanonicalPortal)"
|
|
9
9
|
],
|
|
10
|
-
"generatedAt": "2026-06-
|
|
10
|
+
"generatedAt": "2026-06-02T14:55:19.698Z"
|
|
11
11
|
},
|
|
12
12
|
"components": {
|
|
13
13
|
"accordion": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@qijenchen/design-system",
|
|
3
|
-
"version": "0.1.0-beta.
|
|
3
|
+
"version": "0.1.0-beta.48",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "World-class design system — components, patterns, tokens, hooks (single source of truth for team distribution).",
|
|
6
6
|
"type": "module",
|
|
@@ -132,10 +132,11 @@ const PageContent = ({ title, description }: { title: string; description: React
|
|
|
132
132
|
<div className="max-w-2xl">
|
|
133
133
|
<p className="text-body text-fg-secondary mb-6">{description}</p>
|
|
134
134
|
<div className="grid grid-cols-2 gap-4">
|
|
135
|
-
{
|
|
135
|
+
{/* 固定值(非 Math.random)— story 是 visual baseline,必確定性,否則每次 build 像素不同 = composition-fidelity / visual regression 無法比對(2026-06-02 fix)*/}
|
|
136
|
+
{([['專案數量', 24], ['團隊成員', 8], ['本週提交', 47], ['待處理', 3]] as const).map(([t, v]) => (
|
|
136
137
|
<div key={t} className="rounded-lg border border-divider bg-surface p-4">
|
|
137
138
|
<p className="text-caption text-fg-muted">{t}</p>
|
|
138
|
-
<p className="text-h5 font-semibold mt-1">{
|
|
139
|
+
<p className="text-h5 font-semibold mt-1">{v}</p>
|
|
139
140
|
</div>
|
|
140
141
|
))}
|
|
141
142
|
</div>
|