feat(对时): 8888 对时补一条操作记录留痕——与 104 对时对称,被拒不落痕
task-49 盘点盘出的唯一供给缺口,task-50 实现(道H 交付)。为什么这算缺陷而不是「维护工装不值得留痕」:
对时改变的是**其后每一条记录**的时标,而 104 侧的对时**已经留痕** —— 同一类行为两种结果,这个不对称
本身就是缺陷。FTP 上传不留痕则维持原状(那是传输动作,与「装置时钟被改了」不同类),本笔
刻意不扩面到它。
实现:`time_sync_handle_conn` 里 `sys_clock_set_unix` 的返回值原先是**裸丢弃**,现改为接住判
0,==0 才
投 `SYSLOG_OPER`(走 quiet 口,netTask 侧纪律,栈成本已在注释写明);**被拒零投**(不把失败记成改过时
钟);无合并锁存(连续两次对时留两条,不折叠);**epoch 语义零触碰、零时区补偿** —— 时基口径仍在用
户手里,本笔不替产品决定。
新用例四组十二断言:成功恰一条 / 被拒不落痕 / 连续两次两条 / 魔术字不符皆零。假件把 rc 做成可脚本,
并专门钉「文案出现次数」以证不合并;`sys_log.h` 用真实头(纯 stdint,走 task_watchdog 先例),零桩漂移面。
**停发口径的第一批**:新断言**不配 TC 号**,改用语义化用例名 + 函数名追溯,注释里标了口径出处 —— 裁定
能不能落地看的就是第一批,这条留在这里给后来者当样例。
证据:time_sync 92/92(存量 82 零回归);@build **0 错 0 警**,Code=235268 RO=26308 RW
=1572 ZI=136924
(与上一笔的差值是 728d6067 合账所致,不是本笔);栈**以表为证**:timeSyncTask 链 1272→1272 B 零增
量,own frame 152 不变,handle_conn 200 / post_quiet 40 / post 264 逐函数帧全等 ——
按今天刚定稿的栈判
据,「零增量」这句话必须是表,不能是论证。id-check --strict 0(零新号零裸形)、乱码/嵌套/BOM 净。
台账:`ram_baseline.py --update` 已记当日行(IRAM1 61.9% / CCM 87.9%)。覆盖率基线**留给 L
ead 重建** ——
上一版基线是在 time_sync 套件编译不过的破树下打的,少算了该套件的覆盖。
台账同步:本笔代码改了体积(Code=235268),RAM 预算台账受管区与文档快照区按 12:46 那次权威构建回填(ram_baselin
e --write 加 check_mem_numbers --write)。代码与数字不同笔,就是下一次 mem 钩子假红的来源——上一笔 d
ocs 提交被 mem-numbers 与 mem-budget 双双拦下,正是这个原因。
This commit is contained in:
@@ -49,6 +49,7 @@ BUILD = TestBuild(
|
||||
os.path.join(HERE, "stub"),
|
||||
os.path.join(ROOT, "App", "util"),
|
||||
os.path.join(ROOT, "App", "sync"),
|
||||
os.path.join(ROOT, "App", "log"), # sys_log.h 用真实头(纯 stdint,同 task_watchdog.h 先例)
|
||||
HERE,
|
||||
],
|
||||
summary_marker="=== Time Sync Tests:",
|
||||
|
||||
@@ -57,6 +57,8 @@
|
||||
* TC-TIMESYNC-042 屏障未就绪期间持续喂心跳(2026-10-02 台架根因的回归防线)
|
||||
* TC-TIMESYNC-043 网络代次变化 -> 关闭旧监听并重监听
|
||||
* TC-TIMESYNC-044 监听建立失败 -> 5 次重试后放弃并退避 2000ms
|
||||
* 对时操作留痕(道G task-50,语义行名不配号——编号规范已停发测试用例号):
|
||||
* "sync trace on success" / "… rejected" / "… two in a row" / "… bad magic" 四组
|
||||
*
|
||||
* 通过:全部 TC PASS(main 返回 0)。
|
||||
* 入口:int main(void),返回 0=PASS / 1=FAIL(由 run 脚本判读)。
|
||||
@@ -76,6 +78,7 @@
|
||||
#include "sys_clock.h"
|
||||
#include "sys_events.h"
|
||||
#include "task_watchdog.h" /* 真实头(App/util):task_wd_id_t / TASK_WD_TIMESYNC */
|
||||
#include "sys_log.h" /* 真实头(App/log,纯 stdint 无 OS 依赖):syslog_id_t / SYSLOG_OPER 契约,假件签名与之逐字对齐 */
|
||||
|
||||
/* ===================== FreeRTOS 桩 ===================== */
|
||||
static TickType_t s_tick;
|
||||
@@ -152,11 +155,33 @@ void task_wd_bind(task_wd_id_t id) {
|
||||
/* ===================== sys_clock 桩 ===================== */
|
||||
static int s_set_unix_calls;
|
||||
static uint32_t s_set_unix_last;
|
||||
static int s_set_unix_rc; /* 可脚本化返回值:非 0 = 对时被拒(task-50) */
|
||||
|
||||
int sys_clock_set_unix(uint32_t unix_secs) {
|
||||
s_set_unix_calls++;
|
||||
s_set_unix_last = unix_secs;
|
||||
return 0;
|
||||
return s_set_unix_rc;
|
||||
}
|
||||
|
||||
/* ===================== sys_log 投递桩(task-50) =====================
|
||||
* 假件按投递顺序记录:条数 / 日志 ID / 末条描述 / 对时文案出现次数。
|
||||
* "出现次数"专为钉"连续两次不合并"——若生产侧哪天改成边沿锁存,
|
||||
* 第三条用例会红,而那正是要拦的语义漂移。 */
|
||||
static int s_post_calls;
|
||||
static int s_post_id;
|
||||
static char s_post_last_desc[32];
|
||||
static int s_post_desc_count;
|
||||
|
||||
void syslog_post_quiet(syslog_id_t id, const char *desc) {
|
||||
s_post_calls++;
|
||||
s_post_id = (int)id;
|
||||
if (desc != NULL) {
|
||||
(void)strncpy(s_post_last_desc, desc, sizeof(s_post_last_desc) - 1u);
|
||||
s_post_last_desc[sizeof(s_post_last_desc) - 1u] = '\0';
|
||||
if (strcmp(desc, "clock set by 8888") == 0) {
|
||||
s_post_desc_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ===================== net_socket 桩 ===================== */
|
||||
@@ -349,6 +374,11 @@ static void fakes_reset(void) {
|
||||
|
||||
s_set_unix_calls = 0;
|
||||
s_set_unix_last = 0;
|
||||
s_set_unix_rc = 0;
|
||||
s_post_calls = 0;
|
||||
s_post_id = -1;
|
||||
s_post_last_desc[0] = '\0';
|
||||
s_post_desc_count = 0;
|
||||
|
||||
s_htons_last = 0;
|
||||
s_socket_calls = 0;
|
||||
@@ -716,6 +746,61 @@ static void tc_task(void) {
|
||||
CHECK(s_beat_id_bad == 0, "TC-TIMESYNC-044e every beat sets the TIMESYNC bit");
|
||||
}
|
||||
|
||||
/* ===================== 对时操作留痕四组(道G task-50) =========================
|
||||
* 成功应用投一条 quiet OPER;被拒不投(失败不得记成"改过时钟");
|
||||
* 连续两次各一条不合并;魔术字不符不投。
|
||||
* ⚠ 断言标签用语义行名:编号规范 §9 批次三已对测试用例号停发(用户裁定 2026-10-27),
|
||||
* 本组是新口径下写的——追溯靠函数名 tc_oper_trace + 下面的语义标签。 */
|
||||
static void tc_oper_trace(void) {
|
||||
uint8_t pkt[16];
|
||||
|
||||
/* 1) 对时成功 → 恰一条 OPER */
|
||||
fakes_reset();
|
||||
make_time_packet(pkt, 0x20251027u);
|
||||
recv_set(0, 8, pkt, 8, 0U);
|
||||
s_recv_seq_n = 1;
|
||||
s_set_unix_rc = 0;
|
||||
time_sync_handle_conn(7);
|
||||
CHECK(s_set_unix_calls == 1, "sync trace: clock layer applied once");
|
||||
CHECK(s_post_calls == 1, "sync trace on success: exactly one operation record");
|
||||
CHECK(s_post_id == (int)SYSLOG_OPER, "sync trace: record goes to the operation log");
|
||||
CHECK(strcmp(s_post_last_desc, "clock set by 8888") == 0,
|
||||
"sync trace: wording of the same family as the 104 time-sync record");
|
||||
|
||||
/* 2) 对时被拒(时钟层返非 0)→ 零留痕 */
|
||||
fakes_reset();
|
||||
make_time_packet(pkt, 7u);
|
||||
recv_set(0, 8, pkt, 8, 0U);
|
||||
s_recv_seq_n = 1;
|
||||
s_set_unix_rc = -1;
|
||||
time_sync_handle_conn(7);
|
||||
CHECK(s_set_unix_calls == 1, "sync trace rejected: call still reaches the clock layer once");
|
||||
CHECK(s_post_calls == 0, "sync trace rejected: NO operation record written");
|
||||
|
||||
/* 3) 连续两次成功会话 → 两条独立记录,不合并 */
|
||||
fakes_reset();
|
||||
s_set_unix_rc = 0;
|
||||
make_time_packet(pkt, 100u);
|
||||
recv_set(0, 8, pkt, 8, 0U);
|
||||
recv_set(1, 8, pkt, 8, 0U);
|
||||
s_recv_seq_n = 2;
|
||||
time_sync_handle_conn(7);
|
||||
time_sync_handle_conn(7);
|
||||
CHECK(s_set_unix_calls == 2, "sync trace twice: two applied syncs");
|
||||
CHECK(s_post_calls == 2, "sync trace twice: two independent records, not merged");
|
||||
CHECK(s_post_desc_count == 2, "sync trace twice: both records are the time-sync wording (no coalescing latch)");
|
||||
|
||||
/* 4) 前缀不是 TIME → 时钟层都没到,更不该留痕 */
|
||||
fakes_reset();
|
||||
(void)memset(pkt, 'X', 8);
|
||||
recv_set(0, 8, pkt, 8, 0U);
|
||||
s_recv_seq_n = 1;
|
||||
s_set_unix_rc = 0;
|
||||
time_sync_handle_conn(7);
|
||||
CHECK((s_set_unix_calls == 0) && (s_post_calls == 0),
|
||||
"sync trace bad magic: neither moves the clock nor writes a record");
|
||||
}
|
||||
|
||||
/* ===================== main ===================== */
|
||||
|
||||
int main(void) {
|
||||
@@ -729,6 +814,8 @@ int main(void) {
|
||||
tc_handle_conn();
|
||||
printf("-- time_sync_task (barrier / accept / relisten) --\n");
|
||||
tc_task();
|
||||
printf("-- operation trace on sync (task-50) --\n");
|
||||
tc_oper_trace();
|
||||
|
||||
printf("\n=== Time Sync Tests: %d/%d PASSED (failed=%d) ===\n",
|
||||
s_passed, s_total, s_failed);
|
||||
|
||||
Reference in New Issue
Block a user