fix(chunk): auto-accepted stale batch CRCs for previously-touched chunks
- Removed error on stale CRC when a chunk was already modified by an earlier batch op; the model can only know the pre-batch checksum. - `ensure_batch_operation_target_current` now returns `Ok(true)` to signal auto-accept, skipping redundant CRC validation. - Updated prompt to clarify batched line-scoped edits are supported and to require fully qualified chunk paths.
This commit is contained in:
@@ -261,9 +261,12 @@ fn apply_replace(
|
||||
}
|
||||
});
|
||||
let requires_checksum = operation.sel.is_some() || default_crc.is_some();
|
||||
ensure_batch_operation_target_current(state, scheduled, crc, touched_paths)?;
|
||||
let batch_auto_accepted =
|
||||
ensure_batch_operation_target_current(scheduled, crc, touched_paths)?;
|
||||
let resolved = resolve_chunk_with_crc(state, anchor_selector, crc, warnings)?;
|
||||
validate_batch_crc(resolved.chunk, resolved.crc.as_deref(), requires_checksum)?;
|
||||
if !batch_auto_accepted {
|
||||
validate_batch_crc(resolved.chunk, resolved.crc.as_deref(), requires_checksum)?;
|
||||
}
|
||||
let anchor = resolved.chunk.clone();
|
||||
|
||||
if let Some(line) = operation.line {
|
||||
@@ -352,9 +355,12 @@ fn apply_delete(
|
||||
}
|
||||
});
|
||||
let requires_checksum = operation.sel.is_some() || default_crc.is_some();
|
||||
ensure_batch_operation_target_current(state, scheduled, crc, touched_paths)?;
|
||||
let batch_auto_accepted =
|
||||
ensure_batch_operation_target_current(scheduled, crc, touched_paths)?;
|
||||
let resolved = resolve_chunk_with_crc(state, anchor_selector, crc, warnings)?;
|
||||
validate_batch_crc(resolved.chunk, resolved.crc.as_deref(), requires_checksum)?;
|
||||
if !batch_auto_accepted {
|
||||
validate_batch_crc(resolved.chunk, resolved.crc.as_deref(), requires_checksum)?;
|
||||
}
|
||||
let anchor = resolved.chunk.clone();
|
||||
|
||||
let offsets = line_offsets(&state.source);
|
||||
@@ -384,9 +390,12 @@ fn apply_insert(
|
||||
None
|
||||
}
|
||||
});
|
||||
ensure_batch_operation_target_current(state, scheduled, crc, touched_paths)?;
|
||||
let batch_auto_accepted =
|
||||
ensure_batch_operation_target_current(scheduled, crc, touched_paths)?;
|
||||
let resolved = resolve_chunk_with_crc(state, anchor_selector, crc, warnings)?;
|
||||
validate_batch_crc(resolved.chunk, resolved.crc.as_deref(), resolved.crc.is_some())?;
|
||||
if !batch_auto_accepted {
|
||||
validate_batch_crc(resolved.chunk, resolved.crc.as_deref(), resolved.crc.is_some())?;
|
||||
}
|
||||
let anchor = resolved.chunk.clone();
|
||||
|
||||
let pos = match operation.op {
|
||||
@@ -601,45 +610,29 @@ fn touches_chunk_path(touched_paths: &[String], selector: &str) -> bool {
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns `Ok(true)` when the CRC was auto-accepted (chunk was touched by an
|
||||
/// earlier batch op and the model supplied the pre-batch CRC). The caller should
|
||||
/// skip CRC validation in that case.
|
||||
fn ensure_batch_operation_target_current(
|
||||
state: &ChunkStateInner,
|
||||
scheduled: &ScheduledEditOperation,
|
||||
crc: Option<&str>,
|
||||
touched_paths: &[String],
|
||||
) -> Result<(), String> {
|
||||
) -> Result<bool, String> {
|
||||
let Some(selector) = scheduled.requested_selector.as_deref() else {
|
||||
return Ok(());
|
||||
return Ok(false);
|
||||
};
|
||||
let Some(initial_chunk) = scheduled.initial_chunk.as_ref() else {
|
||||
return Ok(());
|
||||
return Ok(false);
|
||||
};
|
||||
let Some(cleaned_crc) = sanitize_crc(crc) else {
|
||||
return Ok(());
|
||||
return Ok(false);
|
||||
};
|
||||
if !touches_chunk_path(touched_paths, selector) || cleaned_crc != initial_chunk.checksum {
|
||||
return Ok(());
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
let mut warnings = Vec::new();
|
||||
let current_chunk =
|
||||
resolve_chunk_selector(state, Some(selector), &mut warnings).map_err(|_| {
|
||||
format!(
|
||||
"Chunk path \"{selector}\" was changed by an earlier batch operation. Re-read after \
|
||||
the earlier edit and retry with the updated selector and checksum."
|
||||
)
|
||||
})?;
|
||||
if current_chunk.checksum != initial_chunk.checksum {
|
||||
return Err(format!(
|
||||
"Chunk \"{selector}\" was changed by an earlier batch operation: checksum \"{}\" is \
|
||||
stale; current checksum is \"{}\" and the current file span is {}-{}. Later operations \
|
||||
in the same batch must use the post-edit checksum and updated line span.",
|
||||
initial_chunk.checksum,
|
||||
current_chunk.checksum,
|
||||
current_chunk.start_line,
|
||||
current_chunk.end_line
|
||||
));
|
||||
}
|
||||
Ok(())
|
||||
// The chunk was touched by an earlier operation in this batch, and the model
|
||||
// supplied the pre-batch CRC (which is all it could know). Auto-accept.
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
fn describe_scheduled_operation(scheduled: &ScheduledEditOperation) -> String {
|
||||
|
||||
@@ -126,8 +126,8 @@ All examples reference this `read` output:
|
||||
- **MUST** include a `#CRC` suffix in `target` for every replace or delete edit.
|
||||
- **MUST** use updated chunk output from the edit response for follow-up edits.
|
||||
- **MUST** use the smallest correct target; do not rewrite siblings unnecessarily.
|
||||
- **MUST NOT** invent chunk paths. Copy them from `read` output including `fn_*` prefixes. Nesting uses `.`.
|
||||
- **MUST** use the **fully qualified** chunk path. Copy the complete path shown in read output — e.g. `fn_handleTerraform.try.if_2`, never just `if_2`. Short/leaf names are ambiguous.
|
||||
- For line-scoped replace edits, use file line numbers from the `read` gutter.
|
||||
- Do NOT batch multiple line-scoped replace edits on the same chunk. Combine them into one wider range or use separate calls.
|
||||
- Multiple line-scoped edits on the same chunk in one batch are fine — the engine auto-updates the checksum between operations.
|
||||
</critical>
|
||||
</output>
|
||||
Reference in New Issue
Block a user