test(bizdev): drain pending confirmations in full-link stage E2E
Stage chain now stops on high-risk candidates; full-link mirrors the product path of confirm + re-run until success or DocGov proposal intercept. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -9,9 +9,75 @@ import (
|
||||
"chat-agent-system/internal/bizdev"
|
||||
"chat-agent-system/internal/config"
|
||||
"chat-agent-system/internal/docgov"
|
||||
"chat-agent-system/internal/docrevision"
|
||||
"chat-agent-system/internal/stream"
|
||||
)
|
||||
|
||||
// executeStageDrainingPending runs ExecuteStage, confirming high-risk agent candidates
|
||||
// (and projecting fact source) until the stage succeeds or stops on a DocGov proposal intercept.
|
||||
// This mirrors the product path: confirm on the page, then re-run the stage.
|
||||
func executeStageDrainingPending(
|
||||
t *testing.T,
|
||||
ctx context.Context,
|
||||
svc *bizdev.Service,
|
||||
req bizdev.StageRunRequest,
|
||||
authorID int64,
|
||||
dataRoot string,
|
||||
) *bizdev.StageRunResult {
|
||||
t.Helper()
|
||||
for attempt := 0; attempt < 16; attempt++ {
|
||||
res, err := svc.ExecuteStage(ctx, req)
|
||||
if err != nil {
|
||||
t.Fatalf("ExecuteStage attempt %d: %v", attempt, err)
|
||||
}
|
||||
if res.Success {
|
||||
return res
|
||||
}
|
||||
for _, sub := range res.SubArtifacts {
|
||||
if sub != nil && sub.IsProposalIntercept() {
|
||||
return res
|
||||
}
|
||||
}
|
||||
if res.PendingAgentCandidateID <= 0 {
|
||||
t.Fatalf("stage failed without pending/proposal: %s", res.ErrorReason)
|
||||
}
|
||||
var pending *bizdev.TaskRunResult
|
||||
for _, sub := range res.SubArtifacts {
|
||||
if sub != nil && sub.AwaitsAgentConfirmation() {
|
||||
pending = sub
|
||||
break
|
||||
}
|
||||
}
|
||||
if pending == nil || pending.DocRecord == nil || pending.DocRecord.DocID == "" {
|
||||
t.Fatalf("pending stage missing DocRecord: %+v", res)
|
||||
}
|
||||
docID := pending.DocRecord.DocID
|
||||
st, err := svc.DocRevision().GetRevisionState(ctx, docID)
|
||||
if err != nil {
|
||||
t.Fatalf("GetRevisionState(%s): %v", docID, err)
|
||||
}
|
||||
st2, err := svc.DocRevision().CommitAgentVersion(ctx, docID, pending.PendingAgentCandidateID, docrevision.CommitAgentDecision{
|
||||
Decision: "commit", Confirmed: true, ActorUserID: authorID,
|
||||
ExpectedInputSHA: st.HeadSHA256,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("CommitAgentVersion(%s,#%d): %v", docID, pending.PendingAgentCandidateID, err)
|
||||
}
|
||||
if err := svc.DocRevision().ProjectOutputMarkdown(docID, dataRoot); err != nil {
|
||||
t.Fatalf("ProjectOutputMarkdown(%s): %v", docID, err)
|
||||
}
|
||||
if st2 != nil && st2.HeadSHA256 != "" {
|
||||
if err := svc.DocGov().MarkDocumentContentUpdated(ctx, docID, st2.HeadSHA256, false); err != nil {
|
||||
t.Fatalf("MarkDocumentContentUpdated: %v", err)
|
||||
}
|
||||
}
|
||||
t.Logf("confirmed pending candidate #%d on %s; re-running stage (attempt %d)",
|
||||
pending.PendingAgentCandidateID, docID, attempt+1)
|
||||
}
|
||||
t.Fatal("stage still unresolved after max pending confirm/retry loops")
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestBizDev_FullLink_V01_V05_V10_E2E(t *testing.T) {
|
||||
cfg := &config.Config{
|
||||
DataDir: t.TempDir(),
|
||||
@@ -114,12 +180,9 @@ func TestBizDev_FullLink_V01_V05_V10_E2E(t *testing.T) {
|
||||
ApproverName: approverName,
|
||||
}
|
||||
|
||||
resV05, err := svc.ExecuteStage(ctx, stageReqV05)
|
||||
if err != nil {
|
||||
t.Fatalf("Stage V0.5 execution failed: %v", err)
|
||||
}
|
||||
resV05 := executeStageDrainingPending(t, ctx, svc, stageReqV05, authorID, cfg.DataDir)
|
||||
if !resV05.Success {
|
||||
t.Fatalf("Stage V0.5 should succeed, got error: %s", resV05.ErrorReason)
|
||||
t.Fatalf("Stage V0.5 should succeed after confirming pendings, got error: %s", resV05.ErrorReason)
|
||||
}
|
||||
if len(resV05.SubArtifacts) != 5 {
|
||||
t.Fatalf("Stage V0.5 should produce 5 sub-artifacts, got %d", len(resV05.SubArtifacts))
|
||||
@@ -167,10 +230,7 @@ func TestBizDev_FullLink_V01_V05_V10_E2E(t *testing.T) {
|
||||
stageReqV05Modified := stageReqV05
|
||||
stageReqV05Modified.TargetMarket = "中国NMPA二类 + 欧盟CE MDR"
|
||||
|
||||
resV05Intercepted, err := svc.ExecuteStage(ctx, stageReqV05Modified)
|
||||
if err != nil {
|
||||
t.Fatalf("ExecuteStage returned unexpected runtime error: %v", err)
|
||||
}
|
||||
resV05Intercepted := executeStageDrainingPending(t, ctx, svc, stageReqV05Modified, authorID, cfg.DataDir)
|
||||
if resV05Intercepted.Success {
|
||||
t.Fatalf("Stage V0.5 re-run on claimed document should be intercepted (Success=false)")
|
||||
}
|
||||
@@ -217,10 +277,7 @@ func TestBizDev_FullLink_V01_V05_V10_E2E(t *testing.T) {
|
||||
stageReqV05Force := stageReqV05Modified
|
||||
stageReqV05Force.ForceDirectEdit = true
|
||||
|
||||
resV05Updated, err := svc.ExecuteStage(ctx, stageReqV05Force)
|
||||
if err != nil {
|
||||
t.Fatalf("Stage V0.5 force re-run failed: %v", err)
|
||||
}
|
||||
resV05Updated := executeStageDrainingPending(t, ctx, svc, stageReqV05Force, authorID, cfg.DataDir)
|
||||
if !resV05Updated.Success {
|
||||
t.Fatalf("Stage V0.5 force re-run should succeed, error: %s", resV05Updated.ErrorReason)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user