feat(1001): story_ids filter for recover_half_written_items
The first dry-run against the live pipeline surfaced 735 orphans (35 tombstoned half-writes, 700 stale content rows with no CRDT entry — mostly artefacts of the pre-numeric-id era). Bulk-recovering would resurrect a lot of stories the user deliberately purged in the past. Add an optional `story_ids` filter that restricts both discovery (in dry-run) and recovery to a named subset, so the operator can target the specific recent half-writes without touching anything else. The new test asserts the filter is honoured. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -131,21 +131,37 @@ pub(crate) fn tool_recover_half_written_items(args: &Value) -> Result<String, St
|
||||
.and_then(|v| v.as_bool())
|
||||
.unwrap_or(true);
|
||||
|
||||
// Optional id filter — when provided, recovery (or the dry-run report) is
|
||||
// restricted to these ids. This is the safe choice for live systems
|
||||
// where the orphan set may include many historic purged stories that
|
||||
// should stay dead.
|
||||
let only: Option<Vec<String>> = args.get("story_ids").and_then(|v| {
|
||||
v.as_array().map(|arr| {
|
||||
arr.iter()
|
||||
.filter_map(|x| x.as_str().map(str::to_string))
|
||||
.collect()
|
||||
})
|
||||
});
|
||||
|
||||
if dry_run {
|
||||
let half = crate::db::find_half_written_items();
|
||||
let mut half = crate::db::find_half_written_items();
|
||||
if let Some(filter) = &only {
|
||||
half.retain(|h| filter.iter().any(|f| f == &h.story_id));
|
||||
}
|
||||
let count = half.len();
|
||||
return serde_json::to_string_pretty(&json!({
|
||||
"dry_run": true,
|
||||
"found": half,
|
||||
"count": half.len(),
|
||||
"count": count,
|
||||
"message": format!(
|
||||
"Discovered {} half-written item(s). Re-run with dry_run=false to recover them.",
|
||||
half.len()
|
||||
"Discovered {count} half-written item(s){scope}. Re-run with dry_run=false to recover them.",
|
||||
scope = if only.is_some() { " matching the filter" } else { "" },
|
||||
),
|
||||
}))
|
||||
.map_err(|e| format!("Serialization error: {e}"));
|
||||
}
|
||||
|
||||
let results = crate::db::recover_half_written_items();
|
||||
let results = crate::db::recover_half_written_items(only.as_deref());
|
||||
serde_json::to_string_pretty(&json!({
|
||||
"dry_run": false,
|
||||
"recovered": results,
|
||||
|
||||
Reference in New Issue
Block a user