Files
dsh_ai1net_server/归档/skills-清理-20261007/content-source-governance/SKILL.md
T
admin c1b5e4d966 chore(工作区): 全量入库 + 补齐 .gitignore(以工作区为准)
- 变更规模:新增 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/ 知识文件,按口径入库)
2026-10-10 23:13:22 +08:00

19 KiB
Raw Blame History

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 自动生成一份日报,三周后一定会出现的五个病:

  1. 信源越用越水——第一周引 Bloomberg,第三周引中文聚合号,第五周引内容农场。
  2. 主角跑偏——想报的是「个人开发者小项目」,实际全是 OpenAI、Anthropic 的融资新闻,因为巨头新闻最好搜、最多、最省事。
  3. 数字对不上——首屏写「28 条」,页脚写「25 条」,某个分区徽标写「11 条」但里面只有 5 张卡。
  4. 历史被覆盖——流程里全是覆盖写,用户开始担心「生成新的会不会把旧的删了」;这类担心一旦出现,信任就已经受损了。
  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 与统计卡的间距,让首屏露出第一个分区标题。

改完必做三项回归

  1. 只改样式:比对「去掉 <style>/<script> 后正文完全一致」——证明没动内容。再加标签开闭差、CSS 花括号差为 0、分区数与卡片数不变。
  2. 桌面端不回归:1440px 下再测一遍(卡片多列、宽表仍是 display:table、导航不需横滚)。
  3. 多份产物一致性:模板 + 最新一期 + 各期归档 + 备份,@media 块必须逐字节一致(md5 校验)。否则改一次只在当期生效,历史各期样式各不相同。用脚本批量替换 + 统一校验,别手改。

最后把量化清单写进每日任务的自检项:新一期生成后要跑一遍并报数。否则下一次生成又把 overflow-x、scroll-margin-top 这些细节丢回去。

另外,截图取证要等动画结束——入场动画进行中抓图会得到「标题半透明、计数为 0」的假象,容易误判成内容缺失。