Writing / field notes
写下来,才想得清楚。
关于工程、AI、产品体验和那些还没有被压缩成一句结论的东西。
七日垂直切片:一个人用 Godot 做能玩的游戏,验证门禁怎么设
《谣言交易所》:七天、23 条情报、4 个各怀鬼胎的 NPC。一个人做游戏最怕的不是做不完,是做完了自己信了——所以我把「能玩」拆成了四层门禁。
能创建、能运行、能连接:接一个新数据源的三道门
Intercom 接入连过三关:创建成功却必报 UNSUPPORTED_SOURCE_TYPE 的半成品、详情页消失的同步按钮、一句 ssl: true 引发的证书信任链事故。
藏起来不等于没有:API Token 的权限面为什么必须前后端同源
想给 Token 勾个「看 trace」的权限,结果页面上能选执行、写入、sandbox,偏偏没有我要的那个只读。往下挖,藏着一条更阴的缝:UI 藏起来的 scope,后端照样能签出去。
我替同事的 Runtime 宣布了「任务完成」:开发隧道的所有权问题
CI 全绿、两百多个测试通过的开发隧道,被一次对抗 review 打穿:我用 Runtime A 的合法凭据,让 Runtime B 的任务带着我写的文本「完成」了。认证、在线、所有权是三件事。
OTA 更新的三个暗坑:连接池、大小写,和一个算出来的版本号
维护一套 Expo Updates 服务,一个月被三个互不相关的坑轮流教育:千级 idle 连接、一个字母的大小写、11 秒里撞车的版本号。
冲突解对了,PR 还是脏了:merge 之后真正要审计的是最终 diff
一次语义完全正确的冲突合并,被提交钩子顺手塞进 6 个无关文件——「没有冲突标记」和「PR 干净」之间隔着整个暂存区。
索引建好了,任务失败了:把首次同步当一桩五段事务来做
一次 CodeGraph 强制同步连踩四个坑:exit 0 的子进程、万级写竞争、白拉的 13 万对象、毁掉终态的 undefined。教训只有一条——「同步完成」不是布尔值,是五段签收。
没有合规基线,就别说「没影响」:PR 影响分析的 fail-closed 契约
一个 low confidence 告警牵出两条独立的可靠性轴:图版本新不新,和图能不能表达你的代码。我们把所有 PR 收紧成「先追平基线、追不上就 unavailable」。
给 Agent 的副作用上锁:计划冻结、fresh read 与验证回执
模型说「写完了」不算数。我把 Agent 的外部写入收敛成一条可审计协议:dry-run 后冻结计划、写后推进 mutation epoch、fresh read 逐项对账,receipt 绑定 planHash。
512 个字符抄丢 2 个:为什么授权材料不能过模型的手
主流程标着 success,图片上传却收到 GCS 403。根因是 Agent 把 512 字符的 RSA 签名转抄成了 510——模型可以是好读者,但不该做授权材料的搬运工。
同一份文档,两次响应差 14KB:API 返回值的三个阶层
get_document 重复调用返回字节不同,真凶是 768 维向量和 20 个每小时重签的 URL。学到的手艺:先分字段阶层,再谈一致性——顺手把签名 URL 换成了无状态短句柄。
同步系统不会自己一致:事件、对账,和一场自激的 OOM 风暴
做知识源同步时学到的三件事:实时事件保证不了最终一致,只看成功水位的调度器会自己把自己打死,而「删除」其实有三种含义。
只读子 Agent 的两道防线:模型承诺 vs 工具级最小权限
子 Agent 的 system prompt 写着「绝对只读」,手里却握着一整套写工具——prompt 是约定不是边界。我把只读拆成两道防线,中间还埋着一个 8 条用例写错模块的事故。
一次两小时卡死的教训:长任务 Agent 为什么需要双层超时
一个无界等待的工具发现调用把 workflow 拖了整整两小时。复盘后我上了两道保险丝:30 秒局部 fail-fast 治已知根因,1800 秒全局 guard 兜未知长尾。
批准点下去了,Slack 却挂着 500:渠道交付是三个协议
业务审批 56 秒跑完、写入成功,Slack 按钮旁却挂着鲜红的 500。追下去才发现:点一次按钮,在 Slack 协议里是三条平行链路,谁也不替谁作证。
同一份需求跑出 10 条和 12 条用例:QA Agent 缺的不是生成能力,是证据治理
FIN-6202 两次执行,模块名不同、粒度不同、数量不同。我给生成链路补的不是更聪明的 prompt,是一层能回答「你凭什么这么说」的中间模型和第二遍审查。
0.66 MB 的会话回放为什么能撑爆 50 万 token:PageSpy 数据的正确打开方式
用户甩来一个 5 分钟就失效的签名 URL,说「帮我看看这次会话有什么问题」。解压后我面对的不是一份日志,是一台需要归一化的状态机。
Skill 越多越笨:Agent 的认知预算与工具发现设计
把全部能力塞进一个 Skill,等于让每次只读请求都替创建、审批、发布规则交认知税。我按意图频率和事务边界拆分,顺手治好了一场 38 万 token 的上下文爆炸。
API 返回 200,用例却进了错目录:领域对象的正确性谁来担保
脑图里看得见、详情页空白、列表归属错误——三个不同方向的事故挤在同一条用例上,而 MeterSphere 全程返回 200。API 成功是传输层的收据,不是业务层的判决。
MCP OAuth 的 .well-known 迷宫:数据面与控制面分开时的路由坑
MCP endpoint 挂在 webhook 数据面,OAuth metadata 却在 main 控制面。一次只转发单个 well-known 端点的代理配置,让新版客户端死在了发现链的中间一环——修好它只需要一个前缀。
在 macOS 上自托管 screenpipe:entitlement 与 TCC 权限边界求生记
不给 Apple 交 $99,也不想付订阅:一个显式 Cargo feature 解锁本地 entitlement,一把稳定的自签名钥匙驯服 TCC。
检索指标涨了,拒答翻了 22 倍:多跳 RAG 的证据存活率
新 Hop 链路 recall/precision/延迟全面改善,正常问题拒答却从 1/103 涨到 22/103。凶手不是检索,是一个多出来的「}」和它的静默 fallback。
把 Node.js 请求塞进 Chrome DevTools:我是怎么给运行时当「口译」的
node --inspect 打开的 DevTools 没有 Network 面板,于是我给 Node 写了一个 CDP Server,让它自己向 DevTools 汇报网络活动。
两次归零:fetch SSE 插桩为什么连发零条消息
给 Node inspector 加 SSE 逐消息事件,测试老老实实返回 0——两次。两个 0 背后是两类完全不同的故障,修的方向相反。
SSE 不是 Fetch:EventSource 在 DevTools 里的分类陷阱
Node 认得 text/event-stream 这个 mimeType,却把它硬编码成 Fetch 资源——分类错了,逐消息可见性更是无从谈起。
Initiator 的执念:调用栈为什么必须在「请求创建时」而不是「发送时」捕获
Network 面板里每条请求都应该能跳回发起它的那行代码——但栈在哪一刻被抓,决定了它指向真相还是指向 inspector 自己。
WebSocket 观测三段论:client、server、inspector 各管一段
ws 库和手写 upgrade 都走 HTTP/1.1 Upgrade 后直接操作裸 socket,Undici hook 覆盖不到——给它们做观测,得拆成三个阶段分别说服。
在解码之前截获:Node inspector 为什么必须在 parser 层拿 raw bytes
用户一句 setEncoding('utf8'),我精心采集的响应体就全线报错——解码后的流只能做 best-effort,观测点要放在字节还是字节的最后一层。
Electron 插件装上了却不显示:renderer 缓存与重载的坑
插件能安装、能注册,就是看不见——问题不在安装链路,而在 renderer 只在启动时加载一次,以及它手里攥着的一堆旧东西。