Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src-tauri/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions src-tauri/crates/orgtrack-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ rusqlite = { workspace = true, optional = true }
sha2 = { version = "0.10", optional = true }
dirs = "6.0"
similar = "2.6"
# Diagnostics only: report records this crate skips rather than raises
# (already a transitive dep via `app_paths`).
tracing = "0.1"
prost-reflect = { version = "0.16.3", features = ["serde"] }
regex = "1"
memchr = "2.7"
Expand Down
17 changes: 15 additions & 2 deletions src-tauri/crates/orgtrack-core/src/sources/anthropic_jsonl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,13 @@ fn sync_cache(config: &AnthropicJsonlSource, conn: &mut Connection) -> Result<()
config.source,
&record.source_session_id,
)?;
let parse = parse_session_meta_incremental(config, record, stored.as_ref())?;
let Some(parse) = imported_history::skip_unparsable_record(
config.source,
&record.source_session_id,
parse_session_meta_incremental(config, record, stored.as_ref()),
) else {
continue;
};
watermark::write_parse_watermark_from_conn(
conn,
config.source,
Expand All @@ -238,7 +244,14 @@ fn sync_cache(config: &AnthropicJsonlSource, conn: &mut Connection) -> Result<()
)?;
parse.meta
} else {
parse_session_meta(config, record)?
let Some(meta) = imported_history::skip_unparsable_record(
config.source,
&record.source_session_id,
parse_session_meta(config, record),
) else {
continue;
};
meta
};
inputs.push(meta_to_cache_input(config, meta));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -611,11 +611,13 @@ fn sync_claude_code_history_cache(conn: &mut Connection) -> Result<(), String> {
.get(&record.source_session_id)
.cloned()
.unwrap_or_default();
let parse = parse_claude_session_meta_with_title(
record,
stored_watermark.as_ref(),
external_title,
)?;
let Some(parse) = imported_history::skip_unparsable_record(
SOURCE_CLAUDE_CODE,
&record.source_session_id,
parse_claude_session_meta_with_title(record, stored_watermark.as_ref(), external_title),
) else {
continue;
};
imported_history::watermark::write_parse_watermark_from_conn(
conn,
SOURCE_CLAUDE_CODE,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,14 @@ pub(super) fn sync_cline_history_cache(conn: &mut Connection) -> Result<(), Stri
})?;
let mut inputs = Vec::new();
for record in changed {
if let Some(meta) = parse_cline_session_meta(record)? {
let Some(parsed) = imported_history::skip_unparsable_record(
SOURCE_CLINE,
&record.record.source_session_id,
parse_cline_session_meta(record),
) else {
continue;
};
if let Some(meta) = parsed {
inputs.push(session_meta_to_cache_input(meta));
}
}
Expand Down
9 changes: 7 additions & 2 deletions src-tauri/crates/orgtrack-core/src/sources/codex/app/index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -319,8 +319,13 @@ fn sync_codex_app_cache(conn: &mut Connection) -> Result<(), String> {
.get(&record.source_session_id)
.cloned()
.unwrap_or_default();
let parse =
parse_codex_session_meta_with_title(record, stored_watermark.as_ref(), external_title)?;
let Some(parse) = imported_history::skip_unparsable_record(
SOURCE_CODEX_APP,
&record.source_session_id,
parse_codex_session_meta_with_title(record, stored_watermark.as_ref(), external_title),
) else {
continue;
};
imported_history::watermark::write_parse_watermark_from_conn(
conn,
SOURCE_CODEX_APP,
Expand Down
28 changes: 28 additions & 0 deletions src-tauri/crates/orgtrack-core/src/sources/imported_history/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,34 @@ pub const FUNCTION_GLOB_FILE_SEARCH: &str = "glob_file_search";
pub const FUNCTION_AWAIT_OUTPUT: &str = "await_output";
pub const DEFAULT_LIST_LIMIT: usize = 200;

/// Drop one unparsable record from a source sync instead of failing the sync.
///
/// A sync that raises leaves `sync_source_cache_from_conn` unreached, so *no*
/// session of that source is written — and because the record keeps its old
/// cache signature, the next scan re-reads the same file and fails the same
/// way. One malformed transcript would permanently cost a provider its entire
/// sidebar. Skipping keeps that record on its last-known cached row (or absent
/// if never cached) and still eligible for a later retry, while every other
/// session in the source syncs normally.
pub fn skip_unparsable_record<T>(
source: &str,
source_session_id: &str,
outcome: Result<T, String>,
) -> Option<T> {
match outcome {
Ok(value) => Some(value),
Err(error) => {
tracing::warn!(
source,
source_session_id,
error = %error,
"imported history: skipping record that failed to parse"
);
None
}
}
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum ImportedHistoryLoader {
ClaudeCode,
Expand Down
Loading
Loading