Generate and edit Draw.io, Mermaid, and Excalidraw diagrams from natural language using a structured JSON spec.
Data & analysis
数据流水线字段名漂移排查
Try it当数据流水线里某个字段「一直读不到」、某类条目静默消失、或下游把「有数据」当成「没数据」时,用契约名比对法定位字段名漂移(同一逻辑字段在采集/暂存/落盘/读取四处各有一个名字),并写「契约名回归测试」钉死。含 grep 排查模板、死变量识别、回填对账顺序。当用户说「这个字段怎么一直是空的」「数据明明有却读不到」「回填没效果」「某类记录莫名不见了」时使用。
What it does
某字段在库里「一直是空的 / 一直是待补」,但数据源明明返回了 下游按某个字段做量级/等级判断,结果把「有大数字」的条目当成「没有数据」 回填脚本跑完显示「N 条已更新」,但目标字段还是空的 某类记录静默消失(不报错、不进异常日志)
The skill document
数据流水线字段名漂移排查
什么时候用
出现下面任一症状,先怀疑字段名漂移,不要先去怀疑数据源或解析器:
- 某字段在库里「一直是空的 / 一直是待补」,但数据源明明返回了
- 下游按某个字段做量级/等级判断,结果把「有大数字」的条目当成「没有数据」
- 回填脚本跑完显示「N 条已更新」,但目标字段还是空的
- 某类记录静默消失(不报错、不进异常日志)
漂移 bug 的共同特征:不报错。 因此它比解析失败更难发现 —— 表现是「今天没采到东西」而不是「今天崩了」。
第一步:把所有引用点摊开比对(核心动作)
按逻辑字段名(人话,比如「近 30 天收入」)在整仓搜,不要按你猜的键名搜:
# 1) 契约声明在哪(数据 schema / 字段清单文档)
grep -rn "字段中文名\|last_30d_revenue" docs/ data/sources.json README.md
# 2) 谁在写、谁在读、谁只是路过
grep -rn "last_30d_revenue\|revenue_last30d\|last30Days\|last30\b" \
--include="*.py" --include="*.js" --include="*.json" --include="*.md" . \
| grep -v "__pycache__\|node_modules\|/.git/\|dist/\|public/"
# 3) 落盘数据里实际存在哪些键(最硬的证据)
python -c "
import json,collections
d=json.load(open('data/xxx.json',encoding='utf-8'))
c=collections.Counter()
for r in (d if isinstance(d,list) else d.values()):
for k in (r.get('metrics') or {}): c[k]+=1
print(dict(c))
"
第 3 条最关键:如果某个键在落盘数据里出现次数为 0,那它在读取侧就是死代码,无论代码写得多对。
典型的三套命名(实测踩过):
| 位置 | 键名 |
|---|---|
契约文档(sources.json / schema) | last_30d_revenue |
采集内部暂存(_api / 原始响应转发) | revenue_last30d |
落盘(metrics) | 一个都没写 |
| 读取(下游评分/初筛) | last_30d_revenue ← 永远读不到 |
第二步:找「读出来但没写入」的死变量
这是最隐蔽的一种。表现是变量声明并赋值了,但从没进入输出:
last30 = rev.get("last30Days") or 0 # 读出来了
total = rev.get("total") or 0
if mrr and not m.get("mrr"):
m["mrr"] = mrr # 写入了
if total and not m.get("all_time"):
m["all_time"] = total # 写入了
# ... last30 再也没出现过 —— 死变量,静默丢数
排查手法:把赋值过的局部变量名丢进 grep,看它是否只出现一次(定义那一次)。只出现一次 = 死变量。
grep -n "last30" script.py # 期望看到「定义 + 至少一次使用」
第三步:修法(三条铁律)
- 以契约文件为唯一真名。 向内落盘(写进
metrics/ 数据库列)一律用契约名;采集层的内部暂存(原样转发的响应)可以保留原名,但要加注释说明两者关系,否则下一个人还会踩。 - 口径照实写。 如果新字段的量级与既有字段差很多(实测有 36 倍差),文案里必须区分,别把「月流水」写成「MRR」。同时把口径写进该记录的
metric_note/ 字段说明。 - 只补空,不覆盖。 回填脚本要幂等:
if val and not m.get(key)。跑第二遍必须是「0 条更新」。
第四步:用「契约名回归测试」钉死
普通单测测「有没有写」,不够 —— 键名再漂移一次,同样的故障会重演。要测三件事:
CONTRACT_KEY = "last_30d_revenue" # 改这个字符串等于改契约,要一起动
class WritesField(unittest.TestCase):
def test_键名是契约名(self):
B.merge_record(r, rich)
self.assertIn(CONTRACT_KEY, r["metrics"])
self.assertNotIn("revenue_last30d", r["metrics"],
"又用回采集内部暂存名了 —— 下游会读不到")
def test_下游能读到(self):
# 端到端:写入方写进去的键,读取方必须真的取得出值
B.merge_record(r, rich)
self.assertEqual(Downstream.revenue_of(r), 79596.73)
def test_幂等(self):
B.merge_record(r, rich); first, _ = B.merge_record(r, rich)
self.assertFalse(first)
class RealData(unittest.TestCase):
def test_存量数据里没有漂移键名(self):
# 扫全库落盘数据,出现非契约键名即失败
...
最后一条最值得写:它是唯一能在数据层面拦住漂移的断言。
第五步:验证顺序(别跳步)
- 先跑纯函数单测(离线、秒级)
- 再跑回填/修复脚本的
--dry-run看会改什么 - 确认后正式跑(要备份:
cp data/x.json _backup/x.json.bak-$(date +%Y%m%d-%H%M%S)) - 对账:改了多少条、目标字段覆盖从几变成几、下游分布是否真的收敛了
- 最后跑全量测试 + 重建派生产物(静态站 / 打包产物)
坑
- 回填脚本走逐条详情页兜底时很慢(每条
sleep+ 网络),全量可能 6 分钟以上,会撞前台超时 → 放后台跑,输出重定向到日志文件(注意 Python 重定向时 stdout 有缓冲,日志会长时间为空,属正常)。 - 别在自测运行时做构建。自测脚本常会「备份→临时改数据→还原」,期间构建会把中间态写进产物;读数据做统计也会得到错数(实测出现过候选池 31/33/34 三个数)。
- 顺带确认派生产物是否该包含这份数据(比如未核实的原始队列通常不该进对外发布的那一份)。默认输出目录常是「本地预览版」,对外版另有开关。
Related skills
Find why your productivity system keeps failing, then apply the smallest fix — capacity math, bottleneck routing, durable local notes.
Run Git operations — commits, branches, merges, rebases, conflict resolution, and recovery — with safety rules enforced.
Stores durable facts in a categorized, plain-markdown vault on disk, alongside your agent's built-in memory.
Fetch raw ad creative, app, ranking, and revenue data from AdMapix as structured JSON.
Write, debug, and tune Playwright specs with locator strategy, trace diagnosis, and CI-aware timeouts.
More from oracis
Browse all skills把本地 Skill 打包并发布到 SkillHub(腾讯 skillhub.cn)与 ClawHub,覆盖预检、发布、状态回读与竞品对标全链路,并在上传被拒时用二分/ddmin 脚本把「服务端 WAF 拦内容(566)」与「包结构/字段问题」精确区分开。当用户说「发布技能到市场」「上架 skill」「SkillHub 提交失败」「Failed to fetch」「566」「上传 zip 报错」「技能审核状态」「版本号被拒」时使用。也讲清「入库成功 ≠ 已公开」——用 `mine` 的 `reviewStatus`、重发探测 `409 VERSION_EXISTS`、`/versions/<v>/signature` 三个探针判断版本到底走到哪一步。
平台只有网页后台、没有上传 API 时,用本机已装的 Chrome/Edge + CDP 自动化走完上传/发布/填表流程——复用真实登录态、零安装(不下载 500MB Chromium)、能给文件选择框塞文件;并实测富文本编辑器(公众号 / CMS / 邮件模板)里到底哪些 CSS 能活下来,以及在决定是否接入平台自带的「一键排版 / AI 美化」前先抓它输出做结构化 diff。当用户说「只能网页上传」「后台发布」「网页填表自动提交」「发布到技能市场/各平台控制台」「复用已登录的浏览器」「公众号排版样式不生效/保存后样式没了」「一键排版要不要用」「点了按钮没反应/提交没成功也没报错」时使用。
一键安装并实测验证已验证可用的免费 LLM 到 WorkBuddy/Claude Code,无需注册、无需 API Key。当用户说「装免费模型」「加免费模型」「免费 LLM」「免费模型一键装」「验证免费模型可用吗」「免费模型怎么接入」「帮我配几个免费模型」「监控免费模型」「免费模型挂了吗」「kilo 网关」「kilo-auto」「nemotron 免费」「space-bunny」「智谱 glm 免费」「zhipu 免费」「glm-4-flash」「glm-4.7-flash」「glm-z1-flash」「glm-4v-flash」「探测国外免费模型」「国外平台免费 llm」「优先用免费模型」「读图桥接」「vision bridge」「给 glm-4-flash 加读图」「不读图的模型怎么看图」「阶跃星辰」「stepfun」「step 5」「step-5-preview」「限时免费模型」「ccproxy 读图转发」「给 claude code 加读图」时使用。也用于验证已有免费模型配置是否真的可用(tool calling 是否支持、是否限流、是否支持读图),以及定期 watch 监控免费模型是否下线/限流/失去工具调用能力。
在中国大陆网络环境下用 yt-dlp 下载视频(含 Windows GUI 封装)。当用户要下载 YouTube、Bilibili、SoundCloud 等 yt-dlp 支持的站点内容,或遇到「yt-dlp 装不上 / 下载报 502 / Tunnel connection failed / ffmpeg not found / 缺 JS runtime / TLS fingerprint / watch?v=&list= 把整个列表都下了 / Sign in to confirm you're not a bot / The page needs to be reloaded / 下到一半突然下不动 / 下回来的视频糊、有拖影残影 / 下载速度特别慢」等问题时使用。
聚合搜索百度网盘/夸克网盘/阿里云盘等网盘分享链接。当用户想按作者名、课程名、剧名、书名、软件名找网盘下载路径,或提到「网盘搜索」「PanSou」「盘搜」「找到下载链接」「夸克/百度/阿里网盘资源」时使用。包含已验证的 PanSou 协议端点、绕过系统代理的必要写法、以及可直接运行的本地 Web 应用 panradar.py。
在 WorkBuddy(Windows)环境里交付零依赖本地 Web 应用,并绕开官方测试技能完全不覆盖的本机专属坑。当用户要在本机跑起来一个本地 Web 应用 / 单文件工具 / 案例库 / 看板 / 小工具,或要验证刚写完的 HTML/JS/Python 交付物真的能工作时使用。独家覆盖:Bash 缺 coreutils、bash 是 WSL 启动桩、rm 是坏 shim、PowerShell 不回显 stdout、cwd 漂移、预览面板靠 HEAD 探活——这些在干净 Linux 环境里遇不到。