refactor(编号): 第一批清号——登记簿旧号/阶段号/台架阶段裸形三族清零,位号目录排除

按 §9 批次一执行。**这批的关键发现是「看着像 62 处编号,实际能算编号的只有一小半」**,所以先分类再动手,
没有按站点数硬清:

· **真·编号(已改名)**:`N-6`(`MDK-ARM/tcp_reconnect_probe.py` 的「TRAP-NET-17 / N-6
」→ 只留 TRAP 锚点
  + 中文说明);台架阶段裸形 `T0`~`T3` 全部转成场景名——`e11_keepalive_probe.py` 的「静默对端 / 正常空闲存活」、
  `ftp_auth_bench.py` 的「匿名登录 / 未登录直接 NLST / 错口令锁定」、`serial_tool.py` 自检里的「行拆分 /
  解码回退链 / 时间戳行格式 / 端口建议」、`net_test_task.c` 与 `CH395F_Test_Guide.md` 的「空闲存活场景」、
  网络自愈设计里的「三路审计」。另把 `test/host/iec104_master.py` 的变量 `T0` 改成 `t_start`(那是起始时刻
  变量,被裸形族误抓)。
· **不是编号、但被误判(按 §4.4 处理,不改语料)**:`tools/netlist_semantics/` 里的 `T1` 是**网络变压
器位号**
  (硬件知识库),整目录进 `excluded_paths`,与 `docs/硬件平台/` 同口径;`BSD_Socket_API_函数调用关系.
md` 的
  `T1/T2/T3` 是 **Mermaid 节点名**,已改成语义节点(`RetryTick`/`PendTick`/`PendShimTic
k`/`ReconcileTick`)——
  图本身没变,只是节点不再叫字母号;`docs/门禁说明/gitlint.md` 里的 `T2` 是 **gitlint 自己的规则名**(不是本仓
  的号),已改写成规则描述;`docs/算法/傅氏算法详解.md` 的 `N-1` 是**数学记号**(求和上界 `x(N-1)`),保留不动,
  并在 §4.4 登记为「唯一已知误判」。
· **规范自身两处示例**顺手去掉字面量:`S3 / TM-PHY-01 / DP-03` → `S3 / TM-… / DP-…`;「报告 N-
16」→「报告 +
  登记簿旧号」。

结果(用门禁接口复测):`TM` 族 0 引用、`T-TEST` 族只剩规范自身 2 处示例、`N` 族只剩数学记号 1 处;
`F-*`(38 站点 / 12 个号,代码注释里的网络设计条目号)**留下批单独做**,因为每处要读懂语义、不能替换字面量。

口径变更已写进 §4.4:位号目录 `tools/netlist_semantics/` 进排除面;`N-1` 声明为已知误判。歧义面收窄后,
新错误级仍为 0、`id-check --strict` exit 0。

