1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
impl QualityProxyService {
/// Proxies a code operation through quality gates.
///
/// # Arguments
///
/// * `request` - The proxy request containing operation details
///
/// # Returns
///
/// A proxy response with quality report and final content
///
/// # Example
///
/// ```
/// use pmat::services::quality_proxy::QualityProxyService;
/// use pmat::models::proxy::{ProxyRequest, ProxyOperation, ProxyMode, QualityConfig};
///
/// # async fn example() -> anyhow::Result<()> {
/// let service = QualityProxyService::new();
/// let request = ProxyRequest {
/// operation: ProxyOperation::Write,
/// file_path: "example.rs".to_string(),
/// content: Some("/// Example function\nfn example() {}".to_string()),
/// old_content: None,
/// new_content: None,
/// mode: ProxyMode::Advisory,
/// quality_config: QualityConfig::default(),
/// };
///
/// let response = service.proxy_operation(request).await?;
/// println!("Status: {:?}", response.status);
/// # Ok(())
/// # }
/// ```
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub async fn proxy_operation(&self, request: ProxyRequest) -> Result<ProxyResponse> {
info!(
"Proxying {} operation for {}",
match request.operation {
ProxyOperation::Write => "write",
ProxyOperation::Edit => "edit",
ProxyOperation::Append => "append",
},
request.file_path
);
let content = self.get_operation_content(&request)?;
let file_extension = Path::new(&request.file_path)
.extension()
.and_then(|ext| ext.to_str())
.unwrap_or("rs");
let ((quality_metrics, passed), violations) = self
.analyze_content(
&content,
&request.file_path,
file_extension,
&request.quality_config,
)
.await?;
let (status, final_content, refactoring_applied, refactoring_plan) = match request.mode {
ProxyMode::Strict => {
if passed {
(ProxyStatus::Accepted, content, false, None)
} else {
(ProxyStatus::Rejected, String::new(), false, None)
}
}
ProxyMode::Advisory => (ProxyStatus::Accepted, content, false, None),
ProxyMode::AutoFix => {
if passed {
(ProxyStatus::Accepted, content, false, None)
} else {
match self
.auto_fix_content(
&content,
&request.file_path,
file_extension,
&request.quality_config,
)
.await
{
Ok((fixed_content, plan)) => {
let ((_, fixed_passed), _) = self
.analyze_content(
&fixed_content,
&request.file_path,
file_extension,
&request.quality_config,
)
.await?;
if fixed_passed {
(ProxyStatus::Modified, fixed_content, true, Some(plan))
} else {
warn!("Auto-fix failed to meet quality standards");
(ProxyStatus::Rejected, String::new(), false, None)
}
}
Err(e) => {
warn!("Auto-fix failed: {}", e);
(ProxyStatus::Rejected, String::new(), false, None)
}
}
}
}
};
Ok(ProxyResponse {
status,
quality_report: QualityReport {
passed,
metrics: quality_metrics,
violations,
},
final_content,
refactoring_applied,
refactoring_plan,
})
}
/// Resolve the post-operation content the quality gates will judge.
///
/// `request.file_path` used to be ignored entirely: with no inline `content`
/// an Edit fell through to the replacement fragment alone and an Append to
/// the appended text alone, so a three-line file came back with
/// `final_content` holding one line and was graded on that fragment. Worse,
/// nothing checked that `old_content` actually occurred anywhere, so an edit
/// anchored to a string absent from the file was reported "accepted". Fall
/// back to the file on disk, and refuse an anchor that occurs nowhere in it.
/// (An anchor that occurs several times still replaces every occurrence —
/// that is the semantic the proxy's property tests pin.)
fn get_operation_content(&self, request: &ProxyRequest) -> Result<String> {
match request.operation {
ProxyOperation::Write => request
.content
.clone()
.context("Write operation requires content"),
ProxyOperation::Edit => {
let old = request
.old_content
.as_ref()
.context("Edit operation requires old_content")?;
let new = request
.new_content
.as_ref()
.context("Edit operation requires new_content")?;
let existing = match &request.content {
Some(inline) => inline.clone(),
None => read_proxy_target(&request.file_path)?.with_context(|| {
format!(
"Edit operation on {} requires the file to exist or inline content",
request.file_path
)
})?,
};
if !existing.contains(old.as_str()) {
anyhow::bail!(
"Edit rejected: old_content does not occur in {}",
request.file_path
);
}
Ok(existing.replace(old, new))
}
ProxyOperation::Append => {
let append_content = request
.content
.as_ref()
.context("Append operation requires content")?;
match &request.old_content {
// Caller-supplied preceding text keeps its historical join.
Some(existing) => Ok(format!("{existing}\n{append_content}")),
None => match read_proxy_target(&request.file_path)? {
Some(existing) => Ok(join_appended(&existing, append_content)),
// Appending to a file that does not exist yet creates
// it — but only somewhere it could actually be created.
// A path under a directory that does not exist was
// silently treated as "an append to the empty file" and
// came back accepted/passed:true, while `quality_gate`
// rejected the very same path with "File does not
// exist". Two tools in one session must not disagree
// about whether a path is real.
None => {
ensure_appendable(&request.file_path)?;
Ok(append_content.clone())
}
},
}
}
}
}
}
/// Read the file an operation targets; `None` when it does not exist yet.
fn read_proxy_target(file_path: &str) -> Result<Option<String>> {
let path = Path::new(file_path);
if !path.is_file() {
return Ok(None);
}
std::fs::read_to_string(path)
.map(Some)
.with_context(|| format!("Failed to read {file_path} for quality proxy"))
}
/// Refuse an append to a path that could not be created if it were performed.
///
/// The file itself may legitimately not exist yet; its directory may not.
fn ensure_appendable(file_path: &str) -> Result<()> {
let path = Path::new(file_path);
match path.parent().filter(|p| !p.as_os_str().is_empty()) {
Some(dir) if !dir.is_dir() => anyhow::bail!(
"Append rejected: {} does not exist and neither does its directory {}",
file_path,
dir.display()
),
_ => Ok(()),
}
}
/// Concatenate appended text without inventing or losing a line break.
fn join_appended(existing: &str, addition: &str) -> String {
if existing.is_empty() || existing.ends_with('\n') {
format!("{existing}{addition}")
} else {
format!("{existing}\n{addition}")
}
}
#[cfg(test)]
mod proxy_file_path_tests {
use super::*;
const THREE_LINES: &str = "pub fn line_one() -> i32 { 1 }\n\
pub fn line_two() -> i32 { 2 }\n\
pub fn line_three() -> i32 { 3 }\n";
fn request(op: ProxyOperation, path: &std::path::Path) -> ProxyRequest {
ProxyRequest {
operation: op,
file_path: path.display().to_string(),
content: None,
old_content: None,
new_content: None,
mode: ProxyMode::Strict,
quality_config: QualityConfig::default(),
}
}
fn fixture() -> (tempfile::TempDir, std::path::PathBuf) {
let dir = tempfile::tempdir().expect("tempdir");
let path = dir.path().join("multi.rs");
std::fs::write(&path, THREE_LINES).expect("write fixture");
(dir, path)
}
/// An edit must be graded on the whole file, not on the replacement alone.
#[test]
fn test_edit_applies_to_the_file_on_disk() {
let (_dir, path) = fixture();
let service = QualityProxyService::new();
let mut req = request(ProxyOperation::Edit, &path);
req.old_content = Some("pub fn line_two() -> i32 { 2 }".to_string());
req.new_content = Some("pub fn line_two() -> i32 { 22 }".to_string());
let content = service.get_operation_content(&req).expect("edit resolves");
assert!(content.contains("line_one"), "{content}");
assert!(content.contains("line_three"), "{content}");
assert!(content.contains("{ 22 }"), "{content}");
assert!(!content.contains("{ 2 }"), "{content}");
}
/// An anchor that occurs nowhere in the file is not an edit — it is an error.
#[test]
fn test_edit_with_absent_old_content_is_rejected() {
let (_dir, path) = fixture();
let service = QualityProxyService::new();
let mut req = request(ProxyOperation::Edit, &path);
req.old_content = Some("THIS STRING IS NOT PRESENT".to_string());
req.new_content = Some("zzz".to_string());
let err = service
.get_operation_content(&req)
.expect_err("an impossible edit must not be accepted");
assert!(err.to_string().contains("does not occur"), "{err}");
}
/// A repeated anchor replaces every occurrence — in the file, not in a
/// fragment (the proxy's property tests pin the replace-all semantic).
#[test]
fn test_edit_replaces_every_occurrence_in_the_file() {
let (_dir, path) = fixture();
let service = QualityProxyService::new();
let mut req = request(ProxyOperation::Edit, &path);
req.old_content = Some("-> i32".to_string());
req.new_content = Some("-> u32".to_string());
let content = service.get_operation_content(&req).expect("edit resolves");
assert_eq!(content.matches("-> u32").count(), 3, "{content}");
assert!(!content.contains("-> i32"), "{content}");
}
/// Append must keep the file it appends to.
#[test]
fn test_append_keeps_the_existing_file() {
let (_dir, path) = fixture();
let service = QualityProxyService::new();
let mut req = request(ProxyOperation::Append, &path);
req.content = Some("pub fn line_four() -> i32 { 4 }\n".to_string());
let content = service.get_operation_content(&req).expect("append resolves");
assert!(content.starts_with(THREE_LINES), "{content}");
assert!(content.contains("line_four"), "{content}");
}
/// `quality_proxy` accepted edit/append on a path that cannot exist while
/// `quality_gate`, in the same session, rejected it with "File does not
/// exist". Both must refuse it.
#[test]
fn test_operations_on_an_impossible_path_are_rejected() {
let service = QualityProxyService::new();
let missing = std::path::Path::new("/does/not/exist/never_existed.rs");
let mut edit = request(ProxyOperation::Edit, missing);
edit.old_content = Some("x".to_string());
edit.new_content = Some("y".to_string());
let err = service
.get_operation_content(&edit)
.expect_err("editing a nonexistent file must fail loudly");
assert!(
err.to_string().contains("requires the file to exist"),
"{err}"
);
let mut append = request(ProxyOperation::Append, missing);
append.content = Some("pub fn added() {}\n".to_string());
let err = service
.get_operation_content(&append)
.expect_err("appending under a nonexistent directory must fail loudly");
assert!(err.to_string().contains("Append rejected"), "{err}");
}
/// Appending to a path that does not exist yet still creates it.
#[test]
fn test_append_to_missing_file_is_just_the_addition() {
let dir = tempfile::tempdir().expect("tempdir");
let service = QualityProxyService::new();
let mut req = request(ProxyOperation::Append, &dir.path().join("new.rs"));
req.content = Some("pub fn only() {}\n".to_string());
assert_eq!(
service.get_operation_content(&req).expect("append resolves"),
"pub fn only() {}\n"
);
}
}