9.6 KiB
9.6 KiB
id, title, phase, deps, status, created, vikunja_task_id, context_ref, work_branch, needs_device, needs_human_review, write_paths
| id | title | phase | deps | status | created | vikunja_task_id | context_ref | work_branch | needs_device | needs_human_review | write_paths | |||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| T-400 | 离线单次提交安全编排 | 4 |
|
TODO | 2026-08-04 | 50 | 8600c33 |
task/t-400-offline-submission-orchestrator | false | true |
|
问题 / 背景
T-305 的正常 dry-run 会在同一设备会话完成三闸门与最终控件只读观察,随后执行一次安全 Back,并以固定 reason DRY_RUN_COMPLETED_BEFORE_FENCE 终止 attempt。它只证明围栏前代码和判据契约已验收,绝不产生可供真实提交复用的运行时 ReadyForSubmission。T-308 将提供严格 fence/result sink、当前进程唯一 permit 和不可恢复的点击意图能力。T-400 只用测试 fixture 验证纯 SinglePassSubmissionOrchestrator、四条件、一次性调用和崩溃闭包;不读取或复用 T-305 的对象、截图、证据、journal、缓存或旧 proof,不提供生产 ReadyForSubmission 构造入口,也不接入 app/UI/PDD/真机。
关联需求与交互
- 功能:F-006、F-007、F-011、F-017 的离线提交安全闭包。
- 用户故事:US-003、US-005、US-008。
- 交互:IX-011 的后台顺序;本任务无生产界面。
- 依赖:T-305、T-308。T-305 只提供已验收的代码/判据契约,T-308 提供冻结接口;两者都不向本任务提供可提交的运行时事实。
- 后续消费者:T-401 在全新真实任务、全新 attempt 的同一趟内重跑全部三闸门并即时构造生产 ReadyForSubmission。
- 生产 app 的 import/call graph 在 T-401 前继续不可达本任务编排、ReadyForSubmission 生产构造和 SubmitOrderPort。
方案
- 在单一窄 execution 模块实现纯 SinglePassSubmissionOrchestrator、只读 ReadyForSubmission 协议和抽象 SubmitOrderPort;只消费 T-308 已冻结的 SubmissionSink 接口,不修改 submissions/remote/localstate/core/PDD/UI/app。
- T-305 的 PreFenceDryRunOrchestrator、终止结果、action journal、AssetRef、截图、缓存、页面对象、attempt 或 proof 不能作为 ReadyForSubmission 输入。T-305 已 Back 且终止的 attempt 永远不能申请 fence、取得 permit 或进入提交编排。
- 本任务不提供任何生产 ReadyForSubmission 具体类、公共构造器、factory、adapter 或 from_dry_run/from_snapshot/from_evidence/from_localstate 路径。只有 tests 中的 immutable fixture 实现该只读协议;生产包内不存在把真实或旧事实装配成 ReadyForSubmission 的入口。
- 测试 fixture 必须显式给出一个虚构但内部一致的同一 task/authorization/attempt/generation/App 版本事实:未消费授权快照、Gate2/Gate3 通过、精确规格/数量/金额、三个受控 AssetRef 和提交文本/唯一计数。它只用于纯逻辑测试,不是页面证据或可发布业务事实。
- 编排在申请 fence 前重新校验 fixture 表达的四条件:一次性授权/claim 一致且未过期、Gate2 通过、Gate3 通过、submit 文本精确且唯一计数为一。任一缺失、漂移、金额不规范或版本不一致均零 fence、零 SubmitOrderPort 调用。
- 只有测试注入的 T-308 当前进程首次明确 SubmissionPermit 可继续。先调用 prepare_click_intent durable 写入唯一点击意图并取得一次性 ArmedSubmission;未成功 arm、重放许可、LOOKUP_ONLY、并发进入或重启恢复均零 SubmitOrderPort 调用。
- SubmitOrderPort 只暴露 submit_once(ArmedSubmission, VerifiedSubmitObservationBoundary)。编排层最多调用一次,不提供 retry、循环、回退、第二调用点或可重复 submit 函数;本任务只注入记录次数/故障点的 fake port,没有具体真机适配器。
- 调用前已经进入不可逆 reconcile-only 状态。fake port 返回、抛错、超时、进程停止或结果不明都不能回到可提交状态;异常只形成 UNKNOWN 待调和事实,不再次调用 port。
- fake port observation 只允许 SUBMITTED、EXTERNAL_PAYMENT_HANDOFF、SECURITY_CHALLENGE、UNKNOWN。编排通过 T-308 固定接口只上报一次 result;HTTP 不明只恢复原 key/载荷,不重复页面观察或提交动作。本任务不实现或测试任何基于真实页面的 SUBMITTED 推断。
- 停止轮询、Esc、查看历史、关闭窗口和重启不是编排的取消/重试输入;它们不能清 permit、点击意图、submission 或 result pending,也不能释放、重新授权、重新领取或推进下一任务。
- T-401 前生产 composition/import/call graph 必须同时证明:不可达 SinglePassSubmissionOrchestrator/SubmitOrderPort;不存在生产 ReadyForSubmission factory;T-305 dry-run 结果类型不可流入提交编排。
验收要点
- 参数化负例逐一移除授权/首次许可、Gate2、Gate3 或唯一控件,证明 fake SubmitOrderPort 调用数均为 0。
- 首次明确 permit + durable 点击意图的纯测试用例证明 fake port 调用数恰好为 1;并发、二次进入、permit 重放和重复 result 均不能增加计数。
- fake port 在调用中或返回解析时抛错/超时,结果均为 reconcile-only/UNKNOWN,调用数仍恰好为 1 且无 retry。
- 崩溃点覆盖 fence 响应前后、permit 落盘前后、点击意图前后、fake port 调用前后和 result 上报前后;恢复全部零 SubmitOrderPort 调用。
- 固定测试至少包含 test_missing_each_submission_condition_never_calls_port、test_first_permit_calls_port_exactly_once、test_port_exception_never_retries、test_restart_after_click_intent_is_reconcile_only、test_t305_runtime_artifacts_are_not_accepted、test_no_production_ready_for_submission_factory、test_production_app_import_closure_cannot_reach_submission。
- AST/import/call-graph 证明生产代码不存在 ReadyForSubmission 构造入口,T-305 已终止结果/截图/缓存/proof 到编排无数据流,app/UI/PDD/device/真实 click/payment 不在本任务闭包。
- 任务 diff 只能修改窄 execution 实现/测试;T-308 submissions/remote/localstate/core 接口保持冻结且零 diff。
- client 全量 unittest、compileall、wheel metadata、完整 init、上下文、Vikunja export 与 diff-check 通过。
- needs_human_review:人工审阅 T-305 零运行时复用、生产 factory 不存在、一次性 fake port 调用和全部崩溃点;确认前不得标 DONE。
执行记录
(暂无)
边界
- T-305 正常 dry-run 已执行一次安全 Back,并以
DRY_RUN_COMPLETED_BEFORE_FENCE终止 attempt。 本任务只能复用其已验收的代码/判据契约;不得接收或复用该次/任何 dry-run 的结果对象、attempt、 screenshot、AssetRef、action journal、缓存、页面对象、本地快照或旧 proof 来申请围栏或提交。 - 本任务只在单一窄 execution 文件实现纯
SinglePassSubmissionOrchestrator、只读ReadyForSubmission协议和抽象SubmitOrderPort;仅测试 fixture 可实现/构造该协议。生产代码 不得存在具体ReadyForSubmission类、公共构造器、factory、adapter、反序列化或from_dry_run/from_snapshot/from_evidence/from_localstate路径。 - 本任务只消费 T-308 已冻结接口,不得修改
submissions/**、remote/**、localstate/**或core/**。不得修改或导入app.py、ui/**、pdd/**、device/**,不得连接真机、使用 uiautomator2 或实现任何具体页面点击适配器。 - 测试 fixture 表达的四条件必须属于同一虚构 task/authorization/attempt/generation 和 App 版本:
未消费授权与首次明确围栏许可、Gate2、Gate3、精确唯一提交控件。它只验证纯逻辑,不是可复用的
页面或业务事实;缺失、漂移、金额/规格/数量冲突均零 fake
SubmitOrderPort调用。 - 编排必须先通过 T-308 durable 写入唯一点击意图,再把当前进程的一次性
ArmedSubmission交给 fakeSubmitOrderPort.submit_once()。该方法在纯测试生命周期最多调用一次;不得存在 retry、循环、 fallback、第二调用点或异常后重新进入路径。 - 点击意图落盘后即进入
RECONCILE_ONLY。fake port 返回、抛错、超时、停止、关闭或进程崩溃都不得 回到可提交状态;结果不明确只能形成UNKNOWN并调和同一 submission,不能再次调用 port、重新 申请许可、释放围栏、重新授权或重新领取。 - 本任务不实现真实页面结果判据。fake fixture/port 的
SUBMITTED只用于协议分支测试,不能成为 生产页面事实;不得从 cmroubao/cmpdd、旧版本、页面语义或人工经验推断真实SUBMITTED。 - T-401 前 production composition/import/call graph 必须同时不可达本任务编排/
SubmitOrderPort, 不存在生产ReadyForSubmission构造入口,并证明 T-305 终止结果到提交编排无数据流。应用启动、 Esc、停止轮询、查看历史和关闭窗口均保持零提交调用。 - T-401 才能领取一条全新已授权真实任务,在新的同一趟 attempt 中重新执行全部实时闸门并即时构造
生产
ReadyForSubmission。本任务不提供人工提交入口,不编写支付、免密支付、先用后付或扣款能力。 needs_human_review: true:自动验证后仍保持DOING,等待人审 T-305 零运行时复用、生产 factory 不存在、一次性 fake port 调用和全部崩溃点;未经明确确认不得标DONE。