OnecardDemo 用户全量同步分阶段耗时日志实施计划
For agentic workers: REQUIRED SUB-SKILL: Use executing-plans to implement this plan task-by-task. Steps use checkbox (
- [ ]) syntax for tracking.
Goal: 为用户全量同步记录总数请求、每批网络请求、XML解析、SQLite保存、单批总计和整轮总计耗时,写入现有本地日志且不修改数据库结构。
Architecture: CustomerSyncService 使用可注入的单调时间源和 SyncLogger 生成结构化 CUSTOMER_SYNC_* 事件;生产适配器转发到现有 ReaderLog,测试适配器收集事件。ServerOperationsActivity 只负责初始化日志,页面和 SQLite schema 保持不变。
Tech Stack: Java 8、JUnit 4、AndroidX Test、现有 ReaderLog/ReaderLogStore、Gradle
Task 1:同步计时与日志契约
Files:
Create:
/Users/liang/AndroidStudioProjects/OnecardDemo/app/src/main/java/com/cpt/onecarddemo/customer/SyncLogger.javaModify:
/Users/liang/AndroidStudioProjects/OnecardDemo/app/src/main/java/com/cpt/onecarddemo/customer/CustomerSyncService.javaModify:
/Users/liang/AndroidStudioProjects/OnecardDemo/app/src/test/java/com/cpt/onecarddemo/customer/CustomerSyncServiceTest.javaStep 1:编写成功流程 RED 测试
在 CustomerSyncServiceTest 增加每次 nanoTime() 前进1毫秒的可控时间源和内存 SyncLogger。两批成功同步后断言:
CUSTOMER_SYNC_START
CUSTOMER_SYNC_COUNT_SUCCESS requestMs=1
CUSTOMER_SYNC_BATCH_START batch=1
CUSTOMER_SYNC_REQUEST_SUCCESS batch=1 requestMs=1 responseBytes>0
CUSTOMER_SYNC_PARSE_SUCCESS batch=1 records=2 parseMs=1
CUSTOMER_SYNC_SAVE_SUCCESS batch=1 saveMs=1 batchMs=7
...第二批同序列...
CUSTOMER_SYNC_SUCCESS elapsedMs>=0
- Step 2:运行测试确认 RED
Run: ./gradlew testDebugUnitTest --tests com.cpt.onecarddemo.customer.CustomerSyncServiceTest
Expected: 编译失败,提示 SyncLogger 或新构造器不存在。
- Step 3:定义日志接口和可测试时间源
新增:
public interface SyncLogger {
void info(String event, String details);
void error(String event, String details, Throwable throwable);
}
把 CustomerSyncService.TimeSource 明确为同时提供 currentTimeMillis() 和 nanoTime();系统实现分别使用 System.currentTimeMillis()、System.nanoTime()。
- Step 4:实现成功流程阶段计时
在不改变原分页、解析、保存顺序的前提下记录:同步开始、总数请求、每批开始、请求成功、解析成功、保存成功和同步成功。responseBytes 使用 response.getRawXml().getBytes(StandardCharsets.UTF_8).length,只记录长度。
日志调用必须通过 safeInfo/safeError 包装并吞掉日志器自身异常,保证日志故障不改变同步结果。
- Step 5:编写失败阶段 RED 测试
分别让总数请求、分页请求、XML解析、仓库保存和完成清理失败,断言唯一的 CUSTOMER_SYNC_FAILURE 包含正确的 stage=count/request/parse/save/complete、当前批次、已保存数、stageMs 和总 elapsedMs;原有“前批保留、失败标记、不调用完成”断言继续成立。
- Step 6:实现失败日志并确认 GREEN
用当前阶段变量和阶段开始的单调时间统一生成失败事件;异常消息不附加 SOAP 原文或任何用户字段值。
Run: ./gradlew testDebugUnitTest --tests com.cpt.onecarddemo.customer.CustomerSyncServiceTest
Expected: BUILD SUCCESSFUL,所有同步测试通过。
Task 2:接入现有本地日志
Files:
Create:
/Users/liang/AndroidStudioProjects/OnecardDemo/app/src/main/java/com/cpt/onecarddemo/customer/ReaderLogSyncLogger.javaModify:
/Users/liang/AndroidStudioProjects/OnecardDemo/app/src/main/java/com/cpt/onecarddemo/customer/CustomerSyncService.javaModify:
/Users/liang/AndroidStudioProjects/OnecardDemo/app/src/main/java/com/cpt/onecarddemo/ServerOperationsActivity.javaModify:
/Users/liang/AndroidStudioProjects/OnecardDemo/app/src/androidTest/java/com/cpt/onecarddemo/ServerOperationsUiTest.javaStep 1:编写生产接入 RED 测试
页面测试直接启动 ServerOperationsActivity 后断言 ReaderLog.getLogDirectory() 非空且目录名为 reader_logs,证明不依赖先进入主页面。
- Step 2:运行页面测试确认 RED
Run: ./gradlew connectedDebugAndroidTest -Pandroid.testInstrumentationRunnerArguments.class=com.cpt.onecarddemo.ServerOperationsUiTest
Expected: 新用例失败,因为服务器页面尚未初始化 ReaderLog。
- Step 3:实现生产日志适配器
ReaderLogSyncLogger.info/error 分别委托 ReaderLog.info/error。CustomerSyncService 公共构造器使用该适配器;包内测试构造器继续允许注入 fake logger。
- Step 4:初始化日志并确认 GREEN
在 ServerOperationsActivity.onCreate() 创建同步服务之前调用 ReaderLog.initialize(this),不增加控件、不修改按钮启用条件。
Run: ./gradlew connectedDebugAndroidTest -Pandroid.testInstrumentationRunnerArguments.class=com.cpt.onecarddemo.ServerOperationsUiTest
Expected: 页面测试全部通过。
Task 3:文档、完整验证和安装
Files:
Modify:
/Users/liang/AndroidStudioProjects/zhct/zhctprompt/work_android/OnecardDemo/designs/2026-08-24-用户全量同步分阶段耗时日志设计.mdModify:
/Users/liang/AndroidStudioProjects/zhct/zhctprompt/work_android/OnecardDemo/protocols/Change单点功能与字段说明.mdModify:
/Users/liang/AndroidStudioProjects/zhct/zhctprompt/work_android/OnecardDemo/change_records/CHANGELOG.mdRegenerate: 上述文档和本计划的同名
.htmlStep 1:同步文档口径
把设计状态改为“已实施,待现场全量同步验证”;协议文档记录所有事件、字段、日志目录、保留规则和敏感信息边界;变更记录写明 RED/GREEN、测试数量、构建、Lint、真机和安装结果。
- Step 2:运行完整自动验证
Run: ./gradlew testDebugUnitTest assembleDebug assembleDebugAndroidTest lintDebug --rerun-tasks
Expected: BUILD SUCCESSFUL,JVM 测试0 failure、0 error,Lint 0 error。
- Step 3:运行本次相关真机测试
Run: ./gradlew connectedDebugAndroidTest -Pandroid.testInstrumentationRunnerArguments.class=com.cpt.onecarddemo.customer.SQLiteCustomerRepositoryTest,com.cpt.onecarddemo.ServerOperationsUiTest
Expected: 本次相关测试0 failure。
- Step 4:安装最终 APK
Run: adb install -r app/build/outputs/apk/debug/app-debug.apk
Expected: Success。
- Step 5:现场验收
用户执行一次全量同步,在“查看读卡日志”中搜索 CUSTOMER_SYNC_,确认每批耗时字段存在且非负;此步骤不由自动构建主动触发。
执行约束
- 当前会话内联执行,不调度子代理。
- 不修改
onecard.db数据库版本、表或字段。 - 不新增页面控件,不改变同步分页和失败停止语义。
- 不记录 SOAP 原文、姓名、卡号、证件号、密码或其他用户字段值。
- 不执行 Git 暂存、提交、推送、切分支或其他 Git 写操作。