4.1 KiB
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 (
ApproveV2AsyncUPSERT 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 →ApproveV2Asynclo 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].