Files
SEONexus/docs/1270-SEONexus-Codex多版本协作交接总文档.md

90 KiB
Raw Blame History

1270-SEONexus Codex 多版本协作交接总文档

正式服接手极简版

如果新的 Codex 会话是在正式服或其他机器上接手,而且当前目标是继续追回 GPT 模板深页 seo_copy 资产,先直接执行这一段,不要先大范围自由发挥。

当前共识

  1. GPT 模板结构恢复主线已经跑通
  2. jpjdxs-com 已验证:
    • 首页可命中 guide-collection
    • 详情页可命中 guide-detail
    • 播放页可命中 guide-play
  3. 当前仓库内真正已经确认有非 default 深页资产的正式 host主要是
    • chuanjiafeng-net
    • liangzuan-net
    • jpjdxs-com
  4. 下面这批 host 当前仓库里仍然只是 detail/play default-only,下一步应优先去正式服或其他机器找历史产物:
    • pcslcl-com
    • lsrxs-com
    • lmjcg-com
    • nblssy-com

当前 Git 节点

2026-04-16 本轮已经完成一笔主链提交:

  • commit: 2a905bbf
  • message: restore gpt seo copy pipeline and stabilize seo tkd output

这一笔提交已经落下的内容包括:

  • videoGpt1seo_copy 模块重新挂载
  • VideoService / SiteContext 的 TKD 输出主链恢复
  • title / keywords / description 输出净化
  • 路由兼容与 slug + id 场景取数修复
  • DPlayer 容器初始化修复
  • jpjdxs-com 样本文案回灌
  • 交接文档同步更新

当前提交后的边界

这次提交之后,仓库里仍然保留一批未整理残留,后续接手时不要误判成“本轮漏提”:

  • 其它 videoGpt1 页面模板改动
  • VideoCategoryModel / VideoModel 的独立改动
  • seo_copy_release_run.php 等脚本改动
  • chuanjiafeng-net / liangzuan-net 下的大量生成或回灌数据
  • code/public/_seo_copy_release/ 下的发布产物

因此后续如果要继续提交,默认进入的是“第二批整理阶段”,不是继续补提第一批主链。

接手后先做什么

