create-dwy 0.10.0 → 0.12.0

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.
Files changed (101) hide show
  1. package/package.json +3 -2
  2. package/src/prompts/grouped-checkbox.js +223 -0
  3. package/src/sync.js +61 -39
  4. package/templates/claude-global/hooks/pre-git-commit-sensitive-check.sh +0 -0
  5. package/templates/claude-global/rules/{dwy-python-backend.md → Python/dwy-python-backend.md} +43 -3
  6. package/templates/claude-global/rules/{dwy-python-core.md → Python/dwy-python-core.md} +35 -2
  7. package/templates/claude-global/skills//345/237/272/347/241/200/345/272/223/dwy-eapi/SKILL.md +226 -0
  8. package/templates/claude-global/skills//346/225/260/346/215/256/345/272/223/dwy-dolphindb/SKILL.md +144 -0
  9. package/templates/claude-global/skills//346/225/260/346/215/256/345/272/223/dwy-dolphindb/references/create-database-table.md +219 -0
  10. package/templates/claude-global/skills//346/225/260/346/215/256/345/272/223/dwy-dolphindb/references/crud-operations.md +281 -0
  11. package/templates/claude-global/skills//346/225/260/346/215/256/345/272/223/dwy-dolphindb/references/data-import.md +271 -0
  12. package/templates/claude-global/skills//346/225/260/346/215/256/345/272/223/dwy-dolphindb/references/docker-deployment.md +63 -0
  13. package/templates/claude-global/skills//346/225/260/346/215/256/345/272/223/dwy-dolphindb/references/performance-tuning.md +223 -0
  14. package/templates/claude-global/skills//346/225/260/346/215/256/345/272/223/dwy-dolphindb/references/pitfalls-and-best-practices.md +352 -0
  15. package/templates/claude-global/skills//346/225/260/346/215/256/345/272/223/dwy-dolphindb/references/python-api.md +306 -0
  16. package/templates/claude-global/skills//346/225/260/346/215/256/345/272/223/dwy-dolphindb/references/setup-and-connection.md +143 -0
  17. package/templates/claude-global/skills//346/225/260/346/215/256/345/272/223/dwy-dolphindb/references/sources.md +46 -0
  18. package/templates/claude-global/skills//346/225/260/346/215/256/345/272/223/dwy-dolphindb/references/sql-batch-compute.md +206 -0
  19. package/templates/claude-global/skills//350/277/220/347/273/264/345/217/221/345/270/203/dwy-cibuildwheel/SKILL.md +354 -0
  20. package/templates/claude-global/skills//350/277/220/347/273/264/345/217/221/345/270/203/dwy-cibuildwheel/references/release-workflow-template.yml +99 -0
  21. package/templates/claude-global/skills/{dwy-deploy-audit → /350/277/220/347/273/264/345/217/221/345/270/203/dwy-deploy-audit}/scripts/check_base.sh +0 -0
  22. package/templates/claude-global/skills/{dwy-deploy-audit → /350/277/220/347/273/264/345/217/221/345/270/203/dwy-deploy-audit}/scripts/check_capacity.sh +0 -0
  23. package/templates/claude-global/skills/{dwy-deploy-audit → /350/277/220/347/273/264/345/217/221/345/270/203/dwy-deploy-audit}/scripts/check_db.sh +0 -0
  24. package/templates/claude-global/skills/{dwy-deploy-audit → /350/277/220/347/273/264/345/217/221/345/270/203/dwy-deploy-audit}/scripts/check_docker.sh +0 -0
  25. package/templates/claude-global/skills/{dwy-deploy-audit → /350/277/220/347/273/264/345/217/221/345/270/203/dwy-deploy-audit}/scripts/check_env.sh +0 -0
  26. package/templates/claude-global/skills/{dwy-deploy-audit → /350/277/220/347/273/264/345/217/221/345/270/203/dwy-deploy-audit}/scripts/check_https.sh +0 -0
  27. package/templates/claude-global/skills/{dwy-deploy-audit → /350/277/220/347/273/264/345/217/221/345/270/203/dwy-deploy-audit}/scripts/check_logs.sh +0 -0
  28. package/templates/claude-global/skills/{dwy-deploy-audit → /350/277/220/347/273/264/345/217/221/345/270/203/dwy-deploy-audit}/scripts/check_nginx.sh +0 -0
  29. package/templates/claude-global/skills/{dwy-deploy-audit → /350/277/220/347/273/264/345/217/221/345/270/203/dwy-deploy-audit}/scripts/check_resilience.sh +0 -0
  30. package/templates/claude-global/skills/{dwy-deploy-audit → /350/277/220/347/273/264/345/217/221/345/270/203/dwy-deploy-audit}/scripts/check_secrets.sh +0 -0
  31. package/templates/claude-global/skills/{dwy-deploy-audit → /350/277/220/347/273/264/345/217/221/345/270/203/dwy-deploy-audit}/scripts/check_services.sh +0 -0
  32. package/templates/claude-global/skills/{dwy-deploy-audit → /350/277/220/347/273/264/345/217/221/345/270/203/dwy-deploy-audit}/scripts/check_ssh.sh +0 -0
  33. package/templates/claude-global/skills/{dwy-deploy-audit → /350/277/220/347/273/264/345/217/221/345/270/203/dwy-deploy-audit}/scripts/run_all.sh +0 -0
  34. package/templates/claude-global/skills/{dwy-docker → /350/277/220/347/273/264/345/217/221/345/270/203/dwy-docker}/scripts/query_dockerhub.py +0 -0
  35. package/templates/claude-global/skills/{dwy-docker → /350/277/220/347/273/264/345/217/221/345/270/203/dwy-docker}/scripts/scan_images.sh +0 -0
  36. package/templates/claude-global/skills/{dwy-mirror-source → /350/277/220/347/273/264/345/217/221/345/270/203/dwy-mirror-source}/scripts/apply_mirrors.py +0 -0
  37. package/templates/claude-global/skills/{dwy-mirror-source → /350/277/220/347/273/264/345/217/221/345/270/203/dwy-mirror-source}/scripts/check_mirrors.py +0 -0
  38. package/templates/claude-global/skills/dwy-dolphindb/SKILL.md +0 -98
  39. package/templates/claude-global/skills/dwy-dolphindb/evals/evals.json +0 -67
  40. package/templates/claude-global/skills/dwy-dolphindb/references/dolphindb-rules.md +0 -441
  41. package/templates/claude-global/skills/dwy-eapi/SKILL.md +0 -495
  42. package/templates/claude-global/skills/dwy-eapi/references/health.md +0 -47
  43. package/templates/claude-global/skills/dwy-eapi/references/logger.md +0 -60
  44. /package/templates/claude-global/rules/{dwy-android-core.md → Android/dwy-android-core.md} +0 -0
  45. /package/templates/claude-global/rules/{dwy-flutter-core.md → Flutter/dwy-flutter-core.md} +0 -0
  46. /package/templates/claude-global/rules/{dwy-flutter-network.md → Flutter/dwy-flutter-network.md} +0 -0
  47. /package/templates/claude-global/rules/{dwy-flutter-router.md → Flutter/dwy-flutter-router.md} +0 -0
  48. /package/templates/claude-global/rules/{dwy-flutter-testing.md → Flutter/dwy-flutter-testing.md} +0 -0
  49. /package/templates/claude-global/rules/{dwy-python-testing.md → Python/dwy-python-testing.md} +0 -0
  50. /package/templates/claude-global/rules/{dwy-vue-core.md → Vue/dwy-vue-core.md} +0 -0
  51. /package/templates/claude-global/rules/{dwy-vue-pinia.md → Vue/dwy-vue-pinia.md} +0 -0
  52. /package/templates/claude-global/rules/{dwy-vue-testing.md → Vue/dwy-vue-testing.md} +0 -0
  53. /package/templates/claude-global/rules/{dwy-tdd-development.md → /345/274/200/345/217/221/346/265/201/347/250/213/dwy-tdd-development.md"} +0 -0
  54. /package/templates/claude-global/rules/{dwy-db-migration.md → /346/225/260/346/215/256/345/272/223/dwy-db-migration.md"} +0 -0
  55. /package/templates/claude-global/rules/{dwy-postgres.md → /346/225/260/346/215/256/345/272/223/dwy-postgres.md"} +0 -0
  56. /package/templates/claude-global/rules/{dwy-redis.md → /346/225/260/346/215/256/345/272/223/dwy-redis.md"} +0 -0
  57. /package/templates/claude-global/skills/{dwy-eapi/references/tasks-integration-guide.md → /345/237/272/347/241/200/345/272/223/dwy-eapi/references/tasks-integration-guide.md"} +0 -0
  58. /package/templates/claude-global/skills/{dwy-ekit/SKILL.md → /345/237/272/347/241/200/345/272/223/dwy-ekit/SKILL.md"} +0 -0
  59. /package/templates/claude-global/skills/{dwy-eui/SKILL.md → /345/237/272/347/241/200/345/272/223/dwy-eui/SKILL.md"} +0 -0
  60. /package/templates/claude-global/skills/{dwy-eui/references/eui-design-guide.md → /345/237/272/347/241/200/345/272/223/dwy-eui/references/eui-design-guide.md"} +0 -0
  61. /package/templates/claude-global/skills/{dwy-eui/references/eui-integration-guide.md → /345/237/272/347/241/200/345/272/223/dwy-eui/references/eui-integration-guide.md"} +0 -0
  62. /package/templates/claude-global/skills/{dwy-eui/references/eui-landing-design-guide.md → /345/237/272/347/241/200/345/272/223/dwy-eui/references/eui-landing-design-guide.md"} +0 -0
  63. /package/templates/claude-global/skills/{dwy-pentest/SKILL.md → /345/256/211/345/205/250/dwy-pentest/SKILL.md"} +0 -0
  64. /package/templates/claude-global/skills/{dwy-pentest/scripts/.python-version → /345/256/211/345/205/250/dwy-pentest/scripts/.python-version"} +0 -0
  65. /package/templates/claude-global/skills/{dwy-pentest/scripts/lib/__init__.py → /345/256/211/345/205/250/dwy-pentest/scripts/lib/__init__.py"} +0 -0
  66. /package/templates/claude-global/skills/{dwy-pentest/scripts/lib/__pycache__/__init__.cpython-311.pyc → /345/256/211/345/205/250/dwy-pentest/scripts/lib/__pycache__/__init__.cpython-311.pyc"} +0 -0
  67. /package/templates/claude-global/skills/{dwy-pentest/scripts/lib/__pycache__/config.cpython-311.pyc → /345/256/211/345/205/250/dwy-pentest/scripts/lib/__pycache__/config.cpython-311.pyc"} +0 -0
  68. /package/templates/claude-global/skills/{dwy-pentest/scripts/lib/__pycache__/executor.cpython-311.pyc → /345/256/211/345/205/250/dwy-pentest/scripts/lib/__pycache__/executor.cpython-311.pyc"} +0 -0
  69. /package/templates/claude-global/skills/{dwy-pentest/scripts/lib/__pycache__/severity.cpython-311.pyc → /345/256/211/345/205/250/dwy-pentest/scripts/lib/__pycache__/severity.cpython-311.pyc"} +0 -0
  70. /package/templates/claude-global/skills/{dwy-pentest/scripts/lib/__pycache__/validator.cpython-311.pyc → /345/256/211/345/205/250/dwy-pentest/scripts/lib/__pycache__/validator.cpython-311.pyc"} +0 -0
  71. /package/templates/claude-global/skills/{dwy-pentest/scripts/lib/config.py → /345/256/211/345/205/250/dwy-pentest/scripts/lib/config.py"} +0 -0
  72. /package/templates/claude-global/skills/{dwy-pentest/scripts/lib/executor.py → /345/256/211/345/205/250/dwy-pentest/scripts/lib/executor.py"} +0 -0
  73. /package/templates/claude-global/skills/{dwy-pentest/scripts/lib/severity.py → /345/256/211/345/205/250/dwy-pentest/scripts/lib/severity.py"} +0 -0
  74. /package/templates/claude-global/skills/{dwy-pentest/scripts/lib/validator.py → /345/256/211/345/205/250/dwy-pentest/scripts/lib/validator.py"} +0 -0
  75. /package/templates/claude-global/skills/{dwy-pentest/scripts/pentest_auth.py → /345/256/211/345/205/250/dwy-pentest/scripts/pentest_auth.py"} +0 -0
  76. /package/templates/claude-global/skills/{dwy-pentest/scripts/pentest_recon.py → /345/256/211/345/205/250/dwy-pentest/scripts/pentest_recon.py"} +0 -0
  77. /package/templates/claude-global/skills/{dwy-pentest/scripts/pentest_report.py → /345/256/211/345/205/250/dwy-pentest/scripts/pentest_report.py"} +0 -0
  78. /package/templates/claude-global/skills/{dwy-pentest/scripts/pentest_scan.py → /345/256/211/345/205/250/dwy-pentest/scripts/pentest_scan.py"} +0 -0
  79. /package/templates/claude-global/skills/{dwy-pentest/scripts/pentest_ssl.py → /345/256/211/345/205/250/dwy-pentest/scripts/pentest_ssl.py"} +0 -0
  80. /package/templates/claude-global/skills/{dwy-pentest/scripts/pentest_vuln.py → /345/256/211/345/205/250/dwy-pentest/scripts/pentest_vuln.py"} +0 -0
  81. /package/templates/claude-global/skills/{dwy-pentest/scripts/pentest_web.py → /345/256/211/345/205/250/dwy-pentest/scripts/pentest_web.py"} +0 -0
  82. /package/templates/claude-global/skills/{dwy-pentest/scripts/pyproject.toml → /345/256/211/345/205/250/dwy-pentest/scripts/pyproject.toml"} +0 -0
  83. /package/templates/claude-global/skills/{dwy-pentest/scripts/setup_tools.sh → /345/256/211/345/205/250/dwy-pentest/scripts/setup_tools.sh"} +0 -0
  84. /package/templates/claude-global/skills/{dwy-pentest/scripts/uv.lock → /345/256/211/345/205/250/dwy-pentest/scripts/uv.lock"} +0 -0
  85. /package/templates/claude-global/skills/{dwy-dev-qa/SKILL.md → /345/274/200/345/217/221/346/265/201/347/250/213/dwy-dev-qa/SKILL.md"} +0 -0
  86. /package/templates/claude-global/skills/{dwy-git-commit/SKILL.md → /345/274/200/345/217/221/346/265/201/347/250/213/dwy-git-commit/SKILL.md"} +0 -0
  87. /package/templates/claude-global/skills/{dwy-fullstack-scaffold/SKILL.md → /350/204/232/346/211/213/346/236/266/dwy-fullstack-scaffold/SKILL.md"} +0 -0
  88. /package/templates/claude-global/skills/{dwy-tech-stack/SKILL.md → /350/204/232/346/211/213/346/236/266/dwy-tech-stack/SKILL.md"} +0 -0
  89. /package/templates/claude-global/skills/{dwy-deploy-audit/SKILL.md → /350/277/220/347/273/264/345/217/221/345/270/203/dwy-deploy-audit/SKILL.md"} +0 -0
  90. /package/templates/claude-global/skills/{dwy-deploy-audit/references/checks-data.md → /350/277/220/347/273/264/345/217/221/345/270/203/dwy-deploy-audit/references/checks-data.md"} +0 -0
  91. /package/templates/claude-global/skills/{dwy-deploy-audit/references/checks-network.md → /350/277/220/347/273/264/345/217/221/345/270/203/dwy-deploy-audit/references/checks-network.md"} +0 -0
  92. /package/templates/claude-global/skills/{dwy-deploy-audit/references/checks-runtime.md → /350/277/220/347/273/264/345/217/221/345/270/203/dwy-deploy-audit/references/checks-runtime.md"} +0 -0
  93. /package/templates/claude-global/skills/{dwy-docker/SKILL.md → /350/277/220/347/273/264/345/217/221/345/270/203/dwy-docker/SKILL.md"} +0 -0
  94. /package/templates/claude-global/skills/{dwy-docker/references/ask-templates.md → /350/277/220/347/273/264/345/217/221/345/270/203/dwy-docker/references/ask-templates.md"} +0 -0
  95. /package/templates/claude-global/skills/{dwy-docker/references/templates.md → /350/277/220/347/273/264/345/217/221/345/270/203/dwy-docker/references/templates.md"} +0 -0
  96. /package/templates/claude-global/skills/{dwy-docker/references/version-rules.md → /350/277/220/347/273/264/345/217/221/345/270/203/dwy-docker/references/version-rules.md"} +0 -0
  97. /package/templates/claude-global/skills/{dwy-mirror-source/SKILL.md → /350/277/220/347/273/264/345/217/221/345/270/203/dwy-mirror-source/SKILL.md"} +0 -0
  98. /package/templates/claude-global/skills/{dwy-mirror-source/references/dockerfile-snippets.md → /350/277/220/347/273/264/345/217/221/345/270/203/dwy-mirror-source/references/dockerfile-snippets.md"} +0 -0
  99. /package/templates/claude-global/skills/{dwy-mirror-source/references/mirror-providers.md → /350/277/220/347/273/264/345/217/221/345/270/203/dwy-mirror-source/references/mirror-providers.md"} +0 -0
  100. /package/templates/claude-global/skills/{dwy-mirror-source/scripts/__pycache__/check_mirrors.cpython-313.pyc → /350/277/220/347/273/264/345/217/221/345/270/203/dwy-mirror-source/scripts/__pycache__/check_mirrors.cpython-313.pyc"} +0 -0
  101. /package/templates/claude-global/skills/{dwy-publish/SKILL.md → /350/277/220/347/273/264/345/217/221/345/270/203/dwy-publish/SKILL.md"} +0 -0
@@ -0,0 +1,354 @@
1
+ ---
2
+ name: dwy-cibuildwheel
3
+ description: "Python Cython SDK 用 GitHub Actions + cibuildwheel 跨平台 build wheel 并通过 PyPI Trusted Publisher (OIDC) 发布到 PyPI 的避坑指南。涵盖 PEP 639 license / cibuildwheel 版本 tag / YAML 冒号转义 / {package} 占位符 / 跨平台 shell 引号 / manylinux 镜像 / 测试阶段 binary 强制 / GitHub runner image 退役(macos-13 已死)等 8 类高频坑。触发条件:编辑或新建 .github/workflows/*.yml 含 cibuildwheel、pyproject.toml 含 Cython、用户说'发 PyPI'/'build wheel'/'cibuildwheel'/'跨平台打包'/'wheel build 失败'/'macos runner 一直 queued'/'发版到 PyPI' 时。"
4
+ ---
5
+
6
+ # dwy-cibuildwheel — Python Cython SDK 跨平台 PyPI 发布避坑
7
+
8
+ 适用场景:含 Cython 编译扩展的 Python 包、跨平台 wheel 分发(linux x86_64/aarch64 + macos x86_64/arm64 + windows AMD64)、GitHub Actions + cibuildwheel + PyPI Trusted Publisher OIDC 发版。
9
+
10
+ **实战来源**:quant-sdk (quantzone) 0.4.0 首发到 PyPI 过程中暴露的 8 类坑,全部沉淀于此。
11
+
12
+ ---
13
+
14
+ ## 8 个高频坑
15
+
16
+ ### 坑 1:PEP 639 license expression 触发 build env 依赖冲突
17
+
18
+ **症状**(任意平台 build 阶段):
19
+ ```
20
+ ImportError: Cannot import `packaging.licenses`.
21
+ Setuptools>=77.0.0 requires "packaging>=24.2" to work properly.
22
+ ```
23
+
24
+ **根因**:`pyproject.toml` 用了 PEP 639 字符串形式 `license = "MIT"`。setuptools 77+ 校验 license expression 时强依赖 `packaging>=24.2`,但跨平台 cibuildwheel 临时 build env 装到老 packaging 时直接撞死。
25
+
26
+ **修复**:在 `[build-system].requires` 显式锁两个下限:
27
+ ```toml
28
+ [build-system]
29
+ requires = [
30
+ "setuptools>=77",
31
+ "packaging>=24.2",
32
+ "wheel",
33
+ "Cython>=3.0.10",
34
+ ]
35
+ build-backend = "setuptools.build_meta"
36
+ ```
37
+
38
+ **例外**:还在用老语法 `license = {text = "MIT"}` / `license = {file = "LICENSE"}` 的项目不触发。但 PEP 639 是趋势,建议主动对齐 + 提前锁依赖。
39
+
40
+ ---
41
+
42
+ ### 坑 2:cibuildwheel action 必须用 minor 级或精确 tag
43
+
44
+ **症状**(workflow 启动几秒就 fail,错误页面提示):
45
+ ```
46
+ Unable to resolve action `pypa/cibuildwheel@v3`, unable to find version `v3`
47
+ ```
48
+
49
+ **根因**:不像 `actions/checkout@v4` 那种 major moving alias,`pypa/cibuildwheel` **只维护 minor 级 moving tag**(`v3.4`)和精确 patch tag(`v3.4.1`),**没有 `v3` 这种 major alias**。
50
+
51
+ **修复**:
52
+ ```yaml
53
+ - uses: pypa/cibuildwheel@v3.4 # minor moving,自动跟 v3.4.x patch(推荐)
54
+ # 或精确锁
55
+ - uses: pypa/cibuildwheel@v3.4.1
56
+ ```
57
+
58
+ **自检**:改 action 版本前先查实际存在的 tag:
59
+ ```bash
60
+ curl -sL https://api.github.com/repos/pypa/cibuildwheel/git/refs/tags \
61
+ | python3 -c "import sys,json; tags=[r['ref'].replace('refs/tags/','') for r in json.load(sys.stdin)]; print([t for t in tags if t.startswith('v3')][-10:])"
62
+ ```
63
+
64
+ 通用教训:**不要假设任何 GitHub Action 都有 `v<N>` major alias**,必须先查仓库 tag 列表。
65
+
66
+ ---
67
+
68
+ ### 坑 3:YAML 字符串含冒号必须加引号(静默杀手)
69
+
70
+ **症状**:workflow 触发后几秒 conclusion=failure,但 `gh run view <id> --json jobs` 显示 **jobs 数组为空**——一个 job 都没启动。
71
+
72
+ **根因**:GitHub Actions 在 yaml 解析失败时直接拒绝 workflow,不启动任何 job。最常见触发:
73
+ ```yaml
74
+ CIBW_BEFORE_TEST: pip install --only-binary=:all: pyarrow # 错!
75
+ ```
76
+ `:all:` 第二个冒号被 YAML 解析为 mapping value delimiter,整个文件解析失败。
77
+
78
+ **修复**:整行加引号:
79
+ ```yaml
80
+ CIBW_BEFORE_TEST: "pip install --only-binary=:all: pyarrow pandas"
81
+ ```
82
+
83
+ **强制自检**(改完任何 workflow 后必跑):
84
+ ```bash
85
+ python3 -c "import yaml; yaml.safe_load(open('.github/workflows/release.yml'))"
86
+ ```
87
+ 本地报错就修,不要 push 后等 GitHub 告诉你(GitHub 不给具体 yaml 错误行号,得自己查)。
88
+
89
+ **调试线索**:run conclusion=failure + jobs 为空 → 99% yaml 解析问题。
90
+
91
+ ---
92
+
93
+ ### 坑 4:CIBW_TEST_COMMAND 用 `{package}` 不要用 `{project}`
94
+
95
+ **症状**(monorepo + SDK 在子目录):
96
+ ```
97
+ ERROR: file or directory not found: /runner/work/<repo>/<repo>/tests
98
+ collected 0 items
99
+ ============================ no tests ran in 0.00s =============================
100
+ ```
101
+
102
+ **根因**:`{project}` 占位符替换为 cibuildwheel 调用的工作目录(**repo 根**),不是 `package-dir`。如果 SDK 在 `quant-sdk/` 子目录,测试在 `quant-sdk/tests/`,但 `{project}/tests` 会找 `<repo-root>/tests`,找不到。
103
+
104
+ **修复**:用 `{package}` 占位符:
105
+ ```yaml
106
+ - uses: pypa/cibuildwheel@v3.4
107
+ with:
108
+ package-dir: quant-sdk
109
+ env:
110
+ CIBW_TEST_COMMAND: 'pytest {package}/tests -v -k "not requires_server"'
111
+ ```
112
+
113
+ **占位符对照表**:
114
+
115
+ | 占位符 | 替换为 |
116
+ |---|---|
117
+ | `{project}` | cibuildwheel 调用的工作目录(repo 根) |
118
+ | `{package}` | `package-dir` 的绝对路径 |
119
+
120
+ **适用场景**:monorepo 必须用 `{package}`;单包仓库 `{project}` `{package}` 等价。习惯用 `{package}` 不会错。
121
+
122
+ ---
123
+
124
+ ### 坑 5:跨平台 shell 引号必须外单内双
125
+
126
+ **症状**(仅 Windows,linux/macos 正常):
127
+ ```
128
+ + pytest D:\a\repo\repo\quant-sdk/tests -v -k 'not requires_server'
129
+ ERROR: file or directory not found: requires_server'
130
+ collecting ... collected 0 items
131
+ ```
132
+
133
+ **根因**:Windows cmd **不解析单引号字符串**。`-k 'not requires_server'` 在 cmd 里被拆成两个独立参数 `'not` 和 `requires_server'`,pytest 把第二个当成目录路径。
134
+
135
+ **修复**:YAML value 外层用**单引号**,里面 shell 命令用**双引号**(双引号在 sh + cmd 都正常):
136
+ ```yaml
137
+ CIBW_TEST_COMMAND: 'pytest {package}/tests -v -k "not requires_server"'
138
+ ```
139
+
140
+ **反例**(外双内单 = Windows 必坏):
141
+ ```yaml
142
+ CIBW_TEST_COMMAND: "pytest {package}/tests -v -k 'not requires_server'" # 错!
143
+ ```
144
+
145
+ **通用原则**:跨平台跑的命令字符串里,shell 引号统一用双引号;YAML 引号统一用单引号。**永远不要在跨平台命令里用单引号包参数**。
146
+
147
+ ---
148
+
149
+ ### 坑 6:manylinux 镜像必须升到 `_2_28`
150
+
151
+ **症状**(仅 linux 容器内 pip install 阶段):
152
+ ```
153
+ ERROR: Could not find a version that satisfies the requirement pyarrow (from versions: none)
154
+ ERROR: No matching distribution found for pyarrow
155
+ ```
156
+
157
+ **根因**:`pyarrow` / `pandas` / `numpy` 等大型 C 扩展库**早已只发 `manylinux_2_28` wheel**(要求 glibc 2.28+,CentOS 8+ / Ubuntu 18.04+ / Debian 10+),**不再支持 `manylinux2014`**(glibc 2.17)。cibuildwheel 老配置默认起 `manylinux2014` 容器,容器内 pip 找不到任何匹配 wheel。
158
+
159
+ **修复**:
160
+ ```yaml
161
+ env:
162
+ CIBW_MANYLINUX_X86_64_IMAGE: manylinux_2_28
163
+ CIBW_MANYLINUX_AARCH64_IMAGE: manylinux_2_28
164
+ # musllinux 通常不用动
165
+ CIBW_MUSLLINUX_X86_64_IMAGE: musllinux_1_2
166
+ CIBW_MUSLLINUX_AARCH64_IMAGE: musllinux_1_2
167
+ ```
168
+
169
+ **风险评估**:升 manylinux_2_28 提高了用户机器的 glibc 要求,但你的 SDK 既然依赖 pyarrow,用户本来就受这个约束,**所以不增加额外限制**。
170
+
171
+ **判断标准**:你的运行时依赖里有 pyarrow / pandas / numpy / scipy / lxml 等 → 必须 `manylinux_2_28`。
172
+
173
+ ---
174
+
175
+ ### 坑 7:测试阶段三方依赖必须强制 binary
176
+
177
+ **症状**(任意平台、最容易在 aarch64 触发):
178
+ ```
179
+ ERROR: Failed building wheel for libcst
180
+ error: can't find Rust compiler
181
+ ERROR: Failed to build 'pyarrow' when installing build dependencies for pyarrow
182
+ ```
183
+
184
+ **根因**:cibuildwheel 在 test 阶段 `pip install <built-wheel>` 时自动装 SDK 的 runtime deps。pip 默认 prefer binary 但**允许源码 fallback**——某些版本/架构组合下 pip 找不到合适 binary,回退源码 build pyarrow → pyarrow build dep 拉 libcst → libcst 需要 Rust → 容器内没装 → 整个链 fail。
185
+
186
+ **修复**:在 test 前预装大依赖,**强制只用 binary**:
187
+ ```yaml
188
+ env:
189
+ CIBW_TEST_REQUIRES: pytest pytest-asyncio respx
190
+ CIBW_BEFORE_TEST: "pip install --only-binary=:all: pyarrow pandas"
191
+ CIBW_TEST_COMMAND: 'pytest {package}/tests -v -k "not requires_server"'
192
+ ```
193
+
194
+ `--only-binary=:all:` 表示对**所有包**拒绝任何源码 build。找不到合适 wheel 直接 fail(快速明确),不会拉长得离谱的 build chain。
195
+
196
+ **关键**:必须搭配坑 6 的 `manylinux_2_28`,否则 pip 找不到 binary 直接报"No matching distribution"(参见坑 6 现象)。
197
+
198
+ ---
199
+
200
+ ### 坑 8:macos-13 runner 已退休(2025-12 起死等)
201
+
202
+ **症状**:workflow 长期卡在
203
+ ```
204
+ Requested labels: macos-13
205
+ Waiting for a runner to pick up this job...
206
+ ```
207
+ 小时级 queued,runner 永远不分配。其他 job 都成功,publish 因 `needs: build_wheels` 一直不启动。
208
+
209
+ **根因**:GitHub 已于 **2025-12-04** 正式退役 `macos-13` runner image。配 `runs-on: macos-13` 的 job 不是排队,是 **runner pool 已被删空**——永远等不到。GitHub 没有为这种 case 抛错,只让你 queued 着。
210
+
211
+ Apple 完全停 Intel + GitHub 计划 **2027 秋停所有 x86_64 macOS runner**,整个 Intel Mac runner 时代在落幕。
212
+
213
+ **修复**:根据是否需要 macOS x86_64 wheel 选一:
214
+
215
+ ```yaml
216
+ matrix:
217
+ include:
218
+ - { os: ubuntu-latest, archs: x86_64 }
219
+ - { os: ubuntu-24.04-arm, archs: aarch64 }
220
+ # 选项 A: 仍需 x86_64 wheel(开发者自己是 Intel Mac / 重要用户群有 Intel Mac)
221
+ - { os: macos-15-intel, archs: x86_64 } # ✅ 替代死掉的 macos-13(真 Intel runner)
222
+ # 选项 B: 不需要 x86_64,删掉上一行,Intel Mac 用户走 Rosetta 跑 arm64 wheel
223
+ - { os: macos-14, archs: arm64 }
224
+ - { os: windows-latest, archs: AMD64 }
225
+ ```
226
+
227
+ **其他可选替代 label**:
228
+
229
+ | label | 说明 |
230
+ |---|---|
231
+ | `macos-15-intel` | 真 Intel Mac runner(新引入,推荐) |
232
+ | `macos-14-large` / `macos-15-large` | Apple Silicon 上虚拟化跑 x86_64,贵且慢 |
233
+
234
+ **通用教训**:GitHub runner image 会按计划退役(macos-11/12/13 已退,macos-14 在用,macos-15 是新主力)。改 workflow 前去 https://github.com/actions/runner-images 看当前 supported labels;不要假设 stackoverflow 上的老 yaml 还能跑。
235
+
236
+ **自检**: 看 `Waiting for a runner` 卡超过 30 分钟,基本 100% 是 label 已死(而不是真排队)。
237
+
238
+ ---
239
+
240
+ ## 完整 workflow 模板
241
+
242
+ 直接复制 `references/release-workflow-template.yml` 到项目 `.github/workflows/release.yml`,只改两处:
243
+
244
+ 1. `package-dir: <PACKAGE_DIR>` → 实际 SDK 子目录(monorepo 必填)
245
+ 2. `CIBW_BUILD` 行的 Python 版本枚举(按需调整)
246
+
247
+ 模板已内置全部 7 项修复,开箱即用。
248
+
249
+ ---
250
+
251
+ ## Pre-flight checklist(发版前必跑)
252
+
253
+ ```bash
254
+ # 1. 工作树干净
255
+ git status
256
+
257
+ # 2. tag 必须 = pyproject 版本(避开 workflow version_check 失败)
258
+ grep '^version = ' <PACKAGE_DIR>/pyproject.toml
259
+ git tag -l 'v*'
260
+
261
+ # 3. PyPI 上无该版本(PyPI 版本号永久不可重用!)
262
+ curl -s https://pypi.org/pypi/<your-package>/json \
263
+ | python3 -c "import sys,json; print(list(json.load(sys.stdin).get('releases',{}).keys()))"
264
+
265
+ # 4. CHANGELOG 有新版本条目
266
+ head -20 <PACKAGE_DIR>/CHANGELOG.md
267
+
268
+ # 5. Trusted Publisher 已配(PyPI 网页 https://pypi.org/manage/account/publishing/ 确认)
269
+ # owner = GitHub org,repo = GitHub repo 名(仓库改过名要同步改 PyPI!)
270
+ # workflow = release.yml,environment = pypi
271
+
272
+ # 6. GitHub Environment "pypi" 存在
273
+ gh api repos/<owner>/<repo>/environments --jq '.environments[].name'
274
+
275
+ # 7. workflow yml 本地解析通过
276
+ python3 -c "import yaml; yaml.safe_load(open('.github/workflows/release.yml'))"
277
+ ```
278
+
279
+ ---
280
+
281
+ ## Build 失败后的安全重发流程
282
+
283
+ **前提**:PyPI 上还**没有 publish 成功**该版本号(PyPI 一旦 publish 成功,号码永久占用,必须 bump 下一个版本)。
284
+
285
+ ```bash
286
+ # 1. cancel 失败 run,节省 CI 额度
287
+ gh run cancel <run-id>
288
+
289
+ # 2. 修代码 + commit + push
290
+ git add <修改文件>
291
+ git commit -m "ci(sdk): 修复 xxx"
292
+ git push origin main
293
+
294
+ # 3. 删本地 + 远端 tag,重打指向新 commit
295
+ git push origin :refs/tags/v0.4.0
296
+ git tag -d v0.4.0
297
+ git tag v0.4.0
298
+ git push origin v0.4.0
299
+
300
+ # 4. 监控新 run
301
+ run_id=$(gh run list --workflow=release.yml --limit=1 --json databaseId --jq '.[0].databaseId')
302
+ gh run watch "$run_id" --exit-status
303
+ ```
304
+
305
+ ⚠️ **commit 前隔离 staging**:如果你边修边并行有其他文件改动,用 `git commit -- <specific-file>` 只 commit 指定文件,避免把不相关改动一起打包到"修复 commit"里污染历史。
306
+
307
+ ---
308
+
309
+ ## 调试技巧
310
+
311
+ | 场景 | 命令 |
312
+ |---|---|
313
+ | 看**进行中** job 的日志(`gh run view --log` 不让看 in-progress) | `gh api repos/<owner>/<repo>/actions/jobs/<job-id>/logs` |
314
+ | 拿失败 job ID 列表 | `gh run view <run-id> --json jobs --jq '.jobs[] \| select(.conclusion=="failure") \| "\(.databaseId) \| \(.name)"'` |
315
+ | 阻塞等待 run 完成(后台跑) | `gh run watch <run-id> --exit-status` |
316
+ | run 几秒 fail + jobs 为空 | 99% yaml 解析错误,本地跑 `python3 -c "import yaml; yaml.safe_load(...)"` |
317
+ | Filter 失败 job 关键错误 | `gh api .../jobs/<id>/logs \| grep -iE "error\|importerror\|cython\|setuptools\|packaging\|fatal\|not found"` |
318
+
319
+ ---
320
+
321
+ ## 仓库改名 / 迁移注意
322
+
323
+ GitHub repo 改名后:
324
+
325
+ - ✅ `Settings → Environments`(含 `pypi`)跟着 repo 保留,**不丢**
326
+ - ✅ Trusted Publisher 是绑 `owner/repo` 的,repo 改名后**必须**去 PyPI 改 publisher 配置(`https://pypi.org/manage/account/publishing/` → 找到 publisher → 改 repo 名),否则下次 publish 被 PyPI 拒绝
327
+ - ✅ 旧 repo URL 自动 301 redirect 一段时间,但建议立刻更新本地 `git remote set-url origin <新地址>`
328
+
329
+ ---
330
+
331
+ ## 不要做
332
+
333
+ - ❌ **不要在本地跑 `python -m build && twine upload`** —— 本地无法 build 跨平台 wheel,且容易绕过 Trusted Publisher 引入凭证管理风险
334
+ - ❌ **不要发 sdist 到 PyPI**(`pypa/gh-action-pypi-publish` 默认只发 wheel,保持这个行为)—— Cython 编译模块的 `.py` 源码会通过 sdist 完整泄漏,破坏混淆意义
335
+ - ❌ **不要假设 GitHub Action 的 `v<N>` major moving tag 一定存在**,先查仓库实际 tag 列表
336
+ - ❌ **workflow 改完不要直接 push**,先 `python3 -c "import yaml; yaml.safe_load(...)"` 本地验证
337
+ - ❌ **不要在 publish 前先发同版本号 sdist 占位** —— PyPI 同版本号占了就废,下次 publish 被拒
338
+ - ❌ **不要在 manylinux2014 容器里期望装上 pyarrow 24+ wheel** —— 必须 manylinux_2_28
339
+ - ❌ **跨平台命令里不要用单引号包参数** —— Windows cmd 不识别
340
+
341
+ ---
342
+
343
+ ## 违规检测清单
344
+
345
+ | 检查项 | 违规模式 | 严重程度 |
346
+ |--------|---------|---------|
347
+ | build-system 缺 packaging 锁 | 用 PEP 639 license 但 `[build-system].requires` 没列 `packaging>=24.2` | **致命 → 必坏** |
348
+ | YAML 含 `:` 未加引号 | env 值有 `=:all:` / `port:8080` 等冒号但整行未加引号 | **致命 → 必坏** |
349
+ | cibuildwheel 用 major alias | `pypa/cibuildwheel@v3`(不存在)/ `@v2`(不存在) | **致命 → 必坏** |
350
+ | TEST_COMMAND 用 `{project}` | monorepo 子目录 SDK 用 `{project}/tests` | 高 |
351
+ | TEST_COMMAND 外双内单 | `"... -k 'not xxx'"` Windows 必坏 | 高 |
352
+ | manylinux2014 + 大库依赖 | 依赖含 pyarrow/pandas/numpy 但 manylinux 镜像还是 2014 | 高 |
353
+ | 缺 CIBW_BEFORE_TEST binary 锁 | 大型 C 库依赖未预装 binary,源码 build 链失败 | 中 |
354
+ | 用了已退役 runner image | matrix 含 `macos-13` / `macos-12` / `macos-11` / `ubuntu-20.04` 等已下线 label | **致命 → 死等不报错** |
@@ -0,0 +1,99 @@
1
+ # Python Cython SDK 跨平台 wheel + PyPI Trusted Publisher 发版 workflow 模板
2
+ #
3
+ # 已内置 dwy-cibuildwheel skill 7 个避坑修复,开箱即用。
4
+ # 复制到项目 .github/workflows/release.yml,只改两处:
5
+ # 1. package-dir: <PACKAGE_DIR> —— 实际 SDK 子目录(monorepo 必填,单包仓库填 . 或省略)
6
+ # 2. CIBW_BUILD —— 按需调整 Python 版本枚举
7
+ #
8
+ # 配套要求(缺一不可):
9
+ # 1. <PACKAGE_DIR>/pyproject.toml 的 [build-system].requires 含:
10
+ # "setuptools>=77", "packaging>=24.2", "wheel", "Cython>=3.0.10"
11
+ # 2. PyPI Trusted Publisher 已配(owner/repo/workflow=release.yml/environment=pypi)
12
+ # 3. GitHub Settings → Environments 存在名为 "pypi" 的 environment
13
+
14
+ name: Release SDK to PyPI
15
+
16
+ on:
17
+ push:
18
+ tags: ["v*"]
19
+ workflow_dispatch:
20
+
21
+ jobs:
22
+ version_check:
23
+ runs-on: ubuntu-latest
24
+ steps:
25
+ - uses: actions/checkout@v4
26
+ - name: Verify tag matches pyproject version
27
+ if: startsWith(github.ref, 'refs/tags/v')
28
+ run: |
29
+ TAG_VERSION="${GITHUB_REF#refs/tags/v}"
30
+ PY_VERSION=$(grep '^version = ' <PACKAGE_DIR>/pyproject.toml | head -1 | cut -d'"' -f2)
31
+ if [ "$TAG_VERSION" != "$PY_VERSION" ]; then
32
+ echo "Tag $TAG_VERSION 不匹配 pyproject.toml $PY_VERSION"
33
+ exit 1
34
+ fi
35
+ echo "Version check OK: $TAG_VERSION"
36
+
37
+ build_wheels:
38
+ needs: version_check
39
+ strategy:
40
+ fail-fast: false
41
+ matrix:
42
+ include:
43
+ - { os: ubuntu-latest, archs: x86_64 }
44
+ - { os: ubuntu-24.04-arm, archs: aarch64 }
45
+ # 坑 8: macos-13 已于 2025-12-04 退休,用 macos-15-intel(真 Intel runner)替代
46
+ # 如果不需要 x86_64 wheel,删掉下一行,Intel Mac 用户走 Rosetta 跑 arm64 wheel
47
+ - { os: macos-15-intel, archs: x86_64 }
48
+ - { os: macos-14, archs: arm64 }
49
+ - { os: windows-latest, archs: AMD64 }
50
+ runs-on: ${{ matrix.os }}
51
+ steps:
52
+ - uses: actions/checkout@v4
53
+
54
+ - name: Build wheels
55
+ # 坑 2: 不能用 @v3(major alias 不存在),用 minor 移动 tag 或精确版本
56
+ uses: pypa/cibuildwheel@v3.4
57
+ with:
58
+ package-dir: <PACKAGE_DIR>
59
+ output-dir: wheelhouse
60
+ env:
61
+ CIBW_BUILD: "cp311-* cp312-* cp313-* cp314-*"
62
+ CIBW_ARCHS: ${{ matrix.archs }}
63
+ # 坑 6: pyarrow/pandas 等只发 manylinux_2_28,不能用老 manylinux2014
64
+ CIBW_MANYLINUX_X86_64_IMAGE: manylinux_2_28
65
+ CIBW_MANYLINUX_AARCH64_IMAGE: manylinux_2_28
66
+ CIBW_MUSLLINUX_X86_64_IMAGE: musllinux_1_2
67
+ CIBW_MUSLLINUX_AARCH64_IMAGE: musllinux_1_2
68
+ CIBW_TEST_REQUIRES: pytest pytest-asyncio respx
69
+ # 坑 3 + 坑 7: 整行加双引号避免 YAML 冒号歧义;强制 binary 防止源码 build 链
70
+ CIBW_BEFORE_TEST: "pip install --only-binary=:all: pyarrow pandas"
71
+ # 坑 4 + 坑 5: monorepo 用 {package} 而非 {project};外单内双跨平台兼容
72
+ CIBW_TEST_COMMAND: 'pytest {package}/tests -v -k "not requires_server"'
73
+
74
+ - uses: actions/upload-artifact@v4
75
+ with:
76
+ name: wheels-${{ matrix.os }}-${{ matrix.archs }}
77
+ path: ./wheelhouse/*.whl
78
+
79
+ publish:
80
+ needs: build_wheels
81
+ if: github.event_name == 'push'
82
+ runs-on: ubuntu-latest
83
+ environment: pypi
84
+ permissions:
85
+ id-token: write
86
+ steps:
87
+ - uses: actions/download-artifact@v4
88
+ with:
89
+ path: dist
90
+ merge-multiple: true
91
+
92
+ - name: List wheels to publish
93
+ run: ls -la dist/
94
+
95
+ # Trusted Publisher OIDC,无需 token
96
+ # 默认只发 wheel,不发 sdist(Cython 编译模块的 .py 源码不会泄漏)
97
+ - uses: pypa/gh-action-pypi-publish@release/v1
98
+ with:
99
+ packages-dir: dist/
@@ -1,98 +0,0 @@
1
- ---
2
- name: dwy-dolphindb
3
- description: >
4
- DolphinDB 开发规范与最佳实践审查。当用户要求生成、修改、审查或优化涉及
5
- DolphinDB 的 Python/SQL 代码、脚本拼接、批量写入、查询优化、连接管理、分区
6
- 裁剪、分区方案设计(OLAP/TSDB/PKEY 引擎单分区大小估算、范围/值/哈希分区选型)、
7
- STRING/BLOB/SYMBOL 字段长度限制、数据类型转换、Docker 配置或测试 Mock 时,
8
- **必须**使用此 skill。即使用户没有明确提到 "DolphinDB",但只要代码中出现
9
- dolphindb、run_ddb、loadTable、append!、dropPartition、DBConnectionPool、
10
- DDBSession、tickDB、factorDB、addRangePartitions、newValuePartitionPolicy
11
- 等关键字,或涉及 TSDB 分区、时间序列数据库存储、金融 tick 数据/因子数据写入,
12
- 也要触发此 skill。用于确保代码符合社区版 8GB 内存限制、2 节点集群限制、
13
- 分区裁剪(包括禁止链式比较 `a <= col <= b`)、输入校验、批量写入 ≤500K 行、
14
- SYMBOL ≤255 字节、单分区大小落在引擎推荐区间等硬约束。
15
- ---
16
-
17
- # DolphinDB 开发规范 Skill
18
-
19
- ## 何时使用
20
-
21
- 只要任务涉及以下任一内容,立即读取 `references/dolphindb-rules.md` 并按本 skill 执行审查:
22
-
23
- - 编写或修改调用 DolphinDB 的 Python 代码(`run_ddb`、`run_ddb_with_data`、`DDBSession`、`DBConnectionPool` 等)
24
- - 编写或修改 DolphinDB 脚本(`loadTable`、`append!`、`dropPartition`、`select` 等)
25
- - 批量写入 tick 数据或因子数据到 DolphinDB
26
- - 查询 DolphinDB 中的 tick/因子数据,尤其是 WHERE 条件设计
27
- - 数据类型转换(Feather/Pandas → DolphinDB)
28
- - Docker 中部署或配置 DolphinDB
29
- - 为 DolphinDB 相关代码编写测试 Mock
30
- - 代码审查(CR)时发现文件包含 DolphinDB 调用
31
-
32
- ## 使用步骤
33
-
34
- ### 1. 加载完整规则
35
-
36
- 读取 `references/dolphindb-rules.md`。该文件包含全部 12 章规则,是审查的唯一权威来源。
37
-
38
- ### 2. 识别代码中涉及的规则章节
39
-
40
- 根据当前任务内容,判断主要涉及哪些章节:
41
-
42
- | 任务类型 | 重点章节 |
43
- |---|---|
44
- | 查询脚本编写 | 三(分区裁剪)、八(查询优化) |
45
- | 建库建表/分区方案设计 | 十二(分区设计原则) |
46
- | 批量数据写入 | 二(连接管理)、四(批量写入)、十(数据类型映射)、十三(字符串长度限制) |
47
- | 脚本拼接/动态生成 | 五(脚本语法)、六(输入校验) |
48
- | 服务层 Python 代码 | 二(连接管理)、六(输入校验)、十(数据类型映射) |
49
- | Docker/部署配置 | 九(Docker 环境) |
50
- | 测试代码 | 十一(测试 Mock) |
51
- | 代码审查/CR | 全部,尤其是十四(检查清单) |
52
-
53
- ### 3. 执行规则审查
54
-
55
- 对生成的或已有的代码,逐条检查相关章节的**强制规则**和**违规检测**项。
56
-
57
- **审查输出格式:**
58
-
59
- 对每处问题,使用以下格式报告:
60
-
61
- ```
62
- ⚠️ [规则章节] 具体问题
63
- 违规代码:<摘录>
64
- 修复建议:<具体修改后的代码>
65
- 原因:<引用规则中的说明>
66
- ```
67
-
68
- 对符合规则的代码,可以简要确认:
69
-
70
- ```
71
- ✅ [规则章节] 符合要求 — <简要说明>
72
- ```
73
-
74
- ### 4. 特别关注以下致命违规
75
-
76
- 以下问题会直接导致生产故障或 OOM,必须零容忍:
77
-
78
- 1. **分区列被函数包裹**(如 `date(trade_date)`)→ 全表扫描 → 8GB OOM
79
- 2. **链式比较过滤**(如 `2022.12.01 <= TradeDate <= 2022.12.03`)→ 不触发分区剪枝 → 全表扫描
80
- 3. **单次 append 超过 500K 行** → TSDB 报错 `exceeds max limit`
81
- 4. **未校验的外部输入拼接到脚本** → 脚本注入风险
82
- 5. **连接池做 upload + run** → 变量跨连接不可见
83
- 6. **select *** → 传输全部 30+ 列,浪费带宽和内存
84
- 7. **分页使用 `LIMIT x OFFSET y`** → DolphinDB 不支持 OFFSET 关键字
85
- 8. **`asyncio.to_thread(pool.run, script)`** → SDK v3 的 `pool.run()` 已是原生 async,无需包装
86
- 9. **SYMBOL 列写入未校验长度** → 超 255 字节抛异常,整批写入失败
87
- 10. **建表分区方案过细**(如每天 5000+ 个 0.6MB 小分区)→ 命中 `maxPartitionNumPerQuery=65536` 限制
88
-
89
- ### 5. 检查清单应用
90
-
91
- 如果任务是**代码审查**或**最终确认**,逐条过一遍 `references/dolphindb-rules.md` 第十四章的检查清单(13 项),并给出通过/不通过的明确结论。
92
-
93
- ## 输出要求
94
-
95
- - 审查结果必须结构化,按规则章节分组
96
- - 对每一处违规,必须给出**可落地的修复代码**,不能只说"不符合规则"
97
- - 如果代码完全符合规则,明确声明"所有 DolphinDB 相关规则检查通过"
98
- - 如果任务只是生成代码,在生成过程中就内联应用规则,生成完毕后给出简要的合规确认
@@ -1,67 +0,0 @@
1
- {
2
- "skill_name": "dwy-dolphindb",
3
- "evals": [
4
- {
5
- "id": 1,
6
- "prompt": "帮我写一个 Python 函数,把一个大 pandas DataFrame(约 200 万行 tick 数据)写入 DolphinDB 的 tickDB snapshots 表。表的分区列是 trade_date 和 order_book_id。函数接收 filepath(feather 格式)和 trade_date 参数。",
7
- "expected_output": "生成的代码必须使用 DDBSession 复用连接、分批次 ≤500K 行写入、每批后 del + gc.collect()、用 pyarrow 分片读取、外部输入经过校验、使用 run_ddb_with_data 或 session.upload_and_run。不能出现连接池 upload、单次 append 全部数据、pd.read_feather 全量加载。",
8
- "files": [],
9
- "assertions": [
10
- "代码中包含 BATCH_SIZE 且值 ≤ 500000",
11
- "代码中使用了 gc.collect()",
12
- "代码中没有使用 pd.read_feather 一次性读取大文件",
13
- "代码中使用了 DDBSession 或 run_ddb_with_data 而非连接池做 upload",
14
- "代码中包含对外部输入(如 trade_date、filepath)的校验逻辑"
15
- ]
16
- },
17
- {
18
- "id": 2,
19
- "prompt": "写一个 FastAPI 端点 /api/tick/query,接收 stock_code、start_date、end_date 参数,从 DolphinDB tickDB snapshots 表查询数据并返回。请直接写实现代码。",
20
- "expected_output": "生成的代码必须对输入参数校验、WHERE 条件直接命中分区列(trade_date 和 order_book_id)而不使用函数包裹、只 select 需要的列、使用 DolphinDB 分页语法 limit offset, count(而非 LIMIT OFFSET)、使用 PIVOT BY 或合并聚合查询减少往返。",
21
- "files": [],
22
- "assertions": [
23
- "WHERE 子句中没有 date()、month()、year() 等函数包裹分区列",
24
- "查询中没有 select *",
25
- "分页语法是 limit {offset}, {page_size} 而不是 limit {page_size} offset {offset}",
26
- "代码中包含输入校验(validate_stock_code 或类似逻辑)",
27
- "没有使用 asyncio.to_thread(pool.run)"
28
- ]
29
- },
30
- {
31
- "id": 3,
32
- "prompt": "审查以下代码是否符合 DolphinDB 开发规范,指出所有问题并给出修复后的代码:\n```python\nasync def import_tick_data(filepath: str, trade_date: str):\n df = pd.read_feather(filepath)\n script = f'append!{loadTable(\"dfs://tickDB\", \"snapshots\"), data}'\n await run_ddb(f'upload data = {df}')\n await run_ddb(script)\n return {\"status\": \"ok\"}\n\nasync def query_ticks(stock_code: str, start: str, end: str):\n script = (\n f'select * from loadTable(\"dfs://tickDB\", \"snapshots\") '\n f'where date(trade_date) >= {start} and date(trade_date) <= {end} '\n f'and order_book_id = \"{stock_code}\" '\n f'limit 100 offset 0'\n )\n return await run_ddb(script)\n```",
33
- "expected_output": "审查报告必须指出:1) pd.read_feather 全量加载问题;2) 连接池 upload + run 导致变量跨连接不可见;3) 未校验 filepath、trade_date、stock_code;4) date(trade_date) 函数包裹分区列导致全表扫描;5) select *;6) limit 100 offset 0 语法错误;7) 缺少 BATCH_SIZE 和 gc.collect()。每项必须给出修复代码。",
34
- "files": [],
35
- "assertions": [
36
- "输出中明确指出了 date(trade_date) 或分区列被函数包裹的问题",
37
- "输出中明确指出了 select * 的问题",
38
- "输出中明确指出了 limit 100 offset 0 语法错误",
39
- "输出中明确指出了连接池 upload + run 的问题",
40
- "输出中为每个问题都提供了修复后的代码片段"
41
- ]
42
- },
43
- {
44
- "id": 4,
45
- "prompt": "审查以下 DolphinDB 查询脚本是否能触发分区剪枝,并给出修复后的脚本:\n```sql\nselect * from loadTable(\"dfs://tickDB\", \"snapshots\")\nwhere 2022.12.01 <= TradeDate <= 2022.12.03\n and order_book_id = \"000001.SZ\"\n```",
46
- "expected_output": "审查必须指出:1) `2022.12.01 <= TradeDate <= 2022.12.03` 是链式比较,DolphinDB 不识别两端边界,无法做分区剪枝,会扫描全部分区;2) 给出修复方案:改为 `TradeDate between 2022.12.01 and 2022.12.03` 或拆成 `TradeDate >= 2022.12.01 and TradeDate <= 2022.12.03`;3) 同时指出 select * 浪费带宽,应只取需要的列。",
47
- "files": [],
48
- "assertions": [
49
- "输出中明确指出了链式比较无法触发分区剪枝",
50
- "输出中提供了 between ... and ... 或拆分为两个独立条件的修复方案",
51
- "输出中提到了 select * 的问题"
52
- ]
53
- },
54
- {
55
- "id": 5,
56
- "prompt": "帮我设计一张存储股票 tick 数据的 DolphinDB 分布式表,每天约 5000 万条记录,覆盖国内 5000 只股票,使用 TSDB 引擎。给出分区方案并说明理由。",
57
- "expected_output": "方案必须:1) 一级 VALUE 分区按 TradeDate,二级用 HASH 分区按 SecurityID(约 20 桶),而不是 VALUE 分区,避免每天 5000+ 个小分区命中 maxPartitionNumPerQuery=65536 限制;2) 估算单分区大小(每天 3GB / 20 桶 ≈ 150MB,落在 TSDB 推荐区间 400MB~1GB 之下但仍可接受,或调整桶数让单分区更接近 400MB);3) 提醒分区方案一经确定无法调整;4) 提醒 SYMBOL 列 SecurityID 写入前需校验 ≤255 字节。",
58
- "files": [],
59
- "assertions": [
60
- "方案中二级分区使用 HASH 而非 VALUE",
61
- "方案中包含单分区大小估算并参考 TSDB 100MB~1GB 推荐区间",
62
- "方案中提到 maxPartitionNumPerQuery=65536 或避免分区数爆炸",
63
- "方案中提到 SYMBOL 列长度校验或 ≤255 字节限制"
64
- ]
65
- }
66
- ]
67
- }