Skip to content

Commit cd437a3

Browse files
feat: archive normalized session messages
1 parent a9ceef8 commit cd437a3

13 files changed

Lines changed: 526 additions & 17 deletions

File tree

PROJECT_STATUS.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,14 @@ CodeVetter is a local-first desktop workbench for checking agent-generated code.
2323
- Review Memory Graph has a repo-level and review-scoped first slice: Repo Unpacked now persists a deterministic local `repo_graph` artifact with package scripts, routes, Tauri commands, DB tables, tests, and decision markers; exports local graph JSON plus agent-context markdown sidecars for optional Graphify/Hunk-style interop without adding either dependency; imports graph JSON only through an explicit Repo Unpacked file action, validates CodeVetter or loose graph-shaped JSON, and renders imported graphs as non-mutating previews; CLI review results also carry a bounded local graph over changed files, evidence candidates, procedure gates, blast/history context, the review prompt includes that graph neighborhood, Review shows a compact graph panel plus selected-finding graph focus, copied reviewer proof includes both full graph and focused finding graph nodes/edges, and Review can copy a selected finding as a Hunk-style agent-context note with file/line, evidence status, local history, focused graph, and next verification actions.
2424
- Agent Verification Timeline has a first normalized spine: Review now builds a shared task/review/QA/evidence/claim-check/fix/worktree timeline contract, attaches bounded raw-session command anchors to evidence rows with transcript excerpts, adds a dedicated Claim check row for failed/stale command claims, explicit extracted agent claims, positive test/check claims contradicted by failed/stale command evidence, unchecked findings, unresolved post-fix QA, and fixes without same-flow reruns, attaches edit-origin anchors for fix changed files to worktree rows, renders timeline stages and anchors in the sidebar, exposes first-class jump targets for findings, files, QA artifacts, fix worktrees, command source anchors, and edited files, shows same-flow post-fix QA before/after deltas with artifact anchors on the QA row, can copy segment-scoped fix packets directly from Review/Evidence/QA/Fix/Worktree timeline rows, includes clicked-row timeline replay metadata and transcript snippets in those packets, and includes the same timeline plus source/event/artifact/jump/edit/transcript anchors in copied reviewer proof.
2525
- Codebase History Explainer has a first file-level slice: Review now builds bounded, cited "why this code exists" explanations from local commits, decision markers, recurring findings, agent notes, and command anchors, renders them in the sidebar, and includes them in copied reviewer proof.
26-
- AI Session Intelligence has a first local scorecard slice: indexed sessions produce a schema-versioned six-dimension scorecard with cited evidence refs, anti-gaming notes, recommendations, normalized Claude/Codex/Cursor adapter coverage summaries, production and scorecard adapter run metadata/parse warnings in `session_adapter_runs`, a shared raw parser adapter contract with Claude/Codex/Cursor fixtures, Claude/Codex/Cursor production indexing wired through that contract, a Tauri IPC contract, compact Home dashboard panels for scorecard and source health, visible adapter run status, per-adapter run trends, and recent-run drilldowns.
26+
- AI Session Intelligence has a first local scorecard slice: indexed sessions produce a schema-versioned six-dimension scorecard with cited evidence refs, anti-gaming notes, recommendations, normalized Claude/Codex/Cursor adapter coverage summaries, production and scorecard adapter run metadata/parse warnings in `session_adapter_runs`, a compact `session_message_archive` for normalized adapter messages/tool calls, a shared raw parser adapter contract with Claude/Codex/Cursor fixtures, Claude/Codex/Cursor production indexing wired through that contract, a Tauri IPC contract, compact Home dashboard panels for scorecard and source health, visible adapter run status, per-adapter run trends, and recent-run drilldowns.
2727
- Home now has a persistent Verification Workbench launcher plus a visible latest-roadmap-build banner, so Evidence Search, Agent Timeline, Synthetic QA, Memory Graph, History Brief, AI Sessions, transcript replay, claim checks, replay packets, timeline fix packets, edit origins, and post-fix QA deltas are visible immediately after launch instead of only appearing after a Review or Repo Unpacked run.
2828
- OSS repo-analysis engines were evaluated in `docs/oss-integration-evaluation.md`; optional `ast-grep` changed-file evidence is implemented behind PATH detection with no required runtime dependency.
2929
- Product direction has been consolidated around agent-written code verification, evidence levels, timelines, and explainable codebase history.
3030

