@@ 186,6 186,11 @@ func runFileFromOffset(ctx context.Context, cfg config.Config, src config.Source
return culpa.Wrap(err, "parse source file")
}
if len(events) == 0 {
+ if newOffset > startOffset {
+ if err := store.SaveOffset(ctx, src.Tool, path, newOffset); err != nil {
+ return culpa.Wrap(err, "save skipped-only offset")
+ }
+ }
return nil
}
stampHost(events, cfg.Host)
@@ 487,6 487,55 @@ func TestRunBackfillOnce_InterruptedProgressIsResumable(t *testing.T) {
assertOffset(t, ctx, store, "claude-code", file, 300)
}
+func TestRunOnce_SkippedOnlyParseResultPersistsNewOffsetAndDoesNotPost(t *testing.T) {
+ ctx := context.Background()
+ store := openTestStore(t, ctx)
+ source := testSource(t, "claude-code", 10, 4096)
+ file := filepath.Join(source.Path, "one.jsonl")
+
+ var posted int
+ ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ posted++
+ w.Header().Set("Content-Type", "application/json")
+ _, _ = w.Write([]byte(resultJSON(Result{Accepted: 0})))
+ }))
+ defer ts.Close()
+ sender := NewSender(ts.URL, ts.Client())
+
+ p := newFakeParser("claude-code", []parser.SourceFile{{Path: file}}, map[string]parseResult{
+ file: {events: []wire.TurnEvent{}, newOffset: 250},
+ })
+
+ err := RunOnce(ctx, testConfig(), source, p, store, sender)
+ if err != nil {
+ t.Fatalf("RunOnce: %v", err)
+ }
+
+ assertOffset(t, ctx, store, "claude-code", file, 250)
+ if posted != 0 {
+ t.Errorf("POST count = %d, want 0", posted)
+ }
+}
+
+func TestRunOnce_EmptyParseResultNoProgressDoesNotSaveOffset(t *testing.T) {
+ ctx := context.Background()
+ store := openTestStore(t, ctx)
+ source := testSource(t, "claude-code", 10, 4096)
+ file := filepath.Join(source.Path, "one.jsonl")
+
+ p := newFakeParser("claude-code", []parser.SourceFile{{Path: file}}, map[string]parseResult{
+ file: {events: []wire.TurnEvent{}, newOffset: 0},
+ })
+ sender := acceptingSender(t, nil)
+
+ err := RunOnce(ctx, testConfig(), source, p, store, sender)
+ if err != nil {
+ t.Fatalf("RunOnce: %v", err)
+ }
+
+ assertOffset(t, ctx, store, "claude-code", file, 0)
+}
+
type parseResult struct {
events []wire.TurnEvent
newOffset int64