package workflowdef import ( "regexp" "strings" ) // legacyToCanonical 是 D12 的旧任务键 → 新任务键。 // 冻结实例继续持有旧键;新发布的清单使用新键。两边必须指向同一套步骤和模板。 var legacyToCanonical = map[string]string{ "intake": "bd_intake", "research": "bd_research", "feasibility_dev": "bd_feasibility_dev", "feasibility_reg": "bd_feasibility_reg", "user_requirements": "bd_user_requirements", "prelim_design": "bd_prelim_design", "cdo_quote": "bd_cdo_quote", "system_reqs": "pm_system_reqs", "test_manager": "tm_system_verification", "software_charter": "sw_software_charter", "source_inventory": "sw_source_inventory", "current_state_audit": "sw_current_state_audit", "architecture_baseline": "sw_architecture_baseline", "software_risk_register": "sw_software_risk_register", "product_requirements": "sw_product_requirements", "scope_backlog": "sw_scope_backlog", "target_architecture": "sw_target_architecture", "decision_log": "sw_decision_log", "bootstrap_roadmap": "sw_bootstrap_roadmap", "verification_strategy": "sw_verification_strategy", "operations_baseline": "sw_operations_baseline", "bootstrap_readiness": "sw_bootstrap_readiness", "change_brief": "sw_change_brief", "implementation_plan": "sw_implementation_plan", "change_manifest": "sw_change_manifest", "adr_delta": "sw_adr_delta", "test_report": "sw_test_report", "security_review": "sw_security_review", "release_plan": "sw_release_plan", "release_notes": "sw_release_notes", "retrospective": "sw_retrospective", "backlog_delta": "sw_backlog_delta", } var canonicalToLegacy map[string]string func init() { canonicalToLegacy = make(map[string]string, len(legacyToCanonical)) for legacy, canonical := range legacyToCanonical { canonicalToLegacy[canonical] = legacy } } // CanonicalTaskKey 把旧键收成发布用的新键。未知键(含 rd_*)原样返回。 func CanonicalTaskKey(key string) string { key = strings.TrimSpace(key) if canonical, ok := legacyToCanonical[key]; ok { return canonical } return key } // ImplementationTaskKey 把新键收成现有步骤开关仍使用的旧键。 // 存量执行路径不改写;新键只是别名。 func ImplementationTaskKey(key string) string { key = strings.TrimSpace(key) if legacy, ok := canonicalToLegacy[key]; ok { return legacy } return key } // SameTaskKey 判断两个键是否同一任务(旧键与新键视为相同)。 func SameTaskKey(a, b string) bool { ca := CanonicalTaskKey(a) cb := CanonicalTaskKey(b) return ca != "" && ca == cb } var namespacedDocID = regexp.MustCompile(`^(doc_proj\d+_)(.+)$`) // AlternateDocIDs 给出同一文档的另一种键名形式。 // 账本不批量迁移:旧 ID 仍可查,新 ID 也要能指回旧行。 func AlternateDocIDs(docID string) []string { m := namespacedDocID.FindStringSubmatch(strings.TrimSpace(docID)) if len(m) != 3 { return nil } prefix, suffix := m[1], m[2] var out []string if canonical := CanonicalTaskKey(suffix); canonical != suffix { out = append(out, prefix+canonical) } if legacy := ImplementationTaskKey(suffix); legacy != suffix { out = append(out, prefix+legacy) } return out }