返回 DeepSeek-Reasonix
goal_progress.go
根目录 / internal / evidence / goal_progress.go
1 package evidence
2
3 import (
4 "crypto/sha256"
5 "encoding/json"
6 "fmt"
7 "slices"
8 "strings"
9 )
10
11 // SuccessfulProgressSignaturesSince returns stable successful-work identities.
12 func (l *Ledger) SuccessfulProgressSignaturesSince(index int) []string {
13 if l == nil {
14 return nil
15 }
16 if index < 0 {
17 index = 0
18 }
19 l.mu.Lock()
20 defer l.mu.Unlock()
21 var out []string
22 for i := index; i < len(l.receipts); i++ {
23 if sig, ok := progressReceiptSignature(l.receipts[i]); ok {
24 out = append(out, sig)
25 }
26 }
27 return out
28 }
29
30 // SuccessfulProgressFingerprint returns a stable set fingerprint for successful
31 // host-observed work in the current ledger. Repeating an identical call with an
32 // identical result does not change it, while a novel read result, command
33 // result, mutation, todo update, review, or sign-off does.
34 func (l *Ledger) SuccessfulProgressFingerprint() string {
35 signatures := l.SuccessfulProgressSignaturesSince(0)
36 unique := make(map[string]struct{}, len(signatures))
37 for _, signature := range signatures {
38 unique[signature] = struct{}{}
39 }
40 signatures = signatures[:0]
41 for signature := range unique {
42 signatures = append(signatures, signature)
43 }
44 slices.Sort(signatures)
45 sum := sha256.Sum256([]byte(strings.Join(signatures, "\x00")))
46 return fmt.Sprintf("%x", sum)
47 }
48
49 func progressReceiptSignature(r Receipt) (string, bool) {
50 if !r.Success {
51 return "", false
52 }
53 kind := ""
54 switch {
55 case r.Mutation || r.Write:
56 kind = "mutation"
57 case r.Command != "":
58 kind = "command"
59 case r.ToolName == "todo_write":
60 kind = "todo"
61 case r.ToolName == "complete_step" && r.StepProof:
62 kind = "signoff"
63 case successfulForegroundReviewReceipt(r) || completedStructuredReviewReceipt(r, nil):
64 kind = "review"
65 case r.Read && r.OutputBytes > 0:
66 kind = "read"
67 default:
68 return "", false
69 }
70 payload := strings.TrimSpace(string(r.Args))
71 var decoded any
72 if json.Unmarshal(r.Args, &decoded) == nil {
73 if canonical, err := json.Marshal(decoded); err == nil {
74 payload = string(canonical)
75 }
76 }
77 if (kind == "read" || kind == "command") && r.OutputDigest != "" {
78 payload += "\x00output=" + r.OutputDigest
79 }
80 sum := sha256.Sum256([]byte(kind + "\x00" + r.ToolName + "\x00" + payload))
81 return fmt.Sprintf("%x", sum), true
82 }
83
83 lines GO