- 正在读上游选股计划…… 上游装配这份计划要读论断与催化事件,慢的时候要几十秒。
+ 正在读上游选股计划…… 正在读取已发布的完整版本。
这段时间抽屉是空的,属正常;真读不到会在这里显示原因。
「预期空间」= 券商目标价相对现价的空间 (上游 upside 字段, 2.12 → +212%)。噪音大,
- 所以永不参与排序 —— 排序始终按 score; 只在 PMS_PLAN_MIN_UPSIDE 上做下限过滤。
+ 所以永不参与排序 —— 排序按当前有效模式与稳定次级键; 只在 PMS_PLAN_MIN_UPSIDE 上做下限过滤。
筛选参数在「参数设置」里: PMS_PLAN_TOP_N / PMS_PLAN_TIERS / PMS_PLAN_INCLUDE_OBSERVE /
PMS_PLAN_MIN_SCORE / PMS_PLAN_MIN_SOURCES / PMS_PLAN_MIN_UPSIDE / PMS_PLAN_STALE_TDAYS。
发给上游的三个: PMS_PLAN_TOP / PMS_PLAN_OBS_TOP / PMS_PLAN_THEME_CAP (0=不传, 用上游默认
@@ -4453,7 +4455,7 @@ createApp({
const src = p.plan_source === 'snapshot' ? '快照' : (p.plan_source === 'live' ? '现算' : (p.plan_source || ''));
const gate = p.gate_on === true ? '赛道闸开' : (p.gate_on === false ? '赛道闸关' : '');
const head = ['选股计划数据至 ' + (p.date || '-') + '(数据日)', planFetchedText.value, src, gate].filter(Boolean).join(' · ');
- return head + '。日期是数据日:上游每个交易日早上 07:10 用上一交易日收盘后的证据出计划,持仓系统 08:40 拉取,所以正常显示的是上一交易日。计划来源:快照=盘前落盘那份,毫秒返回、可复现;现算=盘中实时装配,较慢,多半是快照过旧回落。赛道闸=上游是否只在十条赛道内选票。';
+ return head + '。日期是数据日:上游每个交易日早上 07:10 用上一交易日收盘后的证据出计划,持仓系统 08:40 拉取,所以正常显示的是上一交易日。计划来源:快照=已发布的完整版本,包含晨版及盘中修订;旧接口的现算来源不具备同等追溯能力。赛道闸=上游是否只在十条赛道内选票。';
});
const hdMenuLabel = computed(() => {
const who = authed.value ? (me.value.username || me.value.phone || '') : '';
diff --git a/scripts/test_batch8_units.py b/scripts/test_batch8_units.py
index f7a4d4f..af890fe 100644
--- a/scripts/test_batch8_units.py
+++ b/scripts/test_batch8_units.py
@@ -632,6 +632,33 @@ def t_j4():
restore()
+@case("[J4b] 新版收到身份写读一致,查询范围变化不能误认同版")
+def t_j4b():
+ from app.services import plan_feed as pf
+ from unittest.mock import patch
+ store, restore = _with_fake_repo({"PMS_PLAN_SNAPSHOT": True})
+ try:
+ p = plan(main=[_r("600418.SH", 1, 242.24)], date="2026-07-30")
+ p.update(decision={'id': 'decision-a', 'input_hash': 'a'}, requested={'top': 300})
+ pf.snapshot(p)
+ before = len(store['rows'])
+ assert pf.preview_changes(p)['same_as_stored'] is True
+ with patch.object(pf, 'get_plan', return_value=p):
+ assert pf.changes()['in_sync'] is True
+ assert len(store['rows']) == before
+ q = dict(p, requested={'top': 100})
+ assert pf.preview_changes(q)['same_as_stored'] is False
+ q = dict(p, decision={'id': 'decision-b', 'input_hash': 'b'})
+ with patch.object(pf, 'get_plan', return_value=q):
+ assert pf.changes()['in_sync'] is False
+ assert pf.snapshot(q)['stored'] is True
+ with patch.object(pf, 'get_plan', return_value=q):
+ assert pf.changes()['in_sync'] is True
+ assert pf.preview_changes(q)['same_as_stored'] is True
+ finally:
+ restore()
+
+
@case("[J5] 只读预览能比出手上这份与库里那份的差异")
def t_j5():
from app.services import plan_feed as pf