3131
## Planned Next
3232

33-
1. Continue the AI Session Intelligence PRD in `docs/PRD-AI-SESSION-INTELLIGENCE.md`: normalize full message/tool-call archives into the SQLite evidence archive; Claude, Codex, and Cursor production session rows now use the normalized raw parser adapter contract, production index passes persist adapter run metadata/parse warnings, and Home shows latest source-health status with per-adapter trends and recent-run drilldowns.
33+
1. Continue the AI Session Intelligence PRD in `docs/PRD-AI-SESSION-INTELLIGENCE.md`: add full-text search and live update events over the normalized session message archive; Claude, Codex, and Cursor production session rows now use the normalized raw parser adapter contract, production index passes persist adapter run metadata/parse warnings plus compact message/tool-call archive rows, and Home shows latest source-health status with per-adapter trends and recent-run drilldowns.
3434
2. Continue the Agent Verification Timeline PRD in `docs/PRD-AGENT-VERIFICATION-TIMELINE.md`: add richer claim-vs-evidence discrepancy parsing beyond literal positive test/check claim contradictions, command/QA/evidence-count signals, and fuller multi-turn transcript replay; raw session command anchors with bounded transcript excerpts, explicit agent-claim anchors, dedicated claim-check rows, edit-origin anchors, timeline-specific jump targets, timeline-segment replay packets, same-flow post-fix QA deltas, and the Home latest-roadmap-build banner are now attached to visible Review/Home actions and proof export.
3535
3. Continue the Codebase History Explainer PRD in `docs/PRD-CODEBASE-HISTORY-EXPLAINER.md`: turn the persisted `history_brief` slice into a queryable local history graph; Repo Unpacked history brief integration and agent-context sidecar export are now implemented.
3636
4. Curate 20-30 real public agent-generated PR benchmark cases with hand-labeled ground truth before making external catch-rate claims.

