返回 DeepSeek-Reasonix
profile.go
根目录 / internal / evidence / profile.go
1 package evidence
2
3 import "strings"
4
5 // EffectReason is a privacy-safe, argument-free classification note.
6 type EffectReason string
7
8 const (
9 ReasonReadOnly EffectReason = "read_only"
10 ReasonWorkspaceWrite EffectReason = "workspace_write"
11 ReasonRepoMetadata EffectReason = "repository_metadata"
12 ReasonHostState EffectReason = "host_state"
13 ReasonExternalState EffectReason = "external_state"
14 ReasonOpaqueWriter EffectReason = "opaque_writer"
15 ReasonDestructive EffectReason = "destructive"
16 ReasonUnknown EffectReason = "unknown"
17 ReasonHintReadOnly EffectReason = "annotation_read_only"
18 ReasonHintDestructive EffectReason = "annotation_destructive"
19 ReasonScratch EffectReason = "scratch_write"
20 )
21
22 // TargetKind classifies one concrete action target.
23 type TargetKind uint8
24
25 const (
26 TargetUnspecified TargetKind = iota
27 TargetFile
28 TargetDirectory
29 TargetRepo
30 TargetHost
31 TargetExternal
32 )
33
34 // Target is one resolved path or state domain the call touches.
35 type Target struct {
36 Path string
37 Kind TargetKind
38 }
39
40 // TargetKey is a comparable identity for an action target.
41 type TargetKey string
42
43 // Key returns a stable identity. Empty paths collapse by kind only.
44 func (t Target) Key() TargetKey {
45 path := strings.TrimSpace(t.Path)
46 if path == "" {
47 return TargetKey(targetKindName(t.Kind))
48 }
49 return TargetKey(targetKindName(t.Kind) + ":" + normalizeTargetPath(path))
50 }
51
52 func targetKindName(k TargetKind) string {
53 switch k {
54 case TargetFile:
55 return "file"
56 case TargetDirectory:
57 return "dir"
58 case TargetRepo:
59 return "repo"
60 case TargetHost:
61 return "host"
62 case TargetExternal:
63 return "external"
64 default:
65 return "target"
66 }
67 }
68
69 // EffectProfile is the host's concrete classification of one tool invocation.
70 type EffectProfile struct {
71 Known bool
72 ReadOnly bool
73 WorkspaceWrite bool
74 RepoMetadata bool
75 HostState bool
76 ExternalState bool
77 Destructive bool
78 Irreversible bool
79 Privileged bool
80 ExecutesCode bool
81 UsesNetwork bool
82 Targets []Target
83 Reason EffectReason
84 }
85
86 // Clone copies Targets so callers cannot share a mutable slice.
87 func (p EffectProfile) Clone() EffectProfile {
88 if len(p.Targets) > 0 {
89 p.Targets = append([]Target(nil), p.Targets...)
90 }
91 return p
92 }
93
94 // MutatesState reports whether the call can change durable state.
95 func (p EffectProfile) MutatesState() bool {
96 if !p.Known {
97 return true
98 }
99 return p.WorkspaceWrite || p.RepoMetadata || p.HostState || p.ExternalState
100 }
101
102 // OpaqueWriter reports a write-capable call whose effects are not proven.
103 func (p EffectProfile) OpaqueWriter() bool {
104 return !p.Known && !p.ReadOnly
105 }
106
107 // TargetKeys copies comparable identities for the classified targets.
108 func (p EffectProfile) TargetKeys() []TargetKey {
109 if len(p.Targets) == 0 {
110 return nil
111 }
112 out := make([]TargetKey, len(p.Targets))
113 for i, t := range p.Targets {
114 out[i] = t.Key()
115 }
116 return out
117 }
118
119 // ToolEffects projects the profile onto the existing policy/evidence boundary.
120 func (p EffectProfile) ToolEffects() ToolEffects {
121 return ToolEffects{
122 StateMutation: p.MutatesState(),
123 WorkspaceMutation: !p.Known || p.WorkspaceWrite || p.RepoMetadata,
124 ContentMutation: !p.Known || p.WorkspaceWrite,
125 RepositoryMutation: p.RepoMetadata,
126 Known: p.Known,
127 Reason: p.displayReason(),
128 }
129 }
130
131 func (p EffectProfile) displayReason() string {
132 switch p.Reason {
133 case ReasonRepoMetadata:
134 return "repository metadata write"
135 case ReasonWorkspaceWrite:
136 return "workspace content write"
137 case ReasonHostState:
138 return "host state write"
139 case ReasonExternalState:
140 return "external state write"
141 case ReasonOpaqueWriter:
142 return "opaque writer"
143 case ReasonDestructive:
144 return "destructive write"
145 case ReasonScratch:
146 return "scratch write"
147 case ReasonUnknown:
148 return "unknown command"
149 default:
150 return string(p.Reason)
151 }
152 }
153
154 // CallHint is the optional host-only preview collected before classification.
155 type CallHint struct {
156 Present bool
157 Known bool
158 ReadOnly bool
159 Destructive bool
160 Privileged bool
161 UsesNetwork bool
162 ExecutesCode bool
163 Targets []string
164 }
165
166 // EffectInput is one concrete invocation to classify.
167 type EffectInput struct {
168 ToolName string
169 Args []byte
170 StaticReadOnly bool
171 Hint CallHint
172 ActualPaths []string
173 WorkspaceRoot string
174 ScratchRoots []string
175 }
176
176 lines GO