Skip to content

fix(bpm-core): respect manager resolution priority when building approvers - #4

Merged
fantasywind merged 3 commits into
Rytass:mainfrom
coollugi:fix/manager-resolution-priority
Aug 4, 2026
Merged

fix(bpm-core): respect manager resolution priority when building approvers#4
fantasywind merged 3 commits into
Rytass:mainfrom
coollugi:fix/manager-resolution-priority

Conversation

@coollugi

@coollugi coollugi commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

問題

每個人的「發起人主管」關卡都會把上層組織單位繼承下來的主管規則一起撈進來,不管那條規則的優先序多低

用 demo seed 看特別明顯 —— reset-demo-data.ts 在組織根節點放了一條 catch-all:

managerResolution('ORG_UNIT', ORG_UNIT_IDS.ROOT,    'member-001', 10)   // 林總經理, meant as a floor
managerResolution('ORG_UNIT', ORG_UNIT_IDS.FINANCE, 'member-101', 100)
managerResolution('MEMBER',   'member-102',         'member-101', 220)

10 / 100 / 220 這個級距要有意義,前提是級距真的被套用
但它沒有,所以 member-102 會同時解出 member-101 member-001,而其他每一個人也都會多帶到 member-001

根因

resolveManagerResolutionCandidates 排序完命中的規則之後,把全部都回傳了:

const active = resolutions
  .filter(...)
  .filter((resolution) => isDateRangeActive(resolution, date))
  .sort(compareManagerResolution);

return uniqueTexts(active.map((resolution) => resolution.managerMemberId));

OrganizationService.resolveManagerMemberId 組出一模一樣的候選集合、套用一模一樣的 filter、呼叫一模一樣的 comparator,然後收斂成一個:

return active[0]?.managerMemberId ?? null;

也就是兩個模組對「一條主管規則代表什麼」的解讀不一致,而 admin UI 上的說明(「簽核主管規則獨立於組織樹 parent,解析優先序為會員、組織、職位」)描述的是 organization 模組那邊的行為

修法

保留勝出的那一層,而不是只留單一列,讓同優先序的規則仍然可以共用同一個關卡:

function readTopPriorityResolutions(resolutions) {
  const [top] = resolutions;
  if (!top) return [];
  return resolutions.filter(
    (r) => r.priority === top.priority && r.scopeType === top.scopeType,
  );
}

測試

workflow-engine.service.spec.ts 新增兩個案例:

  • 低優先序的上層規則不再加入簽核人清單
  • 在勝出層打平的兩條規則都會保留

createServiceFixture 另外開放了 savedTaskCandidates(原本 candidate 資料列有存但觀察不到,導致簽核人集合的迴歸無法斷言)

驗證過兩個都是真的迴歸防護:只還原 source 的改動,它們都會紅

nx test bpm-core(21 suites/162 tests)/nx lint bpm-corenx typecheck bpm-core 全部通過

關於同優先序打平的處理(已請教過並取得答覆)

admin 對話框的 priority 預設是 0,畫面上沒有任何關於數字方向或建議級距的提示
如果所有規則都沿用這個預設值,不同組織層級的規則會在 priorityscopeType 上同時打平,而這個修法會把它們全部保留

原本考慮再加第三層排序(組織深度,離該成員最近的單位勝出),但那會動到 compareManagerResolution 的簽章,因為它目前只看得到規則本身
已就這點請教過,得到的答覆是同層級的多位主管本來就應該一起簽,所以這裡維持現在的做法,不再往下比組織深度

另外 priority 欄位確實值得補上 UI 指引(數字方向、建議級距),否則這個值不容易被正確使用
這一點也得到可以做的答覆,會另外處理,不放在這個 PR 裡

順帶提醒:這個 fix 進去之後 demo seed 的行為會變 —— ROOT 那條 priority 10 的 catch-all 會回到「只在找不到其他主管時才生效」,這應該就是它原本的用意

🤖 Generated with Claude Code

https://claude.ai/code/session_01BVBYyU83KfmAeJGj6gGsVm

@coollugi
coollugi force-pushed the fix/manager-resolution-priority branch from 2a5def4 to 94e5499 Compare August 3, 2026 12:23
@coollugi
coollugi changed the base branch from main to staging August 3, 2026 12:23
@coollugi

coollugi commented Aug 3, 2026

Copy link
Copy Markdown
Contributor Author

base 已經從 main 改成 staging,原因寫在 #2

@coollugi
coollugi changed the base branch from staging to main August 3, 2026 13:03
coollugi and others added 3 commits August 4, 2026 00:17
…overs

resolveManagerResolutionCandidates sorted the matching rules by priority and
scope specificity and then returned every one of them, so a low-priority
catch-all rule on an ancestor org unit was appended to the approver list of
every member below it. The sort had no observable effect beyond ordering.

OrganizationService.resolveManagerMemberId already narrows the same sorted list
down to active[0]. The workflow engine now keeps the winning tier instead of a
single row, so several managers of equal precedence can still share one step.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BVBYyU83KfmAeJGj6gGsVm
@fantasywind
fantasywind force-pushed the fix/manager-resolution-priority branch from 94e5499 to 36c687e Compare August 3, 2026 16:23
@fantasywind
fantasywind merged commit 3098637 into Rytass:main Aug 4, 2026
1 check failed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants