Skip to content

sync --include-comments downloads comments again for every open thread, even when the thread has not changed #198

Description

@vlsi

Summary

I keep a local archive of pgjdbc/pgjdbc (489 open issues and pull requests) and want to refresh it every week or month. Each gitcrawl sync owner/repo --include-comments run downloads the comments of every open thread again, including threads whose updated_at has not changed since the previous run. With --with pr-details the same happens to files, commits, checks, and review threads of every open pull request. A periodic refresh therefore costs about as many API requests as the first backfill.

Reproduction

gitcrawl 0.9.6, a fresh database, two runs back to back:

export GITCRAWL_CONFIG=$PWD/gc/config.toml GITCRAWL_DB_PATH=$PWD/gc/gc.db
gitcrawl init --db $PWD/gc/gc.db --json
gitcrawl sync openclaw/gitcrawl --include-comments --progress-file $PWD/gc/p1.json --json
gitcrawl sync openclaw/gitcrawl --include-comments --progress-file $PWD/gc/p2.json --json

Progress file after the second run:

{"schema":"gitcrawl.sync-progress.v1","repository":"openclaw/gitcrawl","state":"succeeded","stage":"finalizing","issues_received":0,"pull_requests_received":1,"comments_received":2,"observed_at":"2026-09-13T15:03:25.977678Z"}

The one open thread is #197. Its updated_at did not change between the runs, and the database already held its comments at that updated_at before the second run started:

$ sqlite3 gc/gc.db "select t.number, t.updated_at_gh, r.family, r.source_updated_at from threads t join thread_child_observation_reservations r on r.thread_id = t.id where t.state = 'open'"
197|2026-09-13T14:11:55Z|comments|2026-09-13T14:11:55Z

On this repository the second run fetches 2 comments. On a repository with a few hundred open threads, it fetches the comments of all of them. I have not measured the request count on pgjdbc/pgjdbc itself.

Expected

When a thread's updated_at in the list response equals the source_updated_at recorded for a child family in thread_child_observation_reservations, sync does not request that family for the thread. In the reproduction above, the second run reports "comments_received": 0.

A way to force a full re-download (for example, a flag) stays available for data that can change without moving updated_at.

Actual

Syncer.Sync requests comments, review threads, and pull request details for every row in the list response (internal/syncer/syncer.go, the loop over rows before persist). The comparison with thread_child_observation_reservations happens only afterwards, in ReserveThreadChildObservation, when the data is written. Unchanged data is discarded after it has been downloaded.

Possible approach

This part is a suggestion; the report above stands without it.

  1. Before the download loop, read ThreadChildObservation for each thread and family, and skip the request when source_updated_at equals the row's updated_at.
  2. Check runs and workflow runs probably need a different key, such as the head SHA. As far as I know, a new CI run does not change a pull request's updated_at; I have not verified this.
  3. Optionally, fetch the open list with since taken from a watermark, as the closed sweep already does with closed_sweep_through. After fix: avoid stalled embedding batches and stale open threads #175, threads missing from a response are not treated as closed or deleted.

Workaround

--state all --since <date of the previous sync> limits the list to threads updated after that date, so only those are hydrated. The caller has to track the date, and a run with --since does not advance closed_sweep_through.

Related

I found no existing issue or pull request about this (searched open and closed items for since, incremental, watermark, and comments hydration). #175 fixed missed closures after an offline period, but it does not change which threads are hydrated.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Normal priority bug or improvement with limited blast radius.clawsweeper:needs-maintainer-reviewClawSweeper marked this issue as needing maintainer review before automation.clawsweeper:needs-product-decisionClawSweeper marked this issue as needing a product or behavior decision.clawsweeper:no-new-fix-prClawSweeper does not recommend queueing a new automated fix PR for this issue.clawsweeper:source-reproClawSweeper found a high-confidence source-level issue reproduction.impact:otherThis issue has meaningful maintainer-visible impact outside the owned taxonomy.issue-rating: 🦞 diamond lobsterVery strong issue quality with high-confidence source-level or clear reproduction.

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions