14 KiB
14 KiB
财务后台定位与主导航减法:执行计划
0. 规划与启动门禁
- 用户批准创建 task 并进入规划。
- 核验最初四个候选导航项、flag key、batch transaction、后端副作用和生产普查证据。
- 明确本轮只有“定位固化 + 三个固定 flag 关闭”;原条件目标
project_domain_v1已因本地准入失败排除,二级入口不实施。 - 用户只读复核
prd.md、design.md、implement.md并明确批准启动;已运行task.py start。
1. 本地定位固化(启动批准后)
- 更新
docs/产品口径.md:将 A/B 未决门替换为“范围收缩为财务/台账后台,核心 OA 主办流程要求真实使用”。 - 对齐 P0-1/P0-3/P0-10 中 OA 主办域,明确项目主域当前冻结候选,合同/采购/资产仍为低频台账。
- 更新
project-governance.md的 Adoption Mode decision,禁止按失效 R63–R66 排期继续扩建。 - 只纠正当前活跃任务中会把执行带回 R63–R66 的前向说明;未批量改归档历史。
git diff --name-only断言没有client/src、server/src、scripts、migration、依赖或部署配置;不新增执行脚本。
2. 本地验证与生产审批停点
- 启动本地服务并复用两张本地草稿;一张保持未关联,另一张仅在验证窗口内临时关联现有合成项目;记录 flag on 基线。
- 本地临时
force_off project_domain_v1,用真实浏览器验证页面、控件、错误提示、已关联项目名称/编号和/api/projects网络响应。 - 恢复本地 flag 完整 snapshot 并复核;准入失败,生产 target 固定为 3,
project_domain_v1不进入本轮生产写入。 python3 ./.trellis/scripts/task.py validate 08-11-internal-oa-finance-backoffice-positioning-and-navigation-reductionnode scripts/qa/check-trellis-governance.mjsnode scripts/qa/check-process-contract.mjs --baseline --jsonnode scripts/qa/audit-docs.mjs --check-registry(退出 0;保留基线 warning:22 个未登记 docs 文件,本轮未新增 docs 文件)- 敏感扫描与
git diff --checkPASS。 - 形成生产批准包:PRE、三个固定 target、完整副作用、一次 batch、APPLY_UNCERTAIN、可选一次回滚;已在用户批准前停止。
2.1 本地真实浏览器证据(2026-08-11)
- 环境:本地 PostgreSQL、真实 Fastify/Vite、仓库已安装的 Playwright Chromium;无
page.route、无组件 mock、无产品代码或测试代码改动。Playwright CLI 因系统 Chrome 通道缺失且 CLI Firefox 构建不支持当前环境而未能启动,故只在浏览器驱动层回退到仓库 Playwright,验证对象和网络路径不变。 - 合成样本:本地原有 1 个项目;从原有草稿中取 2 张,一张保持
project_id=null,另一张临时关联该项目。窗口前后全库已关联报销数均为 0。 - 开启基线:两张详情的
/api/projects均为 200;未关联控件有“不关联项目 + 现有项目”两项,已关联控件选中现有项目,项目名称和编号显示一致。 - 关闭观察:两张详情的
/api/projects均为 409;页面无红色可见错误,但未关联控件仍启用且只剩“不关联项目”,没有“项目能力已关闭/不可用”的解释;已关联详情的事实卡仍显示原项目名称和编号,控件却丢失该项目选项并回落到“不关联项目”。这会把“关联事实仍存在”呈现成“当前未关联”,不满足明确且不误导的准入合同。 - 请求边界:关闭阶段自动出现 2 次
POST /api/reimbursements/:id/precheck,代码和现场均确认它是只读预检;其他业务 mutation 为 0。 - 恢复:flag 的 override/rollout/departments/note/version/创建与更新时间/更新人 snapshot 精确一致;已关联报销数恢复为 0;专用本地浏览器 session 已删除。本地第一次恢复尝试曾把 JSON
[]通过 raw 参数写成{},门禁立即识别并恢复为原数组;最终有效 witness 的恢复路径只改override_mode,完整 snapshot PASS。 - 判定:
project_domain_v1不通过本地准入,不得进入生产 batch。最终生产目标恰好为announcements_v1、todo_board_v1、weekly_report_v1。
3. 生产 PRE(需单独批准)
- 只读确认 trialrun identity、运行 SHA、migration 和当前产品差异;不因本地文档提交领先误报运行漂移。
- 复用既有只读普查能力严格一次确认三个最终 target 模块仍为零数据/零真人活动;任一非零即 PAUSED。
- 管理员登录一次,只读保存三个最终 target 的 override/rollout/departments/note/version/effective snapshot 和审计基线;不输出账号或凭据。
- GET 三项 impact,确认副作用与批准合同一致。
- 断言
project_linking_v1与合同、采购、资产相关配置不在目标集合。
3.1 生产 PRE 证据(2026-08-12)
- 身份与运行:唯一 trialrun 身份 PASS;既有部署聚合体检
PASS=13 FAIL=0;运行候选与origin/main已部署提交一致,当前本地领先的 8 个提交在client/src、server/src和部署 compose 上零差异。数据库三方身份 PASS,migrationpending=none,回滚窗口OPEN / terminatedRows=0 / basis=terminated_status_count。 - preflight 执行边界:第一次 detached 临时 worktree 在 provenance 阶段因无 upstream 被拒,尚未进入迁移查询;随后使用跟踪
origin/main的 clean 临时分支完成唯一有效 preflight。临时 worktree/branch 已删除。 - 使用度:复用已审查的只读事务查询器,通过 stdin 送入运行容器且不落盘;公告、普通待办、周报
totalRows=0,30/90 天真人 actor/event 与真人审计 actor/event 均为 0,queryStatus=PASS,effectiveQueryExecutions=1、zeroRetry=true。第一次本地路径拦截发生在 stdin 重定向前,远端查询执行数为 0。 - 管理员只读 API:一次登录、零 retry;三项均为
overrideMode=force_on、rolloutType=global、departmentIds=[]、version=47、envEnabled=true、effectiveEnabled=true、effectiveReason=flag_force_on_global。三项现有 note 均非空且 SHA-256 相同;未保存或输出 note 原文。正常 logout 已用于撤销本次 session。 - 导航与影响:公告
/announcements、普通待办/todos、周报/weekly-reports当前均存在。公告 impact 为公告 API 与 Portal;普通待办 impact 为 todos API、Portal、搜索;周报 impact 为 weekly-reports API、Portal、搜索。公告是“关闭”而非仅隐藏:flag off 后公告 API(含写接口)硬拒,临时发公告前必须先重新开启;Portal/搜索消费者按条件省略,不构成项目 flag 的跨域矛盾。 - 审计基线:全局
FEATURE_FLAG_UPDATED total=1;三项目标 changelog total 均为 0。源码确认 batch 事务对每个 target 各写 1 条FEATURE_FLAG_UPDATED,没有独立 batch 审计;因此预期写后为全局auditDelta=3、三项 changelog 各+1、batch responsecount=3,不得按 4 条判断。 - 最终写入输入:目标恰好为
announcements_v1@47、todo_board_v1@47、weekly_report_v1@47;project_domain_v1、project_linking_v1及其他 flag 不在集合。生产 batch 尚未批准、尚未执行。
4. 生产 APPLY(需单独批准)
- 使用既有 batch API 选择恰好三个固定目标;写前重新确认三项均为
force_on/global/version=47/effective=true,审计与回滚窗口基线未漂移。 - 一次前向 batch 将三项设为
force_off,responsecount=3;单项 PUT=0、workspace PATCH=0、其他业务 mutation=0。 - 执行器随后因只监听页面网络、没有监听同一 browser context 的
APIRequestContext,把已成功的 batch 误计为 0;该本地 witness 缺陷触发了用户预授权的最多一次恢复 batch。恢复 responsecount=3,没有重试前向 batch。 - 请求通道和 JSON 响应始终明确,没有进入
APPLY_UNCERTAIN;实际配置 mutation 精确为一次前向 batch + 一次预授权恢复 batch。
4.1 生产写入与恢复证据(2026-08-12)
- 写前现场锁:三个目标仍为
force_on/global/departmentIds=[]/version=47/effective=true;全局FEATURE_FLAG_UPDATED total=1、各目标 changelog0,回滚窗口OPEN/0。 - 前向写入:batch HTTP 成功且
count=3,三项实际进入force_off@48。执行器的页面级 request listener 没有观察到context.request.fetch,本地计数断言错误报forward_batch_count_0;这不是服务器拒绝或通道不确定。 - 预授权恢复:失败分支只读确认三项确已统一进入
force_off@48后,严格一次 batch 恢复force_on,responsecount=3;终态三项均为force_on/global/departmentIds=[]/version=49/effective=true/reason=flag_force_on_global。 - 独立交叉验证:全局 feature-flag 审计从
1到7,增量6;三个目标 changelog 均从0到2,各增量2,精确对应一次前向和一次恢复。公告、普通待办、周报及项目导航均已恢复,Portal 只读为 200,回滚窗口仍为OPEN / terminatedRows=0 / basis=terminated_status_count。 - 边界与清理:没有单项 PUT、workspace PATCH、其他 flag 或业务数据写入;没有第二次前向 batch。CLI wrapper 权限位、系统 Chrome 缺失、一次缺设备指纹的 400 和一次导航响应形状误判均发生在配置写入之外;最终有效只读核验正常 logout,浏览器/API context 和 token 均销毁。导航响应形状误判的只读核验在 logout 前退出,留下 1 个无人持有的服务端 session;本任务不追加未批准的认证状态写入,记录为自然过期残留。
- 结论:生产安全回到 PRE 功能状态,但“关闭三项并保持关闭”的业务目标未达成。原
expectedVersion=47已消耗,任何后续前向写入必须以现场version=49重新规划并再次获得明确批准,不能沿用本次批准。
5. POST 与回滚判断
- 最终 target 均
force_off/effective=false/reason=flag_force_off,version 各 +1;本次因预授权恢复而未达到该终态。 - 单次前向落地的审计增量恰好为 3、各 target +1;本次最终审计包含前向与恢复,实际为全局 +6、各 target +2。
- 导航所有 section 不含公告、普通待办、周报入口;本次恢复后这些入口按 PRE 状态重新出现。
- 三个最终 target 直达 GET 返回可解释 disabled;本次在进入完整 disabled/Portal witness 前被执行器计数断言中止并恢复,未形成可接受的保持关闭 POST 证据。
- 恢复终态下其他 flag、
project_linking_v1、导航、Portal 和回滚窗口保持 PRE 可用状态;业务 mutation 为 0。 - 只执行用户预授权的最多一次恢复 batch;恢复后停止,没有重试前向写入。
6. 收口
- 更新 task 证据,明确产品代码零改动、部署 0、最终 target=3、batch 次数、审计增量、项目本地准入失败和二级入口延后。
- 重跑 task/governance/process/docs/sensitive/diff 门禁。
- 中文 commit 引用 task 名;不自动推送。
- 用户审查后归档,不创建二级入口或退役子 task。
7. 恢复后再次准入(任何新生产批准之前)
- 新增纯本地
feature-flag-apply-uncertainty.mjs:真实发送次数在sendMutation包装层计数,page.on("request")只作为可选辅助观察;响应和服务端 readback 分开记录,高层入口固定“发送至多一次 → 只读定性”,没有 rollback 回调入口。 - 本地覆盖“batch 成功但页面观察为 0”:readback 为 POST 时返回
CONTINUE_POST,发送次数=1、前向重试=0、rollback=0。 - 本地覆盖响应缺失但 GET 为 POST、响应缺失但 GET 为 PRE、GET 失败、部分状态;分别得到
CONTINUE_POST、STOP_NOT_APPLIED、STOP_UNKNOWN、STOP_FOR_MANUAL_DECISION。部分状态不自动继续或恢复,必须停止并申请人工决策。 node --check scripts/qa/feature-flag-apply-uncertainty.mjsPASS;focused Vitest5/5PASS。npm run prisma:validatePASS。完整 server Vitest 发现既有付款单导出用例 1 条稳定失败(期望 200、实际 409);在干净HEAD临时 worktree 中单独运行同一标题仍失败,证明不是本次 QA 状态机/测试引入。本任务不修改付款业务代码,focused 状态机用例保持 5/5 PASS。- 重新执行生产 PRE,以现场
version=49(或届时新值)冻结三项目标和审计基线;不得沿用version=47。 - 形成新的生产批准包并等待明确批准;本次一次前向与一次恢复的批准均已消耗。
风险与停止条件
- 三个最终 flag 不是纯导航开关;若影响合同/采购/资产/报销页面整体可用性,停止并按已批准边界决定回滚。
- 现场出现任何业务数据或真人活动:停止,不关闭对应模块。
- 目标、version、运行身份或结果不确定:停止,禁止盲重试。
- 发现需要产品代码才能完成:返回规划并重新批准;不得把阶段二偷渡进本轮。
Residual Register
OPEN / OUT_OF_SCOPE:付款批次 BIFF8 导出单测“exports a reviewed CCB batch as BIFF8 and records the first export”稳定得到 409、预期 200;完整 server suite 与干净HEAD临时 worktree 的单标题复现结果一致,证明不是本任务 QA 状态机改动引入。后续应独立定性运行依赖、模板门禁或产品行为,不得长期把该红灯当作可忽略背景噪音;本任务不修改付款业务代码或测试断言。