Skip to content

Commit b4dd574

Browse files
committed
Add remediation hints to review JSON
1 parent d9678d0 commit b4dd574

4 files changed

Lines changed: 88 additions & 5 deletions

File tree

README.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
This is a Rust implementation of an RSScript v0.4.1 review-first front-end MVP.
44

5+
## Goal
6+
57
RSScript is designed for AI-generated code that humans still need to review. It
68
makes mutation, retention, resource lifetime, and local-performance boundaries
79
visible in source code and machine-readable diagnostics.
@@ -15,7 +17,7 @@ It currently implements:
1517
- `rss check --json <file.rss>` with serde-backed machine-readable diagnostics
1618
- `rss check --explain <code>` for diagnostic code explanations
1719
- `rss fmt <file.rss>` as a parse/check gate that prints the source unchanged when valid
18-
- `rss review <old.rss> <new.rss>` and `rss review --json <old.rss> <new.rss>` for first-pass API/type/effect/freshness diffs with structured risk categories, spans, before/after values, and path-aware local/manage boundary summaries
20+
- `rss review <old.rss> <new.rss>` and `rss review --json <old.rss> <new.rss>` for first-pass API/type/effect/freshness diffs with structured risk categories, spans, before/after values, remediation hints, and path-aware local/manage boundary summaries
1921
- Lexer, lightweight parser, syntax AST, HIR signature table, and semantic checks for the review-critical v0.4.1 rules
2022
- Builtin signatures for the current fixture stdlib surface, including `Image`, `File`, `Map`, `ResourcePool`, `Json`, `Csv`, database/resource helpers, and cache/config helpers
2123
- HIR type and field tables for class/struct/resource declarations and handle fields
@@ -61,7 +63,7 @@ Implemented diagnostic classes include:
6163
- local capture by managed closures
6264
- local capture by closures passed to retaining APIs
6365
- `take` of handle fields
64-
- API, type layout, path-aware local/manage boundary, effect, mode, and freshness changes in `rss review`, tagged with structured risk categories, spans, and before/after values in JSON output
66+
- API, type layout, path-aware local/manage boundary, effect, mode, and freshness changes in `rss review`, tagged with structured risk categories, spans, before/after values, and remediation hints in JSON output
6567
- likely operator overload attempts
6668

6769
Non-goals for this stage:
@@ -79,7 +81,7 @@ Non-goals for this stage:
7981
Near-term roadmap:
8082

8183
1. Expand local/resource dataflow precision around typed `ResourcePool<T>` lease propagation and expression-order coverage for short-circuiting/control expressions.
82-
2. Expand `rss review` JSON with richer machine-applicable remediation hints.
84+
2. Expand `rss review` JSON remediation hints into machine-applicable edits where possible.
8385

8486
Run:
8587

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,5 @@ pub use diagnostic::{
1212
format_diagnostic_explanation, format_diagnostics_human, format_diagnostics_json,
1313
};
1414
pub use review::{
15-
ReviewFinding, ReviewRisk, format_review_human, format_review_json, review_sources,
15+
ReviewFinding, ReviewFix, ReviewRisk, format_review_human, format_review_json, review_sources,
1616
};

src/review.rs

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ pub struct ReviewFinding {
1919
pub before: Option<String>,
2020
#[serde(skip_serializing_if = "Option::is_none")]
2121
pub after: Option<String>,
22+
pub fixes: Vec<ReviewFix>,
2223
}
2324

2425
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
@@ -30,6 +31,13 @@ pub struct ReviewSpan {
3031
pub label: String,
3132
}
3233

34+
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
35+
pub struct ReviewFix {
36+
pub kind: String,
37+
pub title: String,
38+
pub applicability: String,
39+
}
40+
3341
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
3442
#[serde(rename_all = "kebab-case")]
3543
pub enum ReviewRisk {
@@ -174,7 +182,63 @@ fn review_finding(
174182
spans,
175183
before,
176184
after,
177-
}
185+
fixes: review_fixes(code),
186+
}
187+
}
188+
189+
fn review_fixes(code: &str) -> Vec<ReviewFix> {
190+
let (kind, title) = match code {
191+
code::REVIEW_MODE_CHANGED => (
192+
"review_file_mode",
193+
"Review whether this file should allow local ownership features.",
194+
),
195+
code::REVIEW_FUNCTION_REMOVED => (
196+
"restore_or_migrate_function",
197+
"Restore the function or migrate all call sites.",
198+
),
199+
code::REVIEW_FUNCTION_ADDED => (
200+
"review_new_api",
201+
"Review the new API surface and ownership contract.",
202+
),
203+
code::REVIEW_PARAMS_CHANGED => (
204+
"update_call_sites",
205+
"Update call sites for the changed parameter contract.",
206+
),
207+
code::REVIEW_RETURN_CHANGED => (
208+
"review_return_contract",
209+
"Review callers that depend on the old return and freshness contract.",
210+
),
211+
code::REVIEW_EFFECTS_CHANGED => (
212+
"review_effect_contract",
213+
"Review added or removed effects and update callers.",
214+
),
215+
code::REVIEW_TYPE_REMOVED => (
216+
"restore_or_migrate_type",
217+
"Restore the type or migrate all consumers.",
218+
),
219+
code::REVIEW_TYPE_ADDED => (
220+
"review_type_exposure",
221+
"Review the new type's ownership and resource fields.",
222+
),
223+
code::REVIEW_TYPE_KIND_CHANGED => (
224+
"review_type_kind",
225+
"Review class, struct, or resource lifetime semantics for this type.",
226+
),
227+
code::REVIEW_TYPE_FIELDS_CHANGED => (
228+
"review_type_layout",
229+
"Review field ownership, handle markers, and resource containment.",
230+
),
231+
code::REVIEW_BOUNDARY_CHANGED => (
232+
"review_local_manage_boundary",
233+
"Review the changed local ownership and manage boundary.",
234+
),
235+
_ => ("review_change", "Review this source-level contract change."),
236+
};
237+
vec![ReviewFix {
238+
kind: kind.to_string(),
239+
title: title.to_string(),
240+
applicability: "manual".to_string(),
241+
}]
178242
}
179243

180244
#[derive(Debug, Clone, PartialEq, Eq)]

tests/checker.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,17 @@ fn render(path: take Path) -> fresh Image
123123
.as_array()
124124
.is_some_and(|spans| spans.len() == 2)
125125
);
126+
let effect_fixes = effect["fixes"]
127+
.as_array()
128+
.expect("review finding should include fixes");
129+
assert!(effect_fixes.iter().any(|fix| {
130+
fix["kind"] == "review_effect_contract" && fix["applicability"] == "manual"
131+
}));
132+
assert!(items.iter().all(|item| {
133+
item["fixes"]
134+
.as_array()
135+
.is_some_and(|fixes| !fixes.is_empty())
136+
}));
126137
assert!(items.iter().all(|item| {
127138
item["summary"]
128139
.as_str()
@@ -307,6 +318,12 @@ fn publish(path: read Path) -> Unit {
307318
assert!(boundary.summary.contains("body[1]"));
308319
assert!(boundary.summary.contains("body[2].value"));
309320
assert_eq!(boundary.risk, ReviewRisk::Boundary);
321+
assert!(
322+
boundary
323+
.fixes
324+
.iter()
325+
.any(|fix| fix.kind == "review_local_manage_boundary")
326+
);
310327
}
311328

312329
fn fixture_paths(directory: &str) -> Vec<PathBuf> {

0 commit comments

Comments
 (0)