Files
solution-erp/.claude/workflows/runs/2026-07-12-S112-pe-signoff-save-advance/run.md
2026-07-12 14:19:19 +07:00

4.1 KiB

RUN — PE "Ý kiến cấp duyệt" save-advance + creator-as-approver + reject-return (investigate)

  • folder: 2026-07-12-S112-pe-signoff-save-advance
  • session: S112 (2026-07-12) · lead: Opus 4.8 MAX (owner-choice)
  • command: /fable-clone vai invest/review đề tài 2 ảnh + "hmw cho Opus 4.8 MAX" (anh-directed)
  • mode: HMW RUN-TRACE · engine: fable-clone ensemble (per-invocation H21) · model=opus effort=inherit(xhigh)
  • input: 2 screenshot chat FDC anh Kiệt/PRO — yêu cầu đổi luồng PE sign-off (save-advance + creator=approver + reject-return)
  • spec: spec-pe-signoff-save-advance-12-07-2026.md

taskList snapshot

Stage Role Lane Lens
Investigate investigator-codebase A Luồng hiện tại (ApproveV2Async advance + creator/approver identity)
Investigate investigator-codebase B Thiết kế thay đổi (BE+FE, save=advance vs tách, self-approval flag)
Investigate investigator-codebase C Reject/TraLai flow (return-to-commenter, re-comment, edge)
Review reviewer 0 Adversarial verify (state-machine · self-approve · reject-loop · multi-cấp)

deliverable

Design-doc: luồng hiện tại + thay đổi BE/FE cần làm + reject-flow + risk → anh quyết design + scope. KHÔNG code lượt này.

synthesis (em-main — wf_fd8f2bfe-9f6, 4/4 clean, Opus 4.8)

sub-file naming = journal-order ≠ lane-order: sub-invest-B=Lane A (current-flow) · sub-invest-C=Lane B (change-design) · sub-invest-A=Lane C (reject) · sub-reviewer=reviewer.

REVIEWER VERDICT: PASS_WITH_CONCERNS. 3 lane khớp source thật 100% (mọi file:line verify đúng). Thiết kế sound, 0 vỡ 5-state.

Cốt lõi (bất ngờ tốt): yêu cầu = sửa 1 CHỖ, cơ chế đã có sẵn

  • "comment-in-own-box → save → advance" ĐÃ tồn tại trong dialog Duyệt (ApproveV2Async UPSERT opinion :763-790 + advance :927, cùng 1 call).
  • 🔴 ĐIỂM CHẶN = ApplyDrafterBypassOnSubmitAsync (PurchaseEvaluationWorkflowService.cs:571-681, gọi :260-261): lúc creator (=DrafterUserId=PRO) submit, nó TỰ ký hộ ô Cấp-1 bằng comment CANNED "(duyệt tự động…)" :619 + advance qua → creator mất ô comment thật của mình (đúng cái screenshot Cấp-1 Bình muốn).
  • 🔴 Đây là feature UAT S60 (anh Kiệt cũ: "TP tạo thì bypass — NV khỏi duyệt lại"). Yêu cầu mới NGƯỢC lạiđảo hành vi S60, cần sign-off.
  • FIX: gỡ/gate bypass → pointer đứng (0,1) → creator gõ comment thật + Duyệt → ApproveV2Async lo phần còn lại. 0 đổi ApproveV2Async · FE ~0. Giữ 1-nút (save=advance); 2-nút draft = thừa (cần schema+endpoint+DTO).

Reject (item 3): phần lớn ĐÃ có (mode Assignee — về NV đã ký, giữ ChoDuyet, re-comment UPSERT, forward). 3 gap: default=Drafter(full-restart) · phải admin bật Allow*-per-slot · rejecter pick tay.

Governance: creator-sign Cấp-1 = bước ĐỀ-XUẤT hợp lệ (CCM/CEO cấp trên mới approval thật, phân-tách nhiệm-vụ giữ). Lỗ CHỈ khi slot creator bật AllowApproverFinalize/SkipToFinal → self-finalize bỏ CEO (hiện 0 guard → đề-xuất guard B2, đã tồn-tại hôm nay qua bypass single-step-terminal).

🔴 EDGE-5 (reviewer nâng latent→REACHABLE, MAJOR pre-existing): Drafter forge Reject+TargetPhase=TraLai trên phiếu DaDuyet của chính mình (đã chốt ApprovedPrice) → mở lại → sửa → gửi lại. Controller :130-143 chỉ [Authorize] class-level + handler FEAT:510-539 KHÔNG guard fromPhase + EnsureCanRejectV2Async early-return khi Phase≠ChoDuyet :321. Vùng reject-return CHÍNH LÀ scope sửa → nên bịt luôn (guard fromPhase∈{DaDuyet,TuChoi}→throw).

6 quyết định owner (anh Kiệt): (1) A1/A2 gỡ-bypass · (2) guard-B2 self-finalize · (3) EDGE-5-fix · (4) 1-nút/2-nút · (5) stale-comment-khi-trả-lại · (6) migrate-data-cũ-bypass.

Harvest: pending @closeout — investigator-codebase + reviewer, stamp [engine: fable-clone-ensemble · Opus-S112].