feat: 数据实体Tab加多写方风险维度(老莫思维提升)——holding_strategies 10写方等高风险标红,孤立死实体标注。修复mofin_db elif缩进

This commit is contained in:
xxm
2026-08-19 23:44:37 +08:00
parent fea6340228
commit a817d303a9
3 changed files with 45 additions and 3 deletions
+1 -1
View File
@@ -2131,7 +2131,7 @@ def write_holding_strategy(conn, code: str, name: str, data: dict,
data['stop_loss'] = float(_op[2]) data['stop_loss'] = float(_op[2])
data['take_profit'] = float(_op[3]) data['take_profit'] = float(_op[3])
print(f" [AUTHORITY-POS] {code} 保护系统仓位'{_old_pos_val[:30]}'", flush=True) print(f" [AUTHORITY-POS] {code} 保护系统仓位'{_old_pos_val[:30]}'", flush=True)
elif _old_ra: elif _old_ra:
try: try:
from datetime import datetime as _ddt3, timedelta as _dtd3 from datetime import datetime as _ddt3, timedelta as _dtd3
_ra_dt3 = _ddt3.fromisoformat(str(_old_ra)[:19]) _ra_dt3 = _ddt3.fromisoformat(str(_old_ra)[:19])
+24 -1
View File
@@ -940,6 +940,24 @@ def build_report():
flow_status = "read_only" flow_status = "read_only"
else: else:
flow_status = "orphan" flow_status = "orphan"
wcnt, rcnt = len(writers), len(readers)
# 2026-08-19 多写方风险(老莫:数据篡改风险的根源)
# 写方>=3 → 高风险(多个模块竞争写同一实体,可能互相覆写/篡改)
if wcnt >= 3:
risk = "high"
risk_note = f"⚠️多写方{wcnt}(竞争写,可能篡改)"
elif wcnt == 0:
risk = "orphan"
risk_note = "无写方(死实体)"
elif rcnt == 0:
risk = "write_only"
risk_note = "写无读(幽灵)"
elif wcnt == 2:
risk = "watch"
risk_note = f"{wcnt}写方(需关注)"
else:
risk = "ok"
risk_note = ""
entities.append({ entities.append({
"name": tname, "name": tname,
"desc": TABLES_DESC.get(tname, ""), "desc": TABLES_DESC.get(tname, ""),
@@ -947,11 +965,16 @@ def build_report():
"rows": cnt, "rows": cnt,
"readers": readers[:10], "readers": readers[:10],
"writers": writers[:10], "writers": writers[:10],
"writer_count": wcnt,
"reader_count": rcnt,
"multi_writer": wcnt >= 3,
"risk": risk,
"risk_note": risk_note,
"has_input": has_input, "has_input": has_input,
"has_output": has_output, "has_output": has_output,
"orphan": flow_status in ("orphan", "read_only", "write_only"), "orphan": flow_status in ("orphan", "read_only", "write_only"),
"flow_status": flow_status, "flow_status": flow_status,
"warn": flow_status != "healthy", "warn": flow_status != "healthy" or wcnt >= 3,
"flow_detail": flow_detail, "flow_detail": flow_detail,
}) })
+20 -1
View File
@@ -269,6 +269,14 @@ function renderDataFlow(entities, jsonFiles, architecture) {
} }
html += `显示 ${filtered.length} 个数据表 + ${jf.length} 个JSON文件的读写流向。绿色→写入,蓝色→读取。</div>`; html += `显示 ${filtered.length} 个数据表 + ${jf.length} 个JSON文件的读写流向。绿色→写入,蓝色→读取。</div>`;
// 2026-08-19 多写方风险汇总
const risky = filtered.filter(e => (e.risk==='high'||(e.writers||[]).length>=3));
if (risky.length > 0) {
html += `<div style="background:#3d1c02;border:1px solid #f85149;border-radius:6px;padding:8px;margin:8px 0">`;
html += `<div style="font-weight:bold;color:#f85149;font-size:12px;margin-bottom:4px">🚨 篡改风险:${risky.length} 个数据实体有多写方竞争</div>`;
html += `<div style="font-size:11px;color:#d29922">多写方=多个模块写同一实体,可能互相覆写/篡改。重点:holding_strategies(策略参数)、candidates(候选池)、todos等。</div>`;
html += `</div>`;
}
// 按写入方数量排序,最活跃的排前面 // 按写入方数量排序,最活跃的排前面
filtered.sort((a,b) => (b.writers||[]).length - (a.writers||[]).length); filtered.sort((a,b) => (b.writers||[]).length - (a.writers||[]).length);
@@ -282,7 +290,18 @@ function renderDataFlow(entities, jsonFiles, architecture) {
const rDesc = fd.readers || {}; const rDesc = fd.readers || {};
html += '<div style="background:#161b22;border:1px solid #30363d;border-radius:6px;padding:10px;margin-bottom:8px">'; html += '<div style="background:#161b22;border:1px solid #30363d;border-radius:6px;padding:10px;margin-bottom:8px">';
html += `<div style="font-weight:bold;font-size:14px;color:#58a6ff;margin-bottom:4px">🗄️ ${e.name}</div>`; // 2026-08-19 多写方风险徽标(老莫:数据篡改风险)
const wcnt = e.writer_count || (e.writers||[]).length;
const rcnt = e.reader_count || (e.readers||[]).length;
let riskBadge = '';
if (e.risk === 'high' || wcnt >= 3) {
riskBadge = `<span style="background:#3d1c02;color:#f85149;border:1px solid #f85149;border-radius:4px;padding:1px 6px;font-size:10px;margin-left:6px">⚠️多写方${wcnt}·篡改风险</span>`;
} else if (wcnt === 0) {
riskBadge = `<span style="color:#f85149;border:1px solid #f85149;border-radius:4px;padding:1px 6px;font-size:10px;margin-left:6px">☠️无写方·死实体</span>`;
} else if (wcnt === 2) {
riskBadge = `<span style="color:#d29922;border:1px solid #d29922;border-radius:4px;padding:1px 6px;font-size:10px;margin-left:6px">${wcnt}写方·关注</span>`;
}
html += `<div style="font-weight:bold;font-size:14px;color:#58a6ff;margin-bottom:4px">🗄️ ${e.name}${riskBadge} <span style="font-size:10px;color:#8b949e;font-weight:normal">(${wcnt}写/ ${rcnt}读)</span></div>`;
html += `<div style="font-size:11px;color:#8b949e;margin-bottom:4px">${e.desc||''}</div>`; html += `<div style="font-size:11px;color:#8b949e;margin-bottom:4px">${e.desc||''}</div>`;
// 综合总结 // 综合总结
if (fd.summary) { if (fd.summary) {