1
2026-06-16 3d835521c8e2d98b015ddd549d0ca9ef5e2b69d2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
from __future__ import annotations
 
import csv
import hashlib
import json
import re
from datetime import datetime, timezone, timedelta
from pathlib import Path
 
 
FINAL_RUN_ID = "RUN-ANA-WUJI-V1-STRICT-NOTE-FINAL-CONCLUSION-20260615-001"
SOURCE_RUN_ID = "RUN-ANA-WUJI-V1-STRICT-NOTE-FULL-RERUN-20260614-001"
ROOT = Path(__file__).resolve().parents[1]
PROJECT_ROOT = ROOT.parents[2]
SOURCE = PROJECT_ROOT / "ana-data" / "result" / SOURCE_RUN_ID
TZ = timezone(timedelta(hours=8))
 
SOURCE_EXEC_AUDIT_ID = "AUDIT-ANA-WUJI-V1-STRICT-NOTE-FULL-RERUN-20260615-EXEC-001"
MOJIBAKE_RE = re.compile(r"\?{3,}|\ufffd|����|À|Ã|Â|澶|鍙|鎬|涓|蹇|瑙|鏃|鐐|甯|瀹|鍚屾剰|鎸夎")
OVERREAD_RE = re.compile(r"(?<!不)是买入建议|(?<!不)构成买入建议|(?<!不)证明策略有效|策略有效性已证明|策略有效性已经证明|完整baseline成功率|完整baseline收益率|严格笔记版.*证明有效")
 
 
def read_csv(path: Path) -> list[dict[str, str]]:
    with path.open("r", encoding="utf-8-sig", newline="") as f:
        return list(csv.DictReader(f))
 
 
def write_csv(path: Path, rows: list[dict[str, object]], fields: list[str]) -> None:
    path.parent.mkdir(parents=True, exist_ok=True)
    with path.open("w", encoding="utf-8-sig", newline="") as f:
        writer = csv.DictWriter(f, fieldnames=fields)
        writer.writeheader()
        for row in rows:
            writer.writerow({k: row.get(k, "") for k in fields})
 
 
def write_text(path: Path, text: str) -> None:
    path.parent.mkdir(parents=True, exist_ok=True)
    path.write_text(text, encoding="utf-8")
 
 
def sha256_file(path: Path) -> str:
    h = hashlib.sha256()
    with path.open("rb") as f:
        for chunk in iter(lambda: f.read(1024 * 1024), b""):
            h.update(chunk)
    return h.hexdigest()
 
 
def rel_to_project(path: Path) -> str:
    return path.relative_to(PROJECT_ROOT).as_posix()
 
 
def rel_to_root(path: Path) -> str:
    return path.relative_to(ROOT).as_posix()
 
 
