Files
Agent-System-Backend/internal/runmgr/task_checkpoint_test.go
T

201 lines
7.4 KiB
Go

package runmgr
import (
"agent-system-backend/internal/cardsvc"
core "agent-system-core"
"crypto/sha256"
"encoding/hex"
"fmt"
"strings"
"testing"
)
func checkpointEnvironment(t *testing.T) *runCtx {
st := openRecoveryStore(t)
m := newRecoveryManager(t, st)
m.SetInstanceID("A")
m.SetCards(cardsvc.New(st, nil))
conv := recoveryConversation(t, st)
parent := recoveryRun(t, st, conv, core.RunRunning)
data := []byte("上线六月")
a := core.Artifact{Owner: conv.Owner, ProjectID: conv.ProjectID, Name: "决定.txt"}
if e := st.CreateArtifact(&a, data); e != nil {
t.Fatal(e)
}
sum := sha256.Sum256(data)
docs := []core.ParsedDocument{{Meta: core.DocMeta{Filename: a.Name, Origin: &core.DocumentOrigin{ArtifactID: a.ID, ContentHash: hex.EncodeToString(sum[:]), ParserRevision: "txt.v1"}}, Blocks: []core.DocBlock{{Type: core.BlockPara, Text: string(data)}}}}
b, _, e := m.registerBackgroundTask(parent, bgSpawnOpts{name: "整理", material: true, documents: docs})
if e != nil {
t.Fatal(e)
}
if e = m.startTaskProjection(b, "run_material"); e != nil {
t.Fatal(e)
}
return &runCtx{mgr: m, run: core.Run{ID: "run_material", Kind: core.RunSubagent, Owner: conv.Owner, ConversationID: conv.ID, ProjectID: conv.ProjectID}, subAgent: materialSubagentID, task: b, sources: materialSources(docs, 48000)}
}
func validCheckpoint(c *runCtx, id string) core.WorkCheckpointCandidate {
var src core.TaskSourceRef
for _, s := range c.sources {
src = s.Ref
break
}
return core.WorkCheckpointCandidate{CheckpointID: id, PhaseID: "crosscheck", Focus: "核对决定", Remaining: "尚在核对", NextStep: "继续整理", Findings: []core.WorkFindingCandidate{{FindingKey: "date", Text: "材料记载上线六月", Kind: "material_record", Impact: "安排交付需要采用该日期", Sources: []core.TaskSourceQuote{{SourceID: src.ID, BlockIndex: src.BlockIndex, Quote: "上线六月"}}}}}
}
func TestMaterialRecordCannotAddAnUnstatedApproval(t *testing.T) {
c := checkpointEnvironment(t)
cp := validCheckpoint(c, "approval")
cp.Findings[0].Text = "上线六月已经批准,无需再次确认"
cp.Findings[0].Impact = "批准状态已经明确"
cp.Findings[0].Assumptions = "审批已完成"
if _, err := c.PublishWorkCheckpoint(cp); err != nil {
t.Fatal(err)
}
card, err := c.mgr.st.GetCard(c.run.Owner, c.task.cardID)
if err != nil {
t.Fatal(err)
}
f := card.Task.Findings[0]
if strings.Contains(f.Text, "批准") || f.Impact != "" || f.Assumptions != "" || !strings.Contains(f.Text, "上线六月") {
t.Fatalf("model interpretation was published as a material record: %+v", f)
}
}
func TestTaskCheckpointNormalizesUnsupportedApproval(t *testing.T) {
c := checkpointEnvironment(t)
cp := validCheckpoint(c, "unsupported-approval")
cp.Findings[0].Kind = "analysis"
cp.Findings[0].Text = "需求规定50万元,是已批准决定"
cp.Findings[0].Assumptions = "把需求条目作为项目基线"
receipt, err := c.PublishWorkCheckpoint(cp)
if err != nil || !strings.Contains(receipt, "待确认") {
t.Fatalf("unsupported approval was not normalized: %q %v", receipt, err)
}
after, err := c.mgr.st.GetCard(c.run.Owner, c.task.cardID)
if err != nil {
t.Fatal(err)
}
if len(after.Task.Findings) != 1 || after.Task.Findings[0].Kind != "needs_user" || strings.Contains(after.Task.Findings[0].Text, "已批准") {
t.Fatal("unsupported approval reached the task card", after.Task.Findings)
}
}
func TestTaskCheckpointPersistentIdempotentAndCorrected(t *testing.T) {
c := checkpointEnvironment(t)
cp := validCheckpoint(c, "1")
if _, e := c.PublishWorkCheckpoint(cp); e != nil {
t.Fatal(e)
}
card, _ := c.mgr.st.GetCard(c.run.Owner, c.task.cardID)
revision := card.Task.Revision
if len(card.Task.Findings) != 1 || !strings.HasPrefix(card.Task.Findings[0].ID, "finding_") {
t.Fatal("checkpoint absent", card.Task)
}
if _, e := c.PublishWorkCheckpoint(cp); e != nil {
t.Fatal(e)
}
card, _ = c.mgr.st.GetCard(c.run.Owner, c.task.cardID)
if card.Task.Revision != revision {
t.Fatal("retransmission advanced revision")
}
cp.Findings[0].Text = "different"
if _, e := c.PublishWorkCheckpoint(cp); e == nil {
t.Fatal("same id different payload accepted")
}
cp = validCheckpoint(c, "2")
cp.Findings[0].Text = "日期需要进一步核对"
cp.Findings[0].Corrects = "date"
if _, e := c.PublishWorkCheckpoint(cp); e != nil {
t.Fatal(e)
}
card, _ = c.mgr.st.GetCard(c.run.Owner, c.task.cardID)
if len(card.Task.Findings) != 2 || card.Task.Findings[0].Status != "corrected" {
t.Fatal("correction erased history", card.Task.Findings)
}
}
func TestTaskCheckpointRejectsFalseSourcesAndLateWrites(t *testing.T) {
c := checkpointEnvironment(t)
cp := validCheckpoint(c, "1")
cp.Findings[0].Sources[0].Quote = "不存在的七月"
if _, e := c.PublishWorkCheckpoint(cp); e == nil {
t.Fatal("invented quotation accepted")
}
cp = validCheckpoint(c, "2")
cp.Findings[0].Kind = "verified"
if _, e := c.PublishWorkCheckpoint(cp); e == nil {
t.Fatal("verification privilege accepted")
}
if e := c.mgr.finishTaskProjection(c.task, core.AgentResultPayload{Summary: "完成"}, nil); e != nil {
t.Fatal(e)
}
if _, e := c.PublishWorkCheckpoint(validCheckpoint(c, "3")); e == nil {
t.Fatal("late terminal checkpoint accepted")
}
}
func TestTaskCheckpointQuotaCorrectionAndSourceScope(t *testing.T) {
c := checkpointEnvironment(t)
for i := 0; i < 6; i++ {
cp := validCheckpoint(c, fmt.Sprint(i))
cp.Findings[0].Text = fmt.Sprintf("第%d项读取结果", i)
if _, e := c.PublishWorkCheckpoint(cp); e != nil {
t.Fatal(e)
}
}
cp := validCheckpoint(c, "over-limit")
if _, e := c.PublishWorkCheckpoint(cp); e == nil {
t.Fatal("quota ignored")
}
cp = validCheckpoint(c, "correction")
cp.Findings[0].Corrects = "date"
cp.Findings[0].Text = "上述口径需重新核验"
if _, e := c.PublishWorkCheckpoint(cp); e != nil {
t.Fatal("correction blocked by quota", e)
}
card, _ := c.mgr.st.GetCard(c.run.Owner, c.task.cardID)
if card.Task.CheckpointCount != 6 || card.Task.ExecutionState != "running" {
t.Fatal("correction changed execution / ordinary budget")
}
other := core.Artifact{Owner: c.run.Owner, ProjectID: "other-project", Name: "other.txt"}
if e := c.mgr.st.CreateArtifact(&other, []byte("上线六月")); e != nil {
t.Fatal(e)
}
for id, src := range c.sources {
src.Ref.ArtifactID = other.ID
c.sources[id] = src
}
cp = validCheckpoint(c, "foreign")
cp.Findings[0].Corrects = "date"
if _, e := c.PublishWorkCheckpoint(cp); e == nil {
t.Fatal("foreign project accepted")
}
}
func TestTaskCheckpointCorrectionWithdrawsOldClaimEvenWhenSnapshotIsFull(t *testing.T) {
c := checkpointEnvironment(t)
cp := validCheckpoint(c, "first")
if _, e := c.PublishWorkCheckpoint(cp); e != nil {
t.Fatal(e)
}
card, _ := c.mgr.st.GetCard(c.run.Owner, c.task.cardID)
task := *card.Task
task.Revision++
task.Findings[0].Text = strings.Repeat("x", 54000)
if e := c.mgr.cards.CommitTask(c.run.Owner, task, card.Task.Revision); e != nil {
t.Fatal(e)
}
cp = validCheckpoint(c, "large-correction")
cp.Findings[0].Corrects = "date"
cp.Findings[0].Text = strings.Repeat("y", 11000)
cp.Findings[0].Kind = "analysis"
cp.Findings[0].Assumptions = "来源尚需复核,撤回旧结论"
if _, e := c.PublishWorkCheckpoint(cp); e != nil {
t.Fatal("known wrong claim must be withdrawn", e)
}
card, _ = c.mgr.st.GetCard(c.run.Owner, c.task.cardID)
for _, f := range card.Task.Findings {
if f.Text == strings.Repeat("x", 54000) && f.Status == "active" {
t.Fatal("known wrong claim retained")
}
}
}