按这个顺序:

  1. 先看本机目标项目目录下是否存在:
    • code/data/seo_copy_published/<host>/detail
    • code/data/seo_copy_published/<host>/play
    • code/storage/domain_bootstrap_bundles
    • code/storage/seo_copy_publish_logs/backups
  2. 重点只找两类文件:
    • detail/*.json 中非 default.json
    • play/*.json 中非 default.json
  3. 如果找到真实深页文件,就回灌到:
    • code/data/seo_copy_published/<host>/detail
    • code/data/seo_copy_published/<host>/play
  4. 回灌后必须再做页面验证:
    • 详情页是否命中 guide-detail
    • 播放页是否命中 guide-play

不要再重复做的事

  1. 不要再默认当前开发仓库里一定还有第二份历史资产
  2. 不要再把“模板入口丢失”和“深页资产缺失”混成一件事
  3. 不要用域名原文去跑目录脚本

例如:

  • 错:--host=jpjdxs.com
  • 对:--host=jpjdxs-com

接手时建议直接回报的最小信息

只要回复这 6 条就够主线继续判断:

  1. 当前排查机器名
  2. 当前项目根目录
  3. 目标 host
  4. 是否存在非 default detail/*.json
  5. 是否存在非 default play/*.json
  6. 回灌后是否命中 guide-detail / guide-play

2026-04-16 晚间补充结论GPT 模板“已做优化突然像没了”的真实根因

这段是给后续 Codex 专门避坑用的。

当出现下面这些现象时:

  • 详情页 / 播放页的引导文像突然没了
  • 播放页 canonical 又指回详情页
  • 详情页切集链接退化成 /bf-76359-/douban-1
  • 你感觉“之前已经测试通过的 GPT 模板优化好像被覆盖了”

不要先判断成:

  • seo_copy 数据丢了
  • seotkd 数据被删了
  • 只是数据库被覆盖了

本轮已经确认过,至少在 videoGpt1 这条线上,更常见的真实根因是:

  1. 活跃模板链路里重新混入了旧模板写法
  2. 旧写法继续使用 {site:vpurl ...},没有稳定走 VideoService::getVideoPlayUrl(...)
  3. 结果就是:
    • 详情页切集列表可能退回旧格式
    • 播放页内部切集入口可能退回旧格式
    • 播放页 canonical / og:url / JSON-LD url 可能重新指错
  4. 所以最终表现会让人误以为“之前做过的 SEO/UI 优化全部消失了”

这次已经确认修过的活跃入口

如果后面又出现类似问题,优先检查这些文件,而不是先去怀疑数据库:

  • code/app/home/view/videoGpt1/video/getVideoPlayUrl.html
  • code/app/home/view/videoGpt1/module/playline/layout/layout_A.html
  • code/app/home/view/videoGpt1/module/playline/layout/layout_B.html
  • code/app/home/view/videoGpt1/module/playline/layout/layout_C.html
  • code/app/home/view/videoGpt1/module/play/play_01.html
  • code/app/home/view/videoGpt1/module/play/play_02.html
  • code/app/home/view/videoGpt1/module/play/play_03.html
  • code/app/home/view/videoGpt1/module/play/play_04.html
  • code/app/home/view/videoGpt1/module/play/play_05.html
  • code/app/home/view/videoGpt1/module/detail_main/action.html
  • code/app/home/view/videoGpt1/module/detail_main/cover.html

这次已经确认过的验证标准

后续 Codex 不要只看页面“能打开”,而要按下面标准验:

  1. 详情页包含 guide-detail
  2. 播放页包含 guide-play
  3. 详情页切集链接必须带 slug例如
    • /bf-76359-san-fen-zhi-yi-qing-ren/douban-1
  4. 不能再出现:
    • /bf-76359-/douban-1
  5. 播放页 canonical 必须指向播放页自己,而不是详情页
  6. og:url 与 JSON-LD url 也必须同步指向播放页自己

模板表达式的额外坑

本轮还确认了一个模板层坑:

  • 在模板 {: ... } 表达式里直接写 app(\app\services\VideoService::class),某些场景下会被模板解析吞掉命名空间
  • 报错形式通常像:
    • 类不存在: appservicesVideoService

因此模板内联调用更稳的写法是:

  • app('app\\services\\VideoService')->getVideoPlayUrl(...)

如果后续又出现“明明逻辑没问题,但模板页直接系统错误”,优先先查这一条。

DPlayer 那条旧问题的当前结论

之前出现过:

  • TypeError: Cannot read properties of null (reading 'classList')

本轮复核后,当前正式生效的编译脚本是:

  • code/public/static/js/compiled/48dd19fee8.js

其中与 DPlayer fullscreen 相关的 classList 访问已经带容器判空保护,因此:

  • 当前仓库主链并没有重新把这条空指针直接引回来
  • 如果后续线上再次出现这类报错,优先怀疑:
    • 老旧静态资源缓存未清
    • 旧模板 JS 被覆盖回线上
    • 不是本轮这批 videoGpt1 模板修复本身造成的

2026-04-16 GPT 模板快速验收清单

这份清单给后续所有 Codex 共用。

目标不是“页面能打开就算过”,而是快速确认:

  • seo_copy 引导块还在
  • TKD 还在
  • URL 没退化
  • detail / play 主链没被旧模板重新接管

验收前提

默认以某个已验证 host 为样本,例如:

  • jpjdxs.com

本轮验证样本里常用的页面有:

  • 首页:/
  • 榜单首页:/phb-index
  • 一级分类页:/videotype/1-dian-ying
  • 二级分类页:/videotype/dian-ying/shao-shi-dian-ying-1
  • 搜索结果页:/get-index?keyword=test
  • 详情页:/neirong-76359-san-fen-zhi-yi-qing-ren
  • 播放页:/bf-76359-san-fen-zhi-yi-qing-ren/douban-1

页面级验收标准

  1. 首页

    • 必须命中:guide-collection
    • 必须能看到:首页导览、自定义首页引导块
    • 必须有正常 title / keywords / description
  2. 榜单首页

    • 必须命中:guide-collection
    • 必须有正常榜单页 TKD
  3. 一级分类页

    • 必须命中:guide-collection
    • 必须有正常分类页 TKD
  4. 二级分类列表页

    • 必须命中:guide-collection
    • 必须有正常列表页 TKD
  5. 搜索结果页

    • 必须命中:guide-collection
    • canonical 必须指向当前真实搜索页
    • og:url 必须与 canonical 一致
    • CollectionPage.url 必须与 canonical 一致
  6. 详情页

    • 必须命中:guide-detail
    • canonical / og:url / JSON-LD url 必须都指向详情页自己
    • 切集链接必须带 slug
    • 不能出现 /bf-76359-/douban-1 这种退化链接
  7. 播放页

    • 必须命中:guide-play
    • canonical / og:url / JSON-LD url 必须都指向播放页自己
    • 播放页内部切集链接不能退化成无 slug 形式

最小命令清单

以下命令是后续 Codex 可直接复用的最小验收方式。

假设当前本地回放入口是:

  • http://127.0.0.1:18081
  • Host 头是:jpjdxs.com
  1. 首页
curl -s -H 'Host: jpjdxs.com' 'http://127.0.0.1:18081/' | rg -n 'guide-collection|首页导览|<title>|<meta name="keywords"|<meta name="description"'
  1. 榜单首页
curl -s -H 'Host: jpjdxs.com' 'http://127.0.0.1:18081/phb-index' | rg -n 'guide-collection|<title>|排行榜|榜单'
  1. 一级分类页
curl -s -H 'Host: jpjdxs.com' 'http://127.0.0.1:18081/videotype/1-dian-ying' | rg -n 'guide-collection|<title>|<meta name="keywords"|<meta name="description"'
  1. 二级分类页
curl -s -H 'Host: jpjdxs.com' 'http://127.0.0.1:18081/videotype/dian-ying/shao-shi-dian-ying-1' | rg -n 'guide-collection|<title>|<meta name="keywords"|<meta name="description"'
  1. 搜索结果页
curl -s -H 'Host: jpjdxs.com' 'http://127.0.0.1:18081/get-index?keyword=test' | rg -n 'guide-collection|canonical|og:url|<title>'
  1. 详情页
curl -s -H 'Host: jpjdxs.com' 'http://127.0.0.1:18081/neirong-76359-san-fen-zhi-yi-qing-ren' | rg -n 'guide-detail|canonical|og:url|/bf-76359-san-fen-zhi-yi-qing-ren/douban-1|/bf-76359-/'
  1. 播放页
curl -s -H 'Host: jpjdxs.com' 'http://127.0.0.1:18081/bf-76359-san-fen-zhi-yi-qing-ren/douban-1' | rg -n 'guide-play|canonical|og:url|https://jpjdxs.com/bf-76359-san-fen-zhi-yi-qing-ren/douban-1'

通过 / 不通过的最小结论模板

后续 Codex 回报时,尽量只按这个格式,不要写散:

  1. 首页:通过 / 不通过
  2. 榜单首页:通过 / 不通过
  3. 一级分类页:通过 / 不通过
  4. 二级分类页:通过 / 不通过
  5. 搜索结果页:通过 / 不通过
  6. 详情页:通过 / 不通过
  7. 播放页:通过 / 不通过
  8. 当前唯一阻塞点:

如果搜索页再次异常,优先先查什么

搜索页这条容易和其它主链问题混在一起,后续若异常,先按这个顺序看:

  1. getSearchVideo.html 是否仍包含 module/seo_copy/collection
  2. canonical / og:url / CollectionPage.url 是否一致
  3. 是否又误用了错误类名
    • 错误示例:app\services\UrlBuilder
    • 正确类:app\common\helper\UrlBuilder
  4. 如果是本地 PHP 内置服务回放异常,再区分:
    • 是模板真报错
    • 还是仅本地回放对 query 参数存在边角波动

目的

这份文档用于让多个 Codex 在 SEONexus 新版与旧版本之间长期协作时,保持:

  • 交接清楚
  • 边界清楚
  • 合并节奏清楚
  • 不互相覆盖
  • 不重复试错

适用场景:

  • 你会在正式环境再安装一个或多个 Codex
  • 一个 Codex 主要盯新版优化
  • 另一个 Codex 主要盯旧版本蜘蛛抓取与优化
  • 后续还可能出现第 3 个、第 4 个 Codex

开工约定:

  • 每个 Codex 开始实际工作前,先阅读本文件
  • 没看完 1270 前,不进入代码改动阶段
  • 如有对应专题文档,再继续看 1269 或最近的 production-fix 文档

核心原则

1. 同一时间只优化一份代码

这是最重要的规则。

任何时刻只允许:

  • 新版在优化 或
  • 旧版本在优化

不允许两个 Codex 同时分别改两份代码后再互相猜着合。

正确节奏是:

  1. 先在一份代码上完成一轮优化
  2. 验证通过
  3. 合并/同步到另一份代码
  4. 再开始另一份代码的分析与优化

2. 另一份代码在未同步最新前,只做“观察”,不做“改动”

如果旧版本还没合并新版最新修复,则旧版本 Codex

  • 可以看日志
  • 可以写分析
  • 可以整理建议
  • 不能先改一套自己的实现

否则后面很容易出现:

  • 同一问题两边各修一版
  • 路由/模板/观测逻辑走偏
  • 合并时冲突越来越重

3. 新版是主验证场,旧版本是回灌场

除非明确说明某个问题只在旧版本存在,否则默认:

  • 新版先验证
  • 旧版本后回灌

这条规则适用于:

  • 蜘蛛抓取分析
  • 路由兼容
  • 抓取入口修复
  • sitemap / rss / robots 修复
  • 前端站群 Nginx 动态回源策略

不适用于:

  • 旧模板专属结构问题
  • 旧模板专属页面 bug
  • 旧模板专属样式/模板分支问题

版本边界

新版负责什么

新版主要承担:

  • SEO 主线优化
  • 蜘蛛抓取分析
  • 新路由兼容策略验证
  • 抓取入口修复
  • 深页 301/404/500 治理
  • RSS / sitemap / canonical 规范
  • 新功能验证

旧版本负责什么

旧版本主要承担:

  • 已验证能力的回灌
  • 老模板抓取稳定性修复
  • 老模板历史路由兼容
  • 老模板蜘蛛行为观察
  • 老模板入口层与规范层修复

不要让旧版本先承担的内容

这些优先在新版验证,不要先在旧版本自由发挥:

  • Bootstrap 总控台整条链
  • 站外 SEO 全量工作台
  • 大型后台运营工作流
  • 新模板展示层重构
  • URL 主输出风格大改

多 Codex 协作角色建议

Codex-A新版主线 Codex

职责:

  • 新版 SEO 优化
  • 蜘蛛日志分析
  • 路由兼容修复
  • 抓取入口修复
  • 新功能验证
  • 输出可回灌结论

Codex-B旧版本回灌 Codex

职责:

  • 等待旧版本合并最新版代码
  • 分析旧版本蜘蛛抓取
  • 验证回灌效果
  • 只做老模板特有问题修复
  • 不先发明与新版不同的实现

Codex-C / Codex-D后续扩展 Codex

职责建议:

  • 专项观察
  • 文档整理
  • 日志归纳
  • 回归验收

不建议一上来让多个 Codex 同时改核心路由/模板。


每次开始工作前必须确认的事项

任何一个 Codex 开工前,先确认以下 8 条:

  1. 先看完:
  • 1270-SEONexus-Codex多版本协作交接总文档
  1. 当前自己负责的是:
  • 新版 还是
  • 旧版本
  1. 另一份代码是否已经合并了最新修复

  2. 当前轮次是:

  • 观察
  • 修复
  • 回灌
  • 验收
  1. 这轮是否允许改代码

  2. 是否已有上一个 Codex 的交接结论

  3. 本轮修复目标是否只限定在一个主题

  4. 当前结论是应该先写本地分析,还是已经可以回流主文档

  5. 当前这轮是否涉及多服务器协作,如果涉及,谁是主线收口责任人

例如:

  • 蜘蛛抓取概览
  • 深页兼容
  • RSS 修复
  • 旧模板入口规范

不要一轮里又修蜘蛛、又修广告、又修 Bootstrap、又补后台工作台。

如果当前是新开会话或新装的 Codex建议固定顺序

  1. 先看 1270
  2. 再看当前阶段执行文档,例如 1269
  3. 再看最近一次相关 production-fix 文档
  4. 最后再去读代码、日志和本地分析文档

严格边界

1. 不自动跨版本做“顺手修复”

例如当前在旧版本分析蜘蛛问题时,不要顺手:

  • 改新版模板
  • 改新版站外 SEO 面板
  • 改新版 Bootstrap

反过来也一样。

2. 不自动提交

除非用户明确要求,否则:

  • 不自动 commit
  • 不自动 push

先把改动留在工作区,等用户确认。

3. 不整包恢复历史提交

22cc72ee 这种历史提交,只能作为:

  • 缺失源码来源

不能整包恢复。

因为这类提交往往还混着:

  • 运行产物
  • 测试数据
  • storage 输出
  • 临时样板文件

正确做法是:

  • 定点恢复源码
  • 然后继续冒烟验证

4. 不在两个版本上同时独立发明方案

例如:

  • 新版把深页兼容做成 A
  • 旧版本同时自己做成 B

这是最容易制造后续冲突的做法。


本轮关键经验补充

这一节记录 2026-04-16 这轮 videoGpt1 恢复与排障中已经确认的高价值结论。

后续任何 Codex 如果再遇到:

  • GPT 模板首页/详情/播放页引导文突然消失
  • 分类首页、榜单列表、搜索页突然 404 或系统错误
  • 某些域名正常,某些域名不正常

请优先先看这一节,再决定是否继续深挖。

1. 不是所有“页面丢内容”都是数据库问题

这轮已经确认GPT 模板前面做过的引导文、补料、搜索引导、详情引导、播放引导,并不一定是数据库被删。

更常见的真实原因有 3 类:

  1. 模板文件被较轻版本覆盖
  2. 路由把请求导错了模板
  3. 服务层类型约束变严后,旧模板传空值直接报错

所以不要一看到:

  • title 空了
  • 引导文没了
  • 分类页报错
  • 搜索页 404

就直接判断成:

  • seo_key 丢了
  • 数据库被覆盖了
  • AI 生成没执行

正确顺序应该是:

  1. 先看实际命中的模板
  2. 再看实际命中的路由
  3. 再看服务层是否因为 null / '' 被强类型拦截
  4. 最后才去怀疑数据层

2. GPT 模板当前已确认恢复的主线页面

这轮已经恢复并验证通过的页面包括:

  • 首页引导层
  • 详情页引导层
  • 播放页引导层
  • 分类首页
  • 一级分类页
  • 二级分类页
  • 榜单首页
  • 榜单列表页
  • 搜索结果页
  • 历史记录页

其中首页、详情页、播放页的引导层恢复,不是只在一个域名生效,而是已经按多种路由家族做过抽查。

3. 本轮确认过的三条高频根因

根因 A模板层被“轻量 seo_copy include”替换后深页补料不再显性输出

现象:

  • 首页还有一点东西
  • 详情页/播放页引导感明显变弱
  • 页面不报错,但前面测试过的引导文 UI、卡片、提示区块明显没了

结论:

  • 不是整套模板消失
  • 是 richer 版本页面级引导层退化成了轻量 include

处理原则:

  • 优先从历史 git 内容里恢复页面级引导结构
  • 不要简单再重写一套全新的风格

根因 B路由注册错位页面请求被导到了错误模板

本轮已确认过两个典型错位:

  1. category_home 错导到 video/getCategory.html
  2. rank_list 错导到 video/getRankIndex.html

后果:

  • 分类首页会拿分类列表模板跑
  • 榜单列表会拿榜单首页模板跑
  • 页面可能有 title但正文报 系统发生错误

处理原则:

  • 先检查 code/app/home/config/router.php
  • 再确认当前 page code 应该落到哪一个视图

根因 C服务层 URL 方法后来加了强类型,旧模板空参数直接炸

本轮确认过的典型报错:

  • getVideoCategoryIndexUrl(): Argument #1 must be of type string, null given
  • getVideoRankUrl(): Argument #1 must be of type string, null given

这类问题的本质不是业务逻辑坏了,而是:

  • 模板原来允许空值
  • 服务层后来把参数收紧成强类型
  • 一些分类首页 / 榜单页 / 空场景入口就直接报错

处理原则:

  • 先恢复服务层对 null / '' 的兼容
  • 不要先大面积改模板传参

原因很简单:

  • 兼容服务层后,多个模板家族都会一起恢复
  • 如果只修模板,很容易这里修好,别处再炸一个

4. .html 冻结路由是 GPT 新路由分支的重点兼容项

这一条非常重要。

当前 videoGpt1 不是走旧模板那套通用路由,而是走前面的 GPT 新路由分支,并且中途会直接 return

这意味着:

  • 后面的旧版搜索/历史等通用路由根本不会执行
  • 任何冻结 family 里定义的搜索、历史、分类、榜单入口,都必须在 GPT 新路由分支里完整注册

本轮已确认一批域名使用:

  • get.html
  • record.html

这类带 .html 的冻结路径。

如果 GPT 新路由只按普通字符串注册,而不补 ->ext('html') 兼容别名,就会出现:

  • 无点路径域名正常
  • .html 路径域名全部 404

这轮已经验证通过的 dot-family 域名包括:

  • chuanjiafeng.net
  • lcdchq.com
  • lgyz.net
  • oronorent.com
  • sdxhtgcl.com

这些域名现在都已经确认:

  • /get.html?keyword=test 正常返回搜索结果页
  • /record.html 正常返回历史记录页

5. 以后排查顺序建议

如果后面 снова 遇到 GPT 模板页面回退、404、搜索失效、分类页异常优先按这个顺序

  1. 看当前域名 theme_cache 里的 url_family
  2. 看该路由在 code/app/home/config/router.php 是否注册到正确视图
  3. 看是不是 .html 冻结路径
  4. 看服务层 URL 方法有没有因为 null 参数炸掉
  5. 看页面实际 HTML 是否已经命中 guide-collection / dm-desc-guide / guide-play
  6. 最后再怀疑数据层或 AI 生成层

不要一开始就:

  • 回滚整仓
  • 重建全部 SEO 数据
  • 重新写一套模板

这样很容易把已经修好的主线再覆盖掉。


本轮主线可复用修复

以下内容属于“主线可复用修复”,后续如果旧版本或其它服务器出现同类问题,可以优先对照吸收:

路由层

  • category_home 应落到 video/getMap.html
  • rank_list 应落到 video/getRankList.html
  • .html 的冻结路径需要补无后缀 ext('html') 兼容别名

服务层

  • getVideoCategoryIndexUrl() 需要兼容 null
  • getVideoRankUrl() 需要兼容 null

模板层

  • 首页需要有显性导览区,不要只剩纯卡片瀑布流
  • 详情页需要保留剧情说明 + 延伸词入口 + 播放跳转提示
  • 播放页需要保留当前线路 / 当前剧集 / 返回详情页 / 观看建议

交接提醒

后续 Codex 如果接到类似任务,请先确认:

  1. 当前问题到底是模板退化、路由错位,还是类型约束报错
  2. 当前域名是否使用 .html 风格冻结搜索/历史路由
  3. 当前问题是否已经在新版主线修过,可以直接回灌而不是重做

如果是同类问题,优先复用本轮思路,不要再重新设计一套实现。


SEO 文案发布层特别注意

1. 不要把“页面退化”直接等同于“模板被回滚”

videoGpt1 这类模板里,页面最终看到的引导文、补料、差异化说明,至少分成两层:

  • 模板层是否还渲染对应区块
  • seo_copy_published 是否真的存在细粒度发布结果

如果模板还在,但 seo_copy_published/<host>/detailplay 下面只剩:

  • default.json

那么前台虽然还能出内容,但只会退回默认文案,不会再有:

  • 单视频差异化文案
  • 单播放页差异化文案
  • 之前那种“每个域名、每个页面不完全一样”的细粒度表现

也就是说:

  • 页面看起来像“前面的优化没了”
  • 不一定是模板没了
  • 很可能是发布层退回默认版了

2. 当前仓库已经确认的事实

2026-04-16 本地排查中,已确认:

  • code/data/seo_copy_published 共 27 个域名
  • 27 个域名全部只有 detail/default.json
  • 27 个域名全部只有 play/default.json
  • 没有任何 detail/<video_id>.json
  • 没有任何 play/<video_id>-play-<type>-<index>.json

这说明当前仓库里的“已发布文案目录”本身就是默认版,不是单个页面偶发异常。

3. 审计命令

后续任何 Codex 遇到“差异化文案是不是又丢了”时,先跑:

php code/scripts/seo_copy_published_audit.php --format=text

按域名单查:

php code/scripts/seo_copy_published_audit.php --host=lmjcg-com --format=text

带样本页检查预期 key 是否存在:

php code/scripts/seo_copy_published_audit.php \
  --host=lmjcg-com \
  --sample-detail=76310 \
  --sample-play=76310:default:1 \
  --format=text

如果输出里看到:

  • detail_default_only: yes
  • play_default_only: yes
  • expected_checks ... exists=no

就说明问题在发布层,不要先去重写模板。

4. Git 历史判断规则

如果怀疑是 git 覆盖导致退化,优先同时检查两块:

  • 模板源码历史
  • code/data/seo_copy_published 历史

这次已经确认:

  • 模板关键文件并没有发生整包回滚到很老版本
  • code/data/seo_copy_published 当前提交内容本身就是 default-only 版本

所以后续排查顺序应固定为:

  1. 先审计 seo_copy_published
  2. 再确认模板区块是否还在
  3. 最后才决定是否需要从历史发布批次恢复细粒度文案

5. Git 推送只能使用 www 用户

这是当前机器的固定约束,不要忽略。

原因:

  • root 用户可以排查问题、读日志、跑测试
  • root 没有 origin2 的可用 SSH 私钥
  • www 用户已经配置好可用私钥,且已验证可正常推送到 origin2

因此后续所有 Codex 都必须遵守:

  • 可以用 root 做分析、读取、验证
  • 一旦涉及 git push,只能切到 www
  • 不要再直接用 root 执行 git push origin2 dev

标准推送命令:

su -s /bin/bash www -c 'git -C /www/wwwroot/diff-maccms/SEONexus push origin2 dev'

如果需要先查看状态,也建议保持同一口径:

su -s /bin/bash www -c 'git -C /www/wwwroot/diff-maccms/SEONexus status'
su -s /bin/bash www -c 'git -C /www/wwwroot/diff-maccms/SEONexus log --oneline -n 3'

已验证结论:

  • root 推送会报 Permission denied (publickey...)
  • www 推送 origin2 正常成功

所以这不是代码问题,也不是远端仓库问题,而是当前机器上的 Git 身份边界。

5.1 仓库 ownership 也必须保持 www:www

除了 git push 只能使用 www,当前机器上还要额外遵守一条:

  • SEONexus 仓库目录本身也必须保持 www:www

尤其不能让下面这些路径长期混入 root:root

  • .git
  • .git/index
  • .git/objects/*
  • docs/
  • 其它会被 git pull / git checkout 自动写入的目录

已经验证过的真实故障现象包括:

  • error: insufficient permission for adding an object to repository database .git/objects
  • fatal: failed to write object
  • fatal: unpack-objects failed
  • error: unable to create file docs/...: Permission denied

这类问题的根因不是远端仓库异常,而是:

  • 前面曾用 root 对仓库做过 commit、写文件或目录创建
  • 导致 www 后续执行 pull / push / stash 时权限链断掉

因此后续建议固定为:

  • 与 Git 直接相关的操作优先都用 www
  • root 只做日志排查、系统命令、权限修复
  • 不要再用 root 在仓库里直接 commitpullpush

如果已经出现 ownership 混乱,优先修复命令为:

chown -R www:www /www/wwwroot/diff-maccms/SEONexus

如果只是 .git 或仓库内同步文档目录出错,也至少要修:

chown -R www:www /www/wwwroot/diff-maccms/SEONexus/.git
chown -R www:www /www/wwwroot/diff-maccms/SEONexus/docs

这条规则和“只能 www 推送”应视为同一组约束,不能只做一半。

6. SEONexusSEONexusAdmin 是同机双仓协作

当前机器上:

  • SEONexus
  • SEONexusAdmin

都位于同一台机器的 /www/wwwroot/ 下。

这意味着:

  • 它们适合联合排查
  • 但仍然是两个独立仓库
  • 不能因为同机就默认一起改

推荐理解方式:

  • SEONexus 主要负责后端接口、路由、helper、model、日志、返回结构
  • SEONexusAdmin 主要负责前端页面、接口调用、参数、token/header、错误展示
  • Nginx / 域名 / 反代 / CORS / 登录态链路属于同机环境层

因此遇到后台报错时:

  • 可以跨仓一起查
  • 但修复时先判断主战场
  • 一轮优先只改一个主仓

例如:

  • 如果是接口 500、类缺失、helper 丢失、路由没挂,主战场通常是 SEONexus
  • 如果是 axios 参数、header、token、前端展示层误报主战场通常是 SEONexusAdmin
  • 如果是跨域、代理、cookie、header 丢失,主战场通常是 Nginx / 反代配置

这条规则的核心不是“分开”,而是:

  • 同机便于联查
  • 分仓便于控边界

7. 不建议现在把所有项目硬并成一个 Git 仓库

当前更适合的结构是:

  • 多个独立 Git 仓库
  • 通过仓库内 doc/ 文档同步协作规则
  • 通过明确边界控制多 Codex 并行协作

不建议现在把所有项目直接并成一个大仓,原因包括:

  • SEONexusSEONexusAdmin、node 工具链、蜘蛛代理脚本、历史参考目录,生命周期并不一致
  • 不同项目的提交节奏不同,强行并仓后日志会很乱
  • 后续回滚、比对、定向发布会更重
  • 正式服未必需要开发机当前的总目录结构
  • 现在真正需要同步的是规则和关键文档,不是把所有杂项目录绑成一个提交历史

当前阶段更推荐:

  • 业务主仓继续独立维护
  • 关键协作文档同步到主仓的 doc/
  • 需要跨仓排查时,通过文档说明目录关系和排查顺序

只有在未来满足以下条件时,才考虑是否要做 monorepo

  • 多个仓长期高度耦合
  • 发布必须严格同版本号
  • CI/CD 也准备统一
  • 权限、分支策略、回滚策略都已经设计清楚

在当前阶段,最稳的结论是:

  • 不要把所有项目硬归成一个 Git
  • 先把“协作规则归一、文档入口归一、推送口径归一”做好
  • 这样收益更大,风险更小

8. 本轮 GPT 模板“像被覆盖了”的根因结论

这条是 2026-04-16 本地持续排查后新增的强结论,后续 Codex 看到“首页 title 变空、引导文没了、播放页像退回毛坯版”时,先按这里理解,不要再一上来误判成“整个 GPT 模板被回滚没了”。

8.1 早期 GPT 模板主骨架其实还在

从 git 历史看,真正把 videoGpt1 模板做起来的关键提交主要是:

  1. eb8c0977 gpttemp2025-12-31
  2. 90fc16fb gpt2026-01-09
  3. 04f303ca index2026-01-10
  4. e23bf61f indextitle2026-01-10

这些提交当时一起改了:

  • code/app/home/view/videoGpt1/...
  • code/app/services/VideoService.php
  • code/app/services/SiteContext.php
  • 列表、评论、播放、详情等页面层

因此本轮看到的退化现象,不应直接理解成“那批 GPT 模板代码整包没了”。

8.2 真正可疑的覆盖点在 origin2/dev

当前分支关系已确认:

  1. origin/dev 停在较早位置
  2. origin2/devorigin/dev 多出一整串后续提交
  3. 其中与这次问题最直接相关的关键提交是:
    • 887e9528 debug2026-04-14

这个提交做了一个非常关键的动作:

  1. 首次把 code/data/seo_copy_published 批量纳入 git
  2. 但纳入的内容是低覆盖版本
  3. 对 27 个域名来说,detail / play 基本只有 default.json
  4. 没有原先那种按视频 id、播放线路、集数拆开的细粒度深页发布结果

8.3 所以当前更像是“发布数据覆盖”,不是“模板源码被删”

更准确的判断应该是:

  1. 模板骨架大部分仍在
  2. theme_cache 和模块布局大部分仍在
  3. 但是模板后续开始接入 seo_copy 后,读取到的是 default-only 的发布产物
  4. 于是原先更细的深页引导文,被统一的默认文案层盖平

用户体感上就会变成:

  • 差异化引导文没了
  • 页面排版味道变弱了
  • 看起来像之前做过的 SEO 优化都被抹掉了

8.4 当前已锁定的责任边界

后续排查和恢复,优先按下面结论执行:

  1. origin/dev 不是这次 seo_copy_published 覆盖的主要来源
  2. 当前已知问题链,主要来自 origin2/dev 这一串后续提交
  3. 其中 887e9528 debug 是这次“深页差异化内容退化”的关键观察点
  4. bd073c677fff1a99 主要修路由、id-first、helper 恢复,不是这次内容退化的首因

8.5 恢复优先级

既然根因更偏向“发布数据被低覆盖版本顶掉”,恢复顺序必须固定为:

  1. 先恢复历史深页 seo_copy 发布数据
  2. 再验证模板区块是否需要微调
  3. 最后才考虑是否补新的内容生成

这一条必须强调:

  • 优先恢复历史已验收资产
  • 不要先用新的通用 AI 文案把旧资产覆盖掉

否则会继续出现:

  • 页面能显示
  • 但和之前测试通过的那版体验不一致
  • 用户感觉“怎么又被重新写坏了”

工作顺序标准流程

场景 A新版先优化旧版本后回灌

  1. 新版 Codex 分析问题
  2. 新版 Codex 实施修复
  3. 新版验证通过
  4. 文档记录“哪些能力适合回灌旧版本”
  5. 旧版本合并最新代码
  6. 旧版本 Codex 开始观察与回灌验证
  7. 只补旧模板特有问题

场景 B旧版本先发现问题

  1. 先判断该问题是不是旧模板专属
  2. 如果不是旧模板专属,先回新版验证
  3. 新版验证后再回灌旧版本
  4. 如果是旧模板专属,再只在旧版本修

哪些优化适合回灌旧版本

适合

这些通常适合回灌:

  • 蜘蛛抓取日志分析
  • 抓取概览工作台
  • robots.txt 修复
  • rss/baidu.xml 修复
  • sitemap 修复
  • canonical 规范
  • 历史 detail/play/category 路由兼容
  • 深页 404/301 治理
  • 前端站群 Nginx 统一动态回源策略

慎回灌

这些要单独评估:

  • 坏链随机视频兜底
  • 播放页 SEO 策略大改
  • URL 主输出规则变更
  • 复杂站外 SEO 面板
  • 导入健康台全家桶
  • Bootstrap 总控台整条链

多 Codex 的交接模板

每个 Codex 每轮结束时,至少留下以下内容:

1. 本轮工作对象

  • 新版 / 旧版本
  • 目录路径
  • 当前分支

2. 本轮目标

例如:

  • 修复百度深页 301 -> 404
  • 验证旧模板蜘蛛抓取概览
  • 补回 rebase 丢失 helper

3. 本轮已改动文件

必须列路径。

4. 本轮未提交改动

说明是否:

  • 仅工作区修改
  • 已暂存
  • 已提交但未 push

5. 本轮验证结果

至少说明:

  • 哪些通过
  • 哪些没通过
  • 哪些未验证

6. 下一位 Codex 的注意事项

必须写明:

  • 不要碰哪些文件
  • 先看哪个文档
  • 下一个最值动作是什么

文档同步规则

每轮有效优化后,至少同步两类文档中的一种:

1. 主题执行文档

例如:

适合记录:

  • 旧模板回灌目标
  • 分阶段策略
  • 验收口径

2. Codex 交接总文档

也就是当前这份文档,适合记录:

  • 协作规则
  • 边界
  • 交接模板
  • 多版本协作方法

如果后续发现某条规则经常踩坑,就更新本文件,不要只留在聊天记录里。

3. 单次线上事件排障文档

这类文档适合记录:

  • 某一次正式服报错的完整排查过程
  • 问题阶段
  • 根因
  • 线上改动
  • 验证结果
  • 下一位 Codex 的接手建议

当前已沉淀样例:

使用原则:

  • 1269 这类文档负责阶段执行
  • 1270 这类文档负责长期协作规则
  • 2026-xx-xx-...production-fix 这类文档负责单次线上事件闭环

这样后续主 Codex 接手时:

  • 先看长期规则
  • 再看当前阶段执行文档
  • 最后看最近一次线上事件文档

就不会只靠聊天记录反推上下文。

4. 项目本地持续分析文档

除了需要进入 Git 的正式文档外,每个项目还允许保留一套“只服务当前项目持续优化”的本地分析文档。

这类文档推荐放在项目自己的:

  • code/storage/_analysis/

使用原因:

  • 每个项目都有自己的蜘蛛日志来源、观察窗口和异常轨迹
  • 这类分析如果完全不记录,后续优化容易断档
  • 但如果全部提交进 Git又会把大量过程性观察和未确认判断写进正式历史

因此这类文档的定位是:

  • 允许持续记录
  • 默认不提交
  • 以项目私有观察为主
  • 适合记录尚在观察期的中间结论

推荐最少按两层组织:

  • code/storage/_analysis/sources/
  • code/storage/_analysis/domains/

例如:

  • code/storage/_analysis/sources/baiduspider.md
  • code/storage/_analysis/sources/sogou.md
  • code/storage/_analysis/domains/sjzyunyang.com.md
  • code/storage/_analysis/domains/jingxifa.com.md

边界规则:

  • 可以在每个独立项目里持续写自己的分析文档
  • 也允许每个独立项目优化“本项目私有层”
  • 但不建议每个项目独立发明一套公共核心方案

也就是:

  • 项目私有观察可以分散记录
  • 公共核心方案仍应集中验证、集中沉淀、再回灌

5. 本地分析必须回流主文档

code/storage/_analysis/ 只负责本地持续观察,不应成为最终知识沉淀的终点。

只要本地分析满足以下任一条件,就必须再整理回主文档:

  1. 已确认根因
  2. 已验证修复有效
  3. 结论能跨机器复用
  4. 结论能跨模板族复用
  5. 结论能减少其它 Codex 的重复劳动
  6. 结论会影响协作边界或排查顺序

推荐回流判断方式:

  • 如果只是某台机器、某个时间窗口的临时观察,可以先留在 storage/_analysis/
  • 如果已经形成“别人以后不用再重新验证”的结论,就应升级到 SEONexus/docs/

推荐回流路径:

  • 全局协作规则 -> 1270
  • 阶段执行 / 回灌策略 -> 1269
  • 单次正式服事件闭环 -> 2026-xx-xx-...production-fix.md
  • 其它模板族或专题结论 -> 对应专题正式文档

这条规则的目标是:

  • 本地分析负责探索
  • 主文档负责共享
  • 不让每台机器都重复学习同一件事

6. 多服务器可以并行分析,但主线应单点收口

允许多台服务器同时进行:

  • 日志分析
  • 外网复测
  • 各自写本地 storage/_analysis
  • 提交各自的中间结论

但不建议多台服务器同时直接改同一个主线核心方案。

推荐规则:

  • 本地分析可以并行
  • 主线代码修改尽量单线
  • 正式共享文档尽量单一主责任人收口

尤其是以下内容,不建议多台机器同时独立改:

  • 深页兼容核心逻辑
  • 路由兼容总逻辑
  • 404 / 500 兜底主链
  • 蜘蛛抓取核心统计逻辑
  • 同一份正式共享文档

更稳的协作方式是:

  1. 多台机器并行做观察
  2. 各自把中间结论写到本地分析
  3. 主 Codex 统一判断哪些结论已经收敛
  4. 由一个主责任人修改主线代码或更新正式共享文档

这条规则的目标是:

  • 允许大家同时学习
  • 避免大家同时改乱主线

特别注意事项

1. 前端 Nginx 不要继续按 URL 模板枚举

前端站群应坚持:

  • 静态资源缓存
  • 非静态请求 MISS 后统一回后端

不要每新增一种 URL family就去补前端 Nginx 前缀。

2. 旧版本不要轻易改主输出 URL 风格

旧版本更适合:

  • 加兼容层
  • 不推翻当前主输出

3. 观测和修复要分开记录

不要把:

  • 日志观察
  • 推测
  • 已验证修复

写混。

4. 真实缺失源码与 CLI 冒烟假阳性要区分

像之前的:

  • Class not found
  • 路由没挂
  • helper 丢失

这类是真缺失。

但像:

  • Undefined array key 9999

在 CLI 直接调控制器时,可能只是 admin 配置上下文不完整,不一定是真缺源码。


推荐的交接口径

每个 Codex 对下一个 Codex 的交接,建议用这种结构:

  1. 当前负责版本
  2. 当前主题
  3. 已完成
  4. 未完成
  5. 禁止动作
  6. 下一步建议

例如:

  1. 当前负责版本:旧版本
  2. 当前主题:蜘蛛抓取概览与深页兼容验证
  3. 已完成:日志分析、入口检查、深页 404 修复验证
  4. 未完成:下一轮百度深抓效果观察
  5. 禁止动作:不要先改新版,不要整包恢复历史提交,不要自动 commit
  6. 下一步建议:先合并最新版后,再观察旧模板的 detail/play 抓取变化

最后的工作纪律

多个 Codex 长期协作时,最重要的不是“每个都很聪明”,而是:

  • 同步节奏一致
  • 边界清楚
  • 不抢改
  • 不乱回滚
  • 不各自发明一套实现

只要坚持这几条,后面就算扩到 3 个、4 个 Codex也仍然能稳。


videoGpt1 页面来源地图

videoGpt1 当前页面体验,不是由单一模块决定,而是至少由下面 4 层共同组成:

1. theme_cache

位置:

  • code/storage/theme_cache/<host>.json

作用:

  • 域名级 seed
  • dom_prefix
  • 页面模块顺序
  • 首页 / 分类 / 详情 / 播放的布局参数
  • 标题文案槽位
  • URL family

判断:

  • 这是 GPT 模板“每个域名看起来不一样”的核心来源之一
  • 当前排查中,这一层没有整体丢失

2. 模板原生结构

位置:

  • code/app/home/view/videoGpt1/...

作用:

  • 页面骨架
  • 标题样式
  • meta 栏
  • 行为按钮
  • 播放器外壳
  • 列表结构

详情页主链:

  • video/getVideoInfo.html
  • module/page/page_router.html
  • module/detail_main/detail_main_router.html
  • module/detail_main/layout/layout_B.html

播放页主链:

  • video/getVideoPlayUrl.html
  • module/page/page_router.html
  • module/player/player_router.html
  • module/player/engine/dplayer.html

3. seoaddon

入口:

  • module/detail_main/desc.html
  • {video:seoaddon ... /}
  • module/detail/_seo_addon.html

后端:

  • code/app/services/VideoService.php
  • code/app/common/helper/SiteStyle.php

作用:

  • 详情页摘要
  • 标签
  • 提示语

判断:

  • 这是原始 GPT 模板的重要组成部分
  • 不是后加的统一卡片层

4. seo_copy

入口:

  • 首页:index/index.html
  • 详情:module/detail_main/desc.html
  • 播放:video/getVideoPlayUrl.html

模板:

  • module/seo_copy/collection.html
  • module/seo_copy/detail.html
  • module/seo_copy/play.html

后端:

  • VideoService::getSeoCopyBlock()
  • SeoCopyStore

作用:

  • 补充说明
  • FAQ
  • guide cards 卡片

判断:

  • 这是后加层
  • 不是原始 GPT 模板的主体

当前恢复策略

为了尽量恢复到前面测试通过时更接近的 GPT 模板体验,当前策略如下:

1. site:seotkd 不允许输出空 TKD

位置:

  • code/app/services/SiteContext.php

兜底顺序:

  1. 新 GPT SEO 池
  2. 旧 SubjectFormat key
  3. domain 表字段

目标:

  • 不再出现空 title
  • 不再出现空 keywords
  • 不再出现空 description

2. detail / play 页面不强行渲染 default-only seo_copy

位置:

  • code/app/services/VideoService.php

原因:

  • 当前 code/data/seo_copy_published 中 27 个域名的 detailplay 全部只有 default.json
  • 同时 module/seo_copy/detail.html / play.html 是统一卡片式输出
  • 这会让详情页和播放页迅速退化成“通用说明卡片”

处理:

  • 如果详情/播放页没有命中具体 page key
  • 只命中 default
  • 就先不渲染这一层

目标:

  • 页面重新回到 theme_cache + 模板原生结构 + seoaddon 主导
  • 尽量靠近之前 GPT 模板实测通过时的观感

当前判断顺序

如果用户反馈“前面做好的 GPT 模板体验又没了”,应按以下顺序排查:

  1. title/keywords/description 是否为空
  2. theme_cache 是否还在且命中正常
  3. 看详情 / 播放页是否只剩 default-only seo_copy
  4. 再判断是否真的发生过模板 Git 回退

不要先入为主认定“全部是 Git 覆盖”,因为当前更明显的现象是:

  • 域名级模板差异仍在
  • seo_copy 深页细粒度内容缺失
  • 叠加 TKD 取值异常后,页面体感会明显变差

2026-04-16 深页 seo_copy 恢复验证结论

已验证结论

本地仓库内,细粒度 detail/play 文案并不是“从未存在”,而是:

  • 以前真实生成过
  • 历史备份仍然存在
  • 当前生效目录退回成了 default-only

可追溯来源主要包括:

  • code/storage/seo_copy_publish_logs
  • code/storage/domain_bootstrap_bundles
  • code/storage/seo_copy_batch

已完成样本恢复

1. chuanjiafeng-net

恢复来源:

  • code/storage/domain_bootstrap_bundles/chuanjiafeng-compact/data/seo_copy

恢复结果:

  • detail_default_only: no
  • play_default_only: no
  • detail: total=17, default=yes, non_default=16
  • play: total=17, default=yes, non_default=16

样本核验:

  • detail | key=154229 | exists=yes
  • play | key=154229-play-douban-1 | exists=yes

2. liangzuan-net

恢复来源:

  • code/storage/domain_bootstrap_bundles/liangzuan-next-stage-b1/data/seo_copy

恢复结果:

  • detail_default_only: no
  • play_default_only: no
  • detail: total=1, default=no, non_default=1
  • play: total=1, default=no, non_default=1

样本核验:

  • detail | key=154124 | exists=yes
  • play | key=154124-play-youzhi-1 | exists=yes

已新增恢复脚本

脚本位置:

  • code/scripts/seo_copy_restore_from_source.php

用途:

  • 从历史来源目录恢复某个 host 的 detail/play 深页 JSON
  • 支持先 --dry-run
  • 支持指定 --host
  • 支持指定 --source
  • 默认写入 code/data/seo_copy_published

示例:

php code/scripts/seo_copy_restore_from_source.php \
  --host=chuanjiafeng-net \
  --source=code/storage/domain_bootstrap_bundles/chuanjiafeng-compact/data/seo_copy \
  --dry-run

正式写入:

php code/scripts/seo_copy_restore_from_source.php \
  --host=chuanjiafeng-net \
  --source=code/storage/domain_bootstrap_bundles/chuanjiafeng-compact/data/seo_copy

批量恢复原则

不要直接对全部 27 个域名做无差别恢复,推荐顺序:

  1. 先做单域名样本恢复
  2. 恢复后立刻跑审计
  3. 确认该域名前台表现符合预期
  4. 再决定是否扩大到更多真实域名

原因:

  • 不同域名的历史覆盖程度不同
  • 有的来源完整,有的来源只有 1 组样本
  • 有些 bundle 是测试/并发演练产物,不适合无脑全量导回

推荐的后续恢复策略

优先从这类来源中选择恢复源:

  1. 单域名专属 bundle
  2. next-stage / compact 这类更像正式沉淀的 bundle
  3. 再考虑 publish_logs

不建议优先使用:

  • 并发批次演练 bundle
  • 只包含样例域名的测试包

2026-04-16 当前 27 域名可恢复性分层

按本地仓库现状盘点:

A. 已完成样本恢复

  • chuanjiafeng-net

    • 当前生效:detail 非默认 16play 非默认 16
    • 最优来源:code/storage/domain_bootstrap_bundles/chuanjiafeng-compact/data/seo_copy/chuanjiafeng-net
    • publish_logs 也存在历史样本11 + 11
  • liangzuan-net

    • 当前生效:detail 非默认 1play 非默认 1
    • 最优来源:code/storage/domain_bootstrap_bundles/liangzuan-next-stage-b1/data/seo_copy/liangzuan-net
    • publish_logs 也存在历史样本1 + 1

B. 当前仓库内暂未发现可恢复深页来源

以下域名在本地盘点时:

  • domain_bootstrap_bundles 中未发现可用 detail/play 深页 JSON
  • seo_copy_publish_logs 中也未发现对应历史深页 JSON

名单如下:

  • caosheninan-com
  • cnzhenbang-com
  • codohealth-com
  • glae-cc
  • gxhongzhuang-com
  • gz-yxsw-com
  • hbczccq-com
  • hyjssb-com
  • jingxifa-com
  • jpjdxs-com
  • jxxgygy-com
  • lcdchq-com
  • leici1940-com
  • lgyz-net
  • lmjcg-com
  • lsrxs-com
  • nblssy-com
  • oronorent-com
  • pcslcl-com
  • sdxhtgcl-com
  • sdxtwnc-com
  • sjzyunyang-com
  • ukoys-com
  • vikau-com
  • visitsumenep-com
  • zbsv3-com

当前批量策略结论

基于现有本地仓库不建议直接做“27 域名全量恢复”,原因很直接:

  1. 当前已验证可恢复的真实域名只有 2 个
  2. 其余 26 个域名,至少在当前本地仓库中还没找到可靠深页来源
  3. 如果强行批量恢复,只会造成:
    • 一部分域名真的恢复
    • 大部分域名仍然 default-only
    • 后续误判“脚本没效果”或“恢复逻辑不一致”

因此当前更稳的策略是:

  1. 先保留已恢复样本域名
  2. 继续从其它机器 / 旧仓库 / 历史备份中找剩余域名来源
  3. 每新增一批可靠来源,再做分批恢复

2026-04-16 新增结论:publish_logs/backups 比之前判断更有价值

继续深挖后,发现前面的判断还可以再前进一步:

  1. code/storage/seo_copy_release_runs/20260408/*/run-summary.json
  2. code/storage/seo_copy_release_runs/20260408/*/batch_publish.summary.json

这两类文件明确证明,当时并不是只有 default-only 的发布层。

已确认的历史事实包括:

  1. 2026-04-08 的发布运行里,校验过 232 个文件
  2. 其中包含:
    • detail: 37
    • play: 39
    • category_list: 41
    • search: 35
    • 以及 home / category_index / rank_index / rank_list / forge
  3. front_verify 里还能直接看到真实页面文案预览,说明当时这些页面不只是存在文件,而且前台命中验证也通过过

这条结论非常重要,因为它说明:

  1. 历史资产在这个仓库里确实存在过
  2. 不是用户记忆偏差
  3. 也不是“从来就没做过”
  4. 只是当前工作树里主数据层已经不完整,剩下的更多是发布备份残留

新增脚本:从发布备份聚合恢复

为了避免手工从各个 backup 目录一个一个抄,当前新增:

  • code/scripts/seo_copy_restore_from_publish_logs.php

作用:

  1. 直接扫描 code/storage/seo_copy_publish_logs/backups
  2. 聚合某个 host 在所有历史发布备份里出现过的页面键
  3. 按场景写回 code/data/seo_copy_published
  4. 支持 --dry-run

示例:

php code/scripts/seo_copy_restore_from_publish_logs.php \
  --host=chuanjiafeng-net \
  --dry-run

正式写入:

php code/scripts/seo_copy_restore_from_publish_logs.php \
  --host=chuanjiafeng-net

用新脚本恢复后的当前结果

chuanjiafeng-net

当前已从 publish_logs/backups 聚合恢复到:

  1. home = 1
  2. category_index = 1
  3. category_list = 21
  4. search = 11
  5. rank_index = 1
  6. rank_list = 1
  7. detail = 11
  8. forge = 11
  9. play = 11

再加上之前从 bundle 恢复过的 detail/play 样本,现在本地发布目录里已达到:

  1. detail = 17
  2. play = 17
  3. home = 1
  4. category_index = 2
  5. category_list = 22
  6. search = 12
  7. rank_index = 1
  8. rank_list = 1
  9. forge = 11

也就是说,chuanjiafeng-net 已经不只是“恢复了几个播放页”而是整套首页、分类、搜索、榜单、详情、播放、forge 都恢复出一批真实历史资产。

liangzuan-net

当前已从 publish_logs/backups 聚合恢复到完整单样本链:

  1. home = 1
  2. category_index = 1
  3. category_list = 1
  4. search = 1
  5. rank_index = 1
  6. rank_list = 1
  7. detail = 1
  8. forge = 1
  9. play = 1

虽然数量不大,但它是完整的场景闭环,不再只是 detail/play 两个点。

这一步对后续排查的意义

从现在开始,后续 Codex 处理“GPT 模板引导文是不是被覆盖没了”这类问题时,应该按下面顺序:

  1. 先看 seo_copy_published 当前是否 default-only
  2. 再看 seo_copy_publish_logs/backups 是否还有历史备份
  3. 能恢复就先恢复历史资产
  4. 最后才考虑模板微调或重新生成内容

不要再跳过第 2 步直接重写,否则很容易把已经存在过、且曾经验证通过的资产再次覆盖掉。

2026-04-16 补充结论:模板接入未丢,缺的是正式域名深页成品数据

这一轮继续追查后,已经可以把“为什么首页还有引导块,但详情页/播放页很多看不到”说明白:

现状不是“GPT 模板又被删了一次”

当前工作树里,videoGpt1 模板实际上已经接入了 seo_copy 模块,且这些接入点都还在:

  1. 首页:
    • code/app/home/view/videoGpt1/index/index.html
    • 已有 video:seocopy scene="home" + module/seo_copy/collection
  2. 分类页:
    • code/app/home/view/videoGpt1/video/getCategory.html
    • code/app/home/view/videoGpt1/video/getCategoryType.html
    • code/app/home/view/videoGpt1/video/getRankIndex.html
    • code/app/home/view/videoGpt1/video/getRankList.html
    • code/app/home/view/videoGpt1/video/getSearchVideo.html
  3. 详情页:
    • code/app/home/view/videoGpt1/module/detail_main/desc.html
    • 已有 video:seocopy scene="detail" + module/seo_copy/detail
  4. 播放页:
    • code/app/home/view/videoGpt1/video/getVideoPlayUrl.html
    • 已有 video:seocopy scene="play" + module/seo_copy/play

也就是说,模板层“挂载引导文模块”这件事本身没有消失。

为什么首页能看到,详情/播放很多域名却看不到

根因已经验证清楚:多数正式域名当前的 seo_copy_published 只有粗粒度页面成品,深页只有 default.json,没有当时实际生成过的 detail/play 样本。

抽查结果:

  1. jpjdxs-com
  2. pcslcl-com
  3. lsrxs-com
  4. lmjcg-com
  5. nblssy-com

它们目前都满足:

  1. home/index.json 存在
  2. category_index/index.json 存在
  3. search/landing.json 存在
  4. detail/default.json 存在,但没有 detail/154229.json 这类真实深页文件
  5. play/default.json 存在,但没有 play/154229-play-douban-1.json 这类真实播放页文件

因此:

  1. 首页能正常出现 guide-collection
  2. 详情页和播放页会因为 default-onlyVideoService 的抑制逻辑直接隐藏

这不是模板再次被误删,而是“深页成品资产后来丢了”。

实页验证结果

已直接用本地后端端口 13205 + Host 头验证:

  1. jpjdxs.com
  2. pcslcl.com
  3. lsrxs.com
  4. lmjcg.com
  5. nblssy.com

验证现象一致:

  1. 首页 HTML 能搜到 guide-collection
  2. 详情页搜不到 guide-detail
  3. 播放页搜不到 guide-play

这和 seo_copy_published_audit.php 的审计结果完全一致。

对“是不是被 git 覆盖了”的判断

当前更准确的表述不是“整套 GPT 模板被 git 覆盖没了”,而是:

  1. 模板接入层还在
  2. 一部分首页/分类/搜索成品还在
  3. 当时生成并发布过的 detail/play 深页成品,大概率在后续同步、回滚、清理或目录覆盖过程中丢失

已知更强证据:

  1. v20260413-openai-batch-26/openai_batch_result.json
  2. v20260413-openai-batch-26/openai_deep_batch_26_rerun_20260414.json

里面明确记录了 jpjdxs.com / pcslcl.com / lsrxs.com / lmjcg.com / nblssy.com 都是:

  • 已生成并发布首页/分类/搜索/详情/播放页文案

说明这些深页文案当时真实存在过。

目前能下的结论

  1. 你记得的那批首页引导文、详情引导文、播放引导文,并不是“记混了”
  2. 模板挂载位并没有整体消失
  3. 当前缺的是正式域名的历史深页成品文件
  4. 后续恢复应继续优先走“历史资产找回”,而不是重新手写一版替代品

后续恢复顺序

后面的 Codex 接手时,应按下面顺序继续:

  1. 先审计目标 host 是否 detail_default_only / play_default_only
  2. 再在 publish_logs / release_runs / batch / bundle / 其它运行产物 中找历史成品
  3. 找到就恢复原始 page-key 文件
  4. 只有在确定历史成品完全无法找回时,才考虑重生成

2026-04-16 补充结论:通用发布链和 bootstrap 发布链不是一回事

这次继续排查后,已经可以把“为什么很多正式域名只剩 default.json”说得更准确一些:

  1. 当前仓库里的“通用 AI 生成/发布链”本身就只覆盖粗粒度页面
  2. 其中 detail 只写 detail/default
  3. 其中 play 只写 play/default
  4. 它并不会自动产出 detail/<videoId>.json
  5. 也不会自动产出 play/<videoId>-<line>-<episode>.json

已确认的代码位置:

  1. code/app/common/helper/SeoCopyGenerationHelper.php
  2. code/app/common/helper/SeoCopyAiProviderHelper.php
  3. code/app/admin/controller/Site.php

这些位置目前都还是按下面的固定目标处理:

  1. home/index
  2. category_index/index
  3. category_list/default
  4. search/landing
  5. detail/default
  6. play/default

也就是说:

  1. 如果某个域名只跑过这条“通用链路”
  2. 那它最终落盘到 seo_copy_published 的结果,本来就很可能只有默认深页

bootstrap 链路才会生成真实深页 page-key

和上面不同,seo_copy_domain_bootstrap.php 这条链路会生成:

  1. detail/<videoId>.json
  2. forge/<videoId>-forge-<n>.json
  3. play/<videoId>-play-<line>-<episode>.json

因此真正的“详情页/播放页差异化补料”主要来自 bootstrap 或等价的深页发布流程,而不是后台那条通用发布流程。

为什么 chuanjiafeng-net / liangzuan-net 还看得到深页差异化

继续查 storage/seo_copy_release_runsstorage/domain_bootstrap_bundles 后,已经拿到了更直接的证据:

  1. chuanjiafeng-net 的 release run 里明确记录过 detail/154229.json
  2. 同一批记录里也明确记录过 play/154229-play-douban-1.json
  3. storage/domain_bootstrap_bundles/chuanjiafeng-compact/ 下也保留了大量真实深页素材
  4. liangzuan-net 也有类似 bundle / 历史产物

这说明它们确实走过“深页发布链”,所以今天还能看到更完整的差异化补料。

为什么 jpjdxs-com 这批正式域名目前看起来像“只剩默认”

对下面这些 host

  1. jpjdxs-com
  2. pcslcl-com
  3. lsrxs-com
  4. lmjcg-com
  5. nblssy-com
  6. lcdchq-com
  7. lgyz-net
  8. oronorent-com
  9. sdxhtgcl-com

当前仓库里已经确认:

  1. code/data/seo_copy_published/<host>/detail/ 只有 default.json
  2. code/data/seo_copy_published/<host>/play/ 只有 default.json
  3. storage/seo_copy_release_runs 里几乎搜不到这些 host 的深页发布记录
  4. storage/domain_bootstrap_bundles 里也搜不到它们对应的历史 bundle

这意味着更大的概率不是“这次模板把深页补料删了”,而是下面两种情况之一:

  1. 这些 host 当时根本没有在当前仓库/当前机器里完成 bootstrap 深页发布
  2. 它们的深页发布资产存在于另一台机器、另一份工作区,后来没有同步回来

关于“后台预览看起来全没了”的补充说明

后台当前的已发布预览接口也会加重误判,因为它只展示:

  1. detail/default
  2. play/default

而不会枚举展示真实的:

  1. detail/<videoId>
  2. play/<videoId>-<line>-<episode>

对应代码位置:

  1. code/app/admin/controller/Site.php
  2. 方法:getDomainSeoCopyPublishedPreview

所以后台看到“只有 default”不一定等于前台一定没有具体深页但对本轮这批正式域名来说前台与文件审计结果已经相互印证确实是深页资产缺失。

当前最可靠的判断

截至 2026-04-16这个问题应拆成两层分别处理

  1. 页面模板/UI 层 这层已经恢复,首页/详情/播放的 GPT 模板挂载位、引导块和正文块都在
  2. 深页发布资产层 这层在多数正式域名上仍缺历史 page-key 文件,因此只能 fallback 或直接抑制显示

后续任何 Codex 接手时,不要再把这两个问题混在一起判断。

2026-04-16 再补一条关键证据:openai_batch_result 里的“已发布详情/播放”不是深页发布

这次继续把运行结果、代码和 git 历史对齐后,可以更明确地纠正一个容易误解的点:

  1. v20260413-openai-batch-26/openai_batch_result.json
  2. v20260413-openai-batch-26/openai_deep_batch_26_rerun_20260414.json

里面对很多正式域名都写着:

  1. written_pages = 6
  2. 已生成并发布首页/分类/搜索/详情/播放页文案

但这里的“6 个页面”不是:

  1. 首页
  2. 分类
  3. 搜索
  4. 真实详情深页
  5. 真实播放深页
  6. 其它真实样本页

而是固定指向这 6 个槽位:

  1. home/index
  2. category_index/index
  3. category_list/default
  4. search/landing
  5. detail/default
  6. play/default

已核实的代码证据

以下代码都由同一个提交引入固定槽位配置:

  1. code/app/common/helper/SeoCopyGenerationHelper.php
  2. code/app/common/helper/SeoCopyAiProviderHelper.php
  3. code/app/admin/controller/Site.php

对应 git blame 结果显示,这几处固定配置都来自:

  1. 提交:0794c903
  2. 时间:2026-04-15 14:00:19 +0800

也就是从这套通用链路落地开始,它的设计目标就不是“为每个 host 发布真实 deep page key”。

对批处理成功记录的正确理解

因此当批处理结果里看到:

  1. jpjdxs.com
  2. pcslcl.com
  3. lsrxs.com
  4. lmjcg.com
  5. nblssy.com
  6. lcdchq.com
  7. lgyz.net
  8. oronorent.com
  9. sdxhtgcl.com

都显示:

  1. status = success
  2. written_pages = 6

更准确的解释应该是:

  1. 它们成功写入了“6 个固定 SEO 文案槽位”
  2. 不是成功写入了真实 detail/<videoId>.json
  3. 也不是成功写入了真实 play/<videoId>-play-<line>-<episode>.json

对“当时明明说发布过详情/播放”的最终解释

现在可以把这句话解释完整了:

  1. 当时说“发布过详情/播放”
  2. 在通用链路语义里成立
  3. 但它指的是 detail/defaultplay/default
  4. 不等于深页差异化资产已经落盘

所以后面再排查“深页引导文为什么没有了”时,不能再单纯依据 openai_batch_result 里的成功状态下结论,必须继续看:

  1. seo_copy_published/<host>/detail/
  2. seo_copy_published/<host>/play/
  3. 是否真的存在非 default 的 page-key 文件

2026-04-16 外部找回清单

截至当前排查结果,下面这些正式域名在当前仓库内的发布状态完全一致:

  1. jpjdxs-com
  2. pcslcl-com
  3. lsrxs-com
  4. lmjcg-com
  5. nblssy-com
  6. lcdchq-com
  7. lgyz-net
  8. oronorent-com
  9. sdxhtgcl-com

它们当前在 code/data/seo_copy_published/<host>/ 下都只有:

  1. home/index.json
  2. category_index/index.json
  3. category_list/default.json
  4. search/landing.json
  5. detail/default.json
  6. play/default.json

没有任何:

  1. detail/<videoId>.json
  2. play/<videoId>-play-<line>-<episode>.json

同时也已经确认:

  1. 当前机器 /www/wwwroot 范围内未发现这批 host 的第二份深页 JSON 副本
  2. storage/seo_copy_release_runs 内未发现这批 host 的非 default detail/play 发布证据
  3. storage/domain_bootstrap_bundles 内未发现这批 host 对应 bundle

因此,如果还要继续“找回历史成果”,应优先去当前仓库之外的地方找。

外部找回优先顺序

建议按下面顺序查:

  1. 旧服务器或旧工作区里的 code/data/seo_copy_published
  2. 旧服务器或旧工作区里的 code/data/seo_copy
  3. 旧服务器或旧工作区里的 code/storage/domain_bootstrap_bundles
  4. 旧服务器或旧工作区里的 code/storage/seo_copy_publish_logs
  5. 旧服务器或旧工作区里的 code/storage/seo_copy_release_runs
  6. 当时跑批使用过但未纳入 git 的临时目录、压缩包、备份盘

重点只看下面两类文件:

  1. detail/*.json 中非 default.json 的文件
  2. play/*.json 中非 default.json 的文件

外部找回时的最小判断标准

只要满足下面任意一条,就说明该 host 存在可恢复价值:

  1. 找到至少 1 个 detail/<videoId>.json
  2. 找到至少 1 个 play/<videoId>-play-<line>-<episode>.json
  3. 找到对应 host 的 bootstrap bundle
  4. 找到 release log / publish log 明确记录了非 default 的 detail/play page_key

如果四条都没有,再默认该 host 的历史深页资产在现有环境中不可恢复。

找回后的恢复原则

一旦在外部目录找到了某个 host 的深页资产,恢复时必须遵守下面原则:

  1. 只回灌该 host 缺失的 detail/play 非 default 文件
  2. 不覆盖已经存在的首页、分类、搜索固定槽位
  3. 不修改模板逻辑
  4. 不修改路由逻辑
  5. 不改数据库
  6. 先 dry-run 审计,再正式复制

恢复目标目录仍然是:

  1. code/data/seo_copy_published/<host>/detail/
  2. code/data/seo_copy_published/<host>/play/

如果外部也找不到,最小代价重建方案

只有在确认外部目录也找不到历史资产后,才进入重建方案。

重建时不要直接“大面积重写所有文案”,而应采用最小代价方案:

  1. 继续保留当前首页、分类、搜索固定槽位
  2. 只补 detail/play 深页资产
  3. 先补少量高频样本页,不一次性铺满全站
  4. 补料逻辑必须保持“同域名稳定、同视频稳定、同线路稳定”
  5. 优先生成真实 page-key 文件,而不是再写回 default.json

重建边界

如果进入重建,必须遵守下面边界,避免再把历史成果覆盖成统一模板:

  1. 不改现有 home/index
  2. 不改现有 category_index/index
  3. 不改现有 category_list/default
  4. 不改现有 search/landing
  5. 只新增非 default 的 detail/play 文件
  6. 不把新增深页资产重新压回 detail/default / play/default

推荐的重建节奏

建议节奏如下:

  1. 每个 host 先选 10 到 20 个真实详情页样本
  2. 每个详情页只补 1 个主播放线路、1 个主集数
  3. 先验证前台是否能稳定命中这些 page-key
  4. 再观察蜘蛛是否重新命中并抓取
  5. 只有验证有效后,才继续扩到更多样本

当前阶段最重要的判断

截至 2026-04-16最重要的判断不是“模板还要不要继续改”而是

  1. 先确认正式域名有没有可找回的历史深页资产
  2. 若没有,再进入“新增深页资产”的最小重建方案

在这一步之前,不建议继续大改 GPT 模板页面结构,否则容易把“资产缺失问题”误判成“模板呈现问题”。

2026-04-16 最小重建方案的技术实施蓝图

如果后续确认外部环境也找不到历史深页资产,推荐按下面的技术路径做“最小重建”,并且只做深页资产补回,不做模板重写。

目标

目标只做一件事:

  1. 为缺失的 host 新增少量真实 detail/play page-key JSON

不是要做下面这些事情:

  1. 不是重做首页 SEO
  2. 不是重做分类页 SEO
  3. 不是重做搜索页 SEO
  4. 不是重改 GPT 模板结构
  5. 不是把 fallback 文案整体替换成 AI 文案

已有可复用链路

当前仓库里,已经有一条能生成真实深页 page-key 的现成链路,可作为最小重建基础:

  1. code/scripts/seo_copy_domain_bootstrap.php
  2. code/scripts/seo_copy_release_run.php
  3. code/app/common/helper/SeoCopyFallbackBuilder.php
  4. code/app/common/helper/SeoCopyStore.php
  5. code/app/services/VideoService.php

其中最关键的是:

  1. seo_copy_domain_bootstrap.php 它本来就会生成:
    • detail/<videoId>.json
    • forge/<videoId>-forge-<n>.json
    • play/<videoId>-play-<line>-<episode>.json
  2. VideoService::buildSeoCopyPageKeys() 前台读取时也本来就优先查这些真实 page-key

所以最小重建不需要重新发明一套新格式,重点是把这条深页资产生成链安全地用在正式域名上。

建议的实施顺序

推荐按下面顺序推进:

  1. 样本选择
  2. 深页 JSON 生成
  3. 只回灌 published 目录
  4. 前台命中验证
  5. 蜘蛛抓取观察
  6. 再决定是否扩样本

第 1 步:样本选择

每个 host 先不要全量铺,而是先选小样本:

  1. detail 先选 10 到 20 个 videoId
  2. play 每个 videoId 只先选 1 条主线路
  3. 每条线路只先选 1 个集数

样本建议优先来自:

  1. 当前站点首页正在推荐的内容
  2. 分类页正在曝光的内容
  3. 蜘蛛日志最近命中的真实 detail/play URL
  4. 数据库里播放线路稳定、标题稳定的内容

第 2 步:深页 JSON 生成

生成深页资产时,优先使用现有 bootstrap 链路:

  1. seo_copy_domain_bootstrap.php 生成单 host 小批量 bundle
  2. 让它输出真实 detail/play page-key JSON
  3. 源内容先允许走 SeoCopyFallbackBuilder

这样做的原因是:

  1. 先恢复“深页资产存在”这件事
  2. 再考虑文案质量迭代
  3. 避免一开始把问题扩大成“AI 质量 + 资产缺失 + 模板呈现”三件事同时处理

第 3 步:只回灌 published

真正回灌时,只把生成结果写到:

  1. code/data/seo_copy_published/<host>/detail/
  2. code/data/seo_copy_published/<host>/play/

不建议第一步就把内容同时写回:

  1. code/data/seo_copy
  2. 大批量 approved
  3. 旧的通用 AI 发布链

因为当前最重要的是验证“前台是否会优先命中真实深页 page-key”。

第 4 步:前台命中验证

每次小批量回灌后,必须做 3 类验证:

  1. 文件验证
    • detail/<videoId>.json 是否存在
    • play/<videoId>-play-<line>-<episode>.json 是否存在
  2. 页面验证
    • 详情页是否从“空/抑制”变成命中 guide-detail
    • 播放页是否从“空/抑制”变成命中 guide-play
  3. 回退验证
    • 其他没有补样本的页面,仍然保持原有 default/fallback 行为

第 5 步:蜘蛛抓取观察

回灌后不要立刻扩全站,先观察:

  1. 百度是否重新命中这批 detail/play
  2. 命中后是否稳定返回 200
  3. 页面正文是否能稳定被抓到,不再出现空白深页

当前最应该复用的代码点

后续实施时,优先围绕下面这些点展开,而不是另起炉灶:

  1. code/scripts/seo_copy_domain_bootstrap.php 已具备真实深页 page-key 生成能力
  2. code/app/services/VideoService.php 已具备优先查真实 page-key、缺失时回退 default 的读取逻辑
  3. code/app/common/helper/SeoCopyStore.php 已具备按 host / scene / page_key 写入 JSON 的能力
  4. code/scripts/seo_copy_restore_from_source.php 可作为“把 source 写回 published”的参考工具
  5. code/scripts/seo_copy_published_audit.php 可作为回灌后的审计工具

当前不建议直接改动的代码点

在进入最小重建阶段时,下面这些位置不建议先动:

  1. code/app/home/view/videoGpt1/* 页面层已经恢复,不是当前主问题
  2. code/app/home/config/router.php 路由层已稳定,先不要把问题重新引入
  3. code/app/admin/controller/Site.php 的通用 AI 发布逻辑 这条链本身就是固定槽位链,短期不必强改成深页链

如果后续一定要补“后台一键深页发布”

那应该作为第二阶段做,而不是第一阶段。

第二阶段的方向应该是:

  1. 保留当前后台“固定 6 槽位”能力
  2. 另外新增“深页样本发布”入口
  3. 让后台可以按 host + videoId + playType + playIndex 生成和发布小批量深页 JSON

不要直接把原来的通用 AI 发布按钮改成全深页逻辑,否则风险很高。

最小重建阶段的成功标准

第一阶段不追求“恢复整站所有历史差异化”,只追求下面 4 条:

  1. 某个正式域名出现至少 10 个真实 detail/<videoId>.json
  2. 同一域名出现对应的 play/<videoId>-play-<line>-<episode>.json
  3. 详情页和播放页前台能稳定命中这些 page-key
  4. 蜘蛛开始重新抓到这些非空深页

做到这 4 条,就说明“深页资产链”已经重新打通,后面再扩量才有意义。

2026-04-16 试点重建 checklist

下面这份 checklist 用于“先拿 1 个正式域名做小样本试点”,目标是先验证链路,不追求一次铺满。

一、试点前准备

开始前先确认下面 4 件事:

  1. 只选 1 个 host不并行多 host
  2. 不改模板
  3. 不改路由
  4. 不改数据库结构

建议优先试点 host

  1. lgyz-net
  2. lcdchq-com
  3. jpjdxs-com

原因:

  1. 这几个 host 当前都属于典型 default-only
  2. 前台路由已经验证过可访问
  3. 更适合做“补深页资产后是否立刻生效”的观察

二、样本选择 checklist

每次试点先准备:

  1. 10 到 20 个 videoId
  2. 每个 videoId 只选 1 条主线路
  3. 每条线路只选 1 个主集数

样本优先级:

  1. 首页正在推荐的内容
  2. 分类页正在曝光的内容
  3. 蜘蛛最近命中的详情/播放 URL
  4. 播放线路最稳定的内容

不建议选:

  1. 没有稳定播放线路的视频
  2. 刚入库、字段不完整的视频
  3. 需要复杂 slug 才能访问、当前又不稳定的视频

三、生成 bundle 的建议方式

推荐优先用现有 bootstrap 脚本做单 host 小样本 bundle。

参考命令模板:

php scripts/seo_copy_domain_bootstrap.php <host> \
  --detail-id=<videoId> \
  --detail-slug=<slug> \
  --search-keyword=<keyword> \
  --category-parent=<parent> \
  --category-child=<child> \
  --bundle-root=storage/domain_bootstrap_bundles/<bundle-name> \
  --index-root=storage/domain_bootstrap_bundles \
  --portal-root=public/_seo_copy_release

说明:

  1. 这一步的核心是拿到 bundle 里的真实 detail/play page-key JSON
  2. 不要求一开始就把 10 到 20 个样本一次性都塞进去
  3. 可以先跑通 1 个样本,再扩到 10 个

四、bundle 生成后先做 dry-run

生成 bundle 后,先不要正式应用,先 dry-run。

建议顺序:

php scripts/domain_bootstrap_run.php <bundle-root> --dry-run=1 --format=text

必要时再分步:

php scripts/domain_bootstrap_register.php <bundle-root>/site-register.sample.json --dry-run=1 --format=text
php scripts/domain_seo_bootstrap_apply.php <bundle-root>/site-bootstrap.sample.json --dry-run=1 --format=text

dry-run 通过后,再决定是否继续。

五、写回 published 前的文件检查

在真正回灌前,先确认 bundle/source 里已经出现:

  1. detail/<videoId>.json
  2. play/<videoId>-play-<line>-<episode>.json

如果只有:

  1. detail/default.json
  2. play/default.json

那说明这次生成仍然没有产出真实深页资产,不能继续写回。

六、回灌方式

如果 bundle/source 中已经有真实深页文件,优先用现成恢复脚本回灌:

php code/scripts/seo_copy_restore_from_source.php \
  --host=<host-dir> \
  --source=<bundle-or-source-root> \
  --dry-run

确认无误后,再正式写入:

php code/scripts/seo_copy_restore_from_source.php \
  --host=<host-dir> \
  --source=<bundle-or-source-root>

当前版本的这个脚本已经升级为:

  1. 不传 --scenes 时,自动识别 source 里实际存在的已知场景并回灌
  2. --scenes=... 时,只恢复指定场景

目前默认支持:

  1. home
  2. category_index
  3. category_list
  4. search
  5. rank_index
  6. rank_list
  7. detail
  8. forge
  9. play

如果只想做最小恢复,仍然可以显式指定:

php code/scripts/seo_copy_restore_from_source.php \
  --host=<host-dir> \
  --source=<bundle-or-source-root> \
  --scenes=detail,play \
  --dry-run

七、回灌后的文件审计

写回后第一时间跑审计:

php scripts/seo_copy_published_audit.php --host=<host-dir> --format=text

必要时加样本检查:

php scripts/seo_copy_published_audit.php \
  --host=<host-dir> \
  --sample-detail=<videoId> \
  --sample-play=<videoId>:<playType>:<episode> \
  --format=text

通过标准:

  1. detail_default_only: no
  2. play_default_only: no
  3. 指定 sample 的 expected_page_key 存在

八、前台命中验证

文件审计通过后,再做前台读取验证。

读回验证:

php scripts/seo_copy_readback.php <host> detail <videoId> --format=text
php scripts/seo_copy_readback.php <host> play <videoId> <playType> <episode> --format=text

前台验证:

php scripts/seo_copy_front_verify.php <host> detail <videoId> --base-url=http://127.0.0.1:13205 --format=text
php scripts/seo_copy_front_verify.php <host> play <videoId> <playType> <episode> --base-url=http://127.0.0.1:13205 --format=text

通过标准:

  1. 详情页命中 guide-detail 或等价正文引导块
  2. 播放页命中 guide-play 或等价正文引导块
  3. 不是继续走空白或被抑制状态

九、试点观察窗口

第一次试点完成后,不要立刻扩全量,建议至少观察一个抓取窗口:

  1. 先观察数小时到 1 天
  2. 看蜘蛛是否回打这批深页
  3. 看命中后是否稳定 200
  4. 看正文是否真实输出,不再是空深页

十、试点成功后的扩量规则

只有试点成功后,才允许扩量。

扩量时建议:

  1. 先从 10 个样本扩大到 30 个
  2. 再从 30 个扩大到 100 个
  3. 每次扩量后都要重复审计和前台验证

不要直接:

  1. 一次生成全站所有 detail/play
  2. 一次回灌所有 host

十一、试点失败时怎么判断原因

如果试点失败,优先按下面顺序排查:

  1. bundle/source 是否真的产出非 default detail/play
  2. restore_from_source 是否真的写入 published
  3. seo_copy_published_audit 是否仍显示 default-only
  4. seo_copy_readback 是否能读到真实 page-key
  5. seo_copy_front_verify 是否命中了对应前台 URL

只有先把这 5 层排干净,才允许怀疑模板或路由。

2026-04-16 第一试点 host 建议

基于当前仓库与本机回测结果,第一试点 host 建议优先选:

  1. jpjdxs.com

原因:

  1. 当前属于典型 detail_default_only / play_default_only
  2. 首页和详情页都能稳定打开
  3. 已经能从详情页直接抽到真实播放链接
  4. 详情 URL 和播放 URL 规则相对清晰,便于做第一批 dry-run

当前已确认的 URL 形态:

  1. 详情页:/neirong-<videoId>-<slug>
  2. 播放页:/bf-<videoId>-<slug>/<playType>-<episode>

例如:

  1. 详情页:/neirong-154229-xiang-feng-bu-shi-jiu-shi-ren
  2. 播放页:/bf-154229-xiang-feng-bu-shi-jiu-shi-ren/douban-1

同时也已确认:

  1. seo_copy_published 下不存在 detail/154229.json
  2. seo_copy_published 下不存在 play/154229-play-douban-1.json

这正适合作为第一批“从无到有补深页资产”的试点。

jpjdxs.com 第一批样本候选

当前已从首页与详情页抽到一批真实样本,建议先从下面 8 个详情样本开始:

  1. 76342 / se-jiang-zhi-xue-mei-gui
  2. 76318 / she-sha-shou
  3. 76347 / se-jie
  4. 76341 / se-qing-dian-ying-da-shui-qiang-de-liu-de-wang
  5. 76324 / shao-nv-de-you-huo
  6. 76346 / se-gui-tou-tai
  7. 76359 / san-fen-zhi-yi-qing-ren
  8. 76325 / shao-nv-de-you-huo

对应已抽到的播放页候选如下:

  1. 76342
    • default-1
    • douban-1
    • youzhi-1
  2. 76318
    • default-1
    • douban-1
    • youzhi-1
  3. 76347
    • default-1
    • douban-1
  4. 76341
    • default-1
    • douban-1
  5. 76324
    • default-1
    • douban-1
  6. 76346
    • default-1
    • douban-1
    • youzhi-1
  7. 76359
    • default-1
    • douban-1
    • youzhi-1
  8. 76325
    • default-1
    • douban-1

第一试点最小建议组合

如果要把风险再压低,建议第一轮不是 8 个全上,而是先从下面 3 个 detail + 3 个 play 开始:

  1. detail/76342
  2. detail/76318
  3. detail/76347
  4. play/76342-play-douban-1
  5. play/76318-play-douban-1
  6. play/76347-play-douban-1

原因:

  1. 这 3 个样本都来自首页当前真实曝光内容
  2. 详情页与播放页链接都已实测能抽到
  3. douban-1 在线路上最统一,适合先打通第一轮

当前试点前的已知空缺验证

已直接验证:

  1. jpjdxs.com detail 154229 当前无对应 seo_copy_published 深页文件
  2. jpjdxs.com play 154229 douban 1 当前无对应 seo_copy_published 深页文件

这说明当前环境仍然符合试点前置条件:

  1. 深页资产缺失是真实存在的
  2. 不是已经生成但前台没命中

2026-04-16 jpjdxs.com 第一批深页试点已落地

这段不是计划,是本地已经执行过的结果。

本次选择的最小样本

详情页:

  1. 76318
  2. 76342
  3. 76347

播放页:

  1. 76318-play-douban-1
  2. 76342-play-douban-1
  3. 76347-play-douban-1

已执行动作

  1. seo_copy_domain_bootstrap.php 分别为这 3 个样本生成 bundle
  2. 从 bundle 中抽出真实 detail/play page-key JSON
  3. 先在临时目录做了 seo_copy_batch_import.php 闭环验证
  4. 再把这 6 个深页 JSON 回灌到真实:
    • code/data/seo_copy_published/jpjdxs-com/detail/
    • code/data/seo_copy_published/jpjdxs-com/play/

当前结果

当前 jpjdxs-com 已从原来的深页接近 default-only,变成:

  1. detail 目录:
    • default.json
    • 76318.json
    • 76342.json
    • 76347.json
  2. play 目录:
    • default.json
    • 76318-play-douban-1.json
    • 76342-play-douban-1.json
    • 76347-play-douban-1.json

审计结果

重新跑 seo_copy_published_audit.php 后已确认:

  1. detail_default_only: no
  2. play_default_only: no
  3. detail non_default_count: 3
  4. play non_default_count: 3

也就是说:

  1. 第一批深页资产链已经重新打通
  2. 当前不是停留在“理论上可恢复”
  3. 而是 jpjdxs.com 已经具备最小规模的真实深页 page-key 资产

2026-04-16 再确认:当前仓库里的“生成能力”和“导入能力”边界

这段是给后续所有接手的 Codex 看的,避免再把问题判断错方向。

1. SeoCopyAiProviderHelper 这条通用链,只会发布固定槽位

已再次核对:

  • code/app/common/helper/SeoCopyAiProviderHelper.php
  • code/app/common/helper/SeoCopyGenerationHelper.php

当前通用发布链固定只处理:

  1. home/index
  2. category_index/index
  3. category_list/default
  4. search/landing
  5. detail/default
  6. play/default

也就是说:

  1. 它不会自动产出 detail/<videoId>.json
  2. 它不会自动产出 play/<videoId>-play-<line>-<episode>.json
  3. 所以某个 host 就算“通用 AI 发布成功”,深页也仍然可能是 default-only

这一点非常重要,后面不要再把“通用发布成功”误判成“深页差异化一定已经恢复”。

2. 真正的深页差异化资产,来自 bootstrap 深页链

已再次核对:

  • code/scripts/seo_copy_domain_bootstrap.php

这条链会直接生成真实 page-key

  1. detail/<videoId>.json
  2. forge/<videoId>-forge-<n>.json
  3. play/<videoId>-play-<line>-<episode>.json

因此:

  1. 你之前记得的那批 GPT 模板详情引导文、播放引导文、差异化块
  2. 本质上更接近 bootstrap 深页资产链的结果
  3. 不是后台那条“固定 6 槽位”通用发布链的自然产物

2.1 2026-04-17 再确认:旧 restore_from_source 的缺口已经补上

这轮继续排查 jpjdxs.com 后,已经进一步确认:

  1. 有些 host 不是“source 没有资产”
  2. 而是“source 里有更多场景,但旧恢复脚本只写回了 detail/play

以本机这次实际找到的 source 为例:

  • code/storage/domain_bootstrap_bundles/jpjdxs-seed-a1/data/seo_copy/jpjdxs-com

里面实际存在:

  1. home/index.json
  2. category_index/dian-ying.json
  3. category_list/dian-ying--shao-shi-dian-ying.json
  4. search/h-2d9bf00ea1f2e5ee.json
  5. rank_index/index.json
  6. rank_list/daily.json
  7. detail/76342.json
  8. forge/76342-forge-1.json
  9. play/76342-play-douban-1.json

但旧版 code/scripts/seo_copy_restore_from_source.php 只会扫:

  1. detail
  2. play

所以会出现一种很容易把人带偏的现象:

  1. bundle/source 里明明有榜单、forge、分类、搜索资产
  2. 执行恢复后却只有 detail/play 被补进 published
  3. 前台就会表现成“有些引导文回来了,有些还是像没恢复”

这轮已经把:

  • code/scripts/seo_copy_restore_from_source.php

升级成“按 source 中实际存在场景自动回灌”的版本,默认支持:

  1. home
  2. category_index
  3. category_list
  4. search
  5. rank_index
  6. rank_list
  7. detail
  8. forge
  9. play

并且已在本机对 jpjdxs-com 做过 dry-run 与正式写回验证:

php code/scripts/seo_copy_restore_from_source.php \
  --host=jpjdxs-com \
  --source=code/storage/domain_bootstrap_bundles/jpjdxs-seed-a1/data/seo_copy \
  --dry-run

php code/scripts/seo_copy_restore_from_source.php \
  --host=jpjdxs-com \
  --source=code/storage/domain_bootstrap_bundles/jpjdxs-seed-a1/data/seo_copy

写回后重新审计,已经新增恢复出:

  1. category_index/dian-ying.json
  2. category_list/dian-ying--shao-shi-dian-ying.json
  3. search/h-2d9bf00ea1f2e5ee.json
  4. rank_index/index.json
  5. rank_list/daily.json
  6. forge/76342-forge-1.json

同时前台闭环验证已经通过:

php code/scripts/seo_copy_front_verify.php jpjdxs.com rank_index --target-root=code/data/seo_copy_published --base-url=https://jpjdxs.com --format=text
php code/scripts/seo_copy_front_verify.php jpjdxs.com rank_list daily --target-root=code/data/seo_copy_published --base-url=https://jpjdxs.com --format=text
php code/scripts/seo_copy_front_verify.php jpjdxs.com forge 76342 1 --target-root=code/data/seo_copy_published --base-url=https://jpjdxs.com --format=text

结果都已经:

  1. status: 200
  2. all_matched: yes

这条结论以后非常重要:

  1. 如果 source 里有 rank_index / rank_list / forge / category / search
  2. published 里只有 detail / play

优先先查:

  1. 当前机器上的 seo_copy_restore_from_source.php 是否已经是“全场景版本”
  2. 之前是不是只跑过旧脚本或 --scenes=detail,play

不要再直接误判成:

  1. 这些资产从来没生成过
  2. bundle/source 已经失效
  3. 之前做好的差异化已经全部被删光

3. 系统并不是“不能导入深页文件”,而是“缺少深页源文件”

已再次核对:

  • code/scripts/seo_copy_batch_import.php
  • code/app/common/helper/SeoCopyBatchImportHelper.php

当前导入器支持的目录结构就是:

  1. <source-dir>/<host-dir>/<scene>/<page_key>.json

这意味着:

  1. 它支持导入任意 detail/<videoId>.json
  2. 它支持导入任意 play/<videoId>-play-<line>-<episode>.json
  3. 当前真正缺的不是导入能力
  4. 当前真正缺的是:
    • 历史深页源文件
    • 或新生成出来的深页源文件

4. 以后再排查“引导文没了”,统一按这个顺序

  1. 先看模板层是不是挂载还在
  2. 再看运行时是不是被 suppress / fallback 卡住
  3. 再看 seo_copy_published/<host>/detailplay 是否只剩 default.json
  4. 再看 storage/domain_bootstrap_bundles / storage/seo_copy_publish_logs / storage/seo_copy_release_runs 里有没有历史深页成品
  5. 确认历史成品确实不存在后,才进入“小批量 bootstrap 深页重建”

2026-04-16 深夜补充:不是“模板又没了”,而是 runtime/home/temp 权限污染

这次线上又出现了一次很容易误判的现象,必须单独记下来。

1. 现象

当时看到的是:

  1. 首页 title/keywords/description 正常
  2. 详情页大多正常
  3. 播放页有时正常,有时直接变成 ThinkPHP 错误页
  4. 从体感上很像:
    • 之前做好的 GPT 模板引导文又没了
    • 页面又像被 git 覆盖回旧状态
    • SEO 头信息像“忽然空掉”

2. 实际根因

实测抓到的不是模板逻辑丢失,而是:

  • code/runtime/home/temp 里混进了一批 root:root 的编译模板文件
  • 实际 PHP-FPM 进程是 www 用户
  • 所以当 ThinkPHP 需要重写这些模板缓存时,会报:
    • file_put_contents(...runtime/home/temp/...php): Failed to open stream: Permission denied

3. 为什么它会表现得像“优化被覆盖了”

因为这个问题不是“所有页面一起死”,而是:

  1. 已经命中旧缓存的页面,可能还能正常显示
  2. 需要重新编译模板的页面,会直接报错
  3. 于是现场看起来就像:
    • 一部分 GPT 引导文还在
    • 一部分页面像恢复成旧样子
    • 一部分页面干脆系统错误

所以这种现象不能第一时间认定成:

  1. git 又把模板覆盖了
  2. SEO key 又丢了
  3. 数据库把引导文清空了

4. 这次实际处理方式

已在正式排查中确认:

  1. php-fpm 运行用户是 www
  2. runtime/home/temp 中存在多份 root root 文件
  3. runtime/home 下属主纠正回 www:www
  4. 再复测:
    • 详情页恢复正常
    • 播放页恢复正常
    • guide-detail / guide-play 正常输出
    • canonical / og:url / JSON-LD url 恢复到正确页面

5. 后续所有 Codex 统一排查顺序

以后再遇到“GPT 模板像突然失忆”时,统一先做这 4 步:

  1. 先抓线上实际 HTML不要只凭浏览器体感判断
  2. 看是不是 ThinkPHP 错误页,尤其关注 runtime/home/temp 写入失败
  3. 检查 runtime/home/temp 是否混入 root:root
  4. 只有确认运行时缓存正常后,才继续判断是不是模板 / SEO copy / git 历史问题

2026-04-17 凌晨补充:搜索页串页不是模板错,是前端缓存 key 漏了 query string

这也是一个很容易把人带偏的问题,必须单列。

1. 实测现象

同一时间分别抓:

  1. /get-index?keyword=爱情
  2. /get-index?keyword=动作

结果两次返回:

  1. x-cache-status: HIT
  2. HTML 里的 title
  3. canonical
  4. og:url

全部都是“爱情”那一页的内容。

也就是说:

  1. 不同关键词请求
  2. 命中了同一份前端缓存
  3. 不是后端模板在实时生成对应 query 的页面

2. 结论

这说明当前前端缓存层对搜索页的 cache key 存在高概率配置问题:

  1. cache key 没有带上 query string
  2. 或搜索页请求被错误归入“只按 URI 缓存”的 location

它会直接造成:

  1. 搜索页串页
  2. canonical / og:url / title 与真实 query 不一致
  3. SEO 表现看起来像“模板或 SEO 数据随机失效”

3. 这类问题的判定规则

以后凡是看到:

  1. 搜索页关键词 A 打开后像关键词 B
  2. canonical 看着像随机错乱
  3. 源码明明已经修对,但线上输出不稳定

优先先看:

  1. 响应头里的 x-cache-status
  2. 前端缓存 key 是否包含 query string

不要第一时间误判为:

  1. 模板回滚
  2. seo_copy 丢失
  3. 数据库内容被覆盖

4. 当前前端 nginx 模板里的直接根因

已对照当前仓库内的前端配置模板:

问题点在于动态页缓存 key 原来是:

proxy_cache_key "$scheme$request_method$host$uri";

这意味着:

  1. /get-index?keyword=爱情
  2. /get-index?keyword=动作

会共用同一个缓存 key因为它们的 uri 都只是 /get-index

5. 最小修复方案

动态页缓存 key 至少改成:

proxy_cache_key "$scheme$request_method$host$uri$is_args$args";

这样:

  1. 不同 query string 会拆分缓存
  2. 搜索页不会再互相串页
  3. canonical / og:url / title 不会再被别的关键词页面污染

6. 推荐同步修复范围

不要只改搜索页单点 location。

当前建议直接同步到:

  1. location /
  2. location ~* \.(html|htm)$

原因是:

  1. 搜索页当前命中的是 location /
  2. 但以后如果某些动态页走 .html 风格并带 query也会遇到同类问题

7. 上线后复测方法

改完 nginx 并清缓存后,用两组不同关键词直接抓响应头和 HTML

curl -s -D - 'https://你的域名/get-index?keyword=爱情' -o /tmp/a.html
curl -s -D - 'https://你的域名/get-index?keyword=动作' -o /tmp/b.html
rg '<title>|canonical|og:url' /tmp/a.html
rg '<title>|canonical|og:url' /tmp/b.html

通过标准:

  1. 两个页面的 title 不同
  2. canonical 分别指向各自关键词
  3. og:url 分别指向各自关键词
  4. 不再出现“动作词页返回爱情 HTML”的现象