- authoring: identity write 도메인 구현 (identity_write.go) - authoring: request/result 도메인 정리 및 테스트 개선 - scheduler: job/river 구조 리팩토링 및 테스트 보완 - gitosync: bridge/scanner 테스트 개선 - roadmap: plane-origin-authoring-roundtrip-sync 마일스톤 업데이트
126 lines
3.2 KiB
Go
126 lines
3.2 KiB
Go
package authoring
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/nomadcode/nomadcode-core/internal/projectsync"
|
|
"github.com/nomadcode/nomadcode-core/internal/roadmapsync"
|
|
)
|
|
|
|
// DecisionInput contains the outputs and signals from the authoring process,
|
|
// used to determine the final authoring run state.
|
|
type DecisionInput struct {
|
|
BridgeSuccess bool
|
|
DevelopMatch roadmapsync.ProjectionCandidate
|
|
ExitCode *int
|
|
PushFailed bool
|
|
DirtyWorkspace bool
|
|
Conflict bool
|
|
IdentityWriteFailed bool
|
|
IdentityMissing bool
|
|
}
|
|
|
|
// Decision represents the state, reason, and failure category determined by the result helper.
|
|
type Decision struct {
|
|
State string // "in_progress", "succeeded", "failed"
|
|
Reason string
|
|
FailureCategory string // "bridge_failed", "exit_code", "push_failed", "dirty_workspace", "conflict"
|
|
}
|
|
|
|
// DecideAuthoringResult evaluates the authoring run inputs and signals to classify
|
|
// the task outcome as succeeded, failed (with specific category), or in_progress.
|
|
func DecideAuthoringResult(in DecisionInput) Decision {
|
|
if !in.BridgeSuccess {
|
|
return Decision{
|
|
State: "failed",
|
|
Reason: "model bridge response failed",
|
|
FailureCategory: "bridge_failed",
|
|
}
|
|
}
|
|
|
|
if in.IdentityWriteFailed {
|
|
return Decision{
|
|
State: "failed",
|
|
Reason: "provider identity write failed",
|
|
FailureCategory: "identity_write_failed",
|
|
}
|
|
}
|
|
|
|
if in.IdentityMissing {
|
|
return Decision{
|
|
State: "failed",
|
|
Reason: "provider identity missing",
|
|
FailureCategory: "identity_missing",
|
|
}
|
|
}
|
|
|
|
if in.ExitCode != nil && *in.ExitCode != 0 {
|
|
return Decision{
|
|
State: "failed",
|
|
Reason: fmt.Sprintf("agent process exited with non-zero code %d", *in.ExitCode),
|
|
FailureCategory: "exit_code",
|
|
}
|
|
}
|
|
|
|
if in.PushFailed {
|
|
return Decision{
|
|
State: "failed",
|
|
Reason: "git push to develop branch failed",
|
|
FailureCategory: "push_failed",
|
|
}
|
|
}
|
|
|
|
if in.DirtyWorkspace {
|
|
return Decision{
|
|
State: "failed",
|
|
Reason: "workspace contains dirty changes",
|
|
FailureCategory: "dirty_workspace",
|
|
}
|
|
}
|
|
|
|
if in.Conflict {
|
|
return Decision{
|
|
State: "failed",
|
|
Reason: "git merge conflict detected",
|
|
FailureCategory: "conflict",
|
|
}
|
|
}
|
|
|
|
if in.DevelopMatch.Ready {
|
|
reason := in.DevelopMatch.Reason
|
|
if reason == "" {
|
|
reason = "pushed develop milestone matched expected identity"
|
|
}
|
|
return Decision{
|
|
State: "succeeded",
|
|
Reason: reason,
|
|
}
|
|
}
|
|
|
|
reason := in.DevelopMatch.Reason
|
|
if reason == "" {
|
|
reason = "waiting for pushed develop milestone match"
|
|
}
|
|
return Decision{
|
|
State: "in_progress",
|
|
Reason: reason,
|
|
}
|
|
}
|
|
|
|
// SlotStateForAuthoringOutcome maps terminal authoring outcomes to the slot
|
|
// state the scheduler should persist. Non-terminal decisions are not applied.
|
|
func SlotStateForAuthoringOutcome(decision Decision) (projectsync.SlotState, bool) {
|
|
switch decision.State {
|
|
case "succeeded":
|
|
return projectsync.SlotStateAvailable, true
|
|
case "failed":
|
|
switch decision.FailureCategory {
|
|
case "dirty_workspace", "conflict", "push_failed":
|
|
return projectsync.SlotStateDirty, true
|
|
default:
|
|
return projectsync.SlotStateError, true
|
|
}
|
|
default:
|
|
return "", false
|
|
}
|
|
}
|