From 750b904439bf04d971c9d63c6370d240304bd1d5 Mon Sep 17 00:00:00 2001 From: weichen Date: Thu, 17 Sep 2026 09:59:38 +0000 Subject: [PATCH] feat(app): wire projectinstance duties into bizdev Composition-root adapter maps live instance DocTasks to bizdev's narrow InstanceDutySource without crossing module boundaries. Co-authored-by: Cursor --- internal/app/app.go | 1 + internal/app/instance_duty_adapter.go | 46 +++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 internal/app/instance_duty_adapter.go diff --git a/internal/app/app.go b/internal/app/app.go index e7a09236..e4ad17fa 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -222,6 +222,7 @@ func Assemble(cfg *config.Config, svc *bizdev.Service) (*Runtime, error) { }) if instSvc != nil { instSvc.SetAuthorOnlyPolicySource(&sysadminAuthorOnlyPolicyAdapter{svc: rt.SysAdmin}) + svc.SetInstanceDutySource(&projectInstanceDutyAdapter{inst: instSvc}) } rt.DocNotify = &docnotify.Subscriber{Notify: rt.Notify, Docs: parts.Gov} rt.DocNotify.SkipWrite = func(ctx context.Context) bool { diff --git a/internal/app/instance_duty_adapter.go b/internal/app/instance_duty_adapter.go new file mode 100644 index 00000000..301d4c51 --- /dev/null +++ b/internal/app/instance_duty_adapter.go @@ -0,0 +1,46 @@ +package app + +import ( + "context" + "strings" + + "chat-agent-system/internal/projectinstance" +) + +// projectInstanceDutyAdapter 将活跃工作流实例的逐文档职责投影为 bizdev 窄接口, +// 避免 bizdev 导入 projectinstance。 +type projectInstanceDutyAdapter struct { + inst *projectinstance.Service +} + +func (a *projectInstanceDutyAdapter) ResolveGovernedDuty(ctx context.Context, projectID int64, taskKey string) (author, reviewer, approver int64, dutyPolicy string, governed bool, err error) { + if a == nil || a.inst == nil || projectID <= 0 { + return 0, 0, 0, "", false, nil + } + taskKey = strings.TrimSpace(taskKey) + if taskKey == "" { + return 0, 0, 0, "", false, nil + } + detail, _, derr := a.inst.GetLiveInstanceDetail(ctx, projectID) + if derr != nil || detail == nil { + // 无活跃实例(规划中/legacy)→ 不受治理,非错误 + return 0, 0, 0, "", false, nil + } + for _, st := range detail.Instance.ConfigSnapshot.Stages { + for _, dt := range st.DocTasks { + if dt.TaskKey != taskKey || !dt.Enabled { + continue + } + mode, effective, isAuthorOnly := projectinstance.ResolveDocTaskDuty(dt) + if mode != projectinstance.DutyModeFull { + return 0, 0, 0, "", false, nil + } + policy := projectinstance.DutyPolicySeparated + if isAuthorOnly { + policy = projectinstance.DutyPolicyAuthorOnly + } + return effective.AuthorUserID, effective.ReviewerUserID, effective.ApproverUserID, policy, true, nil + } + } + return 0, 0, 0, "", false, nil +}