平台工程

赛事状态机到点不切换 · 写入方不等于推进方

入档:2026-07-25 来源:PB Arena(pb.tiaozhuxiansheng.com)第 1 次内测后的修复会话,3 个功能提交 + 1 篇文档,已部署上线并封版 v2026.07.25(pb-arena 仓库 20c7d0f / c5447fb / 2e9ddba) 状态:已上线并线上验证;四条 insight 均为本次首次发现 ⚠️,尚未跨项目二次验证

事实记录(不可修改区)

一句话总结

状态字段有人写、有人显示,不等于有人推进它——时间驱动的功能必须存在一个「谁在到点时改这个字段」的答案,验收标准也要写成「不碰任何按钮,等它自己变」。

四条可复用 insight

1. 写入方 ≠ 推进方 ⚠️首次

official_events.phase_ends_at 一直被正确写入(建赛时算好)、被前端正确读取(倒计时一秒一跳),唯独没有任何代码在它到期时推进状态。于是所有表象都齐了:后台看得到「当前阶段」,用户看得到倒计时归零——只是永远不会翻页。

这类缺陷天然抗发现:字段在、UI 在、倒计时在,grep phase_ends_at 也一堆命中;缺的是”消费者”。定位方式不是搜字段名,而是问「谁在到点时改它」并要求指到具体行,答不出来就是没有。

验收口径要跟着改:手动点按钮能切阶段,证明的是”切换逻辑存在”,不是”自动切换存在”。时间驱动功能的验收必须是不碰任何按钮,等它自己变——这次线上那场无人访问却自动完赛的赛事,才是真正的验收证据。

2. 并列名词要逐项可达,遍历不是控制 ⚠️首次

同事的原话是「控制出图 上传 投票」。我第一版给了「跳到下一阶段」——顺序推进,三个阶段确实都能到达,看起来满足了。但比赛已进投票、发现有人没传完想退回上传时,做不到。

需求里并列列举的名词,默认要求的是逐项直达(随机访问),不是按顺序遍历。 遍历只能满足”最终能到”,直达才满足”现在就要到”。第二版补了阶段下拉框 +「切到该阶段」才算真的做完。判据很简单:把用户列举的每一项当作一个入口,逐个问”能不能一步到”

3. 只有一个用户复现的排版问题,通常全员都在临界点内侧 ⚠️首次

用户截图里胶囊文字换行、压住「封神榜」,其他人都正常。直觉结论是”她浏览器的问题”,实际不是:阶段文字缺 white-space: nowrap,而胶囊是写死的 height: 40px,只要这行字被挤到放不下就换行,换行就溢出。触发条件有四个,任一即可——浏览器设了最小字号(中文用户常设 12px,而这行是 10px)、页面缩放 125%、等宽字体加载失败回退到系统中文字体、窗口更窄。

决定性的一步是量,不是猜:本地默认配置下量到这行字实际宽 56px、单行需要 86px——所有人其实都已经在换行了,只是还没溢出到导航上。她不是例外,她只是先到临界点。

顺带一个反直觉的 CSS 坑:想让文字不换行时,别顺手加 overflow: hidden。它会把 flex / grid 项的自动最小尺寸压成 0,元素反而收缩到被省略号吃掉——本次中途就踩了一次,胶囊从 184px 缩到 104px,文字全没了。正解是只给”必须完整显示”的元素加 nowrap(不加 overflow),把省略让给可牺牲的那个元素(这里是比赛标题)。

4. 状态机上线会追认存量数据,先查再部署 ⚠️首次

新的推进逻辑一旦上线,会立刻按原定时间表处理所有存量记录——不只是以后新建的。线上那场开赛时间已过 56 分钟、4 轮共 48 分钟赛程早已走完的「报名中」赛事,部署后一路被推到「已结束」。

这个行为本身正确(赛程确实过去了),但它是一次静默的批量数据变更,不能由工程侧默认决定。上线前的动作:① 查存量里有多少条会被新逻辑立刻改写、分别会变成什么;② 备份数据库;③ 把处置选项交给运营拍板(本次给了「让它自然结束 / 先延时推到未来 / 删掉」三选一,运营选了第一个)。

顺手教训

下次改进

后续修正(2026-07-25 同日续篇)

本篇的 insight 1「写入方 ≠ 推进方」成立,但默认了这个状态转移就是时间驱动的,这一点是错的。补完自动推进的当天,下一轮内测就反馈「比赛不应该创建后直接开始计时,应该在管理员发布每个题目后才开始」——到点自动进入出图,等于要求运营在开赛那一秒前就把题目写好,而真实流程是人到齐了现场公布题目。

更要命的是同一次反馈暴露:那场”验收通过”的比赛,从来没有人能提交作品(线上 battles / submissions / votes 三张表 0 行)。本篇的验收标准「不碰任何按钮等它自己变」只证明了阶段会流转,没证明这个阶段里有人能干活。

完整结论见 ⚠️ 零作品的比赛_界面演完不等于链路存在_v1:先问「谁在到点改它」,再问「到点该不该发生这件事」,最后问「这功能跑完数据库该多出什么」。

关联文档

类型/平台工程