apps/desktop/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@code-reviewer/desktop",
3-
"version": "1.1.43",
3+
"version": "1.1.44",
44
"private": true,
55
"scripts": {
66
"dev": "lsof -ti:1420 | xargs kill -9 2>/dev/null; vite",

apps/desktop/src-tauri/src/commands/history.rs

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,7 @@ fn full_index_impl(conn: &rusqlite::Connection) -> Result<(u64, u64, u64), Strin
238238
if let Some(ref meta) = existing {
239239
if meta.file_mtime.as_deref() == file_mtime_str.as_deref()
240240
&& meta.message_count > 0
241+
&& meta.archived_message_count > 0
241242
{
242243
skipped_sessions += 1;
243244
continue;
@@ -323,7 +324,9 @@ fn full_index_impl(conn: &rusqlite::Connection) -> Result<(u64, u64, u64), Strin
323324
.map_err(|e| e.to_string())?;
324325

325326
if let Some(ref meta) = existing {
326-
if meta.file_mtime.as_deref() == file_mtime_str.as_deref() && meta.message_count > 0
327+
if meta.file_mtime.as_deref() == file_mtime_str.as_deref()
328+
&& meta.message_count > 0
329+
&& meta.archived_message_count > 0
327330
{
328331
skipped_sessions += 1;
329332
continue;
@@ -668,9 +671,12 @@ fn upsert_adapter_summary_session(
668671
.map(String::from)
669672
.or_else(|| summary.stable_id.clone())
670673
.unwrap_or_else(|| uuid::Uuid::new_v4().to_string());
674+
let adapter_id = summary.adapter_id.clone();
675+
let agent_type = summary.agent_type.clone();
671676
let source_ref = summary.source_ref.clone();
672677
let message_count = summary.message_count.max(0) as u64;
673678
let day_counts = summary.day_counts.clone();
679+
let archive_messages = summary.archive_messages.clone();
674680
let parse_warnings = summary.parse_warnings.clone();
675681

676682
for warning in &summary.parse_warnings {
@@ -699,7 +705,7 @@ fn upsert_adapter_summary_session(
699705
&queries::SessionInput {
700706
id: sid.clone(),
701707
project_id: project_id.to_string(),
702-
agent_type: Some(summary.agent_type),
708+
agent_type: Some(agent_type.clone()),
703709
jsonl_path: Some(source_ref.clone()),
704710
git_branch: summary.git_branch,
705711
cwd: summary.cwd,
@@ -726,6 +732,27 @@ fn upsert_adapter_summary_session(
726732
let _ = queries::bump_session_day(conn, &sid, day, *n);
727733
}
728734

735+
let archive_inputs: Vec<_> = archive_messages
736+
.into_iter()
737+
.enumerate()
738+
.map(|(idx, message)| queries::SessionMessageArchiveInput {
739+
adapter_id: adapter_id.clone(),
740+
agent_type: agent_type.clone(),
741+
source_ref: source_ref.clone(),
742+
source_line: message.source_line,
743+
message_index: idx as i64,
744+
role: message.role,
745+
kind: message.kind,
746+
timestamp: message.timestamp,
747+
content_text: message.content_text,
748+
tool_name: message.tool_name,
749+
tool_call_id: message.tool_call_id,
750+
raw_type: message.raw_type,
751+
})
752+
.collect();
753+
queries::replace_session_message_archive(conn, &sid, &archive_inputs)
754+
.map_err(|e| e.to_string())?;
755+
729756
Ok(IndexedAdapterSession {
730757
session_id: sid,
731758
source_ref,
@@ -1018,6 +1045,7 @@ fn index_cursor_sessions(conn: &rusqlite::Connection) -> Result<(u64, u64, u64),
10181045
if let Some(ref existing) = existing {
10191046
if existing.file_mtime.as_deref() == composer_mtime.as_deref()
10201047
&& existing.message_count > 0
1048+
&& existing.archived_message_count > 0
10211049
{
10221050
skipped_sessions += 1;
10231051
continue;
@@ -1278,6 +1306,13 @@ mod tests {
12781306
)
12791307
.expect("session day bucket");
12801308
assert_eq!(day_count, 3);
1309+
1310+
let archived =
1311+
queries::list_session_message_archive(&conn, "claude-session-1", 10).expect("archive");
1312+
assert_eq!(archived.len(), 3);
1313+
assert_eq!(archived[0].adapter_id, "claude-code");
1314+
assert_eq!(archived[0].role.as_deref(), Some("user"));
1315+
assert_eq!(archived[2].kind, "compaction");
12811316
}
12821317

12831318
#[test]
@@ -1332,6 +1367,13 @@ mod tests {
13321367
)
13331368
.expect("session day bucket");
13341369
assert_eq!(day_count, 2);
1370+
1371+
let archived =
1372+
queries::list_session_message_archive(&conn, "codex-session-1", 10).expect("archive");
1373+
assert_eq!(archived.len(), 2);
1374+
assert_eq!(archived[0].adapter_id, "codex");
1375+
assert_eq!(archived[0].role.as_deref(), Some("user"));
1376+
assert_eq!(archived[1].raw_type.as_deref(), Some("response_item"));
13351377
}
13361378

13371379
#[test]
@@ -1390,6 +1432,16 @@ mod tests {
13901432
)
13911433
.expect("session day bucket");
13921434
assert_eq!(day_count, 2);
1435+
1436+
let archived =
1437+
queries::list_session_message_archive(&conn, "cursor-composer-1", 10).expect("archive");
1438+
assert_eq!(archived.len(), 2);
1439+
assert_eq!(archived[0].adapter_id, "cursor");
1440+
assert_eq!(
1441+
archived[0].content_text.as_deref(),
1442+
Some("Fix checkout test")
1443+
);
1444+
assert_eq!(archived[1].role.as_deref(), Some("assistant"));
13931445
}
13941446

13951447
#[test]

0 commit comments

Comments
 (0)