From 099f58cf3b623a129223f41d6c81abf94f238588 Mon Sep 17 00:00:00 2001 From: shunli Date: Sun, 9 Aug 2026 10:46:51 +0800 Subject: [PATCH] =?UTF-8?q?=E8=AE=B0=E5=BD=95(08-08-production-authenticat?= =?UTF-8?q?ed-readiness):=20=E6=94=B6=E5=8F=A3=E7=94=9F=E4=BA=A7=E7=99=BB?= =?UTF-8?q?=E5=BD=95=E6=80=81=E9=83=A8=E5=88=86=E9=AA=8C=E6=94=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .trellis/spec/hyb-oa/deployment-trialrun.md | 109 ++++++++++++++++++ .../implement.md | 26 +++-- .../prd.md | 12 +- 3 files changed, 131 insertions(+), 16 deletions(-) diff --git a/.trellis/spec/hyb-oa/deployment-trialrun.md b/.trellis/spec/hyb-oa/deployment-trialrun.md index a65f7ad4..4c0aae99 100644 --- a/.trellis/spec/hyb-oa/deployment-trialrun.md +++ b/.trellis/spec/hyb-oa/deployment-trialrun.md @@ -1989,3 +1989,112 @@ capture audit baseline -> require baseline + 1 atomic rename -> compare identifier/password in-process -> login once -> change password once -> final verify -> destroy temporary material ``` + +## Scenario: Zero-Retry Production Authenticated Readiness + +### 1. Scope / Trigger + +- Trigger: a separately approved production-readiness task uses one real login + attempt to inspect an already deployed feature without business writes. +- Purpose: preserve the only authentication attempt and produce a precise safe + result when production data does not contain the samples needed by the UI + assertions. + +### 2. Signatures + +- Browser execution contract: `workers=1`, `retries=0`, one login submission + per approved role. +- Product status-label source: + `features/contractsRegistry/presentation.ts` (or the current shared mapping + imported by the production page under test). +- Required evidence fields: `stage`, `loginAttempts`, `loginHttpStatus`, + `sampleCategory`, `sampleCount`, `businessMutationCount`, and the relevant + endpoint-specific request count such as `terminatePostCount`. + +### 3. Contracts + +- Define fine-grained safe stages before execution, including authentication, + route reachability, list loading, sample selection, detail loading and each + optional state-specific assertion. A single catch-all "browser failed" stage + is not acceptable evidence for a zero-retry run. +- UI labels and state words must come from the current product source or shared + presentation mapping. Do not retype remembered Chinese labels in the runner; + a stale label can consume the only login while testing an assertion that is + not part of the deployed product contract. +- Query or observe the available sample categories without creating data. + Report each missing category and count independently. Missing `active`, + `archived` or `terminated` data makes only its dependent assertions + `PAUSED`; it is not an authentication failure and does not authorize a retry. +- Install network mutation counters before navigation. A stopped run may claim + safety only from explicit counts such as `terminatePostCount=0` and + `businessMutationCount=0`, not from the fact that a detail page was never + reached. +- Record authentication side effects separately from prohibited business + writes. A successful login normally creates a session and login audit; do not + summarize that run as "production writes = 0". If logout is not reached, + record the residual session and follow the approved session-lifecycle policy + rather than revoking it directly without authority. +- Recheck any state-based rollback window before and after the browser run. + Missing samples and a still-open window remain independent facts. + +### 4. Validation & Error Matrix + +- Login fails once -> stop with the authentication stage and re-read lock/failure + state; no second login. +- Login succeeds but the required sample count is zero -> authentication PASS, + sample-dependent UI checks `PAUSED`, mutation counters must remain zero. +- Runner label differs from the current shared product mapping -> runner + contract defect; stop without relabeling the product and do not rerun the + consumed login solely to repair evidence. +- Mutation counter is missing or positive -> no safe read-only claim; classify + the exact endpoint/stage and stop. +- Browser exits before logout after a successful login -> record the new session + as an authentication side effect; do not conceal it or revoke it by an + unapproved database write. +- Rollback window closes while the runner sent no relevant mutation -> record a + concurrent real-user event and switch to the approved roll-forward policy. + +### 5. Good/Base/Bad Cases + +- Good: one login returns 200, the contract table is empty, the runner reports + `sampleCategory=contracts`, `sampleCount=0`, all mutation counters are zero, + and detail/termination assertions remain explicitly `PAUSED`. +- Base: suitable existing samples are present, so the runner checks only the + approved read-only UI stages and exits with zero business mutations. +- Bad: hard-code a remembered label, fail at list selection, then report only + "browser failed" and spend a second login to discover that production had no + sample. +- Bad: say "no production writes" after a successful login created a session + and audit row. + +### 6. Tests Required + +- Before a live run, statically compare every runner-owned status label with the + current shared presentation mapping, or import that mapping directly. +- Exercise a local zero-sample fixture and assert it emits the independent safe + category/count, preserves authentication PASS and marks only dependent UI + checks `PAUSED`. +- Assert `workers=1`, `retries=0`, login submission count at most one per role, + and mutation listeners installed before the first application navigation. +- Evidence review must reconcile login attempts with session/audit changes and + reconcile every unexecuted UI assertion with its sample count and stage. +- Production execution still requires explicit approval, pre/post rollback + window snapshots, sensitive-content scanning and a read-only reviewer. + +### 7. Wrong vs Correct + +#### Wrong + +```text +remembered UI label -> one broad browser stage -> sample lookup fails +-> retry login -> report "no production writes" +``` + +#### Correct + +```text +current shared mapping -> fine-grained stages + mutation listeners +-> login once -> classify sample categories/counts +-> zero sample means dependent checks PAUSED, not auth failure +-> reconcile session/audit side effects -> post-window snapshot +``` diff --git a/.trellis/tasks/08-08-production-authenticated-readiness/implement.md b/.trellis/tasks/08-08-production-authenticated-readiness/implement.md index 6ed4c377..14d53b73 100644 --- a/.trellis/tasks/08-08-production-authenticated-readiness/implement.md +++ b/.trellis/tasks/08-08-production-authenticated-readiness/implement.md @@ -60,27 +60,31 @@ ### Phase C:有限登录(仅凭据合法恢复后) - [x] 管理员凭据来源已切换:来自已归档 `08-09-production-admin-break-glass-reset` 的受控 break-glass 恢复和首次强制改密,不是本任务最初诊断为失效的原始 secret;值不进入任务证据。 -- [ ] READY:admin 仓库外最终凭据已经应用登录和 `--verify-password-changed` 双重验证,本轮仍只允许一次登录、零 retry。 +- [x] admin 只执行一次登录、零 retry,HTTP 200 并进入 `/portal`;写后只读复核为 failureCount=0、locked=false、近 15 分钟 login success=1、login failure=0。 - [ ] PAUSED:employee 目标账号不唯一,现有验收密码不匹配任何活跃非管理员候选;本轮不选择、重置或修改员工账号。 -- [ ] PAUSED:admin 未登录,attempts=0。 +- [x] admin attempts=1;未发生第二次登录。浏览器在合同台账阶段 fail-closed 后关闭,未到达正常 logout;active sessions 从恢复后的 1 变为 2,新增会话留待自然过期,本任务未获直接数据库撤销授权。 - [ ] PAUSED:employee 未登录,attempts=0。 -- [x] 已记录每角色 attempts=0;没有第二次尝试,也没有增加失败计数。 +- [x] 已记录 admin attempts=1、employee attempts=0;没有第二次尝试,管理员失败计数仍为 0 且未锁定。 ### Phase D:登录态只读验收 -- [ ] PAUSED:管理员会话未建立,未进入合同台账或详情。 -- [ ] PAUSED:未进入终止面板;未填写原因、未打开确认层、terminate POST=0。 +- [ ] PARTIAL:admin 登录成功;浏览器进入合同台账阶段后因无可用合同样本停止,未进入详情。生产数据库只读计数确认合同总数为 0,active/expired/draft/archived/terminated 均为 0。 +- [ ] PAUSED:无 active/expired 样本,无法进入终止面板;未填写原因、未打开确认层、terminate POST=0、全部合同 mutation request=0。 - [ ] PAUSED:员工会话未建立,未执行权限负向路径;未扩大权限或删除断言。 -- [ ] PAUSED:未在无登录态情况下探查 archived 样本,未创建数据。 -- [ ] PAUSED:PRE/POST 均证明 terminatedRows=0,因此无现有 terminated 样本可验;未制造样本。 +- [ ] PAUSED:archived 样本数为 0,无法验证字段锁定;未创建数据。 +- [ ] PAUSED:terminated 样本数为 0,无法验证“已终止”标签与终止事实区;未制造样本。 ### Phase E:窗口复核与收口 - [x] 首次账号分流、扩展账号诊断、邮件能力诊断后均查询 POST;连同初始 PRE 共四次,均为 `terminatedRows=0`、`rollbackWindow=OPEN`、`basis=terminated_status_count`。 - [x] 四次窗口证据均为 OPEN/0,未发现同期真实用户关闭窗口。 -- [x] 汇总:登录 attempts=0、terminate POST=0、生产账号/权限/合同/schema 写入=0。 -- [x] 扩展诊断只读 reviewer 首轮 `PASS_WITH_FINDINGS` 要求收窄员工密码与 UI PAUSED 措辞,修订后最终复查为 `PASS`;reviewer 未修改代码或生产状态。 -- [ ] 按实际证据更新 PRD AC;不得把缺失样本或凭据阻塞勾成通过。 +- [x] 凭据恢复后的管理员验收 PRE/POST 再次均为 `terminatedRows=0`、`rollbackWindow=OPEN`、`basis=terminated_status_count`;本任务累计六次快照均 OPEN/0。 +- [x] 本轮浏览器 admin login=1/200;terminate POST=0、合同 mutation=0。runner 的状态词基线曾写成“已到期”而产品映射为“已过期”,但生产合同总数为 0,状态循环未执行,该观察不是本轮停止原因;依零 retry 合同未重跑。 +- [x] 汇总:admin attempts=1、employee attempts=0;terminate POST=0、合同 mutation=0;未执行账号修复、权限、合同或 schema 写入。成功登录按产品合同创建 1 个新 session 并写登录审计,浏览器未到达 logout。 +- [x] 扩展诊断只读 reviewer 首轮 `PASS_WITH_FINDINGS` 要求收窄员工密码与 UI PAUSED 措辞,修订后最终复查为 `PASS`;浏览器验收收口复核另发现旧汇总把成功登录副作用误写成“写入 0”,修正为 admin attempts=1、session 1→2 与登录审计后,最终复核为 `PASS`。reviewer 未修改文件、代码或生产状态。 +- [x] 已按实际证据更新 PRD AC;管理员认证记为通过,员工与无样本 UI 分支保持 `PARTIAL/PAUSED`,未把缺失样本勾成通过。 +- [x] 已按 `trellis-update-spec` 将零 retry runner 的细粒度阶段、状态词源码基线、无样本独立分类和登录副作用对账写入现有 `.trellis/spec/hyb-oa/deployment-trialrun.md`,未新建规约文件。 +- [x] 已为合同 UI `PAUSED` 写死事件触发条件:生产出现首条 `contract_registry` 记录后启动只读补验,不按日期等待、不制造样本,也不把记录出现视为终止授权。仓库事实源显示合同台账原已纳入首批真实使用且历史存在测试数据,因此当前零合同只记为待负责人确认的运营事实,不擅自归因为“模块尚未启用”。 ## 4. 预期证据表 @@ -104,4 +108,4 @@ ## 6. 当前结论 -生产只读基线与账号诊断已执行。扩展诊断证明唯一活跃管理员的原始仓库外凭据不匹配;独立任务 `08-09-production-admin-break-glass-reset` 随后按单次 apply、强制改密和最终验证合同恢复了管理员认证,并已销毁旧 hash 与临时凭据。员工侧目标仍不唯一且现有验收密码不匹配活跃候选。此前四次窗口均 OPEN/0,登录 attempts=0。当前管理员只读验收阻塞已解除,员工负向仍 `PAUSED`;下一步只执行管理员一次登录、合同只读 UI 和前后窗口快照,不告知用户可以测试。 +生产只读基线与账号诊断已执行,独立任务 `08-09-production-admin-break-glass-reset` 已恢复管理员认证。管理员本轮唯一一次登录返回 200,失败计数仍为 0 且未锁定;但生产合同总数为 0,无法验证详情、终止入口、归档锁定或已终止标签,未制造样本。仓库事实源不能证明零合同属于预期未启用,后续由负责人确认其运营含义;一旦生产出现首条记录,即触发只读补验。员工目标仍不唯一,负向权限未验证。凭据恢复后的 PRE/POST 与此前四次快照全部 OPEN/0,terminate POST 和合同 mutation 均为 0。当前结论为管理员认证通过、合同 UI 因无数据 `PAUSED`、员工负向 `PAUSED`;仍不得告知用户可以测试合同终止功能。 diff --git a/.trellis/tasks/08-08-production-authenticated-readiness/prd.md b/.trellis/tasks/08-08-production-authenticated-readiness/prd.md index 82147a52..dae34053 100644 --- a/.trellis/tasks/08-08-production-authenticated-readiness/prd.md +++ b/.trellis/tasks/08-08-production-authenticated-readiness/prd.md @@ -77,11 +77,11 @@ - [x] AC1:生产运行/公网 SHA 对应已部署产品候选 `0224ad8`(短标识 `0224ad83d7f8`);65 条 migration 仍全部 applied、pending=none,未触发部署或 schema 写入。 - [x] AC2:任何登录前已对管理员、员工完成同一 `BEGIN READ ONLY` 查询合同;查询设计覆盖 `matchedBy`、active/archived/locked、失败计数和期望角色是否就绪。两个 identifier 实际均 `matchedBy=none`,故账号属性记为 `N/A` 而非生产事实,不含账号或凭据明文。 - [x] AC3:两个仓库外 identifier 均不匹配 email/phone/employee_no。只读角色候选与远端内存密码 hash 比对进一步证明:唯一活跃管理员可解析为 email、未锁定、失败计数为 0,但现有管理员密码不匹配;员工有 5 个活跃非管理员候选,现有员工验收密码对这些候选的匹配数为 0。登录尝试保持 0,未输出 identifier/hash。 -- [ ] AC4 — PAUSED:管理员正确 identifier 已在只读内存中唯一解析,但现有密码确认失效;生产 `EMAIL_ENABLED=false`,公网 capabilities 为 `emailDeliveryReady=false / email_disabled`,自助重置不可用。管理员受控直接重置需要单独批准;员工目标账号仍不唯一。本轮各角色登录尝试均为 0。 -- [ ] AC5 — PAUSED:管理员 identifier 已解析但密码不匹配,未建立管理员会话,未进入合同详情或终止面板;终止端点 `POST` 计数为 0,确认层未打开。 -- [ ] AC6 — PAUSED:员工目标账号未唯一确定且现有验收密码不匹配活跃候选,未执行权限负向或 archived/terminated 样本 UI 检查;未扩大权限、修改断言或制造数据。 -- [x] AC7:初始、登录前停止后、扩展账号诊断后、邮件能力诊断后共四次窗口证据均为 `terminatedRows=0`、`rollbackWindow=OPEN`、`basis=terminated_status_count`;窗口未变化,本任务真实合同终止写入计数为 0。 -- [x] AC8:邮件能力与 break-glass 建议新增审查首轮 `PASS_WITH_FINDINGS` 的两项措辞已修订,最终复查为 `PASS`;task validate、process contract、governance、sensitive scan、diff check 均通过。 +- [ ] AC4 — PARTIAL:管理员凭据已由独立 `08-09-production-admin-break-glass-reset` 合法恢复,本轮唯一一次登录 HTTP 200,失败计数为 0 且未锁定;员工目标账号仍不唯一,员工登录 attempts=0。浏览器未重试管理员登录。 +- [ ] AC5 — PAUSED:管理员认证通过,但生产合同总数为 0,无法进入详情或终止面板;终止端点 `POST` 计数为 0、全部合同 mutation 计数为 0,确认层未打开,未制造合同。 +- [ ] AC6 — PAUSED:员工目标账号未唯一确定且现有验收密码不匹配活跃候选,未执行权限负向;archived/terminated 样本数均为 0,无法执行对应 UI 检查;未扩大权限、修改断言或制造数据。 +- [x] AC7:初始、登录前停止后、扩展账号诊断后、邮件能力诊断后及管理员验收 PRE/POST 共六次窗口证据均为 `terminatedRows=0`、`rollbackWindow=OPEN`、`basis=terminated_status_count`;窗口未变化,本任务真实合同终止写入计数为 0。 +- [x] AC8:邮件能力与 break-glass 建议审查、浏览器验收收口审查的 findings 均已按证据边界修订,最终只读复查为 `PASS`;task validate、process contract、governance、sensitive scan、docs registry audit 与 diff check 已复跑,docs audit 仅保留既有 22 个未注册文件 warning。 - [x] AC9:结论明确为产品已部署、生产基线健康,但登录态验收仍 `PAUSED`;当前不得告知用户可以测试。 ## Out of Scope @@ -96,6 +96,8 @@ ## Accepted Risk and Deferred Items - 生产终止功能已可达,真实用户可能在验收期间关闭回滚窗口;双快照只能发现变化,不能阻止真实使用。窗口一旦关闭,只能 roll-forward 或兼容 hotfix。 +- 合同 UI 后续验收不按日期开放等待,而以生产 `contract_registry` 出现首条记录为触发条件:届时先只读复核样本状态与 rollback window,再在不修改该记录的前提下补验详情、状态标签、字段锁定和终止按钮初始禁用;不得把“首条记录出现”自动解释为允许终止写入。 +- 当前生产合同总数为 0 是数据库事实,但仓库事实源已将合同台账列为首批真实使用域,历史试运行报告还曾记录 `TEST/SMOKE` 数据。现有证据只能排除连错库,不能判定零数据是预期未启用、后续清理结果或尚未完成真实数据迁入;在负责人确认前保持为运营事实待确认,不把它写成产品缺陷或正常结论。 - 没有同构预发环境;本任务主动放弃确认层视觉验收,以降低不可逆误操作风险。 - 既有生产可能没有 archived 或 terminated 样本;缺少数据时相应只读断言保持 `PAUSED`,不得为覆盖率制造业务数据。 - 如果仓库外凭据确已失效,本任务可能在账号诊断阶段结束而无法完成登录态验收;这是真实阻塞,不授权以生产账号写入换取通过。