weather scheduler proposal E / deterministic

方案 E · GID 确定性排布自然雨 = 纯函数,永不落盘

自然雷雨排布 = f(GID, activity_id, dayIdx, 配置),以 splitmix64 定点哈希逐段演算; 道具雨只存事件(append-only),读时前向重放叠加顺延。任何 Pod、任何时刻(历史/未来)、任何玩家(含从不登录)都能算出同一答案。

加权评分(要实时徽标情景)4.26 加权评分(cache-on-visit 情景)4.11 落盘 item_rains 单字段 timer 依赖 配置 first 10-20m · next 30-60m · duration 20m · buffer 10-15m
SERVER TIMEDay0 00:00:00
01

排布如何生成 · 种子推导(玩家甲 · 当前天)

纯函数,零状态,零 IO —— 下表随左上角时钟实时重算

推导链(真实 splitmix64,BigInt 逐位一致)


      

每天 0 点(CST)按 (GID, activity_id, dayIdx) 三元组 re-seed;段间隔 = hash-per-index 独立可算; 绝对时间链式累加。跨午夜尾窗由次日 spillback 回看 + 自然 floor(前一日链候选携带)保证 duration / 间隔不被午夜切碎。

当天基线窗口表(玩家甲 · 未叠加道具雨)

02

三类玩家 + BOT 伙伴 · 三天排布时间轴

点击标尺跳转时间 · 横向滚动查看三天 · 伙伴与玩家同轴同引擎(零特殊化)
伙伴种子口径(BOT-Q1 已拍 2026-07-02:盐化)
自然雷雨(现算,不落盘) 道具雨(item_rains 落盘) 被顺延的自然雨(重放时自动后移) 好友列表所见基线(仅玩家甲第二行) 列表态 vs 实际 偏差带 全服同步带(裸口径教学档 · 伙伴泳道)

全部泳道对每个 GID 都无条件存在——排布是数学对象,不需要登录、不需要 timer、不需要任何触发点。 玩家丙(从不登录)与玩家甲同样精确;玩家乙离线三周后重登,任何历史时刻同样可点查(dayIdx 按目标时刻寻址,非按 now)。 BOT 伙伴与玩家同轴同引擎(bot/entity.proto:伙伴内嵌 owner Model、非 actor;不用瓶 → item_rains 恒空 → 基线即精确)——伙伴泳道不是新机制,正是"任意 GID 可算"的字面演示;读点全部持 owner 锁(Enter/GetBriefs/BotTick 回调),离线种植烘焙零前置。

03

道具雨干扰 · 顺延与跨午夜

互斥:当前有任何雨时召唤瓶不可用
— 操作日志 —

玩家甲 · WeatherState(唯一落盘物)


      

顺延不写任何字段:读时重放对每条 item_rain 施加 next = max(next, item_end + bufSec(gid,act,k)), 级联在前向重放中自动发生——没有被存储的排期列表可以被改坏。bufSec 走独立 tag 哈希流,不扰动自然间隔序列。

04

配置热更干扰 · 版本化 + dayIdx 天界门控(05 §14)

排布 = f(GID, dayIdx, cfg(dayIdx))——配置是入参,"何时生效"决定撕不撕裂
生效策略:
新版本参数生成的窗(v≥1 着色) v0 冻结参照(热更前世界) 两个世界的差异带 ┆ 热更时刻 │ 生效天界

上下游影响面板(随策略实时重算)

— 配置变更日志 —

E 的处理协议:①改参数一律走版本列表 + effective_from_day,cfg(dayIdx) 纯函数选版(§14.3), 历史日永选旧版 → 已揭示变异 / (dayIdx,segIdx) 场次身份 / 镜像 buf 全稳定;生效日须 ≥ 明日天界且晚于代码滚更完成(§14.4)。 ②ItemRain.duration_sec 使用时落盘(§15.3)→ 热更只影响此后新用的瓶,历史道具雨窗不动。 ③顺延缓冲范围的版本按 use_ts 归属日选取(演示采用 · 待冻结规则)——与 E-Q2④「buf 预算入镜像」天然一致。 ④eager 烘焙门跨生效天界会陈旧(§14.8 的"lazy 自动吸收"在 §16.9 锁 eager 后不再免费): 吸收路径三选一待拍——登录触点 gate-only 重算 / 揭示时代际校验(修正「纯投影」契约)/ 接受快照语义(暴露面 ≤ 生效前 24h 内种下且门落在生效日后的作物)。 增补候选触点(10 §11.4):配置变更后首个心跳——在线玩家 O(1) 代际比对即时吸收、离线交三选一;建议主方案=揭示时代际校验(消费点闭环,10 §11.5)。 ⑤当日紧急止血:§14.10 倾向不引入当日内版本边界,配错走停活动重开——「当日时刻分段」选项仅演示其代价。 ⑥算法本体(splitmix64/种子构造/日界)永不热更,改则开新 activity_id(§14.9)。

05

好友列表 ·「雷雨中」徽标(观察者视角)

徽标 = 纯 f(好友GID, now),零好友读、零 actor load

在线/离线不影响徽标计算(E 的核心卖点:pre-visit 实时徽标)。 默认口径下,用过召唤瓶的好友在顺延生效期间,列表基线(纯 GID)与实际存在偏差带(泳道图红色斜纹)。 勾选上方提案后:观察者在 friend 列表装配处(buildFriendListReply,api.go:573)用「基线 + 镜像 rains」重放 → 偏差消失, 且好友的道具雨本身也能上榜(纯基线永远做不到)。先例:info.Plant.plant_data 已镜像未来时间戳 (ripe_time_sec 等,info.proto:107-121),写侧 plant/impl/system.go:78 注册 builder + 各操作点 MarkFieldDirty(FieldPlant)。 从不登录好友 item_rains 恒空,两种口径下均精确。

06

作物与闪电变异 · eager 烘焙 + 纯投影揭示 + 施肥移轴

集成模型 = eager(05 §16.9 已锁):种植时预判烘焙,揭晓不查天气

尚未种植。选一种成熟时长(4/8/12/24h),把时间调到某场雨前再种;观察四个跨阶段判定点是否落进雨窗,再试施肥把判定点整体前移。

07

双方如何拿到同一份排布 · 数据流

三条读路径共用同一确定性引擎(禁分叉,golden 冻结)
观 察 者 Pod(好友列表)
friend.SyncAll 批量拉好友 锁外查 info(Redis 镜像)· 既有链路
│ 对每个好友 GID(含从不登录)
徽标 = IsRaining(friendGID, now) 纯 CPU 演算 ~微秒级 · 零 actor load · 零 IO
└ 用过瓶好友 → 列表态基线(精确档进农场取)
(提案)info.FieldWeather 携带近 48h item_rains 先例 = info.FieldPlant 已镜像未来 ripe_time_sec;用瓶时 MarkFieldDirty · 事件驱动非读触发写 → 列表徽标含顺延/道具雨
owner Actor(自己 / 被访问)
种植 / 施肥 / 收获(InvokeLock 内) WeatherByTime(gid, BeginTime_k) 纯算 → 烘焙 Phases[].Mutants
好友进农场:plant/visit SS → owner actor 锁内读 item_rains → 重放 → 精确天气 + 作物纯投影
使用召唤瓶(itemsys.Use · self-context) AppendItemRain → markDirty(唯一写点)
存 储 / 基础设施
Tcaplus player 记录 WeatherState{ item_rains } 单字段 · 从不用瓶者零记录
timersvr —— 不使用 ——
配置(Bottle 版本列表 + effective_from_day) 按 dayIdx 纯函数选版本 · 天界生效 · 不落盘(04 节可交互热更)
08

三优三劣 与 三个开放问题

优点

  1. 覆盖与徽标的结构性独占:任意 GID 任意时刻(历史/当下/未来)纯算可答——从不登录好友徽标、离线数周补算、种植问未来,全部零 actor load、零落盘。
  2. 零运行期基础设施:无 timer / 无续约孤儿治理 / 无水位线 GC;存储单字段,从不用瓶玩家整活动零写。
  3. 正确性可枚举可冻结:排布 = 纯函数 → golden 向量一次冻结全量回归;改时间测试零成本;跨 Pod 一致是构造性质。

缺点

  1. 冻结契约税:splitmix64 + 种子构造 + 日界 + buf tag 流成为跨 Pod/跨版本 bit 级契约;上线不可改,修 bug 只能按 activity_id 开新算法版本。
  2. 设计期复杂度高:spillback + 自然 floor 午夜缝、override 前向重放、config 版本化 + dayIdx 门控、多类型 K 路归并 + 饥饿建模,接手心智门槛高。
  3. 可观测与列表精度短板:离线排布无事件发射点(统计走解析式/日终重放);用过瓶好友列表态默认存在顺延偏差带——info 镜像携带 item_rains 提案(见 05 节开关)可消除,但引入 info/friend 两处协议改动与签字点。

就方案 E 还需要拍板的三个问题(详见 10_DE_REEVAL.md §4)

  1. E-Q1 排布函数的活动间演进机制:修 bug/换哈希只能按 activity_id 开新版本——"schedule 版本注册表"(activity_id→算法版本、golden 多版本归档、旧版保留期)要不要现在定?
  2. E-Q2 徽标计算落点与 info 镜像方案签字:评估结论=「info 镜像携带近 48h item_rains」是好方案(先例 FieldPlant、事件驱动写、搭车 BatchGetInfo 零额外读),但需拍:info.proto 加 FieldWeather + fieldTypeMapping(info owner 🟡)、GameFriend proto 加 weather 字段(含 end_ts 供客户端倒计时)、镜像条目窗口(48h)与 buf_sec 预算入镜像、活动结束镜像清理口径、MarkFieldDirty 秒级陈旧窗口可接受性。
  3. E-Q3 "同场特殊天气仅 1 次采集瓶"的场次身份:E 的雨窗无落盘实体无 ID,场次键只能是 (owner_gid, window_begin) 记访客侧——跨午夜 spill 窗归属、owner 顺延后 begin 变化导致键失配的规则未定义。

BOT 伙伴增补(泳道见 02 节 · 徽标见 05 节 · 详见 10_DE_REEVAL §10)

  1. 成本账 = 0:无新增落盘(伙伴无 item_rains、无物化窗)、无新增 timer(天气不搭 BotTick)、无镜像;BotTick 离线回调里 DriveBehavior→PlantForCtx 种植烘焙照常——纯函数任意上下文可算。BOT 变异 roll 走同一条 CalculateAllPhaseMutations(保底跳过 bot,system_plant.go:341)。
  2. R-B2 初始化即成熟:伙伴首建 plantAndMatureAllLands 先种植(烘焙未来门)再 MaturePlantForCtx 把全部 BeginTime 压到 now(system_ops.go:57)——四个判定点瞬时坍缩。须定口径:首建作物不参与天气变异(推荐),或按压缩后时点判定一次(now 恰在雨中 = 四门齐触发,超发面)。
  3. BOT-Q3 采集瓶 × 伙伴农场:伙伴农场的"访客"只有 owner 本人(Companion 私有)。若可用 = 每玩家保底 N 伙伴 × ~23 场/天的抽奖点(经济口径须策划拍);场次身份沿用生成坐标 (act, companionSeedGid, type, dayIdx, segIdx),去重记录存 owner 自身模型——比真人好友更简单。
  4. D′ 对照:同一 BOT 议题在 D′ 页须独立成节(09 节 · BOT-Q2 物化存储位三选一)——E 里伙伴消融于常规机制、D′ 里伙伴是结构难题,这个不对称本身即选型论据。
09

算法内幕 · 逐行解剖(附录)

splitmix64 每一步在做什么 · 常数从哪来 · 与窗口表 / 施肥 / spillback / currentWeather 如何串联

mix(x) 七步分解(live · 输入可改)

GOLD = ⌊2^64/φ⌋(黄金分割 · 必须是奇数:与 2^64 互质 → 加法序列 2^64 步不重复);乘数 C1/C2 与移位 30/27/31 = Stafford Mix13——2011 年计算机海选(按"雪崩偏差最小"打分穷举移位+奇乘数组合)的第 13 号优胜配方,不是理论推导出来的;乘数为奇数 ⇒ 每步 mod 2^64 可逆 ⇒ mix 是 64 位双射(不同输入必不同输出、熵零损失)。

雪崩实验:翻 1 个输入位,输出变几位?

雪崩 = 1 个输入位的扰动平均翻转一半(32±5)输出位、且翻哪些位看起来随机。乘法只把信息往高位搬(进位链),异或右移把高位折回低位——两个方向交替两轮,信息才跑得遍 64 位。终混 ^(x>>31) 是最后一次高位反哺低位——rr 用 % 取模恰恰消费低位,终混是它的安全垫(配套设计,非巧合)。

推导链跟踪:常数 → 玩家甲当天窗口表(live)

间隔流按索引直取(rngAt(seed,i) 互相独立、可随机寻址),但窗口位置是累加的——第 i 场起点 = 前面全部时长+间隔之和,所以出表 = 一趟前向重放(O(窗口数) ≈ 微秒)。daySeed 先对 gid/act/day 各自 mix 再异或:原始值低熵(高位全 0),直接异或会撞(1000⊕1001 与 1001⊕1000 同值);先 mix 把每个入参撒满 64 位再异或,外层再 mix 消除异或的线性结构。

当天窗口数从哪来?(120 GID × 3 天 = 360 份重放)

窗口数不是配置,是涌现值:期望 ≈ 86400 ÷(时长 1200 + 平均间隔 2700)≈ 22.2 场/天,实际随抽取在 21~24 波动。seg 序号 = 链内位置(0 起),生成时天然确定——"0..23"只是本配置的典型区间,改 duration/next 期望随之移动。(统计用 v0 配置纯基线,忽略跨日 floor 的 ±1 边缘影响)

currentWeather(now) 发生了什么(live · 随时钟变化)

spillback / 跨午夜(live)


        

口径(F1/F2 已拍 2026-07-02):采用连续重放 · floor 恒携带(= 本演示语义,05 §7.5.2/§12.4 已加修订注)——每日链尾候选无条件跨日携带为次日 floor,golden 自活动起点定义;恒携带顺手修掉"前日无 spill 但尾窗贴近午夜 → 今日首窗跨午夜间隔被切短"的残留缝。spillback 短路是这套语义的读侧表现。

cursor:在线玩家的摊还 O(1)(05 §3.10A · live · 播放/拖动时间观察步数)


      

窗口位置 = 随机间隔的前缀和——没有数组就没法二分,先建数组又是一次前向重放。三层成本:定位天 O(1)(ts÷86400 除法寻址);冷查 = 自活动起点连续重放 O(已过天数×W)——floor 跨天链式携带,"只回看 1 天"并不精确(F1 已拍修订,05 §12.4 修订注);30 天活动 ≈ 700 步仍是微秒级,且"每日尾 floor"检查点可摊回 O(W)——**CP 已拍搭车落盘**(2026-07-02:用瓶时随 markDirty 写入 Model+镜像,读同记录零边际;加速器非真值,10 §14.5);在线连续查询 cursor 摊还 O(1)——时间单调前进,游标只消费新经过的窗口,每天每玩家合计也只走 W 步。cursor 是进程内纯加速器:不落盘(05 §15.1 表)、不进冻结契约、任何时刻丢弃都回退冷查——本卡每帧都断言 cursor 结果与冷查逐位一致(G2 一致性三查的第四路)。失效重建条件:用瓶/热更/复位(输入变)、时间回拨;跨天是自动续走、不算失效。本页其余泳道用的是第四种策略"整段物化 memo"(可视化需要全量数组),生产热路径不需要。

施肥时 plant 怎么调 weather(走查 · live)

实战走查:7月1日开活动,7月23日 10:00 在下雨吗?(F1/F2/F3 已拍口径 · 独立场景,不随页面时钟)


      

      

判定流程(F1 连续语义):输入三件套(全量 item_rains 5 条 + 配置版本表 3 版 + actStart)→ 自 Day0 连续重放——每窗按起点时刻选版(v0→v1→v2 天界切换)、瓶按 use_ts 插队并抬 floor(buf 按全局序号 k=0..4)、每日尾候选恒携带为次日 floor(F2)→ 走到 Day22 10:00 命中扫描。逐日表的"入 floor 生效"列是 F1 论断修正的实证(floor 生效远非罕见);Day1 三瓶把当日链整体推后并波及 Day2 入 floor;Day5/Day20 行可见 v1(时长 20→15m 窗数变多)与 v2(间隔 30-60→40-80m 窗数变少)的天界切换。

b-weather-rain-statemachine-260624 · weather-demo-E.html · 2026-07-02 · 算法与 05 §3.10/§7/§12/§14/§15、09 §2 逐条对齐;F1/F2/F3 已拍口径(连续重放 · floor 恒携带 · 镜像全量)(演示级简化:日界用整 86400,真实实现走 pkg/utils/time.go CST)