From 492920cd757d55de858c37d8ab3edf4ec9d5504f Mon Sep 17 00:00:00 2001 From: shunli Date: Sat, 5 Sep 2026 22:04:32 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E8=A1=A5=E9=BD=90=E8=B4=A2=E5=8A=A1?= =?UTF-8?q?=E8=BA=AB=E4=BB=BD=E9=AA=8C=E6=94=B6=E7=AA=97=E5=8F=A3=E8=A7=84?= =?UTF-8?q?=E7=BA=A6=EF=BC=8809-05-error-explainability-payment-readiness?= =?UTF-8?q?=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .trellis/spec/hyb-oa/deployment-trialrun.md | 56 +++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/.trellis/spec/hyb-oa/deployment-trialrun.md b/.trellis/spec/hyb-oa/deployment-trialrun.md index a1a19f55..eeb7e0c1 100644 --- a/.trellis/spec/hyb-oa/deployment-trialrun.md +++ b/.trellis/spec/hyb-oa/deployment-trialrun.md @@ -2807,6 +2807,9 @@ helper dry-run -> actions=[] and safe target - Required evidence fields: `stage`, `loginAttempts`, `loginHttpStatus`, `sampleCategory`, `sampleCount`, `businessMutationCount`, and the relevant endpoint-specific request count such as `terminatePostCount`. +- A finance smoke window additionally records `authorizationRef`, `accountAlias`, + `observedRoleCodes`, `disableReason`, `disableAuditRef` and `postDisableStatus`. + Use aliases and redacted references, never credentials or full identifiers. ### 3. Contracts @@ -2834,10 +2837,60 @@ helper dry-run -> actions=[] and safe target - Recheck any state-based rollback window before and after the browser run. Missing samples and a still-open window remain independent facts. +#### Finance-role acceptance checklist + +1. Resolve exactly one configured OA-only finance smoke in the isolated test + department. Before login, read its `status`, `employment_status`, + `archived_at`, `last_working_date`, lock state and effective role grants. + Require exactly `employee + finance`, with no extra roles or wildcard grant. + The database uses `status=archived` for disabled accounts; employees have no + `left_at` field. A disabled account is a blocked acceptance prerequisite, + not permission to weaken the login guard. +2. Obtain explicit authorization for the complete enable -> acceptance -> + disable window before any account write. Record the operator alias, purpose, + deadline and abort/cleanup responsibility. Re-read status and role grants + after enabling. Neither an earlier window nor an unexpectedly active account + grants permission for a new window or permanent activation. +3. Run the approved checks as that finance actor. Administrator results prove + only administrator behavior: wildcard privileges cannot establish finance + visibility, projections or action boundaries. A different read-only actor + likewise cannot replace exact finance-role acceptance. Stop at the precise + failed stage; do not replace the actor and mark the finance criterion PASS. +4. Immediately disable the smoke through the approved account-management path + when checks finish or abort. Read back `status=archived`, non-null + `archived_at` and target session revocation, and link the disable audit event. + A failed cleanup or missing verification leaves the window unclosed and must + be handed off explicitly; it is not a successful closeout. Do not submit an + extra login merely to prove that disabling worked. + +- Record a concrete disable reason, such as `finance_acceptance_complete` or + `finance_acceptance_aborted`, linked to the authorization and disable event. + Current `server/src/routes/users.js` writes `SYSTEM_USER_DISABLED` with + `extra: {}`: audit-native reason persistence is **not implemented**. Until a + separately approved code change adds it, retain the reason in controlled + acceptance evidence linked to the audit reference, operator alias and event + time. Do not claim the audit row contains a reason, invent historical reasons, + or directly patch audit rows to satisfy this checklist. +- Do not treat a permanently active read-only finance account as an account-only + shortcut. Current grants are fixed by `RoleCode`/`EmployeeRole` and + `resolvePermissionsForRoles`, not arbitrary per-account permission strings; + there is no finance-read-only role, and `employee` itself includes writes. + Both payment candidates and combination readiness require + `payment.batch.manage`; `expense.view_all` alone cannot cover them. A future + read/write permission split needs separate approval and projection/denial + verification. Read-only access still exposes confidential financial data and + is not a zero-risk standing identity. + ### 4. Validation & Error Matrix - Login fails once -> stop with the authentication stage and re-read lock/failure state; no second login. +- Finance smoke is disabled -> record the prerequisite as + `PAUSED(finance_account_disabled)`; finance-role acceptance remains unverified. + If login was attempted, distinguish `403/AUTH_003` at `/api/auth/login` from + `403/PERM_001` at a later protected endpoint; never infer the layer from 403 alone. +- Disable reason, linked audit reference or post-disable state proof is missing + -> acceptance-window closeout is incomplete, even when all UI checks passed. - 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 @@ -2875,6 +2928,9 @@ helper dry-run -> actions=[] and safe target 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. +- For a finance window, verify the unique actor and exact grants before login, + and the reason/audit linkage, disabled state and session revocation afterward. + Administrator or alternative-role checks must not satisfy finance-role criteria. - Production execution still requires explicit approval, pre/post rollback window snapshots, sensitive-content scanning and a read-only reviewer.