- 变更规模:新增 514 / 修改 62 / 重命名 155 / 删除 4(归档重组与文档轮次) - .gitignore 修:`归档/**/db-cwd归一-备份-*/` —— 原规则写绝对层级(归档/db-cwd归一-…), 目录搬进 归档/配置与备份/ 后**静默失效**,43 MB 的 DB 备份又变成未跟踪 - .gitignore 补:嵌套 git 内部数据(归档/内嵌git-20261008/、归档/skills-git-旧线-20261007/dotgit-原样移出/) - .gitignore 补:运行态与部署副本(.workbuddy/collab/、.workbuddy/tools/、.workbuddy/.load-pending、.workbuddy/tmp-*) - .gitignore 补:备份件(*.bak-*) - 未跟踪文件从 2190 降到 890(其余为 归档/ 归档件与 .workbuddy/memory/ 知识文件,按口径入库)
19 KiB
name, description, version, updated_at, agent_created
| name | description | version | updated_at | agent_created |
|---|---|---|---|---|
| content-source-governance | 给「定时/周期性自动生成内容」的项目建一套信源治理层——治「AI 每天自动生成日报/周报,但信源越用越水、数字对不上、主角跑偏(该报小项目却全是巨头)、覆盖写把历史产物冲掉、手机上没法看」。当用户说「这个日报/周报要每天自动生成」「信源质量不行」「为什么全是巨头新闻」「再找些更垂直的源」「加个信息源」「生成新的别把历史的删了」「移动端体验不好」时触发。核心 = 治理层与检索层双文件分工 + 信源必先实测再入册 + 「主体分层」决定谁是头条 + 展示数字与注册表条目数机械核对 + 归档只增不减 + 移动端用真机视口量化而非猜测。 | 1.2.0 | 2026-09-28 | true |
content-source-governance — 周期性内容项目的信源治理
一个人每天让 AI 自动生成一份日报,三周后一定会出现的五个病:
- 信源越用越水——第一周引 Bloomberg,第三周引中文聚合号,第五周引内容农场。
- 主角跑偏——想报的是「个人开发者小项目」,实际全是 OpenAI、Anthropic 的融资新闻,因为巨头新闻最好搜、最多、最省事。
- 数字对不上——首屏写「28 条」,页脚写「25 条」,某个分区徽标写「11 条」但里面只有 5 张卡。
- 历史被覆盖——流程里全是覆盖写,用户开始担心「生成新的会不会把旧的删了」;这类担心一旦出现,信任就已经受损了。
- 手机上没法看——用户主要在手机上打开,而版式是按桌面设计的:宽表被压成窄竖条、按钮小到点不准、导航横滑却看不出能滑。
本技能给的是治这五个病的固定结构,不依赖具体项目。
一、两个文件,职责必须分开
放两份文件在项目根目录,不要让一份文件同时干两件事:
| 文件 | 角色 | 装什么 | 谁读 |
|---|---|---|---|
数据源注册表.md |
治理层 | 准入判据 / 剔除判据 / A·B·C 白名单 / 黑名单 / 结构要求(地域、主体) / 每次执行的治理动作 / 变更日志 | 每日任务第一步必读;冲突时以它为准 |
信源地图_xxx.md |
检索层 | 去哪找、怎么用、什么口径、访问方式(直连 or 浏览器)、避坑清单、每日检索起手式 | 每日任务第一步必读 |
为什么必须分开:注册表会被每日任务回写(新增源、拉黑源、记变更日志),信源地图基本只读、越写越厚。混在一起会让每日任务在改「操作方法」时误改「判据」。
注册表头部固定一行 > 最后更新日期:...(本次改了什么)——一眼看出规则版本。
二、信源入册的硬纪律:先实测,再入册
绝不采信搜索摘要里的域名和描述。 搜索摘要会把「不存在的站」「早已死的站」写得像活的。
固定动作(每个候选源都做一遍):
probe() { code=$(curl -s -m 12 -o /dev/null -w "%{http_code}" -L -A "Mozilla/5.0 (Windows NT 10.0; Win64; x64)" "$1" 2>/dev/null); \
t=$(curl -s -m 12 -L -A "Mozilla/5.0 (Windows NT 10.0; Win64; x64)" "$1" 2>/dev/null | grep -o -i "<title>[^<]*</title>" | head -1 | sed 's/<[^>]*>//g' | cut -c1-64); \
printf " %-46s HTTP %-4s %s\n" "$1" "$code" "$t"; }
按状态码处置:
| 结果 | 处置 |
|---|---|
| 200 | 入册,注明口径与访问方式 |
| 403(Cloudflare「Just a moment...」) | 站点真实存在但直连被反爬 → 在册并注明「须走浏览器通道」,不要写「不可用」 |
| 526 / SSL 握手失败 | 站方 TLS 配置故障 → 注明「实测不可用」 |
| 000(DNS/连接失败) | 本机不可达。先判断是不是被墙或需 JS;Reddit、V2EX 这类站正常浏览器能开 → 写「须浏览器通道」,不要误判为死站 |
| 404 | 该路径不存在,试根域名;根域名也 404 → 丢弃 |
附带纪律:搜索摘要里出现、但探测不解析的域名(如 revenuejourneys.com、indiehacker.directory)→ 直接不入册,在变更日志里记一笔「未验证,不入册」。这条纪律本身就是最有价值的产出之一——它挡住了 80% 的假源。
三、主体分层:决定「谁是头条」的唯一杠杆
周期内容跑歪的根因是采集优先级没成文。搜索天然偏好巨头新闻,所以必须把「谁是主角」写成硬规则,而不是靠当期恰好如此。
在注册表里开一节「主体结构要求」,把主体从最小往大分层,每层给判定 + 配额 + 记账口径。以「AI 变现日报」为例(可直接照搬结构,换掉内容):
| 层 | 判定 | 配额 |
|---|---|---|
| 1A 微型项目(最先找) | ≤2 人 · 无雇员 · 收入从 0 起(累计 <$10k 或 MRR <$1k 也照收,不设金额门槛) · 上线 ≤12 个月 · 单点网页/插件/小工具/模板 · 有没有 AI 能力不是必要条件 | 「验证案例」≥1 条;头条能找到就优先放 |
| 1B 个人 / 小团队 | 独立开发者、一人公司、2–20 人小团队、≤50 人初创、开源作者。团队规模优先于金额——几人团队做到千万美元 ARR 仍算主线 | 占主体篇幅 |
| 2 巨头 / 大厂 | 明确的巨头清单 + 员工 >1000 人公司的整体财报或战略级动作 + 巨头间并购 | 只进末尾「新闻速览」分区,≤ 总条数 25%,不得进头条,不得作收入样本 |
四条必须一起写进去的反直觉规则(缺一条,规则就会被绕过):
- 金额小不构成降级理由:¥2000/月的插件、$400/三周的小站,都是合格头条候选。
- 找不到就如实说明,不得用巨头顶位:写明「今日未采到达标的小项目」并列出检索过的源。
- 不得把「作品集收录」「榜单排名」当业绩:上榜 ≠ 有收入。
- 「0 收入」样本不是废料但要配对:可进「雷区预警」,但必须与已赚到钱的样本同篇呈现,不得整篇只有失败样本。
记账口径也按同一分层写死,例如四段:微型项目 X 条 · 个人/小团队 Y 条 · 中小创业公司 Z 条 · 巨头 W 条,并要求每期变更日志记录。
四、越小的主体,越不能靠媒体——必须去「没有记者」的地方
这是本技能最实用的一条经验。微型项目不会有任何媒体报道,靠新闻搜索永远采不到。已实测可用的入口类型(换题材时替换具体站点):
| 类型 | 例子 | 给什么 |
|---|---|---|
| 作品集 / 展示墙 | madewithlovable.com、madewithbolt.com、vibecoded.directory |
个人搭出来的成品清单(含作者名)——⛔ 无收入数字,纯发现用 |
| 微型首发榜 | fazier.com、tinylaunch.com、uneed.best、betalist.com |
最近 1–2 天新上线的小项目与首发定价 |
| 逐日流水账 | dev.to/t/buildinpublic、dev.to/t/sideproject、Reddit r/SideProject |
「第一位付费用户」「$0 → $1」的一手实录,最诚实 |
| 中文社区域 | V2EX(分享创造 / 副业)、即刻(独立开发者圈) | 中文极小额样本主产地 |
| 二次汇总(省时间) | txtmix.com「AI 副业午报」(日更)、neodrop.ai 收入周报(周更) |
别人已替你从 Reddit/V2EX 摘好中文摘要并附原文链接 → 只作线索,引用必须回指原文 |
写作纪律:自述类源(社区、作品集、汇总站)只能用于「发现项目」;入报数字必须回访作者带日期的原始披露或其支付侧页面;回访不到就标「来源:XXX 自述(平台 + 链接),未独立核实」,只做配角。
顺带一个副产品:把「已核实样本清单」写进信源地图(项目 · 主体 · 形态 · 自述数字 · 原文),每天任务就有一把**「什么量级才算这个层」的对照尺**,避免把 $10k MRR 当小项目、把 $20 当业绩。
五、展示数字必须与注册表机械核对
只要有「信源健康度 4 个数字」这类展示位,就一定会在某天开始对不上(改注册表时容易忘)。
先定义口径,再写脚本核:
计数口径 = 该等级列表的条目数(表格一行 = 1 条;一个列表项 = 1 条;同一行内并列的多个站点合并计 1)
然后每次改完必跑:
import re
t = open('数据源注册表.md', encoding='utf-8').read()
def rows(s, e):
seg = t.split(s)[1].split(e)[0]
L = [l for l in seg.split('\n') if l.strip().startswith('|')]
return [l for l in L if not re.match(r'^\|\s*-+', l.strip()) and '| 源 |' not in l]
real = {'A 级': len(rows('### A 级','### B 级')), 'B 级': len(rows('### B 级','### C 级')),
'C 级': len([l for l in t.split('### C 级')[1].split('## 四、黑名单')[0].split('\n') if l.strip().startswith('- ')]),
'黑名单': len(rows('## 四、黑名单','## 五、'))}
h = open('index.html', encoding='utf-8').read()
idx = dict((m.group(2).split(' ·')[0], m.group(1)) for m in re.finditer(r'<div class="n">(\d+)</div><div class="l">([^<]+)</div>', h))
for k, v in real.items():
print(f"{k} 注册表 {v} index {idx.get(k)} {'✅' if str(v)==str(idx.get(k)) else '❌'}")
同时必须把这句写进每日任务的 prompt:「该四格必须等于注册表各等级的实际条目数,用脚本核对,禁止凭印象填」——否则明天的自动执行又会凭感觉改回去。
同类计数口径(条数 = 各内容分区卡片数之和、行动块不计条、页脚总数 = 首屏总数 = 各分区徽标之和)也要一次定义清楚并写进任务,否则历史遗留的「验证案例 11 条但只有 7 张卡」会一直存在。
六、每日任务的 prompt 怎么写
automation_update 的 prompt 要自包含(未来执行看不到本次对话),固定五段结构:
【第一步 · 读治理与检索文件】精确路径 + 本次最该看的那一节
【第二步 · 采集】分轮次,最小主体在最前(第 0 轮),逐轮给站点与英文关键词
【第三步 · 生成 HTML】占位符清单 + 分区顺序 + 计数口径(自检一遍)
【第四步 · 落盘】写哪几个文件、哪个锚点插行、哪个数字要脚本核对
【第五步 · 源治理】新增/拉黑/升降级都要回写,变更日志记什么(含分布)
【硬约束】红线清单
三条容易漏的硬约束,务必写上:
- 不得修改模板文件(它只作版式参考);发现版式与最近一期不一致就先问,不要擅自改版。
present_files只传.html——预览面板只服务 HTML,.md会显示「文件已被删除」,让用户以为文件丢了。- 完成后回复里要给一句话摘要 + 分布统计(信源地域分布、主体分布、本期新采用的源),让用户能一眼验证规则生效。
七、变更日志写什么
每期一条,倒序(最新在最上),固定含:
- 日期 + 第几次执行
- 新增 / 剔除 / 降级了哪些源,各自理由
- 本期实际采用的信源
- 本期分布:信源地域(海外 X / 国内 Y)+ 主体分层(四段)
- 规则修订时另起一条,写「起因(谁提的什么反馈)+ 改动清单 + 本期实测结论」
规则修订条目里必须记起因的原话。否则三个月后没人知道那条看似奇怪的配额是怎么来的,很容易被当成冗余删掉——然后病就复发了。
八、产物保护:归档只增不减(第四个病)
「每天生成」意味着流程里有覆盖写。用户迟早会问一句「生成新的别把历史的删了啊」——这句话一旦出现,说明之前只是恰好没删,而不是规则上不能删。 所以要在还没出事的时候就把规则写死。
核查顺序:先证明历史现在没丢(列出文件、逐条比 md5、确认索引行与链接可解析),再补规则。不要一被问就道歉并重写流程——先拿证据说话,很可能什么都没丢;真正缺的只是「明令禁止删除」这条成文约束。
三层落地:
① 任务层——prompt 里写死两件事:
- 开跑前记基线:归档文件数
N_before+ 文件名清单、索引归档行数R_before+ 日期集合。 - 执行后双向校验:归档文件数必须 =
N_before + 1(同日重跑 =N_before),索引日期集合只增不减;不符 → 立即停止写入并报告差异,不要继续动文件。
② 治理层——给每个路径写明「允许写 / 禁止写」,别只写一句「不要删历史」:
| 典型路径 | 允许 | 禁止 |
|---|---|---|
archive/{date}.html |
新建当日文件;同日重跑可覆盖 | 删除、覆盖非当日历史文件 |
latest.html |
覆盖(它是「最新一期副本」;覆盖前必须确认当期已先写入 archive) | 在 archive 写入成功前覆盖 |
index.html |
锚点之间插入/更新当日行;刷新统计数字 | 删除历史行、清空锚点区间、整表重写 |
| 历史留档 / 模板 / 治理文件 | 只追加(变更日志) | 任何删除或改写 |
③ 恢复网——一个只增不减的备份目录:每日在校验通过之后,只把 archive 里尚不存在于备份的文件复制过去(只复制、不删除)。这样任何一次生成异常都有回退源。
两条必须点明的语义,否则规则会被绕过:
latest.html是副本,允许覆盖;历史由archive/承载。先写 archive、后覆盖 latest,顺序颠倒就永久丢一期。- 禁止凭记忆重建历史——发现缺失只能从备份复制取回,取不回就如实报告。模型的「补一份出来」会制造比缺失更糟的问题:一份看不出是假的假历史。
④ 版本控制——如果项目目录在 git 仓库里,把产物纳入跟踪是最强的一层(完整历史 + 可 diff + 可恢复到任意一天)。四条实操纪律:
- 先查再动:
git check-ignore -v <路径>确认它是「被忽略」还是「仅仅未跟踪」——新建目录常常只是没人 add 过,不是被刻意排除。是否纳入属于用户的仓库约定,先问一句。 - 按路径提交,禁止
git add -A/git add .:日报项目往往和别的代码同仓,通配 add 会把无关改动一起提交。用git add "<日报目录>"。 - 只提交、不推送:
git push由用户决定。 - 固定换行符:Windows 上
core.autocrlf=true时加一条.gitattributes把产物目录钉成text eol=lf,否则 checkout 后文件变 CRLF,会出现「内容没变却显示已修改」的幻影差异,干扰每日校验。
自动化里这一步要写成可跳过:git 未配置 / 报冲突就跳过并说明,绝不允许在自动化里跑 git reset、git checkout --、git clean——那反而是最可能真正删掉东西的操作。
另外,同仓里如果存在旧副本目录(迁移前的源目录),要在任务 prompt 里明确写「唯一有效目录是 X,Y 已停用、不要写它」。否则未来某次执行可能误写旧路径,产出两份互不同步的日报。不要直接删除旧副本——加一份说明文件标明「已迁移 + 当前位置 + 缺什么」更安全,也顺带消除「打开旧版以为历史丢失」的误判。
九、移动端:别猜,用真机视口量化
周期性内容的产物多半是在手机上看。用户说「移动端体验不好」时,不要凭 CSS 打补丁——先量化,因为最难的问题往往不在你以为的地方。
量化体检(跑这一段,问题基本全暴露)
用真机逻辑视口(如 iPhone 393×852)加载页面,然后逐项取数:
// 视口与溢出
innerWidth; document.documentElement.scrollWidth - innerWidth; // 必须 ≤ 0
// 逐元素查溢出
document.querySelectorAll('*').forEach(el => { /* getBoundingClientRect().right > innerWidth */ });
// 点击目标
[...document.querySelectorAll('a,button')].map(el => el.getBoundingClientRect()); // 高 <44px 不达标
// 字号
getComputedStyle(el).fontSize; // 正文 <15px 偏小
// 粘性导航遮挡
getComputedStyle(section).scrollMarginTop >= topnav.getBoundingClientRect().height;
// 表格列是否被压垮(横向布局在窄屏的头号杀手)
[...document.querySelectorAll('th')].map(th => th.getBoundingClientRect().width);
踩坑提醒:CDP 设视口要在建 tab 之后再 Emulation.setDeviceMetricsOverride,否则会失效、测出的是旧宽度——那样得到的结论会偏乐观。
实测最容易暴露的两类问题
① 宽表被压成窄竖条。 表格在窄屏不会溢出,它会把列挤扁。实测遇到过:摘要列被压到只剩 80px,中文每行 5–6 字,单行高 428px(占半屏),几行就撑满整页。这类问题从「有没有横向滚动条」完全看不出来。
修法:@media 里把 table/tr/td 重排为卡片(display:block/grid),不要改 HTML 结构——如果项目靠注释锚点在表格里插行(如 ARCHIVE_ROWS_START/END),换成 div 卡片会直接破坏插入协议。纯 CSS 重排既解决问题又保住协议。
② 横向可滚的导航,没有「可滑」的暗示。 7 个按钮在 393px 下必然装不下。若只有 overflow-x:auto,用户会以为按钮就这几个。要补三件事:
- 右侧渐隐:
mask-image:linear-gradient(90deg,#000 calc(100% - 30px),transparent) - 激活项自动滚入视野:手动点的按钮要滚进来,scrollspy 高亮时也要(否则高亮的那个在屏幕外,等于没高亮);只滚横向容器,别动页面纵向
- 品牌区瘦身:长标题在小屏只留图标,能省出近百像素
两条产品判断(不只是技术)
- 别把信息截断成省略号。来源、口径、时间窗是这类日报的可信度依据,
text-overflow:ellipsis把它变成「(某口径)…」等于把立论依据藏起来。小屏上应允许换行。 - 首屏别只放装饰。hero 占 62% 屏时,用户看不到任何内容。压缩 hero 与统计卡的间距,让首屏露出第一个分区标题。
改完必做三项回归
- 只改样式:比对「去掉
<style>/<script>后正文完全一致」——证明没动内容。再加标签开闭差、CSS 花括号差为 0、分区数与卡片数不变。 - 桌面端不回归:1440px 下再测一遍(卡片多列、宽表仍是
display:table、导航不需横滚)。 - 多份产物一致性:模板 + 最新一期 + 各期归档 + 备份,
@media块必须逐字节一致(md5 校验)。否则改一次只在当期生效,历史各期样式各不相同。用脚本批量替换 + 统一校验,别手改。
最后把量化清单写进每日任务的自检项:新一期生成后要跑一遍并报数。否则下一次生成又把 overflow-x、scroll-margin-top 这些细节丢回去。
另外,截图取证要等动画结束——入场动画进行中抓图会得到「标题半透明、计数为 0」的假象,容易误判成内容缺失。