0f7b5a87fb
登记簿、文档与代码注释里的存量字母加数字编号(N-x / S-x / T-x / E-x / A-x / 卡号) 一律改写为语义短语,净删 2,028 处引用;删除基线与待确认、并行分道方案、排期详述、 采集保护收尾 4 篇(内容已并入 docs/任务规划/README 与登记簿)。 门禁机器与三张账同批重打:check_ids.py 新增变更记录行豁免与第二根护栏 undecidable_total_ceiling;check_test_traceability.py 只加 stdout/stderr UTF-8 reconfigure(TC_RE 未动);check_cubemx_survival.py 的 --write 固定 newline=LF; id_registry / id_aliases(+19 条 retired-to-phrase)/ id_known_backlog 重打。 test/ 56 个文件同步 TC 标签语义化,其中 18 个 TU 改了 CHECK / printf 里的标签文字, 是本批唯一改变构建产物的文件集合。 为什么合成一笔、不拆四笔(实测撞闸,非偏好):pre-commit 跑钩子前会 stash 未 staged 部分,拆开后中间提交必然是「新规则 + 旧语料」——实跑可判定 85.15% < 基线 86.00%、 不可判定 1,453 > 上限 1,166,编号门禁直接拦下。编号识别面与它描述的语料只能同码移动。 实跑基线(工作区全量):754 文件 / 8,230 处编号字面量 / 可判定 7,079 = 86.01% (基线 86.0%,容差 0.1pp)/ 不可判定绝对数 1,151(上限 1,166)/ 校验 1-6 错误级 0 / 告警 = 悬空 2(App/algo/freq.c 的 S2,属 §4.4 同号不同义)+ 孤儿 50。 基线从 84.0 抬到 86.0 的理由见 docs/门禁说明/id-check.md §7.6:本批真删了 2,028 处 引用,可判定面随真实内容上升,不是把分母做小。同批新增排除 docs/硬件平台/ 语料,使 识别面少 264 处——芯片手册位号与网表料号不属编号空间(registry 有 excluded_paths_note)。 ⚠ 余量只剩 0.11pp(约 10 处)与绝对数 15 处:把「可判定的引用」改成散文会立刻撞第二 根护栏。另遗留一项:id_aliases 里 retired 的 N / S / T / A 别名没有 scope(U1~U5 有), 今后有人新写一个 A-4,校验 3 不会响,只能靠人,建议下批补 scope。 固件不变证据:115 个 .c/.h 剥注释并归一字符串后与 HEAD 逐字节全等,残留代码差异 0; App / Src / Drivers 的字符串字面量零改动。@build 0 错误 0 警告;40/40 主机套件、2,889 断言全通过;覆盖率 line 89.2% / func 92.6%;pre-commit 48 钩子 --all-files 全绿; check_doc_links --all 通过(176 文档,章节引用无法判定 0);逐字节卫生核过:14 个带 BOM 文件与 HEAD 一致、0 个 CR、0 个 U+FFFD,字符串字面量纯 ASCII。 .cubemx_survival_baseline.json 的 watchdog-module 哈希 56bf27 变 2bb051 属合法: Src/freertos.c 的 USER CODE 区内只有注释文字随编号改写,代码未变。 同批带上体积同码凭证与 RAM 台账行(@build 之后盖戳):RW_IRAM1 79,008 B / 60.3%, RW_CCM 57,376 B / 87.9%,阈值 92%。
111 lines
4.5 KiB
Python
111 lines
4.5 KiB
Python
#!/usr/bin/env python3
|
||
"""头阻塞专项台架探针(timeSync 侧,A/B 对照用)。
|
||
|
||
场景(历史审计的头阻塞触发形态,属主文档已于 2026-10-15 删除):
|
||
1. 一个"挂起"的对时客户端连上 :8888 后不发任何数据(空闲/故障客户端,
|
||
常见工况)——旧固件在此触发 30s 阻塞 net_recv 独占 netTask,
|
||
全体消费者的队列消息停摆最长 30s;
|
||
2. 2s 后从 PC 发起 FTP(:21) 连接,测 banner 到达时延 = 队列响应性:
|
||
修复前 ≈ 25~30s(队头冻结),修复后 ≈ 数百 ms 内;
|
||
3. 34s 时 30s 总预算应已耗尽:设备拆掉该会话(net_drop_conn:
|
||
FIN 关闭 + 本层收口 + 重监听),随后**本探针模拟守规矩对端**:
|
||
close 自己的 socket;
|
||
4. 芯片回 CLOSED(TC-NET-204 模式 A:TIME_WAIT 过渡 ~150ms)→ relisten,
|
||
:8888 应能再接受新连接(3s 重试窗内);新连接发完整 8 字节 TIME 包 →
|
||
设备应落 "wall clock updated"。
|
||
|
||
⚠ 定案口径(TRAP-NET-07 定案更正 2026-10-11 + 《网络自愈架构设计》§5.2 E13):CH395F close
|
||
**无 RST 语义**。若对端内核存活(app 挂起但 socket 不关,内核自动 ACK FIN),
|
||
芯片停在 FIN_WAIT_2、监听恢复受限于对端 close——探针第 3 步的 close 正是
|
||
模拟"对端配合"这一可恢复边界;不配合场景的兜底是芯片 TIMEOUT/keepalive
|
||
拆僵尸会话(E13 定案,30~90s)。
|
||
|
||
用法: python e02_probe.py <run-tag>
|
||
退出码: 0 = 队列响应性 PASS;1 = FAIL;2 = 探针自身异常
|
||
"""
|
||
import socket
|
||
import sys
|
||
import time
|
||
|
||
DEV = "192.168.1.100"
|
||
tag = sys.argv[1] if len(sys.argv) > 1 else "run"
|
||
|
||
t0 = time.time()
|
||
|
||
|
||
def log(msg):
|
||
print("[%s] %9.3f %s" % (tag, time.time() - t0, msg), flush=True)
|
||
|
||
|
||
def main():
|
||
# 1. 挂起对时客户端:连接后不发任何数据
|
||
ts = socket.create_connection((DEV, 8888), timeout=5)
|
||
log("time-sync conn open (hung client: sends nothing)")
|
||
|
||
# 2. 2s 后测 FTP banner 时延(队列响应性)
|
||
time.sleep(2.0)
|
||
t1 = time.time()
|
||
banner = None
|
||
try:
|
||
ftp = socket.create_connection((DEV, 21), timeout=35)
|
||
banner = ftp.recv(256)
|
||
dt = time.time() - t1
|
||
log("FTP banner after %8.1f ms: %r" % (dt * 1000, banner[:40]))
|
||
ftp.close()
|
||
except Exception as e:
|
||
dt = time.time() - t1
|
||
log("FTP connect FAIL after %8.1f ms: %r" % (dt * 1000, e))
|
||
dt = None
|
||
queue_ok = (banner is not None) and (dt is not None) and (dt < 3.0)
|
||
log("queue responsiveness: %s (banner %s ms)"
|
||
% ("PASS" if queue_ok else "FAIL",
|
||
("%.0f" % (dt * 1000)) if dt is not None else "n/a"))
|
||
|
||
# 3. 等 30s 总预算耗尽(设备应拆会话:FIN + 本层收口 + 重监听)
|
||
remain = 34.0 - (time.time() - t0)
|
||
if remain > 0:
|
||
time.sleep(remain)
|
||
|
||
# 3b. 模拟守规矩对端:设备已发 FIN(drop_conn),本端 close 配合拆链。
|
||
# CH395F close 无 RST 语义(TRAP-NET-07 定案更正):不配合的内核存活对端
|
||
# 会把芯片停在 FIN_WAIT_2,监听恢复受限于对端 close——不在本探针判据内。
|
||
try:
|
||
ts.close()
|
||
log("hung client socket closed (cooperate with device FIN)")
|
||
except OSError:
|
||
pass # 设备已先拆连,本地 close 报 ECONNRESET 属预期
|
||
|
||
# 4. 监听应已重建(芯片 TIME_WAIT 过渡 ~150ms + relisten):3s 重试窗
|
||
t2 = time.time()
|
||
listener_ok = False
|
||
ts2 = None
|
||
while time.time() - t2 < 3.0:
|
||
try:
|
||
ts2 = socket.create_connection((DEV, 8888), timeout=2)
|
||
break
|
||
except Exception as e:
|
||
log("second time-sync conn retry: %r" % (e,))
|
||
time.sleep(0.3)
|
||
if ts2 is not None:
|
||
dt2 = time.time() - t2
|
||
epoch = int(time.time())
|
||
log("new time-sync conn in %6.0f ms, sent full TIME packet (epoch=%d)"
|
||
% (dt2 * 1000, epoch))
|
||
ts2.sendall(b"TIME" + epoch.to_bytes(4, "big"))
|
||
time.sleep(1.5) # 留时间给设备处理并打日志
|
||
ts2.close()
|
||
listener_ok = True
|
||
else:
|
||
log("second time-sync conn FAIL (3s window)")
|
||
log("OVERALL: queue=%s listener=%s"
|
||
% ("PASS" if queue_ok else "FAIL", "PASS" if listener_ok else "FAIL"))
|
||
return 0 if (queue_ok and listener_ok) else 1
|
||
|
||
|
||
if __name__ == "__main__":
|
||
try:
|
||
sys.exit(main())
|
||
except Exception as e:
|
||
print("[%s] PROBE ERROR: %r" % (tag, e), flush=True)
|
||
sys.exit(2)
|