def main() -> None:
    generated_at = datetime.now(TZ).isoformat(timespec="seconds")
    source_summary = json.loads((SOURCE / "strict_note_execution_summary.json").read_text(encoding="utf-8"))
    case_rows = read_csv(SOURCE / "strict_note_case_summary.csv")
    boundary_rows = read_csv(SOURCE / "strict_note_boundary_table.csv")
 
    readouts = [
        {
            "readout_id": "STRICT_NOTE_PRIMARY_STRICT_CLOSED_CASE",
            "value": source_summary["primary_strict_closed_case_count"],
            "unit": "case",
            "meaning_cn": "严格笔记版主口径严格闭合 case 数;只包含已严格 BUY 且 lot 全部由外部卖点裁决 SELL 闭合、无未闭合滚动低吸边界的 case。",
            "source_path": rel_to_project(SOURCE / "strict_note_execution_summary.json"),
        },
        {
            "readout_id": "STRICT_NOTE_PRIMARY_POSITIVE_CASE",
            "value": source_summary["primary_positive_case_count"],
            "unit": "case",
            "meaning_cn": "严格笔记版主口径中账户贡献为正的 case 数。",
            "source_path": rel_to_project(SOURCE / "strict_note_case_summary.csv"),
        },
        {
            "readout_id": "STRICT_NOTE_PRIMARY_SUCCESS_RATE",
            "value": source_summary["primary_success_rate_readout"],
            "unit": "ratio",
            "meaning_cn": "严格笔记版主口径成功率读数,等于正收益主口径 case / 主口径严格闭合 case。",
            "source_path": rel_to_project(SOURCE / "strict_note_execution_summary.json"),
        },
        {
            "readout_id": "STRICT_NOTE_PRIMARY_ACCOUNT_CONTRIBUTION",
            "value": source_summary["primary_account_contribution_readout"],
            "unit": "account_contribution",
            "meaning_cn": "严格笔记版主口径账户贡献合计读数。",
            "source_path": rel_to_project(SOURCE / "strict_note_execution_summary.json"),
        },
        {
            "readout_id": "STRICT_NOTE_ALL_BUY_CASE_COVERAGE",
            "value": source_summary["case_count"],
            "unit": "case",
            "meaning_cn": "严格笔记版有 strict BUY 的 case 覆盖数;不替代主成功率分母。",
            "source_path": rel_to_project(SOURCE / "strict_note_case_summary.csv"),
        },
        {
            "readout_id": "STRICT_NOTE_BOUNDARY_RECORDS",
            "value": source_summary["boundary_records"],
            "unit": "record",
            "meaning_cn": "严格笔记版边界记录数,包含市场闸门关闭、买点待审、分钟缺口、HOLD、REVIEW_HELD 和滚动低吸未闭合边界。",
            "source_path": rel_to_project(SOURCE / "strict_note_boundary_table.csv"),
        },
    ]
    write_csv(ROOT / "strict_note_final_readouts.csv", readouts, ["readout_id", "value", "unit", "meaning_cn", "source_path"])
 
    case_index_fields = [
        "case_id",
        "entry_trade_date",
        "signal_trade_date",
        "symbols",
        "case_scope_status",
        "primary_strict_closed_case_flag",
        "net_account_contribution",
        "positive_case_flag",
        "strict_buy_orders",
        "sell_orders",
        "rolling_low_buy_orders",
        "boundary_lots",
        "case_image_board_path",
        "case_story_board_path",
    ]
    write_csv(ROOT / "strict_note_case_readout_index.csv", case_rows, case_index_fields)
    write_csv(ROOT / "strict_note_boundary_table.csv", boundary_rows, list(boundary_rows[0].keys()) if boundary_rows else ["boundary_id"])
 
    summary = {
        "run_id": FINAL_RUN_ID,
        "source_run_id": SOURCE_RUN_ID,
        "generated_at": generated_at,
        "source_execution_audit_id": SOURCE_EXEC_AUDIT_ID,
        "strict_note_primary_strict_closed_case_count": source_summary["primary_strict_closed_case_count"],
        "strict_note_primary_positive_case_count": source_summary["primary_positive_case_count"],
        "strict_note_primary_success_rate_readout": source_summary["primary_success_rate_readout"],
        "strict_note_primary_account_contribution_readout": source_summary["primary_account_contribution_readout"],
        "strict_note_all_buy_case_coverage": source_summary["case_count"],
        "strict_note_boundary_records": source_summary["boundary_records"],
        "citation_policy": {
            "allowed": "可按严格笔记版主口径、审计 ID 和边界表分层引用。",
            "required_text": "该读数只覆盖严格笔记版已审核主口径,不构成买入建议,不证明策略有效性,不得写成无边界完整 baseline。",
            "must_cite": [
                SOURCE_EXEC_AUDIT_ID,
                "strict_note_boundary_table.csv",
            ],
        },
    }
    write_text(ROOT / "strict_note_final_conclusion_summary.json", json.dumps(summary, ensure_ascii=False, indent=2) + "\n")
 
    summary_md = f"""# 严格笔记版最终引用包摘要
 
来源执行包:`{SOURCE_RUN_ID}`
 
来源执行审核 ID:`{SOURCE_EXEC_AUDIT_ID}`
 
## 可引用读数
 
在严格笔记版主口径 `STRICT_NOTE_PRIMARY_STRICT_CLOSED_CASE` 下,{summary['strict_note_primary_strict_closed_case_count']} 个严格闭合 case 中 {summary['strict_note_primary_positive_case_count']} 个为正收益,成功率读数为 {summary['strict_note_primary_success_rate_readout']},账户贡献合计读数为 {summary['strict_note_primary_account_contribution_readout']}。
 
同时必须说明:严格笔记版有 strict BUY 的覆盖 case 为 {summary['strict_note_all_buy_case_coverage']} 个;边界记录为 {summary['strict_note_boundary_records']} 条,边界样本不得混入主口径。
 
## 必须保留的边界
 
1. 本包不是买入建议。
2. 本包不证明策略有效性。
3. 本包不得写成无边界完整 baseline 成功率、收益率、胜率或回撤。
4. 引用时必须同时写明来源执行审核 ID、严格笔记版主口径和边界表。
5. 不得与旧 V1 宽口径 / 代理 BUY 池读数混用。
"""
    write_text(ROOT / "strict_note_final_conclusion_summary.md", summary_md)
 
    human_index = f"""# 严格笔记版最终引用包人工第一入口
 
本入口给同事和审核员快速判断:严格按《笔记精简版.md》重建 BUY 池并重放 V1 卖点 / 趋势止盈 / 滚动低吸后,哪些读数可以引用,哪些不能引用。
 
## 可以引用
 
- 主口径严格闭合 case:{summary['strict_note_primary_strict_closed_case_count']}
- 主口径正收益 case:{summary['strict_note_primary_positive_case_count']}
- 主口径成功率读数:{summary['strict_note_primary_success_rate_readout']}
- 主口径账户贡献读数:{summary['strict_note_primary_account_contribution_readout']}
- 覆盖 case:{summary['strict_note_all_buy_case_coverage']},只说明覆盖,不替代主成功率分母
- 边界记录:{summary['strict_note_boundary_records']}
 
## 必须同时引用
 
- 来源执行审核 ID:`{SOURCE_EXEC_AUDIT_ID}`
- 本最终引用包审核 ID:待审核员填写
- 边界表:[`strict_note_boundary_table.csv`](strict_note_boundary_table.csv)
- 来源执行包入口:[`strict_note_human_review_index.md`](../{SOURCE_RUN_ID}/strict_note_human_review_index.md)
 
## 不能引用
 
- 不能写成买入建议。
- 不能写成策略有效性证明。
- 不能写成无边界完整 baseline 成功率、收益率、胜率或回撤。
- 不能和旧 V1 宽口径 / 代理 BUY 池读数混用。
 
## 文件入口
 
- [`strict_note_final_conclusion_summary.md`](strict_note_final_conclusion_summary.md)
- [`strict_note_final_readouts.csv`](strict_note_final_readouts.csv)
- [`strict_note_case_readout_index.csv`](strict_note_case_readout_index.csv)
- [`strict_note_boundary_table.csv`](strict_note_boundary_table.csv)
- [`source_artifact_manifest.csv`](source_artifact_manifest.csv)
- [`self_check_items.csv`](self_check_items.csv)
"""
    write_text(ROOT / "strict_note_final_human_review_index.md", human_index)
 
    readme = f"""# {FINAL_RUN_ID}
 
严格笔记版最终引用包。
 
本包只整理已审核来源 `{SOURCE_RUN_ID}` 的读数,不重跑候选池、买点裁决、卖点裁决、滚动低吸或账户账本。
 
第一入口:`strict_note_final_human_review_index.md`
"""
    write_text(ROOT / "README.md", readme)
 
    source_paths = [
        SOURCE / "strict_note_execution_summary.json",
        SOURCE / "strict_note_case_summary.csv",
        SOURCE / "strict_note_boundary_table.csv",
        SOURCE / "strict_note_order_ledger.csv",
        SOURCE / "strict_note_position_lot_ledger.csv",
        SOURCE / "strict_note_human_review_index.md",
        SOURCE / "strict_note_execution_self_check.json",
        SOURCE / "strict_note_execution_manifest.csv",
    ]
    source_manifest = []
    for path in source_paths:
        source_manifest.append({
            "source_run_id": SOURCE_RUN_ID,
            "path": rel_to_project(path),
            "size": path.stat().st_size,
            "sha256": sha256_file(path),
        })
    write_csv(ROOT / "source_artifact_manifest.csv", source_manifest, ["source_run_id", "path", "size", "sha256"])
 
    scan_files = [
        ROOT / "README.md",
        ROOT / "strict_note_final_human_review_index.md",
        ROOT / "strict_note_final_conclusion_summary.md",
        ROOT / "strict_note_final_conclusion_summary.json",
        ROOT / "strict_note_final_readouts.csv",
        ROOT / "strict_note_case_readout_index.csv",
        ROOT / "strict_note_boundary_table.csv",
    ]
    mojibake_hits = []
    overread_hits = []
    for path in scan_files:
        text = path.read_text(encoding="utf-8-sig")
        if MOJIBAKE_RE.search(text):
            mojibake_hits.append(rel_to_root(path))
        if OVERREAD_RE.search(text):
            overread_hits.append(rel_to_root(path))
 
    checks = [
        {"check_id": "SOURCE_EXECUTION_PACKAGE_EXISTS", "status": "PASS" if SOURCE.exists() else "FAIL", "detail": rel_to_project(SOURCE)},
        {"check_id": "READOUTS_MATCH_SOURCE_SUMMARY", "status": "PASS" if readouts[0]["value"] == source_summary["primary_strict_closed_case_count"] else "FAIL", "detail": "source summary copied"},
        {"check_id": "BOUNDARY_TABLE_COPIED", "status": "PASS" if len(boundary_rows) == source_summary["boundary_records"] else "FAIL", "detail": str(len(boundary_rows))},
        {"check_id": "SOURCE_ARTIFACT_HASHES_RECORDED", "status": "PASS" if len(source_manifest) == len(source_paths) else "FAIL", "detail": str(len(source_manifest))},
        {"check_id": "NO_MOJIBAKE_IN_FINAL_PACKAGE", "status": "PASS" if not mojibake_hits else "FAIL", "detail": ";".join(mojibake_hits[:20])},
        {"check_id": "NO_OVERREAD_CLAIMS", "status": "PASS" if not overread_hits else "FAIL", "detail": ";".join(overread_hits[:20])},
    ]
    write_csv(ROOT / "self_check_items.csv", checks, ["check_id", "status", "detail"])
    self_check = {
        "run_id": FINAL_RUN_ID,
        "stage": "PASS_FOR_STRICT_NOTE_FINAL_CONCLUSION_REVIEW_READY" if all(c["status"] == "PASS" for c in checks) else "FAIL",
        "generated_at": generated_at,
        "pass_count": sum(1 for c in checks if c["status"] == "PASS"),
        "fail_count": sum(1 for c in checks if c["status"] != "PASS"),
    }
    write_text(ROOT / "self_check.json", json.dumps(self_check, ensure_ascii=False, indent=2) + "\n")
 
    manifest_items = [
        "README.md",
        "strict_note_final_human_review_index.md",
        "strict_note_final_conclusion_summary.md",
        "strict_note_final_conclusion_summary.json",
        "strict_note_final_readouts.csv",
        "strict_note_case_readout_index.csv",
        "strict_note_boundary_table.csv",
        "source_artifact_manifest.csv",
        "self_check_items.csv",
        "self_check.json",
        "tools/build_strict_note_final_conclusion_package.py",
    ]
    manifest = []
    for item in manifest_items:
        path = ROOT / item
        manifest.append({"path": item, "size": path.stat().st_size, "sha256": sha256_file(path)})
    write_csv(ROOT / "manifest.csv", manifest, ["path", "size", "sha256"])
    write_text(ROOT / "manifest.json", json.dumps(manifest, ensure_ascii=False, indent=2) + "\n")
 
    print(json.dumps(summary, ensure_ascii=False, indent=2))
 
 
if __name__ == "__main__":
    main()