docs: std corpus 2026-05 snapshot + batch-1000/4000/remaining log

Snapshot of full oshwhub std corpus delivery:
- 12,493 projects total, 12,166 (97.4%) with editor source
- 4 sweep batches + 1 early-mixed = 5 zip artifacts in COS GZ + SG buckets
- 30-day SG-region presigned URLs for downstream pickup

log.md tracks the multi-batch sweep including driver bug postmortem
(bash heredoc python3 missed httpx → 26-min run wasted on empty zips,
recovered by switching to uv run).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-03 10:56:09 +08:00
parent d5cc6507cb
commit 6aa72faf84
2 changed files with 315 additions and 0 deletions

144
docs/std_corpus_2026-05.md Normal file
View File

@@ -0,0 +1,144 @@
# oshwhub Std corpus 交付2026-05 快照)
**快照时间**2026-05-03
**数据源**oshwhub.comorigin=std
**用途**:研究用,不再分发;下游同学批量接入 EPRO2/Std → KiCad / Wokwi pipeline
---
## 总览
| 项 | 值 |
|---|---:|
| oshwhub Std 项目总数origin=std | **12,493** |
| 含完整可编辑器源工程 | **12,16697.4%** |
| 仅 metadata + 附件upstream 没编辑器 session | 3272.6% |
| sch + pcb doc 总数(多页累加) | **30,488** |
| 源工程文件体积(`.json` 解码后) | 11.79 GB |
| 上游 listing pool 覆盖率 | 12,493 / 12,493 = **100%** |
---
## 按批次
| 批次 | 项目数 | 有源 | attach_only | docs | 选取规则 |
|---|---:|---:|---:|---:|---|
| `batch_early_std` | 112 | 108 | 4 | 427 | 早期混抓Pro 同期顺手抓的 std|
| `batch1000_std` | 1,000 | 963 | 37 | 2,853 | A 档头部like p50=43 |
| `batch4000_std` | 4,000 | 3,884 | 116 | 10,100 | A 档剩余 + B + C 头 |
| `batch_remaining_a_std` | 3,691 | 3,641 | 50 | 8,877 | rank 中段 |
| `batch_remaining_b_std` | 3,690 | 3,570 | 120 | 8,231 | 长尾grade 0/1|
| **合计** | **12,493** | **12,166** | **327** | **30,488** | |
---
## License 分布top 12
| 数 | 占比 | License |
|---:|---:|---|
| 7,050 | 56.4% | GPL 3.0 |
| 2,384 | 19.1% | Public Domain |
| 543 | 4.3% | CC-BY-NC-SA 3.0 |
| 507 | 4.1% | unknown |
| 377 | 3.0% | MIT |
| 156 | 1.2% | MIT License同 MIT立创平台没归一|
| 147 | 1.2% | CC BY-NC-SA 4.0 |
| 147 | 1.2% | BSD |
| 144 | 1.2% | CERN Open Hardware License |
| 140 | 1.1% | LGPL 3.0 |
| 136 | 1.1% | CC-BY-NC 3.0 |
| 132 | 1.1% | CC BY-NC-SA 3.0 |
| 630 | 5.0% | 其它 21 种(含 TAPR / CC BY / CC0 / null …)|
> 下游做 license 归一化白名单时,正向许可可见 6 类MIT / BSD / Apache / CC0 / CC-BY / Public Domain。注意 license 字段保留原始字符串,未做归一化("MIT" 与 "MIT License" 视为不同 key
---
## EasyEDA Std editor 版本top 10含源工程的 12,166 项里统计)
| 数 | 占比 | 版本 |
|---:|---:|---|
| 1,192 | 9.8% | 6.4.25 |
| 906 | 7.4% | 6.4.7 |
| 678 | 5.6% | 6.5.5 |
| 564 | 4.6% | 6.5.15 |
| 535 | 4.4% | 6.5.22 |
| 447 | 3.7% | 6.4.20.6 |
| 403 | 3.3% | 6.5.1 |
| 355 | 2.9% | 6.5.23 |
| 350 | 2.9% | 6.5.34 |
| 327 | 2.7% | 6.5.28 |
剩余分布在 6.3.x ~ 6.5.4x 全谱系。下游 parser 按 6.4.x / 6.5.x 主版本分支处理即可。
---
## 数据交付
### 双桶副本(腾讯云 COS
| Region | Bucket |
|---|---|
| ap-guangzhou | `facere-gz-1321068335` |
| ap-singapore | `facere-1321068335` |
### Singapore 区直链下载30 天有效2026-06-02 过期)
| 对象 key | 大小 | 项目数 | 直链 |
|---|---:|---:|---|
| `batch_early_std.zip` | 93 MB | 112 | [download](https://facere-1321068335.cos.ap-singapore.myqcloud.com/batch_early_std.zip?q-sign-algorithm=sha1&q-ak=AKID6HF1bx6A3jCSXP3UjneIjwwj7JJ8kANN&q-sign-time=1777776835%3B1780368895&q-key-time=1777776835%3B1780368895&q-header-list=host&q-url-param-list=&q-signature=09bf61ec57fbe8d758397c73d981faff47e1086e) |
| `batch1000_std.zip` | 471 MB | 1,000 | [download](https://facere-1321068335.cos.ap-singapore.myqcloud.com/batch1000_std.zip?q-sign-algorithm=sha1&q-ak=AKID6HF1bx6A3jCSXP3UjneIjwwj7JJ8kANN&q-sign-time=1777776835%3B1780368895&q-key-time=1777776835%3B1780368895&q-header-list=host&q-url-param-list=&q-signature=fd003a27c831c0c0337615b36e7f697159f4f83e) |
| `batch4000_std.zip` | 1,378 MB | 4,000 | [download](https://facere-1321068335.cos.ap-singapore.myqcloud.com/batch4000_std.zip?q-sign-algorithm=sha1&q-ak=AKID6HF1bx6A3jCSXP3UjneIjwwj7JJ8kANN&q-sign-time=1777776835%3B1780368895&q-key-time=1777776835%3B1780368895&q-header-list=host&q-url-param-list=&q-signature=427b5f15f2888f630c91b5ca5e0107b2d6b15c4c) |
| `batch_remaining_a.zip` | 1,065 MB | 3,691 | [download](https://facere-1321068335.cos.ap-singapore.myqcloud.com/batch_remaining_a.zip?q-sign-algorithm=sha1&q-ak=AKID6HF1bx6A3jCSXP3UjneIjwwj7JJ8kANN&q-sign-time=1777776835%3B1780368895&q-key-time=1777776835%3B1780368895&q-header-list=host&q-url-param-list=&q-signature=9fa2744d879bd17842129396b2656cb1f56ae81b) |
| `batch_remaining_b.zip` | 891 MB | 3,690 | [download](https://facere-1321068335.cos.ap-singapore.myqcloud.com/batch_remaining_b.zip?q-sign-algorithm=sha1&q-ak=AKID6HF1bx6A3jCSXP3UjneIjwwj7JJ8kANN&q-sign-time=1777776835%3B1780368895&q-key-time=1777776835%3B1780368895&q-header-list=host&q-url-param-list=&q-signature=f5cfa3b6010ac2fd81df36c61e64e9da2d68d8fa) |
| **合计** | **3,898 MB** | **12,493** | |
直链特性:
- presigned URL30 天有效(到 **2026-06-02 ~17:14 UTC** 失效)
- URL 内嵌 `q-ak`COS access key id公开标识不是密钥不含 SecretKey
- 任何能访问公网的机器 `wget` / `curl -O` 即可
- 失效后联系我重新签发URL 本身不可续期
下载示例:
```bash
wget -O batch1000_std.zip 'https://facere-1321068335.cos.ap-singapore.myqcloud.com/batch1000_std.zip?...'
```
或用 coscmd需要凭据
```bash
coscmd download batch1000_std.zip ./batch1000_std.zip
```
---
## 解压后单项目目录结构
每个 zip 解开后落到 `data/raw/oshwhub/<project_uuid>/`
```
data/raw/oshwhub/<uuid>/
├── metadata.json # 统一 schema见 schemas/project.schema.json
├── description.md # 标题 + 简介 + license
├── cover.{jpg,png} # 封面图(如果上游有)
├── _urls.json # 原始 URL 集合
└── source/ # EasyEDA Std 源工程(含完整源的项目才有)
├── <doc_uuid_1>.json
├── <doc_uuid_2>.json
└── ...
```
`source/*.json` 是 EasyEDA Std API 返回的 dataStr
- `result.docType` = 1schematic/ 3PCB/ 2symbol library
- `result.dataStr.shape[]` = `VERB~field1~field2~...` 串数组LIB / W / N / TRACK / VIA / COPPERAREA …)
- `result.dataStr.canvas` / `layers` / `head`(含 editorVersion
下游 EPRO2/Std → KiCad / Wokwi 适配代码已经在 `tools/epro2/std/` 走通,参考 `docs/sources/epro2_to_std_mapping.md` 看字段映射。
---
## 注意事项
- **327 项 attach_only**upstream API 返空 `documents`,多为早期纯 PCB 上传 / 项目废弃;保留了 metadata + 附件 URL没有可编辑器源
- **license 未归一化**:保留 oshwhub 原始字段值;下游做白名单过滤时注意大小写 / 空格 / 同义词(如 "MIT" vs "MIT License" vs "mit"
- **小批次(< 100 项)抽样验证**:建议下游先抽 `batch1000_std.zip` 跑通解析 pipeline确认无误再吃全量
- **重新签发 URL**:临时脚本 `/tmp/gen_urls.py`dev1 + SG box 都有),改 `TTL` 后重跑

171
log.md
View File

@@ -4,6 +4,177 @@
---
## 2026-05-03 07:17 batch-remaining-std扫完所有未抓 std 项目7,381双桶副本
**Claude 会话**
收尾批:把 unfetched std 池子7,381 项)一次扫完。拆 A/B 两批 ~3690 each按 rank 50/50 切A 头部、B 长尾),**取消单作者上限 2**(这是 sweep 全量,不需要再做多样性约束)。两批走完整 1-4 步 + zip + 双桶推送。
### 候选筛选
- Atop 3691 by rankgrade 0-4 都有likes p50=8 / p90=29 / max=275
- Bbottom 3690几乎全 grade 0/1likes p50=1 / p90=4 / max=21
- 候选 jsonl`data/state/oshwhub_remaining_{a,b}_std_candidates.jsonl`
### 第一轮 driver bug 全军覆没(必读)
**症状**driver 跑了 26 min "顺利完成",但所有 7,381 项 source 都 0——`source_documents=[]` 全空。两个 zip 才 7 MB / 6.8 MB只 metadata + description没 source
**根因**driver 里 Step 4 用 `python3 - <<PYEOF` 而不是 `uv run python -u -`
- Step 1`uv run -m crawlers.oshwhub`)走的是项目 venvhttpx 在
- Step 4 用 system python3**`crawlers.oshwhub.crawler` 第一行 `import httpx` 直接 ImportError**
- `set -uo pipefail` 没设 `-e`,每个 Step 的 stderr 写到日志后继续走,外面看 zip 也成功 / COS 也成功
- driver 不会 fail但源工程 0 拿到
**教训**bash heredoc + 多 venv 项目里,**所有依赖项目代码的 Python 调用必须 `uv run`**,仅 stdlib + 系统 pip 包(`qcloud_cos``zipfile`)的可以 system python3。下次写 driver 检查时把每个 PYEOF 块对应的 import 列出来对照。
### Recovery driver
重写 `/tmp/recover_driver.sh`:所有 Python 调用改成 `cat > /tmp/step_X.py <<PYEOF ... && uv run python -u /tmp/step_X.py`(避免 heredoc-stdin 路径文件式更稳。Step 1/Step 2 已经成功就跳过,只做 Step 4 + retry + zip + COS。
| 阶段 | 时间 |
|---|---:|
| RECOVERY START | 06:18:44 |
| batch_remaining_a 收工 | 06:48:5530 min |
| batch_remaining_b 收工 | 07:17:1128 min |
| **整 recovery 走时** | **58 min** |
### 完成度
| batch | meta | with_source | attach_only | docs | src bytes |
|---|---:|---:|---:|---:|---:|
| remaining_a | 3,691 | 3,641 (98.6%) | 50 | 8,877 | 3,317 MB |
| remaining_b | 3,690 | 3,570 (96.7%) | 120 | 8,231 | 2,783 MB |
attach_only 比例A 1.4% / B 3.3%)比 batch-1000 (3.7%)、batch-4000 (0.05%) 没明显异常D/E tier 项目被废弃 / upstream 删的比例本来就偏高,正常。
### 双桶最终状态
两个桶现在内容完全一致:
| 对象 | 大小 |
|---|---:|
| `batch1000_std.zip` | 471 MB |
| `batch4000_std.zip` | 1.38 GB |
| `batch_remaining_a.zip` | 1.06 GB |
| `batch_remaining_b.zip` | 891 MB |
| **每桶合计** | **~3.78 GB** |
走 GZ→SG 服务端 cross-region copy 链路,完全不碰 dev1↔SG 公网丢包链路。100 GB 套餐占 ~7.6 GB双桶
### 整体 corpus 落幕
- listing 里 origin=std 总数:**12,493**
- corpus 里 std 项目12,4935,112 旧 + 7,381 本批)—— **100% 覆盖**
- corpus 总目录数(含 Pro / 早期混抓12,523
- dev1 占盘13 GB40 GB 总,余 13 GB / 33% free
- license 主流:约 60% GPL 3.0 + 18% Public Domain + 5% MIT + 5% NC variants混合 batch-1-4 趋势一致)
### 决策Why
- **不设作者上限**sweep 全量批次,多样性已在 batch-1000 / batch-4000 阶段保证;这里要的是 "全部",不能掉作者。
- **batch-A vs batch-B 按 rank 切而不是随机**:万一空间不够,优先保 A更高质量实际两批都顺利完成但万一中断 A 是先做的更稳。
- **不删 GZ 桶副本**:用户有 100 GB 套餐,~3.78 GB 双桶舒适;多副本对未来跨区拉取友好。
### 下一步建议
- crawler 加 `--backfill-uuids-file <path>` 选项替代 `--uuids` 字符串,下次大批量不用绕路写 driver 内嵌 Python参考 `/tmp/backfill_4000.py` 模式可以直接搬进 crawler
- driver 模板加 sanity check跑完每个 batch 用 `du -sh /tmp/${SHORT}.zip` 与 raw bytes 比,如果压缩比 < 5% 报警(这次的 7 MB zip 用这个能立即抓到)
- 全 std corpus 已落地,下次扩量目标应该是 Pro 项目93 项飞控 Pro 候选还没动)或扩到 oshwhub 之外站点
---
## 2026-05-03 03:58 batch-4000-stdStep 1-4 + zip + COS 链路落地 SG box
**Claude 会话**
接 batch-1000-std。再扩 4000 项 std → corpus 142 → 1142 → 5142。本批走完整 1-4 步zip 后通过 COS 跨区链路拉到 SG box 本地(绕开 dev1↔SG 公网丢包链路)。
### 候选筛选
- 数据源同上
- A 档grade≥3 & like≥10剩 396 项不够 4000下沉到 unfetched 全池 11,381 按 rank score 倒排,单作者 ≤ 2取前 4000
- 候选 jsonl 落 dev1 `data/state/oshwhub_batch4000_std_candidates.jsonl`
- 质量分布grade 4: 16 / 3: 448 / 2: 1798 / 1: 1319 / 0: 419likes p50=10 / p90=42A 档第三梯队 + B + C 头部)
### 抓取dev1concurrency=5
- **Step 1** 详情扫 license~24 min3989/4000 OK + 11 fail全 "Server disconnected"),重抓 concurrency=2 全过 → 4000/4000 metadata
- **Step 2** license 盘点56% GPL 3.0、20% PD、4.8% MIT、4.8% NC-SA、4.3% unknownunknown 比例比 batch-1000 高B/C tier 项目 license 标注更随便)
- **Step 4** std-source backfill~31 min3983 OK + 17 fail
- 15 项 "Server disconnected" 瞬态,重抓全过
- 2 项 upstream 真实问题1× `404 文档未找到`doc 被删1× `code 104001`(项目封)。这 2 项保留 metadata-only
- 最终4000/4000 metadata · **3998 含完整 sch/pcb 源工程** · 2 metadata-only
### 关键修:`--uuids` 撞 ARG_MAX
- backfill 路径用 `--uuids "$(jq ... | paste -sd,)"`4000 UUID × 33B ≈ 132 KB > ARG_MAX (128 KiB)
- 现象:`bash: /usr/bin/nohup: Argument list too long`,进程没启动,但 pgrep 误匹配 stale shell
- 修:临时脚本 `/tmp/backfill_4000.py`,直接 import `crawlers.oshwhub.crawler` 内部函数(`_run_backfill_concurrent` / `fetch_std_source`UUID 集从 candidates jsonl 读,绕开命令行
- 长期crawler 应加 `--backfill-uuids-file <path>` 选项,下次扩量再改
### ZIP 打包dev1
- 4000 dirs26,098 文件4,489 MB raw → **1,445 MB zip**,压缩比 32.2%99 秒完成
- 用 Python `zipfile` + `compresslevel=1`dev1 没装 `zip` 二进制)
### 传输链路COS 三段0 字节走公网丢包链路)
| 段 | 时长 | 速度 | 路径 |
|---|---:|---:|---|
| dev1 → `facere-gz-1321068335` (ap-guangzhou) | 17s | 166 MB/s | 同区内网 |
| GZ 桶 → `facere-1321068335` (ap-singapore) | 23s | — | COS 服务端 copyVM 不参与) |
| SG 桶 → SG box | 8.5s | 201 MB/s | 同区内网 |
| **整 1.4 GB 跨地域 ~50 秒** | | | |
哈希校验穿三段:`a79a87e4a3f5dfbad80d9ba94f557b09010e104f6e0c968ea87eba2267b262b3`
### 决策Why
- **rank-score top-4000 不设硬阈值**硬过滤太挑会漏rank score 已综合 like\*3 + grade\*50 + views/100 + comments\*2 + fork\*2 + star自动平衡。最低 like=0 也进了几百项(多数是 grade≥1 但社区互动少的),可接受。
- **不传统 scp走 COS 三段**:之前飞控-77 33 MB scp 走 dev1↔SG 6.5%-loss 链路要 3 min这次 1.4 GB 走 COS 50 s 完事,提速 ~150×。COS 跨区复制流量计费 ~¥0.5/GB × 1.4 GB ≈ ¥0.7,零头。
- **zip vs tar.gz**zip 选 level=1速度 vs 体积平衡tar.gz 单线程 deflate 跟 zip-l1 体积相近但慢 2-3×
### 完成度
- corpus 由 1142 项扩到 **5142 项**+4000
- License: 56% GPL 3.0 主流不变unknown 比例从 0.4% (batch-1000) 涨到 4.3% (batch-4000),与 B/C tier 项目低标注度一致
- editor 版本从 6.3 全谱系到 6.5.42 都覆盖到了
- 源文件体积dev1 上 `data/raw/oshwhub/` 占 ~10 GB含全部历史 + 本批)
### 下一步建议
- corpus 已经达 5142 项,足够下游 EPRO2/Std → KiCad 训练数据规模
- 真要继续扩A+B+C 档已基本吃完头部,下沉 D 档grade=0 或 like=0质量回报递减可暂缓
- crawler 加 `--backfill-uuids-file` 选项,避免下次 ARG_MAX 撞墙
- COS GZ 桶里的 `batch1000_std.zip` + `batch4000_std.zip` 用完可以删SG 桶副本足够),节省 ~¥0.2/月 存储费
---
## 2026-05-03 batch-1000-stdStep 1-41000 块标准板源工程入库dev1
**Claude 会话**
走 batch-200 脚手架抓 1000 项 std A 档剩量。**用户指令"只走 1-4 步"**:不抓附件、不传 SG、不 push gitea数据留 dev1。
### 候选筛选
- 数据源:`data/state/oshwhub_listing_full.jsonl`33,695 项)
- 过滤:`origin=std AND grade≥3 AND like≥10`A 档),减去已抓 142 项 → 池子 1,396 项
- 排序rank score 倒序;单作者 ≤ 2 → 取前 1000791 唯一作者)
- 候选 jsonl 落 dev1 `data/state/oshwhub_batch1000_std_candidates.jsonl`(不入 git可重算
- like p50=43 / p90=170 / max=420A 档第三梯队,吃掉 1,396 池子的 ~72%
### 抓取dev1 Guangzhouconcurrency=5
- **Step 1** 详情扫 license~80s996/1000 OK + 4 "Server disconnected" 瞬态 fail
- 4 项重抓 (concurrency=2) 全 OK → 1000/1000 metadata
- **Step 2** license 盘点57% GPL 3.0、19% PD、8.6% CC-BY-NC-SA、5.4% MIT、其它 < 2%。形态与 batch-50 / batch-200 一致。
- **Step 3** SKIP本批 std-only没有 Pro 候选
- **Step 4** std-source backfill~6 分钟1000/1000 OK0 fail
### 完成度
- 1000/1000 metadata
- 963 项有完整 std 源工程2,853 个 sch+pcb doc平均 2.96 docs/proj
- 37 项 upstream attachments-only`source_documents=[]` 真实状态,跟飞控-77 4/77 同形态)
- 源文件体积1.47 GB on dev1按 batch-50 估算 12 MB/项 偏高,实测 1.5 MB/项——A 档第三梯队项目体量比头部小)
- editor 版本194 项 6.4.25 / 91 项 6.5.5 / 77 项 6.5.16.4-6.5 全谱系覆盖
- corpus 由 142 项扩到 1,142 项(+1000
### 决策Why
- **不传 SG / 不 push gitea**:用户指明只走 1-4 步。数据 1.47 GB 走 dev1↔SG 6.5%-loss link 估 ~3 hr 单 scp没必要现在花。要传时再走 COS 跨区或 split-parallel-scp。
- **concurrency=5 全程**:飞控-77 验证过 std doc endpoint 这个并发安全;实测 Step 1 ~12s/100项、Step 4 ~36s/100项零限流告警。
- **Step 3 跳过**:候选池纯 std-originPro backfill 没数据可处理。
### 下一步建议
- 真要消费这批数据:(a) 在 dev1 直接 push giteaSSH transport~10 min @ 1.5 GB或 (b) 走 COS 跨区同步到 SG。
- 该批的 metadata-only 部分37 项 attachments-only若想补 sch/pcb需要回头单独扫 attachment ZIP 看里面是否 bundled 了 EasyEDA 工程,那得改 crawler。
- A 档剩余只有 396 项了;下次再扩可以下沉到 B 档grade≥2 & like≥53,884 项 unfetched
---
## 2026-04-30 19:10 飞控-77主题定向抓 77 块标准飞控板
**Claude 会话**