⚠ 这批**刻意没有复活「别名表洗白」那条路**:`N-6` 这类死号不进 `id_aliases.json`,让门禁继续咬将来的残留
引用(与 FTP 死号同一处理,见 §5.7)。
This commit is contained in:
2026-10-27 07:39:00 +08:00
parent 8bac9869c7
commit 95beaab313
12 changed files with 61 additions and 54 deletions
@@ -1123,26 +1123,26 @@ def run_selftest():
def check(name, cond, detail=""):
results.append((name, bool(cond), detail))
# T1 行拆分:CRLF / 多行 / 残行冲刷
# 行拆分:CRLF / 多行 / 残行冲刷
sp = LineSplitter()
got = [l for _, l in sp.feed(b"abc\r\n", 1000.0)]
check("T1a CRLF 行", got == [b"abc"], repr(got))
check("行拆分:CRLF 行", got == [b"abc"], repr(got))
got = [l for _, l in sp.feed(b"de\nf\n", 1001.0)]
check("T1b 多行", got == [b"de", b"f"], repr(got))
check("T1c 残行不入文件", sp.feed(b"ghi", 1002.0) == [] and sp.buf == b"ghi")
check("行拆分:多行", got == [b"de", b"f"], repr(got))
check("行拆分:残行不入文件", sp.feed(b"ghi", 1002.0) == [] and sp.buf == b"ghi")
got = [l for _, l in sp.flush_partial()]
check("T1d 残行冲刷", got == [b"ghi"], repr(got))
check("行拆分:残行冲刷", got == [b"ghi"], repr(got))
got = sp.feed(b"\n\n", 1003.0)
check("T1e 空行忽略", all(not raw for _, raw in got) and sp.buf == b"", repr(got))
check("行拆分:空行忽略", all(not raw for _, raw in got) and sp.buf == b"", repr(got))
# T2 解码回退链
# 解码回退链
check("T2a UTF-8", decode_line("中文ok".encode("utf-8")) == "中文ok")
check("T2b GBK", decode_line("中文".encode("gbk")) == "中文")
check("T2c HEX 兜底", decode_line(b"\xff\xfe\x01") == "HEX:fffe01")
# T3 时间戳格式
# 时间戳格式
s = line_at(time.time(), "RX", "x")
check("T3 行格式", s.startswith("[RX] ") and "T" in s.split(" ")[1], s)
check("时间戳行格式", s.startswith("[RX] ") and "T" in s.split(" ")[1], s)
# T4 截头算法(保留尾部 + 截后继续追加)
pat = b"0123456789abcdef"
@@ -1298,8 +1298,8 @@ def run_selftest():
except OSError:
pass
# T10 端口建议:换 USB 口后 COM 号变了,唯一候选直接给(多候选不猜)
check("T10 port_hint 唯一候选才给建议",
# 端口建议:换 USB 口后 COM 号变了,唯一候选直接给(多候选不猜)
check("端口建议:唯一候选才给建议",
port_hint("COM7", ["COM6"]) == "COM6"
and port_hint("COM7", ["COM6", "COM9"]) is None
and port_hint("COM6", ["COM6"]) is None)
+1 -1
View File
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
# TRAP-NET-17 / N-6 trustworthy reproduction probe: rapid reconnect to a device listener.
# TRAP-NET-17 复现探针:快速重连到设备监听器: rapid reconnect to a device listener.
#
# Failure under test (original report): after a rapid reconnect (<~1s) on a
# relistened socket, the chip completes the handshake but the MCU never gets
+1 -1
View File
@@ -1095,7 +1095,7 @@ IDLE → ACCEPT → [SEND: 分块发 → DONE] / [RECV: 分块收+校验 → DON
| **标题** | TCP 连接空闲超过 KeepAlive 阈值后自动断开 |
| **前置条件** | 1. `NET_KEEPALIVE_IDLE_MS=60000` / `INTVL=5000` / `CNT=3`(`net_config.h`)<br>2. 对端须为**死对端**:PC 连接 8080 后**禁用网卡**制造"链路在、对端静默"(存活对端会 ACK 探测 → 永不 TIMEOUT;Windows 防火墙规则对已建立连接无效,E11 实证)<br>3. 勿与 Phase 6/9/10/13 混选(recv 互抢数据) |
| **测试步骤** | 1. PC 连接 8080,不发数据<br>2. 立即禁用 PC 网卡(中间有交换机 → 设备侧 PHY 链路保持)<br>3. 等待芯片报 TIM_OUT(实测判死窗:连接起 **18~31s**,芯片定时语义与手册公式 75s 不符,见 `docs/网络/网络自愈架构设计.md` §5.2 E11/E13)<br>4. 本层 QUARANTINE → reconciler 形态③④ 重建 → s0 回 LISTEN<br>5. 恢复网卡,重连 8080 验证端口已恢复 |
| **通过标准** | recv 返回 0 且耗时落在 **10s~120s 有界窗**(下限防"存活空闲会话被误杀"——T2 实测存活对端静默 90s 不触发;上限防"判死缺位");s0 回 LISTEN 且可接受新连接。报告后测试自动释放 socket 等新连接再测(一次性,防对已死连接 10ms 节奏刷假 FAIL) |
| **通过标准** | recv 返回 0 且耗时落在 **10s~120s 有界窗**(下限防"存活空闲会话被误杀"——空闲存活场景实测存活对端静默 90s 不触发;上限防"判死缺位");s0 回 LISTEN 且可接受新连接。报告后测试自动释放 socket 等新连接再测(一次性,防对已死连接 10ms 节奏刷假 FAIL) |
---
+8 -3
View File
@@ -74,7 +74,7 @@ P-6 号必须能反查到定义(属主登记处得存在)· P-7 编号不语
- 登记处就是那张表:表首格写短语,**不要再配一个字母号**;跨文档引用写成
`` `docs/任务规划/登记簿.md` 「双转换器无共同采样触发」 ``,同篇后续直接用短语。
- 文档内的实施步骤 / 测试阶段 / 设计原则条目写中文:「步骤 3」「阶段 7」「DMA 边界安全」,
**不写 `S3` / `TM-PHY-01` / `DP-03` 这种号**。
**不写 `S3` / `TM-…` / `DP-…` 这种号**。
---
@@ -128,11 +128,16 @@ P-6 号必须能反查到定义(属主登记处得存在)· P-7 编号不语
元器件位号 `U1`/`C12`/`R3`/`L5`/`D7`(硬件语料按目录整体排除)、数学与协议记号(`N-1`、测频的正序与
负序分量 `S1`/`S2`、`SHA-256`、`RS-485`、`ADC1_IN14`、手册页码)、活表代号 `E0~E19`(网络自愈 §5.2,
**无连字符**,与死号 `E-nn` 只差一个连字符)、Socket 状态组合 `U1~U15`(网络自愈 §1.1)、档位词 `P0~P3`。
判据只有一条:**带连字符、且能在属主登记表查到定义**才叫编号;查不到的就是普通文本,不是"漏登记的号"。
判据只有一条:**带连字符、且能在属主登记表查到定义**才叫编号;查不到的就是普通文本,不是「漏登记的号」。
> 2026-10-27 补两条实测口径:① **元器件位号目录整体排除**——`tools/netlist_semantics/` 是硬件知识库
> (`T1` 在那里是网络变压器位号),已进 `id_registry.json` 的 `excluded_paths`,与 `docs/硬件平台/` 同口径;
> ② **唯一已知误判**:`docs/算法/傅氏算法详解.md` 里的数学记号 `N-1`(「一个周波 N 个点」的求和上界)会被
> `N-x` 族命中,属可判定引用、不影响两根护栏,**不清**——清了反而破坏公式。
### 4.5 已删报告的自有族
《项目审查与优化建议报告》2026-10-25 已删除,它自造的六族随之失去定义,且与登记簿同字母不同义。
看到"报告 N-16"这类写法一律按死号处理:删号留事实——各条目原本指向的设计文档就是现在的出处。
看到「报告 + 登记簿旧号」这类写法一律按死号处理:删号留事实——各条目原本指向的设计文档就是现在的出处。
---
@@ -50,10 +50,10 @@ flowchart TB
subgraph NT["netTask 主循环 — 1ms/tick;芯片操作唯一执行者"]
NPM["netProcessMessages<br/>先跑 4 个 tick,再排空队列分派"]
NP["netPoll<br/>INT# GPIO 轮询 → 全局中断 → 各 Socket SINT → 状态缓存全量刷新 + sock_reset 步进 → 每轮一批"]
T1["① netListenerRetryTick<br/>D10 重监听重试:30ms / 2s 时限"]
T2["② netPendingTick<br/>挂起 recv:①数据 ②到点(仅显式预算) ③断连 ④tripwire 60s 只留痕"]
T2B["③ netSendPendingTick<br/>挂起 send:①断连 ②推进(每轮≤1块) ③写完 ④无进展超时"]
T3["④ netReconcileTick<br/>TRAP-NET-17 对账 + 监听重建合一:100ms / 分级去抖 / 冷却<br/>读驱动状态缓存(①②③④⑤ + U11)"]
RetryTick["① netListenerRetryTick<br/>D10 重监听重试:30ms / 2s 时限"]
PendTick["② netPendingTick<br/>挂起 recv:①数据 ②到点(仅显式预算) ③断连 ④tripwire 60s 只留痕"]
PendShimTick["③ netSendPendingTick<br/>挂起 send:①断连 ②推进(每轮≤1块) ③写完 ④无进展超时"]
ReconcileTick["④ netReconcileTick<br/>TRAP-NET-17 对账 + 监听重建合一:100ms / 分级去抖 / 冷却<br/>读驱动状态缓存(①②③④⑤ + U11)"]
DISP["队列分派 switch<br/>SEND · RECV · CLOSE<br/>CONNECT · LISTEN · ACCEPT · DROP_CONN"]
subgraph LK["_locked / 内部分派目标(仅 netTask 上下文)"]
LL["netListenLocked<br/>初次监听(open 重试 3× + sock_reset 排渣)"]
@@ -76,24 +76,24 @@ flowchart TB
PUB -->|入队| MQ
MQ --> DISP
DISP --> LL & LN & LS & LR & LA & LC & DC & RLS
NPM --> T1 & T2 & T2B & T3 & NP
T1 --> RLS
T3 -->|"① 已断"| EV
T3 -->|"② 补 accept"| EV
T3 -->|"⑤ 静默回收:RESYNC 只修本层 + 取消挂起(不发芯片命令,吸收原 net_resync_listen 语义)"| RSY["reconcile⑤ RESYNC 动作"]
T3 -->|"③④ 监听失位 / 孤儿监听即重建(原 pump)"| RLS
NPM --> RetryTick & PendTick & PendShimTick & ReconcileTick & NP
RetryTick --> RLS
ReconcileTick -->|"① 已断"| EV
ReconcileTick -->|"② 补 accept"| EV
ReconcileTick -->|"⑤ 静默回收:RESYNC 只修本层 + 取消挂起(不发芯片命令,吸收原 net_resync_listen 语义)"| RSY["reconcile⑤ RESYNC 动作"]
ReconcileTick -->|"③④ 监听失位 / 孤儿监听即重建(原 pump)"| RLS
DC -->|"拆会话后登记重监听"| RLS
NP --> EV
EV --> FE
FE -.-> CB
EV -->|"断连/超时:只置事实"| ST
ST -.->|"事实 → 由 reconciler 形态③④ 统一重建"| T3
ST -.->|"事实 → 由 reconciler 形态③④ 统一重建"| ReconcileTick
LR -->|无数据+阻塞| PR
PR --> T2
T2 -->|xTaskNotify| XN
PR --> PendTick
PendTick -->|xTaskNotify| XN
LS -->|等发送缓冲超预算| SR
SR --> T2B
T2B -->|xTaskNotify| XN
SR --> PendShimTick
PendShimTick -->|xTaskNotify| XN
XN -->|唤醒| PUB
NP --> CH
LL & LN & LS & LR & LA & LC & DC & RLS --> CH
@@ -107,7 +107,7 @@ flowchart TB
2. `net_process_messages()` 开头的 **4 个 tick 是网络层自愈主干**:没有任何应用消息时,重试 / 挂起 recv 完成 / 挂起 send 推进 / 状态对账 + 监听重建照常运转——"断连后即使没人发消息,监听器也能自己活过来"靠的就是它们。
3. 事件处理器**只由 `net_poll` 驱动**,例外是 `net_reconcile_tick`(分级去抖 + 1s 冷却)可再入 `handle_disconnect_event` / `handle_connect_event`——对账是事件未收到的自愈通道(TRAP-NET-17)。**注意职责边界(对账与重建合并后)**:对账与事件处理器**只置事实**(置 CLOSED / 登记沉降),**重建监听的动作统一由 `net_reconcile_tick` 形态③④ 做**(本层唯一重建入口)——"谁先看到 DISCONNECT 就谁重建"的竞争在结构上消失。
4. 回调 `event_cb` 在 **netTask 上下文**执行:回调内不得阻塞、不得发网络操作。
5. **模块归属**:`T1`(D10 重试)/ `RLS` 的 `net_listener_request` / `ST`(settle)在 `net_listener.c`(真机专属、模拟器不编译);挂起 recv 完成检查(`net_pending_tick`)、挂起 send 推进(`net_send_pending_tick`)与两张挂起表(`PR` / `SR`)在 `net_pending.c`(真机专属);其余 tick(含合并后的 `T3` reconciler)与 `_locked` 在 `net_socket.c`。
5. **模块归属**:`RetryTick`(D10 重试)/ `RLS` 的 `net_listener_request` / `ST`(settle)在 `net_listener.c`(真机专属、模拟器不编译);挂起 recv 完成检查(`net_pending_tick`)、挂起 send 推进(`net_send_pending_tick`)与两张挂起表(`PR` / `SR`)在 `net_pending.c`(真机专属);其余 tick(含合并后的 `ReconcileTick` reconciler)与 `_locked` 在 `net_socket.c`。
---
+1 -1
View File
@@ -858,7 +858,7 @@ accept 走 `handle_connect_event`),且 `NET_RECON_STABLE_DEATH` 两边共用
- 本文引用格式:`docs/网络/网络自愈架构设计.md` §N.M(紧邻写法);E 编号引 §5.2
(如"§5.2 E12"),F 编号引 §7。
- **勿引用已删除的过程章节**。过程考古:
- N34 自愈审计(T1~T4 三路审计、39 条编号发现全文、E0~E15 原始记录、分阶段实施清单):
- N34 自愈审计(三路审计、39 条编号发现全文、E0~E15 原始记录、分阶段实施清单):
`git show 1a35b36^:docs/网络/N34-自愈审计/`(目录合并前 7 份文档)或
`git log --oneline -- docs/网络/N34-自愈审计/`;
- 监听生命周期(本文 §1.1~§1.4 / §4.9 / §9~§11 的来源,含 P0~P3 勾选清单与台架验收记录):
+1 -1
View File
@@ -35,7 +35,7 @@
```
gitlint..............................................................Failed
12: BBody line length limit exceeded, lengthy body line (max-line-length: 79)
1: T2 Title has trailing whitespace
1: Title has trailing whitespace
```
- 前缀数字是行号(第 1 行是标题)。本仓最常犯的是 `B`(正文行超长)与标题超 100。
+4 -2
View File
@@ -59,7 +59,8 @@
".dsh/n31_neg_inject_gen221_form5.log",
"scripts/id_known_backlog.json",
"scripts/rename_maps/",
"docs/硬件平台/"
"docs/硬件平台/",
"tools/netlist_semantics/"
],
"excluded_suffixes": [
".svg",
@@ -133,7 +134,8 @@
"^Y[0-9]-[0-9]+$",
"^A-Z0-9$",
"^X-[0-9]+$",
"^V[0-9A-Z]{2,}-[0-9]+$"
"^V[0-9A-Z]{2,}-[0-9]+$",
"N-1"
],
"malformed": [
{
+1 -1
View File
@@ -842,7 +842,7 @@ static int phase11_run(int32_t sockfd) {
* 生产参数实测判死窗口 18~31s(产品验证 连接+30.5s、E11 T5
* 对端失联+30s、T4 短参数 连接+~10s)。本 socket 无在途 TX、
* 对端静默且已失联 → 唯一开枪源是 keepalive,故判据为
* **有界窗**:>=10s(存活空闲会话 T2 实测 90s 不被杀,10s 下限
* **有界窗**:>=10s(存活空闲会话 空闲存活场景实测 90s 不被杀,10s 下限
* 区分"误杀"与"keepalive 判死")且 <=120s(判死必须发生)。
* 勿改回 >=60000——那是对着手册公式写的,会在正确固件上假 FAIL */
TEST_CHECK(elapsed >= 10000U && elapsed <= 120000U,
+4 -4
View File
@@ -8,18 +8,18 @@ App/ 无任何 net_connect() → 产品上 keepalive 实际关闭。本脚本用
"开启后能否在有界时间内判死静默对端,且不误杀正常空闲会话"。
用法:
# T2 正常空闲存活:连接后静默 hold 秒,末尾发 KEEPLIVE 验证会话仍在
# 场景「正常空闲存活」:连接后静默 hold 秒,末尾发 KEEPLIVE 验证会话仍在
python e11_keepalive_probe.py --mode idle --hold-s 90
# T1 静默对端:连接后立即装 Windows 防火墙入站 DROP(仅本连接本地端口 +
# 场景「静默对端」:连接后立即装 Windows 防火墙入站 DROP(仅本连接本地端口 +
# 设备 IP)→ 芯片 keepalive 探测得不到 ACK → 期望设备在
# IDLE + INTVL×CNT 内判死(本仓 60 + 5x3 = 75s)
python e11_keepalive_probe.py --mode block --hold-s 120
判据(设备侧事件由串口日志核对,本脚本打印 PC 侧时间线):
T1 期望:串口出现 `[ERR][NET] sockN TIMEOUT`(耗时≈75s),随后
期望:串口出现 `[ERR][NET] sockN TIMEOUT`(耗时≈75s),随后
`sockN pump/relisten` 恢复;本脚本移除规则后新连接必须成功。
T2 期望:hold 期间**无** TIMEOUT;末尾 KEEPLIVE 必须收到 0xBB 回显。
期望:hold 期间**无** TIMEOUT;末尾 KEEPLIVE 必须收到 0xBB 回显。
需要管理员权限(仅 block 模式装/卸防火墙规则;脚本自行清理)。
"""
+11 -11
View File
@@ -5,9 +5,9 @@
验证固件侧 lftpd 鉴权集成的完整行为矩阵(主机单测 test/host/ftp_auth 覆盖
不到的"协议接线"部分:命令门、530/331/230/550 响应码、跨会话锁定):
T1 匿名登录(anonymous) → 期望 530 拒
T2 未登录直接 NLST → 期望 530(命令门)
T3 对用户名 + 错口令 ×5 → 期望 530 ×5(并触发锁定)
场景「匿名登录」(anonymous) → 期望 530 拒
场景「未登录直接 NLST」 → 期望 530(命令门)
场景「对用户名 + 错口令 ×5」 → 期望 530 ×5(并触发锁定)
T4 锁定窗内正确口令 → 期望 530(LOCKED,不算哈希)
T5 等待锁定期满后正确口令 → 期望 230(60s + 余量)
T6 登录后 NLST / STOR / RETR / DELE → 期望全通(出厂 write=1)
@@ -83,26 +83,26 @@ def main(argv=None):
if not cond:
fails.append(name)
# ---- T1 匿名登录被拒 ----
# ---- 场景「匿名登录被拒」----
ok, code, conn = _try_login(args.host, args.port, args.timeout, "anonymous", "x@x")
if ok is None:
print("[env] 连不上 %s:%d → %s" % (args.host, args.port, code))
return 2
expect("T1 匿名登录 → 530", (ok is False) and code.startswith("530"), code)
expect("匿名登录 → 530", (ok is False) and code.startswith("530"), code)
if conn:
conn.quit()
# ---- T2 未登录直接 NLST → 530(命令门)----
# ---- 场景「未登录直接 NLST → 530(命令门)」----
time.sleep(0.5) # 单连接 socket:等 auto_relisten 沉降(~50 ms + 余量)
f = FTP()
f.connect(args.host, args.port, timeout=args.timeout)
try:
f.sendcmd("NLST")
expect("T2 未登录 NLST → 530", False, "居然放行")
expect("未登录 NLST → 530", False, "居然放行")
except error_perm as e:
expect("T2 未登录 NLST → 530", str(e).startswith("530"), str(e))
expect("未登录 NLST → 530", str(e).startswith("530"), str(e))
except Exception as e: # noqa: BLE001
expect("T2 未登录 NLST → 530", False, repr(e))
expect("未登录 NLST → 530", False, repr(e))
# ⚠ 必须 close:单连接模型下不关 = 占住 socket,后续步骤全被拒
# (2026-10-11 台架实测:QUIT 后不 close → 芯片视角旧连接仍 ESTABLISHED)
try:
@@ -114,11 +114,11 @@ def main(argv=None):
pass
time.sleep(0.5)
# ---- T3 错口令 ×5 → 530 ×5 ----
# ---- 场景「错口令 ×5 → 530 ×5」----
for i in range(1, 6):
ok, code, conn = _try_login(args.host, args.port, args.timeout,
args.user, "wrong-pass-%d" % i)
expect("T3.%d 错口令 → 530" % i, (ok is False) and code.startswith("530"), code)
expect("错口令 %d → 530" % i, (ok is False) and code.startswith("530"), code)
if conn:
conn.quit()
+2 -2
View File
@@ -80,11 +80,11 @@ SCAN_COTS = (COT_BG, COT_INIT)
YX_NAMES = {15: "YX15 fault-total", 16: "YX16 OC-I", 17: "YX17 OC-II",
18: "YX18 OC-III", 23: "YX23 overload", 31: "YX31 prot-block"}
T0 = time.time()
t_start = time.time()
def log(msg):
print("[%9.3fs] %s" % (time.time() - T0, msg), flush=True)
print("[%9.3fs] %s" % (time.time() - t_start, msg), flush=True)
def hexs(b):