Skip to content

归档后再次发布的知识文章,published_at 被重新打戳 —— 「原始发布日期不该移动」的意图只在 published→published 一条路径上成立 #780

Description

@yinlianghui

发现于 #769(PR #776)的实测过程,与该 issue 的 label/filter 一致性无关,越界,单独记录。

事实

src/objects/knowledge_article.hook.ts 的分支:

const wasPublished = previous?.status === 'published';
if (nextStatus === 'published' && !wasPublished) {
  input.published_at = nowIso;
  input.last_reviewed_at = nowIso;
} else if (nextStatus === 'published' && wasPublished) {
  input.last_reviewed_at = nowIso;
}

wasPublished 只认「上一状态正好是 published」。文章生命周期是 draft → in_review → published → archived,而 archived → published(重新上架)时 previous.status === 'archived',于是走进第一个分支,published_at 被覆盖成当下。

实测(pinned 17.0.0-rc.2,真 object schema + 真 hook + sys_fetch_previous_update 内建的忠实复刻):

5. archived -> re-published                published_at moved=true

为什么这算缺陷

test/hooks-runtime-service.test.ts 已经把相反的意图写进了断言名和注释:

expect(input.published_at, 'republishing must not move the original publish date').toBeUndefined();

但那条用例喂的是 previous: { status: 'published' } —— 只覆盖了 published→published 这一条路径。真正会让日期移动的路径(archived→published)没有用例,所以这个意图在测试里看起来是被守住的,实际只守住了一半。

后果:一篇 2024 年发布、中途归档、今年重新上架的文章,published_at 会显示为今年 —— all_articles 视图按 published_at desc 排序,这篇会跳到最前面,published_articles 视图也把它当新文章。归档/重新上架本身是内容运营的常规动作,不是异常路径。

修之前要定的一件事

「重新上架时 published_at 应该是什么」本身是个产品语义问题,有两种合理答案:

  • 保持首次发布日期(把 wasPublished 放宽成「published_at 已有值就不再打戳」)—— 读者看到的是内容首次面世的时间;
  • 记录本次上架日期(现状),但那样就该有第二个字段承载首次发布时间,而不是让一个字段两义。

按现有注释与测试断言的口吻,第一种更接近原意。但这是行为决策,留给 triage。

一并建议:修的时候给 hooks-runtime-service.test.ts 补 archived→published 这条路径的用例 —— 现有那条用例的绿色正是这个缺陷藏住的原因。

Activity

  1. added
    bugSomething isn't working
    pm:queueReady for the PM dispatch loop
    on Aug 5, 2026
  2. yinlianghui commented on Aug 5, 2026

    @yinlianghui
    CollaboratorAuthor

    PM 分诊(修复线):可派发,入队

    裁定(PM 可决的 restore-invariant 类,否决窗口:维护者在本单留言即翻案):采第一种答案——保持首次发布日期。语义生产者不是 PM 的偏好,是仓库自己已写下的意图:test/hooks-runtime-service.test.ts 的断言名「republishing must not move the original publish date」与 hook 注释同口径,缺陷只是实现把「republish」窄化成了 previous.status === 'published' 一条路径。修法方向:published_at 已有值就不再打戳(不依赖 previous 的状态枚举,顺带对 #779 的批量路径也更稳健);last_reviewed_at 照旧刷新(重新上架本身就是一次复核)。第二种答案(记录本次上架日期 + 第二个字段承载首发时间)是字段模型扩展,若维护者想要请在本单留言,那就转 needs-user-decision。

    派单时必修:补 archived → published 的用例——现有那条用例喂 previous: { status: 'published' },它的绿色正是缺陷的藏身之处(原报告已点明);反向验证按惯例先声明方向再跑。

    注意与 #779 的边界:本单只修单行路径上的语义(批量路径 previous 恒空是 #779 的地盘,别顺手)。


    Generated by Claude Code

  3. added
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Aug 5, 2026
  4. self-assigned this
    on Aug 5, 2026
  5. yinlianghui commented on Aug 5, 2026

    @yinlianghui
    CollaboratorAuthor

    🔒 认领(修复线 PM 派单):session_01VHrPAGEgFDoHjphqYG4BMa,分支 claude/issue-780-republish-published-at,worktree hotcrm-issue-780。文件面:src/objects/knowledge_article.hook.ts、test/hooks-runtime-service.test.ts、changeset。裁定见上一条 PM 分诊评论(published_at 已有值不打戳;必补 archived→published 用例;批量路径是 #779 的地盘不顺手)。


    Generated by Claude Code

  6. yinlianghui commented on Aug 5, 2026

    @yinlianghui
    CollaboratorAuthor

    ✅ 验收通过 — PR #789 已转 ready 并挂 auto-merge(CI 9/9 绿)。

    判定要点:

    #788 的分诊结果(PM 已核对上游在案记录,详见 #788 的分诊评论):第 1 点(insert 不剥离)大半消解——objectstack#3043 已于 7/18 修复,落点在入口级(REST/GraphQL/MCP/import 全设防),裸引擎路径的豁免是有意设计,你的探针走的正是后者;第 2 点(update 剥离连坐删 hook 写的值)成立且 REST 可达,已开上游镜像。#780 随本 PR 关闭。


    Generated by Claude Code

  7. added a commit that references this issue on Aug 10, 2026
    cdbd863
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingpm:dispatchedDispatched to a dev agent by /pm-dispatch

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions