Repository navigation
forecast_snapshot 与启动重播种的互动:每次 dev 重启后,当季出现一条无 owner 的幻影快照行与 owner 键控行并存 #702
Description
Activity
- addedbugSomething isn't workingSomething isn't workingmetadataDeclarative metadata — schema, security posture, UI surfacesDeclarative metadata — schema, security posture, UI surfaces
on Aug 5, 2026 - added a commit that references this issue
on Aug 5, 2026 - addedpm:dispatchedDispatched to a dev agent by /pm-dispatchDispatched to a dev agent by /pm-dispatch
on Aug 5, 2026 认领:PM 循环(17.0 发布修复线)第 1 轮(顶替 #708 空出的槽位)
会话:session_01VHrPAGEgFDoHjphqYG4BMa
分支:claude/issue-702-forecast-phantom-row
Worktree:hotcrm-issue-702
文件面:三选一落点 ——src/flows/demo-bootstrap.flow.ts(认领清单加 crm_forecast)或 forecast 种子数据(不再播当季行)或src/flows/forecast-snapshot.flow.ts(收养无主当季行),外加相关测试与 changeset。⛔ 不触 #684 在飞的七个 record-change flow 文件。派发注记:本单证据采自验收线 pre-#677 基线(5a78f88),而 #677 重写过
demo-bootstrap.flow.ts(±126 行,owner 双列已并成owner_id单列)且 #708 已核实认领谓词现为{owner_id: null}。三个 contributing factor 需逐一对 origin/main 重核(尤其「demo_bootstrap 不认领 crm_forecast」与「seed 行无 owner」两条)后再选修法。
Generated by Claude Code
验收 ACCEPT(PM 复核,对照 GitHub 实况):PR #717,CI 9/9 绿,已转 ready 并挂自动合并。
复核要点:
- 前提在 post-fix: bug 批次修复(PM 派发循环)— #606 #673 #610 #548 #678 #650 已落地 #677 的 main 上逐条重核成立(三要素全在,仅「8 objects × 2 columns」措辞过时);碰撞收敛到唯一一条
demo_quarter_current。 - 方案选择有实测依据,不是偏好:方向 1(仅认领)被证明是调度顺序依赖的 —— sweep 先到窗口时产生永不自愈的重复行(findOne 只刷新先碰到的一条),反向验证的红法不对称恰好暴露了「方向 1 单用会看起来修好了」;方向 3(收养无主行)在 flow lookup 的表达力下语义错误(多 owner 争抢)。最终:种子退出当季窗口(one producer per window)+ 认领清单补
crm_forecast(后者的独立理由:private OWD 下无主快照对所有 rep 不可见、对所有人不可编)。 - 依赖方向写进了源码注释:顺序无关性来自种子退让,不来自认领 —— 防止后来者只抄认领那半。
- 代价如实声明:新种 org 的 Quota Attainment 表在 03:00 sweep 前为空、quota 需手工设 —— 替换掉的是一条不属于任何人的 1.5M quota 幻影行,是净改善;changeset 给了存量库的处理指引(
pnpm demo:reset,已核实该脚本存在)。 - 守卫从 flow 自身的
find_forecastfilter 推导禁区窗口,SNAPSHOT_PERIOD改动时守卫自动跟随;[CRM] Forecast「This Quarter」视图恒为空:种子数据 period_start 不落在季度边界 #530/quota_attainment_by_repsums forecast rows across every period, so month + quarter snapshots double-count #614 的既有性质被「改指」而非删除,论证清楚。 - 衍生发现 demo_bootstrap 不认领 crm_campaign / crm_knowledge_article:两类种子行永远无 owner,marketing_user 与 service_agent 有 allowEdit 却编辑不了 #716(campaign / knowledge_article 未认领,Seeded contracts are ownerless at the platform level (
owner_idnull) — nobody, admin included, can edit one #622 形态)已立单并分诊入队。
Generated by Claude Code
- 前提在 post-fix: bug 批次修复(PM 派发循环)— #606 #673 #610 #548 #678 #650 已落地 #677 的 main 上逐条重核成立(三要素全在,仅「8 objects × 2 columns」措辞过时);碰撞收敛到唯一一条
[17.0-rc2验收复核] 运行时实测复核 · 环境
hotcrm@0899b4f + @objectstack 17.0.0-rc.2(独立 scratch DB,端口 4098)。⚠ 本基线0899b4f(09:39Z)早于 PR #717 合入(~14:54Z),故 #717 的修复不在本树内。即便如此,幻影行不复现。实测
- 冷启动:
crm_forecast8 行(与声明一致),全部owner_id=SET(admin)。原因:平台claimSeedOwnership首管交接(packages/runtime/src/app-plugin.ts:951-956)把所有 NULL-owner 种子行改归提升后的 admin —— 包含crm_forecast,而 demo_bootstrap 的CLAIMED_OBJECTS并不含它。故种子 forecast 行在本基线不是无主的,本单机制第 2/3 环的前提(「种子无主 → owner 域查找落空 → 建兄弟行」)被推翻。 - 触发 forecast_snapshot:总数保持 8;当季 Q3-2026(2026-07-01→09-30)quarter 行原地更新(pipeline 0→2.91M),无无主兄弟行。
- 暖重启(重播种)后:re-upsert 保留
owner_id(金额被重置回种子值,owner 不动);Q3-2026 quarter 行=1、有主、无主=0。再次触发 forecast_snapshot → 仍 8 行、1 有主、0 无主。
两次复现均为:
total=8, Q3-2026-quarter=1 (owned=1, ownerless=0)。结论
本验收基线上幻影不可复现 —— claimSeedOwnership 把种子 forecast 行预先归给了 snapshot flow 所键控的同一个 admin,owner 域查找命中既有行并原地更新。补充一条发布风险事实:#717 的「种子退出当季窗口」不在
0899b4f,故若发布从0899b4f切,仍会播一条当季 forecast 种子行(但它是有主行,不是幻影)。仅记录实测,不动标签。
Generated by Claude Code
- 冷启动:
- added 4 commits that reference this issue
on Aug 10, 2026 - added a commit that references this issue
on Aug 25, 2026 - addedpriority:p2Medium: important, M3Medium: important, M3and removed
on Sep 9, 2026 - added a commit that references this issue
on Oct 2, 2026
Found during the 17.0 GA acceptance sweep on
@objectstack/*17.0.0-rc.2 (currentmain), flow phase. Minor, demo-data-only, but it produces visibly wrong analytics rows on every re-seeded dev boot.Mechanism (observed live)
forecast_snapshot(03:00) maintains an owner-keyed current-quarter row per deal-owning user — that part works (verified: gate skips no-deal users, creates/updates the owner's row, sums the four buckets, leavesquotauntouched).updated: 288at 07:19:43), which re-upserts all 8 seed forecast rows — and seed rows carry no owner (seeds cannot declare one; known limitation).Result: any consumer grouping forecasts by owner sees a phantom ownerless duplicate for the current quarter after every re-seeded dev boot. (This also compounds the
display_title: nullissue #690 — the phantom row renders with no title AND no owner.)Contributing factors, each individually known
owner(platform seed limitation),demo_bootstrapclaims ownership on 8 objects × 2 columns but does not claimcrm_forecast,Suggested direction (CRM-side, pick one)
crm_forecasttodemo_bootstrap's claim list (cheapest), orAttribution
CRM (seed data + demo_bootstrap claim list interplay); the platform pieces (ownerless seeds, warm-boot re-upsert) are each behaving as documented.
Refs #690 #617 #671