# 文章自动点赞维护 适用FNA_V3;2026-10-29用户要求新增“一年内增加指定额度,完成后停止”,并为后续AI新文章配置默认参数。AI写作默认值与业务口径的唯一正文为[写作规范](../content/WRITING.md#ai-新文章的点赞参数2026-10-29),发布调用入口为[独立文章API](EDITORIAL_API.md)。2026-10-29已按用户“上线,把之前没处理的文章也处理”授权发布正式cfn并补齐10篇教程,test未更新,本机调度未启动。部署与回退记录见本文末尾。 ## 三项独立机制 - 原短期机制:`i7like`为剩余量,`article:sync-likes`按原随机逻辑扣减。保留原年龄窗口及频率实现,没有借本次改造重写短期算法。 - 原持续年度机制:`i365like`为每日中奖概率的分子,每日只按原缓存日期锁执行一轮,不扣余额、不以一年为终点。参数50是统计期望,不是精确年度配额;该原有缓存锁不等同于数据库并发锁。 - 新一次性年度机制:`iYearLikeTarget`是本轮额外增加量,`iYearLikeAdded`是本轮已增加量,`sYearLikeStartedAt`是开始时间。三项分别保存,不能用总点赞数倒推本轮进度,也不能拿其他机制或真实点赞抵扣本轮额度。 ## 新年度额度的执行 `app/Services/OneYearArticleLikes.php`负责进度,沿用现有每5分钟的`article:sync-likes`调度,不新增独立cron。`due = floor(target × 已过秒数 / 本日历年总秒数)`,实际增加`max(0, due - added)`;已过时间限制在0~一年长度之间。起点到周年日计算使用`addYearNoOverflow`,闰日对应下一年2月28日。完成后保留target和added供核对,后续扫描不再选中满额文章。 未公开文章不执行;暂停期间仍按原开始时间计时,重新公开后补至应有进度,不自动延长周期。没有开始时间但额度非零的手动计划,首次执行只填当前时间,不按旧文章创建日追补。调度延误时下一次执行补到应有量,周年后恢复则补足余额;停机时不能保证准点完成。 每篇通过事务与`lockForUpdate`读取最新进度,额度计数和总点赞数在同一次SQL更新中累加,防止本项重入重复支付,并保留同时发生的真实点赞。使用Query Builder避免触发文章内容`updated_at`、模型搜索同步等副作用;仅更新`iLikeCount`、`iYearLikeAdded`、`sLastLikedAt`,任务结束后刷新原“点赞活跃”缓存。其他两项原有代码保留。 ## 独立文章API `Publisher::draft()`支持可选`like_settings`对象,键为`seven_day`、`yearly`、`one_year`;创建新文章时缺省键使用写作规范默认值。`seven_day`与`one_year`接受0~1000000整数,`yearly`接受0~365整数;0关闭对应机制。保存草稿时为每篇独立取随机值并保存在冻结items中,`getDraft()`返回实际设置,查询及同请求重试不再随机。 发布新文章时将冻结值落入对应字段,已支付为0,年度开始时间为实际发布时间。更改现有文章、显式接管和内容回退保留全部计数、参数与年度进度;已存在文章的普通改稿不接受`like_settings`,返回422,防止重写时意外重置。旧版本冻结草稿没有该对象的,保留其原来全0语义,不在发布时临时抽值。 鉴权`GET source-articles/{id}`返回`like_growth`:`seven_day_remaining`、`yearly`、`one_year_target`、`one_year_added`、`one_year_started_at`,只用于维护回读,不进入公开模板或文章正文。内容回退不回退点赞进度。 ## 迁移、验证与回退 新增迁移`database/migrations/2026_10_29_200000_add_one_year_article_likes.php`仅给articles增加三列,默认0/0/null,不启用旧文计划。部署时先备份并执行这一条指定迁移,再启用依赖新字段的应用/任务代码,不执行整库重置或导入。 ```sh php artisan migrate --path=database/migrations/2026_10_29_200000_add_one_year_article_likes.php --force ``` 2026-10-29已在本地`fna_v3`执行此迁移;迁移前后170篇原有行字段SHA256一致,现有启用新计划数为0。证据为`output/article-like-growth-20261029/local-before.json`、`local-after.json`。正常命令依赖现有系统调度器;本次没有手工运行真实数据的加赞任务或安装cron。 测试位于`tests/Feature/OneYearArticleLikesTest.php`、`tests/Feature/EditorialApiTest.php`,使用SQLite内存数据库。覆盖渐进增加、满额停止、重复执行、真实赞独立、原年度机制独立继续、停机补进度、禁用/未来开始时间、闰日、空起点、CLI任务接入、草稿随机默认值稳定、发布映射、编辑保留和非法输入;结果为23项测试、225次断言全部通过,回执见输出目录tests.xml。原项目存在命令类文件名与类名不一致的遗留注册问题,测试沿用原编辑API测试的独立进程模式避免重复注册,不修改无关遗留命令。 回退功能时先停用调用新service的任务代码及新版发布代码,保留新字段和历史进度。不要在仍有新版写入者时drop列;需要撤销迁移时先备份新字段、确认没有活动计划和依赖调用方,再在独立维护窗口执行其down。已有文章总点赞数不会自动减回,避免删除真实/其他来源的赞。 本地鉴权`source-articles/365`只读HTTP回读200,新进度字段返回正确的0/0/null,原有文章字段哈希保持一致;证据为输出目录source-check.json。未发布临时文章、未触发真实文章加赞。 ## 已有编辑文章补配命令 `article:backfill-editorial-likes`默认只预览;显式`--apply`才写入。仅处理editorial_documents已绑定且已发布的文章,不处理日更资源。目标额、已支付量均为0且开始时间为空时才补一次性年度额度;短期和持续年度参数同时为0的,另补默认值。已有年度参数和短期余额保留,已过短期窗口的文章不重启短期计划。使用事务行锁,重复执行候选数为0,不重抽、不覆盖进度,也不修改正文、总点赞数和内容日期。 ## 正式部署与补齐(2026-10-29) - 生产目录`/www/wwwroot/clashfreenode-new.com`经白色机SSH更新到已推送Git提交`ea394987069cc0e7a980c60ebe2dc845c03b5fbe`,分支`codex/article-like-growth-20261029`,父提交`cbb847aed89f5452fdbd351968cc2b9c993d9f66`。后续如有仅文档提交,应用代码仍以上述提交为准。 - 服务器私有恢复点`VPS-003:/root/backups/cfn-likes-20261029/`:生产数据库一致性快照、Git bundle、原生成模板、补配前公开文章快照、补配预览和回执。秘密与数据库备份未导出本机。 - 只执行本次指定迁移。10篇教程全部补新增年度额度:原7篇ID206~212分别253/204/137/492/194/297/274,原短期余额0及持续年度30/30/40/30/30/30/50保持。3篇新文:DNS ID375短期30/持续年度50/一次性444;系统代理TUN ID376为34/50/106;Windows ID377为23/50/165。一次性额度从本次补配时计时。 - 生产184篇文章完整保留;补配阶段总点赞数、正文、创建/更新时间、标签和其他元数据不改,174篇资源文章逐行不变。命令重复执行候选数为0;任务正常执行后的短期赞数可持续变化,不能把初始额度当作当前剩余。 - 验证任务时发现原root调度创建的文件缓存目录造成nginx无权刷新,且发布前已有同类真实点赞报错。仅将该站现有每分钟schedule:run条目的PHP执行用户改为nginx,原调度频率、工作目录、日志重定向和其他cron条目保留;业务命令仍由Laravel每5分钟调度。修复该站file cache下6个root所有项的归属,权限模式不扩大;原cron和权限元数据已私有备份。随后以nginx执行命令成功,新增额度与短期原逻辑均接入。 - 2026-10-29 13:32:52 UTC服务器侧首页、综合栏目及系统代理TUN文章HTTP200;编辑API维持关闭,生产环境和原生成模板保留。没有修改广告、Resource、test、DNS、Nginx或其他站点。未做线上页面验收。 - 非秘密发布回执:[ARTICLE_LIKES_RELEASE_2026-10-29.json](ARTICLE_LIKES_RELEASE_2026-10-29.json)。已观察13:35:01 UTC(北京时间21:35:01)自动刷新,缓存写入用户nginx;手动验收后另有4次新调度唤起,证据在回执`automatic_schedule`字段,未为观察再次手动加赞。 回退本次代码可检出上述父提交,但保留新增列、已支付进度及增加的总赞,不自动扣赞或覆盖整库。需要撤销某个额度时先依据本次精确回执、当前已支付量及并行配置生成定点方案;不得把原始快照整行回灌。已修复的调度用户与缓存权限默认保留,不能为回退代码重新引入root缓存写入问题;其原始状态仍留恢复点供审计。